kanban 0.1.8 → 0.1.9

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.
@@ -1,6 +1,6 @@
1
1
  import { I as r } from "./index-B3UqAa14.js";
2
2
  import { I as s } from "./index-Ba0NPEqA.js";
3
- import { p as n, I as c } from "./index-wbRvTOKg.js";
3
+ import { p as n, I as c } from "./index-DZcGgUMk.js";
4
4
  import "./xterm-vendor-x1-S2SBl.js";
5
5
  function i(t, a) {
6
6
  const o = n(t);
@@ -1,9 +1,9 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/allPaths-BDxYnTzd.js","assets/index-B3UqAa14.js","assets/index-Ba0NPEqA.js","assets/index-wbRvTOKg.js","assets/xterm-vendor-x1-S2SBl.js","assets/xterm-vendor-GVL3fBIr.css","assets/index-Cu5zb3Kf.css"])))=>i.map(i=>d[i]);
2
- import { _ as r } from "./index-wbRvTOKg.js";
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/allPaths-DOTpTORM.js","assets/index-B3UqAa14.js","assets/index-Ba0NPEqA.js","assets/index-DZcGgUMk.js","assets/xterm-vendor-x1-S2SBl.js","assets/xterm-vendor-GVL3fBIr.css","assets/index-Cu5zb3Kf.css"])))=>i.map(i=>d[i]);
2
+ import { _ as r } from "./index-DZcGgUMk.js";
3
3
  import "./xterm-vendor-x1-S2SBl.js";
4
4
  const e = async (t, _) => {
5
5
  const { getIconPaths: a } = await r(async () => {
6
- const { getIconPaths: o } = await import("./allPaths-BDxYnTzd.js");
6
+ const { getIconPaths: o } = await import("./allPaths-DOTpTORM.js");
7
7
  return { getIconPaths: o };
8
8
  }, true ? __vite__mapDeps([0,1,2,3,4,5,6]) : void 0);
9
9
  return a(t, _);
@@ -1,4 +1,4 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/allPathsLoader-DSjs6l5u.js","assets/xterm-vendor-x1-S2SBl.js","assets/xterm-vendor-GVL3fBIr.css","assets/splitPathsBySizeLoader-BqUPAhbU.js"])))=>i.map(i=>d[i]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/allPathsLoader-QnqMU9zv.js","assets/xterm-vendor-x1-S2SBl.js","assets/xterm-vendor-GVL3fBIr.css","assets/splitPathsBySizeLoader-BpwicruJ.js"])))=>i.map(i=>d[i]);
2
2
  var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -672,10 +672,10 @@ async function RD(e, t) {
672
672
  async function AD(e) {
673
673
  const { loader: t = za.defaultLoader } = e;
674
674
  return typeof t == "function" ? t : t === "all" ? (await Xw(async () => {
675
- const { allPathsLoader: n } = await import("./allPathsLoader-DSjs6l5u.js");
675
+ const { allPathsLoader: n } = await import("./allPathsLoader-QnqMU9zv.js");
676
676
  return { allPathsLoader: n };
677
677
  }, true ? __vite__mapDeps([0,1,2]) : void 0)).allPathsLoader : (await Xw(async () => {
678
- const { splitPathsBySizeLoader: n } = await import("./splitPathsBySizeLoader-BqUPAhbU.js");
678
+ const { splitPathsBySizeLoader: n } = await import("./splitPathsBySizeLoader-BpwicruJ.js");
679
679
  return { splitPathsBySizeLoader: n };
680
680
  }, true ? __vite__mapDeps([3,1,2]) : void 0)).splitPathsBySizeLoader;
681
681
  }
@@ -22953,7 +22953,7 @@ function dB({ isOpen: e, onClose: t }) {
22953
22953
  const fB = "https://github.com/cline/kanban";
22954
22954
  function pB({ projects: e, isLoadingProjects: t = false, currentProjectId: n, removingProjectId: r, onSelectProject: i, onRemoveProject: s, onAddProject: a }) {
22955
22955
  const c = [...e].sort((m, y) => m.path.localeCompare(y.path)), [u, f] = b.useState(null), p = u !== null && r === u.id, h = u ? u.taskCounts.backlog + u.taskCounts.in_progress + u.taskCounts.review + u.taskCounts.trash : 0;
22956
- return v.jsxs("aside", { style: { display: "flex", flexDirection: "column", width: "20%", minHeight: 0, overflow: "hidden", borderRight: `1px solid ${Lr}`, background: ve.DARK_GRAY2 }, children: [v.jsx("div", { style: { padding: "12px 12px 8px" }, children: v.jsxs("div", { style: { display: "flex", alignItems: "flex-start", gap: 8 }, children: [v.jsx(et, { icon: "alignment-top", size: 20, color: "#AAB0B7", style: { marginTop: 4.5 } }), v.jsxs("div", { children: [v.jsxs("div", { style: { fontWeight: 600, fontSize: "var(--bp-typography-size-body-large)" }, children: ["kanban", " ", v.jsxs("span", { className: It, style: { fontWeight: 400, fontSize: "var(--bp-typography-size-body-small)" }, children: ["v", "0.1.8"] })] }), v.jsx(Ah, { href: fB, target: "_blank", rel: "noopener noreferrer", variant: "minimal", intent: "primary", size: "small", style: { padding: 0, minHeight: 0, fontSize: "var(--bp-typography-size-body-small)" }, children: "View on GitHub" })] })] }) }), v.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", padding: "4px 12px" }, children: [v.jsx("span", { className: It, style: { fontSize: "var(--bp-typography-size-body-medium)" }, children: "Projects" }), v.jsx(He, { icon: "plus", size: "small", variant: "minimal", onClick: a, "aria-label": "Add project", disabled: r !== null })] }), v.jsxs("div", { style: { flex: "1 1 0", minHeight: 0, overflowY: "auto", overscrollBehavior: "contain", padding: "4px 0" }, children: [c.length === 0 ? t ? v.jsx("div", { style: { padding: "4px 0" }, children: Array.from({ length: 3 }).map((m, y) => v.jsx(hB, {}, `project-skeleton-${y}`)) }) : v.jsx("div", { style: { padding: "24px 12px", textAlign: "center" }, children: v.jsx("span", { className: It, children: "No projects yet" }) }) : null, c.map((m) => v.jsx(mB, { project: m, isCurrent: n === m.id, removingProjectId: r, onSelect: i, onRemove: (y) => {
22956
+ return v.jsxs("aside", { style: { display: "flex", flexDirection: "column", width: "20%", minHeight: 0, overflow: "hidden", borderRight: `1px solid ${Lr}`, background: ve.DARK_GRAY2 }, children: [v.jsx("div", { style: { padding: "12px 12px 8px" }, children: v.jsxs("div", { style: { display: "flex", alignItems: "flex-start", gap: 8 }, children: [v.jsx(et, { icon: "alignment-top", size: 20, color: "#AAB0B7", style: { marginTop: 4.5 } }), v.jsxs("div", { children: [v.jsxs("div", { style: { fontWeight: 600, fontSize: "var(--bp-typography-size-body-large)" }, children: ["kanban", " ", v.jsxs("span", { className: It, style: { fontWeight: 400, fontSize: "var(--bp-typography-size-body-small)" }, children: ["v", "0.1.9"] })] }), v.jsx(Ah, { href: fB, target: "_blank", rel: "noopener noreferrer", variant: "minimal", intent: "primary", size: "small", style: { padding: 0, minHeight: 0, fontSize: "var(--bp-typography-size-body-small)" }, children: "View on GitHub" })] })] }) }), v.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", padding: "4px 12px" }, children: [v.jsx("span", { className: It, style: { fontSize: "var(--bp-typography-size-body-medium)" }, children: "Projects" }), v.jsx(He, { icon: "plus", size: "small", variant: "minimal", onClick: a, "aria-label": "Add project", disabled: r !== null })] }), v.jsxs("div", { style: { flex: "1 1 0", minHeight: 0, overflowY: "auto", overscrollBehavior: "contain", padding: "4px 0" }, children: [c.length === 0 ? t ? v.jsx("div", { style: { padding: "4px 0" }, children: Array.from({ length: 3 }).map((m, y) => v.jsx(hB, {}, `project-skeleton-${y}`)) }) : v.jsx("div", { style: { padding: "24px 12px", textAlign: "center" }, children: v.jsx("span", { className: It, children: "No projects yet" }) }) : null, c.map((m) => v.jsx(mB, { project: m, isCurrent: n === m.id, removingProjectId: r, onSelect: i, onRemove: (y) => {
22957
22957
  const C = c.find((w) => w.id === y);
22958
22958
  C && f(C);
22959
22959
  } }, m.id))] }), v.jsxs("div", { className: It, style: { padding: "8px 12px", fontSize: "var(--bp-typography-size-body-x-small)", textAlign: "center" }, children: ["Made with ", v.jsx(et, { icon: "heart", size: 10 }), " by Cline"] }), v.jsxs(El, { isOpen: u !== null, icon: "warning-sign", intent: "danger", confirmButtonText: p ? "Deleting..." : "Delete Project", cancelButtonText: "Cancel", loading: p, onCancel: () => {
@@ -1,4 +1,4 @@
1
- import { p as s, I as r, _ as a } from "./index-wbRvTOKg.js";
1
+ import { p as s, I as r, _ as a } from "./index-DZcGgUMk.js";
2
2
  import "./xterm-vendor-x1-S2SBl.js";
3
3
  const E = async (e, o) => {
4
4
  const i = s(e);
@@ -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 Webview</title>
11
- <script type="module" crossorigin src="/assets/index-wbRvTOKg.js"></script>
11
+ <script type="module" crossorigin src="/assets/index-DZcGgUMk.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-Cu5zb3Kf.css">
@@ -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;AAwSjC,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,CAmEzC;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"}
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;AAgRjC,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"}
@@ -1,12 +1,14 @@
1
1
  import { execFile } from "node:child_process";
2
- import { access, lstat, mkdir, readdir, rm, symlink } from "node:fs/promises";
3
- import { basename, dirname, join } from "node:path";
2
+ import { access, lstat, mkdir, readFile, readdir, rm, symlink, writeFile } from "node:fs/promises";
3
+ import { basename, dirname, isAbsolute, join } from "node:path";
4
4
  import { promisify } from "node:util";
5
5
  import { createGitProcessEnv } from "../core/git-process-env.js";
6
6
  import { getRuntimeHomePath, loadWorkspaceContext } from "../state/workspace-state.js";
7
7
  const execFileAsync = promisify(execFile);
8
8
  const GIT_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
9
9
  const WORKTREES_DIR = "worktrees";
10
+ const KANBAN_MANAGED_EXCLUDE_BLOCK_START = "# kanban-managed-symlinked-ignored-paths:start";
11
+ const KANBAN_MANAGED_EXCLUDE_BLOCK_END = "# kanban-managed-symlinked-ignored-paths:end";
10
12
  const SYMLINK_PATH_SEGMENT_BLACKLIST = new Set([
11
13
  ".git",
12
14
  ".DS_Store",
@@ -110,15 +112,7 @@ function shouldSkipSymlink(relativePath) {
110
112
  function isPathWithinRoot(path, root) {
111
113
  return path === root || path.startsWith(`${root}/`);
112
114
  }
113
- function isPathWithinAnyRoot(path, roots) {
114
- for (const root of roots) {
115
- if (isPathWithinRoot(path, root)) {
116
- return true;
117
- }
118
- }
119
- return false;
120
- }
121
- function getRootIgnoredPaths(relativePaths) {
115
+ function getUniquePaths(relativePaths) {
122
116
  const uniquePaths = Array.from(new Set(relativePaths.map((path) => toPlatformRelativePath(path)).filter(Boolean)));
123
117
  uniquePaths.sort((left, right) => {
124
118
  const leftDepth = left.split("/").length;
@@ -152,77 +146,64 @@ async function listIgnoredPaths(repoPath) {
152
146
  .map((line) => toPlatformRelativePath(line))
153
147
  .filter((line) => line.length > 0);
154
148
  }
155
- function isIgnoredByOwnNestedRule(ignoredPath, ignoreSourcePath) {
156
- const normalizedIgnoredPath = toPlatformRelativePath(ignoredPath);
157
- const normalizedIgnoreSourcePath = toPlatformRelativePath(ignoreSourcePath);
158
- if (!normalizedIgnoredPath || !normalizedIgnoreSourcePath) {
159
- return false;
160
- }
161
- return normalizedIgnoreSourcePath.startsWith(`${normalizedIgnoredPath}/`);
149
+ function escapeGitIgnoreLiteral(path) {
150
+ const normalized = toPlatformRelativePath(path);
151
+ return normalized
152
+ .replace(/\\/g, "\\\\")
153
+ .replace(/^([#!])/u, "\\$1")
154
+ .replace(/([*?\[])/g, "\\$1");
162
155
  }
163
- function parseCheckIgnoreVerboseLine(line) {
164
- const [sourceMetadata, ignoredPathRaw] = line.split("\t");
165
- if (!sourceMetadata || !ignoredPathRaw) {
166
- return null;
167
- }
168
- const sourceMatch = sourceMetadata.match(/^(.*):(\d+):(.*)$/u);
169
- if (!sourceMatch) {
170
- return null;
171
- }
172
- const ignoreSourcePath = toPlatformRelativePath(sourceMatch[1] ?? "");
173
- const ignoredPath = toPlatformRelativePath(ignoredPathRaw);
174
- if (!ignoreSourcePath || !ignoredPath) {
175
- return null;
176
- }
177
- return {
178
- ignoredPath,
179
- ignoreSourcePath,
180
- };
181
- }
182
- async function listSelfIgnoredPaths(repoPath, relativePaths) {
183
- // Some tool-managed directories are ignored by nested rules inside the directory itself,
184
- // e.g. Husky's `.husky/_/.gitignore` with `*` ignores `.husky/_/`.
185
- // If we symlink those directories into a worktree, git won't apply the nested ignore rule
186
- // through the symlink boundary and the path shows up as untracked (`?? .husky/_`).
187
- // We detect those root paths and skip symlinking them.
188
- const rootIgnoredPaths = getRootIgnoredPaths(relativePaths);
189
- if (rootIgnoredPaths.length === 0) {
190
- return new Set();
191
- }
192
- const selfIgnoredPaths = new Set();
193
- for (const relativePath of rootIgnoredPaths) {
194
- const sourcePath = join(repoPath, relativePath);
195
- const sourceStat = await lstat(sourcePath).catch(() => null);
196
- if (!sourceStat?.isDirectory()) {
197
- continue;
198
- }
199
- const output = await tryRunGit(["-C", repoPath, "check-ignore", "-v", "--", `${relativePath}/`]);
200
- if (!output) {
201
- continue;
202
- }
203
- const parsed = parseCheckIgnoreVerboseLine(output.split("\n")[0] ?? "");
204
- if (!parsed) {
156
+ function stripManagedExcludeBlock(content) {
157
+ const lines = content.split("\n");
158
+ const nextLines = [];
159
+ let insideManagedBlock = false;
160
+ for (const line of lines) {
161
+ if (line === KANBAN_MANAGED_EXCLUDE_BLOCK_START) {
162
+ insideManagedBlock = true;
205
163
  continue;
206
164
  }
207
- if (parsed.ignoredPath !== relativePath) {
165
+ if (line === KANBAN_MANAGED_EXCLUDE_BLOCK_END) {
166
+ insideManagedBlock = false;
208
167
  continue;
209
168
  }
210
- if (isIgnoredByOwnNestedRule(relativePath, parsed.ignoreSourcePath)) {
211
- selfIgnoredPaths.add(relativePath);
169
+ if (!insideManagedBlock) {
170
+ nextLines.push(line);
212
171
  }
213
172
  }
214
- return selfIgnoredPaths;
173
+ return nextLines.join("\n").replace(/\n+$/g, "");
174
+ }
175
+ async function syncManagedIgnoredPathExcludes(repoPath, relativePaths) {
176
+ const excludePathOutput = (await runGit(["-C", repoPath, "rev-parse", "--git-path", "info/exclude"])).trim();
177
+ if (!excludePathOutput) {
178
+ return;
179
+ }
180
+ const excludePath = isAbsolute(excludePathOutput) ? excludePathOutput : join(repoPath, excludePathOutput);
181
+ const existingContent = await readFile(excludePath, "utf8").catch(() => "");
182
+ const preservedContent = stripManagedExcludeBlock(existingContent);
183
+ const managedPaths = getUniquePaths(relativePaths);
184
+ const managedBlock = managedPaths.length === 0
185
+ ? ""
186
+ : [
187
+ KANBAN_MANAGED_EXCLUDE_BLOCK_START,
188
+ "# Keep symlinked ignored paths ignored inside Kanban task worktrees.",
189
+ ...managedPaths.map((relativePath) => `/${escapeGitIgnoreLiteral(relativePath)}`),
190
+ KANBAN_MANAGED_EXCLUDE_BLOCK_END,
191
+ ].join("\n");
192
+ const nextContent = [preservedContent, managedBlock].filter(Boolean).join("\n\n").replace(/\n+$/g, "");
193
+ const normalizedNextContent = nextContent ? `${nextContent}\n` : "";
194
+ if (normalizedNextContent === existingContent) {
195
+ return;
196
+ }
197
+ await mkdir(dirname(excludePath), { recursive: true });
198
+ await writeFile(excludePath, normalizedNextContent, "utf8");
215
199
  }
216
- async function symlinkIgnoredPaths(repoPath, worktreePath) {
217
- const ignoredPaths = await listIgnoredPaths(repoPath);
218
- const selfIgnoredRootPaths = await listSelfIgnoredPaths(repoPath, ignoredPaths);
200
+ async function syncIgnoredPathsIntoWorktree(repoPath, worktreePath) {
201
+ const ignoredPaths = getUniquePaths(await listIgnoredPaths(repoPath)).filter((relativePath) => !shouldSkipSymlink(relativePath));
202
+ await syncManagedIgnoredPathExcludes(repoPath, ignoredPaths);
219
203
  for (const relativePath of ignoredPaths) {
220
204
  if (shouldSkipSymlink(relativePath)) {
221
205
  continue;
222
206
  }
223
- if (isPathWithinAnyRoot(relativePath, selfIgnoredRootPaths)) {
224
- continue;
225
- }
226
207
  const sourcePath = join(repoPath, relativePath);
227
208
  if (!(await pathExists(sourcePath))) {
228
209
  continue;
@@ -269,6 +250,7 @@ export async function ensureTaskWorktreeIfDoesntExist(options) {
269
250
  // worktrees are now treated as authoritative and only missing worktrees are created.
270
251
  const existingCommit = await tryRunGit(["-C", worktreePath, "rev-parse", "HEAD"]);
271
252
  if (existingCommit) {
253
+ await syncIgnoredPathsIntoWorktree(context.repoPath, worktreePath);
272
254
  return {
273
255
  ok: true,
274
256
  path: worktreePath,
@@ -304,7 +286,7 @@ export async function ensureTaskWorktreeIfDoesntExist(options) {
304
286
  }
305
287
  await mkdir(dirname(worktreePath), { recursive: true });
306
288
  await runGit(["-C", context.repoPath, "worktree", "add", "--detach", worktreePath, baseCommit]);
307
- await symlinkIgnoredPaths(context.repoPath, worktreePath);
289
+ await syncIgnoredPathsIntoWorktree(context.repoPath, worktreePath);
308
290
  return {
309
291
  ok: true,
310
292
  path: 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, rm, symlink } from \"node:fs/promises\";\nimport { basename, dirname, 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 { 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 WORKTREES_DIR = \"worktrees\";\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 normalizeTaskId(taskId: string): string {\n\tconst normalized = taskId.trim();\n\tif (!normalized || normalized.includes(\"/\") || normalized.includes(\"\\\\\") || normalized.includes(\"..\")) {\n\t\tthrow new Error(\"Invalid task id for worktree path.\");\n\t}\n\treturn normalized;\n}\n\nfunction getWorkspaceFolderLabel(repoPath: string): string {\n\tconst trimmed = repoPath.trim().replace(/[\\\\/]+$/g, \"\");\n\tconst folder = basename(trimmed);\n\tif (!folder) {\n\t\treturn \"workspace\";\n\t}\n\tconst cleaned = [...folder]\n\t\t.filter((char) => {\n\t\t\tconst code = char.charCodeAt(0);\n\t\t\treturn code >= 32 && code !== 127;\n\t\t})\n\t\t.join(\"\")\n\t\t.trim();\n\treturn cleaned || \"workspace\";\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 = normalizeTaskId(taskId);\n\treturn join(getRuntimeHomePath(), WORKTREES_DIR, normalizedTaskId);\n}\n\nfunction getWorktreesBaseRootPath(): string {\n\treturn join(getRuntimeHomePath(), WORKTREES_DIR);\n}\n\nfunction getTaskWorktreePath(repoPath: string, taskId: string): string {\n\tconst workspaceLabel = getWorkspaceFolderLabel(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 isPathWithinAnyRoot(path: string, roots: Set<string>): boolean {\n\tfor (const root of roots) {\n\t\tif (isPathWithinRoot(path, root)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction getRootIgnoredPaths(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 isIgnoredByOwnNestedRule(ignoredPath: string, ignoreSourcePath: string): boolean {\n\tconst normalizedIgnoredPath = toPlatformRelativePath(ignoredPath);\n\tconst normalizedIgnoreSourcePath = toPlatformRelativePath(ignoreSourcePath);\n\tif (!normalizedIgnoredPath || !normalizedIgnoreSourcePath) {\n\t\treturn false;\n\t}\n\treturn normalizedIgnoreSourcePath.startsWith(`${normalizedIgnoredPath}/`);\n}\n\nfunction parseCheckIgnoreVerboseLine(line: string): { ignoredPath: string; ignoreSourcePath: string } | null {\n\tconst [sourceMetadata, ignoredPathRaw] = line.split(\"\\t\");\n\tif (!sourceMetadata || !ignoredPathRaw) {\n\t\treturn null;\n\t}\n\n\tconst sourceMatch = sourceMetadata.match(/^(.*):(\\d+):(.*)$/u);\n\tif (!sourceMatch) {\n\t\treturn null;\n\t}\n\n\tconst ignoreSourcePath = toPlatformRelativePath(sourceMatch[1] ?? \"\");\n\tconst ignoredPath = toPlatformRelativePath(ignoredPathRaw);\n\tif (!ignoreSourcePath || !ignoredPath) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tignoredPath,\n\t\tignoreSourcePath,\n\t};\n}\n\nasync function listSelfIgnoredPaths(repoPath: string, relativePaths: string[]): Promise<Set<string>> {\n\t// Some tool-managed directories are ignored by nested rules inside the directory itself,\n\t// e.g. Husky's `.husky/_/.gitignore` with `*` ignores `.husky/_/`.\n\t// If we symlink those directories into a worktree, git won't apply the nested ignore rule\n\t// through the symlink boundary and the path shows up as untracked (`?? .husky/_`).\n\t// We detect those root paths and skip symlinking them.\n\tconst rootIgnoredPaths = getRootIgnoredPaths(relativePaths);\n\tif (rootIgnoredPaths.length === 0) {\n\t\treturn new Set<string>();\n\t}\n\n\tconst selfIgnoredPaths = new Set<string>();\n\tfor (const relativePath of rootIgnoredPaths) {\n\t\tconst sourcePath = join(repoPath, relativePath);\n\t\tconst sourceStat = await lstat(sourcePath).catch(() => null);\n\t\tif (!sourceStat?.isDirectory()) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst output = await tryRunGit([\"-C\", repoPath, \"check-ignore\", \"-v\", \"--\", `${relativePath}/`]);\n\t\tif (!output) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst parsed = parseCheckIgnoreVerboseLine(output.split(\"\\n\")[0] ?? \"\");\n\t\tif (!parsed) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (parsed.ignoredPath !== relativePath) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (isIgnoredByOwnNestedRule(relativePath, parsed.ignoreSourcePath)) {\n\t\t\tselfIgnoredPaths.add(relativePath);\n\t\t}\n\t}\n\n\treturn selfIgnoredPaths;\n}\n\nasync function symlinkIgnoredPaths(repoPath: string, worktreePath: string): Promise<void> {\n\tconst ignoredPaths = await listIgnoredPaths(repoPath);\n\tconst selfIgnoredRootPaths = await listSelfIgnoredPaths(repoPath, ignoredPaths);\n\tfor (const relativePath of ignoredPaths) {\n\t\tif (shouldSkipSymlink(relativePath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isPathWithinAnyRoot(relativePath, selfIgnoredRootPaths)) {\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 = normalizeTaskId(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\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 symlinkIgnoredPaths(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 = normalizeTaskId(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 = normalizeTaskId(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, readFile, readdir, rm, symlink, writeFile } from \"node:fs/promises\";\nimport { basename, 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 { 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 WORKTREES_DIR = \"worktrees\";\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 normalizeTaskId(taskId: string): string {\n\tconst normalized = taskId.trim();\n\tif (!normalized || normalized.includes(\"/\") || normalized.includes(\"\\\\\") || normalized.includes(\"..\")) {\n\t\tthrow new Error(\"Invalid task id for worktree path.\");\n\t}\n\treturn normalized;\n}\n\nfunction getWorkspaceFolderLabel(repoPath: string): string {\n\tconst trimmed = repoPath.trim().replace(/[\\\\/]+$/g, \"\");\n\tconst folder = basename(trimmed);\n\tif (!folder) {\n\t\treturn \"workspace\";\n\t}\n\tconst cleaned = [...folder]\n\t\t.filter((char) => {\n\t\t\tconst code = char.charCodeAt(0);\n\t\t\treturn code >= 32 && code !== 127;\n\t\t})\n\t\t.join(\"\")\n\t\t.trim();\n\treturn cleaned || \"workspace\";\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 = normalizeTaskId(taskId);\n\treturn join(getRuntimeHomePath(), WORKTREES_DIR, normalizedTaskId);\n}\n\nfunction getWorktreesBaseRootPath(): string {\n\treturn join(getRuntimeHomePath(), WORKTREES_DIR);\n}\n\nfunction getTaskWorktreePath(repoPath: string, taskId: string): string {\n\tconst workspaceLabel = getWorkspaceFolderLabel(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((relativePath) => !shouldSkipSymlink(relativePath));\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 = normalizeTaskId(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 = normalizeTaskId(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 = normalizeTaskId(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.8",
3
+ "version": "0.1.9",
4
4
  "description": "A kanban foundation for coding agents",
5
5
  "publishConfig": {
6
6
  "access": "public",