@staff0rd/assist 0.481.0 → 0.482.1

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.481.0",
9
+ version: "0.482.1",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -6665,10 +6665,10 @@ async function prepareRun(id, resumeSessionId) {
6665
6665
  import chalk39 from "chalk";
6666
6666
  function reportDuplicateRun(itemId2, holder) {
6667
6667
  const since = holder.timestamp ? `, started ${holder.timestamp}` : "";
6668
- const reason2 = `another session is already running it (pid ${holder.pid}${since}); close that session before running it again`;
6668
+ const reason4 = `another session is already running it (pid ${holder.pid}${since}); close that session before running it again`;
6669
6669
  console.log(chalk39.yellow(`Already running: ${formatItemId(itemId2)}`));
6670
- console.log(chalk39.dim(`Refusing to start a second run \u2014 ${reason2}.`));
6671
- appendDaemonLog(`backlog run ${itemId2}: refused \u2014 ${reason2}`);
6670
+ console.log(chalk39.dim(`Refusing to start a second run \u2014 ${reason4}.`));
6671
+ appendDaemonLog(`backlog run ${itemId2}: refused \u2014 ${reason4}`);
6672
6672
  }
6673
6673
 
6674
6674
  // src/commands/backlog/consumePause.ts
@@ -8332,11 +8332,11 @@ import {
8332
8332
  var SPAWN_TIMEOUT_MS = 1e4;
8333
8333
  var RETRY_DELAY_MS2 = 200;
8334
8334
  var STALE_LOCK_MS = SPAWN_TIMEOUT_MS + 5e3;
8335
- async function ensureDaemonRunning(reason2 = "unspecified") {
8335
+ async function ensureDaemonRunning(reason4 = "unspecified") {
8336
8336
  if (await isDaemonRunning()) return;
8337
8337
  mkdirSync10(daemonPaths.dir, { recursive: true });
8338
8338
  const holdsLock = acquireSpawnLock();
8339
- if (holdsLock) spawnDaemon(reason2);
8339
+ if (holdsLock) spawnDaemon(reason4);
8340
8340
  try {
8341
8341
  await waitForDaemon();
8342
8342
  } finally {
@@ -8385,12 +8385,12 @@ function releaseSpawnLock() {
8385
8385
  } catch {
8386
8386
  }
8387
8387
  }
8388
- function spawnDaemon(reason2) {
8388
+ function spawnDaemon(reason4) {
8389
8389
  const log = openSync2(daemonPaths.log, "a");
8390
8390
  const child = spawn4(process.execPath, [process.argv[1], "daemon", "run"], {
8391
8391
  detached: true,
8392
8392
  stdio: ["ignore", log, log],
8393
- env: { ...process.env, ASSIST_DAEMON_SPAWN_REASON: reason2 }
8393
+ env: { ...process.env, ASSIST_DAEMON_SPAWN_REASON: reason4 }
8394
8394
  });
8395
8395
  child.unref();
8396
8396
  }
@@ -8971,7 +8971,7 @@ async function patchSubtaskStatus(req, res, id, idx) {
8971
8971
  }
8972
8972
 
8973
8973
  // src/commands/backlog/rewindItemToPhase.ts
8974
- async function rewindItemToPhase(orm, item, phaseNumber, reason2) {
8974
+ async function rewindItemToPhase(orm, item, phaseNumber, reason4) {
8975
8975
  const plan2 = resolveRewindPlan(item);
8976
8976
  if (phaseNumber < 1 || phaseNumber > plan2.length) {
8977
8977
  return {
@@ -8990,7 +8990,7 @@ async function rewindItemToPhase(orm, item, phaseNumber, reason2) {
8990
8990
  await appendComment(
8991
8991
  orm,
8992
8992
  item.id,
8993
- `Rewound to phase ${phaseNumber} (${phaseName}): ${reason2}`,
8993
+ `Rewound to phase ${phaseNumber} (${phaseName}): ${reason4}`,
8994
8994
  { phase: phaseNumber }
8995
8995
  );
8996
8996
  await updateCurrentPhase(orm, item.id, phaseNumber);
@@ -9001,11 +9001,11 @@ async function rewindItemToPhase(orm, item, phaseNumber, reason2) {
9001
9001
 
9002
9002
  // src/commands/backlog/web/rewindItemPhase.ts
9003
9003
  async function rewindItemPhase(req, res, id) {
9004
- const { phase, reason: reason2 } = await parseRewindBody(req);
9004
+ const { phase, reason: reason4 } = await parseRewindBody(req);
9005
9005
  const result = await findItemOr404(res, id);
9006
9006
  if (!result) return;
9007
9007
  const { orm, item } = result;
9008
- const outcome = await rewindItemToPhase(orm, item, phase, reason2);
9008
+ const outcome = await rewindItemToPhase(orm, item, phase, reason4);
9009
9009
  if (!outcome.ok) {
9010
9010
  respondJson(res, 400, { error: outcome.error });
9011
9011
  return;
@@ -11750,8 +11750,8 @@ function countCopyRows(data) {
11750
11750
 
11751
11751
  // src/commands/backlog/dump/parseDump.ts
11752
11752
  var NEWLINE = 10;
11753
- function invalid(reason2) {
11754
- throw new Error(`Invalid dump: ${reason2}`);
11753
+ function invalid(reason4) {
11754
+ throw new Error(`Invalid dump: ${reason4}`);
11755
11755
  }
11756
11756
  function readLine(dump, start3) {
11757
11757
  const eol = dump.indexOf(NEWLINE, start3);
@@ -13123,14 +13123,14 @@ async function unstar(id) {
13123
13123
 
13124
13124
  // src/commands/backlog/wontdo/index.ts
13125
13125
  import chalk98 from "chalk";
13126
- async function wontdo(id, reason2) {
13126
+ async function wontdo(id, reason4) {
13127
13127
  const found = await findOneItem(id);
13128
13128
  if (!found) return;
13129
13129
  const { orm, item } = found;
13130
13130
  await updateStatus(orm, item.id, "wontdo");
13131
- if (reason2) {
13131
+ if (reason4) {
13132
13132
  const phase = item.currentPhase ?? 1;
13133
- await appendComment(orm, item.id, reason2, { phase, type: "summary" });
13133
+ await appendComment(orm, item.id, reason4, { phase, type: "summary" });
13134
13134
  }
13135
13135
  console.log(
13136
13136
  chalk98.red(`Won't do item ${formatItemId(item.id)}: ${item.name}`)
@@ -14697,9 +14697,9 @@ function resolvePermission(toolName, parts) {
14697
14697
  if (denied) return denied;
14698
14698
  const reasons = [];
14699
14699
  for (const part of parts) {
14700
- const reason2 = isApprovedRead(part, toolName);
14701
- if (!reason2) return void 0;
14702
- reasons.push(reason2);
14700
+ const reason4 = isApprovedRead(part, toolName);
14701
+ if (!reason4) return void 0;
14702
+ reasons.push(reason4);
14703
14703
  }
14704
14704
  return {
14705
14705
  permissionDecision: "allow",
@@ -14823,13 +14823,13 @@ function cliHookCheck(command, toolName = "Bash") {
14823
14823
  if (reportDeny(toolName, parts)) return;
14824
14824
  const reasons = [];
14825
14825
  for (const part of parts) {
14826
- const reason2 = isApprovedRead(part, toolName);
14827
- if (!reason2) {
14826
+ const reason4 = isApprovedRead(part, toolName);
14827
+ if (!reason4) {
14828
14828
  console.log(`not approved (unrecognised: ${part})`);
14829
14829
  process.exitCode = 1;
14830
14830
  return;
14831
14831
  }
14832
- reasons.push(` ${part} -> ${reason2}`);
14832
+ reasons.push(` ${part} -> ${reason4}`);
14833
14833
  }
14834
14834
  console.log(`approved
14835
14835
  ${reasons.join("\n")}`);
@@ -17888,14 +17888,14 @@ async function editHook() {
17888
17888
  const input = tryParseInput2(await readStdin());
17889
17889
  if (!input) return;
17890
17890
  const existing = input.tool_name === "Write" ? readExisting(input.tool_input.file_path) : void 0;
17891
- const reason2 = decideOverrideGuard(input, existing) ?? decideCommentGuard(input, existing) ?? decideMigrationGuard(input, existing);
17892
- if (!reason2) return;
17891
+ const reason4 = decideOverrideGuard(input, existing) ?? decideCommentGuard(input, existing) ?? decideMigrationGuard(input, existing);
17892
+ if (!reason4) return;
17893
17893
  console.log(
17894
17894
  JSON.stringify({
17895
17895
  hookSpecificOutput: {
17896
17896
  hookEventName: "PreToolUse",
17897
17897
  permissionDecision: "deny",
17898
- permissionDecisionReason: reason2
17898
+ permissionDecisionReason: reason4
17899
17899
  }
17900
17900
  })
17901
17901
  );
@@ -18841,10 +18841,12 @@ function persistedTreeRoots() {
18841
18841
  }
18842
18842
 
18843
18843
  // src/commands/sessions/daemon/worktree/seedWorktree.ts
18844
- import { execFile as execFile8 } from "child_process";
18845
18844
  import { copyFileSync, existsSync as existsSync46, mkdirSync as mkdirSync16 } from "fs";
18846
18845
  import { dirname as dirname24, join as join48 } from "path";
18847
18846
 
18847
+ // src/commands/sessions/daemon/worktree/runInstall.ts
18848
+ import { spawn as spawn5 } from "child_process";
18849
+
18848
18850
  // src/commands/sessions/daemon/worktree/resolveInstallCommand.ts
18849
18851
  import { existsSync as existsSync45 } from "fs";
18850
18852
  import { join as join47 } from "path";
@@ -18861,6 +18863,90 @@ function resolveInstallCommand(repoRoot, install) {
18861
18863
  return detectInstallCommand(repoRoot);
18862
18864
  }
18863
18865
 
18866
+ // src/commands/sessions/daemon/worktree/stopInstall.ts
18867
+ import { execFile as execFile8 } from "child_process";
18868
+ var running2 = /* @__PURE__ */ new Map();
18869
+ function trackInstall(worktreePath, child) {
18870
+ running2.set(worktreePath, child);
18871
+ }
18872
+ function untrackInstall(worktreePath, child) {
18873
+ if (running2.get(worktreePath) === child) running2.delete(worktreePath);
18874
+ }
18875
+ function stopInstall(worktreePath) {
18876
+ const child = running2.get(worktreePath);
18877
+ running2.delete(worktreePath);
18878
+ if (!child?.pid) return;
18879
+ daemonLog(
18880
+ `worktree ${worktreePath} install still running at teardown; killing pid ${child.pid} so removal is not racing it`
18881
+ );
18882
+ killTree(child.pid);
18883
+ }
18884
+ function killTree(pid) {
18885
+ if (process.platform === "win32") {
18886
+ execFile8("taskkill", ["/T", "/F", "/PID", String(pid)], () => {
18887
+ });
18888
+ return;
18889
+ }
18890
+ try {
18891
+ process.kill(-pid, "SIGKILL");
18892
+ } catch {
18893
+ try {
18894
+ process.kill(pid, "SIGKILL");
18895
+ } catch {
18896
+ }
18897
+ }
18898
+ }
18899
+
18900
+ // src/commands/sessions/daemon/worktree/installInvocation.ts
18901
+ function installInvocation(worktreePath, command) {
18902
+ const windows = /^[A-Za-z]:[\\/]/.test(worktreePath);
18903
+ const shell = windows ? "cmd.exe" : process.env.SHELL ?? "bash";
18904
+ const args = windows ? ["/c", `cd /d ${quoteForCmd(worktreePath)} && ${command}`] : ["-l", "-c", `cd ${quoteForPosixShell(worktreePath)} && ${command}`];
18905
+ return [
18906
+ shell,
18907
+ args,
18908
+ { cwd: worktreePath, detached: true, stdio: ["ignore", "ignore", "pipe"] }
18909
+ ];
18910
+ }
18911
+ function quoteForCmd(value) {
18912
+ return `"${value.replaceAll('"', "")}"`;
18913
+ }
18914
+ function quoteForPosixShell(value) {
18915
+ return `'${value.replaceAll("'", `'\\''`)}'`;
18916
+ }
18917
+
18918
+ // src/commands/sessions/daemon/worktree/runInstall.ts
18919
+ var STDERR_TAIL = 2e3;
18920
+ function runInstall(worktreePath, clone, install, onSeeded) {
18921
+ const command = resolveInstallCommand(clone, install);
18922
+ if (!command) {
18923
+ onSeeded();
18924
+ return;
18925
+ }
18926
+ daemonLog(`worktree ${worktreePath} installing deps: ${command}`);
18927
+ const child = spawn5(...installInvocation(worktreePath, command));
18928
+ trackInstall(worktreePath, child);
18929
+ let stderr = "";
18930
+ child.stderr?.on("data", (chunk) => {
18931
+ stderr = (stderr + chunk.toString()).slice(-STDERR_TAIL);
18932
+ });
18933
+ let settled = false;
18934
+ const settle = (outcome) => {
18935
+ if (settled) return;
18936
+ settled = true;
18937
+ untrackInstall(worktreePath, child);
18938
+ daemonLog(`worktree ${worktreePath} install ${outcome}`);
18939
+ onSeeded();
18940
+ };
18941
+ child.on("error", (error) => settle(`failed to start: ${error.message}`));
18942
+ child.on(
18943
+ "close",
18944
+ (code, signal) => settle(
18945
+ code === 0 ? "complete" : `failed (${signal ? `signal ${signal}` : `exit ${code}`}): ${stderr.trim() || "no output"}`
18946
+ )
18947
+ );
18948
+ }
18949
+
18864
18950
  // src/commands/sessions/daemon/worktree/seedWorktree.ts
18865
18951
  function seedWorktree(worktreePath, clone, onSeeded = () => {
18866
18952
  }) {
@@ -18884,29 +18970,6 @@ function copyConfigFiles(worktreePath, clone, copy) {
18884
18970
  }
18885
18971
  }
18886
18972
  }
18887
- function runInstall(worktreePath, clone, install, onSeeded) {
18888
- const command = resolveInstallCommand(clone, install);
18889
- if (!command) {
18890
- onSeeded();
18891
- return;
18892
- }
18893
- const windows = /^[A-Za-z]:[\\/]/.test(worktreePath);
18894
- const shell = windows ? "cmd.exe" : process.env.SHELL ?? "bash";
18895
- const shellArgs = windows ? ["/c", `cd /d ${quoteForCmd(worktreePath)} && ${command}`] : ["-l", "-c", `cd ${quoteForPosixShell(worktreePath)} && ${command}`];
18896
- daemonLog(`worktree ${worktreePath} installing deps: ${command}`);
18897
- execFile8(shell, shellArgs, { cwd: worktreePath }, (error) => {
18898
- daemonLog(
18899
- error ? `worktree ${worktreePath} install failed: ${error.message}` : `worktree ${worktreePath} install complete`
18900
- );
18901
- onSeeded();
18902
- });
18903
- }
18904
- function quoteForPosixShell(value) {
18905
- return `'${value.replaceAll("'", `'\\''`)}'`;
18906
- }
18907
- function quoteForCmd(value) {
18908
- return `"${value.replaceAll('"', "")}"`;
18909
- }
18910
18973
  function message(error) {
18911
18974
  return error instanceof Error ? error.message : String(error);
18912
18975
  }
@@ -20881,16 +20944,16 @@ function reply(commentId, body) {
20881
20944
 
20882
20945
  // src/commands/prs/wontfix.ts
20883
20946
  import { execSync as execSync50 } from "child_process";
20884
- function validateReason(reason2) {
20885
- const lowerReason = reason2.toLowerCase();
20947
+ function validateReason(reason4) {
20948
+ const lowerReason = reason4.toLowerCase();
20886
20949
  if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
20887
20950
  console.error('Error: Reason must not contain "claude" or "opus"');
20888
20951
  process.exit(1);
20889
20952
  }
20890
20953
  }
20891
- function validateShaReferences(reason2) {
20954
+ function validateShaReferences(reason4) {
20892
20955
  const commitLinkPattern = /\[[0-9a-f]{7}\]\(https:\/\/github\.com\/[^/]+\/[^/]+\/commit\/([0-9a-f]{40})\)/gi;
20893
- const shas = Array.from(reason2.matchAll(commitLinkPattern), (m) => m[1]);
20956
+ const shas = Array.from(reason4.matchAll(commitLinkPattern), (m) => m[1]);
20894
20957
  if (shas.length === 0) {
20895
20958
  return;
20896
20959
  }
@@ -20909,11 +20972,11 @@ function validateShaReferences(reason2) {
20909
20972
  process.exit(1);
20910
20973
  }
20911
20974
  }
20912
- function wontfix(commentId, reason2) {
20913
- validateReason(reason2);
20914
- validateShaReferences(reason2);
20975
+ function wontfix(commentId, reason4) {
20976
+ validateReason(reason4);
20977
+ validateShaReferences(reason4);
20915
20978
  try {
20916
- resolveCommentWithReply(commentId, reason2);
20979
+ resolveCommentWithReply(commentId, reason4);
20917
20980
  } catch (error) {
20918
20981
  if (isGhNotInstalled(error)) {
20919
20982
  console.error("Error: GitHub CLI (gh) is not installed.");
@@ -21092,8 +21155,8 @@ function registerPrs(program2) {
21092
21155
  prsCommand.command("fixed <comment-id> <sha>").description("Reply with commit link and resolve thread").action((commentId, sha) => {
21093
21156
  fixed(Number.parseInt(commentId, 10), sha);
21094
21157
  });
21095
- prsCommand.command("wontfix <comment-id> <reason>").description("Reply with reason and resolve thread").action((commentId, reason2) => {
21096
- wontfix(Number.parseInt(commentId, 10), reason2);
21158
+ prsCommand.command("wontfix <comment-id> <reason>").description("Reply with reason and resolve thread").action((commentId, reason4) => {
21159
+ wontfix(Number.parseInt(commentId, 10), reason4);
21097
21160
  });
21098
21161
  prsCommand.command("reply <comment-id> <body>").description("Reply to a comment thread without resolving it").action((commentId, body) => {
21099
21162
  reply(Number.parseInt(commentId, 10), body);
@@ -21542,7 +21605,7 @@ function registerRavendb(program2) {
21542
21605
  }
21543
21606
 
21544
21607
  // src/commands/refactor/check/index.ts
21545
- import { spawn as spawn5 } from "child_process";
21608
+ import { spawn as spawn6 } from "child_process";
21546
21609
  import * as path36 from "path";
21547
21610
 
21548
21611
  // src/commands/refactor/logViolations.ts
@@ -21690,7 +21753,7 @@ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES) {
21690
21753
  // src/commands/refactor/check/index.ts
21691
21754
  function runScript(script, cwd) {
21692
21755
  return new Promise((resolve20) => {
21693
- const child = spawn5("npm", ["run", script], {
21756
+ const child = spawn6("npm", ["run", script], {
21694
21757
  stdio: "pipe",
21695
21758
  shell: true,
21696
21759
  cwd
@@ -23074,10 +23137,10 @@ function listFilesRecursive(dir) {
23074
23137
  }
23075
23138
  return results;
23076
23139
  }
23077
- function addDirectoryFileMoves(moves, childDir, newLocation, reason2) {
23140
+ function addDirectoryFileMoves(moves, childDir, newLocation, reason4) {
23078
23141
  for (const file of listFilesRecursive(childDir)) {
23079
23142
  const rel = path55.relative(childDir, file);
23080
- moves.push({ from: file, to: path55.join(newLocation, rel), reason: reason2 });
23143
+ moves.push({ from: file, to: path55.join(newLocation, rel), reason: reason4 });
23081
23144
  }
23082
23145
  }
23083
23146
  function resolveChildDest(parentDir, childDir) {
@@ -23088,8 +23151,8 @@ function childMoveReason(parentDir) {
23088
23151
  }
23089
23152
  function registerDirectoryMove(result, childDir, dest, parentDir) {
23090
23153
  result.directories.push(dest);
23091
- const reason2 = childMoveReason(parentDir);
23092
- addDirectoryFileMoves(result.moves, childDir, dest, reason2);
23154
+ const reason4 = childMoveReason(parentDir);
23155
+ addDirectoryFileMoves(result.moves, childDir, dest, reason4);
23093
23156
  }
23094
23157
  function planChildDirectoryMove(result, parentDir, childDir) {
23095
23158
  const dest = resolveChildDest(parentDir, childDir);
@@ -24384,7 +24447,7 @@ function reportReviewerToolUse(name, use, spinner) {
24384
24447
  }
24385
24448
 
24386
24449
  // src/commands/review/runStreamingChild.ts
24387
- import { spawn as spawn6 } from "child_process";
24450
+ import { spawn as spawn7 } from "child_process";
24388
24451
 
24389
24452
  // src/commands/review/attachLineParser.ts
24390
24453
  function flushBuffer(buffer, onLine) {
@@ -24535,7 +24598,7 @@ function writeStdinSafely(child, payload) {
24535
24598
  }
24536
24599
  }
24537
24600
  function startChild(spec) {
24538
- const child = spawn6(spec.command, spec.args, {
24601
+ const child = spawn7(spec.command, spec.args, {
24539
24602
  stdio: ["pipe", "pipe", "pipe"],
24540
24603
  shell: process.platform === "win32"
24541
24604
  });
@@ -26192,7 +26255,7 @@ function setup() {
26192
26255
  }
26193
26256
 
26194
26257
  // src/commands/voice/start.ts
26195
- import { spawn as spawn7 } from "child_process";
26258
+ import { spawn as spawn8 } from "child_process";
26196
26259
  import { mkdirSync as mkdirSync23, writeFileSync as writeFileSync40 } from "fs";
26197
26260
  import { join as join65 } from "path";
26198
26261
 
@@ -26207,11 +26270,11 @@ function buildDaemonEnv(options2) {
26207
26270
  // src/commands/voice/start.ts
26208
26271
  function spawnForeground(python, script, env) {
26209
26272
  console.log("Starting voice daemon in foreground...");
26210
- const child = spawn7(python, [script], { stdio: "inherit", env });
26273
+ const child = spawn8(python, [script], { stdio: "inherit", env });
26211
26274
  child.on("exit", (code) => process.exit(code ?? 0));
26212
26275
  }
26213
26276
  function spawnBackground(python, script, env) {
26214
- const child = spawn7(python, [script], {
26277
+ const child = spawn8(python, [script], {
26215
26278
  detached: true,
26216
26279
  stdio: "ignore",
26217
26280
  env
@@ -27012,7 +27075,7 @@ function runPreCommands(pre, cwd) {
27012
27075
  }
27013
27076
 
27014
27077
  // src/commands/run/spawnRunCommand.ts
27015
- import { execFileSync as execFileSync12, spawn as spawn8 } from "child_process";
27078
+ import { execFileSync as execFileSync12, spawn as spawn9 } from "child_process";
27016
27079
  import { existsSync as existsSync58 } from "fs";
27017
27080
  import { dirname as dirname29, join as join67, resolve as resolve15 } from "path";
27018
27081
  function resolveCommand2(command) {
@@ -27028,7 +27091,7 @@ function resolveCommand2(command) {
27028
27091
  }
27029
27092
  function spawnRunCommand(command, args, env, cwd, quiet) {
27030
27093
  const start3 = Date.now();
27031
- const child = spawn8(resolveCommand2(command), args, {
27094
+ const child = spawn9(resolveCommand2(command), args, {
27032
27095
  stdio: quiet ? "pipe" : "inherit",
27033
27096
  env: env ? { ...process.env, ...expandEnv(env) } : void 0,
27034
27097
  cwd
@@ -28104,9 +28167,89 @@ function otherTreeHolders(sessions, session) {
28104
28167
  }
28105
28168
 
28106
28169
  // src/commands/sessions/daemon/worktree/reapWorktree.ts
28107
- import { existsSync as existsSync62 } from "fs";
28170
+ import { existsSync as existsSync63 } from "fs";
28108
28171
  import { basename as basename16 } from "path";
28109
28172
 
28173
+ // src/commands/sessions/daemon/worktree/deleteStrandedTree.ts
28174
+ import { existsSync as existsSync62 } from "fs";
28175
+ import { join as join73 } from "path";
28176
+
28177
+ // src/commands/sessions/daemon/worktree/deleteTreeDirectly.ts
28178
+ import { statSync as statSync11 } from "fs";
28179
+ import { rm as rm2 } from "fs/promises";
28180
+ import { join as join72 } from "path";
28181
+ async function deleteTreeDirectly(clone, worktreePath, why) {
28182
+ if (holdsAGitDirectoryRatherThanALink(worktreePath)) {
28183
+ daemonLog(
28184
+ `worktree ${worktreePath} not deleted directly (${why}): it is a clone of its own, not a linked worktree`
28185
+ );
28186
+ return false;
28187
+ }
28188
+ daemonLog(`worktree ${worktreePath} deleting its directory directly: ${why}`);
28189
+ try {
28190
+ await rm2(worktreePath, {
28191
+ recursive: true,
28192
+ force: true,
28193
+ maxRetries: 3,
28194
+ retryDelay: 200
28195
+ });
28196
+ } catch (error) {
28197
+ daemonLog(
28198
+ `worktree ${worktreePath} directory delete failed, left in place for the next reconcile: ${reason(error)}`
28199
+ );
28200
+ return false;
28201
+ }
28202
+ daemonLog(`worktree ${worktreePath} directory deleted directly`);
28203
+ await pruneBookkeeping(clone, worktreePath);
28204
+ return true;
28205
+ }
28206
+ function holdsAGitDirectoryRatherThanALink(worktreePath) {
28207
+ return statSync11(join72(worktreePath, ".git"), {
28208
+ throwIfNoEntry: false
28209
+ })?.isDirectory() === true;
28210
+ }
28211
+ async function pruneBookkeeping(clone, worktreePath) {
28212
+ try {
28213
+ await git2(clone, ["worktree", "prune"]);
28214
+ daemonLog(
28215
+ `worktree bookkeeping pruned in clone ${clone} after deleting ${worktreePath} directly`
28216
+ );
28217
+ } catch (error) {
28218
+ daemonLog(
28219
+ `worktree bookkeeping prune failed in clone ${clone} after deleting ${worktreePath}: ${reason(error)}`
28220
+ );
28221
+ }
28222
+ }
28223
+ function reason(error) {
28224
+ return error instanceof Error ? error.message : String(error);
28225
+ }
28226
+
28227
+ // src/commands/sessions/daemon/worktree/deleteStrandedTree.ts
28228
+ async function deleteStrandedTree(clone, worktreePath, cause) {
28229
+ const stranded = strandedReason(worktreePath, cause);
28230
+ if (!stranded) {
28231
+ daemonLog(
28232
+ `worktree ${worktreePath} left in place for the next reconcile: ${reason2(cause)}`
28233
+ );
28234
+ return false;
28235
+ }
28236
+ return await deleteTreeDirectly(
28237
+ clone,
28238
+ worktreePath,
28239
+ `git can no longer remove it, ${stranded}`
28240
+ );
28241
+ }
28242
+ function strandedReason(worktreePath, cause) {
28243
+ if (!existsSync62(join73(worktreePath, ".git")))
28244
+ return "its .git link is already gone";
28245
+ if (/not a working tree|not a git repository/i.test(reason2(cause)))
28246
+ return "git no longer recognises it as a working tree";
28247
+ return null;
28248
+ }
28249
+ function reason2(error) {
28250
+ return error instanceof Error ? error.message : String(error);
28251
+ }
28252
+
28110
28253
  // src/commands/sessions/daemon/worktree/removeTree.ts
28111
28254
  async function removeTree(clone, worktreePath, force) {
28112
28255
  const remove2 = (forced) => git2(clone, [
@@ -28119,12 +28262,17 @@ async function removeTree(clone, worktreePath, force) {
28119
28262
  await remove2(force);
28120
28263
  return true;
28121
28264
  } catch (error) {
28122
- daemonLog(`worktree ${worktreePath} removal failed: ${reason(error)}`);
28265
+ daemonLog(`worktree ${worktreePath} removal failed: ${reason3(error)}`);
28266
+ if (force)
28267
+ return await deleteTreeDirectly(
28268
+ clone,
28269
+ worktreePath,
28270
+ `its work was discarded and git could not remove it: ${reason3(error)}`
28271
+ );
28123
28272
  }
28124
- if (force) return false;
28125
- return await removeIgnoringLeftovers(remove2, worktreePath);
28273
+ return await removeIgnoringLeftovers(clone, remove2, worktreePath);
28126
28274
  }
28127
- async function removeIgnoringLeftovers(remove2, worktreePath) {
28275
+ async function removeIgnoringLeftovers(clone, remove2, worktreePath) {
28128
28276
  try {
28129
28277
  await remove2(true);
28130
28278
  daemonLog(
@@ -28133,18 +28281,18 @@ async function removeIgnoringLeftovers(remove2, worktreePath) {
28133
28281
  return true;
28134
28282
  } catch (error) {
28135
28283
  daemonLog(
28136
- `worktree ${worktreePath} left in place for the next reconcile: ${reason(error)}`
28284
+ `worktree ${worktreePath} forced removal failed: ${reason3(error)}`
28137
28285
  );
28138
- return false;
28286
+ return await deleteStrandedTree(clone, worktreePath, error);
28139
28287
  }
28140
28288
  }
28141
- function reason(error) {
28289
+ function reason3(error) {
28142
28290
  return error instanceof Error ? error.message : String(error);
28143
28291
  }
28144
28292
 
28145
28293
  // src/commands/sessions/daemon/worktree/reapWorktree.ts
28146
28294
  async function reapWorktree(worktreePath, force = false) {
28147
- if (!existsSync62(worktreePath)) {
28295
+ if (!existsSync63(worktreePath)) {
28148
28296
  daemonLog(`worktree ${worktreePath} already gone; skipping reap`);
28149
28297
  return false;
28150
28298
  }
@@ -28155,13 +28303,24 @@ async function reapWorktree(worktreePath, force = false) {
28155
28303
  return false;
28156
28304
  }
28157
28305
  }
28158
- const clone = mainWorktree(worktreePath) ?? worktreePath;
28306
+ stopInstall(worktreePath);
28307
+ const clone = owningClone(worktreePath);
28159
28308
  if (!await removeTree(clone, worktreePath, force)) return false;
28160
28309
  await deleteWorktreeBranch(clone, basename16(worktreePath));
28161
28310
  forgetWorktree(worktreePath);
28162
28311
  daemonLog(`worktree ${worktreePath} reaped${force ? " (forced)" : ""}`);
28163
28312
  return true;
28164
28313
  }
28314
+ function owningClone(worktreePath) {
28315
+ const recorded = worktreeAttributionIncludingReaped(worktreePath)?.clone;
28316
+ if (recorded && existsSync63(recorded)) return recorded;
28317
+ const detected = mainWorktree(worktreePath);
28318
+ if (detected) return detected;
28319
+ daemonLog(
28320
+ `worktree ${worktreePath} has no resolvable clone; tearing it down on its own`
28321
+ );
28322
+ return worktreePath;
28323
+ }
28165
28324
  async function deleteWorktreeBranch(clone, branch2) {
28166
28325
  if (!listLocalBranches(clone).includes(branch2)) return;
28167
28326
  const current = await gitOrNull2(clone, ["symbolic-ref", "--short", "HEAD"]);
@@ -28241,12 +28400,12 @@ function setStatus2(session, newStatus) {
28241
28400
  }
28242
28401
 
28243
28402
  // src/commands/sessions/daemon/worktree/watchGitState.ts
28244
- import { existsSync as existsSync63, watch } from "fs";
28403
+ import { existsSync as existsSync64, watch } from "fs";
28245
28404
  var DEBOUNCE_MS = 500;
28246
28405
  var POLL_MS = 3e4;
28247
28406
  function watchGitState(cwd, onChange) {
28248
28407
  const common = gitCommonDir(cwd);
28249
- if (!common || !existsSync63(common)) return void 0;
28408
+ if (!common || !existsSync64(common)) return void 0;
28250
28409
  const watchers = [
28251
28410
  watchGitDir(common, onChange),
28252
28411
  pollGitState(cwd, onChange)
@@ -28300,12 +28459,12 @@ async function resolveCloseDurability(session, finalize, notify2) {
28300
28459
  session.gitWatcher = void 0;
28301
28460
  finalize();
28302
28461
  }
28303
- function holdStopped(session, tree, reason2, finalize, notify2) {
28304
- if (session.undurable?.reason !== reason2)
28462
+ function holdStopped(session, tree, reason4, finalize, notify2) {
28463
+ if (session.undurable?.reason !== reason4)
28305
28464
  daemonLog(
28306
- `session ${session.id} stopped; ${tree.removable ? "reap" : "close"} blocked in ${tree.path}: ${reason2}`
28465
+ `session ${session.id} stopped; ${tree.removable ? "reap" : "close"} blocked in ${tree.path}: ${reason4}`
28307
28466
  );
28308
- session.undurable = { reason: reason2, removesTree: tree.removable };
28467
+ session.undurable = { reason: reason4, removesTree: tree.removable };
28309
28468
  session.closing = void 0;
28310
28469
  setStatus2(session, "stopped");
28311
28470
  if (!session.gitWatcher) {
@@ -28650,10 +28809,10 @@ function emitSessionOutput(session, clients, data) {
28650
28809
  }
28651
28810
 
28652
28811
  // src/commands/sessions/daemon/exitReason.ts
28653
- import { existsSync as existsSync64 } from "fs";
28812
+ import { existsSync as existsSync65 } from "fs";
28654
28813
  function exitReason(session, exitCode) {
28655
28814
  const base = `process exited with code ${exitCode}`;
28656
- if (session.cwd && !existsSync64(session.cwd))
28815
+ if (session.cwd && !existsSync65(session.cwd))
28657
28816
  return `${base}: working directory ${session.cwd} no longer exists`;
28658
28817
  return base;
28659
28818
  }
@@ -28671,7 +28830,7 @@ function handleFailedResume(session, exitCode, onStatusChange) {
28671
28830
  }
28672
28831
 
28673
28832
  // src/commands/sessions/daemon/watchActivity.ts
28674
- import { existsSync as existsSync65, mkdirSync as mkdirSync26, watch as watch2 } from "fs";
28833
+ import { existsSync as existsSync66, mkdirSync as mkdirSync26, watch as watch2 } from "fs";
28675
28834
  import { dirname as dirname31 } from "path";
28676
28835
 
28677
28836
  // src/commands/sessions/daemon/applyReviewPause.ts
@@ -28752,7 +28911,7 @@ function watchActivity(session, notify2, onClaudeSessionId) {
28752
28911
  if (timer) clearTimeout(timer);
28753
28912
  timer = setTimeout(read, DEBOUNCE_MS2);
28754
28913
  });
28755
- if (existsSync65(path71)) read();
28914
+ if (existsSync66(path71)) read();
28756
28915
  }
28757
28916
  function refreshActivity(session) {
28758
28917
  if (session.commandType !== "assist" || !session.cwd) return;
@@ -29767,14 +29926,14 @@ function restoreSession(id, persisted) {
29767
29926
  }
29768
29927
 
29769
29928
  // src/commands/sessions/daemon/restoreOne.ts
29770
- function restoreOne(persisted, spawn12, sessions) {
29929
+ function restoreOne(persisted, spawn13, sessions) {
29771
29930
  try {
29772
- const id = spawn12((sid) => restoreSession(sid, persisted));
29931
+ const id = spawn13((sid) => restoreSession(sid, persisted));
29773
29932
  logUnresumable(persisted.name, id, sessions.get(id));
29774
29933
  } catch (error) {
29775
- const reason2 = logRestoreError(persisted.name, error);
29934
+ const reason4 = logRestoreError(persisted.name, error);
29776
29935
  try {
29777
- spawn12((id) => errorSession(id, persisted, reason2));
29936
+ spawn13((id) => errorSession(id, persisted, reason4));
29778
29937
  } catch {
29779
29938
  }
29780
29939
  }
@@ -29786,9 +29945,9 @@ function logUnresumable(name, id, session) {
29786
29945
  );
29787
29946
  }
29788
29947
  function logRestoreError(name, error) {
29789
- const reason2 = error instanceof Error ? error.message : String(error);
29790
- daemonLog(`failed to restore session "${name}": ${reason2}`);
29791
- return reason2;
29948
+ const reason4 = error instanceof Error ? error.message : String(error);
29949
+ daemonLog(`failed to restore session "${name}": ${reason4}`);
29950
+ return reason4;
29792
29951
  }
29793
29952
 
29794
29953
  // src/commands/sessions/daemon/sessionLimits.ts
@@ -29809,7 +29968,7 @@ var sessionLimits = {
29809
29968
  };
29810
29969
 
29811
29970
  // src/commands/sessions/daemon/restoreAll.ts
29812
- function restoreAll(spawn12, sessions) {
29971
+ function restoreAll(spawn13, sessions) {
29813
29972
  const persisted = loadPersistedSessions();
29814
29973
  const toRestore = persisted.slice(0, sessionLimits.maxRestore);
29815
29974
  const skipped = persisted.length - toRestore.length;
@@ -29818,7 +29977,7 @@ function restoreAll(spawn12, sessions) {
29818
29977
  `restore capped at ${sessionLimits.maxRestore}; skipping ${skipped} persisted session(s)`
29819
29978
  );
29820
29979
  return toRestore.map((persisted2) => {
29821
- restoreOne(persisted2, spawn12, sessions);
29980
+ restoreOne(persisted2, spawn13, sessions);
29822
29981
  return persisted2.name;
29823
29982
  });
29824
29983
  }
@@ -29841,7 +30000,7 @@ function rearmStoppedSessions(sessions, notify2) {
29841
30000
  }
29842
30001
 
29843
30002
  // src/commands/sessions/daemon/worktree/reconcileWorktreesOnRestore.ts
29844
- import { existsSync as existsSync68 } from "fs";
30003
+ import { existsSync as existsSync69 } from "fs";
29845
30004
  import { basename as basename18 } from "path";
29846
30005
 
29847
30006
  // src/commands/sessions/daemon/worktree/accountedTrees.ts
@@ -29897,10 +30056,10 @@ function bindResumedWorktree(session, cwd, notify2) {
29897
30056
 
29898
30057
  // src/commands/sessions/daemon/worktree/describeHeldWork.ts
29899
30058
  var MAX_ITEMS = 20;
29900
- async function describeHeldWork(path71, reason2) {
29901
- if (reason2.startsWith("uncommitted")) return await changedFiles(path71);
29902
- if (reason2.startsWith("unpushed")) return await unpushedCommits(path71, reason2);
29903
- return { summary: reason2, items: [] };
30059
+ async function describeHeldWork(path71, reason4) {
30060
+ if (reason4.startsWith("uncommitted")) return await changedFiles(path71);
30061
+ if (reason4.startsWith("unpushed")) return await unpushedCommits(path71, reason4);
30062
+ return { summary: reason4, items: [] };
29904
30063
  }
29905
30064
  async function changedFiles(path71) {
29906
30065
  const status3 = await gitResult(path71, ["status", "--porcelain"]);
@@ -29910,9 +30069,9 @@ async function changedFiles(path71) {
29910
30069
  items: capped(lines)
29911
30070
  };
29912
30071
  }
29913
- async function unpushedCommits(path71, reason2) {
30072
+ async function unpushedCommits(path71, reason4) {
29914
30073
  const log = await gitResult(path71, ["log", "--oneline", "@{upstream}..HEAD"]);
29915
- if (!log.ok) return { summary: reason2, items: [] };
30074
+ if (!log.ok) return { summary: reason4, items: [] };
29916
30075
  const lines = nonEmptyLines(log.out);
29917
30076
  return {
29918
30077
  summary: `${lines.length} unpushed ${lines.length === 1 ? "commit" : "commits"}`,
@@ -29931,20 +30090,20 @@ function capped(lines) {
29931
30090
  }
29932
30091
 
29933
30092
  // src/commands/sessions/daemon/worktree/reclaimVanishedWorktrees.ts
29934
- import { existsSync as existsSync67 } from "fs";
30093
+ import { existsSync as existsSync68 } from "fs";
29935
30094
  async function reclaimVanishedWorktrees(clone, paths) {
29936
- if (!existsSync67(clone)) {
30095
+ if (!existsSync68(clone)) {
29937
30096
  for (const { path: path71 } of paths) forgetWorktree(path71);
29938
30097
  daemonLog(
29939
30098
  `clone ${clone} is gone; forgot ${paths.length} worktree record(s) it owned`
29940
30099
  );
29941
30100
  return;
29942
30101
  }
29943
- await pruneBookkeeping(clone);
30102
+ await pruneBookkeeping2(clone);
29944
30103
  for (const { path: path71, branch: branch2 } of paths)
29945
30104
  if (await reclaimBranch(clone, branch2)) forgetWorktree(path71);
29946
30105
  }
29947
- async function pruneBookkeeping(clone) {
30106
+ async function pruneBookkeeping2(clone) {
29948
30107
  try {
29949
30108
  await git2(clone, ["worktree", "prune"]);
29950
30109
  daemonLog(`worktree bookkeeping pruned for clone ${clone}`);
@@ -29971,7 +30130,7 @@ async function reclaimBranch(clone, branch2) {
29971
30130
  // src/commands/sessions/daemon/worktree/resurfaceOrphanedWorktree.ts
29972
30131
  import { basename as basename17 } from "path";
29973
30132
  function resurfaceOrphanedWorktree(sessions, spawnWith, recovered, notify2) {
29974
- const { orphan, reason: reason2, held } = recovered;
30133
+ const { orphan, reason: reason4, held } = recovered;
29975
30134
  let id;
29976
30135
  try {
29977
30136
  id = spawnWith((sid) => orphanedSession(sid, recovered));
@@ -29982,14 +30141,14 @@ function resurfaceOrphanedWorktree(sessions, spawnWith, recovered, notify2) {
29982
30141
  return;
29983
30142
  }
29984
30143
  daemonLog(
29985
- `orphaned worktree ${orphan.path} resurfaced as stopped session ${id}: ${reason2} (${held.summary})`
30144
+ `orphaned worktree ${orphan.path} resurfaced as stopped session ${id}: ${reason4} (${held.summary})`
29986
30145
  );
29987
30146
  const session = sessions.get(id);
29988
30147
  if (session) armStoppedSession(sessions, session, notify2);
29989
30148
  notify2();
29990
30149
  }
29991
30150
  function orphanedSession(id, recovered) {
29992
- const { orphan, reason: reason2, held } = recovered;
30151
+ const { orphan, reason: reason4, held } = recovered;
29993
30152
  return {
29994
30153
  ...sessionBase(id, "stopped"),
29995
30154
  name: `recovered ${basename17(orphan.path)}`,
@@ -29998,7 +30157,7 @@ function orphanedSession(id, recovered) {
29998
30157
  pty: null,
29999
30158
  cwd: orphan.path,
30000
30159
  worktree: { path: orphan.path, clone: orphan.clone },
30001
- undurable: { reason: reason2, removesTree: true },
30160
+ undurable: { reason: reason4, removesTree: true },
30002
30161
  scrollback: recoveryNotice(recovered)
30003
30162
  };
30004
30163
  }
@@ -30026,7 +30185,7 @@ async function recoverOrphanedWorktrees(sessions, spawnWith, notify2) {
30026
30185
  const vanished = /* @__PURE__ */ new Map();
30027
30186
  for (const { path: path71, clone } of readWorktreeRegistry()) {
30028
30187
  if (accounted.has(path71)) continue;
30029
- if (!existsSync68(path71)) {
30188
+ if (!existsSync69(path71)) {
30030
30189
  vanished.set(clone, [
30031
30190
  ...vanished.get(clone) ?? [],
30032
30191
  { path: path71, branch: basename18(path71) }
@@ -30239,6 +30398,12 @@ function startHeldSession(session, sessions, clients, onStatusChange, notify2) {
30239
30398
  );
30240
30399
  return;
30241
30400
  }
30401
+ if (session.closing) {
30402
+ daemonLog(
30403
+ `session ${session.id} not started after seeding: card is closing (${session.worktree?.path ?? "no worktree"})`
30404
+ );
30405
+ return;
30406
+ }
30242
30407
  session.startedAt = Date.now();
30243
30408
  if (session.status === "running") session.runningSince = session.startedAt;
30244
30409
  session.pty = start3();
@@ -30315,7 +30480,7 @@ async function isWindowsDaemonRunning() {
30315
30480
  }
30316
30481
 
30317
30482
  // src/commands/sessions/daemon/ensureWindowsDaemonRunning.ts
30318
- import { spawn as spawn10 } from "child_process";
30483
+ import { spawn as spawn11 } from "child_process";
30319
30484
 
30320
30485
  // src/commands/sessions/daemon/logChildStream.ts
30321
30486
  import { createInterface as createInterface7 } from "readline";
@@ -30340,7 +30505,7 @@ async function ensureWindowsDaemonRunning() {
30340
30505
  await waitForWindowsDaemon();
30341
30506
  }
30342
30507
  function launchWindowsDaemon() {
30343
- const child = spawn10("pwsh.exe", ["-Command", "assist daemon run"], {
30508
+ const child = spawn11("pwsh.exe", ["-Command", "assist daemon run"], {
30344
30509
  detached: true,
30345
30510
  stdio: ["ignore", "pipe", "pipe"]
30346
30511
  });
@@ -30388,13 +30553,13 @@ async function defaultConnect() {
30388
30553
  }
30389
30554
 
30390
30555
  // src/commands/sessions/daemon/hasPersistedWindowsSessions.ts
30391
- import { existsSync as existsSync69, readFileSync as readFileSync50 } from "fs";
30556
+ import { existsSync as existsSync70, readFileSync as readFileSync50 } from "fs";
30392
30557
  import { posix } from "path";
30393
30558
  function hasPersistedWindowsSessions() {
30394
30559
  const sessionsFile = windowsSessionsFileFromWsl();
30395
30560
  if (!sessionsFile) return false;
30396
30561
  try {
30397
- if (!existsSync69(sessionsFile)) return false;
30562
+ if (!existsSync70(sessionsFile)) return false;
30398
30563
  const data = JSON.parse(readFileSync50(sessionsFile, "utf8"));
30399
30564
  return Array.isArray(data) && data.length > 0;
30400
30565
  } catch (error) {
@@ -30643,7 +30808,7 @@ function handleWindowsClose(state) {
30643
30808
  }
30644
30809
 
30645
30810
  // src/commands/sessions/daemon/healWindowsDaemon.ts
30646
- import { spawn as spawn11 } from "child_process";
30811
+ import { spawn as spawn12 } from "child_process";
30647
30812
  var UPDATE_TIMEOUT_MS = 5 * 6e4;
30648
30813
  var STOP_TIMEOUT_MS2 = 3e4;
30649
30814
  async function healWindowsDaemon() {
@@ -30663,7 +30828,7 @@ async function healWindowsDaemon() {
30663
30828
  }
30664
30829
  function runOnWindowsHost(command, timeoutMs) {
30665
30830
  return new Promise((resolve20, reject) => {
30666
- const child = spawn11("pwsh.exe", ["-Command", command], {
30831
+ const child = spawn12("pwsh.exe", ["-Command", command], {
30667
30832
  stdio: ["ignore", "pipe", "pipe"]
30668
30833
  });
30669
30834
  logChildStream(child.stdout, `windows ${command}`);
@@ -31285,10 +31450,10 @@ import * as net3 from "net";
31285
31450
  import { createInterface as createInterface9 } from "readline";
31286
31451
 
31287
31452
  // src/commands/sessions/daemon/creator.ts
31288
- function creator(isNew, spawn12) {
31453
+ function creator(isNew, spawn13) {
31289
31454
  return (client, m, d) => {
31290
31455
  if (m.windowsProxy.route(client, d)) return;
31291
- sendTo(client, { type: "created", sessionId: spawn12(m, d), isNew });
31456
+ sendTo(client, { type: "created", sessionId: spawn13(m, d), isNew });
31292
31457
  };
31293
31458
  }
31294
31459
 
@@ -32018,13 +32183,13 @@ function buildLimitsSegment(rateLimits) {
32018
32183
  }
32019
32184
 
32020
32185
  // src/commands/readGitBranch.ts
32021
- import { readFileSync as readFileSync53, statSync as statSync12 } from "fs";
32022
- import { isAbsolute as isAbsolute3, join as join73, resolve as resolve18 } from "path";
32186
+ import { readFileSync as readFileSync53, statSync as statSync13 } from "fs";
32187
+ import { isAbsolute as isAbsolute3, join as join75, resolve as resolve18 } from "path";
32023
32188
  function resolveGitDir(cwd) {
32024
- const dotGit = join73(cwd, ".git");
32189
+ const dotGit = join75(cwd, ".git");
32025
32190
  let stat3;
32026
32191
  try {
32027
- stat3 = statSync12(dotGit);
32192
+ stat3 = statSync13(dotGit);
32028
32193
  } catch {
32029
32194
  return null;
32030
32195
  }
@@ -32051,7 +32216,7 @@ function readGitBranch(cwd) {
32051
32216
  }
32052
32217
  let head;
32053
32218
  try {
32054
- head = readFileSync53(join73(gitDir, "HEAD"), "utf8");
32219
+ head = readFileSync53(join75(gitDir, "HEAD"), "utf8");
32055
32220
  } catch {
32056
32221
  return null;
32057
32222
  }