@staff0rd/assist 0.533.3 → 0.535.0

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/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@staff0rd/assist",
9
- version: "0.533.3",
9
+ version: "0.535.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -149,8 +149,8 @@ import { dirname as dirname2, join as join2 } from "path";
149
149
 
150
150
  // src/commands/backlog/getCurrentOrigin.ts
151
151
  import { execFileSync } from "child_process";
152
- function stripLeadingSlashes(path71) {
153
- return path71.replace(/^\/+/, "");
152
+ function stripLeadingSlashes(path73) {
153
+ return path73.replace(/^\/+/, "");
154
154
  }
155
155
  function normalizeOrigin(raw) {
156
156
  const trimmed = raw.trim().replace(/\.git$/i, "").replace(/\/+$/, "");
@@ -225,9 +225,9 @@ function findGitLink(dir) {
225
225
  }
226
226
  return null;
227
227
  }
228
- function isFile(path71) {
228
+ function isFile(path73) {
229
229
  try {
230
- return statSync(path71).isFile();
230
+ return statSync(path73).isFile();
231
231
  } catch {
232
232
  return false;
233
233
  }
@@ -246,9 +246,9 @@ function linkedGitDirParent(gitDir) {
246
246
  const match = /^(.*)[/\\]worktrees[/\\][^/\\]+[/\\]?$/.exec(gitDir);
247
247
  return match ? match[1] : null;
248
248
  }
249
- function readTrimmed(path71) {
249
+ function readTrimmed(path73) {
250
250
  try {
251
- const content = readFileSync(path71, "utf8").trim();
251
+ const content = readFileSync(path73, "utf8").trim();
252
252
  return content === "" ? null : content;
253
253
  } catch {
254
254
  return null;
@@ -261,10 +261,10 @@ function absolute(target, from) {
261
261
  // src/shared/loadRawYaml.ts
262
262
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
263
263
  import { parse as parseYaml } from "yaml";
264
- function loadRawYaml(path71) {
265
- if (!existsSync2(path71)) return {};
264
+ function loadRawYaml(path73) {
265
+ if (!existsSync2(path73)) return {};
266
266
  try {
267
- const content = readFileSync2(path71, "utf8");
267
+ const content = readFileSync2(path73, "utf8");
268
268
  return parseYaml(content) || {};
269
269
  } catch {
270
270
  return {};
@@ -336,8 +336,8 @@ function mergeRawConfigs(globalRaw, projectRaw) {
336
336
  // src/commands/backlog/originDisplayName.ts
337
337
  function originDisplayName(origin) {
338
338
  if (origin.startsWith("local:")) {
339
- const path71 = origin.slice("local:".length).replace(/\/+$/, "");
340
- const segments = path71.split("/").filter(Boolean);
339
+ const path73 = origin.slice("local:".length).replace(/\/+$/, "");
340
+ const segments = path73.split("/").filter(Boolean);
341
341
  return segments[segments.length - 1] ?? origin;
342
342
  }
343
343
  const firstSlash = origin.indexOf("/");
@@ -1746,8 +1746,8 @@ function findUnmergedPaths() {
1746
1746
  }
1747
1747
  const found = /* @__PURE__ */ new Set();
1748
1748
  for (const line of output.split("\n")) {
1749
- const path71 = line.split(" ")[1];
1750
- if (path71) found.add(path71.trim());
1749
+ const path73 = line.split(" ")[1];
1750
+ if (path73) found.add(path73.trim());
1751
1751
  }
1752
1752
  return [...found];
1753
1753
  }
@@ -1857,8 +1857,8 @@ function getPreferredRemoteRepo(cwd) {
1857
1857
  function gitRefUrl(kind, ref, cwd) {
1858
1858
  const repo = getPreferredRemoteRepo(cwd);
1859
1859
  if (!repo) return void 0;
1860
- const path71 = kind === "branch" ? "tree" : "commit";
1861
- return `https://github.com/${repo.org}/${repo.repo}/${path71}/${ref}`;
1860
+ const path73 = kind === "branch" ? "tree" : "commit";
1861
+ return `https://github.com/${repo.org}/${repo.repo}/${path73}/${ref}`;
1862
1862
  }
1863
1863
 
1864
1864
  // src/commands/commit/collectCommitRefs.ts
@@ -3833,11 +3833,11 @@ function enumValues(node) {
3833
3833
  function opaqueConfigNode(inner, base) {
3834
3834
  return { ...base, kind: "other", type: leafTypeOf(inner) };
3835
3835
  }
3836
- function build(node, path71) {
3836
+ function build(node, path73) {
3837
3837
  const { inner, defaultValue, optional } = unwrapSchemaNode(node);
3838
3838
  const secret = isSecretSchemaNode(node) || isSecretSchemaNode(inner);
3839
3839
  const base = {
3840
- path: path71,
3840
+ path: path73,
3841
3841
  ...optional ? { optional: true } : {},
3842
3842
  ...defaultValue === void 0 ? {} : { defaultValue },
3843
3843
  ...secret ? { secret: true } : {}
@@ -3856,9 +3856,9 @@ function segmentText(segment) {
3856
3856
  if (segment.kind === "index") return `[${segment.index}]`;
3857
3857
  return "[]";
3858
3858
  }
3859
- function formatConfigPath(path71) {
3859
+ function formatConfigPath(path73) {
3860
3860
  let text17 = "";
3861
- for (const segment of path71) {
3861
+ for (const segment of path73) {
3862
3862
  const dotted = segment.kind === "key" || segment.kind === "entry";
3863
3863
  const rendered = segmentText(segment);
3864
3864
  text17 += dotted && text17 ? `.${rendered}` : rendered;
@@ -4471,9 +4471,9 @@ import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
4471
4471
 
4472
4472
  // src/commands/verify/forbiddenStrings/findForbiddenStrings.ts
4473
4473
  import { minimatch as minimatch2 } from "minimatch";
4474
- function resolveStringsAtPath(data, path71) {
4474
+ function resolveStringsAtPath(data, path73) {
4475
4475
  let current = data;
4476
- for (const segment of path71.split(".")) {
4476
+ for (const segment of path73.split(".")) {
4477
4477
  if (current === null || typeof current !== "object") return [];
4478
4478
  current = current[segment];
4479
4479
  }
@@ -4486,10 +4486,10 @@ function resolveStringsAtPath(data, path71) {
4486
4486
  }
4487
4487
  function findRuleViolations(data, rule) {
4488
4488
  const violations = [];
4489
- for (const path71 of rule.paths) {
4490
- for (const value of resolveStringsAtPath(data, path71)) {
4489
+ for (const path73 of rule.paths) {
4490
+ for (const value of resolveStringsAtPath(data, path73)) {
4491
4491
  if (minimatch2(value, rule.disallowed))
4492
- violations.push({ file: rule.file, path: path71, value });
4492
+ violations.push({ file: rule.file, path: path73, value });
4493
4493
  }
4494
4494
  }
4495
4495
  return violations;
@@ -4528,8 +4528,8 @@ function forbiddenStrings() {
4528
4528
  process.exit(0);
4529
4529
  }
4530
4530
  console.log("Forbidden strings found:\n");
4531
- for (const { file, path: path71, value } of violations) {
4532
- console.log(` ${file} ${path71}: ${value}`);
4531
+ for (const { file, path: path73, value } of violations) {
4532
+ console.log(` ${file} ${path73}: ${value}`);
4533
4533
  }
4534
4534
  console.log(`
4535
4535
  Total: ${violations.length} forbidden string(s).`);
@@ -4844,15 +4844,15 @@ function readBaselineMigrations(repoRelativeDir, ref) {
4844
4844
  } catch {
4845
4845
  return baseline;
4846
4846
  }
4847
- const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path71) => MIGRATION_FILE3.test(basename2(path71)));
4848
- for (const path71 of paths) {
4847
+ const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path73) => MIGRATION_FILE3.test(basename2(path73)));
4848
+ for (const path73 of paths) {
4849
4849
  try {
4850
- const content = execSync14(`git show "${ref}:${path71}"`, {
4850
+ const content = execSync14(`git show "${ref}:${path73}"`, {
4851
4851
  encoding: "utf8",
4852
4852
  maxBuffer: 16 * 1024 * 1024,
4853
4853
  stdio: ["pipe", "pipe", "pipe"]
4854
4854
  });
4855
- baseline.set(basename2(path71), content);
4855
+ baseline.set(basename2(path73), content);
4856
4856
  } catch {
4857
4857
  }
4858
4858
  }
@@ -6286,10 +6286,10 @@ var hooksSettings = {
6286
6286
  }
6287
6287
  };
6288
6288
  function ensureHooksSettings() {
6289
- const path71 = daemonPaths.hooksSettings;
6290
- mkdirSync5(dirname13(path71), { recursive: true });
6291
- writeFileSync15(path71, JSON.stringify(hooksSettings, null, 2));
6292
- return path71;
6289
+ const path73 = daemonPaths.hooksSettings;
6290
+ mkdirSync5(dirname13(path73), { recursive: true });
6291
+ writeFileSync15(path73, JSON.stringify(hooksSettings, null, 2));
6292
+ return path73;
6293
6293
  }
6294
6294
 
6295
6295
  // src/shared/spawnInherit.ts
@@ -6587,9 +6587,9 @@ var LOCAL_FILES = ["backlog.jsonl", "backlog.db"];
6587
6587
  function backupLocalBacklogFiles(dir) {
6588
6588
  const moved = [];
6589
6589
  for (const name of LOCAL_FILES) {
6590
- const path71 = join15(dir, ".assist", name);
6591
- if (existsSync19(path71)) {
6592
- renameSync(path71, `${path71}.bak`);
6590
+ const path73 = join15(dir, ".assist", name);
6591
+ if (existsSync19(path73)) {
6592
+ renameSync(path73, `${path73}.bak`);
6593
6593
  moved.push(`${name} \u2192 ${name}.bak`);
6594
6594
  }
6595
6595
  }
@@ -7068,8 +7068,8 @@ var backlogItemSchema = z4.strictObject({
7068
7068
  var backlogFileSchema = z4.array(backlogItemSchema);
7069
7069
 
7070
7070
  // src/commands/backlog/parseBacklogJsonl.ts
7071
- function parseBacklogJsonl(path71) {
7072
- const content = readFileSync15(path71, "utf8").trim();
7071
+ function parseBacklogJsonl(path73) {
7072
+ const content = readFileSync15(path73, "utf8").trim();
7073
7073
  if (content.length === 0) return [];
7074
7074
  return content.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => backlogItemSchema.parse(JSON.parse(line)));
7075
7075
  }
@@ -7856,24 +7856,24 @@ function getOwnerPath(itemId2) {
7856
7856
  function recordSignalOwner(itemId2) {
7857
7857
  const sessionId = process.env.ASSIST_SESSION_ID;
7858
7858
  if (!sessionId) return;
7859
- const path71 = getOwnerPath(itemId2);
7860
- mkdirSync7(dirname15(path71), { recursive: true });
7861
- writeFileSync17(path71, JSON.stringify({ sessionId }));
7859
+ const path73 = getOwnerPath(itemId2);
7860
+ mkdirSync7(dirname15(path73), { recursive: true });
7861
+ writeFileSync17(path73, JSON.stringify({ sessionId }));
7862
7862
  }
7863
7863
  function readSignalOwner(itemId2) {
7864
- const path71 = getOwnerPath(itemId2);
7865
- if (!existsSync23(path71)) return void 0;
7864
+ const path73 = getOwnerPath(itemId2);
7865
+ if (!existsSync23(path73)) return void 0;
7866
7866
  try {
7867
- const parsed = JSON.parse(readFileSync16(path71, "utf8"));
7867
+ const parsed = JSON.parse(readFileSync16(path73, "utf8"));
7868
7868
  return parsed.sessionId;
7869
7869
  } catch {
7870
7870
  return void 0;
7871
7871
  }
7872
7872
  }
7873
7873
  function clearSignalOwner(itemId2) {
7874
- const path71 = getOwnerPath(itemId2);
7874
+ const path73 = getOwnerPath(itemId2);
7875
7875
  try {
7876
- rmSync(path71);
7876
+ rmSync(path73);
7877
7877
  } catch {
7878
7878
  }
7879
7879
  }
@@ -7910,19 +7910,19 @@ function resolveSignalTarget(event, data) {
7910
7910
  function writeSignal(event, data) {
7911
7911
  const target = resolveSignalTarget(event, data);
7912
7912
  if (!target) return;
7913
- const path71 = getSignalPath(target);
7914
- if (!path71) return;
7913
+ const path73 = getSignalPath(target);
7914
+ if (!path73) return;
7915
7915
  const signal = { event, sessionId: target, ...data };
7916
- mkdirSync8(dirname16(path71), { recursive: true });
7917
- writeFileSync18(path71, JSON.stringify(signal));
7916
+ mkdirSync8(dirname16(path73), { recursive: true });
7917
+ writeFileSync18(path73, JSON.stringify(signal));
7918
7918
  }
7919
7919
 
7920
7920
  // src/commands/backlog/readSignal.ts
7921
7921
  function readSignal() {
7922
- const path71 = getSignalPath();
7923
- if (!path71 || !existsSync24(path71)) return void 0;
7922
+ const path73 = getSignalPath();
7923
+ if (!path73 || !existsSync24(path73)) return void 0;
7924
7924
  try {
7925
- return JSON.parse(readFileSync17(path71, "utf8"));
7925
+ return JSON.parse(readFileSync17(path73, "utf8"));
7926
7926
  } catch {
7927
7927
  return void 0;
7928
7928
  }
@@ -8119,13 +8119,13 @@ function activityPath(sessionId) {
8119
8119
  function emitActivity(activity2) {
8120
8120
  const sessionId = process.env.ASSIST_ACTIVITY_ID;
8121
8121
  if (!sessionId) return;
8122
- const path71 = activityPath(sessionId);
8123
- mkdirSync9(dirname17(path71), { recursive: true });
8124
- writeFileSync19(path71, JSON.stringify({ ...activity2, startedAt: Date.now() }));
8122
+ const path73 = activityPath(sessionId);
8123
+ mkdirSync9(dirname17(path73), { recursive: true });
8124
+ writeFileSync19(path73, JSON.stringify({ ...activity2, startedAt: Date.now() }));
8125
8125
  }
8126
- function readActivity(path71) {
8126
+ function readActivity(path73) {
8127
8127
  try {
8128
- return JSON.parse(readFileSync18(path71, "utf8"));
8128
+ return JSON.parse(readFileSync18(path73, "utf8"));
8129
8129
  } catch {
8130
8130
  return void 0;
8131
8131
  }
@@ -8135,9 +8135,9 @@ function reconcileActivity(sessionId, activity2) {
8135
8135
  removeActivity(sessionId);
8136
8136
  return;
8137
8137
  }
8138
- const path71 = activityPath(sessionId);
8139
- mkdirSync9(dirname17(path71), { recursive: true });
8140
- writeFileSync19(path71, JSON.stringify(activity2));
8138
+ const path73 = activityPath(sessionId);
8139
+ mkdirSync9(dirname17(path73), { recursive: true });
8140
+ writeFileSync19(path73, JSON.stringify(activity2));
8141
8141
  }
8142
8142
  function removeActivity(sessionId) {
8143
8143
  try {
@@ -8146,8 +8146,27 @@ function removeActivity(sessionId) {
8146
8146
  }
8147
8147
  }
8148
8148
 
8149
+ // src/shared/harnessLabel.ts
8150
+ var HARNESS_LABELS = {
8151
+ claude: "Claude",
8152
+ codex: "Codex",
8153
+ pi: "pi"
8154
+ };
8155
+ function resolveHarness(harness) {
8156
+ return harness ?? "claude";
8157
+ }
8158
+ function harnessLabel(harness) {
8159
+ return HARNESS_LABELS[resolveHarness(harness)];
8160
+ }
8161
+
8162
+ // src/shared/harnessActivityFields.ts
8163
+ function harnessActivityFields(harness, claudeSessionId) {
8164
+ const kind = resolveHarness(harness);
8165
+ return kind === "claude" ? { claudeSessionId } : { harness: kind };
8166
+ }
8167
+
8149
8168
  // src/commands/backlog/reportPhaseActivity.ts
8150
- function reportPhaseActivity(item, phaseNumber, totalPhases, phase, claudeSessionId) {
8169
+ function reportPhaseActivity(item, phaseNumber, totalPhases, phase, claudeSessionId, harness) {
8151
8170
  const isReviewPhase = phaseNumber >= totalPhases;
8152
8171
  emitActivity({
8153
8172
  kind: "backlog",
@@ -8156,7 +8175,7 @@ function reportPhaseActivity(item, phaseNumber, totalPhases, phase, claudeSessio
8156
8175
  phase: phaseNumber,
8157
8176
  phaseName: isReviewPhase ? REVIEW_PHASE_NAME : phase.name,
8158
8177
  totalPhases,
8159
- claudeSessionId
8178
+ ...harnessActivityFields(harness, claudeSessionId)
8160
8179
  });
8161
8180
  }
8162
8181
 
@@ -8405,7 +8424,14 @@ async function preparePhaseSession(item, phase, phaseIndex, phaseNumber, totalPh
8405
8424
  if (resumeSessionId && !await verifyPhaseResume(item.id, resumeSessionId, phaseLabel2)) {
8406
8425
  return void 0;
8407
8426
  }
8408
- reportPhaseActivity(item, phaseNumber, totalPhases, phase, claudeSessionId);
8427
+ reportPhaseActivity(
8428
+ item,
8429
+ phaseNumber,
8430
+ totalPhases,
8431
+ phase,
8432
+ claudeSessionId,
8433
+ spawnOptions?.harness
8434
+ );
8409
8435
  if (!resumeSessionId) {
8410
8436
  await persistPhaseSessionId(item.id, phaseIndex, claudeSessionId);
8411
8437
  }
@@ -9380,10 +9406,10 @@ function getStorePath(filename) {
9380
9406
  return join24(getStoreDir(), filename);
9381
9407
  }
9382
9408
  function loadJson(filename) {
9383
- const path71 = getStorePath(filename);
9384
- if (existsSync27(path71)) {
9409
+ const path73 = getStorePath(filename);
9410
+ if (existsSync27(path73)) {
9385
9411
  try {
9386
- return JSON.parse(readFileSync19(path71, "utf8"));
9412
+ return JSON.parse(readFileSync19(path73, "utf8"));
9387
9413
  } catch {
9388
9414
  return {};
9389
9415
  }
@@ -9402,22 +9428,22 @@ function saveJson(filename, data) {
9402
9428
  var REGISTRY_FILE = "worktrees.json";
9403
9429
  function readWorktreeRegistry() {
9404
9430
  const data = loadJson(REGISTRY_FILE);
9405
- return Object.entries(data).filter(([, record]) => !record.reaped).map(([path71, record]) => ({ path: path71, ...record }));
9431
+ return Object.entries(data).filter(([, record]) => !record.reaped).map(([path73, record]) => ({ path: path73, ...record }));
9406
9432
  }
9407
- function worktreeAttributionIncludingReaped(path71) {
9408
- const record = loadJson(REGISTRY_FILE)[path71];
9433
+ function worktreeAttributionIncludingReaped(path73) {
9434
+ const record = loadJson(REGISTRY_FILE)[path73];
9409
9435
  return record ? { clone: record.clone, origin: record.origin } : void 0;
9410
9436
  }
9411
- function recordWorktree(path71, clone, origin) {
9437
+ function recordWorktree(path73, clone, origin) {
9412
9438
  const data = loadJson(REGISTRY_FILE);
9413
- data[path71] = { clone, origin };
9439
+ data[path73] = { clone, origin };
9414
9440
  saveJson(REGISTRY_FILE, data);
9415
9441
  }
9416
- function forgetWorktree(path71) {
9442
+ function forgetWorktree(path73) {
9417
9443
  const data = loadJson(REGISTRY_FILE);
9418
- const record = data[path71];
9444
+ const record = data[path73];
9419
9445
  if (!record || record.reaped) return;
9420
- data[path71] = { ...record, reaped: true };
9446
+ data[path73] = { ...record, reaped: true };
9421
9447
  saveJson(REGISTRY_FILE, data);
9422
9448
  }
9423
9449
 
@@ -10173,8 +10199,8 @@ async function loadCommittedPaths(cwd, sessionId) {
10173
10199
  for (const commit2 of commits2) {
10174
10200
  const resolved = await resolveCommit(cwd, commit2.sha);
10175
10201
  if (!resolved) continue;
10176
- for (const path71 of resolved.paths) {
10177
- if (!bases.has(path71)) bases.set(path71, resolved.base);
10202
+ for (const path73 of resolved.paths) {
10203
+ if (!bases.has(path73)) bases.set(path73, resolved.base);
10178
10204
  }
10179
10205
  }
10180
10206
  return { commits: commits2, bases };
@@ -10192,16 +10218,16 @@ async function itemChangeSet(cwd, sessionId) {
10192
10218
  }
10193
10219
  function groupByBase(bases) {
10194
10220
  const groups = /* @__PURE__ */ new Map();
10195
- for (const [path71, base] of bases) {
10221
+ for (const [path73, base] of bases) {
10196
10222
  const paths = groups.get(base);
10197
- if (paths) paths.push(path71);
10198
- else groups.set(base, [path71]);
10223
+ if (paths) paths.push(path73);
10224
+ else groups.set(base, [path73]);
10199
10225
  }
10200
10226
  return [...groups].map(([base, paths]) => ({ base, paths: paths.sort() }));
10201
10227
  }
10202
10228
  async function dirtyPaths(cwd, bases) {
10203
10229
  const output = await execGit(cwd, ["diff", "--name-only", "HEAD"]);
10204
- return output.split("\n").filter((path71) => path71 && !bases.has(path71)).sort();
10230
+ return output.split("\n").filter((path73) => path73 && !bases.has(path73)).sort();
10205
10231
  }
10206
10232
 
10207
10233
  // src/commands/sessions/web/scopedDiff.ts
@@ -10210,8 +10236,8 @@ async function scopedDiff(cwd, session, scope) {
10210
10236
  if (scope.kind === "commit") return commitDiff(cwd, scope.sha);
10211
10237
  return await trackedScopeDiff(cwd, session, scope) + await untrackedDiff(cwd);
10212
10238
  }
10213
- async function untrackedFileDiff(cwd, path71) {
10214
- return execGit(cwd, ["diff", "--no-index", "--", "/dev/null", path71], {
10239
+ async function untrackedFileDiff(cwd, path73) {
10240
+ return execGit(cwd, ["diff", "--no-index", "--", "/dev/null", path73], {
10215
10241
  maxBuffer: MAX_DIFF_BYTES,
10216
10242
  allowFailure: true
10217
10243
  });
@@ -10224,7 +10250,7 @@ async function untrackedDiff(cwd) {
10224
10250
  ]);
10225
10251
  const paths = list5.split("\n").filter(Boolean);
10226
10252
  const diffs = await Promise.all(
10227
- paths.map((path71) => untrackedFileDiff(cwd, path71))
10253
+ paths.map((path73) => untrackedFileDiff(cwd, path73))
10228
10254
  );
10229
10255
  return diffs.join("");
10230
10256
  }
@@ -10317,9 +10343,9 @@ import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve10
10317
10343
  function repoRoot(cwd) {
10318
10344
  return resolve10(toGitCwd(cwd));
10319
10345
  }
10320
- function resolveWithinCwd(cwd, path71) {
10346
+ function resolveWithinCwd(cwd, path73) {
10321
10347
  const root = repoRoot(cwd);
10322
- const target = resolve10(root, path71);
10348
+ const target = resolve10(root, path73);
10323
10349
  const rel = relative2(root, target);
10324
10350
  if (rel === "" || rel.startsWith("..") || isAbsolute2(rel)) return null;
10325
10351
  return target;
@@ -10329,14 +10355,14 @@ function resolveWithinCwd(cwd, path71) {
10329
10355
  function getFileTarget(req, res) {
10330
10356
  const cwd = getCwdParam(req, res);
10331
10357
  if (!cwd) return null;
10332
- const path71 = new URL(req.url ?? "/", "http://localhost").searchParams.get(
10358
+ const path73 = new URL(req.url ?? "/", "http://localhost").searchParams.get(
10333
10359
  "path"
10334
10360
  );
10335
- if (!path71) {
10361
+ if (!path73) {
10336
10362
  respondJson(res, 400, { error: "Missing path" });
10337
10363
  return null;
10338
10364
  }
10339
- const target = resolveWithinCwd(cwd, path71);
10365
+ const target = resolveWithinCwd(cwd, path73);
10340
10366
  if (!target) {
10341
10367
  respondJson(res, 400, { error: "Path outside cwd" });
10342
10368
  return null;
@@ -10405,35 +10431,35 @@ function isPlainRecord(value) {
10405
10431
  }
10406
10432
 
10407
10433
  // src/shared/mapConfigSecrets.ts
10408
- function mapChildren(value, path71, childNode, map) {
10434
+ function mapChildren(value, path73, childNode, map) {
10409
10435
  if (!isPlainRecord(value)) return value;
10410
10436
  return Object.fromEntries(
10411
10437
  Object.entries(value).map(([name, child]) => [
10412
10438
  name,
10413
- walk(child, [...path71, name], childNode(name), map)
10439
+ walk(child, [...path73, name], childNode(name), map)
10414
10440
  ])
10415
10441
  );
10416
10442
  }
10417
- function mapItems(value, path71, item, map) {
10443
+ function mapItems(value, path73, item, map) {
10418
10444
  if (!Array.isArray(value)) return value;
10419
- return value.map((entry, index3) => walk(entry, [...path71, index3], item, map));
10445
+ return value.map((entry, index3) => walk(entry, [...path73, index3], item, map));
10420
10446
  }
10421
- function walk(value, path71, node, map) {
10447
+ function walk(value, path73, node, map) {
10422
10448
  if (!node || value === void 0 || value === null) return value;
10423
- if (node.secret) return map(value, path71);
10449
+ if (node.secret) return map(value, path73);
10424
10450
  switch (node.kind) {
10425
10451
  case "object":
10426
10452
  case "unionOfObjects":
10427
10453
  return mapChildren(
10428
10454
  value,
10429
- path71,
10455
+ path73,
10430
10456
  (name) => configNodeField(node, name),
10431
10457
  map
10432
10458
  );
10433
10459
  case "objectList":
10434
- return mapItems(value, path71, node.item, map);
10460
+ return mapItems(value, path73, node.item, map);
10435
10461
  case "record":
10436
- return mapChildren(value, path71, () => node.value, map);
10462
+ return mapChildren(value, path73, () => node.value, map);
10437
10463
  default:
10438
10464
  return value;
10439
10465
  }
@@ -10465,9 +10491,9 @@ function isTraversable(value) {
10465
10491
  function stepInto(current, key) {
10466
10492
  return isTraversable(current) ? current[key] : void 0;
10467
10493
  }
10468
- function getNestedValue(obj, path71) {
10494
+ function getNestedValue(obj, path73) {
10469
10495
  let current = obj;
10470
- for (const key of path71.split(".")) current = stepInto(current, key);
10496
+ for (const key of path73.split(".")) current = stepInto(current, key);
10471
10497
  return current;
10472
10498
  }
10473
10499
 
@@ -10552,9 +10578,9 @@ function step(node, segment) {
10552
10578
  return void 0;
10553
10579
  }
10554
10580
  }
10555
- function findConfigNode(root, path71) {
10581
+ function findConfigNode(root, path73) {
10556
10582
  let current = root;
10557
- for (const segment of path71) {
10583
+ for (const segment of path73) {
10558
10584
  if (!current) return void 0;
10559
10585
  current = step(current, segment);
10560
10586
  }
@@ -10571,34 +10597,34 @@ function nameSegment(name) {
10571
10597
  return name === RECORD_ENTRY_TOKEN ? { kind: "entry" } : { kind: "key", name };
10572
10598
  }
10573
10599
  function parseConfigPath(text17) {
10574
- const path71 = [];
10600
+ const path73 = [];
10575
10601
  let at2 = 0;
10576
10602
  while (at2 < text17.length) {
10577
10603
  if (text17[at2] === "[") {
10578
10604
  const close = text17.indexOf("]", at2);
10579
10605
  const segment = close === -1 ? void 0 : bracketSegment(text17.slice(at2 + 1, close));
10580
10606
  if (!segment) return void 0;
10581
- path71.push(segment);
10607
+ path73.push(segment);
10582
10608
  at2 = close + 1;
10583
10609
  continue;
10584
10610
  }
10585
10611
  if (text17[at2] === ".") {
10586
- if (path71.length === 0) return void 0;
10612
+ if (path73.length === 0) return void 0;
10587
10613
  at2 += 1;
10588
10614
  }
10589
10615
  const start3 = at2;
10590
10616
  while (at2 < text17.length && text17[at2] !== "." && text17[at2] !== "[") at2 += 1;
10591
10617
  const name = text17.slice(start3, at2);
10592
10618
  if (!name) return void 0;
10593
- path71.push(nameSegment(name));
10619
+ path73.push(nameSegment(name));
10594
10620
  }
10595
- return path71;
10621
+ return path73;
10596
10622
  }
10597
10623
 
10598
10624
  // src/commands/config/configEntryNode.ts
10599
10625
  function configEntryNode(root, key) {
10600
- const path71 = parseConfigPath(key);
10601
- return path71 ? findConfigNode(root, path71) : void 0;
10626
+ const path73 = parseConfigPath(key);
10627
+ return path73 ? findConfigNode(root, path73) : void 0;
10602
10628
  }
10603
10629
 
10604
10630
  // src/commands/config/readConfigEntries.ts
@@ -10703,7 +10729,7 @@ function findSynthesisForBranch(repoReviewsDir, branch2) {
10703
10729
  const parent = dirname21(branchKeyPath);
10704
10730
  const branchPrefix = basename7(branchKeyPath);
10705
10731
  if (!existsSync29(parent)) return null;
10706
- const synthesisFiles = readdirSync2(parent).filter((name) => name.startsWith(branchPrefix)).map((name) => join27(parent, name, "synthesis.md")).filter((path71) => existsSync29(path71)).map((path71) => ({ path: path71, mtime: statSync4(path71).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
10732
+ const synthesisFiles = readdirSync2(parent).filter((name) => name.startsWith(branchPrefix)).map((name) => join27(parent, name, "synthesis.md")).filter((path73) => existsSync29(path73)).map((path73) => ({ path: path73, mtime: statSync4(path73).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
10707
10733
  return synthesisFiles[0]?.path ?? null;
10708
10734
  }
10709
10735
 
@@ -10733,12 +10759,12 @@ async function getReviewSynthesis(req, res) {
10733
10759
  const cwd = getCwdParam(req, res);
10734
10760
  if (!cwd) return;
10735
10761
  try {
10736
- const path71 = await resolveSynthesisPath(cwd);
10737
- if (!path71) {
10762
+ const path73 = await resolveSynthesisPath(cwd);
10763
+ if (!path73) {
10738
10764
  respondJson(res, 404, { error: "No synthesis found" });
10739
10765
  return;
10740
10766
  }
10741
- respondJson(res, 200, { synthesis: readFileSync21(path71, "utf8") });
10767
+ respondJson(res, 200, { synthesis: readFileSync21(path73, "utf8") });
10742
10768
  } catch {
10743
10769
  respondJson(res, 404, { error: "No synthesis found" });
10744
10770
  }
@@ -10821,8 +10847,8 @@ function parseDiffNameStatus(output) {
10821
10847
  if (!status3 || fields.length < 2) continue;
10822
10848
  const category = categorize(status3[0]);
10823
10849
  if (!category) continue;
10824
- const path71 = fields[fields.length - 1];
10825
- if (path71) result[category].push(path71);
10850
+ const path73 = fields[fields.length - 1];
10851
+ if (path73) result[category].push(path73);
10826
10852
  }
10827
10853
  return result;
10828
10854
  }
@@ -10958,21 +10984,21 @@ function subsequenceScore(text17, query) {
10958
10984
  }
10959
10985
  return score - Math.min(text17.length, MAX_LENGTH_PENALTY);
10960
10986
  }
10961
- function scoreFilePath(path71, query) {
10987
+ function scoreFilePath(path73, query) {
10962
10988
  const needle = query.trim().toLowerCase();
10963
10989
  if (!needle) return 0;
10964
- const basename21 = path71.slice(path71.lastIndexOf("/") + 1);
10965
- const inBasename = subsequenceScore(basename21, needle);
10990
+ const basename23 = path73.slice(path73.lastIndexOf("/") + 1);
10991
+ const inBasename = subsequenceScore(basename23, needle);
10966
10992
  if (inBasename !== null) return BASENAME_WEIGHT + inBasename;
10967
- return subsequenceScore(path71, needle);
10993
+ return subsequenceScore(path73, needle);
10968
10994
  }
10969
10995
 
10970
10996
  // src/commands/sessions/web/rankFilePaths.ts
10971
10997
  function rankFilePaths(paths, query, limit) {
10972
10998
  const scored = [];
10973
- for (const path71 of paths) {
10974
- const score = scoreFilePath(path71, query);
10975
- if (score !== null) scored.push({ path: path71, score });
10999
+ for (const path73 of paths) {
11000
+ const score = scoreFilePath(path73, query);
11001
+ if (score !== null) scored.push({ path: path73, score });
10976
11002
  }
10977
11003
  scored.sort((a, b) => b.score - a.score || a.path.localeCompare(b.path));
10978
11004
  return scored.slice(0, limit).map((entry) => entry.path);
@@ -11437,38 +11463,38 @@ async function restartWeb(req, res, deps2 = {}) {
11437
11463
  import { relative as relative3 } from "path";
11438
11464
 
11439
11465
  // src/commands/sessions/web/revertPathChanges.ts
11440
- async function isTracked(cwd, path71) {
11466
+ async function isTracked(cwd, path73) {
11441
11467
  try {
11442
- await execGit(cwd, ["ls-files", "--error-unmatch", "--", path71]);
11468
+ await execGit(cwd, ["ls-files", "--error-unmatch", "--", path73]);
11443
11469
  return true;
11444
11470
  } catch {
11445
11471
  return false;
11446
11472
  }
11447
11473
  }
11448
- async function isInHead(cwd, path71) {
11449
- const listing = await execGit(cwd, ["ls-tree", "HEAD", "--", path71]);
11474
+ async function isInHead(cwd, path73) {
11475
+ const listing = await execGit(cwd, ["ls-tree", "HEAD", "--", path73]);
11450
11476
  return listing.trim().length > 0;
11451
11477
  }
11452
- async function revertPathChanges(cwd, path71) {
11453
- if (!await isTracked(cwd, path71)) {
11454
- await execGit(cwd, ["clean", "-f", "--", path71]);
11478
+ async function revertPathChanges(cwd, path73) {
11479
+ if (!await isTracked(cwd, path73)) {
11480
+ await execGit(cwd, ["clean", "-f", "--", path73]);
11455
11481
  return;
11456
11482
  }
11457
- if (await isInHead(cwd, path71)) {
11458
- await execGit(cwd, ["checkout", "HEAD", "--", path71]);
11483
+ if (await isInHead(cwd, path73)) {
11484
+ await execGit(cwd, ["checkout", "HEAD", "--", path73]);
11459
11485
  return;
11460
11486
  }
11461
- await execGit(cwd, ["rm", "-f", "--", path71]);
11487
+ await execGit(cwd, ["rm", "-f", "--", path73]);
11462
11488
  }
11463
11489
 
11464
11490
  // src/commands/sessions/web/revertDiffFile.ts
11465
11491
  async function revertDiffFile(req, res) {
11466
11492
  const resolved = getFileTarget(req, res);
11467
11493
  if (!resolved) return;
11468
- const path71 = relative3(repoRoot(resolved.cwd), resolved.target);
11494
+ const path73 = relative3(repoRoot(resolved.cwd), resolved.target);
11469
11495
  try {
11470
- await revertPathChanges(resolved.cwd, path71);
11471
- respondJson(res, 200, { reverted: path71 });
11496
+ await revertPathChanges(resolved.cwd, path73);
11497
+ respondJson(res, 200, { reverted: path73 });
11472
11498
  } catch (error) {
11473
11499
  respondJson(res, 500, {
11474
11500
  error: error instanceof Error ? error.message : "Failed to revert file"
@@ -11549,11 +11575,11 @@ function coerceStructuredConfigValue(key, raw) {
11549
11575
  };
11550
11576
  }
11551
11577
  function formatIssue(key, issue) {
11552
- const path71 = formatConfigPath([
11578
+ const path73 = formatConfigPath([
11553
11579
  { kind: "key", name: key },
11554
11580
  ...issue.path.map(toSegment)
11555
11581
  ]);
11556
- return `${path71}: ${issue.message}`;
11582
+ return `${path73}: ${issue.message}`;
11557
11583
  }
11558
11584
  function toSegment(part) {
11559
11585
  return typeof part === "number" ? { kind: "index", index: part } : { kind: "key", name: String(part) };
@@ -11648,9 +11674,9 @@ function coerceUnion(key, raw, types) {
11648
11674
  }
11649
11675
 
11650
11676
  // src/shared/valueAtConfigPath.ts
11651
- function valueAtConfigPath(value, path71) {
11677
+ function valueAtConfigPath(value, path73) {
11652
11678
  let current = value;
11653
- for (const key of path71) {
11679
+ for (const key of path73) {
11654
11680
  if (typeof key === "number") {
11655
11681
  if (!Array.isArray(current)) return void 0;
11656
11682
  current = current[key];
@@ -11667,7 +11693,7 @@ function restoreConfigSecrets(value, stored, node) {
11667
11693
  return mapConfigSecrets(
11668
11694
  value,
11669
11695
  node,
11670
- (secret, path71) => isRedactedSecret(secret) ? valueAtConfigPath(stored, path71) : secret
11696
+ (secret, path73) => isRedactedSecret(secret) ? valueAtConfigPath(stored, path73) : secret
11671
11697
  );
11672
11698
  }
11673
11699
 
@@ -11716,8 +11742,8 @@ function stepIntoNested(container, key, nextKey) {
11716
11742
  }
11717
11743
  return ensureObject(container, resolved);
11718
11744
  }
11719
- function setNestedValue(obj, path71, value) {
11720
- const keys = path71.split(".");
11745
+ function setNestedValue(obj, path73, value) {
11746
+ const keys = path73.split(".");
11721
11747
  const result = { ...obj };
11722
11748
  let current = result;
11723
11749
  for (let i = 0; i < keys.length - 1; i++) {
@@ -11738,8 +11764,8 @@ function validateConfig(updated, key, schema2 = assistConfigSchema) {
11738
11764
  };
11739
11765
  }
11740
11766
  function formatIssue2(issue, key) {
11741
- const path71 = issue.path.length > 0 ? issue.path.join(".") : key;
11742
- return `${path71}: ${issue.message}`;
11767
+ const path73 = issue.path.length > 0 ? issue.path.join(".") : key;
11768
+ return `${path73}: ${issue.message}`;
11743
11769
  }
11744
11770
 
11745
11771
  // src/commands/config/applyConfigSet.ts
@@ -11970,8 +11996,8 @@ function removeAt(container, keys) {
11970
11996
  }
11971
11997
  return removeFromChild(container, key, rest);
11972
11998
  }
11973
- function unsetNestedValue(obj, path71) {
11974
- const { container, removed } = removeAt(obj, path71.split("."));
11999
+ function unsetNestedValue(obj, path73) {
12000
+ const { container, removed } = removeAt(obj, path73.split("."));
11975
12001
  return { config: container, removed };
11976
12002
  }
11977
12003
 
@@ -12963,9 +12989,9 @@ function originToSshUrl(origin) {
12963
12989
  const firstSlash = origin.indexOf("/");
12964
12990
  if (firstSlash <= 0) return null;
12965
12991
  const host = origin.slice(0, firstSlash);
12966
- const path71 = origin.slice(firstSlash + 1);
12967
- if (!path71) return null;
12968
- return `git@${host}:${path71}.git`;
12992
+ const path73 = origin.slice(firstSlash + 1);
12993
+ if (!path73) return null;
12994
+ return `git@${host}:${path73}.git`;
12969
12995
  }
12970
12996
 
12971
12997
  // src/commands/backlog/cloneRepo.ts
@@ -14192,6 +14218,17 @@ This is usually a transient database/network blip \u2014 the work is saved and t
14192
14218
  }
14193
14219
  }
14194
14220
 
14221
+ // src/commands/backlog/reportLaunchActivity.ts
14222
+ function reportLaunchActivity(slashCommand, claudeSessionId, harness, item) {
14223
+ emitActivity({
14224
+ kind: "command",
14225
+ name: slashCommand,
14226
+ itemId: item?.itemId,
14227
+ itemName: item?.itemName,
14228
+ ...harnessActivityFields(harness, claudeSessionId)
14229
+ });
14230
+ }
14231
+
14195
14232
  // src/commands/backlog/launchMode.ts
14196
14233
  function buildSlashCommand(slashCommand, description) {
14197
14234
  const trimmed = description?.trim();
@@ -14202,15 +14239,10 @@ async function launchMode(slashCommand, options2) {
14202
14239
  if (!resumeSessionId) pullIfConfigured();
14203
14240
  process.env.ASSIST_SESSION_ID ??= String(process.pid);
14204
14241
  const claudeSessionId = resumeSessionId ?? randomUUID4();
14205
- emitActivity({
14206
- kind: "command",
14207
- name: slashCommand,
14208
- itemId: options2?.itemId,
14209
- itemName: options2?.itemName,
14210
- claudeSessionId
14211
- });
14242
+ const harness = options2?.harness ?? "claude";
14243
+ reportLaunchActivity(slashCommand, claudeSessionId, harness, options2);
14212
14244
  const prompt = resumeSessionId ? resumeNudge() : buildSlashCommand(slashCommand, options2?.description);
14213
- const { child, done: done2 } = spawnHarness(options2?.harness ?? "claude", prompt, {
14245
+ const { child, done: done2 } = spawnHarness(harness, prompt, {
14214
14246
  sessionId: claudeSessionId,
14215
14247
  resumeSessionId,
14216
14248
  cwd: process.cwd()
@@ -14265,7 +14297,7 @@ async function refine(id, options2) {
14265
14297
  }
14266
14298
 
14267
14299
  // src/commands/backlog/resolveHarness.ts
14268
- function resolveHarness(value) {
14300
+ function resolveHarness2(value) {
14269
14301
  if (value === "claude" || value === "codex" || value === "pi") return value;
14270
14302
  return loadConfig().harness.engine;
14271
14303
  }
@@ -14278,7 +14310,7 @@ function registerRefineCommand(cmd) {
14278
14310
  ).action(
14279
14311
  (id, opts) => refine(id, {
14280
14312
  once: opts.once,
14281
- harness: resolveHarness(opts.harness)
14313
+ harness: resolveHarness2(opts.harness)
14282
14314
  })
14283
14315
  );
14284
14316
  }
@@ -14321,7 +14353,7 @@ function registerRunCommand(cmd) {
14321
14353
  if (!opts.resumeSession) pullIfConfigured();
14322
14354
  await run2(id, {
14323
14355
  allowEdits: opts.write !== false,
14324
- harness: resolveHarness(opts.harness),
14356
+ harness: resolveHarness2(opts.harness),
14325
14357
  resumeSessionId: opts.resumeSession
14326
14358
  });
14327
14359
  }
@@ -15937,9 +15969,9 @@ var __dirname4 = dirname23(__filename3);
15937
15969
  function packageRoot() {
15938
15970
  return __dirname4;
15939
15971
  }
15940
- function readLines(path71) {
15941
- if (!existsSync32(path71)) return [];
15942
- return readFileSync25(path71, "utf8").split("\n").filter((line) => line.trim() !== "");
15972
+ function readLines(path73) {
15973
+ if (!existsSync32(path73)) return [];
15974
+ return readFileSync25(path73, "utf8").split("\n").filter((line) => line.trim() !== "");
15943
15975
  }
15944
15976
  var cachedReads;
15945
15977
  var cachedWrites;
@@ -16433,14 +16465,14 @@ function showProgress(p, label2) {
16433
16465
  const pct = Math.round(p.done / p.total * 100);
16434
16466
  process.stderr.write(`\r\x1B[K[${pct}%] Scanning ${label2}...`);
16435
16467
  }
16436
- async function resolveCommand(cli, path71, description, depth, p) {
16437
- showProgress(p, path71.join(" "));
16438
- const subHelp = await runHelp([cli, ...path71]);
16468
+ async function resolveCommand(cli, path73, description, depth, p) {
16469
+ showProgress(p, path73.join(" "));
16470
+ const subHelp = await runHelp([cli, ...path73]);
16439
16471
  if (!subHelp || !hasSubcommands(subHelp)) {
16440
- return [{ path: path71, description }];
16472
+ return [{ path: path73, description }];
16441
16473
  }
16442
- const children = await discoverAt(cli, path71, depth + 1, p);
16443
- return children.length > 0 ? children : [{ path: path71, description }];
16474
+ const children = await discoverAt(cli, path73, depth + 1, p);
16475
+ return children.length > 0 ? children : [{ path: path73, description }];
16444
16476
  }
16445
16477
  async function discoverAt(cli, parentPath, depth, p) {
16446
16478
  if (depth > SAFETY_DEPTH) return [];
@@ -16588,9 +16620,9 @@ function logPath(cli) {
16588
16620
  return join34(homedir16(), ".assist", `cli-discover-${safeName}.log`);
16589
16621
  }
16590
16622
  function readCache(cli) {
16591
- const path71 = logPath(cli);
16592
- if (!existsSync34(path71)) return void 0;
16593
- return readFileSync27(path71, "utf8");
16623
+ const path73 = logPath(cli);
16624
+ if (!existsSync34(path73)) return void 0;
16625
+ return readFileSync27(path73, "utf8");
16594
16626
  }
16595
16627
  function writeCache(cli, output) {
16596
16628
  const dir = join34(homedir16(), ".assist");
@@ -16750,9 +16782,9 @@ function sweepRestrictedDir(dir = getRestrictedDir()) {
16750
16782
  }
16751
16783
  const cutoff = Date.now() - STALE_AFTER_MS;
16752
16784
  for (const entry of entries) {
16753
- const path71 = join36(dir, entry);
16785
+ const path73 = join36(dir, entry);
16754
16786
  try {
16755
- if (statSync5(path71).mtimeMs < cutoff) unlinkSync7(path71);
16787
+ if (statSync5(path73).mtimeMs < cutoff) unlinkSync7(path73);
16756
16788
  } catch {
16757
16789
  continue;
16758
16790
  }
@@ -16762,10 +16794,10 @@ function sweepRestrictedDir(dir = getRestrictedDir()) {
16762
16794
  // src/commands/codeComment/readPinState.ts
16763
16795
  import { existsSync as existsSync35, readFileSync as readFileSync28 } from "fs";
16764
16796
  function readPinState(pin) {
16765
- const path71 = getPinStatePath(pin);
16766
- if (!existsSync35(path71)) return void 0;
16797
+ const path73 = getPinStatePath(pin);
16798
+ if (!existsSync35(path73)) return void 0;
16767
16799
  try {
16768
- const state = JSON.parse(readFileSync28(path71, "utf8"));
16800
+ const state = JSON.parse(readFileSync28(path73, "utf8"));
16769
16801
  if (state.pin !== pin) return void 0;
16770
16802
  return state;
16771
16803
  } catch {
@@ -17850,10 +17882,10 @@ function getMigrationApprovalPath(migrationId) {
17850
17882
  // src/commands/dbMigration/readMigrationPinState.ts
17851
17883
  import { existsSync as existsSync37, readFileSync as readFileSync30 } from "fs";
17852
17884
  function readMigrationPinState(pin) {
17853
- const path71 = getMigrationPinPath(pin);
17854
- if (!existsSync37(path71)) return void 0;
17885
+ const path73 = getMigrationPinPath(pin);
17886
+ if (!existsSync37(path73)) return void 0;
17855
17887
  try {
17856
- const state = JSON.parse(readFileSync30(path71, "utf8"));
17888
+ const state = JSON.parse(readFileSync30(path73, "utf8"));
17857
17889
  if (state.pin !== pin) return void 0;
17858
17890
  if (!Number.isInteger(state.migrationId)) return void 0;
17859
17891
  return state;
@@ -19251,10 +19283,10 @@ function decideCommentGuard(input, existingContent) {
19251
19283
  import { existsSync as existsSync43, unlinkSync as unlinkSync11 } from "fs";
19252
19284
  function consumeMigrationApproval(migrationId) {
19253
19285
  sweepRestrictedDir();
19254
- const path71 = getMigrationApprovalPath(migrationId);
19255
- if (!existsSync43(path71)) return false;
19286
+ const path73 = getMigrationApprovalPath(migrationId);
19287
+ if (!existsSync43(path73)) return false;
19256
19288
  try {
19257
- unlinkSync11(path71);
19289
+ unlinkSync11(path73);
19258
19290
  return true;
19259
19291
  } catch {
19260
19292
  return false;
@@ -19972,7 +20004,7 @@ function runRefine(id, opts) {
19972
20004
  return refine(id, {
19973
20005
  once: opts.once,
19974
20006
  resumeSessionId: opts.resumeSession,
19975
- harness: resolveHarness(opts.harness)
20007
+ harness: resolveHarness2(opts.harness)
19976
20008
  });
19977
20009
  }
19978
20010
  function registerRefineLaunch(program2, resumeFlag) {
@@ -20061,22 +20093,22 @@ function createWorktree(clone, strategy, boundTreeRoots2, preferredPath) {
20061
20093
  const registered = new Set(listWorktreePaths(clone));
20062
20094
  const branches = new Set(listLocalBranches(clone));
20063
20095
  const isTaken = (candidate) => registered.has(candidate) || existsSync45(candidate) || boundTreeRoots2.has(candidate) || branches.has(basename14(candidate));
20064
- const path71 = preferredPath && !isTaken(preferredPath) ? preferredPath : nextWorktreePath(clone, base, isTaken);
20096
+ const path73 = preferredPath && !isTaken(preferredPath) ? preferredPath : nextWorktreePath(clone, base, isTaken);
20065
20097
  const start3 = worktreeStartPoint(clone, strategy.trunk);
20066
20098
  gitSync(clone, [
20067
20099
  "worktree",
20068
20100
  "add",
20069
20101
  start3.track ? "--track" : "--no-track",
20070
20102
  "-b",
20071
- basename14(path71),
20072
- path71,
20103
+ basename14(path73),
20104
+ path73,
20073
20105
  start3.ref
20074
20106
  ]);
20075
- recordWorktree(path71, clone, getCurrentOrigin(clone));
20107
+ recordWorktree(path73, clone, getCurrentOrigin(clone));
20076
20108
  daemonLog(
20077
- start3.track ? `worktree allocated ${path71} (branch ${basename14(path71)} tracking ${start3.ref}) for clone ${clone}` : `worktree allocated ${path71} (branch ${basename14(path71)} off ${start3.ref}, no mainline tracking) for clone ${clone}`
20109
+ start3.track ? `worktree allocated ${path73} (branch ${basename14(path73)} tracking ${start3.ref}) for clone ${clone}` : `worktree allocated ${path73} (branch ${basename14(path73)} off ${start3.ref}, no mainline tracking) for clone ${clone}`
20078
20110
  );
20079
- return path71;
20111
+ return path73;
20080
20112
  }
20081
20113
 
20082
20114
  // src/commands/sessions/daemon/worktree/treeDurability.ts
@@ -20188,13 +20220,13 @@ function allocateTree(requestedCwd, boundTreeRoots2, options2 = {}) {
20188
20220
  if (forcedSpill) daemonLog(forcedSpill);
20189
20221
  else if (reusesClone(clone, boundTreeRoots2, reuse))
20190
20222
  return { cwd: clone, kind: "primary", created: false, clone };
20191
- const path71 = createWorktree(
20223
+ const path73 = createWorktree(
20192
20224
  clone,
20193
20225
  { root: cfg.root, trunk: cfg.trunk },
20194
20226
  boundTreeRoots2,
20195
20227
  options2.replacesTree
20196
20228
  );
20197
- return { cwd: path71, kind: "worktree", created: true, clone };
20229
+ return { cwd: path73, kind: "worktree", created: true, clone };
20198
20230
  }
20199
20231
  function keptInPlace(cwd) {
20200
20232
  daemonLog(
@@ -20525,13 +20557,13 @@ function worktreeHoldingBranch(cwd, branch2) {
20525
20557
  const listing = gitSyncOrNull(cwd, ["worktree", "list", "--porcelain"]);
20526
20558
  if (!listing) return null;
20527
20559
  const here = gitSyncOrNull(cwd, ["rev-parse", "--show-toplevel"]);
20528
- let path71 = null;
20560
+ let path73 = null;
20529
20561
  for (const line of listing.split("\n")) {
20530
20562
  const trimmed = line.trim();
20531
20563
  if (trimmed.startsWith("worktree "))
20532
- path71 = trimmed.slice("worktree ".length).trim();
20564
+ path73 = trimmed.slice("worktree ".length).trim();
20533
20565
  else if (trimmed === `branch refs/heads/${branch2}`)
20534
- return path71 && path71 !== here ? path71 : null;
20566
+ return path73 && path73 !== here ? path73 : null;
20535
20567
  }
20536
20568
  return null;
20537
20569
  }
@@ -20988,9 +21020,9 @@ function parseRscRows(flight) {
20988
21020
  }
20989
21021
  function makeRscResolver(rows) {
20990
21022
  return (ref) => {
20991
- const [id, ...path71] = ref.slice(1).replace(/^[L@]/, "").split(":");
21023
+ const [id, ...path73] = ref.slice(1).replace(/^[L@]/, "").split(":");
20992
21024
  let v = rows[id];
20993
- for (const key of path71) {
21025
+ for (const key of path73) {
20994
21026
  if (v == null || typeof v !== "object") return void 0;
20995
21027
  v = v[key];
20996
21028
  }
@@ -21676,15 +21708,15 @@ function postComment(vars) {
21676
21708
  const stdout = startLine === void 0 ? runGhGraphql(MUTATION_SINGLE, base) : runGhGraphql(MUTATION_MULTI, { ...base, startLine });
21677
21709
  assertThreadCreated(stdout);
21678
21710
  }
21679
- function comment2(path71, line, body, startLine) {
21711
+ function comment2(path73, line, body, startLine) {
21680
21712
  validateBody(body);
21681
21713
  validateLine(line);
21682
21714
  if (startLine !== void 0) validateLine(startLine);
21683
21715
  try {
21684
21716
  const prId = getCurrentPrNodeId();
21685
- postComment({ prId, body, path: path71, line, startLine });
21717
+ postComment({ prId, body, path: path73, line, startLine });
21686
21718
  const range = startLine !== void 0 ? `${startLine}-${line}` : `${line}`;
21687
- console.log(`Added review comment on ${path71}:${range}`);
21719
+ console.log(`Added review comment on ${path73}:${range}`);
21688
21720
  } catch (error) {
21689
21721
  if (isGhNotInstalled(error)) {
21690
21722
  console.error("Error: GitHub CLI (gh) is not installed.");
@@ -22939,8 +22971,8 @@ function registerPrs(program2) {
22939
22971
  prsCommand.command("reply <comment-id> <body>").description("Reply to a comment thread without resolving it").action((commentId, body) => {
22940
22972
  reply(Number.parseInt(commentId, 10), body);
22941
22973
  });
22942
- prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path71, line, body) => {
22943
- comment2(path71, Number.parseInt(line, 10), body);
22974
+ prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path73, line, body) => {
22975
+ comment2(path73, Number.parseInt(line, 10), body);
22944
22976
  });
22945
22977
  configHelp(prsCommand, prsConfigHelp);
22946
22978
  }
@@ -23193,10 +23225,10 @@ function resolveOpSecret(reference) {
23193
23225
  }
23194
23226
 
23195
23227
  // src/commands/ravendb/ravenFetch.ts
23196
- async function ravenFetch(connection, path71) {
23228
+ async function ravenFetch(connection, path73) {
23197
23229
  const apiKey = resolveOpSecret(connection.apiKeyRef);
23198
23230
  let accessToken = await getAccessToken(apiKey);
23199
- const url = `${connection.url}${path71}`;
23231
+ const url = `${connection.url}${path73}`;
23200
23232
  const headers = {
23201
23233
  Authorization: `Bearer ${accessToken}`,
23202
23234
  "Content-Type": "application/json"
@@ -23286,16 +23318,16 @@ import chalk182 from "chalk";
23286
23318
  // src/commands/ravendb/buildQueryPath.ts
23287
23319
  function buildQueryPath(opts) {
23288
23320
  const db = encodeURIComponent(opts.db);
23289
- let path71;
23321
+ let path73;
23290
23322
  if (opts.collection) {
23291
- path71 = `/databases/${db}/indexes/dynamic/${encodeURIComponent(opts.collection)}?start=${opts.start}&pageSize=${opts.pageSize}&sort=${encodeURIComponent(opts.sort)}`;
23323
+ path73 = `/databases/${db}/indexes/dynamic/${encodeURIComponent(opts.collection)}?start=${opts.start}&pageSize=${opts.pageSize}&sort=${encodeURIComponent(opts.sort)}`;
23292
23324
  } else {
23293
- path71 = `/databases/${db}/queries?start=${opts.start}&pageSize=${opts.pageSize}`;
23325
+ path73 = `/databases/${db}/queries?start=${opts.start}&pageSize=${opts.pageSize}`;
23294
23326
  }
23295
23327
  if (opts.query) {
23296
- path71 += `&query=${encodeURIComponent(opts.query)}`;
23328
+ path73 += `&query=${encodeURIComponent(opts.query)}`;
23297
23329
  }
23298
- return path71;
23330
+ return path73;
23299
23331
  }
23300
23332
 
23301
23333
  // src/commands/ravendb/fetchAllPages.ts
@@ -23304,7 +23336,7 @@ async function fetchAllPages(connection, opts) {
23304
23336
  let start3 = 0;
23305
23337
  while (true) {
23306
23338
  const effectivePageSize = opts.limit !== void 0 ? Math.min(opts.pageSize, opts.limit - allResults.length) : opts.pageSize;
23307
- const path71 = buildQueryPath({
23339
+ const path73 = buildQueryPath({
23308
23340
  db: connection.database,
23309
23341
  collection: opts.collection,
23310
23342
  start: start3,
@@ -23312,7 +23344,7 @@ async function fetchAllPages(connection, opts) {
23312
23344
  sort: opts.sort,
23313
23345
  query: opts.query
23314
23346
  });
23315
- const data = await ravenFetch(connection, path71);
23347
+ const data = await ravenFetch(connection, path73);
23316
23348
  const results = data.Results ?? [];
23317
23349
  const totalResults = data.TotalResults ?? 0;
23318
23350
  if (results.length === 0) break;
@@ -24753,8 +24785,8 @@ function findRootParent(file, importedBy, visited) {
24753
24785
  function clusterFiles(graph) {
24754
24786
  const clusters = /* @__PURE__ */ new Map();
24755
24787
  for (const file of graph.files) {
24756
- const basename21 = path52.basename(file, path52.extname(file));
24757
- if (basename21 === "index") continue;
24788
+ const basename23 = path52.basename(file, path52.extname(file));
24789
+ if (basename23 === "index") continue;
24758
24790
  const importers = graph.importedBy.get(file);
24759
24791
  if (!importers || importers.size !== 1) continue;
24760
24792
  const parent = [...importers][0];
@@ -25907,8 +25939,8 @@ async function handlePostSynthesis(synthesisPath, prInfo, options2) {
25907
25939
  // src/commands/review/prepareReviewDir.ts
25908
25940
  import { existsSync as existsSync50, mkdirSync as mkdirSync19, unlinkSync as unlinkSync17, writeFileSync as writeFileSync36 } from "fs";
25909
25941
  function clearReviewFiles(paths) {
25910
- for (const path71 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
25911
- if (existsSync50(path71)) unlinkSync17(path71);
25942
+ for (const path73 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
25943
+ if (existsSync50(path73)) unlinkSync17(path73);
25912
25944
  }
25913
25945
  }
25914
25946
  function prepareReviewDir(paths, requestBody, force) {
@@ -26998,8 +27030,8 @@ import chalk203 from "chalk";
26998
27030
 
26999
27031
  // src/commands/seq/fetchSeq.ts
27000
27032
  import chalk200 from "chalk";
27001
- async function fetchSeq(conn, path71, params) {
27002
- const url = `${conn.url}${path71}?${params}`;
27033
+ async function fetchSeq(conn, path73, params) {
27034
+ const url = `${conn.url}${path73}?${params}`;
27003
27035
  const response = await fetch(url, {
27004
27036
  headers: {
27005
27037
  Accept: "application/json",
@@ -27548,6 +27580,438 @@ function registerSql(program2) {
27548
27580
  configHelp(cmd, sqlConfigHelp);
27549
27581
  }
27550
27582
 
27583
+ // src/commands/sync.ts
27584
+ import * as fs43 from "fs";
27585
+ import * as os4 from "os";
27586
+ import * as path68 from "path";
27587
+ import { fileURLToPath as fileURLToPath7 } from "url";
27588
+
27589
+ // src/commands/sync/pruneCommands.ts
27590
+ import * as path59 from "path";
27591
+
27592
+ // src/commands/sync/pruneTarget.ts
27593
+ import * as fs35 from "fs";
27594
+ import * as path58 from "path";
27595
+ function pruneTarget(targetDir, keepNames, shape, options2) {
27596
+ const result = {
27597
+ orphans: [],
27598
+ removed: [],
27599
+ skipped: [],
27600
+ unmanaged: []
27601
+ };
27602
+ if (!fs35.existsSync(targetDir)) return result;
27603
+ const keep = new Set(keepNames);
27604
+ for (const entry of fs35.readdirSync(targetDir, { withFileTypes: true })) {
27605
+ const name = shape.nameOf(entry);
27606
+ if (name === void 0) {
27607
+ result.unmanaged.push(entry.name);
27608
+ continue;
27609
+ }
27610
+ if (keep.has(name)) continue;
27611
+ result.orphans.push(entry.name);
27612
+ const entryPath = path58.join(targetDir, entry.name);
27613
+ const reason4 = shape.blockedBy?.(entryPath);
27614
+ if (reason4) {
27615
+ result.skipped.push({ name: entry.name, reason: reason4 });
27616
+ continue;
27617
+ }
27618
+ if (options2.force) {
27619
+ fs35.rmSync(entryPath, { recursive: true });
27620
+ result.removed.push(entry.name);
27621
+ }
27622
+ }
27623
+ return result;
27624
+ }
27625
+
27626
+ // src/commands/sync/pruneCommands.ts
27627
+ function pruneCommands(targetDir, commandNames, options2) {
27628
+ return pruneTarget(
27629
+ targetDir,
27630
+ commandNames,
27631
+ {
27632
+ nameOf: (entry) => entry.isFile() && entry.name.endsWith(".md") ? path59.basename(entry.name, ".md") : void 0
27633
+ },
27634
+ options2
27635
+ );
27636
+ }
27637
+
27638
+ // src/commands/sync/reportPrune.ts
27639
+ function reportPrune(label2, result, force) {
27640
+ if (result.orphans.length === 0) {
27641
+ console.log(`No orphaned commands in ${label2}`);
27642
+ } else if (force) {
27643
+ for (const name of result.removed) {
27644
+ console.log(`Removed ${name} from ${label2}`);
27645
+ }
27646
+ } else {
27647
+ console.log(`Orphaned commands in ${label2} (run with --force to remove):`);
27648
+ for (const name of result.orphans) {
27649
+ console.log(` ${name}`);
27650
+ }
27651
+ }
27652
+ if (result.skipped.length > 0) {
27653
+ console.log(`Left in place in ${label2} (not written by sync):`);
27654
+ for (const { name, reason: reason4 } of result.skipped) {
27655
+ console.log(` ${name} - ${reason4}`);
27656
+ }
27657
+ }
27658
+ if (result.unmanaged.length === 0) return;
27659
+ console.log(`Not managed by sync in ${label2} (never removed):`);
27660
+ for (const name of result.unmanaged) {
27661
+ console.log(` ${name}`);
27662
+ }
27663
+ }
27664
+
27665
+ // src/commands/sync/syncClaudeMd.ts
27666
+ import * as fs36 from "fs";
27667
+ import * as path60 from "path";
27668
+ import chalk210 from "chalk";
27669
+ async function syncClaudeMd(claudeDir, targetBase, options2) {
27670
+ const source = path60.join(claudeDir, "CLAUDE.md");
27671
+ const target = path60.join(targetBase, "CLAUDE.md");
27672
+ const sourceContent = fs36.readFileSync(source, "utf8");
27673
+ if (fs36.existsSync(target)) {
27674
+ const targetContent = fs36.readFileSync(target, "utf8");
27675
+ if (sourceContent !== targetContent) {
27676
+ console.log(
27677
+ chalk210.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
27678
+ );
27679
+ console.log();
27680
+ printDiff(targetContent, sourceContent);
27681
+ if (!options2?.yes) {
27682
+ printAutoConfirmHint();
27683
+ const confirm = await promptConfirm(
27684
+ chalk210.red("Overwrite existing CLAUDE.md?"),
27685
+ false
27686
+ );
27687
+ if (!confirm) {
27688
+ console.log("Skipped CLAUDE.md");
27689
+ return;
27690
+ }
27691
+ }
27692
+ }
27693
+ }
27694
+ fs36.copyFileSync(source, target);
27695
+ console.log("Copied CLAUDE.md to ~/.claude/CLAUDE.md");
27696
+ }
27697
+
27698
+ // src/commands/sync/syncCodex.ts
27699
+ import * as path63 from "path";
27700
+
27701
+ // src/commands/sync/installHarnessCommands.ts
27702
+ import * as fs37 from "fs";
27703
+ import * as path61 from "path";
27704
+ function installHarnessCommands(claudeDir, harness, transform) {
27705
+ const commandsSource = path61.join(claudeDir, "commands");
27706
+ const files = fs37.readdirSync(commandsSource);
27707
+ const names = [];
27708
+ let synced = 0;
27709
+ for (const file of files) {
27710
+ if (!file.endsWith(".md")) continue;
27711
+ const name = file.replace(/\.md$/, "");
27712
+ names.push(name);
27713
+ const content = fs37.readFileSync(path61.join(commandsSource, file), "utf8");
27714
+ const target = path61.join(harness.homeDir, harness.sync.commandDest(name));
27715
+ fs37.mkdirSync(path61.dirname(target), { recursive: true });
27716
+ fs37.writeFileSync(target, transform(name, content));
27717
+ synced++;
27718
+ }
27719
+ const agentsTarget = path61.join(harness.homeDir, harness.sync.agentsFile);
27720
+ fs37.mkdirSync(path61.dirname(agentsTarget), { recursive: true });
27721
+ fs37.copyFileSync(path61.join(claudeDir, "CLAUDE.md"), agentsTarget);
27722
+ return { total: files.length, synced, names };
27723
+ }
27724
+
27725
+ // src/commands/sync/pruneSkills.ts
27726
+ import * as fs38 from "fs";
27727
+ function pruneSkills(targetDir, skillNames, options2) {
27728
+ return pruneTarget(
27729
+ targetDir,
27730
+ skillNames,
27731
+ {
27732
+ nameOf: (entry) => entry.isDirectory() ? entry.name : void 0,
27733
+ blockedBy: unexpectedContent
27734
+ },
27735
+ options2
27736
+ );
27737
+ }
27738
+ function unexpectedContent(skillDir) {
27739
+ const entries = fs38.readdirSync(skillDir);
27740
+ const others = entries.filter((entry) => entry !== "SKILL.md");
27741
+ if (others.length > 0) return `contains ${others.sort().join(", ")}`;
27742
+ return entries.length === 0 ? "no SKILL.md" : void 0;
27743
+ }
27744
+
27745
+ // src/commands/sync/syncCodexHooks.ts
27746
+ import * as fs39 from "fs";
27747
+ import * as path62 from "path";
27748
+ var BEGIN = "# >>> assist codex hooks (managed) \u2014 do not edit >>>";
27749
+ var END = "# <<< assist codex hooks (managed) <<<";
27750
+ function upsertManagedBlock(existing, body) {
27751
+ const block = `${BEGIN}
27752
+ ${body.trim()}
27753
+ ${END}`;
27754
+ const begin = existing.indexOf(BEGIN);
27755
+ if (begin === -1) {
27756
+ const base = existing.replace(/\s*$/, "");
27757
+ return base ? `${base}
27758
+
27759
+ ${block}
27760
+ ` : `${block}
27761
+ `;
27762
+ }
27763
+ const endMarker = existing.indexOf(END, begin);
27764
+ const after = endMarker === -1 ? existing.length : endMarker + END.length;
27765
+ const before = existing.slice(0, begin).replace(/\s*$/, "");
27766
+ const rest = existing.slice(after).replace(/^\s*/, "");
27767
+ const head = before ? `${before}
27768
+
27769
+ ${block}` : block;
27770
+ return rest ? `${head}
27771
+
27772
+ ${rest}
27773
+ ` : `${head}
27774
+ `;
27775
+ }
27776
+ function syncCodexHooks(sourcePath) {
27777
+ const body = fs39.readFileSync(sourcePath, "utf8");
27778
+ const configPath = path62.join(harnesses.codex.homeDir, "config.toml");
27779
+ const existing = fs39.existsSync(configPath) ? fs39.readFileSync(configPath, "utf8") : "";
27780
+ fs39.mkdirSync(path62.dirname(configPath), { recursive: true });
27781
+ fs39.writeFileSync(configPath, upsertManagedBlock(existing, body));
27782
+ console.log(
27783
+ "Registered assist codex-hook in ~/.codex/config.toml (PreToolUse, PermissionRequest)"
27784
+ );
27785
+ }
27786
+
27787
+ // src/commands/sync/syncCodex.ts
27788
+ function quoteYaml(value) {
27789
+ return `"${value.replace(/\\/g, String.raw`\\`).replace(/"/g, String.raw`\"`)}"`;
27790
+ }
27791
+ function commandToSkill(name, content) {
27792
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
27793
+ const frontmatter = match ? match[1] : "";
27794
+ const body = match ? content.slice(match[0].length) : content;
27795
+ const descriptionMatch = frontmatter.match(/^description:\s*(.*)$/m);
27796
+ const description = descriptionMatch ? descriptionMatch[1].trim().replace(/^["']|["']$/g, "") : name;
27797
+ const header = `---
27798
+ name: ${name}
27799
+ description: ${quoteYaml(description)}
27800
+ ---
27801
+
27802
+ `;
27803
+ return header + body.replace(/^\r?\n+/, "");
27804
+ }
27805
+ function syncCodex(claudeDir, options2) {
27806
+ if (!isHarnessAvailable("codex")) return;
27807
+ const { total, names } = installHarnessCommands(
27808
+ claudeDir,
27809
+ harnesses.codex,
27810
+ commandToSkill
27811
+ );
27812
+ syncCodexHooks(path63.join(claudeDir, "..", "codex", "config.toml"));
27813
+ console.log(
27814
+ `Synced ${total} skill(s) to ~/.codex/skills and CLAUDE.md to ~/.codex/AGENTS.md`
27815
+ );
27816
+ if (!options2?.prune) return;
27817
+ const force = options2.force ?? false;
27818
+ reportPrune(
27819
+ "~/.codex/skills",
27820
+ pruneSkills(path63.join(harnesses.codex.homeDir, "skills"), names, { force }),
27821
+ force
27822
+ );
27823
+ }
27824
+
27825
+ // src/commands/sync/syncDesign.ts
27826
+ import * as fs40 from "fs";
27827
+ import * as path64 from "path";
27828
+ function syncDesign(claudeDir, targetBase) {
27829
+ const systemPromptSource = path64.join(claudeDir, "design-system-prompt.md");
27830
+ const systemPromptTarget = path64.join(targetBase, "design-system-prompt.md");
27831
+ fs40.copyFileSync(systemPromptSource, systemPromptTarget);
27832
+ console.log(
27833
+ "Copied design-system-prompt.md to ~/.claude/design-system-prompt.md"
27834
+ );
27835
+ const skillsSource = path64.join(claudeDir, "skills");
27836
+ const skillsTarget = path64.join(targetBase, "skills");
27837
+ fs40.mkdirSync(skillsTarget, { recursive: true });
27838
+ const files = fs40.readdirSync(skillsSource);
27839
+ for (const file of files) {
27840
+ fs40.copyFileSync(
27841
+ path64.join(skillsSource, file),
27842
+ path64.join(skillsTarget, file)
27843
+ );
27844
+ }
27845
+ console.log(`Synced ${files.length} design skill(s) to ~/.claude/skills`);
27846
+ }
27847
+
27848
+ // src/commands/sync/syncPi.ts
27849
+ import * as path66 from "path";
27850
+
27851
+ // src/commands/sync/syncPiHooks.ts
27852
+ import * as fs41 from "fs";
27853
+ import * as path65 from "path";
27854
+ function piExtensionsDir() {
27855
+ return path65.join(harnesses.pi.homeDir, "extensions");
27856
+ }
27857
+ function syncPiHooks(sourceDir) {
27858
+ const target = piExtensionsDir();
27859
+ fs41.mkdirSync(target, { recursive: true });
27860
+ const files = fs41.readdirSync(sourceDir).filter((f) => f.endsWith(".ts"));
27861
+ for (const file of files) {
27862
+ fs41.copyFileSync(
27863
+ path65.join(sourceDir, file),
27864
+ path65.join(target, `assist-${file}`)
27865
+ );
27866
+ }
27867
+ console.log(
27868
+ `Registered ${files.length} assist extension(s) in ~/.pi/agent/extensions`
27869
+ );
27870
+ }
27871
+
27872
+ // src/commands/sync/syncPi.ts
27873
+ function unquote(value) {
27874
+ return value.trim().replace(/^["']|["']$/g, "");
27875
+ }
27876
+ function commandToPrompt(name, content) {
27877
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
27878
+ const frontmatter = match ? match[1] : "";
27879
+ const body = match ? content.slice(match[0].length) : content;
27880
+ const descriptionMatch = frontmatter.match(/^description:\s*(.*)$/m);
27881
+ const description = descriptionMatch ? unquote(descriptionMatch[1]) : name;
27882
+ const argsMatch = frontmatter.match(/^allowed_args:\s*(.*)$/m);
27883
+ const argumentHint = argsMatch ? unquote(argsMatch[1]) : void 0;
27884
+ const header = [
27885
+ "---",
27886
+ `description: ${description}`,
27887
+ ...argumentHint ? [`argument-hint: ${argumentHint}`] : [],
27888
+ "---",
27889
+ "",
27890
+ ""
27891
+ ].join("\n");
27892
+ return header + body.replace(/^\r?\n+/, "");
27893
+ }
27894
+ function syncPi(claudeDir, options2) {
27895
+ if (!isHarnessAvailable("pi")) return;
27896
+ const { synced, names } = installHarnessCommands(
27897
+ claudeDir,
27898
+ harnesses.pi,
27899
+ commandToPrompt
27900
+ );
27901
+ syncPiHooks(path66.join(claudeDir, "..", "pi"));
27902
+ console.log(
27903
+ `Synced ${synced} prompt(s) to ~/.pi/agent/prompts and CLAUDE.md to ~/.pi/agent/AGENTS.md`
27904
+ );
27905
+ if (!options2?.prune) return;
27906
+ const force = options2.force ?? false;
27907
+ reportPrune(
27908
+ "~/.pi/agent/prompts",
27909
+ pruneCommands(path66.join(harnesses.pi.homeDir, "prompts"), names, { force }),
27910
+ force
27911
+ );
27912
+ }
27913
+
27914
+ // src/commands/sync/syncSettings.ts
27915
+ import * as fs42 from "fs";
27916
+ import * as path67 from "path";
27917
+ import chalk211 from "chalk";
27918
+ async function syncSettings(claudeDir, targetBase, options2) {
27919
+ const source = path67.join(claudeDir, "settings.json");
27920
+ const target = path67.join(targetBase, "settings.json");
27921
+ const sourceContent = fs42.readFileSync(source, "utf8");
27922
+ const sourceSettings = JSON.parse(sourceContent);
27923
+ const targetExists = fs42.existsSync(target);
27924
+ const targetContent = targetExists ? fs42.readFileSync(target, "utf8") : "";
27925
+ const preservedUserSettings = targetExists ? JSON.parse(targetContent) : {};
27926
+ const mergedContent = JSON.stringify(
27927
+ { ...preservedUserSettings, ...sourceSettings },
27928
+ null,
27929
+ " "
27930
+ );
27931
+ if (targetExists) {
27932
+ const normalizedTarget = JSON.stringify(preservedUserSettings, null, " ");
27933
+ if (mergedContent !== normalizedTarget) {
27934
+ if (!options2?.yes) {
27935
+ console.log(
27936
+ chalk211.yellow(
27937
+ "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
27938
+ )
27939
+ );
27940
+ console.log();
27941
+ printDiff(targetContent, mergedContent);
27942
+ printAutoConfirmHint();
27943
+ const confirm = await promptConfirm(
27944
+ chalk211.red("Overwrite existing settings.json?"),
27945
+ false
27946
+ );
27947
+ if (!confirm) {
27948
+ console.log("Skipped settings.json");
27949
+ return;
27950
+ }
27951
+ }
27952
+ }
27953
+ }
27954
+ fs42.writeFileSync(target, mergedContent);
27955
+ console.log("Copied settings.json to ~/.claude/settings.json");
27956
+ }
27957
+
27958
+ // src/commands/sync.ts
27959
+ var __filename4 = fileURLToPath7(import.meta.url);
27960
+ var __dirname5 = path68.dirname(__filename4);
27961
+ async function sync(options2) {
27962
+ const config = loadConfig();
27963
+ const yes = options2?.yes ?? config.sync.autoConfirm;
27964
+ const prune = { prune: options2?.prune, force: options2?.force };
27965
+ const claudeDir = path68.join(__dirname5, "..", "claude");
27966
+ const targetBase = path68.join(os4.homedir(), ".claude");
27967
+ const commandFiles = syncCommands(claudeDir, targetBase);
27968
+ syncDesign(claudeDir, targetBase);
27969
+ await syncSettings(claudeDir, targetBase, { yes });
27970
+ await syncClaudeMd(claudeDir, targetBase, { yes });
27971
+ syncCodex(claudeDir, prune);
27972
+ syncPi(claudeDir, prune);
27973
+ if (!options2?.prune) return;
27974
+ const commandNames = commandFiles.filter((file) => file.endsWith(".md")).map((file) => path68.basename(file, ".md"));
27975
+ const force = options2.force ?? false;
27976
+ reportPrune(
27977
+ "~/.claude/commands",
27978
+ pruneCommands(path68.join(targetBase, "commands"), commandNames, { force }),
27979
+ force
27980
+ );
27981
+ }
27982
+ function syncCommands(claudeDir, targetBase) {
27983
+ const sourceDir = path68.join(claudeDir, "commands");
27984
+ const targetDir = path68.join(targetBase, "commands");
27985
+ fs43.mkdirSync(targetDir, { recursive: true });
27986
+ const files = fs43.readdirSync(sourceDir);
27987
+ for (const file of files) {
27988
+ fs43.copyFileSync(path68.join(sourceDir, file), path68.join(targetDir, file));
27989
+ console.log(`Copied ${file} to ${targetDir}`);
27990
+ }
27991
+ console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
27992
+ return files;
27993
+ }
27994
+
27995
+ // src/commands/registerSync.ts
27996
+ function registerSync(program2) {
27997
+ const syncCommand = program2.command("sync").description(
27998
+ "Copy command files to ~/.claude/commands; when codex is detected, also install commands as ~/.codex/skills/<name>/SKILL.md, CLAUDE.md as ~/.codex/AGENTS.md, and register the assist codex-hook auto-approval hook in ~/.codex/config.toml; when pi is detected, also install commands as ~/.pi/agent/prompts/<name>.md, CLAUDE.md as ~/.pi/agent/AGENTS.md, and register the assist pi-hook permission-gate extension in ~/.pi/agent/extensions. With --prune, also report commands in those target dirs that sync did not write, and with --prune --force remove them"
27999
+ ).option("-y, --yes", "Overwrite settings.json without prompting").option(
28000
+ "--prune",
28001
+ "After syncing, list commands in the target dirs whose name is not in the repo's claude/commands/*.md set; subdirectories and non-.md files are listed separately and never removed"
28002
+ ).option(
28003
+ "--force",
28004
+ "With --prune, remove the listed orphaned commands; a codex skill directory is removed only when SKILL.md is its sole content. Errors without --prune"
28005
+ ).action((options2) => {
28006
+ if (options2.force && !options2.prune) {
28007
+ console.error("--force requires --prune.");
28008
+ process.exit(1);
28009
+ }
28010
+ return sync(options2);
28011
+ });
28012
+ configHelp(syncCommand, rootConfigHelp.sync);
28013
+ }
28014
+
27551
28015
  // src/commands/transcript/shared.ts
27552
28016
  import * as readline2 from "readline";
27553
28017
  function createReadlineInterface() {
@@ -27619,27 +28083,27 @@ async function configure() {
27619
28083
  }
27620
28084
 
27621
28085
  // src/commands/transcript/list.ts
27622
- import { existsSync as existsSync53, readdirSync as readdirSync11, statSync as statSync9 } from "fs";
27623
- import { join as join61 } from "path";
28086
+ import { existsSync as existsSync57, readdirSync as readdirSync17, statSync as statSync9 } from "fs";
28087
+ import { join as join71 } from "path";
27624
28088
  function list4() {
27625
28089
  const { vttDir } = getTranscriptConfig();
27626
- if (!existsSync53(vttDir)) return;
27627
- for (const entry of readdirSync11(vttDir)) {
28090
+ if (!existsSync57(vttDir)) return;
28091
+ for (const entry of readdirSync17(vttDir)) {
27628
28092
  if (!entry.endsWith(".vtt")) continue;
27629
- if (statSync9(join61(vttDir, entry)).isDirectory()) continue;
28093
+ if (statSync9(join71(vttDir, entry)).isDirectory()) continue;
27630
28094
  console.log(entry);
27631
28095
  }
27632
28096
  }
27633
28097
 
27634
28098
  // src/commands/transcript/move.ts
27635
28099
  import {
27636
- existsSync as existsSync54,
27637
- mkdirSync as mkdirSync20,
27638
- readFileSync as readFileSync43,
28100
+ existsSync as existsSync58,
28101
+ mkdirSync as mkdirSync25,
28102
+ readFileSync as readFileSync47,
27639
28103
  renameSync as renameSync2,
27640
- writeFileSync as writeFileSync38
28104
+ writeFileSync as writeFileSync41
27641
28105
  } from "fs";
27642
- import { basename as basename17, join as join62 } from "path";
28106
+ import { basename as basename19, join as join72 } from "path";
27643
28107
 
27644
28108
  // src/commands/transcript/cleanText.ts
27645
28109
  function cleanText(text17) {
@@ -27847,14 +28311,14 @@ function formatChatLog(messages) {
27847
28311
  // src/commands/transcript/move.ts
27848
28312
  var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
27849
28313
  function convertVttToMarkdown(inputPath) {
27850
- const cues = parseVtt(readFileSync43(inputPath, "utf8"));
28314
+ const cues = parseVtt(readFileSync47(inputPath, "utf8"));
27851
28315
  const messages = cuesToChatMessages(deduplicateCues(cues));
27852
28316
  return formatChatLog(messages);
27853
28317
  }
27854
28318
  function archiveRawVtt(vttDir, sourcePath, filename) {
27855
- const processedDir = join62(vttDir, "processed");
27856
- mkdirSync20(processedDir, { recursive: true });
27857
- renameSync2(sourcePath, join62(processedDir, filename));
28319
+ const processedDir = join72(vttDir, "processed");
28320
+ mkdirSync25(processedDir, { recursive: true });
28321
+ renameSync2(sourcePath, join72(processedDir, filename));
27858
28322
  }
27859
28323
  function move(file, options2) {
27860
28324
  const { date, client } = options2;
@@ -27863,20 +28327,20 @@ function move(file, options2) {
27863
28327
  process.exit(1);
27864
28328
  }
27865
28329
  const { vttDir, transcriptsDir, summaryDir } = getTranscriptConfig();
27866
- const filename = basename17(file);
27867
- const sourcePath = join62(vttDir, filename);
27868
- if (!existsSync54(sourcePath)) {
28330
+ const filename = basename19(file);
28331
+ const sourcePath = join72(vttDir, filename);
28332
+ if (!existsSync58(sourcePath)) {
27869
28333
  console.error(`Error: VTT file not found: ${sourcePath}`);
27870
28334
  process.exit(1);
27871
28335
  }
27872
- const base = basename17(filename, ".vtt").replace(/ Transcription$/, "");
28336
+ const base = basename19(filename, ".vtt").replace(/ Transcription$/, "");
27873
28337
  const outputName = `${date} ${base}.md`;
27874
- const formattedDir = join62(transcriptsDir, client);
27875
- mkdirSync20(formattedDir, { recursive: true });
27876
- const formattedPath = join62(formattedDir, outputName);
27877
- writeFileSync38(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
28338
+ const formattedDir = join72(transcriptsDir, client);
28339
+ mkdirSync25(formattedDir, { recursive: true });
28340
+ const formattedPath = join72(formattedDir, outputName);
28341
+ writeFileSync41(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
27878
28342
  archiveRawVtt(vttDir, sourcePath, filename);
27879
- const summaryPath = join62(summaryDir, client, outputName);
28343
+ const summaryPath = join72(summaryDir, client, outputName);
27880
28344
  console.log(`Formatted transcript: ${formattedPath}`);
27881
28345
  console.log(`Summary target: ${summaryPath}`);
27882
28346
  }
@@ -27958,50 +28422,50 @@ function registerVerify(program2) {
27958
28422
 
27959
28423
  // src/commands/voice/devices.ts
27960
28424
  import { spawnSync as spawnSync6 } from "child_process";
27961
- import { join as join64 } from "path";
28425
+ import { join as join74 } from "path";
27962
28426
 
27963
28427
  // src/commands/voice/shared.ts
27964
- import { homedir as homedir22 } from "os";
27965
- import { dirname as dirname31, join as join63 } from "path";
27966
- import { fileURLToPath as fileURLToPath7 } from "url";
27967
- var __dirname5 = dirname31(fileURLToPath7(import.meta.url));
27968
- var VOICE_DIR = join63(homedir22(), ".assist", "voice");
28428
+ import { homedir as homedir23 } from "os";
28429
+ import { dirname as dirname34, join as join73 } from "path";
28430
+ import { fileURLToPath as fileURLToPath8 } from "url";
28431
+ var __dirname6 = dirname34(fileURLToPath8(import.meta.url));
28432
+ var VOICE_DIR = join73(homedir23(), ".assist", "voice");
27969
28433
  var voicePaths = {
27970
28434
  dir: VOICE_DIR,
27971
- pid: join63(VOICE_DIR, "voice.pid"),
27972
- log: join63(VOICE_DIR, "voice.log"),
27973
- venv: join63(VOICE_DIR, ".venv"),
27974
- lock: join63(VOICE_DIR, "voice.lock")
28435
+ pid: join73(VOICE_DIR, "voice.pid"),
28436
+ log: join73(VOICE_DIR, "voice.log"),
28437
+ venv: join73(VOICE_DIR, ".venv"),
28438
+ lock: join73(VOICE_DIR, "voice.lock")
27975
28439
  };
27976
28440
  function getPythonDir() {
27977
- return join63(__dirname5, "commands", "voice", "python");
28441
+ return join73(__dirname6, "commands", "voice", "python");
27978
28442
  }
27979
28443
  function getVenvPython() {
27980
- return process.platform === "win32" ? join63(voicePaths.venv, "Scripts", "python.exe") : join63(voicePaths.venv, "bin", "python");
28444
+ return process.platform === "win32" ? join73(voicePaths.venv, "Scripts", "python.exe") : join73(voicePaths.venv, "bin", "python");
27981
28445
  }
27982
28446
  function getLockDir() {
27983
28447
  const config = loadConfig();
27984
28448
  return config.voice?.lockDir ?? VOICE_DIR;
27985
28449
  }
27986
28450
  function getLockFile() {
27987
- return join63(getLockDir(), "voice.lock");
28451
+ return join73(getLockDir(), "voice.lock");
27988
28452
  }
27989
28453
 
27990
28454
  // src/commands/voice/devices.ts
27991
28455
  function devices() {
27992
- const script = join64(getPythonDir(), "list_devices.py");
28456
+ const script = join74(getPythonDir(), "list_devices.py");
27993
28457
  spawnSync6(getVenvPython(), [script], { stdio: "inherit" });
27994
28458
  }
27995
28459
 
27996
28460
  // src/commands/voice/logs.ts
27997
- import { existsSync as existsSync55, readFileSync as readFileSync44 } from "fs";
28461
+ import { existsSync as existsSync59, readFileSync as readFileSync48 } from "fs";
27998
28462
  function logs(options2) {
27999
- if (!existsSync55(voicePaths.log)) {
28463
+ if (!existsSync59(voicePaths.log)) {
28000
28464
  console.log("No voice log file found");
28001
28465
  return;
28002
28466
  }
28003
28467
  const count8 = Number.parseInt(options2.lines ?? "150", 10);
28004
- const content = readFileSync44(voicePaths.log, "utf8").trim();
28468
+ const content = readFileSync48(voicePaths.log, "utf8").trim();
28005
28469
  if (!content) {
28006
28470
  console.log("Voice log is empty");
28007
28471
  return;
@@ -28023,13 +28487,13 @@ function logs(options2) {
28023
28487
 
28024
28488
  // src/commands/voice/setup.ts
28025
28489
  import { spawnSync as spawnSync7 } from "child_process";
28026
- import { mkdirSync as mkdirSync22 } from "fs";
28027
- import { join as join66 } from "path";
28490
+ import { mkdirSync as mkdirSync27 } from "fs";
28491
+ import { join as join76 } from "path";
28028
28492
 
28029
28493
  // src/commands/voice/checkLockFile.ts
28030
28494
  import { execSync as execSync59 } from "child_process";
28031
- import { existsSync as existsSync56, mkdirSync as mkdirSync21, readFileSync as readFileSync45, writeFileSync as writeFileSync39 } from "fs";
28032
- import { join as join65 } from "path";
28495
+ import { existsSync as existsSync60, mkdirSync as mkdirSync26, readFileSync as readFileSync49, writeFileSync as writeFileSync42 } from "fs";
28496
+ import { join as join75 } from "path";
28033
28497
  function isProcessAlive2(pid) {
28034
28498
  try {
28035
28499
  process.kill(pid, 0);
@@ -28040,9 +28504,9 @@ function isProcessAlive2(pid) {
28040
28504
  }
28041
28505
  function checkLockFile() {
28042
28506
  const lockFile = getLockFile();
28043
- if (!existsSync56(lockFile)) return;
28507
+ if (!existsSync60(lockFile)) return;
28044
28508
  try {
28045
- const lock2 = JSON.parse(readFileSync45(lockFile, "utf8"));
28509
+ const lock2 = JSON.parse(readFileSync49(lockFile, "utf8"));
28046
28510
  if (lock2.pid && isProcessAlive2(lock2.pid)) {
28047
28511
  console.error(
28048
28512
  `Voice daemon already running (PID ${lock2.pid}, env: ${lock2.env}). Stop it first with: assist voice stop`
@@ -28053,7 +28517,7 @@ function checkLockFile() {
28053
28517
  }
28054
28518
  }
28055
28519
  function bootstrapVenv() {
28056
- if (existsSync56(getVenvPython())) return;
28520
+ if (existsSync60(getVenvPython())) return;
28057
28521
  console.log("Setting up Python environment...");
28058
28522
  const pythonDir = getPythonDir();
28059
28523
  execSync59(
@@ -28066,8 +28530,8 @@ function bootstrapVenv() {
28066
28530
  }
28067
28531
  function writeLockFile(pid) {
28068
28532
  const lockFile = getLockFile();
28069
- mkdirSync21(join65(lockFile, ".."), { recursive: true });
28070
- writeFileSync39(
28533
+ mkdirSync26(join75(lockFile, ".."), { recursive: true });
28534
+ writeFileSync42(
28071
28535
  lockFile,
28072
28536
  JSON.stringify({
28073
28537
  pid,
@@ -28079,10 +28543,10 @@ function writeLockFile(pid) {
28079
28543
 
28080
28544
  // src/commands/voice/setup.ts
28081
28545
  function setup() {
28082
- mkdirSync22(voicePaths.dir, { recursive: true });
28546
+ mkdirSync27(voicePaths.dir, { recursive: true });
28083
28547
  bootstrapVenv();
28084
28548
  console.log("\nDownloading models...\n");
28085
- const script = join66(getPythonDir(), "setup_models.py");
28549
+ const script = join76(getPythonDir(), "setup_models.py");
28086
28550
  const result = spawnSync7(getVenvPython(), [script], {
28087
28551
  stdio: "inherit",
28088
28552
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -28095,8 +28559,8 @@ function setup() {
28095
28559
 
28096
28560
  // src/commands/voice/start.ts
28097
28561
  import { spawn as spawn8 } from "child_process";
28098
- import { mkdirSync as mkdirSync23, writeFileSync as writeFileSync40 } from "fs";
28099
- import { join as join67 } from "path";
28562
+ import { mkdirSync as mkdirSync28, writeFileSync as writeFileSync43 } from "fs";
28563
+ import { join as join77 } from "path";
28100
28564
 
28101
28565
  // src/commands/voice/buildDaemonEnv.ts
28102
28566
  function buildDaemonEnv(options2) {
@@ -28124,17 +28588,17 @@ function spawnBackground(python, script, env) {
28124
28588
  console.error("Failed to start voice daemon");
28125
28589
  process.exit(1);
28126
28590
  }
28127
- writeFileSync40(voicePaths.pid, String(pid));
28591
+ writeFileSync43(voicePaths.pid, String(pid));
28128
28592
  writeLockFile(pid);
28129
28593
  console.log(`Voice daemon started (PID ${pid})`);
28130
28594
  }
28131
28595
  function start2(options2) {
28132
- mkdirSync23(voicePaths.dir, { recursive: true });
28596
+ mkdirSync28(voicePaths.dir, { recursive: true });
28133
28597
  checkLockFile();
28134
28598
  bootstrapVenv();
28135
28599
  const debug = options2.debug || options2.foreground || process.platform === "win32";
28136
28600
  const env = buildDaemonEnv({ debug });
28137
- const script = join67(getPythonDir(), "voice_daemon.py");
28601
+ const script = join77(getPythonDir(), "voice_daemon.py");
28138
28602
  const python = getVenvPython();
28139
28603
  if (options2.foreground) {
28140
28604
  spawnForeground(python, script, env);
@@ -28144,7 +28608,7 @@ function start2(options2) {
28144
28608
  }
28145
28609
 
28146
28610
  // src/commands/voice/status.ts
28147
- import { existsSync as existsSync57, readFileSync as readFileSync46 } from "fs";
28611
+ import { existsSync as existsSync61, readFileSync as readFileSync50 } from "fs";
28148
28612
  function isProcessAlive3(pid) {
28149
28613
  try {
28150
28614
  process.kill(pid, 0);
@@ -28154,16 +28618,16 @@ function isProcessAlive3(pid) {
28154
28618
  }
28155
28619
  }
28156
28620
  function readRecentLogs(count8) {
28157
- if (!existsSync57(voicePaths.log)) return [];
28158
- const lines2 = readFileSync46(voicePaths.log, "utf8").trim().split("\n");
28621
+ if (!existsSync61(voicePaths.log)) return [];
28622
+ const lines2 = readFileSync50(voicePaths.log, "utf8").trim().split("\n");
28159
28623
  return lines2.slice(-count8);
28160
28624
  }
28161
28625
  function status2() {
28162
- if (!existsSync57(voicePaths.pid)) {
28626
+ if (!existsSync61(voicePaths.pid)) {
28163
28627
  console.log("Voice daemon: not running (no PID file)");
28164
28628
  return;
28165
28629
  }
28166
- const pid = Number.parseInt(readFileSync46(voicePaths.pid, "utf8").trim(), 10);
28630
+ const pid = Number.parseInt(readFileSync50(voicePaths.pid, "utf8").trim(), 10);
28167
28631
  const alive = isProcessAlive3(pid);
28168
28632
  console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
28169
28633
  const recent = readRecentLogs(5);
@@ -28182,13 +28646,13 @@ function status2() {
28182
28646
  }
28183
28647
 
28184
28648
  // src/commands/voice/stop.ts
28185
- import { existsSync as existsSync58, readFileSync as readFileSync47, unlinkSync as unlinkSync20 } from "fs";
28649
+ import { existsSync as existsSync62, readFileSync as readFileSync51, unlinkSync as unlinkSync20 } from "fs";
28186
28650
  function stop2() {
28187
- if (!existsSync58(voicePaths.pid)) {
28651
+ if (!existsSync62(voicePaths.pid)) {
28188
28652
  console.log("Voice daemon is not running (no PID file)");
28189
28653
  return;
28190
28654
  }
28191
- const pid = Number.parseInt(readFileSync47(voicePaths.pid, "utf8").trim(), 10);
28655
+ const pid = Number.parseInt(readFileSync51(voicePaths.pid, "utf8").trim(), 10);
28192
28656
  try {
28193
28657
  process.kill(pid, "SIGTERM");
28194
28658
  console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
@@ -28201,7 +28665,7 @@ function stop2() {
28201
28665
  }
28202
28666
  try {
28203
28667
  const lockFile = getLockFile();
28204
- if (existsSync58(lockFile)) unlinkSync20(lockFile);
28668
+ if (existsSync62(lockFile)) unlinkSync20(lockFile);
28205
28669
  } catch {
28206
28670
  }
28207
28671
  console.log("Voice daemon stopped");
@@ -28220,7 +28684,7 @@ function registerVoice(program2) {
28220
28684
  }
28221
28685
 
28222
28686
  // src/commands/watch/readBuiltVersion.ts
28223
- import { join as join68 } from "path";
28687
+ import { join as join78 } from "path";
28224
28688
 
28225
28689
  // src/commands/watch/resolveUpstream.ts
28226
28690
  import { execFileSync as execFileSync10 } from "child_process";
@@ -28266,7 +28730,7 @@ function resolveUpstream(cwd) {
28266
28730
  function readBuiltVersion(cwd) {
28267
28731
  try {
28268
28732
  const root = runGit2(["rev-parse", "--show-toplevel"], cwd);
28269
- return readPackageJson(join68(root, "package.json")).version ?? "unknown";
28733
+ return readPackageJson(join78(root, "package.json")).version ?? "unknown";
28270
28734
  } catch {
28271
28735
  return "unknown";
28272
28736
  }
@@ -28318,11 +28782,11 @@ var webUiPrefix = "src/commands/sessions/web/ui/";
28318
28782
  var sessionsPrefix = "src/commands/sessions/";
28319
28783
  var rules = [
28320
28784
  {
28321
- matches: (path71) => path71.startsWith(webUiPrefix),
28785
+ matches: (path73) => path73.startsWith(webUiPrefix),
28322
28786
  advice: "restart the web server, then hard-reload the browser tab"
28323
28787
  },
28324
28788
  {
28325
- matches: (path71) => path71.startsWith(sessionsPrefix) && !path71.startsWith(webUiPrefix),
28789
+ matches: (path73) => path73.startsWith(sessionsPrefix) && !path73.startsWith(webUiPrefix),
28326
28790
  advice: "restart the daemon"
28327
28791
  }
28328
28792
  ];
@@ -28564,7 +29028,7 @@ function resolveParams(params, cliArgs) {
28564
29028
  }
28565
29029
 
28566
29030
  // src/commands/run/resolveRunCwd.ts
28567
- import { existsSync as existsSync59 } from "fs";
29031
+ import { existsSync as existsSync63 } from "fs";
28568
29032
  import { resolve as resolve17 } from "path";
28569
29033
  var MissingRunCwdError = class extends Error {
28570
29034
  constructor(runName, cwd) {
@@ -28577,25 +29041,25 @@ var MissingRunCwdError = class extends Error {
28577
29041
  function resolveRunCwd(config, baseDir = runConfigBaseDir()) {
28578
29042
  if (!config.cwd) return void 0;
28579
29043
  const cwd = resolve17(baseDir, config.cwd);
28580
- if (!existsSync59(cwd)) throw new MissingRunCwdError(config.name, cwd);
29044
+ if (!existsSync63(cwd)) throw new MissingRunCwdError(config.name, cwd);
28581
29045
  return cwd;
28582
29046
  }
28583
29047
 
28584
29048
  // src/commands/run/runCommandToCompletion.ts
28585
29049
  import { spawn as spawn9 } from "child_process";
28586
- import { existsSync as existsSync61 } from "fs";
29050
+ import { existsSync as existsSync65 } from "fs";
28587
29051
 
28588
29052
  // src/commands/run/resolveCommand.ts
28589
29053
  import { execFileSync as execFileSync11 } from "child_process";
28590
- import { existsSync as existsSync60 } from "fs";
28591
- import { dirname as dirname32, join as join69, resolve as resolve18 } from "path";
29054
+ import { existsSync as existsSync64 } from "fs";
29055
+ import { dirname as dirname35, join as join79, resolve as resolve18 } from "path";
28592
29056
  function resolveCommand2(command) {
28593
29057
  if (process.platform !== "win32" || command !== "bash") return command;
28594
29058
  try {
28595
29059
  const gitPath = execFileSync11("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
28596
- const gitRoot = resolve18(dirname32(gitPath), "..");
28597
- const gitBash = join69(gitRoot, "bin", "bash.exe");
28598
- if (existsSync60(gitBash)) return gitBash;
29060
+ const gitRoot = resolve18(dirname35(gitPath), "..");
29061
+ const gitBash = join79(gitRoot, "bin", "bash.exe");
29062
+ if (existsSync64(gitBash)) return gitBash;
28599
29063
  } catch {
28600
29064
  return command;
28601
29065
  }
@@ -28605,7 +29069,7 @@ function resolveCommand2(command) {
28605
29069
  // src/commands/run/runCommandToCompletion.ts
28606
29070
  function runCommandToCompletion(command, args, env, cwd, quiet) {
28607
29071
  return new Promise((resolveResult) => {
28608
- if (cwd && !existsSync61(cwd)) {
29072
+ if (cwd && !existsSync65(cwd)) {
28609
29073
  resolveResult({
28610
29074
  kind: "failed",
28611
29075
  message: `Failed to execute command: cwd ${cwd} does not exist`
@@ -28835,7 +29299,7 @@ function registerWatch(program2) {
28835
29299
 
28836
29300
  // src/commands/roam/auth.ts
28837
29301
  import { randomBytes } from "crypto";
28838
- import chalk210 from "chalk";
29302
+ import chalk212 from "chalk";
28839
29303
 
28840
29304
  // src/commands/roam/waitForCallback.ts
28841
29305
  import { createServer as createServer3 } from "http";
@@ -28966,13 +29430,13 @@ async function auth() {
28966
29430
  saveGlobalConfig(config);
28967
29431
  const state = randomBytes(16).toString("hex");
28968
29432
  console.log(
28969
- chalk210.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
29433
+ chalk212.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
28970
29434
  );
28971
- console.log(chalk210.white("http://localhost:14523/callback\n"));
28972
- console.log(chalk210.blue("Opening browser for authorization..."));
28973
- console.log(chalk210.dim("Waiting for authorization callback..."));
29435
+ console.log(chalk212.white("http://localhost:14523/callback\n"));
29436
+ console.log(chalk212.blue("Opening browser for authorization..."));
29437
+ console.log(chalk212.dim("Waiting for authorization callback..."));
28974
29438
  const { code, redirectUri } = await authorizeInBrowser(clientId, state);
28975
- console.log(chalk210.dim("Exchanging code for tokens..."));
29439
+ console.log(chalk212.dim("Exchanging code for tokens..."));
28976
29440
  const tokens = await exchangeToken({
28977
29441
  code,
28978
29442
  clientId,
@@ -28988,25 +29452,25 @@ async function auth() {
28988
29452
  };
28989
29453
  saveGlobalConfig(config);
28990
29454
  console.log(
28991
- chalk210.green("Roam credentials and tokens saved to ~/.assist.yml")
29455
+ chalk212.green("Roam credentials and tokens saved to ~/.assist.yml")
28992
29456
  );
28993
29457
  }
28994
29458
 
28995
29459
  // src/commands/roam/postRoamActivity.ts
28996
29460
  import { execFileSync as execFileSync13 } from "child_process";
28997
- import { readdirSync as readdirSync12, readFileSync as readFileSync48, statSync as statSync10 } from "fs";
28998
- import { join as join70 } from "path";
29461
+ import { readdirSync as readdirSync18, readFileSync as readFileSync52, statSync as statSync10 } from "fs";
29462
+ import { join as join80 } from "path";
28999
29463
  function findPortFile(roamDir) {
29000
29464
  let entries;
29001
29465
  try {
29002
- entries = readdirSync12(roamDir);
29466
+ entries = readdirSync18(roamDir);
29003
29467
  } catch {
29004
29468
  return void 0;
29005
29469
  }
29006
29470
  const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
29007
- const path71 = join70(roamDir, name);
29471
+ const path73 = join80(roamDir, name);
29008
29472
  try {
29009
- return { path: path71, mtimeMs: statSync10(path71).mtimeMs };
29473
+ return { path: path73, mtimeMs: statSync10(path73).mtimeMs };
29010
29474
  } catch {
29011
29475
  return void 0;
29012
29476
  }
@@ -29016,11 +29480,11 @@ function findPortFile(roamDir) {
29016
29480
  function postRoamActivity(app, event) {
29017
29481
  const appData = process.env.APPDATA;
29018
29482
  if (!appData) return;
29019
- const portFile = findPortFile(join70(appData, "Roam"));
29483
+ const portFile = findPortFile(join80(appData, "Roam"));
29020
29484
  if (!portFile) return;
29021
29485
  let port;
29022
29486
  try {
29023
- port = readFileSync48(portFile, "utf8").trim();
29487
+ port = readFileSync52(portFile, "utf8").trim();
29024
29488
  } catch {
29025
29489
  return;
29026
29490
  }
@@ -29148,8 +29612,8 @@ async function run3(name, args) {
29148
29612
  }
29149
29613
 
29150
29614
  // src/commands/run/add.ts
29151
- import { mkdirSync as mkdirSync24, writeFileSync as writeFileSync41 } from "fs";
29152
- import { join as join71 } from "path";
29615
+ import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync44 } from "fs";
29616
+ import { join as join81 } from "path";
29153
29617
 
29154
29618
  // src/commands/run/extractOption.ts
29155
29619
  function extractOption(args, flag) {
@@ -29210,16 +29674,16 @@ function saveNewRunConfig(name, command, args, cwd) {
29210
29674
  saveConfig(config);
29211
29675
  }
29212
29676
  function createCommandFile(name) {
29213
- const dir = join71(".claude", "commands");
29214
- mkdirSync24(dir, { recursive: true });
29677
+ const dir = join81(".claude", "commands");
29678
+ mkdirSync29(dir, { recursive: true });
29215
29679
  const content = `---
29216
29680
  description: Run ${name}
29217
29681
  ---
29218
29682
 
29219
29683
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
29220
29684
  `;
29221
- const filePath = join71(dir, `${name}.md`);
29222
- writeFileSync41(filePath, content);
29685
+ const filePath = join81(dir, `${name}.md`);
29686
+ writeFileSync44(filePath, content);
29223
29687
  console.log(`Created command file: ${filePath}`);
29224
29688
  }
29225
29689
  function add3() {
@@ -29242,11 +29706,11 @@ function findLinkIndex() {
29242
29706
  function parseLinkArgs() {
29243
29707
  const idx = findLinkIndex();
29244
29708
  if (idx === -1) return null;
29245
- const path71 = process.argv[idx + 1];
29709
+ const path73 = process.argv[idx + 1];
29246
29710
  const rest = process.argv.slice(idx + 2);
29247
29711
  const { value: prefix2 } = extractOption(rest, "--prefix");
29248
29712
  if (!prefix2) return null;
29249
- return { path: path71, prefix: prefix2 };
29713
+ return { path: path73, prefix: prefix2 };
29250
29714
  }
29251
29715
  function hasDuplicateLink(runList, linkPath) {
29252
29716
  return runList.some(
@@ -29274,8 +29738,8 @@ function link2() {
29274
29738
  }
29275
29739
 
29276
29740
  // src/commands/run/remove.ts
29277
- import { existsSync as existsSync62, unlinkSync as unlinkSync21 } from "fs";
29278
- import { join as join72 } from "path";
29741
+ import { existsSync as existsSync66, unlinkSync as unlinkSync21 } from "fs";
29742
+ import { join as join82 } from "path";
29279
29743
  function findRemoveIndex() {
29280
29744
  const idx = process.argv.indexOf("remove");
29281
29745
  if (idx === -1 || idx + 1 >= process.argv.length) return -1;
@@ -29290,8 +29754,8 @@ function parseRemoveName() {
29290
29754
  return process.argv[idx + 1];
29291
29755
  }
29292
29756
  function deleteCommandFile(name) {
29293
- const filePath = join72(".claude", "commands", `${name}.md`);
29294
- if (existsSync62(filePath)) {
29757
+ const filePath = join82(".claude", "commands", `${name}.md`);
29758
+ if (existsSync66(filePath)) {
29295
29759
  unlinkSync21(filePath);
29296
29760
  console.log(`Deleted command file: ${filePath}`);
29297
29761
  }
@@ -29336,10 +29800,10 @@ function registerRun(program2) {
29336
29800
 
29337
29801
  // src/commands/screenshot/index.ts
29338
29802
  import { execSync as execSync61 } from "child_process";
29339
- import { existsSync as existsSync63, mkdirSync as mkdirSync25, unlinkSync as unlinkSync22, writeFileSync as writeFileSync42 } from "fs";
29803
+ import { existsSync as existsSync67, mkdirSync as mkdirSync30, unlinkSync as unlinkSync22, writeFileSync as writeFileSync45 } from "fs";
29340
29804
  import { tmpdir as tmpdir8 } from "os";
29341
- import { join as join73, resolve as resolve19 } from "path";
29342
- import chalk211 from "chalk";
29805
+ import { join as join83, resolve as resolve19 } from "path";
29806
+ import chalk213 from "chalk";
29343
29807
 
29344
29808
  // src/commands/screenshot/captureWindowPs1.ts
29345
29809
  var captureWindowPs1 = `
@@ -29468,15 +29932,15 @@ Write-Output $OutputPath
29468
29932
 
29469
29933
  // src/commands/screenshot/index.ts
29470
29934
  function buildOutputPath(outputDir, processName) {
29471
- if (!existsSync63(outputDir)) {
29472
- mkdirSync25(outputDir, { recursive: true });
29935
+ if (!existsSync67(outputDir)) {
29936
+ mkdirSync30(outputDir, { recursive: true });
29473
29937
  }
29474
29938
  const timestamp6 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
29475
29939
  return resolve19(outputDir, `${processName}-${timestamp6}.png`);
29476
29940
  }
29477
29941
  function runPowerShellScript(processName, outputPath) {
29478
- const scriptPath = join73(tmpdir8(), `assist-screenshot-${Date.now()}.ps1`);
29479
- writeFileSync42(scriptPath, captureWindowPs1, "utf8");
29942
+ const scriptPath = join83(tmpdir8(), `assist-screenshot-${Date.now()}.ps1`);
29943
+ writeFileSync45(scriptPath, captureWindowPs1, "utf8");
29480
29944
  try {
29481
29945
  execSync61(
29482
29946
  `powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
@@ -29490,13 +29954,13 @@ function screenshot(processName) {
29490
29954
  const config = loadConfig();
29491
29955
  const outputDir = resolve19(config.screenshot.outputDir);
29492
29956
  const outputPath = buildOutputPath(outputDir, processName);
29493
- console.log(chalk211.gray(`Capturing window for process "${processName}" ...`));
29957
+ console.log(chalk213.gray(`Capturing window for process "${processName}" ...`));
29494
29958
  try {
29495
29959
  runPowerShellScript(processName, outputPath);
29496
- console.log(chalk211.green(`Screenshot saved: ${outputPath}`));
29960
+ console.log(chalk213.green(`Screenshot saved: ${outputPath}`));
29497
29961
  } catch (error) {
29498
29962
  const msg = error instanceof Error ? error.message : String(error);
29499
- console.error(chalk211.red(`Failed to capture screenshot: ${msg}`));
29963
+ console.error(chalk213.red(`Failed to capture screenshot: ${msg}`));
29500
29964
  process.exit(1);
29501
29965
  }
29502
29966
  }
@@ -29552,7 +30016,7 @@ function applyLine(result, pending, line) {
29552
30016
  }
29553
30017
 
29554
30018
  // src/commands/sessions/daemon/reportStolenSocket.ts
29555
- import { readFileSync as readFileSync49 } from "fs";
30019
+ import { readFileSync as readFileSync53 } from "fs";
29556
30020
  function reportStolenSocket(socketPid) {
29557
30021
  if (!socketPid) return;
29558
30022
  const filePid = readPidFile();
@@ -29564,7 +30028,7 @@ function reportStolenSocket(socketPid) {
29564
30028
  function readPidFile() {
29565
30029
  try {
29566
30030
  const pid = Number.parseInt(
29567
- readFileSync49(daemonPaths.pid, "utf8").trim(),
30031
+ readFileSync53(daemonPaths.pid, "utf8").trim(),
29568
30032
  10
29569
30033
  );
29570
30034
  return Number.isInteger(pid) ? pid : void 0;
@@ -29699,7 +30163,7 @@ function requestDrain(socket, lines2) {
29699
30163
  }
29700
30164
 
29701
30165
  // src/commands/sessions/daemon/runDaemon.ts
29702
- import { mkdirSync as mkdirSync29 } from "fs";
30166
+ import { mkdirSync as mkdirSync34 } from "fs";
29703
30167
 
29704
30168
  // src/commands/sessions/daemon/createAutoExit.ts
29705
30169
  var DEFAULT_GRACE_MS = 6e4;
@@ -29962,42 +30426,42 @@ function serverRunMeta(runName, cwd) {
29962
30426
  }
29963
30427
 
29964
30428
  // src/commands/sessions/daemon/readDesignSystemPrompt.ts
29965
- import * as fs35 from "fs";
29966
- import * as path58 from "path";
29967
- import { fileURLToPath as fileURLToPath8 } from "url";
29968
- var __filename4 = fileURLToPath8(import.meta.url);
29969
- var __dirname6 = path58.dirname(__filename4);
30429
+ import * as fs44 from "fs";
30430
+ import * as path69 from "path";
30431
+ import { fileURLToPath as fileURLToPath9 } from "url";
30432
+ var __filename5 = fileURLToPath9(import.meta.url);
30433
+ var __dirname7 = path69.dirname(__filename5);
29970
30434
  function readDesignSystemPrompt() {
29971
- const promptPath = path58.join(
29972
- __dirname6,
30435
+ const promptPath = path69.join(
30436
+ __dirname7,
29973
30437
  "..",
29974
30438
  "claude",
29975
30439
  "design-system-prompt.md"
29976
30440
  );
29977
- return fs35.readFileSync(promptPath, "utf8");
30441
+ return fs44.readFileSync(promptPath, "utf8");
29978
30442
  }
29979
30443
 
29980
30444
  // src/commands/sessions/daemon/spawnPty.ts
29981
- import { existsSync as existsSync65 } from "fs";
30445
+ import { existsSync as existsSync69 } from "fs";
29982
30446
  import * as pty from "node-pty";
29983
30447
 
29984
30448
  // src/commands/sessions/daemon/ensureSpawnHelperExecutable.ts
29985
- import { chmodSync, existsSync as existsSync64, statSync as statSync11 } from "fs";
30449
+ import { chmodSync, existsSync as existsSync68, statSync as statSync11 } from "fs";
29986
30450
  import { createRequire as createRequire3 } from "module";
29987
- import path59 from "path";
30451
+ import path70 from "path";
29988
30452
  var require4 = createRequire3(import.meta.url);
29989
30453
  var ensured = false;
29990
30454
  function ensureSpawnHelperExecutable() {
29991
30455
  if (ensured || process.platform !== "darwin") return;
29992
30456
  ensured = true;
29993
- const ptyRoot = path59.join(path59.dirname(require4.resolve("node-pty")), "..");
29994
- const helper = path59.join(
30457
+ const ptyRoot = path70.join(path70.dirname(require4.resolve("node-pty")), "..");
30458
+ const helper = path70.join(
29995
30459
  ptyRoot,
29996
30460
  "prebuilds",
29997
30461
  `${process.platform}-${process.arch}`,
29998
30462
  "spawn-helper"
29999
30463
  );
30000
- if (!existsSync64(helper)) return;
30464
+ if (!existsSync68(helper)) return;
30001
30465
  const mode = statSync11(helper).mode;
30002
30466
  if ((mode & 73) === 0) chmodSync(helper, mode | 493);
30003
30467
  }
@@ -30033,7 +30497,7 @@ function spawnPty(args, cwd, sessionId, extraEnv) {
30033
30497
  });
30034
30498
  }
30035
30499
  function refuseMissingCwd(cwd, sessionId) {
30036
- if (!cwd || existsSync65(cwd)) return;
30500
+ if (!cwd || existsSync69(cwd)) return;
30037
30501
  daemonLog(
30038
30502
  `${sessionId ? `session ${sessionId}` : "pty"} not spawned: working directory ${cwd} no longer exists`
30039
30503
  );
@@ -30164,17 +30628,17 @@ function setStatus2(session, newStatus) {
30164
30628
  }
30165
30629
 
30166
30630
  // src/commands/sessions/daemon/worktree/reapWorktree.ts
30167
- import { existsSync as existsSync67 } from "fs";
30168
- import { basename as basename18 } from "path";
30631
+ import { existsSync as existsSync71 } from "fs";
30632
+ import { basename as basename20 } from "path";
30169
30633
 
30170
30634
  // src/commands/sessions/daemon/worktree/deleteStrandedTree.ts
30171
- import { existsSync as existsSync66 } from "fs";
30172
- import { join as join76 } from "path";
30635
+ import { existsSync as existsSync70 } from "fs";
30636
+ import { join as join86 } from "path";
30173
30637
 
30174
30638
  // src/commands/sessions/daemon/worktree/deleteTreeDirectly.ts
30175
30639
  import { statSync as statSync12 } from "fs";
30176
30640
  import { rm as rm2 } from "fs/promises";
30177
- import { join as join75 } from "path";
30641
+ import { join as join85 } from "path";
30178
30642
  async function deleteTreeDirectly(clone, worktreePath, why) {
30179
30643
  if (holdsAGitDirectoryRatherThanALink(worktreePath)) {
30180
30644
  const refusal = "it is a clone of its own, not a linked worktree";
@@ -30202,7 +30666,7 @@ async function deleteTreeDirectly(clone, worktreePath, why) {
30202
30666
  return { removed: true };
30203
30667
  }
30204
30668
  function holdsAGitDirectoryRatherThanALink(worktreePath) {
30205
- return statSync12(join75(worktreePath, ".git"), {
30669
+ return statSync12(join85(worktreePath, ".git"), {
30206
30670
  throwIfNoEntry: false
30207
30671
  })?.isDirectory() === true;
30208
30672
  }
@@ -30238,7 +30702,7 @@ async function deleteStrandedTree(clone, worktreePath, cause) {
30238
30702
  );
30239
30703
  }
30240
30704
  function strandedReason(worktreePath, cause) {
30241
- if (!existsSync66(join76(worktreePath, ".git")))
30705
+ if (!existsSync70(join86(worktreePath, ".git")))
30242
30706
  return "its .git link is already gone";
30243
30707
  if (/not a working tree|not a git repository/i.test(reason2(cause)))
30244
30708
  return "git no longer recognises it as a working tree";
@@ -30290,7 +30754,7 @@ function reason3(error) {
30290
30754
 
30291
30755
  // src/commands/sessions/daemon/worktree/reapWorktree.ts
30292
30756
  async function reapWorktree(worktreePath, force = false) {
30293
- if (!existsSync67(worktreePath)) {
30757
+ if (!existsSync71(worktreePath)) {
30294
30758
  forgetWorktree(worktreePath);
30295
30759
  daemonLog(
30296
30760
  `worktree ${worktreePath} already gone; its record was forgotten`
@@ -30308,14 +30772,14 @@ async function reapWorktree(worktreePath, force = false) {
30308
30772
  const clone = owningClone(worktreePath);
30309
30773
  const removal = await removeTree(clone, worktreePath, force);
30310
30774
  if (!removal.removed) return removal;
30311
- await deleteWorktreeBranch(clone, basename18(worktreePath));
30775
+ await deleteWorktreeBranch(clone, basename20(worktreePath));
30312
30776
  forgetWorktree(worktreePath);
30313
30777
  daemonLog(`worktree ${worktreePath} reaped${force ? " (forced)" : ""}`);
30314
30778
  return removal;
30315
30779
  }
30316
30780
  function owningClone(worktreePath) {
30317
30781
  const recorded = worktreeAttributionIncludingReaped(worktreePath)?.clone;
30318
- if (recorded && existsSync67(recorded)) return recorded;
30782
+ if (recorded && existsSync71(recorded)) return recorded;
30319
30783
  const detected = mainWorktree(worktreePath);
30320
30784
  if (detected) return detected;
30321
30785
  daemonLog(
@@ -30443,12 +30907,12 @@ function closeGateApplies(sessions, session) {
30443
30907
  }
30444
30908
 
30445
30909
  // src/commands/sessions/daemon/worktree/watchGitState.ts
30446
- import { existsSync as existsSync68, watch } from "fs";
30910
+ import { existsSync as existsSync72, watch } from "fs";
30447
30911
  var DEBOUNCE_MS = 500;
30448
30912
  var POLL_MS = 3e4;
30449
30913
  function watchGitState(cwd, onChange) {
30450
30914
  const common = gitCommonDir(cwd);
30451
- if (!common || !existsSync68(common)) return void 0;
30915
+ if (!common || !existsSync72(common)) return void 0;
30452
30916
  const watchers = [
30453
30917
  watchGitDir(common, onChange),
30454
30918
  pollGitState(cwd, onChange)
@@ -30893,10 +31357,10 @@ function emitSessionOutput(session, clients, data) {
30893
31357
  }
30894
31358
 
30895
31359
  // src/commands/sessions/daemon/exitReason.ts
30896
- import { existsSync as existsSync69 } from "fs";
31360
+ import { existsSync as existsSync73 } from "fs";
30897
31361
  import { resolve as resolve20 } from "path";
30898
31362
  function exitDetail(session) {
30899
- if (session.cwd && !existsSync69(session.cwd))
31363
+ if (session.cwd && !existsSync73(session.cwd))
30900
31364
  return `working directory ${session.cwd} no longer exists`;
30901
31365
  return missingRunConfigCwd(session);
30902
31366
  }
@@ -30910,7 +31374,7 @@ function missingRunConfigCwd(session) {
30910
31374
  const config = resolveRunConfig(session.runName, dir);
30911
31375
  if (!config?.cwd) return void 0;
30912
31376
  const configured = resolve20(runConfigBaseDirFrom(dir), config.cwd);
30913
- if (existsSync69(configured)) return void 0;
31377
+ if (existsSync73(configured)) return void 0;
30914
31378
  return `run config "${config.name}": cwd ${configured} does not exist`;
30915
31379
  }
30916
31380
 
@@ -30927,8 +31391,16 @@ function handleFailedResume(session, exitCode, onStatusChange) {
30927
31391
  }
30928
31392
 
30929
31393
  // src/commands/sessions/daemon/watchActivity.ts
30930
- import { existsSync as existsSync70, mkdirSync as mkdirSync26, watch as watch2 } from "fs";
30931
- import { dirname as dirname34 } from "path";
31394
+ import { existsSync as existsSync74, mkdirSync as mkdirSync31, watch as watch2 } from "fs";
31395
+ import { dirname as dirname37 } from "path";
31396
+
31397
+ // src/commands/sessions/daemon/applyActivityToSession.ts
31398
+ function applyActivityToSession(session, activity2) {
31399
+ session.activity = activity2;
31400
+ if (activity2.harness) session.harness = activity2.harness;
31401
+ if (activity2.claudeSessionId)
31402
+ session.claudeSessionId = activity2.claudeSessionId;
31403
+ }
30932
31404
 
30933
31405
  // src/commands/sessions/daemon/applyReviewPause.ts
30934
31406
  function applyReviewPause(session, activity2) {
@@ -30981,10 +31453,10 @@ async function seedRunningMsFromUsage(session, notify2) {
30981
31453
  var DEBOUNCE_MS2 = 50;
30982
31454
  function watchActivity(session, notify2, onClaudeSessionId) {
30983
31455
  if (session.commandType !== "assist" || !session.cwd) return;
30984
- const path71 = activityPath(session.id);
30985
- const dir = dirname34(path71);
31456
+ const path73 = activityPath(session.id);
31457
+ const dir = dirname37(path73);
30986
31458
  try {
30987
- mkdirSync26(dir, { recursive: true });
31459
+ mkdirSync31(dir, { recursive: true });
30988
31460
  } catch {
30989
31461
  return;
30990
31462
  }
@@ -30992,31 +31464,26 @@ function watchActivity(session, notify2, onClaudeSessionId) {
30992
31464
  let timer = null;
30993
31465
  const read = () => {
30994
31466
  timer = null;
30995
- const activity2 = readActivity(path71);
31467
+ const activity2 = readActivity(path73);
30996
31468
  if (!activity2) return;
30997
- session.activity = activity2;
30998
- if (activity2.claudeSessionId) {
30999
- session.claudeSessionId = activity2.claudeSessionId;
31000
- onClaudeSessionId?.(session);
31001
- }
31469
+ applyActivityToSession(session, activity2);
31470
+ if (activity2.claudeSessionId) onClaudeSessionId?.(session);
31002
31471
  applyReviewPause(session, activity2);
31003
31472
  void seedRunningMsFromUsage(session, notify2);
31004
31473
  notify2();
31005
31474
  };
31006
31475
  session.activityWatcher = watch2(dir, (_event, filename) => {
31007
- if (filename && !path71.endsWith(filename)) return;
31476
+ if (filename && !path73.endsWith(filename)) return;
31008
31477
  if (timer) clearTimeout(timer);
31009
31478
  timer = setTimeout(read, DEBOUNCE_MS2);
31010
31479
  });
31011
- if (existsSync70(path71)) read();
31480
+ if (existsSync74(path73)) read();
31012
31481
  }
31013
31482
  function refreshActivity(session) {
31014
31483
  if (session.commandType !== "assist" || !session.cwd) return;
31015
31484
  const activity2 = readActivity(activityPath(session.id));
31016
31485
  if (!activity2) return;
31017
- session.activity = activity2;
31018
- if (activity2.claudeSessionId)
31019
- session.claudeSessionId = activity2.claudeSessionId;
31486
+ applyActivityToSession(session, activity2);
31020
31487
  }
31021
31488
 
31022
31489
  // src/commands/sessions/daemon/handleStoppedExit.ts
@@ -31097,56 +31564,56 @@ function reportSilentFailure(session, clients) {
31097
31564
  import { watch as watch3 } from "fs";
31098
31565
 
31099
31566
  // src/commands/sessions/shared/findTranscriptPathSync.ts
31100
- import * as fs36 from "fs";
31101
- import * as os4 from "os";
31102
- import * as path60 from "path";
31567
+ import * as fs45 from "fs";
31568
+ import * as os5 from "os";
31569
+ import * as path71 from "path";
31103
31570
  function projectDirForCwd(cwd) {
31104
- return path60.join(
31105
- os4.homedir(),
31571
+ return path71.join(
31572
+ os5.homedir(),
31106
31573
  ".claude",
31107
31574
  "projects",
31108
31575
  cwd.replace(/[^a-zA-Z0-9]/g, "-")
31109
31576
  );
31110
31577
  }
31111
31578
  function transcriptPathFor(cwd, claudeSessionId) {
31112
- return path60.join(projectDirForCwd(cwd), `${claudeSessionId}.jsonl`);
31579
+ return path71.join(projectDirForCwd(cwd), `${claudeSessionId}.jsonl`);
31113
31580
  }
31114
31581
  function findTranscriptPathSync(cwd, claudeSessionId) {
31115
31582
  const direct = transcriptPathFor(cwd, claudeSessionId);
31116
- if (fs36.existsSync(direct)) return direct;
31583
+ if (fs45.existsSync(direct)) return direct;
31117
31584
  const dir = projectDirForCwd(cwd);
31118
31585
  let files;
31119
31586
  try {
31120
- files = fs36.readdirSync(dir);
31587
+ files = fs45.readdirSync(dir);
31121
31588
  } catch {
31122
31589
  return null;
31123
31590
  }
31124
31591
  for (const file of files) {
31125
31592
  if (!file.endsWith(".jsonl")) continue;
31126
- if (headContainsSessionId(path60.join(dir, file), claudeSessionId))
31127
- return path60.join(dir, file);
31593
+ if (headContainsSessionId(path71.join(dir, file), claudeSessionId))
31594
+ return path71.join(dir, file);
31128
31595
  }
31129
31596
  return null;
31130
31597
  }
31131
31598
  function headContainsSessionId(filePath, claudeSessionId) {
31132
31599
  let fd;
31133
31600
  try {
31134
- fd = fs36.openSync(filePath, "r");
31601
+ fd = fs45.openSync(filePath, "r");
31135
31602
  const buf = Buffer.alloc(16384);
31136
- const bytesRead = fs36.readSync(fd, buf, 0, buf.length, 0);
31603
+ const bytesRead = fs45.readSync(fd, buf, 0, buf.length, 0);
31137
31604
  return buf.toString("utf8", 0, bytesRead).includes(claudeSessionId);
31138
31605
  } catch {
31139
31606
  return false;
31140
31607
  } finally {
31141
- if (fd !== void 0) fs36.closeSync(fd);
31608
+ if (fd !== void 0) fs45.closeSync(fd);
31142
31609
  }
31143
31610
  }
31144
31611
 
31145
31612
  // src/commands/sessions/daemon/ensureProjectDirExists.ts
31146
- import { mkdirSync as mkdirSync27 } from "fs";
31613
+ import { mkdirSync as mkdirSync32 } from "fs";
31147
31614
  function ensureProjectDirExists(dir, sessionId) {
31148
31615
  try {
31149
- mkdirSync27(dir, { recursive: true });
31616
+ mkdirSync32(dir, { recursive: true });
31150
31617
  return true;
31151
31618
  } catch (error) {
31152
31619
  daemonLog(
@@ -31253,7 +31720,7 @@ function resolvedToolUseIds(events, afterIdx) {
31253
31720
  }
31254
31721
 
31255
31722
  // src/commands/sessions/shared/readTranscriptTail.ts
31256
- import * as fs37 from "fs";
31723
+ import * as fs46 from "fs";
31257
31724
  var DEFAULT_MAX_BYTES = 256 * 1024;
31258
31725
  function parseTailEntries(raw) {
31259
31726
  const entries = [];
@@ -31277,7 +31744,7 @@ function dropPartialFirstLine(raw, sliced) {
31277
31744
  async function readTranscriptTail(filePath, maxBytes = DEFAULT_MAX_BYTES) {
31278
31745
  let handle;
31279
31746
  try {
31280
- handle = await fs37.promises.open(filePath, "r");
31747
+ handle = await fs46.promises.open(filePath, "r");
31281
31748
  const { size } = await handle.stat();
31282
31749
  const start3 = Math.max(0, size - maxBytes);
31283
31750
  const length = size - start3;
@@ -31296,20 +31763,20 @@ async function readTranscriptTail(filePath, maxBytes = DEFAULT_MAX_BYTES) {
31296
31763
  function readTranscriptTailSync(filePath, maxBytes = DEFAULT_MAX_BYTES) {
31297
31764
  let fd;
31298
31765
  try {
31299
- fd = fs37.openSync(filePath, "r");
31300
- const { size } = fs37.fstatSync(fd);
31766
+ fd = fs46.openSync(filePath, "r");
31767
+ const { size } = fs46.fstatSync(fd);
31301
31768
  const start3 = Math.max(0, size - maxBytes);
31302
31769
  const length = size - start3;
31303
31770
  if (length === 0) return [];
31304
31771
  const buf = Buffer.alloc(length);
31305
- fs37.readSync(fd, buf, 0, length, start3);
31772
+ fs46.readSync(fd, buf, 0, length, start3);
31306
31773
  return parseTailEntries(
31307
31774
  dropPartialFirstLine(buf.toString("utf8"), start3 > 0)
31308
31775
  );
31309
31776
  } catch {
31310
31777
  return [];
31311
31778
  } finally {
31312
- if (fd !== void 0) fs37.closeSync(fd);
31779
+ if (fd !== void 0) fs46.closeSync(fd);
31313
31780
  }
31314
31781
  }
31315
31782
 
@@ -31674,7 +32141,7 @@ async function recordWindowTokens(db, window, resetsAt, tokensUp, tokensDown) {
31674
32141
  }
31675
32142
 
31676
32143
  // src/commands/sessions/shared/transcriptUsage.ts
31677
- import * as fs38 from "fs";
32144
+ import * as fs47 from "fs";
31678
32145
  function transcriptUsage(lines2) {
31679
32146
  const byId = /* @__PURE__ */ new Map();
31680
32147
  for (const line of lines2) {
@@ -31698,7 +32165,7 @@ function transcriptUsage(lines2) {
31698
32165
  return [...byId.values()];
31699
32166
  }
31700
32167
  async function readTranscriptUsage(transcriptPath2) {
31701
- const content = await fs38.promises.readFile(transcriptPath2, "utf8");
32168
+ const content = await fs47.promises.readFile(transcriptPath2, "utf8");
31702
32169
  return transcriptUsage(content.split("\n"));
31703
32170
  }
31704
32171
 
@@ -31921,8 +32388,15 @@ function respawnSession(session, respawn, status3, clients, onStatusChange) {
31921
32388
  wirePtyEvents(session, clients, onStatusChange);
31922
32389
  }
31923
32390
 
31924
- // src/commands/sessions/daemon/respawnPlan.ts
31925
- import { randomUUID as randomUUID10 } from "crypto";
32391
+ // src/shared/harnessResumesConversation.ts
32392
+ var RESUMES_CONVERSATION = {
32393
+ claude: true,
32394
+ codex: false,
32395
+ pi: false
32396
+ };
32397
+ function harnessResumesConversation(harness) {
32398
+ return RESUMES_CONVERSATION[resolveHarness(harness)];
32399
+ }
31926
32400
 
31927
32401
  // src/commands/sessions/daemon/assistResumeArgs.ts
31928
32402
  function assistResumeArgs(session) {
@@ -31930,36 +32404,22 @@ function assistResumeArgs(session) {
31930
32404
  return session.claudeSessionId ? [...args, "--resume-session", session.claudeSessionId] : args;
31931
32405
  }
31932
32406
 
31933
- // src/commands/sessions/daemon/respawnPlan.ts
31934
- function respawnPlan(session) {
31935
- const { commandType, claudeSessionId, cwd, assistArgs, initialPrompt } = session;
31936
- if (commandType === "claude") {
31937
- if (claudeSessionId)
31938
- return {
31939
- spawn: () => spawnClaude2({
31940
- resumeSessionId: claudeSessionId,
31941
- cwd,
31942
- sessionId: session.id
31943
- }),
31944
- status: "waiting"
31945
- };
31946
- if (initialPrompt) return freshClaudePlan(session, initialPrompt, cwd);
31947
- if (cwd && session.harness !== "pi")
31948
- return freshClaudePlan(session, void 0, cwd);
31949
- return null;
31950
- }
31951
- if (commandType === "assist" && assistArgs) {
31952
- const idle = session.status === "waiting";
32407
+ // src/commands/sessions/daemon/interactiveRespawnPlan.ts
32408
+ import { randomUUID as randomUUID10 } from "crypto";
32409
+ function interactiveRespawnPlan(session, resumes) {
32410
+ const { claudeSessionId, cwd, initialPrompt } = session;
32411
+ if (!resumes) return null;
32412
+ if (claudeSessionId)
31953
32413
  return {
31954
- spawn: () => spawnPty(
31955
- assistResumeArgs({ assistArgs, claudeSessionId }),
32414
+ spawn: () => spawnClaude2({
32415
+ resumeSessionId: claudeSessionId,
31956
32416
  cwd,
31957
- session.id,
31958
- idle ? { ASSIST_RESUME_IDLE: "1" } : void 0
31959
- ),
31960
- status: idle ? "waiting" : "running"
32417
+ sessionId: session.id
32418
+ }),
32419
+ status: "waiting"
31961
32420
  };
31962
- }
32421
+ if (initialPrompt) return freshClaudePlan(session, initialPrompt, cwd);
32422
+ if (cwd) return freshClaudePlan(session, void 0, cwd);
31963
32423
  return null;
31964
32424
  }
31965
32425
  function freshClaudePlan(session, prompt, cwd) {
@@ -31978,6 +32438,29 @@ function freshClaudePlan(session, prompt, cwd) {
31978
32438
  };
31979
32439
  }
31980
32440
 
32441
+ // src/commands/sessions/daemon/respawnPlan.ts
32442
+ function respawnPlan(session) {
32443
+ const { commandType, claudeSessionId, cwd, assistArgs } = session;
32444
+ const resumes = harnessResumesConversation(session.harness);
32445
+ if (commandType === "claude") return interactiveRespawnPlan(session, resumes);
32446
+ if (commandType === "assist" && assistArgs) {
32447
+ const idle = session.status === "waiting";
32448
+ return {
32449
+ spawn: () => spawnPty(
32450
+ assistResumeArgs({
32451
+ assistArgs,
32452
+ claudeSessionId: resumes ? claudeSessionId : void 0
32453
+ }),
32454
+ cwd,
32455
+ session.id,
32456
+ idle ? { ASSIST_RESUME_IDLE: "1" } : void 0
32457
+ ),
32458
+ status: idle ? "waiting" : "running"
32459
+ };
32460
+ }
32461
+ return null;
32462
+ }
32463
+
31981
32464
  // src/commands/sessions/daemon/restartSession.ts
31982
32465
  function restartSession(session, clients, onStatusChange) {
31983
32466
  const plan2 = respawnPlan(session);
@@ -32187,7 +32670,7 @@ function restoredSession(base, persisted, pty2, status3) {
32187
32670
 
32188
32671
  // src/commands/sessions/daemon/restoreInteractiveSession.ts
32189
32672
  function restoreInteractiveSession(id, persisted, base, idle) {
32190
- if (persisted.commandType !== "run" && persisted.claudeSessionId) {
32673
+ if (persisted.commandType !== "run" && persisted.claudeSessionId && harnessResumesConversation(persisted.harness)) {
32191
32674
  return resumeViaClaude(id, persisted, base, idle);
32192
32675
  }
32193
32676
  if (persisted.commandType === "claude") {
@@ -32211,11 +32694,10 @@ function resumeViaClaude(id, persisted, base, idle) {
32211
32694
  return idle ? waitingSession(base, persisted, pty2) : runningSession(base, persisted, pty2);
32212
32695
  }
32213
32696
  function unrecoverableClaude(id, persisted) {
32214
- return errorSession(
32215
- id,
32216
- persisted,
32217
- "no claude session id was recorded before the daemon stopped, so the conversation cannot be resumed"
32218
- );
32697
+ return errorSession(id, persisted, unresumableReason(persisted.harness));
32698
+ }
32699
+ function unresumableReason(harness) {
32700
+ return harnessResumesConversation(harness) ? "no claude session id was recorded before the daemon stopped, so the conversation cannot be resumed" : `${harnessLabel(harness)} sessions cannot be resumed yet, so the conversation cannot be restored`;
32219
32701
  }
32220
32702
  function notRestoredStub(base, persisted) {
32221
32703
  return {
@@ -32365,8 +32847,8 @@ function rearmStoppedSessions(sessions, notify2) {
32365
32847
  }
32366
32848
 
32367
32849
  // src/commands/sessions/daemon/worktree/reconcileWorktreesOnRestore.ts
32368
- import { existsSync as existsSync73 } from "fs";
32369
- import { basename as basename20 } from "path";
32850
+ import { existsSync as existsSync77 } from "fs";
32851
+ import { basename as basename22 } from "path";
32370
32852
 
32371
32853
  // src/commands/sessions/daemon/worktree/accountedTrees.ts
32372
32854
  function accountedTrees(sessions) {
@@ -32421,21 +32903,21 @@ function bindResumedWorktree(session, cwd, notify2) {
32421
32903
 
32422
32904
  // src/commands/sessions/daemon/worktree/describeHeldWork.ts
32423
32905
  var MAX_ITEMS = 20;
32424
- async function describeHeldWork(path71, reason4) {
32425
- if (reason4.startsWith("uncommitted")) return await changedFiles(path71);
32426
- if (reason4.startsWith("unpushed")) return await unpushedCommits(path71, reason4);
32906
+ async function describeHeldWork(path73, reason4) {
32907
+ if (reason4.startsWith("uncommitted")) return await changedFiles(path73);
32908
+ if (reason4.startsWith("unpushed")) return await unpushedCommits(path73, reason4);
32427
32909
  return { summary: reason4, items: [] };
32428
32910
  }
32429
- async function changedFiles(path71) {
32430
- const status3 = await gitResult(path71, ["status", "--porcelain"]);
32911
+ async function changedFiles(path73) {
32912
+ const status3 = await gitResult(path73, ["status", "--porcelain"]);
32431
32913
  const lines2 = status3.ok ? nonEmptyLines(status3.out) : [];
32432
32914
  return {
32433
32915
  summary: `${lines2.length} uncommitted ${lines2.length === 1 ? "file" : "files"}`,
32434
32916
  items: capped(lines2)
32435
32917
  };
32436
32918
  }
32437
- async function unpushedCommits(path71, reason4) {
32438
- const log2 = await gitResult(path71, ["log", "--oneline", "@{upstream}..HEAD"]);
32919
+ async function unpushedCommits(path73, reason4) {
32920
+ const log2 = await gitResult(path73, ["log", "--oneline", "@{upstream}..HEAD"]);
32439
32921
  if (!log2.ok) return { summary: reason4, items: [] };
32440
32922
  const lines2 = nonEmptyLines(log2.out);
32441
32923
  return {
@@ -32455,18 +32937,18 @@ function capped(lines2) {
32455
32937
  }
32456
32938
 
32457
32939
  // src/commands/sessions/daemon/worktree/reclaimVanishedWorktrees.ts
32458
- import { existsSync as existsSync72 } from "fs";
32940
+ import { existsSync as existsSync76 } from "fs";
32459
32941
  async function reclaimVanishedWorktrees(clone, paths) {
32460
- if (!existsSync72(clone)) {
32461
- for (const { path: path71 } of paths) forgetWorktree(path71);
32942
+ if (!existsSync76(clone)) {
32943
+ for (const { path: path73 } of paths) forgetWorktree(path73);
32462
32944
  daemonLog(
32463
32945
  `clone ${clone} is gone; forgot ${paths.length} worktree record(s) it owned`
32464
32946
  );
32465
32947
  return;
32466
32948
  }
32467
32949
  await pruneBookkeeping2(clone);
32468
- for (const { path: path71, branch: branch2 } of paths)
32469
- if (await reclaimBranch(clone, branch2)) forgetWorktree(path71);
32950
+ for (const { path: path73, branch: branch2 } of paths)
32951
+ if (await reclaimBranch(clone, branch2)) forgetWorktree(path73);
32470
32952
  }
32471
32953
  async function pruneBookkeeping2(clone) {
32472
32954
  try {
@@ -32493,7 +32975,7 @@ async function reclaimBranch(clone, branch2) {
32493
32975
  }
32494
32976
 
32495
32977
  // src/commands/sessions/daemon/worktree/resurfaceOrphanedWorktree.ts
32496
- import { basename as basename19 } from "path";
32978
+ import { basename as basename21 } from "path";
32497
32979
  function resurfaceOrphanedWorktree(sessions, spawnWith, recovered, notify2) {
32498
32980
  const { orphan, reason: reason4, held } = recovered;
32499
32981
  let id;
@@ -32516,7 +32998,7 @@ function orphanedSession(id, recovered) {
32516
32998
  const { orphan, reason: reason4, held } = recovered;
32517
32999
  return {
32518
33000
  ...sessionBase(id, "stopped"),
32519
- name: `recovered ${basename19(orphan.path)}`,
33001
+ name: `recovered ${basename21(orphan.path)}`,
32520
33002
  subtitle: `${held.summary} in ${orphan.path}`,
32521
33003
  commandType: "claude",
32522
33004
  pty: null,
@@ -32541,17 +33023,17 @@ function recoveryNotice({ orphan, held }) {
32541
33023
  }
32542
33024
 
32543
33025
  // src/commands/sessions/daemon/worktree/logVanishedTree.ts
32544
- function logVanishedTree(sessions, path71) {
33026
+ function logVanishedTree(sessions, path73) {
32545
33027
  const claimants = [...sessions.values()].filter(
32546
- (s) => s.cwd === path71 || s.worktree?.path === path71
33028
+ (s) => s.cwd === path73 || s.worktree?.path === path73
32547
33029
  );
32548
33030
  if (claimants.length === 0) {
32549
- daemonLog(`worktree ${path71} gone from disk and unclaimed; reclaiming it`);
33031
+ daemonLog(`worktree ${path73} gone from disk and unclaimed; reclaiming it`);
32550
33032
  return;
32551
33033
  }
32552
33034
  for (const s of claimants)
32553
33035
  daemonLog(
32554
- `session ${s.id} ("${s.name}") claims worktree ${path71}, which is gone from disk; reclaiming it`
33036
+ `session ${s.id} ("${s.name}") claims worktree ${path73}, which is gone from disk; reclaiming it`
32555
33037
  );
32556
33038
  }
32557
33039
 
@@ -32563,17 +33045,17 @@ function reconcileWorktreesOnRestore(sessions, spawnWith, notify2) {
32563
33045
  async function recoverOrphanedWorktrees(sessions, spawnWith, notify2) {
32564
33046
  const accounted = accountedTrees(sessions);
32565
33047
  const vanished = /* @__PURE__ */ new Map();
32566
- for (const { path: path71, clone } of readWorktreeRegistry()) {
32567
- if (!existsSync73(path71)) {
32568
- logVanishedTree(sessions, path71);
33048
+ for (const { path: path73, clone } of readWorktreeRegistry()) {
33049
+ if (!existsSync77(path73)) {
33050
+ logVanishedTree(sessions, path73);
32569
33051
  vanished.set(clone, [
32570
33052
  ...vanished.get(clone) ?? [],
32571
- { path: path71, branch: basename20(path71) }
33053
+ { path: path73, branch: basename22(path73) }
32572
33054
  ]);
32573
33055
  continue;
32574
33056
  }
32575
- if (accounted.has(path71)) continue;
32576
- await recoverOrphan(sessions, spawnWith, { path: path71, clone }, notify2);
33057
+ if (accounted.has(path73)) continue;
33058
+ await recoverOrphan(sessions, spawnWith, { path: path73, clone }, notify2);
32577
33059
  }
32578
33060
  for (const [clone, paths] of vanished)
32579
33061
  await reclaimVanishedWorktrees(clone, paths);
@@ -33152,14 +33634,14 @@ async function defaultConnect() {
33152
33634
  }
33153
33635
 
33154
33636
  // src/commands/sessions/daemon/hasPersistedWindowsSessions.ts
33155
- import { existsSync as existsSync74, readFileSync as readFileSync51 } from "fs";
33637
+ import { existsSync as existsSync78, readFileSync as readFileSync55 } from "fs";
33156
33638
  import { posix } from "path";
33157
33639
  function hasPersistedWindowsSessions() {
33158
33640
  const sessionsFile = windowsSessionsFileFromWsl();
33159
33641
  if (!sessionsFile) return false;
33160
33642
  try {
33161
- if (!existsSync74(sessionsFile)) return false;
33162
- const data = JSON.parse(readFileSync51(sessionsFile, "utf8"));
33643
+ if (!existsSync78(sessionsFile)) return false;
33644
+ const data = JSON.parse(readFileSync55(sessionsFile, "utf8"));
33163
33645
  return Array.isArray(data) && data.length > 0;
33164
33646
  } catch (error) {
33165
33647
  const message3 = error instanceof Error ? error.message : String(error);
@@ -33737,7 +34219,7 @@ function addAgentToStream(ctx, targetId, prompt, harness) {
33737
34219
  }
33738
34220
 
33739
34221
  // src/commands/sessions/daemon/worktree/spawnInTree.ts
33740
- import { existsSync as existsSync77 } from "fs";
34222
+ import { existsSync as existsSync81 } from "fs";
33741
34223
 
33742
34224
  // src/commands/sessions/daemon/createAssistSession.ts
33743
34225
  function createAssistSession(id, assistArgs, cwd, meta, holdPty) {
@@ -33790,11 +34272,11 @@ function resumeSession(id, sessionId, cwd, name, holdPty) {
33790
34272
  }
33791
34273
 
33792
34274
  // src/commands/sessions/daemon/worktree/resumeInReplacementTree.ts
33793
- import { existsSync as existsSync76 } from "fs";
34275
+ import { existsSync as existsSync80 } from "fs";
33794
34276
 
33795
34277
  // src/commands/sessions/daemon/worktree/carryTranscriptToTree.ts
33796
- import { copyFileSync as copyFileSync2, existsSync as existsSync75, mkdirSync as mkdirSync28 } from "fs";
33797
- import { join as join78 } from "path";
34278
+ import { copyFileSync as copyFileSync7, existsSync as existsSync79, mkdirSync as mkdirSync33 } from "fs";
34279
+ import { join as join88 } from "path";
33798
34280
  function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
33799
34281
  const dir = projectDirForCwd(toCwd);
33800
34282
  if (dir === projectDirForCwd(fromCwd)) {
@@ -33803,8 +34285,8 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
33803
34285
  );
33804
34286
  return;
33805
34287
  }
33806
- const dest = join78(dir, `${claudeSessionId}.jsonl`);
33807
- if (existsSync75(dest)) {
34288
+ const dest = join88(dir, `${claudeSessionId}.jsonl`);
34289
+ if (existsSync79(dest)) {
33808
34290
  daemonLog(`transcript ${claudeSessionId} already present in ${dir}`);
33809
34291
  return;
33810
34292
  }
@@ -33816,8 +34298,8 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
33816
34298
  return;
33817
34299
  }
33818
34300
  try {
33819
- mkdirSync28(dir, { recursive: true });
33820
- copyFileSync2(source, dest);
34301
+ mkdirSync33(dir, { recursive: true });
34302
+ copyFileSync7(source, dest);
33821
34303
  daemonLog(
33822
34304
  `transcript ${source} copied to ${dest} so ${toCwd} can resume it`
33823
34305
  );
@@ -33848,7 +34330,7 @@ function resumeInReplacementTree(ctx, claudeSessionId, missingCwd, name) {
33848
34330
  }
33849
34331
  function cloneForReapedTree(missingCwd) {
33850
34332
  const clone = worktreeAttributionIncludingReaped(missingCwd)?.clone;
33851
- if (!clone || !existsSync76(clone))
34333
+ if (!clone || !existsSync80(clone))
33852
34334
  throw new Error(
33853
34335
  `working directory no longer exists and no clone is recorded to re-allocate from: ${missingCwd}`
33854
34336
  );
@@ -33880,7 +34362,7 @@ function spawnAssistInTree(ctx, assistArgs, cwd, meta) {
33880
34362
  return id;
33881
34363
  }
33882
34364
  function resumeInTree(ctx, sessionId, cwd, name) {
33883
- if (!existsSync77(cwd))
34365
+ if (!existsSync81(cwd))
33884
34366
  return resumeInReplacementTree(ctx, sessionId, cwd, name);
33885
34367
  const id = ctx.spawnWith((sid) => resumeSession(sid, sessionId, cwd, name));
33886
34368
  daemonLog(`session ${id} resuming ${sessionId} in ${cwd}`);
@@ -34172,12 +34654,12 @@ function handleSetStatus(client, m, d) {
34172
34654
  }
34173
34655
 
34174
34656
  // src/commands/sessions/shared/parseTranscript.ts
34175
- import * as fs39 from "fs";
34657
+ import * as fs48 from "fs";
34176
34658
  async function parseTranscript(sessionId) {
34177
34659
  const filePath = await findSessionJsonlPath(sessionId);
34178
34660
  if (!filePath) return [];
34179
34661
  try {
34180
- const raw = await fs39.promises.readFile(filePath, "utf8");
34662
+ const raw = await fs48.promises.readFile(filePath, "utf8");
34181
34663
  return parseTranscriptLines(raw.split("\n"));
34182
34664
  } catch {
34183
34665
  return [];
@@ -34201,9 +34683,9 @@ function safeParse2(line) {
34201
34683
  }
34202
34684
 
34203
34685
  // src/commands/sessions/daemon/repoDirExists.ts
34204
- import { existsSync as existsSync78 } from "fs";
34686
+ import { existsSync as existsSync82 } from "fs";
34205
34687
  function repoDirExists(cwd) {
34206
- return existsSync78(toGitCwd(cwd));
34688
+ return existsSync82(toGitCwd(cwd));
34207
34689
  }
34208
34690
 
34209
34691
  // src/commands/sessions/daemon/withRepoGroups.ts
@@ -34404,10 +34886,10 @@ function handleConnection(socket, manager) {
34404
34886
  }
34405
34887
 
34406
34888
  // src/commands/sessions/daemon/onListening.ts
34407
- import { unlinkSync as unlinkSync23, writeFileSync as writeFileSync43 } from "fs";
34889
+ import { unlinkSync as unlinkSync23, writeFileSync as writeFileSync46 } from "fs";
34408
34890
 
34409
34891
  // src/commands/sessions/daemon/startPidFileWatchdog.ts
34410
- import { readFileSync as readFileSync52 } from "fs";
34892
+ import { readFileSync as readFileSync56 } from "fs";
34411
34893
  var WATCHDOG_INTERVAL_MS = 5e3;
34412
34894
  function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
34413
34895
  const timer = setInterval(() => {
@@ -34418,7 +34900,7 @@ function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
34418
34900
  }
34419
34901
  function ownsPidFile() {
34420
34902
  try {
34421
- return readFileSync52(daemonPaths.pid, "utf8").trim() === String(process.pid);
34903
+ return readFileSync56(daemonPaths.pid, "utf8").trim() === String(process.pid);
34422
34904
  } catch {
34423
34905
  return false;
34424
34906
  }
@@ -34426,7 +34908,7 @@ function ownsPidFile() {
34426
34908
 
34427
34909
  // src/commands/sessions/daemon/onListening.ts
34428
34910
  function onListening(manager, checkAutoExit) {
34429
- writeFileSync43(daemonPaths.pid, String(process.pid));
34911
+ writeFileSync46(daemonPaths.pid, String(process.pid));
34430
34912
  startPidFileWatchdog(() => {
34431
34913
  daemonLog("lost daemon.pid ownership; shutting down sessions and exiting");
34432
34914
  void manager.flushActiveMs().finally(() => {
@@ -34508,7 +34990,7 @@ async function recoverFromAddrInUse(server, manager, checkAutoExit) {
34508
34990
 
34509
34991
  // src/commands/sessions/daemon/runDaemon.ts
34510
34992
  async function runDaemon() {
34511
- mkdirSync29(daemonPaths.dir, { recursive: true });
34993
+ mkdirSync34(daemonPaths.dir, { recursive: true });
34512
34994
  daemonLog(
34513
34995
  `starting (reason: ${process.env.ASSIST_DAEMON_SPAWN_REASON ?? "manual"})`
34514
34996
  );
@@ -34562,17 +35044,17 @@ function registerSetStatusCommand(cmd) {
34562
35044
  }
34563
35045
 
34564
35046
  // src/commands/sessions/summarise/index.ts
34565
- import * as fs41 from "fs";
34566
- import chalk212 from "chalk";
35047
+ import * as fs50 from "fs";
35048
+ import chalk214 from "chalk";
34567
35049
 
34568
35050
  // src/commands/sessions/summarise/shared.ts
34569
- import * as fs40 from "fs";
35051
+ import * as fs49 from "fs";
34570
35052
  function writeSummary(jsonlPath2, summary) {
34571
- fs40.writeFileSync(summaryPathFor(jsonlPath2), `${summary.trim()}
35053
+ fs49.writeFileSync(summaryPathFor(jsonlPath2), `${summary.trim()}
34572
35054
  `, "utf8");
34573
35055
  }
34574
35056
  function hasSummary(jsonlPath2) {
34575
- return fs40.existsSync(summaryPathFor(jsonlPath2));
35057
+ return fs49.existsSync(summaryPathFor(jsonlPath2));
34576
35058
  }
34577
35059
  function summaryPathFor(jsonlPath2) {
34578
35060
  return jsonlPath2.replace(/\.jsonl$/, ".summary");
@@ -34622,29 +35104,29 @@ ${firstMessage}`);
34622
35104
  async function summarise2(options2) {
34623
35105
  const files = await discoverSessionFiles();
34624
35106
  if (files.length === 0) {
34625
- console.log(chalk212.yellow("No sessions found."));
35107
+ console.log(chalk214.yellow("No sessions found."));
34626
35108
  return;
34627
35109
  }
34628
35110
  const toProcess = selectCandidates(files, options2);
34629
35111
  if (toProcess.length === 0) {
34630
- console.log(chalk212.green("All sessions already summarised."));
35112
+ console.log(chalk214.green("All sessions already summarised."));
34631
35113
  return;
34632
35114
  }
34633
35115
  console.log(
34634
- chalk212.cyan(
35116
+ chalk214.cyan(
34635
35117
  `Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
34636
35118
  )
34637
35119
  );
34638
35120
  const { succeeded, failed: failed2 } = processSessions(toProcess);
34639
35121
  console.log(
34640
- chalk212.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk212.yellow(`, ${failed2} skipped`) : "")
35122
+ chalk214.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk214.yellow(`, ${failed2} skipped`) : "")
34641
35123
  );
34642
35124
  }
34643
35125
  function selectCandidates(files, options2) {
34644
35126
  const candidates = options2.force ? files : files.filter((f) => !hasSummary(f));
34645
35127
  candidates.sort((a, b) => {
34646
35128
  try {
34647
- return fs41.statSync(b).mtimeMs - fs41.statSync(a).mtimeMs;
35129
+ return fs50.statSync(b).mtimeMs - fs50.statSync(a).mtimeMs;
34648
35130
  } catch {
34649
35131
  return 0;
34650
35132
  }
@@ -34657,16 +35139,16 @@ function processSessions(files) {
34657
35139
  let failed2 = 0;
34658
35140
  for (let i = 0; i < files.length; i++) {
34659
35141
  const file = files[i];
34660
- process.stdout.write(chalk212.dim(` [${i + 1}/${files.length}] `));
35142
+ process.stdout.write(chalk214.dim(` [${i + 1}/${files.length}] `));
34661
35143
  const summary = summariseSession(file);
34662
35144
  if (summary) {
34663
35145
  writeSummary(file, summary);
34664
35146
  succeeded++;
34665
- process.stdout.write(`${chalk212.green("\u2713")} ${summary}
35147
+ process.stdout.write(`${chalk214.green("\u2713")} ${summary}
34666
35148
  `);
34667
35149
  } else {
34668
35150
  failed2++;
34669
- process.stdout.write(` ${chalk212.yellow("skip")}
35151
+ process.stdout.write(` ${chalk214.yellow("skip")}
34670
35152
  `);
34671
35153
  }
34672
35154
  }
@@ -34687,7 +35169,7 @@ function registerSessions(program2) {
34687
35169
  }
34688
35170
 
34689
35171
  // src/commands/statusLine.ts
34690
- import chalk214 from "chalk";
35172
+ import chalk216 from "chalk";
34691
35173
 
34692
35174
  // src/shared/contextLevel.ts
34693
35175
  function contextLevel(pct) {
@@ -34697,7 +35179,7 @@ function contextLevel(pct) {
34697
35179
  }
34698
35180
 
34699
35181
  // src/commands/buildLimitsSegment.ts
34700
- import chalk213 from "chalk";
35182
+ import chalk215 from "chalk";
34701
35183
 
34702
35184
  // src/shared/rateLimitLevel.ts
34703
35185
  var FIVE_HOUR_SECONDS = 5 * 3600;
@@ -34733,9 +35215,9 @@ function rateLimitLevel(pct, resetsAt, windowSeconds, now) {
34733
35215
 
34734
35216
  // src/commands/buildLimitsSegment.ts
34735
35217
  var LEVEL_COLOR = {
34736
- ok: chalk213.green,
34737
- warn: chalk213.yellow,
34738
- over: chalk213.red
35218
+ ok: chalk215.green,
35219
+ warn: chalk215.yellow,
35220
+ over: chalk215.red
34739
35221
  };
34740
35222
  function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel, now) {
34741
35223
  const level = rateLimitLevel(pct, resetsAt, windowSeconds, now);
@@ -34766,10 +35248,10 @@ function buildLimitsSegment(rateLimits) {
34766
35248
  }
34767
35249
 
34768
35250
  // src/commands/readGitBranch.ts
34769
- import { readFileSync as readFileSync54, statSync as statSync14 } from "fs";
34770
- import { isAbsolute as isAbsolute4, join as join79, resolve as resolve21 } from "path";
35251
+ import { readFileSync as readFileSync58, statSync as statSync14 } from "fs";
35252
+ import { isAbsolute as isAbsolute4, join as join89, resolve as resolve21 } from "path";
34771
35253
  function resolveGitDir(cwd) {
34772
- const dotGit = join79(cwd, ".git");
35254
+ const dotGit = join89(cwd, ".git");
34773
35255
  let stat4;
34774
35256
  try {
34775
35257
  stat4 = statSync14(dotGit);
@@ -34781,7 +35263,7 @@ function resolveGitDir(cwd) {
34781
35263
  }
34782
35264
  let contents;
34783
35265
  try {
34784
- contents = readFileSync54(dotGit, "utf8");
35266
+ contents = readFileSync58(dotGit, "utf8");
34785
35267
  } catch {
34786
35268
  return null;
34787
35269
  }
@@ -34799,7 +35281,7 @@ function readGitBranch(cwd) {
34799
35281
  }
34800
35282
  let head;
34801
35283
  try {
34802
- head = readFileSync54(join79(gitDir, "HEAD"), "utf8");
35284
+ head = readFileSync58(join89(gitDir, "HEAD"), "utf8");
34803
35285
  } catch {
34804
35286
  return null;
34805
35287
  }
@@ -34831,7 +35313,7 @@ async function relayUsage(claudeSessionId, transcriptPath2, usedPct) {
34831
35313
  }
34832
35314
 
34833
35315
  // src/commands/statusLine.ts
34834
- chalk214.level = 3;
35316
+ chalk216.level = 3;
34835
35317
  function formatNumber(num) {
34836
35318
  return num.toLocaleString("en-US");
34837
35319
  }
@@ -34839,9 +35321,9 @@ function colorizePercent(pct) {
34839
35321
  const label2 = `${Math.round(pct)}%`;
34840
35322
  switch (contextLevel(pct)) {
34841
35323
  case "red":
34842
- return chalk214.red(label2);
35324
+ return chalk216.red(label2);
34843
35325
  case "yellow":
34844
- return chalk214.yellow(label2);
35326
+ return chalk216.yellow(label2);
34845
35327
  default:
34846
35328
  return label2;
34847
35329
  }
@@ -34854,7 +35336,7 @@ async function statusLine() {
34854
35336
  const usedPct = data.context_window.used_percentage ?? 0;
34855
35337
  const dir = data.workspace?.current_dir ?? data.cwd;
34856
35338
  const branch2 = dir ? readGitBranch(toGitCwd(dir)) : null;
34857
- const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${chalk214.cyan(branch2)} | ` : "";
35339
+ const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${chalk216.cyan(branch2)} | ` : "";
34858
35340
  console.log(
34859
35341
  `${branchSegment}${model} | Tokens - ${formatNumber(totalIn)} \u2191 : ${formatNumber(totalOut)} \u2193 | Context - ${colorizePercent(usedPct)}${buildLimitsSegment(data.rate_limits)}`
34860
35342
  );
@@ -34866,299 +35348,9 @@ async function statusLine() {
34866
35348
  );
34867
35349
  }
34868
35350
 
34869
- // src/commands/sync.ts
34870
- import * as fs48 from "fs";
34871
- import * as os5 from "os";
34872
- import * as path69 from "path";
34873
- import { fileURLToPath as fileURLToPath9 } from "url";
34874
-
34875
- // src/commands/sync/syncClaudeMd.ts
34876
- import * as fs42 from "fs";
34877
- import * as path61 from "path";
34878
- import chalk215 from "chalk";
34879
- async function syncClaudeMd(claudeDir, targetBase, options2) {
34880
- const source = path61.join(claudeDir, "CLAUDE.md");
34881
- const target = path61.join(targetBase, "CLAUDE.md");
34882
- const sourceContent = fs42.readFileSync(source, "utf8");
34883
- if (fs42.existsSync(target)) {
34884
- const targetContent = fs42.readFileSync(target, "utf8");
34885
- if (sourceContent !== targetContent) {
34886
- console.log(
34887
- chalk215.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
34888
- );
34889
- console.log();
34890
- printDiff(targetContent, sourceContent);
34891
- if (!options2?.yes) {
34892
- printAutoConfirmHint();
34893
- const confirm = await promptConfirm(
34894
- chalk215.red("Overwrite existing CLAUDE.md?"),
34895
- false
34896
- );
34897
- if (!confirm) {
34898
- console.log("Skipped CLAUDE.md");
34899
- return;
34900
- }
34901
- }
34902
- }
34903
- }
34904
- fs42.copyFileSync(source, target);
34905
- console.log("Copied CLAUDE.md to ~/.claude/CLAUDE.md");
34906
- }
34907
-
34908
- // src/commands/sync/syncCodex.ts
34909
- import * as path64 from "path";
34910
-
34911
- // src/commands/sync/installHarnessCommands.ts
34912
- import * as fs43 from "fs";
34913
- import * as path62 from "path";
34914
- function installHarnessCommands(claudeDir, harness, transform) {
34915
- const commandsSource = path62.join(claudeDir, "commands");
34916
- const files = fs43.readdirSync(commandsSource);
34917
- let synced = 0;
34918
- for (const file of files) {
34919
- if (!file.endsWith(".md")) continue;
34920
- const name = file.replace(/\.md$/, "");
34921
- const content = fs43.readFileSync(path62.join(commandsSource, file), "utf8");
34922
- const target = path62.join(harness.homeDir, harness.sync.commandDest(name));
34923
- fs43.mkdirSync(path62.dirname(target), { recursive: true });
34924
- fs43.writeFileSync(target, transform(name, content));
34925
- synced++;
34926
- }
34927
- const agentsTarget = path62.join(harness.homeDir, harness.sync.agentsFile);
34928
- fs43.mkdirSync(path62.dirname(agentsTarget), { recursive: true });
34929
- fs43.copyFileSync(path62.join(claudeDir, "CLAUDE.md"), agentsTarget);
34930
- return { total: files.length, synced };
34931
- }
34932
-
34933
- // src/commands/sync/syncCodexHooks.ts
34934
- import * as fs44 from "fs";
34935
- import * as path63 from "path";
34936
- var BEGIN = "# >>> assist codex hooks (managed) \u2014 do not edit >>>";
34937
- var END = "# <<< assist codex hooks (managed) <<<";
34938
- function upsertManagedBlock(existing, body) {
34939
- const block = `${BEGIN}
34940
- ${body.trim()}
34941
- ${END}`;
34942
- const begin = existing.indexOf(BEGIN);
34943
- if (begin === -1) {
34944
- const base = existing.replace(/\s*$/, "");
34945
- return base ? `${base}
34946
-
34947
- ${block}
34948
- ` : `${block}
34949
- `;
34950
- }
34951
- const endMarker = existing.indexOf(END, begin);
34952
- const after = endMarker === -1 ? existing.length : endMarker + END.length;
34953
- const before = existing.slice(0, begin).replace(/\s*$/, "");
34954
- const rest = existing.slice(after).replace(/^\s*/, "");
34955
- const head = before ? `${before}
34956
-
34957
- ${block}` : block;
34958
- return rest ? `${head}
34959
-
34960
- ${rest}
34961
- ` : `${head}
34962
- `;
34963
- }
34964
- function syncCodexHooks(sourcePath) {
34965
- const body = fs44.readFileSync(sourcePath, "utf8");
34966
- const configPath = path63.join(harnesses.codex.homeDir, "config.toml");
34967
- const existing = fs44.existsSync(configPath) ? fs44.readFileSync(configPath, "utf8") : "";
34968
- fs44.mkdirSync(path63.dirname(configPath), { recursive: true });
34969
- fs44.writeFileSync(configPath, upsertManagedBlock(existing, body));
34970
- console.log(
34971
- "Registered assist codex-hook in ~/.codex/config.toml (PreToolUse, PermissionRequest)"
34972
- );
34973
- }
34974
-
34975
- // src/commands/sync/syncCodex.ts
34976
- function quoteYaml(value) {
34977
- return `"${value.replace(/\\/g, String.raw`\\`).replace(/"/g, String.raw`\"`)}"`;
34978
- }
34979
- function commandToSkill(name, content) {
34980
- const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
34981
- const frontmatter = match ? match[1] : "";
34982
- const body = match ? content.slice(match[0].length) : content;
34983
- const descriptionMatch = frontmatter.match(/^description:\s*(.*)$/m);
34984
- const description = descriptionMatch ? descriptionMatch[1].trim().replace(/^["']|["']$/g, "") : name;
34985
- const header = `---
34986
- name: ${name}
34987
- description: ${quoteYaml(description)}
34988
- ---
34989
-
34990
- `;
34991
- return header + body.replace(/^\r?\n+/, "");
34992
- }
34993
- function syncCodex(claudeDir) {
34994
- if (!isHarnessAvailable("codex")) return;
34995
- const { total } = installHarnessCommands(
34996
- claudeDir,
34997
- harnesses.codex,
34998
- commandToSkill
34999
- );
35000
- syncCodexHooks(path64.join(claudeDir, "..", "codex", "config.toml"));
35001
- console.log(
35002
- `Synced ${total} skill(s) to ~/.codex/skills and CLAUDE.md to ~/.codex/AGENTS.md`
35003
- );
35004
- }
35005
-
35006
- // src/commands/sync/syncDesign.ts
35007
- import * as fs45 from "fs";
35008
- import * as path65 from "path";
35009
- function syncDesign(claudeDir, targetBase) {
35010
- const systemPromptSource = path65.join(claudeDir, "design-system-prompt.md");
35011
- const systemPromptTarget = path65.join(targetBase, "design-system-prompt.md");
35012
- fs45.copyFileSync(systemPromptSource, systemPromptTarget);
35013
- console.log(
35014
- "Copied design-system-prompt.md to ~/.claude/design-system-prompt.md"
35015
- );
35016
- const skillsSource = path65.join(claudeDir, "skills");
35017
- const skillsTarget = path65.join(targetBase, "skills");
35018
- fs45.mkdirSync(skillsTarget, { recursive: true });
35019
- const files = fs45.readdirSync(skillsSource);
35020
- for (const file of files) {
35021
- fs45.copyFileSync(
35022
- path65.join(skillsSource, file),
35023
- path65.join(skillsTarget, file)
35024
- );
35025
- }
35026
- console.log(`Synced ${files.length} design skill(s) to ~/.claude/skills`);
35027
- }
35028
-
35029
- // src/commands/sync/syncPi.ts
35030
- import * as path67 from "path";
35031
-
35032
- // src/commands/sync/syncPiHooks.ts
35033
- import * as fs46 from "fs";
35034
- import * as path66 from "path";
35035
- function piExtensionsDir() {
35036
- return path66.join(harnesses.pi.homeDir, "extensions");
35037
- }
35038
- function syncPiHooks(sourceDir) {
35039
- const target = piExtensionsDir();
35040
- fs46.mkdirSync(target, { recursive: true });
35041
- const files = fs46.readdirSync(sourceDir).filter((f) => f.endsWith(".ts"));
35042
- for (const file of files) {
35043
- fs46.copyFileSync(
35044
- path66.join(sourceDir, file),
35045
- path66.join(target, `assist-${file}`)
35046
- );
35047
- }
35048
- console.log(
35049
- `Registered ${files.length} assist extension(s) in ~/.pi/agent/extensions`
35050
- );
35051
- }
35052
-
35053
- // src/commands/sync/syncPi.ts
35054
- function unquote(value) {
35055
- return value.trim().replace(/^["']|["']$/g, "");
35056
- }
35057
- function commandToPrompt(name, content) {
35058
- const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
35059
- const frontmatter = match ? match[1] : "";
35060
- const body = match ? content.slice(match[0].length) : content;
35061
- const descriptionMatch = frontmatter.match(/^description:\s*(.*)$/m);
35062
- const description = descriptionMatch ? unquote(descriptionMatch[1]) : name;
35063
- const argsMatch = frontmatter.match(/^allowed_args:\s*(.*)$/m);
35064
- const argumentHint = argsMatch ? unquote(argsMatch[1]) : void 0;
35065
- const header = [
35066
- "---",
35067
- `description: ${description}`,
35068
- ...argumentHint ? [`argument-hint: ${argumentHint}`] : [],
35069
- "---",
35070
- "",
35071
- ""
35072
- ].join("\n");
35073
- return header + body.replace(/^\r?\n+/, "");
35074
- }
35075
- function syncPi(claudeDir) {
35076
- if (!isHarnessAvailable("pi")) return;
35077
- const { synced } = installHarnessCommands(
35078
- claudeDir,
35079
- harnesses.pi,
35080
- commandToPrompt
35081
- );
35082
- syncPiHooks(path67.join(claudeDir, "..", "pi"));
35083
- console.log(
35084
- `Synced ${synced} prompt(s) to ~/.pi/agent/prompts and CLAUDE.md to ~/.pi/agent/AGENTS.md`
35085
- );
35086
- }
35087
-
35088
- // src/commands/sync/syncSettings.ts
35089
- import * as fs47 from "fs";
35090
- import * as path68 from "path";
35091
- import chalk216 from "chalk";
35092
- async function syncSettings(claudeDir, targetBase, options2) {
35093
- const source = path68.join(claudeDir, "settings.json");
35094
- const target = path68.join(targetBase, "settings.json");
35095
- const sourceContent = fs47.readFileSync(source, "utf8");
35096
- const sourceSettings = JSON.parse(sourceContent);
35097
- const targetExists = fs47.existsSync(target);
35098
- const targetContent = targetExists ? fs47.readFileSync(target, "utf8") : "";
35099
- const preservedUserSettings = targetExists ? JSON.parse(targetContent) : {};
35100
- const mergedContent = JSON.stringify(
35101
- { ...preservedUserSettings, ...sourceSettings },
35102
- null,
35103
- " "
35104
- );
35105
- if (targetExists) {
35106
- const normalizedTarget = JSON.stringify(preservedUserSettings, null, " ");
35107
- if (mergedContent !== normalizedTarget) {
35108
- if (!options2?.yes) {
35109
- console.log(
35110
- chalk216.yellow(
35111
- "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
35112
- )
35113
- );
35114
- console.log();
35115
- printDiff(targetContent, mergedContent);
35116
- printAutoConfirmHint();
35117
- const confirm = await promptConfirm(
35118
- chalk216.red("Overwrite existing settings.json?"),
35119
- false
35120
- );
35121
- if (!confirm) {
35122
- console.log("Skipped settings.json");
35123
- return;
35124
- }
35125
- }
35126
- }
35127
- }
35128
- fs47.writeFileSync(target, mergedContent);
35129
- console.log("Copied settings.json to ~/.claude/settings.json");
35130
- }
35131
-
35132
- // src/commands/sync.ts
35133
- var __filename5 = fileURLToPath9(import.meta.url);
35134
- var __dirname7 = path69.dirname(__filename5);
35135
- async function sync(options2) {
35136
- const config = loadConfig();
35137
- const yes = options2?.yes ?? config.sync.autoConfirm;
35138
- const claudeDir = path69.join(__dirname7, "..", "claude");
35139
- const targetBase = path69.join(os5.homedir(), ".claude");
35140
- syncCommands(claudeDir, targetBase);
35141
- syncDesign(claudeDir, targetBase);
35142
- await syncSettings(claudeDir, targetBase, { yes });
35143
- await syncClaudeMd(claudeDir, targetBase, { yes });
35144
- syncCodex(claudeDir);
35145
- syncPi(claudeDir);
35146
- }
35147
- function syncCommands(claudeDir, targetBase) {
35148
- const sourceDir = path69.join(claudeDir, "commands");
35149
- const targetDir = path69.join(targetBase, "commands");
35150
- fs48.mkdirSync(targetDir, { recursive: true });
35151
- const files = fs48.readdirSync(sourceDir);
35152
- for (const file of files) {
35153
- fs48.copyFileSync(path69.join(sourceDir, file), path69.join(targetDir, file));
35154
- console.log(`Copied ${file} to ${targetDir}`);
35155
- }
35156
- console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
35157
- }
35158
-
35159
35351
  // src/commands/update.ts
35160
35352
  import { execSync as execSync62 } from "child_process";
35161
- import * as path70 from "path";
35353
+ import * as path72 from "path";
35162
35354
 
35163
35355
  // src/commands/restartDaemonAfterUpdate.ts
35164
35356
  async function restartDaemonAfterUpdate() {
@@ -35177,12 +35369,12 @@ async function restartDaemonAfterUpdate() {
35177
35369
  // src/commands/update.ts
35178
35370
  function isGlobalNpmInstall(dir) {
35179
35371
  try {
35180
- const resolved = path70.resolve(dir);
35181
- if (resolved.split(path70.sep).includes("node_modules")) {
35372
+ const resolved = path72.resolve(dir);
35373
+ if (resolved.split(path72.sep).includes("node_modules")) {
35182
35374
  return true;
35183
35375
  }
35184
35376
  const globalPrefix = execSync62("npm prefix -g", { stdio: "pipe" }).toString().trim();
35185
- return resolved.toLowerCase().startsWith(path70.resolve(globalPrefix).toLowerCase());
35377
+ return resolved.toLowerCase().startsWith(path72.resolve(globalPrefix).toLowerCase());
35186
35378
  } catch {
35187
35379
  return false;
35188
35380
  }
@@ -35227,10 +35419,7 @@ function reportCliError(error) {
35227
35419
  // src/index.ts
35228
35420
  var program = new Command();
35229
35421
  program.name("assist").description("CLI application").version(package_default.version).option("--no-open", "Do not open a browser on startup").action((options2) => web({ port: "3100", open: options2.open }));
35230
- var syncCommand = program.command("sync").description(
35231
- "Copy command files to ~/.claude/commands; when codex is detected, also install commands as ~/.codex/skills/<name>/SKILL.md, CLAUDE.md as ~/.codex/AGENTS.md, and register the assist codex-hook auto-approval hook in ~/.codex/config.toml; when pi is detected, also install commands as ~/.pi/agent/prompts/<name>.md, CLAUDE.md as ~/.pi/agent/AGENTS.md, and register the assist pi-hook permission-gate extension in ~/.pi/agent/extensions"
35232
- ).option("-y, --yes", "Overwrite settings.json without prompting").action((options2) => sync(options2));
35233
- configHelp(syncCommand, rootConfigHelp.sync);
35422
+ registerSync(program);
35234
35423
  program.command("init").description("Initialize VS Code and verify configurations").action(init5);
35235
35424
  var commitCommand = program.command("commit").description("Create a git commit with validation").argument("<args...>", "status | <message> [files...]").action(commit);
35236
35425
  configHelp(commitCommand, rootConfigHelp.commit);