kanban 0.1.12 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/cli.js +10 -2
  2. package/dist/cli.js.map +1 -1
  3. package/dist/core/api-contract.d.ts +15 -0
  4. package/dist/core/api-contract.d.ts.map +1 -1
  5. package/dist/core/api-contract.js +4 -1
  6. package/dist/core/api-contract.js.map +1 -1
  7. package/dist/server/shutdown-coordinator.d.ts +1 -0
  8. package/dist/server/shutdown-coordinator.d.ts.map +1 -1
  9. package/dist/server/shutdown-coordinator.js +4 -0
  10. package/dist/server/shutdown-coordinator.js.map +1 -1
  11. package/dist/server/workspace-metadata-monitor.d.ts.map +1 -1
  12. package/dist/server/workspace-metadata-monitor.js +3 -0
  13. package/dist/server/workspace-metadata-monitor.js.map +1 -1
  14. package/dist/state/workspace-state.js +2 -2
  15. package/dist/state/workspace-state.js.map +1 -1
  16. package/dist/terminal/claude-workspace-trust.d.ts.map +1 -1
  17. package/dist/terminal/claude-workspace-trust.js +2 -1
  18. package/dist/terminal/claude-workspace-trust.js.map +1 -1
  19. package/dist/terminal/session-manager.d.ts +1 -0
  20. package/dist/terminal/session-manager.d.ts.map +1 -1
  21. package/dist/terminal/session-manager.js +28 -0
  22. package/dist/terminal/session-manager.js.map +1 -1
  23. package/dist/terminal/terminal-session-service.d.ts +1 -0
  24. package/dist/terminal/terminal-session-service.d.ts.map +1 -1
  25. package/dist/terminal/terminal-session-service.js.map +1 -1
  26. package/dist/terminal/ws-server.d.ts.map +1 -1
  27. package/dist/terminal/ws-server.js +2 -0
  28. package/dist/terminal/ws-server.js.map +1 -1
  29. package/dist/trpc/app-router.d.ts +4 -1
  30. package/dist/trpc/app-router.d.ts.map +1 -1
  31. package/dist/trpc/workspace-api.d.ts.map +1 -1
  32. package/dist/trpc/workspace-api.js +1 -0
  33. package/dist/trpc/workspace-api.js.map +1 -1
  34. package/dist/web-ui/assets/{index-vGZ9z0JT.css → index-0KAf_GGl.css} +124 -26
  35. package/dist/web-ui/assets/{index-BV9iViXZ.js → index-CY5RDApA.js} +9896 -9598
  36. package/dist/web-ui/index.html +2 -2
  37. package/dist/workspace/git-history.d.ts +1 -0
  38. package/dist/workspace/git-history.d.ts.map +1 -1
  39. package/dist/workspace/git-history.js +81 -13
  40. package/dist/workspace/git-history.js.map +1 -1
  41. package/dist/workspace/git-sync.js +2 -2
  42. package/dist/workspace/git-sync.js.map +1 -1
  43. package/dist/workspace/task-worktree-path.d.ts +7 -0
  44. package/dist/workspace/task-worktree-path.d.ts.map +1 -0
  45. package/dist/workspace/task-worktree-path.js +29 -0
  46. package/dist/workspace/task-worktree-path.js.map +1 -0
  47. package/dist/workspace/task-worktree.d.ts.map +1 -1
  48. package/dist/workspace/task-worktree.js +9 -31
  49. package/dist/workspace/task-worktree.js.map +1 -1
  50. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"shutdown-coordinator.js","sourceRoot":"","sources":["../../src/server/shutdown-coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RuntimeTaskSessionSummary, RuntimeWorkspaceStateResponse } from \"../core/api-contract.js\";\nimport { updateTaskDependencies } from \"../core/task-board-mutations.js\";\nimport { loadWorkspaceState, saveWorkspaceState } from \"../state/workspace-state.js\";\nimport type { TerminalSessionManager } from \"../terminal/session-manager.js\";\nimport { deleteTaskWorktree } from \"../workspace/task-worktree.js\";\nimport type { WorkspaceRegistry } from \"./workspace-registry.js\";\nimport { collectProjectWorktreeTaskIdsForRemoval } from \"./workspace-registry.js\";\n\nexport interface RuntimeShutdownCoordinatorDependencies {\n\tworkspaceRegistry: Pick<WorkspaceRegistry, \"listManagedWorkspaces\">;\n\twarn: (message: string) => void;\n\tcloseRuntimeServer: () => Promise<void>;\n}\n\nfunction moveTaskToTrash(\n\tboard: RuntimeWorkspaceStateResponse[\"board\"],\n\ttaskId: string,\n): RuntimeWorkspaceStateResponse[\"board\"] {\n\tconst columns = board.columns.map((column) => ({\n\t\t...column,\n\t\tcards: [...column.cards],\n\t}));\n\tlet removedCard: RuntimeWorkspaceStateResponse[\"board\"][\"columns\"][number][\"cards\"][number] | undefined;\n\n\tfor (const column of columns) {\n\t\tconst cardIndex = column.cards.findIndex((candidate) => candidate.id === taskId);\n\t\tif (cardIndex === -1) {\n\t\t\tcontinue;\n\t\t}\n\t\tremovedCard = column.cards[cardIndex];\n\t\tcolumn.cards.splice(cardIndex, 1);\n\t\tbreak;\n\t}\n\n\tif (!removedCard) {\n\t\treturn board;\n\t}\n\tconst trashColumnIndex = columns.findIndex((column) => column.id === \"trash\");\n\tif (trashColumnIndex === -1) {\n\t\treturn board;\n\t}\n\tconst trashColumn = columns[trashColumnIndex];\n\tif (!trashColumn.cards.some((candidate) => candidate.id === taskId)) {\n\t\ttrashColumn.cards.unshift({\n\t\t\t...removedCard,\n\t\t\tupdatedAt: Date.now(),\n\t\t});\n\t}\n\treturn updateTaskDependencies({\n\t\t...board,\n\t\tcolumns,\n\t});\n}\n\nasync function persistInterruptedSessions(\n\tworkspacePath: string,\n\tinterruptedTaskIds: string[],\n\tterminalManager: TerminalSessionManager,\n): Promise<string[]> {\n\tif (interruptedTaskIds.length === 0) {\n\t\treturn [];\n\t}\n\tconst workspaceState = await loadWorkspaceState(workspacePath);\n\tconst worktreeTaskIds = collectProjectWorktreeTaskIdsForRemoval(workspaceState.board);\n\tconst worktreeTaskIdsToCleanup = interruptedTaskIds.filter((taskId) => worktreeTaskIds.has(taskId));\n\tlet nextBoard = workspaceState.board;\n\tfor (const taskId of interruptedTaskIds) {\n\t\tnextBoard = moveTaskToTrash(nextBoard, taskId);\n\t}\n\tconst nextSessions = {\n\t\t...workspaceState.sessions,\n\t};\n\tfor (const taskId of interruptedTaskIds) {\n\t\tconst summary = terminalManager.getSummary(taskId);\n\t\tif (summary) {\n\t\t\tnextSessions[taskId] = {\n\t\t\t\t...summary,\n\t\t\t\tstate: \"interrupted\",\n\t\t\t\treviewReason: \"interrupted\",\n\t\t\t\tupdatedAt: Date.now(),\n\t\t\t};\n\t\t}\n\t}\n\tawait saveWorkspaceState(workspacePath, {\n\t\tboard: nextBoard,\n\t\tsessions: nextSessions,\n\t});\n\treturn worktreeTaskIdsToCleanup;\n}\n\nasync function cleanupInterruptedTaskWorktrees(\n\trepoPath: string,\n\ttaskIds: string[],\n\twarn: (message: string) => void,\n): Promise<void> {\n\tif (taskIds.length === 0) {\n\t\treturn;\n\t}\n\tconst deletions = await Promise.all(\n\t\ttaskIds.map(async (taskId) => ({\n\t\t\ttaskId,\n\t\t\tdeleted: await deleteTaskWorktree({\n\t\t\t\trepoPath,\n\t\t\t\ttaskId,\n\t\t\t}),\n\t\t})),\n\t);\n\tfor (const { taskId, deleted } of deletions) {\n\t\tif (deleted.ok) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst message = deleted.error ?? `Could not delete task workspace for task \"${taskId}\" during shutdown.`;\n\t\twarn(message);\n\t}\n}\n\nfunction shouldInterruptSessionOnShutdown(summary: RuntimeTaskSessionSummary): boolean {\n\tif (summary.state === \"running\") {\n\t\treturn true;\n\t}\n\treturn summary.state === \"awaiting_review\";\n}\n\nfunction collectShutdownInterruptedTaskIds(\n\tinterruptedSummaries: RuntimeTaskSessionSummary[],\n\tterminalManager: TerminalSessionManager,\n): string[] {\n\tconst taskIds = new Set(interruptedSummaries.map((summary) => summary.taskId));\n\tfor (const summary of terminalManager.listSummaries()) {\n\t\tif (!shouldInterruptSessionOnShutdown(summary)) {\n\t\t\tcontinue;\n\t\t}\n\t\ttaskIds.add(summary.taskId);\n\t}\n\treturn Array.from(taskIds);\n}\n\nexport async function shutdownRuntimeServer(deps: RuntimeShutdownCoordinatorDependencies): Promise<void> {\n\tconst interruptedByWorkspace: Array<{\n\t\tworkspacePath: string;\n\t\tterminalManager: TerminalSessionManager;\n\t\tinterruptedTaskIds: string[];\n\t}> = [];\n\n\tfor (const { workspacePath, terminalManager } of deps.workspaceRegistry.listManagedWorkspaces()) {\n\t\tconst interrupted = terminalManager.markInterruptedAndStopAll();\n\t\tconst interruptedTaskIds = collectShutdownInterruptedTaskIds(interrupted, terminalManager);\n\t\tif (!workspacePath) {\n\t\t\tcontinue;\n\t\t}\n\t\tinterruptedByWorkspace.push({\n\t\t\tworkspacePath,\n\t\t\tterminalManager,\n\t\t\tinterruptedTaskIds,\n\t\t});\n\t}\n\n\tawait Promise.all(\n\t\tinterruptedByWorkspace.map(async (workspace) => {\n\t\t\tconst worktreeTaskIds = await persistInterruptedSessions(\n\t\t\t\tworkspace.workspacePath,\n\t\t\t\tworkspace.interruptedTaskIds,\n\t\t\t\tworkspace.terminalManager,\n\t\t\t);\n\t\t\tawait cleanupInterruptedTaskWorktrees(workspace.workspacePath, worktreeTaskIds, deps.warn);\n\t\t}),\n\t);\n\n\tawait deps.closeRuntimeServer();\n}\n"]}
