Skip to content

Commit 170975d

Browse files
committed
refactor: extract setTaskTitle handler to separate module
1 parent 38dfee6 commit 170975d

File tree

2 files changed

+76
-51
lines changed

2 files changed

+76
-51
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import type { HistoryItem } from "@roo-code/types"
2+
3+
import type { ClineProvider } from "./ClineProvider"
4+
import type { WebviewMessage } from "../../shared/WebviewMessage"
5+
6+
/**
7+
* Normalizes a title string by trimming whitespace and returning undefined for empty strings.
8+
*/
9+
function normalizeTitle(title: string | undefined | null): string | undefined {
10+
if (!title) return undefined
11+
const trimmed = title.trim()
12+
return trimmed.length > 0 ? trimmed : undefined
13+
}
14+
15+
/**
16+
* Handles the setTaskTitle webview message.
17+
* Updates task titles for one or more history items, with deduplication and no-op detection.
18+
*/
19+
export async function handleSetTaskTitle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
20+
// 1. Validate and deduplicate incoming task IDs
21+
const ids = Array.isArray(message.ids)
22+
? Array.from(new Set(message.ids.filter((id): id is string => typeof id === "string" && id.trim().length > 0)))
23+
: []
24+
25+
if (ids.length === 0) {
26+
return
27+
}
28+
29+
// 2. Normalize the incoming title
30+
const normalizedTitle = normalizeTitle(message.text)
31+
32+
// 3. Get task history from state
33+
const { taskHistory } = await provider.getState()
34+
if (!Array.isArray(taskHistory) || taskHistory.length === 0) {
35+
return
36+
}
37+
38+
// 4. Create a map for O(1) lookups
39+
const historyById = new Map(taskHistory.map((item) => [item.id, item] as const))
40+
41+
// 5. Process each ID, skipping no-ops
42+
let hasUpdates = false
43+
44+
for (const id of ids) {
45+
const existingItem = historyById.get(id)
46+
if (!existingItem) {
47+
console.warn(`[setTaskTitle] Unable to locate task history item with id ${id}`)
48+
continue
49+
}
50+
51+
// Normalize existing title for comparison
52+
const normalizedExistingTitle = normalizeTitle(existingItem.title)
53+
54+
// Skip if title is unchanged
55+
if (normalizedExistingTitle === normalizedTitle) {
56+
continue
57+
}
58+
59+
// Update the history item
60+
const updatedItem: HistoryItem = {
61+
...existingItem,
62+
title: normalizedTitle,
63+
}
64+
65+
await provider.updateTaskHistory(updatedItem)
66+
hasUpdates = true
67+
}
68+
69+
// 6. Sync webview state if there were changes
70+
if (hasUpdates) {
71+
await provider.postStateToWebview()
72+
}
73+
}

src/core/webview/webviewMessageHandler.ts

Lines changed: 3 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
type Language,
1111
type GlobalState,
1212
type ClineMessage,
13-
type HistoryItem,
1413
type TelemetrySetting,
1514
type UserSettingsConfig,
1615
TelemetryEventName,
@@ -28,6 +27,7 @@ import { ClineProvider } from "./ClineProvider"
2827
import { BrowserSessionPanelManager } from "./BrowserSessionPanelManager"
2928
import { handleCheckpointRestoreOperation } from "./checkpointRestoreHandler"
3029
import { generateErrorDiagnostics } from "./diagnosticsHandler"
30+
import { handleSetTaskTitle } from "./taskTitleHandler"
3131
import { changeLanguage, t } from "../../i18n"
3232
import { Package } from "../../shared/package"
3333
import { type RouterName, type ModelRecord, toRouterName } from "../../shared/api"
@@ -729,57 +729,9 @@ export const webviewMessageHandler = async (
729729
vscode.window.showErrorMessage(t("common:errors.share_task_failed"))
730730
}
731731
break
732-
case "setTaskTitle": {
733-
const ids = Array.isArray(message.ids)
734-
? Array.from(
735-
new Set(
736-
message.ids.filter((id): id is string => typeof id === "string" && id.trim().length > 0),
737-
),
738-
)
739-
: []
740-
if (ids.length === 0) {
741-
break
742-
}
743-
744-
const rawTitle = message.text ?? ""
745-
const trimmedTitle = rawTitle.trim()
746-
const normalizedTitle = trimmedTitle.length > 0 ? trimmedTitle : undefined
747-
const { taskHistory } = await provider.getState()
748-
if (!Array.isArray(taskHistory) || taskHistory.length === 0) {
749-
break
750-
}
751-
752-
let hasUpdates = false
753-
const historyById = new Map(taskHistory.map((item) => [item.id, item] as const))
754-
755-
for (const id of ids) {
756-
const existingItem = historyById.get(id)
757-
if (!existingItem) {
758-
console.warn(`[setTaskTitle] Unable to locate task history item with id ${id}`)
759-
continue
760-
}
761-
762-
const normalizedExistingTitle =
763-
existingItem.title && existingItem.title.trim().length > 0 ? existingItem.title.trim() : undefined
764-
if (normalizedExistingTitle === normalizedTitle) {
765-
continue
766-
}
767-
768-
const updatedItem: HistoryItem = {
769-
...existingItem,
770-
title: normalizedTitle,
771-
}
772-
773-
await provider.updateTaskHistory(updatedItem)
774-
hasUpdates = true
775-
}
776-
777-
if (hasUpdates) {
778-
await provider.postStateToWebview()
779-
}
780-
732+
case "setTaskTitle":
733+
await handleSetTaskTitle(provider, message)
781734
break
782-
}
783735
case "showTaskWithId":
784736
provider.showTaskWithId(message.text!)
785737
break

0 commit comments

Comments
 (0)