kanban 0.1.13 → 0.1.15
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.
- package/README.md +40 -22
- package/dist/cli.js +26 -41
- package/dist/cli.js.map +1 -1
- package/dist/commands/hooks.d.ts +1 -0
- package/dist/commands/hooks.d.ts.map +1 -1
- package/dist/commands/hooks.js +15 -11
- package/dist/commands/hooks.js.map +1 -1
- package/dist/server/browser.d.ts +8 -1
- package/dist/server/browser.d.ts.map +1 -1
- package/dist/server/browser.js +50 -11
- package/dist/server/browser.js.map +1 -1
- package/dist/server/directory-picker.d.ts +10 -0
- package/dist/server/directory-picker.d.ts.map +1 -0
- package/dist/server/directory-picker.js +114 -0
- package/dist/server/directory-picker.js.map +1 -0
- package/dist/server/process-termination.d.ts +12 -0
- package/dist/server/process-termination.d.ts.map +1 -0
- package/dist/server/process-termination.js +21 -0
- package/dist/server/process-termination.js.map +1 -0
- package/dist/terminal/agent-session-adapters.d.ts.map +1 -1
- package/dist/terminal/agent-session-adapters.js +31 -32
- package/dist/terminal/agent-session-adapters.js.map +1 -1
- package/dist/terminal/opencode-paths.d.ts +10 -0
- package/dist/terminal/opencode-paths.d.ts.map +1 -0
- package/dist/terminal/opencode-paths.js +62 -0
- package/dist/terminal/opencode-paths.js.map +1 -0
- package/dist/terminal/task-start-setup-detection.d.ts.map +1 -1
- package/dist/terminal/task-start-setup-detection.js +2 -10
- package/dist/terminal/task-start-setup-detection.js.map +1 -1
- package/dist/web-ui/assets/{index-CY5RDApA.js → index-2qSmw1LR.js} +5787 -5756
- package/dist/web-ui/index.html +1 -1
- package/dist/workspace/task-worktree.d.ts +8 -0
- package/dist/workspace/task-worktree.d.ts.map +1 -1
- package/dist/workspace/task-worktree.js +15 -1
- package/dist/workspace/task-worktree.js.map +1 -1
- package/package.json +3 -1
package/dist/web-ui/index.html
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
href='data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 16 16%22><path fill=%22%23AAB0B7%22 d=%22M15 0H1C.45 0 0 .45 0 1s.45 1 1 1h14c.55 0 1-.45 1-1s-.45-1-1-1zM6 4H3c-.55 0-1 .45-1 1v9c0 .55.45 1 1 1h3c.55 0 1-.45 1-1V5c0-.55-.45-1-1-1zm7 0h-3c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h3c.55 0 1-.45 1-1V5c0-.55-.45-1-1-1z%22/></svg>'
|
|
9
9
|
/>
|
|
10
10
|
<title>Kanban</title>
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-2qSmw1LR.js"></script>
|
|
12
12
|
<link rel="modulepreload" crossorigin href="/assets/xterm-vendor-x1-S2SBl.js">
|
|
13
13
|
<link rel="stylesheet" crossorigin href="/assets/xterm-vendor-GVL3fBIr.css">
|
|
14
14
|
<link rel="stylesheet" crossorigin href="/assets/index-0KAf_GGl.css">
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { RuntimeTaskWorkspaceInfoResponse, RuntimeWorktreeDeleteResponse, RuntimeWorktreeEnsureResponse } from "../core/api-contract.js";
|
|
2
|
+
type CreateSymlink = (target: string, path: string, type: "dir" | "file") => Promise<void>;
|
|
3
|
+
export declare function mirrorIgnoredPath(options: {
|
|
4
|
+
sourcePath: string;
|
|
5
|
+
targetPath: string;
|
|
6
|
+
isDirectory: boolean;
|
|
7
|
+
createSymlink?: CreateSymlink;
|
|
8
|
+
}): Promise<"mirrored" | "skipped">;
|
|
2
9
|
export declare function ensureTaskWorktreeIfDoesntExist(options: {
|
|
3
10
|
cwd: string;
|
|
4
11
|
taskId: string;
|
|
@@ -24,4 +31,5 @@ export declare function getTaskWorkspaceInfo(options: {
|
|
|
24
31
|
taskId: string;
|
|
25
32
|
baseRef: string;
|
|
26
33
|
}): Promise<RuntimeTaskWorkspaceInfoResponse>;
|
|
34
|
+
export {};
|
|
27
35
|
//# sourceMappingURL=task-worktree.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-worktree.d.ts","sourceRoot":"","sources":["../../src/workspace/task-worktree.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACX,gCAAgC,EAChC,6BAA6B,EAC7B,6BAA6B,EAC7B,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"task-worktree.d.ts","sourceRoot":"","sources":["../../src/workspace/task-worktree.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACX,gCAAgC,EAChC,6BAA6B,EAC7B,6BAA6B,EAC7B,MAAM,yBAAyB,CAAC;AAwBjC,KAAK,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE3F,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,aAAa,CAAC;CAC9B,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAQlC;AA4OD,wBAAsB,+BAA+B,CAAC,OAAO,EAAE;IAC9D,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAoEzC;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAoBzC;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBlB;AAED,wBAAsB,wBAAwB,CAAC,OAAO,EAAE;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,gCAAgC,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC,CAoB5F;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,gCAAgC,CAAC,CAwB5C"}
|
|
@@ -18,6 +18,16 @@ const SYMLINK_PATH_SEGMENT_BLACKLIST = new Set([
|
|
|
18
18
|
".Spotlight-V100",
|
|
19
19
|
".Trashes",
|
|
20
20
|
]);
|
|
21
|
+
export async function mirrorIgnoredPath(options) {
|
|
22
|
+
const createSymlink = options.createSymlink ?? symlink;
|
|
23
|
+
try {
|
|
24
|
+
await createSymlink(options.sourcePath, options.targetPath, options.isDirectory ? "dir" : "file");
|
|
25
|
+
return "mirrored";
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return "skipped";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
21
31
|
function toPlatformRelativePath(path) {
|
|
22
32
|
return path
|
|
23
33
|
.trim()
|
|
@@ -192,7 +202,11 @@ async function syncIgnoredPathsIntoWorktree(repoPath, worktreePath) {
|
|
|
192
202
|
}
|
|
193
203
|
const sourceStat = await lstat(sourcePath);
|
|
194
204
|
await mkdir(dirname(targetPath), { recursive: true });
|
|
195
|
-
await
|
|
205
|
+
await mirrorIgnoredPath({
|
|
206
|
+
sourcePath,
|
|
207
|
+
targetPath,
|
|
208
|
+
isDirectory: sourceStat.isDirectory(),
|
|
209
|
+
});
|
|
196
210
|
}
|
|
197
211
|
}
|
|
198
212
|
async function removeTaskWorktreeInternal(repoPath, worktreePath) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-worktree.js","sourceRoot":"","sources":["../../src/workspace/task-worktree.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile } from \"node:child_process\";\nimport { access, lstat, mkdir, readdir, readFile, rm, symlink, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nimport type {\n\tRuntimeTaskWorkspaceInfoResponse,\n\tRuntimeWorktreeDeleteResponse,\n\tRuntimeWorktreeEnsureResponse,\n} from \"../core/api-contract.js\";\nimport {\n\tKANBAN_TASK_WORKTREES_DIR_NAME,\n\tgetWorkspaceFolderLabelForWorktreePath,\n\tnormalizeTaskIdForWorktreePath,\n} from \"./task-worktree-path.js\";\nimport { createGitProcessEnv } from \"../core/git-process-env.js\";\nimport { getRuntimeHomePath, loadWorkspaceContext } from \"../state/workspace-state.js\";\n\nconst execFileAsync = promisify(execFile);\nconst GIT_MAX_BUFFER_BYTES = 10 * 1024 * 1024;\nconst KANBAN_MANAGED_EXCLUDE_BLOCK_START = \"# kanban-managed-symlinked-ignored-paths:start\";\nconst KANBAN_MANAGED_EXCLUDE_BLOCK_END = \"# kanban-managed-symlinked-ignored-paths:end\";\n\nconst SYMLINK_PATH_SEGMENT_BLACKLIST = new Set([\n\t\".git\",\n\t\".DS_Store\",\n\t\"Thumbs.db\",\n\t\"Desktop.ini\",\n\t\"Icon\\r\",\n\t\".Spotlight-V100\",\n\t\".Trashes\",\n]);\n\nfunction toPlatformRelativePath(path: string): string {\n\treturn path\n\t\t.trim()\n\t\t.replace(/\\/+$/g, \"\")\n\t\t.split(\"/\")\n\t\t.filter((segment) => segment.length > 0)\n\t\t.join(\"/\");\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n\ttry {\n\t\tawait access(path);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function runGit(args: string[]): Promise<string> {\n\tconst { stdout } = await execFileAsync(\"git\", args, {\n\t\tencoding: \"utf8\",\n\t\tmaxBuffer: GIT_MAX_BUFFER_BYTES,\n\t\tenv: createGitProcessEnv(),\n\t});\n\treturn String(stdout).trim();\n}\n\nfunction getGitCommandErrorMessage(error: unknown): string {\n\tif (error && typeof error === \"object\" && \"stderr\" in error) {\n\t\tconst stderr = (error as { stderr?: unknown }).stderr;\n\t\tif (typeof stderr === \"string\" && stderr.trim()) {\n\t\t\treturn stderr.trim();\n\t\t}\n\t}\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nasync function tryRunGit(args: string[]): Promise<string | null> {\n\ttry {\n\t\treturn await runGit(args);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function readGitHeadInfo(cwd: string): Promise<{\n\tbranch: string | null;\n\theadCommit: string | null;\n\tisDetached: boolean;\n}> {\n\tconst headCommit = await tryRunGit([\"-C\", cwd, \"rev-parse\", \"--verify\", \"HEAD\"]);\n\tconst branch = await tryRunGit([\"-C\", cwd, \"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"]);\n\treturn {\n\t\tbranch,\n\t\theadCommit,\n\t\tisDetached: headCommit !== null && branch === null,\n\t};\n}\n\nfunction getWorktreesRootPath(taskId: string): string {\n\tconst normalizedTaskId = normalizeTaskIdForWorktreePath(taskId);\n\treturn join(getRuntimeHomePath(), KANBAN_TASK_WORKTREES_DIR_NAME, normalizedTaskId);\n}\n\nfunction getWorktreesBaseRootPath(): string {\n\treturn join(getRuntimeHomePath(), KANBAN_TASK_WORKTREES_DIR_NAME);\n}\n\nfunction getTaskWorktreePath(repoPath: string, taskId: string): string {\n\tconst workspaceLabel = getWorkspaceFolderLabelForWorktreePath(repoPath);\n\treturn join(getWorktreesRootPath(taskId), workspaceLabel);\n}\n\nfunction shouldSkipSymlink(relativePath: string): boolean {\n\tconst segments = relativePath.split(\"/\").filter((segment) => segment.length > 0);\n\tif (segments.length === 0) {\n\t\treturn true;\n\t}\n\treturn segments.some((segment) => SYMLINK_PATH_SEGMENT_BLACKLIST.has(segment));\n}\n\nfunction isPathWithinRoot(path: string, root: string): boolean {\n\treturn path === root || path.startsWith(`${root}/`);\n}\n\nfunction getUniquePaths(relativePaths: string[]): string[] {\n\tconst uniquePaths = Array.from(new Set(relativePaths.map((path) => toPlatformRelativePath(path)).filter(Boolean)));\n\tuniquePaths.sort((left, right) => {\n\t\tconst leftDepth = left.split(\"/\").length;\n\t\tconst rightDepth = right.split(\"/\").length;\n\t\tif (leftDepth !== rightDepth) {\n\t\t\treturn leftDepth - rightDepth;\n\t\t}\n\t\treturn left.localeCompare(right);\n\t});\n\n\tconst roots: string[] = [];\n\tfor (const path of uniquePaths) {\n\t\tif (roots.some((root) => isPathWithinRoot(path, root))) {\n\t\t\tcontinue;\n\t\t}\n\t\troots.push(path);\n\t}\n\n\treturn roots;\n}\n\nasync function listIgnoredPaths(repoPath: string): Promise<string[]> {\n\tconst output = await runGit([\n\t\t\"-C\",\n\t\trepoPath,\n\t\t\"ls-files\",\n\t\t\"--others\",\n\t\t\"--ignored\",\n\t\t\"--exclude-per-directory=.gitignore\",\n\t\t\"--directory\",\n\t]);\n\treturn output\n\t\t.split(\"\\n\")\n\t\t.map((line) => toPlatformRelativePath(line))\n\t\t.filter((line) => line.length > 0);\n}\n\nfunction escapeGitIgnoreLiteral(path: string): string {\n\tconst normalized = toPlatformRelativePath(path);\n\treturn normalized\n\t\t.replace(/\\\\/g, \"\\\\\\\\\")\n\t\t.replace(/^([#!])/u, \"\\\\$1\")\n\t\t.replace(/([*?[])/g, \"\\\\$1\");\n}\n\nfunction stripManagedExcludeBlock(content: string): string {\n\tconst lines = content.split(\"\\n\");\n\tconst nextLines: string[] = [];\n\tlet insideManagedBlock = false;\n\tfor (const line of lines) {\n\t\tif (line === KANBAN_MANAGED_EXCLUDE_BLOCK_START) {\n\t\t\tinsideManagedBlock = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (line === KANBAN_MANAGED_EXCLUDE_BLOCK_END) {\n\t\t\tinsideManagedBlock = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!insideManagedBlock) {\n\t\t\tnextLines.push(line);\n\t\t}\n\t}\n\treturn nextLines.join(\"\\n\").replace(/\\n+$/g, \"\");\n}\n\nasync function syncManagedIgnoredPathExcludes(repoPath: string, relativePaths: string[]): Promise<void> {\n\tconst excludePathOutput = (await runGit([\"-C\", repoPath, \"rev-parse\", \"--git-path\", \"info/exclude\"])).trim();\n\tif (!excludePathOutput) {\n\t\treturn;\n\t}\n\tconst excludePath = isAbsolute(excludePathOutput) ? excludePathOutput : join(repoPath, excludePathOutput);\n\n\tconst existingContent = await readFile(excludePath, \"utf8\").catch(() => \"\");\n\tconst preservedContent = stripManagedExcludeBlock(existingContent);\n\tconst managedPaths = getUniquePaths(relativePaths);\n\tconst managedBlock =\n\t\tmanagedPaths.length === 0\n\t\t\t? \"\"\n\t\t\t: [\n\t\t\t\t\tKANBAN_MANAGED_EXCLUDE_BLOCK_START,\n\t\t\t\t\t\"# Keep symlinked ignored paths ignored inside Kanban task worktrees.\",\n\t\t\t\t\t...managedPaths.map((relativePath) => `/${escapeGitIgnoreLiteral(relativePath)}`),\n\t\t\t\t\tKANBAN_MANAGED_EXCLUDE_BLOCK_END,\n\t\t\t\t].join(\"\\n\");\n\n\tconst nextContent = [preservedContent, managedBlock].filter(Boolean).join(\"\\n\\n\").replace(/\\n+$/g, \"\");\n\tconst normalizedNextContent = nextContent ? `${nextContent}\\n` : \"\";\n\tif (normalizedNextContent === existingContent) {\n\t\treturn;\n\t}\n\n\tawait mkdir(dirname(excludePath), { recursive: true });\n\tawait writeFile(excludePath, normalizedNextContent, \"utf8\");\n}\n\nasync function syncIgnoredPathsIntoWorktree(repoPath: string, worktreePath: string): Promise<void> {\n\tconst ignoredPaths = getUniquePaths(await listIgnoredPaths(repoPath)).filter(\n\t\t(relativePath) => !shouldSkipSymlink(relativePath),\n\t);\n\tawait syncManagedIgnoredPathExcludes(repoPath, ignoredPaths);\n\tfor (const relativePath of ignoredPaths) {\n\t\tif (shouldSkipSymlink(relativePath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst sourcePath = join(repoPath, relativePath);\n\t\tif (!(await pathExists(sourcePath))) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst targetPath = join(worktreePath, relativePath);\n\t\tif (await pathExists(targetPath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst sourceStat = await lstat(sourcePath);\n\t\tawait mkdir(dirname(targetPath), { recursive: true });\n\t\tawait symlink(sourcePath, targetPath, sourceStat.isDirectory() ? \"dir\" : \"file\");\n\t}\n}\n\nasync function removeTaskWorktreeInternal(repoPath: string, worktreePath: string): Promise<boolean> {\n\tconst existed = await pathExists(worktreePath);\n\tawait tryRunGit([\"-C\", repoPath, \"worktree\", \"remove\", \"--force\", worktreePath]);\n\tawait rm(worktreePath, { recursive: true, force: true });\n\treturn existed;\n}\n\nasync function pruneEmptyParents(rootPath: string, fromPath: string): Promise<void> {\n\tlet current = fromPath;\n\twhile (current.startsWith(rootPath) && current !== rootPath) {\n\t\ttry {\n\t\t\tconst entries = await readdir(current);\n\t\t\tif (entries.length > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait rm(current, { recursive: true, force: true });\n\t\t\tcurrent = dirname(current);\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nexport async function ensureTaskWorktreeIfDoesntExist(options: {\n\tcwd: string;\n\ttaskId: string;\n\tbaseRef: string;\n}): Promise<RuntimeWorktreeEnsureResponse> {\n\ttry {\n\t\tconst context = await loadWorkspaceContext(options.cwd);\n\t\tconst taskId = normalizeTaskIdForWorktreePath(options.taskId);\n\t\tconst worktreePath = getTaskWorktreePath(context.repoPath, taskId);\n\t\t// Investigation note: ensure is called on every task start. The previous implementation\n\t\t// compared the worktree HEAD to the latest baseRef commit and recreated the worktree\n\t\t// when the base branch advanced, which could destroy valid task progress. Existing\n\t\t// worktrees are now treated as authoritative and only missing worktrees are created.\n\t\tconst existingCommit = await tryRunGit([\"-C\", worktreePath, \"rev-parse\", \"HEAD\"]);\n\t\tif (existingCommit) {\n\t\t\tawait syncIgnoredPathsIntoWorktree(context.repoPath, worktreePath);\n\t\t\treturn {\n\t\t\t\tok: true,\n\t\t\t\tpath: worktreePath,\n\t\t\t\tbaseRef: options.baseRef.trim(),\n\t\t\t\tbaseCommit: existingCommit,\n\t\t\t};\n\t\t}\n\n\t\tconst requestedBaseRef = options.baseRef.trim();\n\t\tif (!requestedBaseRef) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tpath: null,\n\t\t\t\tbaseRef: requestedBaseRef,\n\t\t\t\tbaseCommit: null,\n\t\t\t\terror: \"Task base branch is required for worktree creation.\",\n\t\t\t};\n\t\t}\n\n\t\tlet baseCommit: string;\n\t\ttry {\n\t\t\tbaseCommit = await runGit([\"-C\", context.repoPath, \"rev-parse\", \"--verify\", `${requestedBaseRef}^{commit}`]);\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tpath: null,\n\t\t\t\tbaseRef: requestedBaseRef,\n\t\t\t\tbaseCommit: null,\n\t\t\t\terror: getGitCommandErrorMessage(error),\n\t\t\t};\n\t\t}\n\n\t\tif (await pathExists(worktreePath)) {\n\t\t\tawait removeTaskWorktreeInternal(context.repoPath, worktreePath);\n\t\t}\n\n\t\tawait mkdir(dirname(worktreePath), { recursive: true });\n\t\tawait runGit([\"-C\", context.repoPath, \"worktree\", \"add\", \"--detach\", worktreePath, baseCommit]);\n\t\tawait syncIgnoredPathsIntoWorktree(context.repoPath, worktreePath);\n\n\t\treturn {\n\t\t\tok: true,\n\t\t\tpath: worktreePath,\n\t\t\tbaseRef: requestedBaseRef,\n\t\t\tbaseCommit,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tok: false,\n\t\t\tpath: null,\n\t\t\tbaseRef: options.baseRef.trim(),\n\t\t\tbaseCommit: null,\n\t\t\terror: message,\n\t\t};\n\t}\n}\n\nexport async function deleteTaskWorktree(options: {\n\trepoPath: string;\n\ttaskId: string;\n}): Promise<RuntimeWorktreeDeleteResponse> {\n\ttry {\n\t\tconst taskId = normalizeTaskIdForWorktreePath(options.taskId);\n\t\tconst rootPath = getWorktreesBaseRootPath();\n\t\tconst worktreePath = getTaskWorktreePath(options.repoPath, taskId);\n\t\tconst removed = await removeTaskWorktreeInternal(options.repoPath, worktreePath);\n\t\tawait pruneEmptyParents(rootPath, dirname(worktreePath));\n\n\t\treturn {\n\t\t\tok: true,\n\t\t\tremoved,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tok: false,\n\t\t\tremoved: false,\n\t\t\terror: message,\n\t\t};\n\t}\n}\n\nexport async function resolveTaskCwd(options: {\n\tcwd: string;\n\ttaskId: string;\n\tbaseRef: string;\n\tensure?: boolean;\n}): Promise<string> {\n\tconst context = await loadWorkspaceContext(options.cwd);\n\n\tconst normalizedBaseRef = options.baseRef.trim();\n\tif (!normalizedBaseRef) {\n\t\tthrow new Error(\"Task base branch is required for task workspace resolution.\");\n\t}\n\n\tif (options.ensure) {\n\t\tconst ensured = await ensureTaskWorktreeIfDoesntExist({\n\t\t\tcwd: options.cwd,\n\t\t\ttaskId: options.taskId,\n\t\t\tbaseRef: normalizedBaseRef,\n\t\t});\n\t\tif (!ensured.ok) {\n\t\t\tthrow new Error(ensured.error ?? \"Worktree setup failed.\");\n\t\t}\n\t\treturn ensured.path;\n\t}\n\n\tconst worktreePath = getTaskWorktreePath(context.repoPath, options.taskId);\n\tif (await pathExists(worktreePath)) {\n\t\treturn worktreePath;\n\t}\n\tthrow new Error(`Task worktree not found for task \"${options.taskId}\".`);\n}\n\nexport async function getTaskWorkspacePathInfo(options: {\n\tcwd: string;\n\ttaskId: string;\n\tbaseRef: string;\n}): Promise<Pick<RuntimeTaskWorkspaceInfoResponse, \"taskId\" | \"path\" | \"exists\" | \"baseRef\">> {\n\tconst taskId = normalizeTaskIdForWorktreePath(options.taskId);\n\tconst normalizedBaseRef = options.baseRef.trim();\n\tconst repoPath = options.cwd.trim();\n\n\tif (!repoPath) {\n\t\tthrow new Error(\"Task workspace root is required for task workspace info.\");\n\t}\n\n\tif (!normalizedBaseRef) {\n\t\tthrow new Error(\"Task base branch is required for task workspace info.\");\n\t}\n\n\tconst worktreePath = getTaskWorktreePath(repoPath, taskId);\n\treturn {\n\t\ttaskId,\n\t\tpath: worktreePath,\n\t\texists: await pathExists(worktreePath),\n\t\tbaseRef: normalizedBaseRef,\n\t};\n}\n\nexport async function getTaskWorkspaceInfo(options: {\n\tcwd: string;\n\ttaskId: string;\n\tbaseRef: string;\n}): Promise<RuntimeTaskWorkspaceInfoResponse> {\n\tconst workspacePathInfo = await getTaskWorkspacePathInfo(options);\n\tif (!workspacePathInfo.exists) {\n\t\treturn {\n\t\t\ttaskId: workspacePathInfo.taskId,\n\t\t\tpath: workspacePathInfo.path,\n\t\t\texists: false,\n\t\t\tbaseRef: workspacePathInfo.baseRef,\n\t\t\tbranch: null,\n\t\t\tisDetached: false,\n\t\t\theadCommit: null,\n\t\t};\n\t}\n\n\tconst headInfo = await readGitHeadInfo(workspacePathInfo.path);\n\treturn {\n\t\ttaskId: workspacePathInfo.taskId,\n\t\tpath: workspacePathInfo.path,\n\t\texists: true,\n\t\tbaseRef: workspacePathInfo.baseRef,\n\t\tbranch: headInfo.branch,\n\t\tisDetached: headInfo.isDetached,\n\t\theadCommit: headInfo.headCommit,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"task-worktree.js","sourceRoot":"","sources":["../../src/workspace/task-worktree.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile } from \"node:child_process\";\nimport { access, lstat, mkdir, readdir, readFile, rm, symlink, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nimport type {\n\tRuntimeTaskWorkspaceInfoResponse,\n\tRuntimeWorktreeDeleteResponse,\n\tRuntimeWorktreeEnsureResponse,\n} from \"../core/api-contract.js\";\nimport {\n\tKANBAN_TASK_WORKTREES_DIR_NAME,\n\tgetWorkspaceFolderLabelForWorktreePath,\n\tnormalizeTaskIdForWorktreePath,\n} from \"./task-worktree-path.js\";\nimport { createGitProcessEnv } from \"../core/git-process-env.js\";\nimport { getRuntimeHomePath, loadWorkspaceContext } from \"../state/workspace-state.js\";\n\nconst execFileAsync = promisify(execFile);\nconst GIT_MAX_BUFFER_BYTES = 10 * 1024 * 1024;\nconst KANBAN_MANAGED_EXCLUDE_BLOCK_START = \"# kanban-managed-symlinked-ignored-paths:start\";\nconst KANBAN_MANAGED_EXCLUDE_BLOCK_END = \"# kanban-managed-symlinked-ignored-paths:end\";\n\nconst SYMLINK_PATH_SEGMENT_BLACKLIST = new Set([\n\t\".git\",\n\t\".DS_Store\",\n\t\"Thumbs.db\",\n\t\"Desktop.ini\",\n\t\"Icon\\r\",\n\t\".Spotlight-V100\",\n\t\".Trashes\",\n]);\n\ntype CreateSymlink = (target: string, path: string, type: \"dir\" | \"file\") => Promise<void>;\n\nexport async function mirrorIgnoredPath(options: {\n\tsourcePath: string;\n\ttargetPath: string;\n\tisDirectory: boolean;\n\tcreateSymlink?: CreateSymlink;\n}): Promise<\"mirrored\" | \"skipped\"> {\n\tconst createSymlink = options.createSymlink ?? symlink;\n\ttry {\n\t\tawait createSymlink(options.sourcePath, options.targetPath, options.isDirectory ? \"dir\" : \"file\");\n\t\treturn \"mirrored\";\n\t} catch {\n\t\treturn \"skipped\";\n\t}\n}\n\nfunction toPlatformRelativePath(path: string): string {\n\treturn path\n\t\t.trim()\n\t\t.replace(/\\/+$/g, \"\")\n\t\t.split(\"/\")\n\t\t.filter((segment) => segment.length > 0)\n\t\t.join(\"/\");\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n\ttry {\n\t\tawait access(path);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function runGit(args: string[]): Promise<string> {\n\tconst { stdout } = await execFileAsync(\"git\", args, {\n\t\tencoding: \"utf8\",\n\t\tmaxBuffer: GIT_MAX_BUFFER_BYTES,\n\t\tenv: createGitProcessEnv(),\n\t});\n\treturn String(stdout).trim();\n}\n\nfunction getGitCommandErrorMessage(error: unknown): string {\n\tif (error && typeof error === \"object\" && \"stderr\" in error) {\n\t\tconst stderr = (error as { stderr?: unknown }).stderr;\n\t\tif (typeof stderr === \"string\" && stderr.trim()) {\n\t\t\treturn stderr.trim();\n\t\t}\n\t}\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nasync function tryRunGit(args: string[]): Promise<string | null> {\n\ttry {\n\t\treturn await runGit(args);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function readGitHeadInfo(cwd: string): Promise<{\n\tbranch: string | null;\n\theadCommit: string | null;\n\tisDetached: boolean;\n}> {\n\tconst headCommit = await tryRunGit([\"-C\", cwd, \"rev-parse\", \"--verify\", \"HEAD\"]);\n\tconst branch = await tryRunGit([\"-C\", cwd, \"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"]);\n\treturn {\n\t\tbranch,\n\t\theadCommit,\n\t\tisDetached: headCommit !== null && branch === null,\n\t};\n}\n\nfunction getWorktreesRootPath(taskId: string): string {\n\tconst normalizedTaskId = normalizeTaskIdForWorktreePath(taskId);\n\treturn join(getRuntimeHomePath(), KANBAN_TASK_WORKTREES_DIR_NAME, normalizedTaskId);\n}\n\nfunction getWorktreesBaseRootPath(): string {\n\treturn join(getRuntimeHomePath(), KANBAN_TASK_WORKTREES_DIR_NAME);\n}\n\nfunction getTaskWorktreePath(repoPath: string, taskId: string): string {\n\tconst workspaceLabel = getWorkspaceFolderLabelForWorktreePath(repoPath);\n\treturn join(getWorktreesRootPath(taskId), workspaceLabel);\n}\n\nfunction shouldSkipSymlink(relativePath: string): boolean {\n\tconst segments = relativePath.split(\"/\").filter((segment) => segment.length > 0);\n\tif (segments.length === 0) {\n\t\treturn true;\n\t}\n\treturn segments.some((segment) => SYMLINK_PATH_SEGMENT_BLACKLIST.has(segment));\n}\n\nfunction isPathWithinRoot(path: string, root: string): boolean {\n\treturn path === root || path.startsWith(`${root}/`);\n}\n\nfunction getUniquePaths(relativePaths: string[]): string[] {\n\tconst uniquePaths = Array.from(new Set(relativePaths.map((path) => toPlatformRelativePath(path)).filter(Boolean)));\n\tuniquePaths.sort((left, right) => {\n\t\tconst leftDepth = left.split(\"/\").length;\n\t\tconst rightDepth = right.split(\"/\").length;\n\t\tif (leftDepth !== rightDepth) {\n\t\t\treturn leftDepth - rightDepth;\n\t\t}\n\t\treturn left.localeCompare(right);\n\t});\n\n\tconst roots: string[] = [];\n\tfor (const path of uniquePaths) {\n\t\tif (roots.some((root) => isPathWithinRoot(path, root))) {\n\t\t\tcontinue;\n\t\t}\n\t\troots.push(path);\n\t}\n\n\treturn roots;\n}\n\nasync function listIgnoredPaths(repoPath: string): Promise<string[]> {\n\tconst output = await runGit([\n\t\t\"-C\",\n\t\trepoPath,\n\t\t\"ls-files\",\n\t\t\"--others\",\n\t\t\"--ignored\",\n\t\t\"--exclude-per-directory=.gitignore\",\n\t\t\"--directory\",\n\t]);\n\treturn output\n\t\t.split(\"\\n\")\n\t\t.map((line) => toPlatformRelativePath(line))\n\t\t.filter((line) => line.length > 0);\n}\n\nfunction escapeGitIgnoreLiteral(path: string): string {\n\tconst normalized = toPlatformRelativePath(path);\n\treturn normalized\n\t\t.replace(/\\\\/g, \"\\\\\\\\\")\n\t\t.replace(/^([#!])/u, \"\\\\$1\")\n\t\t.replace(/([*?[])/g, \"\\\\$1\");\n}\n\nfunction stripManagedExcludeBlock(content: string): string {\n\tconst lines = content.split(\"\\n\");\n\tconst nextLines: string[] = [];\n\tlet insideManagedBlock = false;\n\tfor (const line of lines) {\n\t\tif (line === KANBAN_MANAGED_EXCLUDE_BLOCK_START) {\n\t\t\tinsideManagedBlock = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (line === KANBAN_MANAGED_EXCLUDE_BLOCK_END) {\n\t\t\tinsideManagedBlock = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!insideManagedBlock) {\n\t\t\tnextLines.push(line);\n\t\t}\n\t}\n\treturn nextLines.join(\"\\n\").replace(/\\n+$/g, \"\");\n}\n\nasync function syncManagedIgnoredPathExcludes(repoPath: string, relativePaths: string[]): Promise<void> {\n\tconst excludePathOutput = (await runGit([\"-C\", repoPath, \"rev-parse\", \"--git-path\", \"info/exclude\"])).trim();\n\tif (!excludePathOutput) {\n\t\treturn;\n\t}\n\tconst excludePath = isAbsolute(excludePathOutput) ? excludePathOutput : join(repoPath, excludePathOutput);\n\n\tconst existingContent = await readFile(excludePath, \"utf8\").catch(() => \"\");\n\tconst preservedContent = stripManagedExcludeBlock(existingContent);\n\tconst managedPaths = getUniquePaths(relativePaths);\n\tconst managedBlock =\n\t\tmanagedPaths.length === 0\n\t\t\t? \"\"\n\t\t\t: [\n\t\t\t\t\tKANBAN_MANAGED_EXCLUDE_BLOCK_START,\n\t\t\t\t\t\"# Keep symlinked ignored paths ignored inside Kanban task worktrees.\",\n\t\t\t\t\t...managedPaths.map((relativePath) => `/${escapeGitIgnoreLiteral(relativePath)}`),\n\t\t\t\t\tKANBAN_MANAGED_EXCLUDE_BLOCK_END,\n\t\t\t\t].join(\"\\n\");\n\n\tconst nextContent = [preservedContent, managedBlock].filter(Boolean).join(\"\\n\\n\").replace(/\\n+$/g, \"\");\n\tconst normalizedNextContent = nextContent ? `${nextContent}\\n` : \"\";\n\tif (normalizedNextContent === existingContent) {\n\t\treturn;\n\t}\n\n\tawait mkdir(dirname(excludePath), { recursive: true });\n\tawait writeFile(excludePath, normalizedNextContent, \"utf8\");\n}\n\nasync function syncIgnoredPathsIntoWorktree(repoPath: string, worktreePath: string): Promise<void> {\n\tconst ignoredPaths = getUniquePaths(await listIgnoredPaths(repoPath)).filter(\n\t\t(relativePath) => !shouldSkipSymlink(relativePath),\n\t);\n\tawait syncManagedIgnoredPathExcludes(repoPath, ignoredPaths);\n\tfor (const relativePath of ignoredPaths) {\n\t\tif (shouldSkipSymlink(relativePath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst sourcePath = join(repoPath, relativePath);\n\t\tif (!(await pathExists(sourcePath))) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst targetPath = join(worktreePath, relativePath);\n\t\tif (await pathExists(targetPath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst sourceStat = await lstat(sourcePath);\n\t\tawait mkdir(dirname(targetPath), { recursive: true });\n\t\tawait mirrorIgnoredPath({\n\t\t\tsourcePath,\n\t\t\ttargetPath,\n\t\t\tisDirectory: sourceStat.isDirectory(),\n\t\t});\n\t}\n}\n\nasync function removeTaskWorktreeInternal(repoPath: string, worktreePath: string): Promise<boolean> {\n\tconst existed = await pathExists(worktreePath);\n\tawait tryRunGit([\"-C\", repoPath, \"worktree\", \"remove\", \"--force\", worktreePath]);\n\tawait rm(worktreePath, { recursive: true, force: true });\n\treturn existed;\n}\n\nasync function pruneEmptyParents(rootPath: string, fromPath: string): Promise<void> {\n\tlet current = fromPath;\n\twhile (current.startsWith(rootPath) && current !== rootPath) {\n\t\ttry {\n\t\t\tconst entries = await readdir(current);\n\t\t\tif (entries.length > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait rm(current, { recursive: true, force: true });\n\t\t\tcurrent = dirname(current);\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nexport async function ensureTaskWorktreeIfDoesntExist(options: {\n\tcwd: string;\n\ttaskId: string;\n\tbaseRef: string;\n}): Promise<RuntimeWorktreeEnsureResponse> {\n\ttry {\n\t\tconst context = await loadWorkspaceContext(options.cwd);\n\t\tconst taskId = normalizeTaskIdForWorktreePath(options.taskId);\n\t\tconst worktreePath = getTaskWorktreePath(context.repoPath, taskId);\n\t\t// Investigation note: ensure is called on every task start. The previous implementation\n\t\t// compared the worktree HEAD to the latest baseRef commit and recreated the worktree\n\t\t// when the base branch advanced, which could destroy valid task progress. Existing\n\t\t// worktrees are now treated as authoritative and only missing worktrees are created.\n\t\tconst existingCommit = await tryRunGit([\"-C\", worktreePath, \"rev-parse\", \"HEAD\"]);\n\t\tif (existingCommit) {\n\t\t\tawait syncIgnoredPathsIntoWorktree(context.repoPath, worktreePath);\n\t\t\treturn {\n\t\t\t\tok: true,\n\t\t\t\tpath: worktreePath,\n\t\t\t\tbaseRef: options.baseRef.trim(),\n\t\t\t\tbaseCommit: existingCommit,\n\t\t\t};\n\t\t}\n\n\t\tconst requestedBaseRef = options.baseRef.trim();\n\t\tif (!requestedBaseRef) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tpath: null,\n\t\t\t\tbaseRef: requestedBaseRef,\n\t\t\t\tbaseCommit: null,\n\t\t\t\terror: \"Task base branch is required for worktree creation.\",\n\t\t\t};\n\t\t}\n\n\t\tlet baseCommit: string;\n\t\ttry {\n\t\t\tbaseCommit = await runGit([\"-C\", context.repoPath, \"rev-parse\", \"--verify\", `${requestedBaseRef}^{commit}`]);\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tpath: null,\n\t\t\t\tbaseRef: requestedBaseRef,\n\t\t\t\tbaseCommit: null,\n\t\t\t\terror: getGitCommandErrorMessage(error),\n\t\t\t};\n\t\t}\n\n\t\tif (await pathExists(worktreePath)) {\n\t\t\tawait removeTaskWorktreeInternal(context.repoPath, worktreePath);\n\t\t}\n\n\t\tawait mkdir(dirname(worktreePath), { recursive: true });\n\t\tawait runGit([\"-C\", context.repoPath, \"worktree\", \"add\", \"--detach\", worktreePath, baseCommit]);\n\t\tawait syncIgnoredPathsIntoWorktree(context.repoPath, worktreePath);\n\n\t\treturn {\n\t\t\tok: true,\n\t\t\tpath: worktreePath,\n\t\t\tbaseRef: requestedBaseRef,\n\t\t\tbaseCommit,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tok: false,\n\t\t\tpath: null,\n\t\t\tbaseRef: options.baseRef.trim(),\n\t\t\tbaseCommit: null,\n\t\t\terror: message,\n\t\t};\n\t}\n}\n\nexport async function deleteTaskWorktree(options: {\n\trepoPath: string;\n\ttaskId: string;\n}): Promise<RuntimeWorktreeDeleteResponse> {\n\ttry {\n\t\tconst taskId = normalizeTaskIdForWorktreePath(options.taskId);\n\t\tconst rootPath = getWorktreesBaseRootPath();\n\t\tconst worktreePath = getTaskWorktreePath(options.repoPath, taskId);\n\t\tconst removed = await removeTaskWorktreeInternal(options.repoPath, worktreePath);\n\t\tawait pruneEmptyParents(rootPath, dirname(worktreePath));\n\n\t\treturn {\n\t\t\tok: true,\n\t\t\tremoved,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tok: false,\n\t\t\tremoved: false,\n\t\t\terror: message,\n\t\t};\n\t}\n}\n\nexport async function resolveTaskCwd(options: {\n\tcwd: string;\n\ttaskId: string;\n\tbaseRef: string;\n\tensure?: boolean;\n}): Promise<string> {\n\tconst context = await loadWorkspaceContext(options.cwd);\n\n\tconst normalizedBaseRef = options.baseRef.trim();\n\tif (!normalizedBaseRef) {\n\t\tthrow new Error(\"Task base branch is required for task workspace resolution.\");\n\t}\n\n\tif (options.ensure) {\n\t\tconst ensured = await ensureTaskWorktreeIfDoesntExist({\n\t\t\tcwd: options.cwd,\n\t\t\ttaskId: options.taskId,\n\t\t\tbaseRef: normalizedBaseRef,\n\t\t});\n\t\tif (!ensured.ok) {\n\t\t\tthrow new Error(ensured.error ?? \"Worktree setup failed.\");\n\t\t}\n\t\treturn ensured.path;\n\t}\n\n\tconst worktreePath = getTaskWorktreePath(context.repoPath, options.taskId);\n\tif (await pathExists(worktreePath)) {\n\t\treturn worktreePath;\n\t}\n\tthrow new Error(`Task worktree not found for task \"${options.taskId}\".`);\n}\n\nexport async function getTaskWorkspacePathInfo(options: {\n\tcwd: string;\n\ttaskId: string;\n\tbaseRef: string;\n}): Promise<Pick<RuntimeTaskWorkspaceInfoResponse, \"taskId\" | \"path\" | \"exists\" | \"baseRef\">> {\n\tconst taskId = normalizeTaskIdForWorktreePath(options.taskId);\n\tconst normalizedBaseRef = options.baseRef.trim();\n\tconst repoPath = options.cwd.trim();\n\n\tif (!repoPath) {\n\t\tthrow new Error(\"Task workspace root is required for task workspace info.\");\n\t}\n\n\tif (!normalizedBaseRef) {\n\t\tthrow new Error(\"Task base branch is required for task workspace info.\");\n\t}\n\n\tconst worktreePath = getTaskWorktreePath(repoPath, taskId);\n\treturn {\n\t\ttaskId,\n\t\tpath: worktreePath,\n\t\texists: await pathExists(worktreePath),\n\t\tbaseRef: normalizedBaseRef,\n\t};\n}\n\nexport async function getTaskWorkspaceInfo(options: {\n\tcwd: string;\n\ttaskId: string;\n\tbaseRef: string;\n}): Promise<RuntimeTaskWorkspaceInfoResponse> {\n\tconst workspacePathInfo = await getTaskWorkspacePathInfo(options);\n\tif (!workspacePathInfo.exists) {\n\t\treturn {\n\t\t\ttaskId: workspacePathInfo.taskId,\n\t\t\tpath: workspacePathInfo.path,\n\t\t\texists: false,\n\t\t\tbaseRef: workspacePathInfo.baseRef,\n\t\t\tbranch: null,\n\t\t\tisDetached: false,\n\t\t\theadCommit: null,\n\t\t};\n\t}\n\n\tconst headInfo = await readGitHeadInfo(workspacePathInfo.path);\n\treturn {\n\t\ttaskId: workspacePathInfo.taskId,\n\t\tpath: workspacePathInfo.path,\n\t\texists: true,\n\t\tbaseRef: workspacePathInfo.baseRef,\n\t\tbranch: headInfo.branch,\n\t\tisDetached: headInfo.isDetached,\n\t\theadCommit: headInfo.headCommit,\n\t};\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kanban",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "A kanban foundation for coding agents",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -79,8 +79,10 @@
|
|
|
79
79
|
"dependencies": {
|
|
80
80
|
"@trpc/client": "^11.11.0",
|
|
81
81
|
"@trpc/server": "^11.11.0",
|
|
82
|
+
"close-with-grace": "^2.5.0",
|
|
82
83
|
"commander": "^14.0.3",
|
|
83
84
|
"node-pty": "^1.2.0-beta.11",
|
|
85
|
+
"tree-kill": "^1.2.2",
|
|
84
86
|
"ws": "^8.18.0",
|
|
85
87
|
"zod": "^4.3.6"
|
|
86
88
|
}
|