1
+ {"version":3,"file":"shutdown-coordinator.js","sourceRoot":"","sources":["../../src/server/shutdown-coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RuntimeTaskSessionSummary, RuntimeWorkspaceStateResponse } from \"../core/api-contract.js\";\nimport { updateTaskDependencies } from \"../core/task-board-mutations.js\";\nimport { loadWorkspaceState, saveWorkspaceState } from \"../state/workspace-state.js\";\nimport type { TerminalSessionManager } from \"../terminal/session-manager.js\";\nimport { deleteTaskWorktree } from \"../workspace/task-worktree.js\";\nimport type { WorkspaceRegistry } from \"./workspace-registry.js\";\nimport { collectProjectWorktreeTaskIdsForRemoval } from \"./workspace-registry.js\";\n\nexport interface RuntimeShutdownCoordinatorDependencies {\n\tworkspaceRegistry: Pick<WorkspaceRegistry, \"listManagedWorkspaces\">;\n\twarn: (message: string) => void;\n\tcloseRuntimeServer: () => Promise<void>;\n\tskipSessionCleanup?: boolean;\n}\n\nfunction moveTaskToTrash(\n\tboard: RuntimeWorkspaceStateResponse[\"board\"],\n\ttaskId: string,\n): RuntimeWorkspaceStateResponse[\"board\"] {\n\tconst columns = board.columns.map((column) => ({\n\t\t...column,\n\t\tcards: [...column.cards],\n\t}));\n\tlet removedCard: RuntimeWorkspaceStateResponse[\"board\"][\"columns\"][number][\"cards\"][number] | undefined;\n\n\tfor (const column of columns) {\n\t\tconst cardIndex = column.cards.findIndex((candidate) => candidate.id === taskId);\n\t\tif (cardIndex === -1) {\n\t\t\tcontinue;\n\t\t}\n\t\tremovedCard = column.cards[cardIndex];\n\t\tcolumn.cards.splice(cardIndex, 1);\n\t\tbreak;\n\t}\n\n\tif (!removedCard) {\n\t\treturn board;\n\t}\n\tconst trashColumnIndex = columns.findIndex((column) => column.id === \"trash\");\n\tif (trashColumnIndex === -1) {\n\t\treturn board;\n\t}\n\tconst trashColumn = columns[trashColumnIndex];\n\tif (!trashColumn.cards.some((candidate) => candidate.id === taskId)) {\n\t\ttrashColumn.cards.unshift({\n\t\t\t...removedCard,\n\t\t\tupdatedAt: Date.now(),\n\t\t});\n\t}\n\treturn updateTaskDependencies({\n\t\t...board,\n\t\tcolumns,\n\t});\n}\n\nasync function persistInterruptedSessions(\n\tworkspacePath: string,\n\tinterruptedTaskIds: string[],\n\tterminalManager: TerminalSessionManager,\n): Promise<string[]> {\n\tif (interruptedTaskIds.length === 0) {\n\t\treturn [];\n\t}\n\tconst workspaceState = await loadWorkspaceState(workspacePath);\n\tconst worktreeTaskIds = collectProjectWorktreeTaskIdsForRemoval(workspaceState.board);\n\tconst worktreeTaskIdsToCleanup = interruptedTaskIds.filter((taskId) => worktreeTaskIds.has(taskId));\n\tlet nextBoard = workspaceState.board;\n\tfor (const taskId of interruptedTaskIds) {\n\t\tnextBoard = moveTaskToTrash(nextBoard, taskId);\n\t}\n\tconst nextSessions = {\n\t\t...workspaceState.sessions,\n\t};\n\tfor (const taskId of interruptedTaskIds) {\n\t\tconst summary = terminalManager.getSummary(taskId);\n\t\tif (summary) {\n\t\t\tnextSessions[taskId] = {\n\t\t\t\t...summary,\n\t\t\t\tstate: \"interrupted\",\n\t\t\t\treviewReason: \"interrupted\",\n\t\t\t\tupdatedAt: Date.now(),\n\t\t\t};\n\t\t}\n\t}\n\tawait saveWorkspaceState(workspacePath, {\n\t\tboard: nextBoard,\n\t\tsessions: nextSessions,\n\t});\n\treturn worktreeTaskIdsToCleanup;\n}\n\nasync function cleanupInterruptedTaskWorktrees(\n\trepoPath: string,\n\ttaskIds: string[],\n\twarn: (message: string) => void,\n): Promise<void> {\n\tif (taskIds.length === 0) {\n\t\treturn;\n\t}\n\tconst deletions = await Promise.all(\n\t\ttaskIds.map(async (taskId) => ({\n\t\t\ttaskId,\n\t\t\tdeleted: await deleteTaskWorktree({\n\t\t\t\trepoPath,\n\t\t\t\ttaskId,\n\t\t\t}),\n\t\t})),\n\t);\n\tfor (const { taskId, deleted } of deletions) {\n\t\tif (deleted.ok) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst message = deleted.error ?? `Could not delete task workspace for task \"${taskId}\" during shutdown.`;\n\t\twarn(message);\n\t}\n}\n\nfunction shouldInterruptSessionOnShutdown(summary: RuntimeTaskSessionSummary): boolean {\n\tif (summary.state === \"running\") {\n\t\treturn true;\n\t}\n\treturn summary.state === \"awaiting_review\";\n}\n\nfunction collectShutdownInterruptedTaskIds(\n\tinterruptedSummaries: RuntimeTaskSessionSummary[],\n\tterminalManager: TerminalSessionManager,\n): string[] {\n\tconst taskIds = new Set(interruptedSummaries.map((summary) => summary.taskId));\n\tfor (const summary of terminalManager.listSummaries()) {\n\t\tif (!shouldInterruptSessionOnShutdown(summary)) {\n\t\t\tcontinue;\n\t\t}\n\t\ttaskIds.add(summary.taskId);\n\t}\n\treturn Array.from(taskIds);\n}\n\nexport async function shutdownRuntimeServer(deps: RuntimeShutdownCoordinatorDependencies): Promise<void> {\n\tif (deps.skipSessionCleanup) {\n\t\tawait deps.closeRuntimeServer();\n\t\treturn;\n\t}\n\n\tconst interruptedByWorkspace: Array<{\n\t\tworkspacePath: string;\n\t\tterminalManager: TerminalSessionManager;\n\t\tinterruptedTaskIds: string[];\n\t}> = [];\n\n\tfor (const { workspacePath, terminalManager } of deps.workspaceRegistry.listManagedWorkspaces()) {\n\t\tconst interrupted = terminalManager.markInterruptedAndStopAll();\n\t\tconst interruptedTaskIds = collectShutdownInterruptedTaskIds(interrupted, terminalManager);\n\t\tif (!workspacePath) {\n\t\t\tcontinue;\n\t\t}\n\t\tinterruptedByWorkspace.push({\n\t\t\tworkspacePath,\n\t\t\tterminalManager,\n\t\t\tinterruptedTaskIds,\n\t\t});\n\t}\n\n\tawait Promise.all(\n\t\tinterruptedByWorkspace.map(async (workspace) => {\n\t\t\tconst worktreeTaskIds = await persistInterruptedSessions(\n\t\t\t\tworkspace.workspacePath,\n\t\t\t\tworkspace.interruptedTaskIds,\n\t\t\t\tworkspace.terminalManager,\n\t\t\t);\n\t\t\tawait cleanupInterruptedTaskWorktrees(workspace.workspacePath, worktreeTaskIds, deps.warn);\n\t\t}),\n\t);\n\n\tawait deps.closeRuntimeServer();\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-metadata-monitor.d.ts","sourceRoot":"","sources":["../../src/server/workspace-metadata-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,gBAAgB,EAGhB,wBAAwB,EACxB,MAAM,yBAAyB,CAAC;AAgCjC,MAAM,WAAW,0CAA0C;IAC1D,iBAAiB,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,wBAAwB,KAAK,IAAI,CAAC;CACrF;AAED,MAAM,WAAW,wBAAwB;IACxC,gBAAgB,EAAE,CAAC,KAAK,EAAE;QACzB,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE,gBAAgB,CAAC;KACxB,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACxC,oBAAoB,EAAE,CAAC,KAAK,EAAE;QAC7B,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE,gBAAgB,CAAC;KACxB,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACxC,mBAAmB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,gBAAgB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,KAAK,EAAE,MAAM,IAAI,CAAC;CAClB;AAmND,wBAAgB,8BAA8B,CAC7C,IAAI,EAAE,0CAA0C,GAC9C,wBAAwB,CAqH1B"}
1
+ {"version":3,"file":"workspace-metadata-monitor.d.ts","sourceRoot":"","sources":["../../src/server/workspace-metadata-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,gBAAgB,EAGhB,wBAAwB,EACxB,MAAM,yBAAyB,CAAC;AAgCjC,MAAM,WAAW,0CAA0C;IAC1D,iBAAiB,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,wBAAwB,KAAK,IAAI,CAAC;CACrF;AAED,MAAM,WAAW,wBAAwB;IACxC,gBAAgB,EAAE,CAAC,KAAK,EAAE;QACzB,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE,gBAAgB,CAAC;KACxB,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACxC,oBAAoB,EAAE,CAAC,KAAK,EAAE;QAC7B,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE,gBAAgB,CAAC;KACxB,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACxC,mBAAmB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,gBAAgB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,KAAK,EAAE,MAAM,IAAI,CAAC;CAClB;AAsND,wBAAgB,8BAA8B,CAC7C,IAAI,EAAE,0CAA0C,GAC9C,wBAAwB,CAqH1B"}
@@ -4,6 +4,9 @@ const WORKSPACE_METADATA_POLL_INTERVAL_MS = 1_000;
4
4
  function collectTrackedTasks(board) {
5
5
  const tracked = [];
6
6
  for (const column of board.columns) {
7
+ // Backlog and trash cards do not need git metadata polling. Tracking only
8
+ // active columns avoids unnecessary work, and trash paths are reconstructed
9
+ // from task id on the web-ui side.
7
10
  if (column.id === "backlog" || column.id === "trash") {
8
11
  continue;
9
12
  }
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-metadata-monitor.js","sourceRoot":"","sources":["../../src/server/workspace-metadata-monitor.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tRuntimeBoardData,\n\tRuntimeGitSyncSummary,\n\tRuntimeTaskWorkspaceMetadata,\n\tRuntimeWorkspaceMetadata,\n} from \"../core/api-contract.js\";\nimport { getGitSyncSummary, probeGitWorkspaceState } from \"../workspace/git-sync.js\";\nimport { getTaskWorkspacePathInfo } from \"../workspace/task-worktree.js\";\n\nconst WORKSPACE_METADATA_POLL_INTERVAL_MS = 1_000;\n\ninterface TrackedTaskWorkspace {\n\ttaskId: string;\n\tbaseRef: string;\n}\n\ninterface CachedHomeGitMetadata {\n\tsummary: RuntimeGitSyncSummary | null;\n\tstateToken: string | null;\n\tstateVersion: number;\n}\n\ninterface CachedTaskWorkspaceMetadata {\n\tdata: RuntimeTaskWorkspaceMetadata;\n\tstateToken: string | null;\n}\n\ninterface WorkspaceMetadataEntry {\n\tworkspacePath: string;\n\ttrackedTasks: TrackedTaskWorkspace[];\n\tsubscriberCount: number;\n\tpollTimer: NodeJS.Timeout | null;\n\trefreshPromise: Promise<RuntimeWorkspaceMetadata> | null;\n\thomeGit: CachedHomeGitMetadata;\n\ttaskMetadataByTaskId: Map<string, CachedTaskWorkspaceMetadata>;\n}\n\nexport interface CreateWorkspaceMetadataMonitorDependencies {\n\tonMetadataUpdated: (workspaceId: string, metadata: RuntimeWorkspaceMetadata) => void;\n}\n\nexport interface WorkspaceMetadataMonitor {\n\tconnectWorkspace: (input: {\n\t\tworkspaceId: string;\n\t\tworkspacePath: string;\n\t\tboard: RuntimeBoardData;\n\t}) => Promise<RuntimeWorkspaceMetadata>;\n\tupdateWorkspaceState: (input: {\n\t\tworkspaceId: string;\n\t\tworkspacePath: string;\n\t\tboard: RuntimeBoardData;\n\t}) => Promise<RuntimeWorkspaceMetadata>;\n\tdisconnectWorkspace: (workspaceId: string) => void;\n\tdisposeWorkspace: (workspaceId: string) => void;\n\tclose: () => void;\n}\n\nfunction collectTrackedTasks(board: RuntimeBoardData): TrackedTaskWorkspace[] {\n\tconst tracked: TrackedTaskWorkspace[] = [];\n\tfor (const column of board.columns) {\n\t\tif (column.id === \"backlog\" || column.id === \"trash\") {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const card of column.cards) {\n\t\t\ttracked.push({\n\t\t\t\ttaskId: card.id,\n\t\t\t\tbaseRef: card.baseRef,\n\t\t\t});\n\t\t}\n\t}\n\treturn tracked;\n}\n\nfunction areGitSummariesEqual(a: RuntimeGitSyncSummary | null, b: RuntimeGitSyncSummary | null): boolean {\n\tif (a === b) {\n\t\treturn true;\n\t}\n\tif (!a || !b) {\n\t\treturn false;\n\t}\n\treturn (\n\t\ta.currentBranch === b.currentBranch &&\n\t\ta.upstreamBranch === b.upstreamBranch &&\n\t\ta.changedFiles === b.changedFiles &&\n\t\ta.additions === b.additions &&\n\t\ta.deletions === b.deletions &&\n\t\ta.aheadCount === b.aheadCount &&\n\t\ta.behindCount === b.behindCount\n\t);\n}\n\nfunction areTaskMetadataEqual(a: RuntimeTaskWorkspaceMetadata, b: RuntimeTaskWorkspaceMetadata): boolean {\n\treturn (\n\t\ta.taskId === b.taskId &&\n\t\ta.path === b.path &&\n\t\ta.exists === b.exists &&\n\t\ta.baseRef === b.baseRef &&\n\t\ta.branch === b.branch &&\n\t\ta.isDetached === b.isDetached &&\n\t\ta.headCommit === b.headCommit &&\n\t\ta.changedFiles === b.changedFiles &&\n\t\ta.additions === b.additions &&\n\t\ta.deletions === b.deletions &&\n\t\ta.stateVersion === b.stateVersion\n\t);\n}\n\nfunction areWorkspaceMetadataEqual(a: RuntimeWorkspaceMetadata, b: RuntimeWorkspaceMetadata): boolean {\n\tif (!areGitSummariesEqual(a.homeGitSummary, b.homeGitSummary)) {\n\t\treturn false;\n\t}\n\tif (a.homeGitStateVersion !== b.homeGitStateVersion) {\n\t\treturn false;\n\t}\n\tif (a.taskWorkspaces.length !== b.taskWorkspaces.length) {\n\t\treturn false;\n\t}\n\tfor (let index = 0; index < a.taskWorkspaces.length; index += 1) {\n\t\tconst left = a.taskWorkspaces[index];\n\t\tconst right = b.taskWorkspaces[index];\n\t\tif (!left || !right || !areTaskMetadataEqual(left, right)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nfunction createEmptyWorkspaceMetadata(): RuntimeWorkspaceMetadata {\n\treturn {\n\t\thomeGitSummary: null,\n\t\thomeGitStateVersion: 0,\n\t\ttaskWorkspaces: [],\n\t};\n}\n\nfunction createWorkspaceEntry(workspacePath: string): WorkspaceMetadataEntry {\n\treturn {\n\t\tworkspacePath,\n\t\ttrackedTasks: [],\n\t\tsubscriberCount: 0,\n\t\tpollTimer: null,\n\t\trefreshPromise: null,\n\t\thomeGit: {\n\t\t\tsummary: null,\n\t\t\tstateToken: null,\n\t\t\tstateVersion: 0,\n\t\t},\n\t\ttaskMetadataByTaskId: new Map<string, CachedTaskWorkspaceMetadata>(),\n\t};\n}\n\nfunction buildWorkspaceMetadataSnapshot(entry: WorkspaceMetadataEntry): RuntimeWorkspaceMetadata {\n\treturn {\n\t\thomeGitSummary: entry.homeGit.summary,\n\t\thomeGitStateVersion: entry.homeGit.stateVersion,\n\t\ttaskWorkspaces: entry.trackedTasks\n\t\t\t.map((task) => entry.taskMetadataByTaskId.get(task.taskId)?.data ?? null)\n\t\t\t.filter((task): task is RuntimeTaskWorkspaceMetadata => task !== null),\n\t};\n}\n\nasync function loadHomeGitMetadata(entry: WorkspaceMetadataEntry): Promise<CachedHomeGitMetadata> {\n\ttry {\n\t\tconst probe = await probeGitWorkspaceState(entry.workspacePath);\n\t\tif (entry.homeGit.stateToken === probe.stateToken) {\n\t\t\treturn entry.homeGit;\n\t\t}\n\t\tconst summary = await getGitSyncSummary(entry.workspacePath, { probe });\n\t\treturn {\n\t\t\tsummary,\n\t\t\tstateToken: probe.stateToken,\n\t\t\tstateVersion: Date.now(),\n\t\t};\n\t} catch {\n\t\treturn entry.homeGit;\n\t}\n}\n\nasync function loadTaskWorkspaceMetadata(\n\tworkspacePath: string,\n\ttask: TrackedTaskWorkspace,\n\tcurrent: CachedTaskWorkspaceMetadata | null,\n): Promise<CachedTaskWorkspaceMetadata | null> {\n\tconst pathInfo = await getTaskWorkspacePathInfo({\n\t\tcwd: workspacePath,\n\t\ttaskId: task.taskId,\n\t\tbaseRef: task.baseRef,\n\t});\n\n\tif (!pathInfo.exists) {\n\t\tif (\n\t\t\tcurrent &&\n\t\t\tcurrent.data.exists === false &&\n\t\t\tcurrent.data.path === pathInfo.path &&\n\t\t\tcurrent.data.baseRef === pathInfo.baseRef\n\t\t) {\n\t\t\treturn current;\n\t\t}\n\t\treturn {\n\t\t\tdata: {\n\t\t\t\ttaskId: task.taskId,\n\t\t\t\tpath: pathInfo.path,\n\t\t\t\texists: false,\n\t\t\t\tbaseRef: pathInfo.baseRef,\n\t\t\t\tbranch: null,\n\t\t\t\tisDetached: false,\n\t\t\t\theadCommit: null,\n\t\t\t\tchangedFiles: null,\n\t\t\t\tadditions: null,\n\t\t\t\tdeletions: null,\n\t\t\t\tstateVersion: Date.now(),\n\t\t\t},\n\t\t\tstateToken: null,\n\t\t};\n\t}\n\n\ttry {\n\t\tconst probe = await probeGitWorkspaceState(pathInfo.path);\n\t\tif (\n\t\t\tcurrent &&\n\t\t\tcurrent.stateToken === probe.stateToken &&\n\t\t\tcurrent.data.path === pathInfo.path &&\n\t\t\tcurrent.data.baseRef === pathInfo.baseRef\n\t\t) {\n\t\t\treturn current;\n\t\t}\n\t\tconst summary = await getGitSyncSummary(pathInfo.path, { probe });\n\t\treturn {\n\t\t\tdata: {\n\t\t\t\ttaskId: task.taskId,\n\t\t\t\tpath: pathInfo.path,\n\t\t\t\texists: true,\n\t\t\t\tbaseRef: pathInfo.baseRef,\n\t\t\t\tbranch: probe.currentBranch,\n\t\t\t\tisDetached: probe.headCommit !== null && probe.currentBranch === null,\n\t\t\t\theadCommit: probe.headCommit,\n\t\t\t\tchangedFiles: summary.changedFiles,\n\t\t\t\tadditions: summary.additions,\n\t\t\t\tdeletions: summary.deletions,\n\t\t\t\tstateVersion: Date.now(),\n\t\t\t},\n\t\t\tstateToken: probe.stateToken,\n\t\t};\n\t} catch {\n\t\tif (current) {\n\t\t\treturn current;\n\t\t}\n\t\treturn {\n\t\t\tdata: {\n\t\t\t\ttaskId: task.taskId,\n\t\t\t\tpath: pathInfo.path,\n\t\t\t\texists: true,\n\t\t\t\tbaseRef: pathInfo.baseRef,\n\t\t\t\tbranch: null,\n\t\t\t\tisDetached: false,\n\t\t\t\theadCommit: null,\n\t\t\t\tchangedFiles: null,\n\t\t\t\tadditions: null,\n\t\t\t\tdeletions: null,\n\t\t\t\tstateVersion: Date.now(),\n\t\t\t},\n\t\t\tstateToken: null,\n\t\t};\n\t}\n}\n\nexport function createWorkspaceMetadataMonitor(\n\tdeps: CreateWorkspaceMetadataMonitorDependencies,\n): WorkspaceMetadataMonitor {\n\tconst workspaces = new Map<string, WorkspaceMetadataEntry>();\n\n\tconst stopWorkspaceTimer = (entry: WorkspaceMetadataEntry) => {\n\t\tif (!entry.pollTimer) {\n\t\t\treturn;\n\t\t}\n\t\tclearInterval(entry.pollTimer);\n\t\tentry.pollTimer = null;\n\t};\n\n\tconst refreshWorkspace = async (workspaceId: string): Promise<RuntimeWorkspaceMetadata> => {\n\t\tconst entry = workspaces.get(workspaceId);\n\t\tif (!entry) {\n\t\t\treturn createEmptyWorkspaceMetadata();\n\t\t}\n\t\tif (entry.refreshPromise) {\n\t\t\treturn await entry.refreshPromise;\n\t\t}\n\n\t\tentry.refreshPromise = (async () => {\n\t\t\tconst previousSnapshot = buildWorkspaceMetadataSnapshot(entry);\n\t\t\tentry.homeGit = await loadHomeGitMetadata(entry);\n\n\t\t\tconst nextTaskEntries = await Promise.all(\n\t\t\t\tentry.trackedTasks.map(async (task) => {\n\t\t\t\t\tconst current = entry.taskMetadataByTaskId.get(task.taskId) ?? null;\n\t\t\t\t\tconst next = await loadTaskWorkspaceMetadata(entry.workspacePath, task, current);\n\t\t\t\t\treturn next ? [task.taskId, next] : null;\n\t\t\t\t}),\n\t\t\t);\n\n\t\t\tentry.taskMetadataByTaskId = new Map(\n\t\t\t\tnextTaskEntries.filter(\n\t\t\t\t\t(candidate): candidate is [string, CachedTaskWorkspaceMetadata] => candidate !== null,\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tconst nextSnapshot = buildWorkspaceMetadataSnapshot(entry);\n\t\t\tif (!areWorkspaceMetadataEqual(previousSnapshot, nextSnapshot)) {\n\t\t\t\tdeps.onMetadataUpdated(workspaceId, nextSnapshot);\n\t\t\t}\n\t\t\treturn nextSnapshot;\n\t\t})().finally(() => {\n\t\t\tconst current = workspaces.get(workspaceId);\n\t\t\tif (current) {\n\t\t\t\tcurrent.refreshPromise = null;\n\t\t\t}\n\t\t});\n\n\t\treturn await entry.refreshPromise;\n\t};\n\n\tconst updateWorkspaceEntry = (input: {\n\t\tworkspaceId: string;\n\t\tworkspacePath: string;\n\t\tboard: RuntimeBoardData;\n\t}): WorkspaceMetadataEntry => {\n\t\tconst existing = workspaces.get(input.workspaceId) ?? createWorkspaceEntry(input.workspacePath);\n\t\texisting.workspacePath = input.workspacePath;\n\t\texisting.trackedTasks = collectTrackedTasks(input.board);\n\t\tworkspaces.set(input.workspaceId, existing);\n\t\treturn existing;\n\t};\n\n\tconst ensureWorkspaceTimer = (workspaceId: string, entry: WorkspaceMetadataEntry) => {\n\t\tif (entry.pollTimer) {\n\t\t\treturn;\n\t\t}\n\t\tconst timer = setInterval(() => {\n\t\t\tvoid refreshWorkspace(workspaceId);\n\t\t}, WORKSPACE_METADATA_POLL_INTERVAL_MS);\n\t\ttimer.unref();\n\t\tentry.pollTimer = timer;\n\t};\n\n\treturn {\n\t\tconnectWorkspace: async ({ workspaceId, workspacePath, board }) => {\n\t\t\tconst entry = updateWorkspaceEntry({ workspaceId, workspacePath, board });\n\t\t\tentry.subscriberCount += 1;\n\t\t\tensureWorkspaceTimer(workspaceId, entry);\n\t\t\treturn await refreshWorkspace(workspaceId);\n\t\t},\n\t\tupdateWorkspaceState: async ({ workspaceId, workspacePath, board }) => {\n\t\t\tconst entry = updateWorkspaceEntry({ workspaceId, workspacePath, board });\n\t\t\tif (entry.subscriberCount === 0) {\n\t\t\t\treturn buildWorkspaceMetadataSnapshot(entry);\n\t\t\t}\n\t\t\treturn await refreshWorkspace(workspaceId);\n\t\t},\n\t\tdisconnectWorkspace: (workspaceId) => {\n\t\t\tconst entry = workspaces.get(workspaceId);\n\t\t\tif (!entry) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tentry.subscriberCount = Math.max(0, entry.subscriberCount - 1);\n\t\t\tif (entry.subscriberCount > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstopWorkspaceTimer(entry);\n\t\t\tworkspaces.delete(workspaceId);\n\t\t},\n\t\tdisposeWorkspace: (workspaceId) => {\n\t\t\tconst entry = workspaces.get(workspaceId);\n\t\t\tif (!entry) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstopWorkspaceTimer(entry);\n\t\t\tworkspaces.delete(workspaceId);\n\t\t},\n\t\tclose: () => {\n\t\t\tfor (const entry of workspaces.values()) {\n\t\t\t\tstopWorkspaceTimer(entry);\n\t\t\t}\n\t\t\tworkspaces.clear();\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"workspace-metadata-monitor.js","sourceRoot":"","sources":["../../src/server/workspace-metadata-monitor.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tRuntimeBoardData,\n\tRuntimeGitSyncSummary,\n\tRuntimeTaskWorkspaceMetadata,\n\tRuntimeWorkspaceMetadata,\n} from \"../core/api-contract.js\";\nimport { getGitSyncSummary, probeGitWorkspaceState } from \"../workspace/git-sync.js\";\nimport { getTaskWorkspacePathInfo } from \"../workspace/task-worktree.js\";\n\nconst WORKSPACE_METADATA_POLL_INTERVAL_MS = 1_000;\n\ninterface TrackedTaskWorkspace {\n\ttaskId: string;\n\tbaseRef: string;\n}\n\ninterface CachedHomeGitMetadata {\n\tsummary: RuntimeGitSyncSummary | null;\n\tstateToken: string | null;\n\tstateVersion: number;\n}\n\ninterface CachedTaskWorkspaceMetadata {\n\tdata: RuntimeTaskWorkspaceMetadata;\n\tstateToken: string | null;\n}\n\ninterface WorkspaceMetadataEntry {\n\tworkspacePath: string;\n\ttrackedTasks: TrackedTaskWorkspace[];\n\tsubscriberCount: number;\n\tpollTimer: NodeJS.Timeout | null;\n\trefreshPromise: Promise<RuntimeWorkspaceMetadata> | null;\n\thomeGit: CachedHomeGitMetadata;\n\ttaskMetadataByTaskId: Map<string, CachedTaskWorkspaceMetadata>;\n}\n\nexport interface CreateWorkspaceMetadataMonitorDependencies {\n\tonMetadataUpdated: (workspaceId: string, metadata: RuntimeWorkspaceMetadata) => void;\n}\n\nexport interface WorkspaceMetadataMonitor {\n\tconnectWorkspace: (input: {\n\t\tworkspaceId: string;\n\t\tworkspacePath: string;\n\t\tboard: RuntimeBoardData;\n\t}) => Promise<RuntimeWorkspaceMetadata>;\n\tupdateWorkspaceState: (input: {\n\t\tworkspaceId: string;\n\t\tworkspacePath: string;\n\t\tboard: RuntimeBoardData;\n\t}) => Promise<RuntimeWorkspaceMetadata>;\n\tdisconnectWorkspace: (workspaceId: string) => void;\n\tdisposeWorkspace: (workspaceId: string) => void;\n\tclose: () => void;\n}\n\nfunction collectTrackedTasks(board: RuntimeBoardData): TrackedTaskWorkspace[] {\n\tconst tracked: TrackedTaskWorkspace[] = [];\n\tfor (const column of board.columns) {\n\t\t// Backlog and trash cards do not need git metadata polling. Tracking only\n\t\t// active columns avoids unnecessary work, and trash paths are reconstructed\n\t\t// from task id on the web-ui side.\n\t\tif (column.id === \"backlog\" || column.id === \"trash\") {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const card of column.cards) {\n\t\t\ttracked.push({\n\t\t\t\ttaskId: card.id,\n\t\t\t\tbaseRef: card.baseRef,\n\t\t\t});\n\t\t}\n\t}\n\treturn tracked;\n}\n\nfunction areGitSummariesEqual(a: RuntimeGitSyncSummary | null, b: RuntimeGitSyncSummary | null): boolean {\n\tif (a === b) {\n\t\treturn true;\n\t}\n\tif (!a || !b) {\n\t\treturn false;\n\t}\n\treturn (\n\t\ta.currentBranch === b.currentBranch &&\n\t\ta.upstreamBranch === b.upstreamBranch &&\n\t\ta.changedFiles === b.changedFiles &&\n\t\ta.additions === b.additions &&\n\t\ta.deletions === b.deletions &&\n\t\ta.aheadCount === b.aheadCount &&\n\t\ta.behindCount === b.behindCount\n\t);\n}\n\nfunction areTaskMetadataEqual(a: RuntimeTaskWorkspaceMetadata, b: RuntimeTaskWorkspaceMetadata): boolean {\n\treturn (\n\t\ta.taskId === b.taskId &&\n\t\ta.path === b.path &&\n\t\ta.exists === b.exists &&\n\t\ta.baseRef === b.baseRef &&\n\t\ta.branch === b.branch &&\n\t\ta.isDetached === b.isDetached &&\n\t\ta.headCommit === b.headCommit &&\n\t\ta.changedFiles === b.changedFiles &&\n\t\ta.additions === b.additions &&\n\t\ta.deletions === b.deletions &&\n\t\ta.stateVersion === b.stateVersion\n\t);\n}\n\nfunction areWorkspaceMetadataEqual(a: RuntimeWorkspaceMetadata, b: RuntimeWorkspaceMetadata): boolean {\n\tif (!areGitSummariesEqual(a.homeGitSummary, b.homeGitSummary)) {\n\t\treturn false;\n\t}\n\tif (a.homeGitStateVersion !== b.homeGitStateVersion) {\n\t\treturn false;\n\t}\n\tif (a.taskWorkspaces.length !== b.taskWorkspaces.length) {\n\t\treturn false;\n\t}\n\tfor (let index = 0; index < a.taskWorkspaces.length; index += 1) {\n\t\tconst left = a.taskWorkspaces[index];\n\t\tconst right = b.taskWorkspaces[index];\n\t\tif (!left || !right || !areTaskMetadataEqual(left, right)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nfunction createEmptyWorkspaceMetadata(): RuntimeWorkspaceMetadata {\n\treturn {\n\t\thomeGitSummary: null,\n\t\thomeGitStateVersion: 0,\n\t\ttaskWorkspaces: [],\n\t};\n}\n\nfunction createWorkspaceEntry(workspacePath: string): WorkspaceMetadataEntry {\n\treturn {\n\t\tworkspacePath,\n\t\ttrackedTasks: [],\n\t\tsubscriberCount: 0,\n\t\tpollTimer: null,\n\t\trefreshPromise: null,\n\t\thomeGit: {\n\t\t\tsummary: null,\n\t\t\tstateToken: null,\n\t\t\tstateVersion: 0,\n\t\t},\n\t\ttaskMetadataByTaskId: new Map<string, CachedTaskWorkspaceMetadata>(),\n\t};\n}\n\nfunction buildWorkspaceMetadataSnapshot(entry: WorkspaceMetadataEntry): RuntimeWorkspaceMetadata {\n\treturn {\n\t\thomeGitSummary: entry.homeGit.summary,\n\t\thomeGitStateVersion: entry.homeGit.stateVersion,\n\t\ttaskWorkspaces: entry.trackedTasks\n\t\t\t.map((task) => entry.taskMetadataByTaskId.get(task.taskId)?.data ?? null)\n\t\t\t.filter((task): task is RuntimeTaskWorkspaceMetadata => task !== null),\n\t};\n}\n\nasync function loadHomeGitMetadata(entry: WorkspaceMetadataEntry): Promise<CachedHomeGitMetadata> {\n\ttry {\n\t\tconst probe = await probeGitWorkspaceState(entry.workspacePath);\n\t\tif (entry.homeGit.stateToken === probe.stateToken) {\n\t\t\treturn entry.homeGit;\n\t\t}\n\t\tconst summary = await getGitSyncSummary(entry.workspacePath, { probe });\n\t\treturn {\n\t\t\tsummary,\n\t\t\tstateToken: probe.stateToken,\n\t\t\tstateVersion: Date.now(),\n\t\t};\n\t} catch {\n\t\treturn entry.homeGit;\n\t}\n}\n\nasync function loadTaskWorkspaceMetadata(\n\tworkspacePath: string,\n\ttask: TrackedTaskWorkspace,\n\tcurrent: CachedTaskWorkspaceMetadata | null,\n): Promise<CachedTaskWorkspaceMetadata | null> {\n\tconst pathInfo = await getTaskWorkspacePathInfo({\n\t\tcwd: workspacePath,\n\t\ttaskId: task.taskId,\n\t\tbaseRef: task.baseRef,\n\t});\n\n\tif (!pathInfo.exists) {\n\t\tif (\n\t\t\tcurrent &&\n\t\t\tcurrent.data.exists === false &&\n\t\t\tcurrent.data.path === pathInfo.path &&\n\t\t\tcurrent.data.baseRef === pathInfo.baseRef\n\t\t) {\n\t\t\treturn current;\n\t\t}\n\t\treturn {\n\t\t\tdata: {\n\t\t\t\ttaskId: task.taskId,\n\t\t\t\tpath: pathInfo.path,\n\t\t\t\texists: false,\n\t\t\t\tbaseRef: pathInfo.baseRef,\n\t\t\t\tbranch: null,\n\t\t\t\tisDetached: false,\n\t\t\t\theadCommit: null,\n\t\t\t\tchangedFiles: null,\n\t\t\t\tadditions: null,\n\t\t\t\tdeletions: null,\n\t\t\t\tstateVersion: Date.now(),\n\t\t\t},\n\t\t\tstateToken: null,\n\t\t};\n\t}\n\n\ttry {\n\t\tconst probe = await probeGitWorkspaceState(pathInfo.path);\n\t\tif (\n\t\t\tcurrent &&\n\t\t\tcurrent.stateToken === probe.stateToken &&\n\t\t\tcurrent.data.path === pathInfo.path &&\n\t\t\tcurrent.data.baseRef === pathInfo.baseRef\n\t\t) {\n\t\t\treturn current;\n\t\t}\n\t\tconst summary = await getGitSyncSummary(pathInfo.path, { probe });\n\t\treturn {\n\t\t\tdata: {\n\t\t\t\ttaskId: task.taskId,\n\t\t\t\tpath: pathInfo.path,\n\t\t\t\texists: true,\n\t\t\t\tbaseRef: pathInfo.baseRef,\n\t\t\t\tbranch: probe.currentBranch,\n\t\t\t\tisDetached: probe.headCommit !== null && probe.currentBranch === null,\n\t\t\t\theadCommit: probe.headCommit,\n\t\t\t\tchangedFiles: summary.changedFiles,\n\t\t\t\tadditions: summary.additions,\n\t\t\t\tdeletions: summary.deletions,\n\t\t\t\tstateVersion: Date.now(),\n\t\t\t},\n\t\t\tstateToken: probe.stateToken,\n\t\t};\n\t} catch {\n\t\tif (current) {\n\t\t\treturn current;\n\t\t}\n\t\treturn {\n\t\t\tdata: {\n\t\t\t\ttaskId: task.taskId,\n\t\t\t\tpath: pathInfo.path,\n\t\t\t\texists: true,\n\t\t\t\tbaseRef: pathInfo.baseRef,\n\t\t\t\tbranch: null,\n\t\t\t\tisDetached: false,\n\t\t\t\theadCommit: null,\n\t\t\t\tchangedFiles: null,\n\t\t\t\tadditions: null,\n\t\t\t\tdeletions: null,\n\t\t\t\tstateVersion: Date.now(),\n\t\t\t},\n\t\t\tstateToken: null,\n\t\t};\n\t}\n}\n\nexport function createWorkspaceMetadataMonitor(\n\tdeps: CreateWorkspaceMetadataMonitorDependencies,\n): WorkspaceMetadataMonitor {\n\tconst workspaces = new Map<string, WorkspaceMetadataEntry>();\n\n\tconst stopWorkspaceTimer = (entry: WorkspaceMetadataEntry) => {\n\t\tif (!entry.pollTimer) {\n\t\t\treturn;\n\t\t}\n\t\tclearInterval(entry.pollTimer);\n\t\tentry.pollTimer = null;\n\t};\n\n\tconst refreshWorkspace = async (workspaceId: string): Promise<RuntimeWorkspaceMetadata> => {\n\t\tconst entry = workspaces.get(workspaceId);\n\t\tif (!entry) {\n\t\t\treturn createEmptyWorkspaceMetadata();\n\t\t}\n\t\tif (entry.refreshPromise) {\n\t\t\treturn await entry.refreshPromise;\n\t\t}\n\n\t\tentry.refreshPromise = (async () => {\n\t\t\tconst previousSnapshot = buildWorkspaceMetadataSnapshot(entry);\n\t\t\tentry.homeGit = await loadHomeGitMetadata(entry);\n\n\t\t\tconst nextTaskEntries = await Promise.all(\n\t\t\t\tentry.trackedTasks.map(async (task) => {\n\t\t\t\t\tconst current = entry.taskMetadataByTaskId.get(task.taskId) ?? null;\n\t\t\t\t\tconst next = await loadTaskWorkspaceMetadata(entry.workspacePath, task, current);\n\t\t\t\t\treturn next ? [task.taskId, next] : null;\n\t\t\t\t}),\n\t\t\t);\n\n\t\t\tentry.taskMetadataByTaskId = new Map(\n\t\t\t\tnextTaskEntries.filter(\n\t\t\t\t\t(candidate): candidate is [string, CachedTaskWorkspaceMetadata] => candidate !== null,\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tconst nextSnapshot = buildWorkspaceMetadataSnapshot(entry);\n\t\t\tif (!areWorkspaceMetadataEqual(previousSnapshot, nextSnapshot)) {\n\t\t\t\tdeps.onMetadataUpdated(workspaceId, nextSnapshot);\n\t\t\t}\n\t\t\treturn nextSnapshot;\n\t\t})().finally(() => {\n\t\t\tconst current = workspaces.get(workspaceId);\n\t\t\tif (current) {\n\t\t\t\tcurrent.refreshPromise = null;\n\t\t\t}\n\t\t});\n\n\t\treturn await entry.refreshPromise;\n\t};\n\n\tconst updateWorkspaceEntry = (input: {\n\t\tworkspaceId: string;\n\t\tworkspacePath: string;\n\t\tboard: RuntimeBoardData;\n\t}): WorkspaceMetadataEntry => {\n\t\tconst existing = workspaces.get(input.workspaceId) ?? createWorkspaceEntry(input.workspacePath);\n\t\texisting.workspacePath = input.workspacePath;\n\t\texisting.trackedTasks = collectTrackedTasks(input.board);\n\t\tworkspaces.set(input.workspaceId, existing);\n\t\treturn existing;\n\t};\n\n\tconst ensureWorkspaceTimer = (workspaceId: string, entry: WorkspaceMetadataEntry) => {\n\t\tif (entry.pollTimer) {\n\t\t\treturn;\n\t\t}\n\t\tconst timer = setInterval(() => {\n\t\t\tvoid refreshWorkspace(workspaceId);\n\t\t}, WORKSPACE_METADATA_POLL_INTERVAL_MS);\n\t\ttimer.unref();\n\t\tentry.pollTimer = timer;\n\t};\n\n\treturn {\n\t\tconnectWorkspace: async ({ workspaceId, workspacePath, board }) => {\n\t\t\tconst entry = updateWorkspaceEntry({ workspaceId, workspacePath, board });\n\t\t\tentry.subscriberCount += 1;\n\t\t\tensureWorkspaceTimer(workspaceId, entry);\n\t\t\treturn await refreshWorkspace(workspaceId);\n\t\t},\n\t\tupdateWorkspaceState: async ({ workspaceId, workspacePath, board }) => {\n\t\t\tconst entry = updateWorkspaceEntry({ workspaceId, workspacePath, board });\n\t\t\tif (entry.subscriberCount === 0) {\n\t\t\t\treturn buildWorkspaceMetadataSnapshot(entry);\n\t\t\t}\n\t\t\treturn await refreshWorkspace(workspaceId);\n\t\t},\n\t\tdisconnectWorkspace: (workspaceId) => {\n\t\t\tconst entry = workspaces.get(workspaceId);\n\t\t\tif (!entry) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tentry.subscriberCount = Math.max(0, entry.subscriberCount - 1);\n\t\t\tif (entry.subscriberCount > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstopWorkspaceTimer(entry);\n\t\t\tworkspaces.delete(workspaceId);\n\t\t},\n\t\tdisposeWorkspace: (workspaceId) => {\n\t\t\tconst entry = workspaces.get(workspaceId);\n\t\t\tif (!entry) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstopWorkspaceTimer(entry);\n\t\t\tworkspaces.delete(workspaceId);\n\t\t},\n\t\tclose: () => {\n\t\t\tfor (const entry of workspaces.values()) {\n\t\t\t\tstopWorkspaceTimer(entry);\n\t\t\t}\n\t\t\tworkspaces.clear();\n\t\t},\n\t};\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { spawnSync } from "node:child_process";
2
- import { randomBytes } from "node:crypto";
2
+ import { randomBytes, randomUUID } from "node:crypto";
3
3
  import { mkdir, readFile, realpath, rename, rm, writeFile } from "node:fs/promises";
4
4
  import { homedir } from "node:os";
5
5
  import { basename, dirname, join, resolve } from "node:path";
@@ -147,7 +147,7 @@ async function readJsonFile(path) {
147
147
  }
148
148
  async function writeJsonFileAtomic(path, payload) {
149
149
  await mkdir(dirname(path), { recursive: true });
150
- const tempPath = `${path}.tmp.${process.pid}.${Date.now()}`;
150
+ const tempPath = `${path}.tmp.${process.pid}.${Date.now()}.${randomUUID()}`;
151
151
  await writeFile(tempPath, JSON.stringify(payload, null, 2), "utf8");
152
152
  await rename(tempPath, path);
153
153
  }
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-state.js","sourceRoot":"","sources":["../../src/state/workspace-state.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport { mkdir, readFile, realpath, rename, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { z } from \"zod\";\n\nimport {\n\ttype RuntimeBoardColumnId,\n\ttype RuntimeBoardData,\n\ttype RuntimeGitRepositoryInfo,\n\ttype RuntimeTaskSessionSummary,\n\ttype RuntimeWorkspaceStateResponse,\n\ttype RuntimeWorkspaceStateSaveRequest,\n\truntimeBoardDataSchema,\n\truntimeTaskSessionSummarySchema,\n\truntimeWorkspaceStateSaveRequestSchema,\n} from \"../core/api-contract.js\";\nimport { createGitProcessEnv } from \"../core/git-process-env.js\";\nimport { updateTaskDependencies } from \"../core/task-board-mutations.js\";\n\nconst RUNTIME_HOME_DIR = \".kanban\";\nconst WORKSPACES_DIR = \"workspaces\";\nconst INDEX_FILENAME = \"index.json\";\nconst BOARD_FILENAME = \"board.json\";\nconst SESSIONS_FILENAME = \"sessions.json\";\nconst META_FILENAME = \"meta.json\";\nconst INDEX_VERSION = 1;\nconst WORKSPACE_ID_COLLISION_SUFFIX_LENGTH = 4;\n\nconst BOARD_COLUMNS: Array<{ id: RuntimeBoardColumnId; title: string }> = [\n\t{ id: \"backlog\", title: \"Backlog\" },\n\t{ id: \"in_progress\", title: \"In Progress\" },\n\t{ id: \"review\", title: \"Review\" },\n\t{ id: \"trash\", title: \"Trash\" },\n];\n\ninterface WorkspaceIndexEntry {\n\tworkspaceId: string;\n\trepoPath: string;\n}\n\nexport interface RuntimeWorkspaceIndexEntry {\n\tworkspaceId: string;\n\trepoPath: string;\n}\n\ninterface WorkspaceIndexFile {\n\tversion: number;\n\tentries: Record<string, WorkspaceIndexEntry>;\n\trepoPathToId: Record<string, string>;\n}\n\ninterface WorkspaceStateMeta {\n\trevision: number;\n\tupdatedAt: number;\n}\n\nconst workspaceStateMetaSchema = z.object({\n\trevision: z.number().int().nonnegative(),\n\tupdatedAt: z.number(),\n});\n\nconst workspaceIndexEntrySchema = z.object({\n\tworkspaceId: z.string().min(1, \"Workspace ID cannot be empty.\"),\n\trepoPath: z.string().min(1, \"Workspace repository path cannot be empty.\"),\n});\n\nconst workspaceIndexFileSchema = z\n\t.object({\n\t\tversion: z.literal(INDEX_VERSION),\n\t\tentries: z.record(z.string(), workspaceIndexEntrySchema),\n\t\trepoPathToId: z.record(z.string(), z.string().min(1, \"Workspace ID cannot be empty.\")),\n\t})\n\t.superRefine((index, context) => {\n\t\tfor (const [workspaceId, entry] of Object.entries(index.entries)) {\n\t\t\tif (entry.workspaceId !== workspaceId) {\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tpath: [\"entries\", workspaceId, \"workspaceId\"],\n\t\t\t\t\tmessage: `Workspace ID must match entry key \"${workspaceId}\".`,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst mappedWorkspaceId = index.repoPathToId[entry.repoPath];\n\t\t\tif (mappedWorkspaceId !== workspaceId) {\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tpath: [\"entries\", workspaceId, \"repoPath\"],\n\t\t\t\t\tmessage: `Missing repoPathToId mapping for \"${entry.repoPath}\" to \"${workspaceId}\".`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tfor (const [repoPath, workspaceId] of Object.entries(index.repoPathToId)) {\n\t\t\tconst entry = index.entries[workspaceId];\n\t\t\tif (!entry) {\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tpath: [\"repoPathToId\", repoPath],\n\t\t\t\t\tmessage: `Mapped workspace \"${workspaceId}\" does not exist in entries.`,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (entry.repoPath !== repoPath) {\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tpath: [\"repoPathToId\", repoPath],\n\t\t\t\t\tmessage: `Mapped repoPath does not match workspace entry path \"${entry.repoPath}\".`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\nconst workspaceSessionsSchema = z\n\t.record(z.string(), runtimeTaskSessionSummarySchema)\n\t.superRefine((sessions, context) => {\n\t\tfor (const [taskId, session] of Object.entries(sessions)) {\n\t\t\tif (session.taskId !== taskId) {\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tpath: [taskId, \"taskId\"],\n\t\t\t\t\tmessage: `Session taskId must match record key \"${taskId}\".`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\nexport interface RuntimeWorkspaceContext {\n\trepoPath: string;\n\tworkspaceId: string;\n\tstatePath: string;\n\tgit: RuntimeGitRepositoryInfo;\n}\n\nexport interface LoadWorkspaceContextOptions {\n\tautoCreateIfMissing?: boolean;\n}\n\nfunction createEmptyBoard(): RuntimeBoardData {\n\treturn {\n\t\tcolumns: BOARD_COLUMNS.map((column) => ({\n\t\t\tid: column.id,\n\t\t\ttitle: column.title,\n\t\t\tcards: [],\n\t\t})),\n\t\tdependencies: [],\n\t};\n}\n\nfunction createEmptyWorkspaceIndex(): WorkspaceIndexFile {\n\treturn {\n\t\tversion: INDEX_VERSION,\n\t\tentries: {},\n\t\trepoPathToId: {},\n\t};\n}\n\nexport function getRuntimeHomePath(): string {\n\treturn join(homedir(), RUNTIME_HOME_DIR);\n}\n\nexport function getWorkspacesRootPath(): string {\n\treturn join(getRuntimeHomePath(), WORKSPACES_DIR);\n}\n\nfunction getWorkspaceIndexPath(): string {\n\treturn join(getWorkspacesRootPath(), INDEX_FILENAME);\n}\n\nexport function getWorkspaceDirectoryPath(workspaceId: string): string {\n\treturn join(getWorkspacesRootPath(), workspaceId);\n}\n\nfunction getWorkspaceBoardPath(workspaceId: string): string {\n\treturn join(getWorkspaceDirectoryPath(workspaceId), BOARD_FILENAME);\n}\n\nfunction getWorkspaceSessionsPath(workspaceId: string): string {\n\treturn join(getWorkspaceDirectoryPath(workspaceId), SESSIONS_FILENAME);\n}\n\nfunction getWorkspaceMetaPath(workspaceId: string): string {\n\treturn join(getWorkspaceDirectoryPath(workspaceId), META_FILENAME);\n}\n\nfunction isNodeErrorWithCode(error: unknown, code: string): boolean {\n\treturn typeof error === \"object\" && error !== null && \"code\" in error && (error as { code?: unknown }).code === code;\n}\n\nasync function readJsonFile(path: string): Promise<unknown | null> {\n\ttry {\n\t\tconst raw = await readFile(path, \"utf8\");\n\t\ttry {\n\t\t\treturn JSON.parse(raw) as unknown;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Malformed JSON in ${path}. ${message}`);\n\t\t}\n\t} catch (error) {\n\t\tif (isNodeErrorWithCode(error, \"ENOENT\")) {\n\t\t\treturn null;\n\t\t}\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(`Could not read JSON file at ${path}. ${message}`);\n\t}\n}\n\nasync function writeJsonFileAtomic(path: string, payload: unknown): Promise<void> {\n\tawait mkdir(dirname(path), { recursive: true });\n\tconst tempPath = `${path}.tmp.${process.pid}.${Date.now()}`;\n\tawait writeFile(tempPath, JSON.stringify(payload, null, 2), \"utf8\");\n\tawait rename(tempPath, path);\n}\n\nfunction formatSchemaIssuePath(pathSegments: PropertyKey[]): string {\n\tif (pathSegments.length === 0) {\n\t\treturn \"root\";\n\t}\n\treturn pathSegments\n\t\t.map((segment) => {\n\t\t\tif (typeof segment === \"number\") {\n\t\t\t\treturn `[${segment}]`;\n\t\t\t}\n\t\t\treturn String(segment);\n\t\t})\n\t\t.join(\".\");\n}\n\nfunction formatSchemaIssues(error: z.ZodError): string {\n\treturn error.issues.map((issue) => `${formatSchemaIssuePath(issue.path)}: ${issue.message}`).join(\"; \");\n}\n\nfunction parsePersistedStateFile<T>(\n\tfilePath: string,\n\tfileLabel: string,\n\traw: unknown | null,\n\tschema: z.ZodType<T>,\n\tdefaultValue: T,\n): T {\n\tif (raw === null) {\n\t\treturn defaultValue;\n\t}\n\tconst parsed = schema.safeParse(raw);\n\tif (!parsed.success) {\n\t\tthrow new Error(\n\t\t\t`Invalid ${fileLabel} file at ${filePath}. ` +\n\t\t\t\t`Fix or remove the file. Validation errors: ${formatSchemaIssues(parsed.error)}`,\n\t\t);\n\t}\n\treturn parsed.data;\n}\n\nfunction parseWorkspaceIndex(rawIndex: unknown | null): WorkspaceIndexFile {\n\tconst indexPath = getWorkspaceIndexPath();\n\treturn parsePersistedStateFile(\n\t\tindexPath,\n\t\tINDEX_FILENAME,\n\t\trawIndex,\n\t\tworkspaceIndexFileSchema,\n\t\tcreateEmptyWorkspaceIndex(),\n\t);\n}\n\nfunction parseWorkspaceStateSavePayload(payload: RuntimeWorkspaceStateSaveRequest): RuntimeWorkspaceStateSaveRequest {\n\tconst parsed = runtimeWorkspaceStateSaveRequestSchema.safeParse(payload);\n\tif (!parsed.success) {\n\t\tthrow new Error(`Invalid workspace state save payload. ${formatSchemaIssues(parsed.error)}`);\n\t}\n\treturn parsed.data;\n}\n\nasync function readWorkspaceBoard(workspaceId: string): Promise<RuntimeBoardData> {\n\tconst boardPath = getWorkspaceBoardPath(workspaceId);\n\tconst rawBoard = await readJsonFile(boardPath);\n\treturn updateTaskDependencies(\n\t\tparsePersistedStateFile(boardPath, BOARD_FILENAME, rawBoard, runtimeBoardDataSchema, createEmptyBoard()),\n\t);\n}\n\nasync function readWorkspaceSessions(workspaceId: string): Promise<Record<string, RuntimeTaskSessionSummary>> {\n\tconst sessionsPath = getWorkspaceSessionsPath(workspaceId);\n\tconst rawSessions = await readJsonFile(sessionsPath);\n\treturn parsePersistedStateFile(sessionsPath, SESSIONS_FILENAME, rawSessions, workspaceSessionsSchema, {});\n}\n\nasync function readWorkspaceMeta(workspaceId: string): Promise<WorkspaceStateMeta> {\n\tconst metaPath = getWorkspaceMetaPath(workspaceId);\n\tconst rawMeta = await readJsonFile(metaPath);\n\treturn parsePersistedStateFile(metaPath, META_FILENAME, rawMeta, workspaceStateMetaSchema, {\n\t\trevision: 0,\n\t\tupdatedAt: 0,\n\t});\n}\n\nasync function readWorkspaceIndex(): Promise<WorkspaceIndexFile> {\n\tconst raw = await readJsonFile(getWorkspaceIndexPath());\n\treturn parseWorkspaceIndex(raw);\n}\n\nasync function writeWorkspaceIndex(index: WorkspaceIndexFile): Promise<void> {\n\tawait writeJsonFileAtomic(getWorkspaceIndexPath(), index);\n}\n\nfunction toWorkspaceIdBase(repoPath: string): string {\n\tconst trimmed = repoPath.trim().replace(/[\\\\/]+$/g, \"\");\n\tconst folderName = basename(trimmed) || \"project\";\n\tconst normalized = folderName\n\t\t.normalize(\"NFKD\")\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9]+/g, \"-\")\n\t\t.replace(/^-+|-+$/g, \"\");\n\treturn normalized || \"project\";\n}\n\nfunction createWorkspaceIdCollisionSuffix(length: number): string {\n\tconst alphabet = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n\tlet suffix = \"\";\n\twhile (suffix.length < length) {\n\t\tconst bytes = randomBytes(length);\n\t\tfor (const byte of bytes) {\n\t\t\tsuffix += alphabet[byte % alphabet.length] ?? \"\";\n\t\t\tif (suffix.length === length) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn suffix;\n}\n\nfunction createWorkspaceId(index: WorkspaceIndexFile, repoPath: string): string {\n\tconst baseId = toWorkspaceIdBase(repoPath);\n\tif (!index.entries[baseId] || index.entries[baseId]?.repoPath === repoPath) {\n\t\treturn baseId;\n\t}\n\n\tfor (let attempt = 0; attempt < 256; attempt += 1) {\n\t\tconst candidate = `${baseId}-${createWorkspaceIdCollisionSuffix(WORKSPACE_ID_COLLISION_SUFFIX_LENGTH)}`;\n\t\tif (!index.entries[candidate] || index.entries[candidate]?.repoPath === repoPath) {\n\t\t\treturn candidate;\n\t\t}\n\t}\n\n\tthrow new Error(`Could not generate a unique workspace ID for ${repoPath}.`);\n}\n\nfunction ensureWorkspaceEntry(\n\tindex: WorkspaceIndexFile,\n\trepoPath: string,\n): { index: WorkspaceIndexFile; entry: WorkspaceIndexEntry; changed: boolean } {\n\tconst existingWorkspaceId = index.repoPathToId[repoPath];\n\tif (existingWorkspaceId) {\n\t\tconst existingEntry = index.entries[existingWorkspaceId];\n\t\tif (existingEntry && existingEntry.repoPath === repoPath) {\n\t\t\treturn {\n\t\t\t\tindex,\n\t\t\t\tentry: existingEntry,\n\t\t\t\tchanged: false,\n\t\t\t};\n\t\t}\n\t}\n\n\tconst workspaceId = createWorkspaceId(index, repoPath);\n\n\tconst entry: WorkspaceIndexEntry = {\n\t\tworkspaceId,\n\t\trepoPath,\n\t};\n\n\treturn {\n\t\tindex: {\n\t\t\tversion: INDEX_VERSION,\n\t\t\tentries: {\n\t\t\t\t...index.entries,\n\t\t\t\t[workspaceId]: entry,\n\t\t\t},\n\t\t\trepoPathToId: {\n\t\t\t\t...index.repoPathToId,\n\t\t\t\t[repoPath]: workspaceId,\n\t\t\t},\n\t\t},\n\t\tentry,\n\t\tchanged: true,\n\t};\n}\n\nfunction findWorkspaceEntry(index: WorkspaceIndexFile, repoPath: string): WorkspaceIndexEntry | null {\n\tconst workspaceId = index.repoPathToId[repoPath];\n\tif (!workspaceId) {\n\t\treturn null;\n\t}\n\tconst entry = index.entries[workspaceId];\n\tif (!entry || entry.repoPath !== repoPath) {\n\t\treturn null;\n\t}\n\treturn entry;\n}\n\nfunction runGitCapture(cwd: string, args: string[]): string | null {\n\tconst result = spawnSync(\"git\", args, {\n\t\tcwd,\n\t\tencoding: \"utf8\",\n\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t\tenv: createGitProcessEnv(),\n\t});\n\tif (result.status !== 0 || typeof result.stdout !== \"string\") {\n\t\treturn null;\n\t}\n\tconst value = result.stdout.trim();\n\treturn value.length > 0 ? value : null;\n}\n\nfunction detectGitRoot(cwd: string): string | null {\n\treturn runGitCapture(cwd, [\"rev-parse\", \"--show-toplevel\"]);\n}\n\nfunction detectGitCurrentBranch(repoPath: string): string | null {\n\treturn runGitCapture(repoPath, [\"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"]);\n}\n\nfunction detectGitBranches(repoPath: string): string[] {\n\tconst output = runGitCapture(repoPath, [\n\t\t\"for-each-ref\",\n\t\t\"--format=%(refname:short)\",\n\t\t\"refs/heads\",\n\t\t\"refs/remotes/origin\",\n\t]);\n\tif (!output) {\n\t\treturn [];\n\t}\n\n\tconst unique = new Set<string>();\n\tfor (const line of output.split(\"\\n\")) {\n\t\tconst trimmed = line.trim();\n\t\tif (!trimmed || trimmed === \"origin/HEAD\" || trimmed === \"HEAD\") {\n\t\t\tcontinue;\n\t\t}\n\t\tconst normalized = trimmed.startsWith(\"origin/\") ? trimmed.slice(\"origin/\".length) : trimmed;\n\t\tif (!normalized || normalized === \"HEAD\") {\n\t\t\tcontinue;\n\t\t}\n\t\tunique.add(normalized);\n\t}\n\treturn Array.from(unique).sort((left, right) => left.localeCompare(right));\n}\n\nfunction detectGitDefaultBranch(repoPath: string, branches: string[]): string | null {\n\tconst remoteHead = runGitCapture(repoPath, [\"symbolic-ref\", \"--quiet\", \"--short\", \"refs/remotes/origin/HEAD\"]);\n\tif (remoteHead) {\n\t\tconst normalized = remoteHead.startsWith(\"origin/\") ? remoteHead.slice(\"origin/\".length) : remoteHead;\n\t\tif (normalized) {\n\t\t\treturn normalized;\n\t\t}\n\t}\n\tif (branches.includes(\"main\")) {\n\t\treturn \"main\";\n\t}\n\tif (branches.includes(\"master\")) {\n\t\treturn \"master\";\n\t}\n\treturn branches[0] ?? null;\n}\n\nfunction detectGitRepositoryInfo(repoPath: string): RuntimeGitRepositoryInfo {\n\tconst gitRoot = detectGitRoot(repoPath);\n\tif (!gitRoot) {\n\t\tthrow new Error(`No git repository detected at ${repoPath}`);\n\t}\n\n\tconst currentBranch = detectGitCurrentBranch(repoPath);\n\tconst branches = detectGitBranches(repoPath);\n\tconst orderedBranches = currentBranch && !branches.includes(currentBranch) ? [currentBranch, ...branches] : branches;\n\tconst defaultBranch = detectGitDefaultBranch(repoPath, orderedBranches);\n\n\treturn {\n\t\tcurrentBranch,\n\t\tdefaultBranch,\n\t\tbranches: orderedBranches,\n\t};\n}\n\nasync function resolveWorkspacePath(cwd: string): Promise<string> {\n\tconst resolvedCwd = resolve(cwd);\n\tlet canonicalCwd = resolvedCwd;\n\ttry {\n\t\tcanonicalCwd = await realpath(resolvedCwd);\n\t} catch {\n\t\tcanonicalCwd = resolvedCwd;\n\t}\n\n\tconst gitRoot = detectGitRoot(canonicalCwd);\n\tif (!gitRoot) {\n\t\tthrow new Error(`No git repository detected at ${canonicalCwd}`);\n\t}\n\n\tconst resolvedGitRoot = resolve(gitRoot);\n\ttry {\n\t\treturn await realpath(resolvedGitRoot);\n\t} catch {\n\t\treturn resolvedGitRoot;\n\t}\n}\n\nfunction toWorkspaceStateResponse(\n\tcontext: RuntimeWorkspaceContext,\n\tboard: RuntimeBoardData,\n\tsessions: Record<string, RuntimeTaskSessionSummary>,\n\trevision: number,\n): RuntimeWorkspaceStateResponse {\n\treturn {\n\t\trepoPath: context.repoPath,\n\t\tstatePath: context.statePath,\n\t\tgit: context.git,\n\t\tboard,\n\t\tsessions,\n\t\trevision,\n\t};\n}\n\nexport class WorkspaceStateConflictError extends Error {\n\treadonly currentRevision: number;\n\n\tconstructor(expectedRevision: number, currentRevision: number) {\n\t\tsuper(`Workspace state revision mismatch: expected ${expectedRevision}, current ${currentRevision}.`);\n\t\tthis.name = \"WorkspaceStateConflictError\";\n\t\tthis.currentRevision = currentRevision;\n\t}\n}\n\nexport async function loadWorkspaceContext(\n\tcwd: string,\n\toptions: LoadWorkspaceContextOptions = {},\n): Promise<RuntimeWorkspaceContext> {\n\tconst repoPath = await resolveWorkspacePath(cwd);\n\tconst autoCreateIfMissing = options.autoCreateIfMissing ?? true;\n\tlet index = await readWorkspaceIndex();\n\tconst existingEntry = findWorkspaceEntry(index, repoPath);\n\tif (!autoCreateIfMissing) {\n\t\tif (!existingEntry) {\n\t\t\tthrow new Error(`Project ${repoPath} is not added to Kanban yet.`);\n\t\t}\n\t\treturn {\n\t\t\trepoPath,\n\t\t\tworkspaceId: existingEntry.workspaceId,\n\t\t\tstatePath: getWorkspaceDirectoryPath(existingEntry.workspaceId),\n\t\t\tgit: detectGitRepositoryInfo(repoPath),\n\t\t};\n\t}\n\n\tconst ensured = existingEntry\n\t\t? { index, entry: existingEntry, changed: false }\n\t\t: ensureWorkspaceEntry(index, repoPath);\n\tindex = ensured.index;\n\tif (ensured.changed) {\n\t\tawait writeWorkspaceIndex(index);\n\t}\n\n\treturn {\n\t\trepoPath,\n\t\tworkspaceId: ensured.entry.workspaceId,\n\t\tstatePath: getWorkspaceDirectoryPath(ensured.entry.workspaceId),\n\t\tgit: detectGitRepositoryInfo(repoPath),\n\t};\n}\n\nexport async function loadWorkspaceContextById(workspaceId: string): Promise<RuntimeWorkspaceContext | null> {\n\tconst index = await readWorkspaceIndex();\n\tconst entry = index.entries[workspaceId];\n\tif (!entry) {\n\t\treturn null;\n\t}\n\ttry {\n\t\treturn await loadWorkspaceContext(entry.repoPath);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function listWorkspaceIndexEntries(): Promise<RuntimeWorkspaceIndexEntry[]> {\n\tconst index = await readWorkspaceIndex();\n\treturn Object.values(index.entries)\n\t\t.map((entry) => ({\n\t\t\tworkspaceId: entry.workspaceId,\n\t\t\trepoPath: entry.repoPath,\n\t\t}))\n\t\t.sort((left, right) => left.repoPath.localeCompare(right.repoPath));\n}\n\nexport async function removeWorkspaceIndexEntry(workspaceId: string): Promise<boolean> {\n\tconst index = await readWorkspaceIndex();\n\tconst entry = index.entries[workspaceId];\n\tif (!entry) {\n\t\treturn false;\n\t}\n\tdelete index.entries[workspaceId];\n\tdelete index.repoPathToId[entry.repoPath];\n\tawait writeWorkspaceIndex(index);\n\treturn true;\n}\n\nexport async function removeWorkspaceStateFiles(workspaceId: string): Promise<void> {\n\tawait rm(getWorkspaceDirectoryPath(workspaceId), {\n\t\trecursive: true,\n\t\tforce: true,\n\t});\n}\n\nexport async function loadWorkspaceState(cwd: string): Promise<RuntimeWorkspaceStateResponse> {\n\tconst context = await loadWorkspaceContext(cwd);\n\tconst board = await readWorkspaceBoard(context.workspaceId);\n\tconst sessions = await readWorkspaceSessions(context.workspaceId);\n\tconst meta = await readWorkspaceMeta(context.workspaceId);\n\treturn toWorkspaceStateResponse(context, board, sessions, meta.revision);\n}\n\nexport async function saveWorkspaceState(\n\tcwd: string,\n\tpayload: RuntimeWorkspaceStateSaveRequest,\n): Promise<RuntimeWorkspaceStateResponse> {\n\tconst parsedPayload = parseWorkspaceStateSavePayload(payload);\n\tconst context = await loadWorkspaceContext(cwd);\n\tconst metaPath = getWorkspaceMetaPath(context.workspaceId);\n\tconst currentMeta = await readWorkspaceMeta(context.workspaceId);\n\tconst expectedRevision = parsedPayload.expectedRevision;\n\tif (\n\t\ttypeof expectedRevision === \"number\" &&\n\t\tNumber.isInteger(expectedRevision) &&\n\t\texpectedRevision >= 0 &&\n\t\texpectedRevision !== currentMeta.revision\n\t) {\n\t\tthrow new WorkspaceStateConflictError(expectedRevision, currentMeta.revision);\n\t}\n\tconst board = parsedPayload.board;\n\tconst sessions = parsedPayload.sessions;\n\tconst nextRevision = currentMeta.revision + 1;\n\tconst nextMeta: WorkspaceStateMeta = {\n\t\trevision: nextRevision,\n\t\tupdatedAt: Date.now(),\n\t};\n\n\tawait writeJsonFileAtomic(getWorkspaceBoardPath(context.workspaceId), board);\n\tawait writeJsonFileAtomic(getWorkspaceSessionsPath(context.workspaceId), sessions);\n\tawait writeJsonFileAtomic(metaPath, nextMeta);\n\n\treturn toWorkspaceStateResponse(context, board, sessions, nextRevision);\n}\n"]}
1
+ {"version":3,"file":"workspace-state.js","sourceRoot":"","sources":["../../src/state/workspace-state.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { randomBytes, randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, realpath, rename, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { z } from \"zod\";\n\nimport {\n\ttype RuntimeBoardColumnId,\n\ttype RuntimeBoardData,\n\ttype RuntimeGitRepositoryInfo,\n\ttype RuntimeTaskSessionSummary,\n\ttype RuntimeWorkspaceStateResponse,\n\ttype RuntimeWorkspaceStateSaveRequest,\n\truntimeBoardDataSchema,\n\truntimeTaskSessionSummarySchema,\n\truntimeWorkspaceStateSaveRequestSchema,\n} from \"../core/api-contract.js\";\nimport { createGitProcessEnv } from \"../core/git-process-env.js\";\nimport { updateTaskDependencies } from \"../core/task-board-mutations.js\";\n\nconst RUNTIME_HOME_DIR = \".kanban\";\nconst WORKSPACES_DIR = \"workspaces\";\nconst INDEX_FILENAME = \"index.json\";\nconst BOARD_FILENAME = \"board.json\";\nconst SESSIONS_FILENAME = \"sessions.json\";\nconst META_FILENAME = \"meta.json\";\nconst INDEX_VERSION = 1;\nconst WORKSPACE_ID_COLLISION_SUFFIX_LENGTH = 4;\n\nconst BOARD_COLUMNS: Array<{ id: RuntimeBoardColumnId; title: string }> = [\n\t{ id: \"backlog\", title: \"Backlog\" },\n\t{ id: \"in_progress\", title: \"In Progress\" },\n\t{ id: \"review\", title: \"Review\" },\n\t{ id: \"trash\", title: \"Trash\" },\n];\n\ninterface WorkspaceIndexEntry {\n\tworkspaceId: string;\n\trepoPath: string;\n}\n\nexport interface RuntimeWorkspaceIndexEntry {\n\tworkspaceId: string;\n\trepoPath: string;\n}\n\ninterface WorkspaceIndexFile {\n\tversion: number;\n\tentries: Record<string, WorkspaceIndexEntry>;\n\trepoPathToId: Record<string, string>;\n}\n\ninterface WorkspaceStateMeta {\n\trevision: number;\n\tupdatedAt: number;\n}\n\nconst workspaceStateMetaSchema = z.object({\n\trevision: z.number().int().nonnegative(),\n\tupdatedAt: z.number(),\n});\n\nconst workspaceIndexEntrySchema = z.object({\n\tworkspaceId: z.string().min(1, \"Workspace ID cannot be empty.\"),\n\trepoPath: z.string().min(1, \"Workspace repository path cannot be empty.\"),\n});\n\nconst workspaceIndexFileSchema = z\n\t.object({\n\t\tversion: z.literal(INDEX_VERSION),\n\t\tentries: z.record(z.string(), workspaceIndexEntrySchema),\n\t\trepoPathToId: z.record(z.string(), z.string().min(1, \"Workspace ID cannot be empty.\")),\n\t})\n\t.superRefine((index, context) => {\n\t\tfor (const [workspaceId, entry] of Object.entries(index.entries)) {\n\t\t\tif (entry.workspaceId !== workspaceId) {\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tpath: [\"entries\", workspaceId, \"workspaceId\"],\n\t\t\t\t\tmessage: `Workspace ID must match entry key \"${workspaceId}\".`,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst mappedWorkspaceId = index.repoPathToId[entry.repoPath];\n\t\t\tif (mappedWorkspaceId !== workspaceId) {\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tpath: [\"entries\", workspaceId, \"repoPath\"],\n\t\t\t\t\tmessage: `Missing repoPathToId mapping for \"${entry.repoPath}\" to \"${workspaceId}\".`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tfor (const [repoPath, workspaceId] of Object.entries(index.repoPathToId)) {\n\t\t\tconst entry = index.entries[workspaceId];\n\t\t\tif (!entry) {\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tpath: [\"repoPathToId\", repoPath],\n\t\t\t\t\tmessage: `Mapped workspace \"${workspaceId}\" does not exist in entries.`,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (entry.repoPath !== repoPath) {\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tpath: [\"repoPathToId\", repoPath],\n\t\t\t\t\tmessage: `Mapped repoPath does not match workspace entry path \"${entry.repoPath}\".`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\nconst workspaceSessionsSchema = z\n\t.record(z.string(), runtimeTaskSessionSummarySchema)\n\t.superRefine((sessions, context) => {\n\t\tfor (const [taskId, session] of Object.entries(sessions)) {\n\t\t\tif (session.taskId !== taskId) {\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: z.ZodIssueCode.custom,\n\t\t\t\t\tpath: [taskId, \"taskId\"],\n\t\t\t\t\tmessage: `Session taskId must match record key \"${taskId}\".`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\nexport interface RuntimeWorkspaceContext {\n\trepoPath: string;\n\tworkspaceId: string;\n\tstatePath: string;\n\tgit: RuntimeGitRepositoryInfo;\n}\n\nexport interface LoadWorkspaceContextOptions {\n\tautoCreateIfMissing?: boolean;\n}\n\nfunction createEmptyBoard(): RuntimeBoardData {\n\treturn {\n\t\tcolumns: BOARD_COLUMNS.map((column) => ({\n\t\t\tid: column.id,\n\t\t\ttitle: column.title,\n\t\t\tcards: [],\n\t\t})),\n\t\tdependencies: [],\n\t};\n}\n\nfunction createEmptyWorkspaceIndex(): WorkspaceIndexFile {\n\treturn {\n\t\tversion: INDEX_VERSION,\n\t\tentries: {},\n\t\trepoPathToId: {},\n\t};\n}\n\nexport function getRuntimeHomePath(): string {\n\treturn join(homedir(), RUNTIME_HOME_DIR);\n}\n\nexport function getWorkspacesRootPath(): string {\n\treturn join(getRuntimeHomePath(), WORKSPACES_DIR);\n}\n\nfunction getWorkspaceIndexPath(): string {\n\treturn join(getWorkspacesRootPath(), INDEX_FILENAME);\n}\n\nexport function getWorkspaceDirectoryPath(workspaceId: string): string {\n\treturn join(getWorkspacesRootPath(), workspaceId);\n}\n\nfunction getWorkspaceBoardPath(workspaceId: string): string {\n\treturn join(getWorkspaceDirectoryPath(workspaceId), BOARD_FILENAME);\n}\n\nfunction getWorkspaceSessionsPath(workspaceId: string): string {\n\treturn join(getWorkspaceDirectoryPath(workspaceId), SESSIONS_FILENAME);\n}\n\nfunction getWorkspaceMetaPath(workspaceId: string): string {\n\treturn join(getWorkspaceDirectoryPath(workspaceId), META_FILENAME);\n}\n\nfunction isNodeErrorWithCode(error: unknown, code: string): boolean {\n\treturn typeof error === \"object\" && error !== null && \"code\" in error && (error as { code?: unknown }).code === code;\n}\n\nasync function readJsonFile(path: string): Promise<unknown | null> {\n\ttry {\n\t\tconst raw = await readFile(path, \"utf8\");\n\t\ttry {\n\t\t\treturn JSON.parse(raw) as unknown;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Malformed JSON in ${path}. ${message}`);\n\t\t}\n\t} catch (error) {\n\t\tif (isNodeErrorWithCode(error, \"ENOENT\")) {\n\t\t\treturn null;\n\t\t}\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(`Could not read JSON file at ${path}. ${message}`);\n\t}\n}\n\nasync function writeJsonFileAtomic(path: string, payload: unknown): Promise<void> {\n\tawait mkdir(dirname(path), { recursive: true });\n\tconst tempPath = `${path}.tmp.${process.pid}.${Date.now()}.${randomUUID()}`;\n\tawait writeFile(tempPath, JSON.stringify(payload, null, 2), \"utf8\");\n\tawait rename(tempPath, path);\n}\n\nfunction formatSchemaIssuePath(pathSegments: PropertyKey[]): string {\n\tif (pathSegments.length === 0) {\n\t\treturn \"root\";\n\t}\n\treturn pathSegments\n\t\t.map((segment) => {\n\t\t\tif (typeof segment === \"number\") {\n\t\t\t\treturn `[${segment}]`;\n\t\t\t}\n\t\t\treturn String(segment);\n\t\t})\n\t\t.join(\".\");\n}\n\nfunction formatSchemaIssues(error: z.ZodError): string {\n\treturn error.issues.map((issue) => `${formatSchemaIssuePath(issue.path)}: ${issue.message}`).join(\"; \");\n}\n\nfunction parsePersistedStateFile<T>(\n\tfilePath: string,\n\tfileLabel: string,\n\traw: unknown | null,\n\tschema: z.ZodType<T>,\n\tdefaultValue: T,\n): T {\n\tif (raw === null) {\n\t\treturn defaultValue;\n\t}\n\tconst parsed = schema.safeParse(raw);\n\tif (!parsed.success) {\n\t\tthrow new Error(\n\t\t\t`Invalid ${fileLabel} file at ${filePath}. ` +\n\t\t\t\t`Fix or remove the file. Validation errors: ${formatSchemaIssues(parsed.error)}`,\n\t\t);\n\t}\n\treturn parsed.data;\n}\n\nfunction parseWorkspaceIndex(rawIndex: unknown | null): WorkspaceIndexFile {\n\tconst indexPath = getWorkspaceIndexPath();\n\treturn parsePersistedStateFile(\n\t\tindexPath,\n\t\tINDEX_FILENAME,\n\t\trawIndex,\n\t\tworkspaceIndexFileSchema,\n\t\tcreateEmptyWorkspaceIndex(),\n\t);\n}\n\nfunction parseWorkspaceStateSavePayload(payload: RuntimeWorkspaceStateSaveRequest): RuntimeWorkspaceStateSaveRequest {\n\tconst parsed = runtimeWorkspaceStateSaveRequestSchema.safeParse(payload);\n\tif (!parsed.success) {\n\t\tthrow new Error(`Invalid workspace state save payload. ${formatSchemaIssues(parsed.error)}`);\n\t}\n\treturn parsed.data;\n}\n\nasync function readWorkspaceBoard(workspaceId: string): Promise<RuntimeBoardData> {\n\tconst boardPath = getWorkspaceBoardPath(workspaceId);\n\tconst rawBoard = await readJsonFile(boardPath);\n\treturn updateTaskDependencies(\n\t\tparsePersistedStateFile(boardPath, BOARD_FILENAME, rawBoard, runtimeBoardDataSchema, createEmptyBoard()),\n\t);\n}\n\nasync function readWorkspaceSessions(workspaceId: string): Promise<Record<string, RuntimeTaskSessionSummary>> {\n\tconst sessionsPath = getWorkspaceSessionsPath(workspaceId);\n\tconst rawSessions = await readJsonFile(sessionsPath);\n\treturn parsePersistedStateFile(sessionsPath, SESSIONS_FILENAME, rawSessions, workspaceSessionsSchema, {});\n}\n\nasync function readWorkspaceMeta(workspaceId: string): Promise<WorkspaceStateMeta> {\n\tconst metaPath = getWorkspaceMetaPath(workspaceId);\n\tconst rawMeta = await readJsonFile(metaPath);\n\treturn parsePersistedStateFile(metaPath, META_FILENAME, rawMeta, workspaceStateMetaSchema, {\n\t\trevision: 0,\n\t\tupdatedAt: 0,\n\t});\n}\n\nasync function readWorkspaceIndex(): Promise<WorkspaceIndexFile> {\n\tconst raw = await readJsonFile(getWorkspaceIndexPath());\n\treturn parseWorkspaceIndex(raw);\n}\n\nasync function writeWorkspaceIndex(index: WorkspaceIndexFile): Promise<void> {\n\tawait writeJsonFileAtomic(getWorkspaceIndexPath(), index);\n}\n\nfunction toWorkspaceIdBase(repoPath: string): string {\n\tconst trimmed = repoPath.trim().replace(/[\\\\/]+$/g, \"\");\n\tconst folderName = basename(trimmed) || \"project\";\n\tconst normalized = folderName\n\t\t.normalize(\"NFKD\")\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9]+/g, \"-\")\n\t\t.replace(/^-+|-+$/g, \"\");\n\treturn normalized || \"project\";\n}\n\nfunction createWorkspaceIdCollisionSuffix(length: number): string {\n\tconst alphabet = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n\tlet suffix = \"\";\n\twhile (suffix.length < length) {\n\t\tconst bytes = randomBytes(length);\n\t\tfor (const byte of bytes) {\n\t\t\tsuffix += alphabet[byte % alphabet.length] ?? \"\";\n\t\t\tif (suffix.length === length) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn suffix;\n}\n\nfunction createWorkspaceId(index: WorkspaceIndexFile, repoPath: string): string {\n\tconst baseId = toWorkspaceIdBase(repoPath);\n\tif (!index.entries[baseId] || index.entries[baseId]?.repoPath === repoPath) {\n\t\treturn baseId;\n\t}\n\n\tfor (let attempt = 0; attempt < 256; attempt += 1) {\n\t\tconst candidate = `${baseId}-${createWorkspaceIdCollisionSuffix(WORKSPACE_ID_COLLISION_SUFFIX_LENGTH)}`;\n\t\tif (!index.entries[candidate] || index.entries[candidate]?.repoPath === repoPath) {\n\t\t\treturn candidate;\n\t\t}\n\t}\n\n\tthrow new Error(`Could not generate a unique workspace ID for ${repoPath}.`);\n}\n\nfunction ensureWorkspaceEntry(\n\tindex: WorkspaceIndexFile,\n\trepoPath: string,\n): { index: WorkspaceIndexFile; entry: WorkspaceIndexEntry; changed: boolean } {\n\tconst existingWorkspaceId = index.repoPathToId[repoPath];\n\tif (existingWorkspaceId) {\n\t\tconst existingEntry = index.entries[existingWorkspaceId];\n\t\tif (existingEntry && existingEntry.repoPath === repoPath) {\n\t\t\treturn {\n\t\t\t\tindex,\n\t\t\t\tentry: existingEntry,\n\t\t\t\tchanged: false,\n\t\t\t};\n\t\t}\n\t}\n\n\tconst workspaceId = createWorkspaceId(index, repoPath);\n\n\tconst entry: WorkspaceIndexEntry = {\n\t\tworkspaceId,\n\t\trepoPath,\n\t};\n\n\treturn {\n\t\tindex: {\n\t\t\tversion: INDEX_VERSION,\n\t\t\tentries: {\n\t\t\t\t...index.entries,\n\t\t\t\t[workspaceId]: entry,\n\t\t\t},\n\t\t\trepoPathToId: {\n\t\t\t\t...index.repoPathToId,\n\t\t\t\t[repoPath]: workspaceId,\n\t\t\t},\n\t\t},\n\t\tentry,\n\t\tchanged: true,\n\t};\n}\n\nfunction findWorkspaceEntry(index: WorkspaceIndexFile, repoPath: string): WorkspaceIndexEntry | null {\n\tconst workspaceId = index.repoPathToId[repoPath];\n\tif (!workspaceId) {\n\t\treturn null;\n\t}\n\tconst entry = index.entries[workspaceId];\n\tif (!entry || entry.repoPath !== repoPath) {\n\t\treturn null;\n\t}\n\treturn entry;\n}\n\nfunction runGitCapture(cwd: string, args: string[]): string | null {\n\tconst result = spawnSync(\"git\", args, {\n\t\tcwd,\n\t\tencoding: \"utf8\",\n\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t\tenv: createGitProcessEnv(),\n\t});\n\tif (result.status !== 0 || typeof result.stdout !== \"string\") {\n\t\treturn null;\n\t}\n\tconst value = result.stdout.trim();\n\treturn value.length > 0 ? value : null;\n}\n\nfunction detectGitRoot(cwd: string): string | null {\n\treturn runGitCapture(cwd, [\"rev-parse\", \"--show-toplevel\"]);\n}\n\nfunction detectGitCurrentBranch(repoPath: string): string | null {\n\treturn runGitCapture(repoPath, [\"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"]);\n}\n\nfunction detectGitBranches(repoPath: string): string[] {\n\tconst output = runGitCapture(repoPath, [\n\t\t\"for-each-ref\",\n\t\t\"--format=%(refname:short)\",\n\t\t\"refs/heads\",\n\t\t\"refs/remotes/origin\",\n\t]);\n\tif (!output) {\n\t\treturn [];\n\t}\n\n\tconst unique = new Set<string>();\n\tfor (const line of output.split(\"\\n\")) {\n\t\tconst trimmed = line.trim();\n\t\tif (!trimmed || trimmed === \"origin/HEAD\" || trimmed === \"HEAD\") {\n\t\t\tcontinue;\n\t\t}\n\t\tconst normalized = trimmed.startsWith(\"origin/\") ? trimmed.slice(\"origin/\".length) : trimmed;\n\t\tif (!normalized || normalized === \"HEAD\") {\n\t\t\tcontinue;\n\t\t}\n\t\tunique.add(normalized);\n\t}\n\treturn Array.from(unique).sort((left, right) => left.localeCompare(right));\n}\n\nfunction detectGitDefaultBranch(repoPath: string, branches: string[]): string | null {\n\tconst remoteHead = runGitCapture(repoPath, [\"symbolic-ref\", \"--quiet\", \"--short\", \"refs/remotes/origin/HEAD\"]);\n\tif (remoteHead) {\n\t\tconst normalized = remoteHead.startsWith(\"origin/\") ? remoteHead.slice(\"origin/\".length) : remoteHead;\n\t\tif (normalized) {\n\t\t\treturn normalized;\n\t\t}\n\t}\n\tif (branches.includes(\"main\")) {\n\t\treturn \"main\";\n\t}\n\tif (branches.includes(\"master\")) {\n\t\treturn \"master\";\n\t}\n\treturn branches[0] ?? null;\n}\n\nfunction detectGitRepositoryInfo(repoPath: string): RuntimeGitRepositoryInfo {\n\tconst gitRoot = detectGitRoot(repoPath);\n\tif (!gitRoot) {\n\t\tthrow new Error(`No git repository detected at ${repoPath}`);\n\t}\n\n\tconst currentBranch = detectGitCurrentBranch(repoPath);\n\tconst branches = detectGitBranches(repoPath);\n\tconst orderedBranches = currentBranch && !branches.includes(currentBranch) ? [currentBranch, ...branches] : branches;\n\tconst defaultBranch = detectGitDefaultBranch(repoPath, orderedBranches);\n\n\treturn {\n\t\tcurrentBranch,\n\t\tdefaultBranch,\n\t\tbranches: orderedBranches,\n\t};\n}\n\nasync function resolveWorkspacePath(cwd: string): Promise<string> {\n\tconst resolvedCwd = resolve(cwd);\n\tlet canonicalCwd = resolvedCwd;\n\ttry {\n\t\tcanonicalCwd = await realpath(resolvedCwd);\n\t} catch {\n\t\tcanonicalCwd = resolvedCwd;\n\t}\n\n\tconst gitRoot = detectGitRoot(canonicalCwd);\n\tif (!gitRoot) {\n\t\tthrow new Error(`No git repository detected at ${canonicalCwd}`);\n\t}\n\n\tconst resolvedGitRoot = resolve(gitRoot);\n\ttry {\n\t\treturn await realpath(resolvedGitRoot);\n\t} catch {\n\t\treturn resolvedGitRoot;\n\t}\n}\n\nfunction toWorkspaceStateResponse(\n\tcontext: RuntimeWorkspaceContext,\n\tboard: RuntimeBoardData,\n\tsessions: Record<string, RuntimeTaskSessionSummary>,\n\trevision: number,\n): RuntimeWorkspaceStateResponse {\n\treturn {\n\t\trepoPath: context.repoPath,\n\t\tstatePath: context.statePath,\n\t\tgit: context.git,\n\t\tboard,\n\t\tsessions,\n\t\trevision,\n\t};\n}\n\nexport class WorkspaceStateConflictError extends Error {\n\treadonly currentRevision: number;\n\n\tconstructor(expectedRevision: number, currentRevision: number) {\n\t\tsuper(`Workspace state revision mismatch: expected ${expectedRevision}, current ${currentRevision}.`);\n\t\tthis.name = \"WorkspaceStateConflictError\";\n\t\tthis.currentRevision = currentRevision;\n\t}\n}\n\nexport async function loadWorkspaceContext(\n\tcwd: string,\n\toptions: LoadWorkspaceContextOptions = {},\n): Promise<RuntimeWorkspaceContext> {\n\tconst repoPath = await resolveWorkspacePath(cwd);\n\tconst autoCreateIfMissing = options.autoCreateIfMissing ?? true;\n\tlet index = await readWorkspaceIndex();\n\tconst existingEntry = findWorkspaceEntry(index, repoPath);\n\tif (!autoCreateIfMissing) {\n\t\tif (!existingEntry) {\n\t\t\tthrow new Error(`Project ${repoPath} is not added to Kanban yet.`);\n\t\t}\n\t\treturn {\n\t\t\trepoPath,\n\t\t\tworkspaceId: existingEntry.workspaceId,\n\t\t\tstatePath: getWorkspaceDirectoryPath(existingEntry.workspaceId),\n\t\t\tgit: detectGitRepositoryInfo(repoPath),\n\t\t};\n\t}\n\n\tconst ensured = existingEntry\n\t\t? { index, entry: existingEntry, changed: false }\n\t\t: ensureWorkspaceEntry(index, repoPath);\n\tindex = ensured.index;\n\tif (ensured.changed) {\n\t\tawait writeWorkspaceIndex(index);\n\t}\n\n\treturn {\n\t\trepoPath,\n\t\tworkspaceId: ensured.entry.workspaceId,\n\t\tstatePath: getWorkspaceDirectoryPath(ensured.entry.workspaceId),\n\t\tgit: detectGitRepositoryInfo(repoPath),\n\t};\n}\n\nexport async function loadWorkspaceContextById(workspaceId: string): Promise<RuntimeWorkspaceContext | null> {\n\tconst index = await readWorkspaceIndex();\n\tconst entry = index.entries[workspaceId];\n\tif (!entry) {\n\t\treturn null;\n\t}\n\ttry {\n\t\treturn await loadWorkspaceContext(entry.repoPath);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function listWorkspaceIndexEntries(): Promise<RuntimeWorkspaceIndexEntry[]> {\n\tconst index = await readWorkspaceIndex();\n\treturn Object.values(index.entries)\n\t\t.map((entry) => ({\n\t\t\tworkspaceId: entry.workspaceId,\n\t\t\trepoPath: entry.repoPath,\n\t\t}))\n\t\t.sort((left, right) => left.repoPath.localeCompare(right.repoPath));\n}\n\nexport async function removeWorkspaceIndexEntry(workspaceId: string): Promise<boolean> {\n\tconst index = await readWorkspaceIndex();\n\tconst entry = index.entries[workspaceId];\n\tif (!entry) {\n\t\treturn false;\n\t}\n\tdelete index.entries[workspaceId];\n\tdelete index.repoPathToId[entry.repoPath];\n\tawait writeWorkspaceIndex(index);\n\treturn true;\n}\n\nexport async function removeWorkspaceStateFiles(workspaceId: string): Promise<void> {\n\tawait rm(getWorkspaceDirectoryPath(workspaceId), {\n\t\trecursive: true,\n\t\tforce: true,\n\t});\n}\n\nexport async function loadWorkspaceState(cwd: string): Promise<RuntimeWorkspaceStateResponse> {\n\tconst context = await loadWorkspaceContext(cwd);\n\tconst board = await readWorkspaceBoard(context.workspaceId);\n\tconst sessions = await readWorkspaceSessions(context.workspaceId);\n\tconst meta = await readWorkspaceMeta(context.workspaceId);\n\treturn toWorkspaceStateResponse(context, board, sessions, meta.revision);\n}\n\nexport async function saveWorkspaceState(\n\tcwd: string,\n\tpayload: RuntimeWorkspaceStateSaveRequest,\n): Promise<RuntimeWorkspaceStateResponse> {\n\tconst parsedPayload = parseWorkspaceStateSavePayload(payload);\n\tconst context = await loadWorkspaceContext(cwd);\n\tconst metaPath = getWorkspaceMetaPath(context.workspaceId);\n\tconst currentMeta = await readWorkspaceMeta(context.workspaceId);\n\tconst expectedRevision = parsedPayload.expectedRevision;\n\tif (\n\t\ttypeof expectedRevision === \"number\" &&\n\t\tNumber.isInteger(expectedRevision) &&\n\t\texpectedRevision >= 0 &&\n\t\texpectedRevision !== currentMeta.revision\n\t) {\n\t\tthrow new WorkspaceStateConflictError(expectedRevision, currentMeta.revision);\n\t}\n\tconst board = parsedPayload.board;\n\tconst sessions = parsedPayload.sessions;\n\tconst nextRevision = currentMeta.revision + 1;\n\tconst nextMeta: WorkspaceStateMeta = {\n\t\trevision: nextRevision,\n\t\tupdatedAt: Date.now(),\n\t};\n\n\tawait writeJsonFileAtomic(getWorkspaceBoardPath(context.workspaceId), board);\n\tawait writeJsonFileAtomic(getWorkspaceSessionsPath(context.workspaceId), sessions);\n\tawait writeJsonFileAtomic(metaPath, nextMeta);\n\n\treturn toWorkspaceStateResponse(context, board, sessions, nextRevision);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"claude-workspace-trust.d.ts","sourceRoot":"","sources":["../../src/terminal/claude-workspace-trust.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAG9D,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAuDpD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGnE;AAWD,wBAAgB,qCAAqC,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAEnG;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAAE,0BAA0B,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAK3G"}
1
+ {"version":3,"file":"claude-workspace-trust.d.ts","sourceRoot":"","sources":["../../src/terminal/claude-workspace-trust.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAI9D,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAuDpD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGnE;AAWD,wBAAgB,qCAAqC,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAEnG;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAAE,0BAA0B,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAK3G"}
@@ -1,4 +1,5 @@
1
1
  import { join } from "node:path";
2
+ import { KANBAN_TASK_WORKTREES_DIR_NAME } from "../workspace/task-worktree-path.js";
2
3
  import { getRuntimeHomePath } from "../state/workspace-state.js";
3
4
  export const WORKSPACE_TRUST_CONFIRM_DELAY_MS = 100;
4
5
  function normalizeTerminalText(input) {
@@ -58,7 +59,7 @@ export function hasClaudeWorkspaceTrustPrompt(text) {
58
59
  return /yes,?\s*i\s*trust\s*this\s*folder/u.test(normalized) || /trust\s+this\s+folder/u.test(normalized);
59
60
  }
60
61
  function isTaskWorktreePath(path) {
61
- const worktreesRoot = `${join(getRuntimeHomePath(), "worktrees").replace(/\\/gu, "/").replace(/\/+$/u, "")}/`;
62
+ const worktreesRoot = `${join(getRuntimeHomePath(), KANBAN_TASK_WORKTREES_DIR_NAME).replace(/\\/gu, "/").replace(/\/+$/u, "")}/`;
62
63
  const normalizedPath = `${path.replace(/\\/gu, "/").replace(/\/+$/u, "")}/`;
63
64
  if (process.platform === "win32") {
64
65
  return normalizedPath.toLowerCase().startsWith(worktreesRoot.toLowerCase());
@@ -1 +1 @@
1
- {"version":3,"file":"claude-workspace-trust.js","sourceRoot":"","sources":["../../src/terminal/claude-workspace-trust.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\n\nimport type { RuntimeAgentId } from \"../core/api-contract.js\";\nimport { getRuntimeHomePath } from \"../state/workspace-state.js\";\n\nexport const WORKSPACE_TRUST_CONFIRM_DELAY_MS = 100;\n\nfunction normalizeTerminalText(input: string): string {\n\treturn input.toLowerCase().replace(/\\s+/gu, \" \");\n}\n\nfunction stripAnsiAndControl(input: string): string {\n\tlet output = \"\";\n\tlet mode: \"text\" | \"escape\" | \"csi\" | \"osc\" | \"osc_escape\" = \"text\";\n\tfor (const char of input) {\n\t\tif (mode === \"text\") {\n\t\t\tif (char === \"\\u001b\") {\n\t\t\t\tmode = \"escape\";\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst code = char.charCodeAt(0);\n\t\t\tif ((code >= 32 && code !== 127) || char === \"\\n\" || char === \"\\r\" || char === \"\\t\") {\n\t\t\t\toutput += char;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (mode === \"escape\") {\n\t\t\tif (char === \"[\") {\n\t\t\t\tmode = \"csi\";\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (char === \"]\") {\n\t\t\t\tmode = \"osc\";\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmode = \"text\";\n\t\t\tcontinue;\n\t\t}\n\t\tif (mode === \"csi\") {\n\t\t\tconst code = char.charCodeAt(0);\n\t\t\tif (code >= 64 && code <= 126) {\n\t\t\t\tmode = \"text\";\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (mode === \"osc\") {\n\t\t\tif (char === \"\\u0007\") {\n\t\t\t\tmode = \"text\";\n\t\t\t} else if (char === \"\\u001b\") {\n\t\t\t\tmode = \"osc_escape\";\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (mode === \"osc_escape\") {\n\t\t\tmode = char === \"\\\\\" ? \"text\" : \"osc\";\n\t\t}\n\t}\n\treturn output;\n}\n\nexport function hasClaudeWorkspaceTrustPrompt(text: string): boolean {\n\tconst normalized = normalizeTerminalText(stripAnsiAndControl(text));\n\treturn /yes,?\\s*i\\s*trust\\s*this\\s*folder/u.test(normalized) || /trust\\s+this\\s+folder/u.test(normalized);\n}\n\nfunction isTaskWorktreePath(path: string): boolean {\n\tconst worktreesRoot = `${join(getRuntimeHomePath(), \"worktrees\").replace(/\\\\/gu, \"/\").replace(/\\/+$/u, \"\")}/`;\n\tconst normalizedPath = `${path.replace(/\\\\/gu, \"/\").replace(/\\/+$/u, \"\")}/`;\n\tif (process.platform === \"win32\") {\n\t\treturn normalizedPath.toLowerCase().startsWith(worktreesRoot.toLowerCase());\n\t}\n\treturn normalizedPath.startsWith(worktreesRoot);\n}\n\nexport function shouldAutoConfirmClaudeWorkspaceTrust(agentId: RuntimeAgentId, cwd: string): boolean {\n\treturn agentId === \"claude\" && isTaskWorktreePath(cwd);\n}\n\nexport function stopWorkspaceTrustTimers(state: { workspaceTrustConfirmTimer: NodeJS.Timeout | null }): void {\n\tif (state.workspaceTrustConfirmTimer) {\n\t\tclearTimeout(state.workspaceTrustConfirmTimer);\n\t\tstate.workspaceTrustConfirmTimer = null;\n\t}\n}\n"]}
1
+ {"version":3,"file":"claude-workspace-trust.js","sourceRoot":"","sources":["../../src/terminal/claude-workspace-trust.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,8BAA8B,EAAE,MAAM,oCAAoC,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEjE,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAG,CAAC;AAEpD,SAAS,qBAAqB,CAAC,KAAa;IAC3C,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACzC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,IAAI,GAAqD,MAAM,CAAC;IACpE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACrB,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvB,IAAI,GAAG,QAAQ,CAAC;gBAChB,SAAS;YACV,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,IAAI,IAAI,EAAE,IAAI,IAAI,KAAK,GAAG,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBACrF,MAAM,IAAI,IAAI,CAAC;YAChB,CAAC;YACD,SAAS;QACV,CAAC;QACD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvB,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBAClB,IAAI,GAAG,KAAK,CAAC;gBACb,SAAS;YACV,CAAC;YACD,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBAClB,IAAI,GAAG,KAAK,CAAC;gBACb,SAAS;YACV,CAAC;YACD,IAAI,GAAG,MAAM,CAAC;YACd,SAAS;QACV,CAAC;QACD,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACpB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;gBAC/B,IAAI,GAAG,MAAM,CAAC;YACf,CAAC;YACD,SAAS;QACV,CAAC;QACD,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACpB,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvB,IAAI,GAAG,MAAM,CAAC;YACf,CAAC;iBAAM,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC9B,IAAI,GAAG,YAAY,CAAC;YACrB,CAAC;YACD,SAAS;QACV,CAAC;QACD,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;YAC3B,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;QACvC,CAAC;IACF,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,IAAY;IACzD,MAAM,UAAU,GAAG,qBAAqB,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;IACpE,OAAO,oCAAoC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,wBAAwB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAC3G,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY;IACvC,MAAM,aAAa,GAAG,GAAG,IAAI,CAAC,kBAAkB,EAAE,EAAE,8BAA8B,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC;IACjI,MAAM,cAAc,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC;IAC5E,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAClC,OAAO,cAAc,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,cAAc,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,qCAAqC,CAAC,OAAuB,EAAE,GAAW;IACzF,OAAO,OAAO,KAAK,QAAQ,IAAI,kBAAkB,CAAC,GAAG,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,KAA4D;IACpG,IAAI,KAAK,CAAC,0BAA0B,EAAE,CAAC;QACtC,YAAY,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC/C,KAAK,CAAC,0BAA0B,GAAG,IAAI,CAAC;IACzC,CAAC;AACF,CAAC","sourcesContent":["import { join } from \"node:path\";\n\nimport type { RuntimeAgentId } from \"../core/api-contract.js\";\nimport { KANBAN_TASK_WORKTREES_DIR_NAME } from \"../workspace/task-worktree-path.js\";\nimport { getRuntimeHomePath } from \"../state/workspace-state.js\";\n\nexport const WORKSPACE_TRUST_CONFIRM_DELAY_MS = 100;\n\nfunction normalizeTerminalText(input: string): string {\n\treturn input.toLowerCase().replace(/\\s+/gu, \" \");\n}\n\nfunction stripAnsiAndControl(input: string): string {\n\tlet output = \"\";\n\tlet mode: \"text\" | \"escape\" | \"csi\" | \"osc\" | \"osc_escape\" = \"text\";\n\tfor (const char of input) {\n\t\tif (mode === \"text\") {\n\t\t\tif (char === \"\\u001b\") {\n\t\t\t\tmode = \"escape\";\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst code = char.charCodeAt(0);\n\t\t\tif ((code >= 32 && code !== 127) || char === \"\\n\" || char === \"\\r\" || char === \"\\t\") {\n\t\t\t\toutput += char;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (mode === \"escape\") {\n\t\t\tif (char === \"[\") {\n\t\t\t\tmode = \"csi\";\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (char === \"]\") {\n\t\t\t\tmode = \"osc\";\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmode = \"text\";\n\t\t\tcontinue;\n\t\t}\n\t\tif (mode === \"csi\") {\n\t\t\tconst code = char.charCodeAt(0);\n\t\t\tif (code >= 64 && code <= 126) {\n\t\t\t\tmode = \"text\";\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (mode === \"osc\") {\n\t\t\tif (char === \"\\u0007\") {\n\t\t\t\tmode = \"text\";\n\t\t\t} else if (char === \"\\u001b\") {\n\t\t\t\tmode = \"osc_escape\";\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (mode === \"osc_escape\") {\n\t\t\tmode = char === \"\\\\\" ? \"text\" : \"osc\";\n\t\t}\n\t}\n\treturn output;\n}\n\nexport function hasClaudeWorkspaceTrustPrompt(text: string): boolean {\n\tconst normalized = normalizeTerminalText(stripAnsiAndControl(text));\n\treturn /yes,?\\s*i\\s*trust\\s*this\\s*folder/u.test(normalized) || /trust\\s+this\\s+folder/u.test(normalized);\n}\n\nfunction isTaskWorktreePath(path: string): boolean {\n\tconst worktreesRoot = `${join(getRuntimeHomePath(), KANBAN_TASK_WORKTREES_DIR_NAME).replace(/\\\\/gu, \"/\").replace(/\\/+$/u, \"\")}/`;\n\tconst normalizedPath = `${path.replace(/\\\\/gu, \"/\").replace(/\\/+$/u, \"\")}/`;\n\tif (process.platform === \"win32\") {\n\t\treturn normalizedPath.toLowerCase().startsWith(worktreesRoot.toLowerCase());\n\t}\n\treturn normalizedPath.startsWith(worktreesRoot);\n}\n\nexport function shouldAutoConfirmClaudeWorkspaceTrust(agentId: RuntimeAgentId, cwd: string): boolean {\n\treturn agentId === \"claude\" && isTaskWorktreePath(cwd);\n}\n\nexport function stopWorkspaceTrustTimers(state: { workspaceTrustConfirmTimer: NodeJS.Timeout | null }): void {\n\tif (state.workspaceTrustConfirmTimer) {\n\t\tclearTimeout(state.workspaceTrustConfirmTimer);\n\t\tstate.workspaceTrustConfirmTimer = null;\n\t}\n}\n"]}
@@ -35,6 +35,7 @@ export declare class TerminalSessionManager implements TerminalSessionService {
35
35
  attach(taskId: string, listener: TerminalSessionListener): (() => void) | null;
36
36
  startTaskSession(request: StartTaskSessionRequest): Promise<RuntimeTaskSessionSummary>;
37
37
  startShellSession(request: StartShellSessionRequest): Promise<RuntimeTaskSessionSummary>;
38
+ recoverStaleSession(taskId: string): RuntimeTaskSessionSummary | null;
38
39
  writeInput(taskId: string, data: Buffer): RuntimeTaskSessionSummary | null;
39
40
  resize(taskId: string, cols: number, rows: number, pixelWidth?: number, pixelHeight?: number): boolean;
40
41
  pauseOutput(taskId: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/terminal/session-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/terminal/session-manager.ts"],"names":[],"mappings":"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"}
@@ -471,6 +471,34 @@ export class TerminalSessionManager {
471
471
  this.emitSummary(entry.summary);
472
472
  return cloneSummary(entry.summary);
473
473
  }
474
+ recoverStaleSession(taskId) {
475
+ const entry = this.entries.get(taskId);
476
+ if (!entry) {
477
+ return null;
478
+ }
479
+ if (entry.active || !isActiveState(entry.summary.state)) {
480
+ return cloneSummary(entry.summary);
481
+ }
482
+ const summary = updateSummary(entry, {
483
+ state: "idle",
484
+ agentId: null,
485
+ workspacePath: null,
486
+ pid: null,
487
+ startedAt: null,
488
+ lastOutputAt: null,
489
+ reviewReason: null,
490
+ exitCode: null,
491
+ lastHookAt: null,
492
+ latestHookActivity: null,
493
+ latestTurnCheckpoint: null,
494
+ previousTurnCheckpoint: null,
495
+ });
496
+ for (const listener of entry.listeners.values()) {
497
+ listener.onState?.(cloneSummary(summary));
498
+ }
499
+ this.emitSummary(summary);
500
+ return cloneSummary(summary);
501
+ }
474
502
  writeInput(taskId, data) {
475
503
  const entry = this.entries.get(taskId);
476
504
  if (!entry?.active) {