@staff0rd/assist 0.488.5 → 0.489.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.488.5",
9
+ version: "0.489.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -2415,8 +2415,8 @@ function printDiff(oldContent, newContent) {
2415
2415
  normalizeJson(newContent)
2416
2416
  );
2417
2417
  for (const change of changes) {
2418
- const lines = change.value.replace(/\n$/, "").split("\n");
2419
- for (const line of lines) {
2418
+ const lines2 = change.value.replace(/\n$/, "").split("\n");
2419
+ for (const line of lines2) {
2420
2420
  if (change.added) {
2421
2421
  console.log(chalk12.green(`+ ${line}`));
2422
2422
  } else if (change.removed) {
@@ -2863,11 +2863,11 @@ function removeVscodeFromGitignore() {
2863
2863
  return;
2864
2864
  }
2865
2865
  const content = fs3.readFileSync(gitignorePath, "utf8");
2866
- const lines = content.split("\n");
2867
- const filteredLines = lines.filter(
2866
+ const lines2 = content.split("\n");
2867
+ const filteredLines = lines2.filter(
2868
2868
  (line) => !line.trim().toLowerCase().includes(".vscode")
2869
2869
  );
2870
- if (filteredLines.length !== lines.length) {
2870
+ if (filteredLines.length !== lines2.length) {
2871
2871
  fs3.writeFileSync(gitignorePath, filteredLines.join("\n"));
2872
2872
  console.log(chalk20.dim("Removed .vscode references from .gitignore"));
2873
2873
  }
@@ -3269,11 +3269,11 @@ ${checkName} failed:
3269
3269
  // src/commands/lint/lint/runImportExtensionCheck.ts
3270
3270
  function checkForImportExtensions(filePath) {
3271
3271
  const content = fs12.readFileSync(filePath, "utf8");
3272
- const lines = content.split("\n");
3272
+ const lines2 = content.split("\n");
3273
3273
  const violations = [];
3274
3274
  const importExtensionPattern = /from\s+["']\..*\.(js|ts)["']/;
3275
- for (let i = 0; i < lines.length; i++) {
3276
- const line = lines[i];
3275
+ for (let i = 0; i < lines2.length; i++) {
3276
+ const line = lines2[i];
3277
3277
  if (importExtensionPattern.test(line)) {
3278
3278
  violations.push({
3279
3279
  filePath,
@@ -3305,12 +3305,12 @@ function runImportExtensionCheck() {
3305
3305
  import fs13 from "fs";
3306
3306
  function checkForDynamicImports(filePath) {
3307
3307
  const content = fs13.readFileSync(filePath, "utf8");
3308
- const lines = content.split("\n");
3308
+ const lines2 = content.split("\n");
3309
3309
  const violations = [];
3310
3310
  const requirePattern = /\brequire\s*\(/;
3311
3311
  const dynamicImportPattern = /\bimport\s*\(/;
3312
- for (let i = 0; i < lines.length; i++) {
3313
- const line = lines[i];
3312
+ for (let i = 0; i < lines2.length; i++) {
3313
+ const line = lines2[i];
3314
3314
  if (requirePattern.test(line) || dynamicImportPattern.test(line)) {
3315
3315
  violations.push({
3316
3316
  filePath,
@@ -3412,9 +3412,9 @@ function collectBicepComments(content) {
3412
3412
  comments3.push({ line, text: match });
3413
3413
  return blankNonNewline(match);
3414
3414
  });
3415
- const lines = work.split("\n");
3416
- for (let i = 0; i < lines.length; i++) {
3417
- const match = lines[i].match(LINE_COMMENT);
3415
+ const lines2 = work.split("\n");
3416
+ for (let i = 0; i < lines2.length; i++) {
3417
+ const match = lines2[i].match(LINE_COMMENT);
3418
3418
  if (match) comments3.push({ line: i + 1, text: match[0] });
3419
3419
  }
3420
3420
  return comments3;
@@ -3429,14 +3429,14 @@ function isHeaderLine(line) {
3429
3429
  return trimmed === "" || trimmed.startsWith("#");
3430
3430
  }
3431
3431
  function collectHashComments(content, options2) {
3432
- const lines = content.split("\n");
3432
+ const lines2 = content.split("\n");
3433
3433
  let start3 = 0;
3434
3434
  if (options2.skipHeader) {
3435
- while (start3 < lines.length && isHeaderLine(lines[start3])) start3++;
3435
+ while (start3 < lines2.length && isHeaderLine(lines2[start3])) start3++;
3436
3436
  }
3437
3437
  const comments3 = [];
3438
- for (let i = start3; i < lines.length; i++) {
3439
- const work = lines[i].replace(
3438
+ for (let i = start3; i < lines2.length; i++) {
3439
+ const work = lines2[i].replace(
3440
3440
  /"(?:[^"\\]|\\.)*"|'(?:[^']|'')*'/g,
3441
3441
  blankNonNewline2
3442
3442
  );
@@ -3470,8 +3470,8 @@ function collectComments(sourceFile) {
3470
3470
  var MAINTAINABILITY_OVERRIDE_MARKER = "assist-maintainability-override";
3471
3471
  var OVERRIDE_MARKER = /^\s*\/\/\s*assist-maintainability-override:?\s*(-?\d+)\s*$/;
3472
3472
  function parseMaintainabilityOverride(content) {
3473
- const lines = content.split("\n").slice(0, 10);
3474
- for (const line of lines) {
3473
+ const lines2 = content.split("\n").slice(0, 10);
3474
+ for (const line of lines2) {
3475
3475
  const match = line.match(OVERRIDE_MARKER);
3476
3476
  if (!match) continue;
3477
3477
  const value = Number(match[1]);
@@ -3508,12 +3508,12 @@ function isCommentExempt(text17) {
3508
3508
  function toSingleLine(text17) {
3509
3509
  return text17.replace(/\s+/g, " ").trim();
3510
3510
  }
3511
- function collectSourceFindings(file, lines, project) {
3511
+ function collectSourceFindings(file, lines2, project) {
3512
3512
  const findings = [];
3513
3513
  const sourceFile = project.addSourceFileAtPath(file);
3514
3514
  for (const { pos, text: text17 } of collectComments(sourceFile)) {
3515
3515
  const { line } = sourceFile.getLineAndColumnAtPos(pos);
3516
- if (!lines.has(line)) continue;
3516
+ if (!lines2.has(line)) continue;
3517
3517
  if (isCommentExempt(text17)) continue;
3518
3518
  findings.push({ file, line, text: toSingleLine(text17) });
3519
3519
  }
@@ -3533,29 +3533,29 @@ function collectYamlComments(content) {
3533
3533
  }
3534
3534
 
3535
3535
  // src/commands/verify/blockCodeComments/collectFileComments.ts
3536
- function toFindings(file, lines, raw, exempt) {
3536
+ function toFindings(file, lines2, raw, exempt) {
3537
3537
  const findings = [];
3538
3538
  for (const { line, text: text17 } of raw) {
3539
- if (!lines.has(line)) continue;
3539
+ if (!lines2.has(line)) continue;
3540
3540
  if (exempt && isCommentExempt(text17)) continue;
3541
3541
  findings.push({ file, line, text: text17.replace(/\s+/g, " ").trim() });
3542
3542
  }
3543
3543
  return findings;
3544
3544
  }
3545
- function collectFileComments(file, lines, project) {
3545
+ function collectFileComments(file, lines2, project) {
3546
3546
  const read = () => fs14.readFileSync(file, "utf8");
3547
3547
  if (isYamlFile(file))
3548
- return toFindings(file, lines, collectYamlComments(read()), false);
3548
+ return toFindings(file, lines2, collectYamlComments(read()), false);
3549
3549
  if (isDockerfile(file) || isEnvFile(file) || isShellFile(file))
3550
3550
  return toFindings(
3551
3551
  file,
3552
- lines,
3552
+ lines2,
3553
3553
  collectHashComments(read(), { skipHeader: isShellFile(file) }),
3554
3554
  true
3555
3555
  );
3556
3556
  if (isBicepFile(file))
3557
- return toFindings(file, lines, collectBicepComments(read()), true);
3558
- return collectSourceFindings(file, lines, project);
3557
+ return toFindings(file, lines2, collectBicepComments(read()), true);
3558
+ return collectSourceFindings(file, lines2, project);
3559
3559
  }
3560
3560
 
3561
3561
  // src/commands/verify/blockCodeComments/parseDiffAddedLines.ts
@@ -3623,9 +3623,9 @@ function findComments(options2) {
3623
3623
  compilerOptions: { allowJs: true }
3624
3624
  });
3625
3625
  const findings = [];
3626
- for (const [file, lines] of addedLines) {
3626
+ for (const [file, lines2] of addedLines) {
3627
3627
  if (!shouldScan(file, options2.ignoreGlobs)) continue;
3628
- findings.push(...collectFileComments(file, lines, project));
3628
+ findings.push(...collectFileComments(file, lines2, project));
3629
3629
  }
3630
3630
  findings.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line);
3631
3631
  return findings;
@@ -3658,10 +3658,10 @@ function getDocumentedConfigKeys() {
3658
3658
  }
3659
3659
  function renderConfigHelp(entries, preamble) {
3660
3660
  const width = Math.max(...entries.map((entry) => entry.setter.length));
3661
- const lines = entries.map(
3661
+ const lines2 = entries.map(
3662
3662
  (entry) => ` ${entry.setter.padEnd(width)} # ${entry.note}`
3663
3663
  );
3664
- const body = preamble ? ["", preamble, "", "Config:", ...lines] : ["", "Config:", ...lines];
3664
+ const body = preamble ? ["", preamble, "", "Config:", ...lines2] : ["", "Config:", ...lines2];
3665
3665
  return body.join("\n");
3666
3666
  }
3667
3667
  function configHelp(command, entries, preamble) {
@@ -3960,14 +3960,14 @@ function findRuleViolations(data, rule) {
3960
3960
  }
3961
3961
  return violations;
3962
3962
  }
3963
- function findForbiddenStrings(rules, readJson) {
3964
- return rules.flatMap((rule) => findRuleViolations(readJson(rule.file), rule));
3963
+ function findForbiddenStrings(rules2, readJson) {
3964
+ return rules2.flatMap((rule) => findRuleViolations(readJson(rule.file), rule));
3965
3965
  }
3966
3966
 
3967
3967
  // src/commands/verify/forbiddenStrings/index.ts
3968
3968
  function forbiddenStrings() {
3969
- const rules = loadConfig().forbiddenStrings ?? [];
3970
- if (rules.length === 0) {
3969
+ const rules2 = loadConfig().forbiddenStrings ?? [];
3970
+ if (rules2.length === 0) {
3971
3971
  console.log("No forbidden-strings rules configured.");
3972
3972
  process.exit(0);
3973
3973
  }
@@ -3988,7 +3988,7 @@ function forbiddenStrings() {
3988
3988
  cache4.set(file, parsed);
3989
3989
  return parsed;
3990
3990
  };
3991
- const violations = findForbiddenStrings(rules, readJson);
3991
+ const violations = findForbiddenStrings(rules2, readJson);
3992
3992
  if (violations.length === 0) {
3993
3993
  console.log("No forbidden strings found.");
3994
3994
  process.exit(0);
@@ -4015,18 +4015,18 @@ function hardcodedColors() {
4015
4015
  const output = execSync13(`grep -rEnH '${pattern}' src/`, {
4016
4016
  encoding: "utf8"
4017
4017
  });
4018
- const lines = output.trim().split("\n").filter((line) => {
4018
+ const lines2 = output.trim().split("\n").filter((line) => {
4019
4019
  const match = line.match(/^(.+?):\d+:/);
4020
4020
  if (!match) return true;
4021
4021
  const file = match[1];
4022
4022
  return !ignoreGlobs.some((glob) => minimatch3(file, glob));
4023
4023
  });
4024
- if (lines.length === 0) {
4024
+ if (lines2.length === 0) {
4025
4025
  console.log("No hardcoded colors found.");
4026
4026
  process.exit(0);
4027
4027
  }
4028
4028
  console.log("Hardcoded colors found:\n");
4029
- for (const line of lines) {
4029
+ for (const line of lines2) {
4030
4030
  const match = line.match(/^(.+):(\d+):(.+)$/);
4031
4031
  if (match) {
4032
4032
  const [, file, lineNum, content] = match;
@@ -4036,7 +4036,7 @@ function hardcodedColors() {
4036
4036
  }
4037
4037
  }
4038
4038
  console.log(`
4039
- Total: ${lines.length} hardcoded color(s)`);
4039
+ Total: ${lines2.length} hardcoded color(s)`);
4040
4040
  console.log("\nUse colors from the 'open-color' (oc) library instead.");
4041
4041
  console.log("\nExample fix:");
4042
4042
  console.log(" Before: color: '#228be6'");
@@ -4523,7 +4523,7 @@ ${failed2.length} script(s) failed:`);
4523
4523
  }
4524
4524
  }
4525
4525
  function runEntry(entry) {
4526
- return new Promise((resolve21) => {
4526
+ return new Promise((resolve22) => {
4527
4527
  const startTime = Date.now();
4528
4528
  const child = spawnCommand(
4529
4529
  entry.fullCommand,
@@ -4535,7 +4535,7 @@ function runEntry(entry) {
4535
4535
  child.on("close", (code) => {
4536
4536
  const exitCode = code ?? 1;
4537
4537
  flushIfFailed(exitCode, chunks);
4538
- resolve21({
4538
+ resolve22({
4539
4539
  script: entry.name,
4540
4540
  code: exitCode,
4541
4541
  durationMs: Date.now() - startTime
@@ -5158,38 +5158,38 @@ var END_MARKER = "# <<< assist backup schedule <<<";
5158
5158
  function buildBlock(every, cronLine) {
5159
5159
  return [BEGIN_MARKER, `# every ${every}`, cronLine, END_MARKER];
5160
5160
  }
5161
- function findBlockRange(lines) {
5162
- const start3 = lines.indexOf(BEGIN_MARKER);
5161
+ function findBlockRange(lines2) {
5162
+ const start3 = lines2.indexOf(BEGIN_MARKER);
5163
5163
  if (start3 === -1) return void 0;
5164
- const end = lines.indexOf(END_MARKER, start3);
5164
+ const end = lines2.indexOf(END_MARKER, start3);
5165
5165
  if (end === -1) return void 0;
5166
5166
  return { start: start3, end };
5167
5167
  }
5168
5168
  function upsertScheduleBlock(crontab, every, cronLine) {
5169
- const lines = crontab.length === 0 ? [] : crontab.replace(/\n$/, "").split("\n");
5169
+ const lines2 = crontab.length === 0 ? [] : crontab.replace(/\n$/, "").split("\n");
5170
5170
  const block = buildBlock(every, cronLine);
5171
- const range = findBlockRange(lines);
5172
- const next3 = range === void 0 ? [...lines, ...block] : [
5173
- ...lines.slice(0, range.start),
5171
+ const range = findBlockRange(lines2);
5172
+ const next3 = range === void 0 ? [...lines2, ...block] : [
5173
+ ...lines2.slice(0, range.start),
5174
5174
  ...block,
5175
- ...lines.slice(range.end + 1)
5175
+ ...lines2.slice(range.end + 1)
5176
5176
  ];
5177
5177
  return `${next3.join("\n")}
5178
5178
  `;
5179
5179
  }
5180
5180
  function removeScheduleBlock(crontab) {
5181
- const lines = crontab.length === 0 ? [] : crontab.replace(/\n$/, "").split("\n");
5182
- const range = findBlockRange(lines);
5181
+ const lines2 = crontab.length === 0 ? [] : crontab.replace(/\n$/, "").split("\n");
5182
+ const range = findBlockRange(lines2);
5183
5183
  if (range === void 0) return crontab;
5184
- const next3 = [...lines.slice(0, range.start), ...lines.slice(range.end + 1)];
5184
+ const next3 = [...lines2.slice(0, range.start), ...lines2.slice(range.end + 1)];
5185
5185
  return next3.length === 0 ? "" : `${next3.join("\n")}
5186
5186
  `;
5187
5187
  }
5188
5188
  function readScheduleBlock(crontab) {
5189
- const lines = crontab.length === 0 ? [] : crontab.split("\n");
5190
- const range = findBlockRange(lines);
5189
+ const lines2 = crontab.length === 0 ? [] : crontab.split("\n");
5190
+ const range = findBlockRange(lines2);
5191
5191
  if (range === void 0) return void 0;
5192
- const body = lines.slice(range.start + 1, range.end);
5192
+ const body = lines2.slice(range.start + 1, range.end);
5193
5193
  const everyLine = body.find((line) => line.startsWith("# every "));
5194
5194
  const cronLine = body.find(
5195
5195
  (line) => !line.startsWith("#") && line.trim() !== ""
@@ -5705,8 +5705,8 @@ function spawnInherit(command, args, options2 = {}) {
5705
5705
  env,
5706
5706
  cwd: options2.cwd
5707
5707
  });
5708
- const done2 = new Promise((resolve21, reject) => {
5709
- child.on("close", (code) => resolve21(code ?? 0));
5708
+ const done2 = new Promise((resolve22, reject) => {
5709
+ child.on("close", (code) => resolve22(code ?? 0));
5710
5710
  child.on("error", reject);
5711
5711
  });
5712
5712
  return { child, done: done2 };
@@ -6851,9 +6851,9 @@ Failed to launch Claude for ${context}: ${message3}`)
6851
6851
  // src/commands/sessions/daemon/connectToDaemon.ts
6852
6852
  import * as net from "net";
6853
6853
  function connectToDaemon() {
6854
- return new Promise((resolve21, reject) => {
6854
+ return new Promise((resolve22, reject) => {
6855
6855
  const socket = net.connect(daemonPaths.socket);
6856
- socket.once("connect", () => resolve21(socket));
6856
+ socket.once("connect", () => resolve22(socket));
6857
6857
  socket.once("error", reject);
6858
6858
  });
6859
6859
  }
@@ -6869,7 +6869,7 @@ async function isDaemonRunning() {
6869
6869
  // src/commands/sessions/daemon/sendToDaemon.ts
6870
6870
  var WRITE_TIMEOUT_MS = 500;
6871
6871
  function sendToDaemon(message3) {
6872
- return new Promise((resolve21, reject) => {
6872
+ return new Promise((resolve22, reject) => {
6873
6873
  connectToDaemon().then((socket) => {
6874
6874
  const timer = setTimeout(() => {
6875
6875
  socket.destroy();
@@ -6883,7 +6883,7 @@ function sendToDaemon(message3) {
6883
6883
  `, () => {
6884
6884
  clearTimeout(timer);
6885
6885
  socket.end();
6886
- resolve21();
6886
+ resolve22();
6887
6887
  });
6888
6888
  }, reject);
6889
6889
  });
@@ -6906,7 +6906,7 @@ function readSocketLines(socket, onLine) {
6906
6906
  // src/commands/sessions/daemon/sendToDaemonAwaitAck.ts
6907
6907
  var ACK_TIMEOUT_MS = 1e3;
6908
6908
  function sendToDaemonAwaitAck(message3) {
6909
- return new Promise((resolve21, reject) => {
6909
+ return new Promise((resolve22, reject) => {
6910
6910
  connectToDaemon().then((socket) => {
6911
6911
  let settled = false;
6912
6912
  const finish = (error) => {
@@ -6915,7 +6915,7 @@ function sendToDaemonAwaitAck(message3) {
6915
6915
  clearTimeout(timer);
6916
6916
  socket.destroy();
6917
6917
  if (error) reject(error);
6918
- else resolve21();
6918
+ else resolve22();
6919
6919
  };
6920
6920
  const timer = setTimeout(
6921
6921
  () => finish(new Error("timed out awaiting daemon ack")),
@@ -6989,7 +6989,7 @@ async function deliverReliably(sessionId, status3, payload) {
6989
6989
  }
6990
6990
  }
6991
6991
  function sleep(ms) {
6992
- return new Promise((resolve21) => setTimeout(resolve21, ms));
6992
+ return new Promise((resolve22) => setTimeout(resolve22, ms));
6993
6993
  }
6994
6994
  function describeError(error) {
6995
6995
  return error instanceof Error ? error.message : String(error);
@@ -7631,14 +7631,14 @@ function backlogRunMarkers(text17) {
7631
7631
  }
7632
7632
 
7633
7633
  // src/commands/sessions/shared/extractSessionMeta.ts
7634
- function extractSessionMeta(lines) {
7634
+ function extractSessionMeta(lines2) {
7635
7635
  let sessionId = "";
7636
7636
  let cwd = "";
7637
7637
  let timestamp6 = "";
7638
7638
  let name = "";
7639
7639
  let commandName = "";
7640
7640
  let commandArgs = "";
7641
- for (const line of lines) {
7641
+ for (const line of lines2) {
7642
7642
  const entry = safeParse(line);
7643
7643
  if (!entry) continue;
7644
7644
  sessionId ||= strField(entry, "sessionId");
@@ -8645,7 +8645,7 @@ function spawnDaemon(reason4) {
8645
8645
  child.unref();
8646
8646
  }
8647
8647
  function delay(ms) {
8648
- return new Promise((resolve21) => setTimeout(resolve21, ms));
8648
+ return new Promise((resolve22) => setTimeout(resolve22, ms));
8649
8649
  }
8650
8650
 
8651
8651
  // src/commands/sessions/daemon/isWindowsCwd.ts
@@ -8682,10 +8682,10 @@ function gitInvocation(cwd, args) {
8682
8682
  }
8683
8683
  function git2(cwd, args) {
8684
8684
  const { file, argv, options: options2 } = gitInvocation(cwd, args);
8685
- return new Promise((resolve21, reject) => {
8685
+ return new Promise((resolve22, reject) => {
8686
8686
  execFile2(file, argv, options2, (error, stdout) => {
8687
8687
  if (error) reject(error);
8688
- else resolve21(stdout.toString());
8688
+ else resolve22(stdout.toString());
8689
8689
  });
8690
8690
  });
8691
8691
  }
@@ -9097,12 +9097,12 @@ async function loadVisibleItems(req) {
9097
9097
 
9098
9098
  // src/commands/backlog/web/parseStatusBody.ts
9099
9099
  function readBody(req) {
9100
- return new Promise((resolve21, reject) => {
9100
+ return new Promise((resolve22, reject) => {
9101
9101
  let body = "";
9102
9102
  req.on("data", (chunk) => {
9103
9103
  body += chunk.toString();
9104
9104
  });
9105
- req.on("end", () => resolve21(body));
9105
+ req.on("end", () => resolve22(body));
9106
9106
  req.on("error", reject);
9107
9107
  });
9108
9108
  }
@@ -10586,17 +10586,17 @@ async function stopDaemon() {
10586
10586
  }
10587
10587
  }
10588
10588
  function closedBeforeTimeout(socket) {
10589
- return new Promise((resolve21) => {
10589
+ return new Promise((resolve22) => {
10590
10590
  const timer = setTimeout(() => {
10591
10591
  socket.destroy();
10592
- resolve21(false);
10592
+ resolve22(false);
10593
10593
  }, STOP_TIMEOUT_MS);
10594
10594
  socket.resume();
10595
10595
  socket.on("error", () => {
10596
10596
  });
10597
10597
  socket.once("close", () => {
10598
10598
  clearTimeout(timer);
10599
- resolve21(true);
10599
+ resolve22(true);
10600
10600
  });
10601
10601
  });
10602
10602
  }
@@ -10647,8 +10647,8 @@ async function restartWeb(req, res, deps2 = {}) {
10647
10647
  respondJson(res, 400, { error: "Invalid target" });
10648
10648
  return;
10649
10649
  }
10650
- await new Promise((resolve21) => {
10651
- res.once("finish", resolve21);
10650
+ await new Promise((resolve22) => {
10651
+ res.once("finish", resolve22);
10652
10652
  respondJson(res, 200, { ok: true });
10653
10653
  });
10654
10654
  if (target === "daemon" || target === "both") {
@@ -11185,8 +11185,8 @@ async function runGhImage(filePath, cwd) {
11185
11185
  `gh image failed: ${stderr.trim() || err.message || "unknown error"}`
11186
11186
  );
11187
11187
  }
11188
- const lines = stdout.split("\n").map((line) => line.trim()).filter(Boolean);
11189
- const markdown = lines.find((line) => /^!\[.*]\(.+\)$/.test(line)) ?? lines.find((line) => line.includes("http")) ?? lines[0];
11188
+ const lines2 = stdout.split("\n").map((line) => line.trim()).filter(Boolean);
11189
+ const markdown = lines2.find((line) => /^!\[.*]\(.+\)$/.test(line)) ?? lines2.find((line) => line.includes("http")) ?? lines2[0];
11190
11190
  if (!markdown) throw new Error("gh image produced no output");
11191
11191
  return markdown;
11192
11192
  }
@@ -11377,10 +11377,10 @@ async function openDaemonConnection(ws, ctx) {
11377
11377
  }
11378
11378
  }
11379
11379
  function relayDaemonLines(conn, ws, repoCwd) {
11380
- const lines = createInterface2({ input: conn });
11381
- lines.on("error", () => {
11380
+ const lines2 = createInterface2({ input: conn });
11381
+ lines2.on("error", () => {
11382
11382
  });
11383
- lines.on("line", (line) => {
11383
+ lines2.on("line", (line) => {
11384
11384
  if (ws.readyState === ws.OPEN) ws.send(withRepoCwd(line, repoCwd));
11385
11385
  });
11386
11386
  conn.on("error", () => {
@@ -11522,7 +11522,7 @@ function firstEnabledIndex(items2) {
11522
11522
  // src/commands/sessions/web/restartMenu/renderRestartMenu.ts
11523
11523
  import chalk59 from "chalk";
11524
11524
  function renderRestartMenu(items2, selected) {
11525
- const lines = [chalk59.bold.cyan("assist \u2014 restart menu")];
11525
+ const lines2 = [chalk59.bold.cyan("assist \u2014 restart menu")];
11526
11526
  items2.forEach((item, i) => {
11527
11527
  const active = i === selected;
11528
11528
  const pointer = active ? chalk59.cyan("\u276F ") : " ";
@@ -11531,10 +11531,10 @@ function renderRestartMenu(items2, selected) {
11531
11531
  let label2 = item.label;
11532
11532
  if (item.disabled) label2 = chalk59.dim(label2);
11533
11533
  else if (active) label2 = chalk59.cyan.bold(label2);
11534
- lines.push(`${pointer}${number}${label2}${note}`);
11534
+ lines2.push(`${pointer}${number}${label2}${note}`);
11535
11535
  });
11536
- lines.push(chalk59.dim("\u2191/\u2193 move \xB7 1-3 jump \xB7 enter select \xB7 esc close"));
11537
- return lines.join("\n");
11536
+ lines2.push(chalk59.dim("\u2191/\u2193 move \xB7 1-3 jump \xB7 enter select \xB7 esc close"));
11537
+ return lines2.join("\n");
11538
11538
  }
11539
11539
 
11540
11540
  // src/commands/sessions/web/restartMenu/createMenuState.ts
@@ -11660,10 +11660,10 @@ async function connect2() {
11660
11660
  }
11661
11661
  }
11662
11662
  function wire(socket) {
11663
- const lines = createInterface3({ input: socket });
11664
- lines.on("error", () => {
11663
+ const lines2 = createInterface3({ input: socket });
11664
+ lines2.on("error", () => {
11665
11665
  });
11666
- lines.on("line", emit);
11666
+ lines2.on("line", emit);
11667
11667
  socket.on("error", () => {
11668
11668
  });
11669
11669
  socket.on("close", scheduleReconnect);
@@ -12203,11 +12203,11 @@ async function countRows(client, table) {
12203
12203
  return rows[0].n;
12204
12204
  }
12205
12205
  function printSummary(tables, current, incoming) {
12206
- const lines = tables.map(
12206
+ const lines2 = tables.map(
12207
12207
  (t, i) => ` ${t.name}: ${current[i]} \u2192 ${incoming[i]} rows`
12208
12208
  );
12209
12209
  console.error(chalk71.bold("\nThis will REPLACE all backlog data:"));
12210
- console.error(`${lines.join("\n")}
12210
+ console.error(`${lines2.join("\n")}
12211
12211
  `);
12212
12212
  }
12213
12213
  async function confirmReplace(client, tables, incoming, fromStdin) {
@@ -12600,7 +12600,7 @@ function parsePreviewDecision(line, requestId) {
12600
12600
 
12601
12601
  // src/commands/sessions/shared/requestPreviewDecision.ts
12602
12602
  function requestPreviewDecision(request) {
12603
- return new Promise((resolve21, reject) => {
12603
+ return new Promise((resolve22, reject) => {
12604
12604
  connectToDaemon().then((socket) => {
12605
12605
  let settled = false;
12606
12606
  const finish = (error, decision) => {
@@ -12608,7 +12608,7 @@ function requestPreviewDecision(request) {
12608
12608
  settled = true;
12609
12609
  socket.destroy();
12610
12610
  if (error) reject(error);
12611
- else resolve21(decision);
12611
+ else resolve22(decision);
12612
12612
  };
12613
12613
  readSocketLines(socket, (line) => {
12614
12614
  const incoming = parsePreviewDecision(line, request.requestId);
@@ -14859,13 +14859,13 @@ function saveCliReads(commands) {
14859
14859
  );
14860
14860
  cachedReads = void 0;
14861
14861
  }
14862
- function findMatch(command, lines) {
14862
+ function findMatch(command, lines2) {
14863
14863
  const words = command.split(/\s+/);
14864
14864
  if (words.length === 0) return void 0;
14865
- if (lines.includes(words[0])) return words[0];
14865
+ if (lines2.includes(words[0])) return words[0];
14866
14866
  if (words.length < 2) return void 0;
14867
14867
  const prefix2 = `${words[0]} ${words[1]}`;
14868
- const candidates = lines.filter(
14868
+ const candidates = lines2.filter(
14869
14869
  (line) => line === prefix2 || line.startsWith(`${prefix2} `)
14870
14870
  );
14871
14871
  return candidates.sort((a, b) => b.length - a.length).find((rc) => command === rc || command.startsWith(`${rc} `));
@@ -15299,12 +15299,12 @@ function hasSubcommands(helpText) {
15299
15299
  // src/commands/permitCliReads/runHelp.ts
15300
15300
  import { exec as exec2 } from "child_process";
15301
15301
  function runHelp(args) {
15302
- return new Promise((resolve21) => {
15302
+ return new Promise((resolve22) => {
15303
15303
  exec2(
15304
15304
  `${args.join(" ")} --help`,
15305
15305
  { encoding: "utf8", timeout: 3e4 },
15306
15306
  (_err, stdout, stderr) => {
15307
- resolve21(stdout || stderr || "");
15307
+ resolve22(stdout || stderr || "");
15308
15308
  }
15309
15309
  );
15310
15310
  });
@@ -15432,14 +15432,14 @@ function formatHuman(cli, commands) {
15432
15432
  const sorted = [...commands].sort(
15433
15433
  (a, b) => a.path.join(" ").localeCompare(b.path.join(" "))
15434
15434
  );
15435
- const lines = [`Discovered ${commands.length} commands for "${cli}":
15435
+ const lines2 = [`Discovered ${commands.length} commands for "${cli}":
15436
15436
  `];
15437
15437
  for (const cmd of sorted) {
15438
15438
  const full = `${cli} ${cmd.path.join(" ")}`;
15439
15439
  const text17 = cmd.description ? `${full} \u2014 ${cmd.description}` : full;
15440
- lines.push(`${prefix(classifyVerb(cmd.path))}${text17}`);
15440
+ lines2.push(`${prefix(classifyVerb(cmd.path))}${text17}`);
15441
15441
  }
15442
- return lines.join("\n");
15442
+ return lines2.join("\n");
15443
15443
  }
15444
15444
 
15445
15445
  // src/commands/permitCliReads/parseCached.ts
@@ -15686,22 +15686,22 @@ function codeCommentConfirm(pin) {
15686
15686
  return;
15687
15687
  }
15688
15688
  const original = readFileSync29(state.file, "utf8");
15689
- const lines = original.split("\n");
15689
+ const lines2 = original.split("\n");
15690
15690
  const index3 = state.line - 1;
15691
- if (index3 > lines.length) {
15691
+ if (index3 > lines2.length) {
15692
15692
  console.error(
15693
15693
  chalk118.red(
15694
- `Line ${state.line} is beyond the end of ${state.file} (${lines.length} lines).`
15694
+ `Line ${state.line} is beyond the end of ${state.file} (${lines2.length} lines).`
15695
15695
  )
15696
15696
  );
15697
15697
  process.exitCode = 1;
15698
15698
  return;
15699
15699
  }
15700
15700
  const marker = isHashCommentFile(state.file) ? "#" : "//";
15701
- const indentSource = lines[index3] ?? "";
15701
+ const indentSource = lines2[index3] ?? "";
15702
15702
  const indent2 = indentSource.match(/^\s*/)?.[0] ?? "";
15703
- lines.splice(index3, 0, `${indent2}${marker} ${state.text}`);
15704
- writeFileSync24(state.file, lines.join("\n"));
15703
+ lines2.splice(index3, 0, `${indent2}${marker} ${state.text}`);
15704
+ writeFileSync24(state.file, lines2.join("\n"));
15705
15705
  unlinkSync8(getPinStatePath(pin));
15706
15706
  console.log(
15707
15707
  chalk118.green(
@@ -16413,17 +16413,17 @@ async function sloc(pattern2 = "**/*.ts", options2 = {}) {
16413
16413
  let hasViolation = false;
16414
16414
  for (const file of files) {
16415
16415
  const content = fs22.readFileSync(file, "utf8");
16416
- const lines = countSloc(content);
16417
- results.push({ file, lines });
16418
- if (options2.threshold !== void 0 && lines > options2.threshold) {
16416
+ const lines2 = countSloc(content);
16417
+ results.push({ file, lines: lines2 });
16418
+ if (options2.threshold !== void 0 && lines2 > options2.threshold) {
16419
16419
  hasViolation = true;
16420
16420
  }
16421
16421
  }
16422
16422
  results.sort((a, b) => b.lines - a.lines);
16423
- for (const { file, lines } of results) {
16424
- const exceedsThreshold = options2.threshold !== void 0 && lines > options2.threshold;
16423
+ for (const { file, lines: lines2 } of results) {
16424
+ const exceedsThreshold = options2.threshold !== void 0 && lines2 > options2.threshold;
16425
16425
  const color = exceedsThreshold ? chalk127.red : chalk127.white;
16426
- console.log(`${color(file)} \u2192 ${chalk127.cyan(lines)} lines`);
16426
+ console.log(`${color(file)} \u2192 ${chalk127.cyan(lines2)} lines`);
16427
16427
  }
16428
16428
  const total = results.reduce((sum, r) => sum + r.lines, 0);
16429
16429
  console.log(
@@ -17010,9 +17010,9 @@ function printCommitsWithFiles(commits2, ignore3, verbose) {
17010
17010
  }
17011
17011
  }
17012
17012
  function parseGitLogCommits(output, ignore3, afterDate) {
17013
- const lines = output.trim().split("\n");
17013
+ const lines2 = output.trim().split("\n");
17014
17014
  const commitsByDate = /* @__PURE__ */ new Map();
17015
- for (const line of lines) {
17015
+ for (const line of lines2) {
17016
17016
  const [date, hash, ...messageParts] = line.split("|");
17017
17017
  const message3 = messageParts.join("|");
17018
17018
  if (afterDate && date <= afterDate) {
@@ -18108,12 +18108,12 @@ function isHeaderLine2(line) {
18108
18108
  return trimmed === "" || trimmed.startsWith("#");
18109
18109
  }
18110
18110
  function extractShellComments(text17) {
18111
- const lines = text17.split("\n");
18111
+ const lines2 = text17.split("\n");
18112
18112
  let firstCodeLine = 0;
18113
- while (firstCodeLine < lines.length && isHeaderLine2(lines[firstCodeLine])) {
18113
+ while (firstCodeLine < lines2.length && isHeaderLine2(lines2[firstCodeLine])) {
18114
18114
  firstCodeLine++;
18115
18115
  }
18116
- return extractYamlComments(lines.slice(firstCodeLine).join("\n"));
18116
+ return extractYamlComments(lines2.slice(firstCodeLine).join("\n"));
18117
18117
  }
18118
18118
 
18119
18119
  // src/commands/editHook/introducedComments.ts
@@ -19424,7 +19424,7 @@ function placedByDaemon() {
19424
19424
  function seed(worktreePath, clone) {
19425
19425
  console.log(`Preparing ${worktreePath}\u2026`);
19426
19426
  return new Promise(
19427
- (resolve21) => seedWorktree(worktreePath, clone, resolve21)
19427
+ (resolve22) => seedWorktree(worktreePath, clone, resolve22)
19428
19428
  );
19429
19429
  }
19430
19430
  async function moveToPrCheckoutTree() {
@@ -19931,25 +19931,25 @@ function isVisibleText(t) {
19931
19931
  return /[a-zA-Z]{3,}/.test(t);
19932
19932
  }
19933
19933
  var isHashtag = (t) => /^#[A-Za-z0-9_]+$/.test(t);
19934
- function collectRscText(v, resolve21, sink2, seen) {
19934
+ function collectRscText(v, resolve22, sink2, seen) {
19935
19935
  if (v == null) return;
19936
19936
  if (typeof v === "string") {
19937
19937
  if (isRscRef(v)) {
19938
19938
  if (!seen.has(v)) {
19939
19939
  seen.add(v);
19940
- collectRscText(resolve21(v), resolve21, sink2, seen);
19940
+ collectRscText(resolve22(v), resolve22, sink2, seen);
19941
19941
  }
19942
19942
  } else if (isHashtag(v)) sink2.hashtags.push(v);
19943
19943
  else if (isVisibleText(v)) sink2.text.push(v);
19944
19944
  return;
19945
19945
  }
19946
19946
  if (Array.isArray(v)) {
19947
- for (const x of v) collectRscText(x, resolve21, sink2, seen);
19947
+ for (const x of v) collectRscText(x, resolve22, sink2, seen);
19948
19948
  return;
19949
19949
  }
19950
19950
  if (typeof v === "object") {
19951
19951
  for (const val of Object.values(v)) {
19952
- collectRscText(val, resolve21, sink2, seen);
19952
+ collectRscText(val, resolve22, sink2, seen);
19953
19953
  }
19954
19954
  }
19955
19955
  }
@@ -19981,7 +19981,7 @@ function visitObjects(root, fn) {
19981
19981
  }
19982
19982
  }
19983
19983
  }
19984
- function buildMentionMap(rows, resolve21) {
19984
+ function buildMentionMap(rows, resolve22) {
19985
19985
  const map = /* @__PURE__ */ new Map();
19986
19986
  visitObjects(rows, (o) => {
19987
19987
  const url = profileActionUrl(o);
@@ -19989,7 +19989,7 @@ function buildMentionMap(rows, resolve21) {
19989
19989
  const slug = slugFromProfileUrl(url);
19990
19990
  if (!slug || map.has(slug)) return;
19991
19991
  const sink2 = { text: [], hashtags: [] };
19992
- collectRscText(o.children, resolve21, sink2, /* @__PURE__ */ new Set());
19992
+ collectRscText(o.children, resolve22, sink2, /* @__PURE__ */ new Set());
19993
19993
  const name = sink2.text.join(" ").replace(/\s+/g, " ").trim();
19994
19994
  map.set(slug, name ? { slug, name, url } : { slug, url });
19995
19995
  });
@@ -20075,10 +20075,10 @@ function buildPost(raw, mentionMap, author) {
20075
20075
 
20076
20076
  // src/commands/netcap/walkPostRow.ts
20077
20077
  var isCommentary = (o) => asObject(o.viewTrackingSpecs)?.viewName === "feed-commentary";
20078
- function walkPostRow(v, resolve21, raw) {
20078
+ function walkPostRow(v, resolve22, raw) {
20079
20079
  if (v == null || typeof v !== "object") return;
20080
20080
  if (Array.isArray(v)) {
20081
- for (const x of v) walkPostRow(x, resolve21, raw);
20081
+ for (const x of v) walkPostRow(x, resolve22, raw);
20082
20082
  return;
20083
20083
  }
20084
20084
  const o = v;
@@ -20092,9 +20092,9 @@ function walkPostRow(v, resolve21, raw) {
20092
20092
  }
20093
20093
  if (isCommentary(o)) {
20094
20094
  const sink2 = { text: raw.text, hashtags: raw.hashtags };
20095
- collectRscText(o.children, resolve21, sink2, /* @__PURE__ */ new Set());
20095
+ collectRscText(o.children, resolve22, sink2, /* @__PURE__ */ new Set());
20096
20096
  }
20097
- for (const val of Object.values(o)) walkPostRow(val, resolve21, raw);
20097
+ for (const val of Object.values(o)) walkPostRow(val, resolve22, raw);
20098
20098
  }
20099
20099
 
20100
20100
  // src/commands/netcap/extractLinkedInPosts.ts
@@ -20108,8 +20108,8 @@ function findCommentaryRows(rows) {
20108
20108
  }
20109
20109
  function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
20110
20110
  const rows = parseRscRows(flight);
20111
- const resolve21 = makeRscResolver(rows);
20112
- const mentionMap = buildMentionMap(rows, resolve21);
20111
+ const resolve22 = makeRscResolver(rows);
20112
+ const mentionMap = buildMentionMap(rows, resolve22);
20113
20113
  const posts = [];
20114
20114
  for (const id of findCommentaryRows(rows)) {
20115
20115
  const raw = {
@@ -20119,7 +20119,7 @@ function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
20119
20119
  links: [],
20120
20120
  related: []
20121
20121
  };
20122
- walkPostRow(rows[id], resolve21, raw);
20122
+ walkPostRow(rows[id], resolve22, raw);
20123
20123
  const post = buildPost(raw, mentionMap, author);
20124
20124
  if (post) posts.push(post);
20125
20125
  }
@@ -20288,9 +20288,9 @@ function extractVoyagerPosts(body) {
20288
20288
 
20289
20289
  // src/commands/netcap/extractPostsFromCapture.ts
20290
20290
  function captureEntries(captureFile) {
20291
- const lines = readFileSync39(captureFile, "utf8").split("\n").filter(Boolean);
20291
+ const lines2 = readFileSync39(captureFile, "utf8").split("\n").filter(Boolean);
20292
20292
  const entries = [];
20293
- for (const line of lines) {
20293
+ for (const line of lines2) {
20294
20294
  let entry;
20295
20295
  try {
20296
20296
  entry = JSON.parse(line);
@@ -20730,11 +20730,11 @@ function findWallOfText(body) {
20730
20730
  function splitParagraphs(body) {
20731
20731
  const paragraphs = [];
20732
20732
  let section3 = "(intro)";
20733
- let lines = [];
20733
+ let lines2 = [];
20734
20734
  const flush = () => {
20735
- if (lines.length > 0) {
20736
- paragraphs.push({ section: section3, lines });
20737
- lines = [];
20735
+ if (lines2.length > 0) {
20736
+ paragraphs.push({ section: section3, lines: lines2 });
20737
+ lines2 = [];
20738
20738
  }
20739
20739
  };
20740
20740
  for (const line of body.split("\n")) {
@@ -20745,17 +20745,17 @@ function splitParagraphs(body) {
20745
20745
  } else if (line.trim() === "") {
20746
20746
  flush();
20747
20747
  } else {
20748
- lines.push(line);
20748
+ lines2.push(line);
20749
20749
  }
20750
20750
  }
20751
20751
  flush();
20752
20752
  return paragraphs;
20753
20753
  }
20754
- function isWallOfText(lines) {
20755
- if (lines.some(isListLine)) {
20754
+ function isWallOfText(lines2) {
20755
+ if (lines2.some(isListLine)) {
20756
20756
  return false;
20757
20757
  }
20758
- const text17 = lines.join(" ").trim();
20758
+ const text17 = lines2.join(" ").trim();
20759
20759
  return text17.length > MAX_PARAGRAPH_CHARS || countSentences(text17) > MAX_PARAGRAPH_SENTENCES;
20760
20760
  }
20761
20761
  function countSentences(paragraph) {
@@ -22198,9 +22198,9 @@ function parseRefactorYml() {
22198
22198
  }
22199
22199
  const content = fs24.readFileSync(REFACTOR_YML_PATH, "utf8");
22200
22200
  const entries = [];
22201
- const lines = content.split("\n");
22201
+ const lines2 = content.split("\n");
22202
22202
  let currentEntry = {};
22203
- for (const line of lines) {
22203
+ for (const line of lines2) {
22204
22204
  const trimmed = line.trim();
22205
22205
  if (trimmed.startsWith("- file:")) {
22206
22206
  if (currentEntry.file) {
@@ -22273,7 +22273,7 @@ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES) {
22273
22273
 
22274
22274
  // src/commands/refactor/check/index.ts
22275
22275
  function runScript(script, cwd) {
22276
- return new Promise((resolve21) => {
22276
+ return new Promise((resolve22) => {
22277
22277
  const child = spawn6("npm", ["run", script], {
22278
22278
  stdio: "pipe",
22279
22279
  shell: true,
@@ -22287,7 +22287,7 @@ function runScript(script, cwd) {
22287
22287
  output += data.toString();
22288
22288
  });
22289
22289
  child.on("close", (code) => {
22290
- resolve21({ script, code: code ?? 1, output });
22290
+ resolve22({ script, code: code ?? 1, output });
22291
22291
  });
22292
22292
  });
22293
22293
  }
@@ -22788,22 +22788,22 @@ function formatImportLine(imp) {
22788
22788
 
22789
22789
  // src/commands/refactor/extract/buildDestinationContent.ts
22790
22790
  function buildDestinationContent(functionTexts, imports, sourceRelativePath, sourceImportNames) {
22791
- const lines = [];
22791
+ const lines2 = [];
22792
22792
  for (const imp of imports) {
22793
- lines.push(formatImportLine(imp));
22793
+ lines2.push(formatImportLine(imp));
22794
22794
  }
22795
22795
  if (sourceImportNames.length > 0) {
22796
- lines.push(
22796
+ lines2.push(
22797
22797
  `import { ${sourceImportNames.join(", ")} } from "${sourceRelativePath}";`
22798
22798
  );
22799
22799
  }
22800
- if (lines.length > 0) lines.push("");
22800
+ if (lines2.length > 0) lines2.push("");
22801
22801
  for (let i = 0; i < functionTexts.length; i++) {
22802
- if (i > 0) lines.push("");
22803
- lines.push(functionTexts[i]);
22802
+ if (i > 0) lines2.push("");
22803
+ lines2.push(functionTexts[i]);
22804
22804
  }
22805
- lines.push("");
22806
- return lines.join("\n");
22805
+ lines2.push("");
22806
+ return lines2.join("\n");
22807
22807
  }
22808
22808
 
22809
22809
  // src/commands/refactor/extract/getRelativeImportPath.ts
@@ -23414,9 +23414,9 @@ function groupReferences(symbol, cwd) {
23414
23414
  const grouped = /* @__PURE__ */ new Map();
23415
23415
  for (const ref of refs) {
23416
23416
  const refFile = path50.relative(cwd, ref.getSourceFile().getFilePath());
23417
- const lines = grouped.get(refFile) ?? [];
23418
- if (!grouped.has(refFile)) grouped.set(refFile, lines);
23419
- lines.push(ref.getStartLineNumber());
23417
+ const lines2 = grouped.get(refFile) ?? [];
23418
+ if (!grouped.has(refFile)) grouped.set(refFile, lines2);
23419
+ lines2.push(ref.getStartLineNumber());
23420
23420
  }
23421
23421
  return grouped;
23422
23422
  }
@@ -23436,9 +23436,9 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
23436
23436
  chalk189.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
23437
23437
  `)
23438
23438
  );
23439
- for (const [refFile, lines] of grouped) {
23439
+ for (const [refFile, lines2] of grouped) {
23440
23440
  console.log(
23441
- ` ${chalk189.dim(refFile)}: lines ${chalk189.cyan(lines.join(", "))}`
23441
+ ` ${chalk189.dim(refFile)}: lines ${chalk189.cyan(lines2.join(", "))}`
23442
23442
  );
23443
23443
  }
23444
23444
  if (options2.apply) {
@@ -23879,12 +23879,12 @@ function headerFor(c) {
23879
23879
  return tags ? `### ${location} [${tags}]` : `### ${location}`;
23880
23880
  }
23881
23881
  function formatThread(thread) {
23882
- const lines = [
23882
+ const lines2 = [
23883
23883
  headerFor(thread.root),
23884
23884
  `**${thread.root.author}**: ${thread.root.body.trim()}`,
23885
23885
  ...thread.replies.map((r) => `**${r.author}** (reply): ${r.body.trim()}`)
23886
23886
  ];
23887
- return lines.join("\n\n");
23887
+ return lines2.join("\n\n");
23888
23888
  }
23889
23889
  var INTRO = `The PR already has the review comments below (including resolved and outdated threads). Avoid re-raising findings that a prior comment substantively covers.`;
23890
23890
  function formatPriorComments(comments3) {
@@ -24191,13 +24191,13 @@ function summariseSynthesis(markdown) {
24191
24191
  return { summary: extractSummary(markdown), totals, findingCount };
24192
24192
  }
24193
24193
  function formatSynthesisSummary(summary) {
24194
- const lines = [];
24194
+ const lines2 = [];
24195
24195
  const { totals, findingCount } = summary;
24196
- lines.push(
24196
+ lines2.push(
24197
24197
  `Findings: ${findingCount} (blocker ${totals.blocker}, major ${totals.major}, minor ${totals.minor}, nit ${totals.nit})`
24198
24198
  );
24199
- if (summary.summary) lines.push("", summary.summary);
24200
- return lines.join("\n");
24199
+ if (summary.summary) lines2.push("", summary.summary);
24200
+ return lines2.join("\n");
24201
24201
  }
24202
24202
 
24203
24203
  // src/commands/review/buildReviewSummary.ts
@@ -24208,12 +24208,12 @@ function formatFindingLine(finding) {
24208
24208
  function buildReviewSummary(markdown) {
24209
24209
  const summary = summariseSynthesis(markdown);
24210
24210
  const findings = parseFindings(markdown);
24211
- const lines = ["## Code review summary", "", formatSynthesisSummary(summary)];
24211
+ const lines2 = ["## Code review summary", "", formatSynthesisSummary(summary)];
24212
24212
  if (findings.length > 0) {
24213
- lines.push("", "### Findings", "");
24214
- for (const finding of findings) lines.push(formatFindingLine(finding));
24213
+ lines2.push("", "### Findings", "");
24214
+ for (const finding of findings) lines2.push(formatFindingLine(finding));
24215
24215
  }
24216
- return lines.join("\n");
24216
+ return lines2.join("\n");
24217
24217
  }
24218
24218
 
24219
24219
  // src/commands/review/sanitiseReviewerNames.ts
@@ -24224,13 +24224,13 @@ function sanitiseReviewerNames(value) {
24224
24224
 
24225
24225
  // src/commands/review/postFindings.ts
24226
24226
  function buildCommentBody(finding) {
24227
- const lines = [];
24227
+ const lines2 = [];
24228
24228
  const severityLabel = finding.severity ?? "finding";
24229
- lines.push(`**${severityLabel}: ${finding.title}**`);
24230
- if (finding.impact) lines.push("", `Impact: ${finding.impact}`);
24229
+ lines2.push(`**${severityLabel}: ${finding.title}**`);
24230
+ if (finding.impact) lines2.push("", `Impact: ${finding.impact}`);
24231
24231
  if (finding.recommendation)
24232
- lines.push("", `Recommendation: ${finding.recommendation}`);
24233
- return sanitiseReviewerNames(lines.join("\n"));
24232
+ lines2.push("", `Recommendation: ${finding.recommendation}`);
24233
+ return sanitiseReviewerNames(lines2.join("\n"));
24234
24234
  }
24235
24235
  function postFindings(findings) {
24236
24236
  let posted = 0;
@@ -24329,10 +24329,10 @@ function buildDiffLineIndex(diff3) {
24329
24329
 
24330
24330
  // src/commands/review/partitionFindingsByDiff.ts
24331
24331
  function isWithinDiff(finding, index3) {
24332
- const lines = index3.get(finding.file);
24333
- if (!lines) return false;
24334
- if (!lines.has(finding.line)) return false;
24335
- if (finding.startLine !== void 0 && !lines.has(finding.startLine)) {
24332
+ const lines2 = index3.get(finding.file);
24333
+ if (!lines2) return false;
24334
+ if (!lines2.has(finding.line)) return false;
24335
+ if (finding.startLine !== void 0 && !lines2.has(finding.startLine)) {
24336
24336
  return false;
24337
24337
  }
24338
24338
  return true;
@@ -24723,8 +24723,8 @@ function indent(text17) {
24723
24723
  return text17.split(/\r?\n/).map((line) => ` ${line}`);
24724
24724
  }
24725
24725
  function tailLines(text17, maxLines) {
24726
- const lines = text17.split(/\r?\n/);
24727
- return lines.length <= maxLines ? text17 : lines.slice(-maxLines).join("\n");
24726
+ const lines2 = text17.split(/\r?\n/);
24727
+ return lines2.length <= maxLines ? text17 : lines2.slice(-maxLines).join("\n");
24728
24728
  }
24729
24729
  function isFastFail(input) {
24730
24730
  return input.exitCode !== 0 && input.elapsedMs !== void 0 && input.elapsedMs < FAST_FAIL_MS;
@@ -25096,12 +25096,12 @@ function onCloseResult(ctx, code) {
25096
25096
  return { ...closed, stderr: ctx.stderr.value, stdout: ctx.stdout.value };
25097
25097
  }
25098
25098
  function waitForChildExit(ctx) {
25099
- return new Promise((resolve21) => {
25099
+ return new Promise((resolve22) => {
25100
25100
  let settled = false;
25101
25101
  const settle = (result) => {
25102
25102
  if (settled) return;
25103
25103
  settled = true;
25104
- resolve21(result);
25104
+ resolve22(result);
25105
25105
  };
25106
25106
  ctx.child.on("error", (err) => settle(onErrorResult(ctx, err)));
25107
25107
  ctx.child.on("close", (code) => settle(onCloseResult(ctx, code)));
@@ -25756,13 +25756,13 @@ function formatEvent(event) {
25756
25756
  const abbrev = levelAbbrev(event.Level);
25757
25757
  const ts8 = chalk198.dim(formatTimestamp(event.Timestamp));
25758
25758
  const msg = renderMessage(event);
25759
- const lines = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
25759
+ const lines2 = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
25760
25760
  if (event.Exception) {
25761
25761
  for (const line of event.Exception.split("\n")) {
25762
- lines.push(chalk198.red(` ${line}`));
25762
+ lines2.push(chalk198.red(` ${line}`));
25763
25763
  }
25764
25764
  }
25765
- return lines.join("\n");
25765
+ return lines2.join("\n");
25766
25766
  }
25767
25767
 
25768
25768
  // src/commands/seq/parseRelativeTime.ts
@@ -26201,9 +26201,9 @@ function createReadlineInterface() {
26201
26201
  });
26202
26202
  }
26203
26203
  function askQuestion(rl, question) {
26204
- return new Promise((resolve21) => {
26204
+ return new Promise((resolve22) => {
26205
26205
  rl.question(question, (answer) => {
26206
- resolve21(answer.trim());
26206
+ resolve22(answer.trim());
26207
26207
  });
26208
26208
  });
26209
26209
  }
@@ -26423,13 +26423,13 @@ function extractSpeaker(fullText) {
26423
26423
  function isTextLine(line) {
26424
26424
  return !!line.trim() && !line.includes("-->");
26425
26425
  }
26426
- function scanTextLines(lines, start3) {
26426
+ function scanTextLines(lines2, start3) {
26427
26427
  let i = start3;
26428
- while (i < lines.length && isTextLine(lines[i])) i++;
26429
- return { texts: lines.slice(start3, i).map((l) => l.trim()), end: i };
26428
+ while (i < lines2.length && isTextLine(lines2[i])) i++;
26429
+ return { texts: lines2.slice(start3, i).map((l) => l.trim()), end: i };
26430
26430
  }
26431
- function collectTextLines(lines, startIndex) {
26432
- const { texts, end } = scanTextLines(lines, startIndex);
26431
+ function collectTextLines(lines2, startIndex) {
26432
+ const { texts, end } = scanTextLines(lines2, startIndex);
26433
26433
  return { text: texts.join(" "), nextIndex: end };
26434
26434
  }
26435
26435
  function parseTimestampLine(line) {
@@ -26440,30 +26440,30 @@ function buildCue(startMs, endMs, fullText) {
26440
26440
  const { speaker, text: text17 } = extractSpeaker(fullText);
26441
26441
  return text17 ? { startMs, endMs, speaker, text: text17 } : null;
26442
26442
  }
26443
- function parseCueLine(lines, i) {
26444
- const { startMs, endMs } = parseTimestampLine(lines[i]);
26445
- const { text: text17, nextIndex: nextIndex2 } = collectTextLines(lines, i + 1);
26443
+ function parseCueLine(lines2, i) {
26444
+ const { startMs, endMs } = parseTimestampLine(lines2[i]);
26445
+ const { text: text17, nextIndex: nextIndex2 } = collectTextLines(lines2, i + 1);
26446
26446
  return { cue: buildCue(startMs, endMs, text17), nextIndex: nextIndex2 };
26447
26447
  }
26448
26448
  function isCueSeparator(line) {
26449
26449
  return line.trim().includes("-->");
26450
26450
  }
26451
- function skipHeader(lines) {
26451
+ function skipHeader(lines2) {
26452
26452
  let i = 0;
26453
- while (i < lines.length && !isCueSeparator(lines[i])) i++;
26453
+ while (i < lines2.length && !isCueSeparator(lines2[i])) i++;
26454
26454
  return i;
26455
26455
  }
26456
- function processLine(cues, lines, i) {
26457
- if (!isCueSeparator(lines[i])) return i + 1;
26458
- const { cue, nextIndex: nextIndex2 } = parseCueLine(lines, i);
26456
+ function processLine(cues, lines2, i) {
26457
+ if (!isCueSeparator(lines2[i])) return i + 1;
26458
+ const { cue, nextIndex: nextIndex2 } = parseCueLine(lines2, i);
26459
26459
  if (cue) cues.push(cue);
26460
26460
  return nextIndex2;
26461
26461
  }
26462
26462
  function parseVtt(content) {
26463
26463
  const cues = [];
26464
- const lines = content.split(/\r?\n/);
26465
- let i = skipHeader(lines);
26466
- while (i < lines.length) i = processLine(cues, lines, i);
26464
+ const lines2 = content.split(/\r?\n/);
26465
+ let i = skipHeader(lines2);
26466
+ while (i < lines2.length) i = processLine(cues, lines2, i);
26467
26467
  return cues;
26468
26468
  }
26469
26469
 
@@ -26688,8 +26688,8 @@ function logs(options2) {
26688
26688
  console.log("Voice log is empty");
26689
26689
  return;
26690
26690
  }
26691
- const lines = content.split("\n").slice(-count8);
26692
- for (const line of lines) {
26691
+ const lines2 = content.split("\n").slice(-count8);
26692
+ for (const line of lines2) {
26693
26693
  try {
26694
26694
  const event = JSON.parse(line);
26695
26695
  const time = event.timestamp?.slice(11, 19) ?? "";
@@ -26837,8 +26837,8 @@ function isProcessAlive3(pid) {
26837
26837
  }
26838
26838
  function readRecentLogs(count8) {
26839
26839
  if (!existsSync56(voicePaths.log)) return [];
26840
- const lines = readFileSync46(voicePaths.log, "utf8").trim().split("\n");
26841
- return lines.slice(-count8);
26840
+ const lines2 = readFileSync46(voicePaths.log, "utf8").trim().split("\n");
26841
+ return lines2.slice(-count8);
26842
26842
  }
26843
26843
  function status2() {
26844
26844
  if (!existsSync56(voicePaths.pid)) {
@@ -26945,6 +26945,152 @@ function registerVoice(program2) {
26945
26945
  configHelp(voiceCommand, voiceConfigHelp);
26946
26946
  }
26947
26947
 
26948
+ // src/commands/watch/readBuiltVersion.ts
26949
+ import { join as join67 } from "path";
26950
+
26951
+ // src/commands/watch/resolveUpstream.ts
26952
+ import { execFileSync as execFileSync10 } from "child_process";
26953
+ function runGit2(args, cwd) {
26954
+ return execFileSync10("git", args, {
26955
+ encoding: "utf8",
26956
+ stdio: ["pipe", "pipe", "pipe"],
26957
+ cwd
26958
+ }).trim();
26959
+ }
26960
+ function resolveUpstream(cwd) {
26961
+ try {
26962
+ runGit2(["rev-parse", "--is-inside-work-tree"], cwd);
26963
+ } catch {
26964
+ throw new Error(
26965
+ "not a git repository \u2014 run assist watch wait from inside a repo"
26966
+ );
26967
+ }
26968
+ let branch2;
26969
+ try {
26970
+ branch2 = runGit2(["symbolic-ref", "--quiet", "--short", "HEAD"], cwd);
26971
+ } catch {
26972
+ throw new Error(
26973
+ "HEAD is detached \u2014 check out a branch before waiting on its upstream"
26974
+ );
26975
+ }
26976
+ try {
26977
+ return {
26978
+ branch: branch2,
26979
+ upstream: runGit2(
26980
+ ["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"],
26981
+ cwd
26982
+ )
26983
+ };
26984
+ } catch {
26985
+ throw new Error(
26986
+ `branch "${branch2}" has no upstream \u2014 set one with: git push -u origin ${branch2}`
26987
+ );
26988
+ }
26989
+ }
26990
+
26991
+ // src/commands/watch/readBuiltVersion.ts
26992
+ function readBuiltVersion(cwd) {
26993
+ try {
26994
+ const root = runGit2(["rev-parse", "--show-toplevel"], cwd);
26995
+ return readPackageJson(join67(root, "package.json")).version ?? "unknown";
26996
+ } catch {
26997
+ return "unknown";
26998
+ }
26999
+ }
27000
+
27001
+ // src/commands/watch/readRecentCommits.ts
27002
+ function readRecentCommits(count8 = 10, cwd) {
27003
+ const output = runGit2(
27004
+ ["log", `-${count8}`, "--pretty=format:%H%x09%h%x09%ar%x09%s"],
27005
+ cwd
27006
+ );
27007
+ if (!output) return [];
27008
+ return output.split("\n").map((line) => {
27009
+ const [sha, short2, when, ...subject] = line.split(" ");
27010
+ return { sha, short: short2, when, subject: subject.join(" ") };
27011
+ });
27012
+ }
27013
+
27014
+ // src/commands/watch/renderWatchReport.ts
27015
+ var escapeCell = (text17) => text17.replaceAll("|", String.raw`\|`);
27016
+ function renderWatchReport({
27017
+ version: version2,
27018
+ commits: commits2,
27019
+ newShas,
27020
+ restarts
27021
+ }) {
27022
+ const isNew = new Set(newShas);
27023
+ const lines2 = [`**Version** ${version2}`, ""];
27024
+ if (commits2.length === 0) {
27025
+ lines2.push("_no commits_");
27026
+ } else {
27027
+ lines2.push("| SHA | When | Subject |", "| --- | --- | --- |");
27028
+ for (const commit2 of commits2) {
27029
+ const marker = isNew.has(commit2.sha) ? " \u2190 new" : "";
27030
+ lines2.push(
27031
+ `| \`${commit2.short}\` | ${commit2.when} | ${escapeCell(commit2.subject)}${marker} |`
27032
+ );
27033
+ }
27034
+ }
27035
+ lines2.push("", "**Restarts**", "");
27036
+ lines2.push(
27037
+ ...restarts.length === 0 ? ["- none needed"] : restarts.map((restart) => `- ${restart}`)
27038
+ );
27039
+ return lines2.join("\n");
27040
+ }
27041
+
27042
+ // src/commands/watch/restartAdvice.ts
27043
+ var webUiPrefix = "src/commands/sessions/web/ui/";
27044
+ var sessionsPrefix = "src/commands/sessions/";
27045
+ var rules = [
27046
+ {
27047
+ matches: (path71) => path71.startsWith(webUiPrefix),
27048
+ advice: "restart the web server, then hard-reload the browser tab"
27049
+ },
27050
+ {
27051
+ matches: (path71) => path71.startsWith(sessionsPrefix) && !path71.startsWith(webUiPrefix),
27052
+ advice: "restart the daemon"
27053
+ }
27054
+ ];
27055
+ function restartAdvice(paths) {
27056
+ return rules.filter((rule) => paths.some(rule.matches)).map((rule) => rule.advice);
27057
+ }
27058
+
27059
+ // src/commands/watch/buildWatchReport.ts
27060
+ var lines = (output) => output.split("\n").filter((line) => line.length > 0);
27061
+ function buildWatchReport(from, cwd) {
27062
+ const range = from ? `${from}..HEAD` : void 0;
27063
+ return renderWatchReport({
27064
+ version: readBuiltVersion(cwd),
27065
+ commits: readRecentCommits(10, cwd),
27066
+ newShas: range ? lines(runGit2(["rev-list", range], cwd)) : [],
27067
+ restarts: restartAdvice(
27068
+ range ? lines(runGit2(["diff", "--name-only", range], cwd)) : []
27069
+ )
27070
+ });
27071
+ }
27072
+
27073
+ // src/commands/watch/gitFailureReason.ts
27074
+ function gitFailureReason(error) {
27075
+ const streams = error;
27076
+ for (const stream of [streams?.stderr, streams?.stdout]) {
27077
+ const text17 = stream == null ? "" : String(stream).trim();
27078
+ if (text17) return text17;
27079
+ }
27080
+ const message3 = error instanceof Error ? error.message : String(error);
27081
+ return message3.trim() || "git failed without reporting a reason";
27082
+ }
27083
+
27084
+ // src/commands/watch/watchReport.ts
27085
+ function watchReport(options2) {
27086
+ try {
27087
+ console.log(buildWatchReport(options2.from));
27088
+ } catch (error) {
27089
+ console.error(`cannot build the report: ${gitFailureReason(error)}`);
27090
+ process.exit(1);
27091
+ }
27092
+ }
27093
+
26948
27094
  // src/commands/watch/describeOutcome.ts
26949
27095
  var short = (sha) => sha.slice(0, 7);
26950
27096
  function describeOutcome(outcome) {
@@ -26997,72 +27143,248 @@ function parseDuration(value) {
26997
27143
  return amount * UNIT_MS[match[2]];
26998
27144
  }
26999
27145
 
27000
- // src/commands/watch/gitFailureReason.ts
27001
- function gitFailureReason(error) {
27002
- const streams = error;
27003
- for (const stream of [streams?.stderr, streams?.stdout]) {
27004
- const text17 = stream == null ? "" : String(stream).trim();
27005
- if (text17) return text17;
27146
+ // src/commands/watch/parseWatchDurations.ts
27147
+ function parseOrExit(value) {
27148
+ try {
27149
+ return parseDuration(value);
27150
+ } catch (error) {
27151
+ console.error(error instanceof Error ? error.message : String(error));
27152
+ return process.exit(1);
27006
27153
  }
27007
- const message3 = error instanceof Error ? error.message : String(error);
27008
- return message3.trim() || "git failed without reporting a reason";
27154
+ }
27155
+ function parseWatchDurations(interval, timeout) {
27156
+ return {
27157
+ intervalMs: parseOrExit(interval),
27158
+ timeoutMs: timeout.trim() === "none" ? void 0 : parseOrExit(timeout)
27159
+ };
27009
27160
  }
27010
27161
 
27011
- // src/commands/watch/resolveUpstream.ts
27012
- import { execFileSync as execFileSync10 } from "child_process";
27013
- function runGit2(args, cwd) {
27014
- return execFileSync10("git", args, {
27015
- encoding: "utf8",
27016
- stdio: ["pipe", "pipe", "pipe"],
27017
- cwd
27018
- }).trim();
27162
+ // src/commands/watch/pullFastForward.ts
27163
+ var STASH_MESSAGE = "assist watch";
27164
+ function attemptGit(args, cwd) {
27165
+ try {
27166
+ runGit2(args, cwd);
27167
+ return { ok: true };
27168
+ } catch (error) {
27169
+ return { ok: false, reason: gitFailureReason(error) };
27170
+ }
27019
27171
  }
27020
- function resolveUpstream(cwd) {
27172
+ function fastForwarded(cwd) {
27173
+ return { kind: "fast-forwarded", sha: runGit2(["rev-parse", "@"], cwd) };
27174
+ }
27175
+ function operationInProgress(cwd) {
27176
+ return ["MERGE_HEAD", "REBASE_HEAD"].some(
27177
+ (ref) => attemptGit(["rev-parse", "--verify", "--quiet", ref], cwd).ok
27178
+ );
27179
+ }
27180
+ function headMatchesUpstream(cwd) {
27021
27181
  try {
27022
- runGit2(["rev-parse", "--is-inside-work-tree"], cwd);
27182
+ return runGit2(["rev-parse", "@"], cwd) === runGit2(["rev-parse", "@{u}"], cwd);
27023
27183
  } catch {
27024
- throw new Error(
27025
- "not a git repository \u2014 run assist watch wait from inside a repo"
27026
- );
27184
+ return false;
27027
27185
  }
27028
- let branch2;
27186
+ }
27187
+ function behindUpstream(cwd) {
27188
+ return attemptGit(["merge-base", "--is-ancestor", "@", "@{u}"], cwd).ok;
27189
+ }
27190
+ function stashDirtyTree(cwd) {
27191
+ let dirty;
27029
27192
  try {
27030
- branch2 = runGit2(["symbolic-ref", "--quiet", "--short", "HEAD"], cwd);
27031
- } catch {
27032
- throw new Error(
27033
- "HEAD is detached \u2014 check out a branch before waiting on its upstream"
27034
- );
27193
+ dirty = runGit2(["status", "--porcelain"], cwd) !== "";
27194
+ } catch (error) {
27195
+ return { ok: false, reason: gitFailureReason(error) };
27196
+ }
27197
+ if (!dirty) return { ok: true, stashed: false };
27198
+ const push = attemptGit(
27199
+ ["stash", "push", "--include-untracked", "--message", STASH_MESSAGE],
27200
+ cwd
27201
+ );
27202
+ return push.ok ? { ok: true, stashed: true } : push;
27203
+ }
27204
+ function mergeBehindBranch(cwd) {
27205
+ const stash = stashDirtyTree(cwd);
27206
+ if (!stash.ok) return { kind: "blocked", reason: stash.reason };
27207
+ const merge = attemptGit(["merge", "--ff-only", "@{u}"], cwd);
27208
+ const restore2 = stash.stashed ? attemptGit(["stash", "pop"], cwd) : { ok: true };
27209
+ if (!merge.ok) return { kind: "blocked", reason: merge.reason };
27210
+ if (!restore2.ok) return { kind: "blocked", reason: restore2.reason };
27211
+ return fastForwarded(cwd);
27212
+ }
27213
+ function pullFastForward(cwd) {
27214
+ const pull = attemptGit(["pull", "--ff-only"], cwd);
27215
+ if (pull.ok) return fastForwarded(cwd);
27216
+ if (operationInProgress(cwd)) return { kind: "blocked", reason: pull.reason };
27217
+ if (headMatchesUpstream(cwd)) return fastForwarded(cwd);
27218
+ if (!behindUpstream(cwd)) return { kind: "blocked", reason: pull.reason };
27219
+ return mergeBehindBranch(cwd);
27220
+ }
27221
+
27222
+ // src/commands/watch/runWatchBuild.ts
27223
+ import { resolve as resolve17 } from "path";
27224
+
27225
+ // src/commands/run/findRunConfig.ts
27226
+ function exitNoRunConfigs() {
27227
+ console.error("No run configurations found in assist.yml");
27228
+ process.exit(1);
27229
+ }
27230
+ function exitWithConfigNotFound(name, configs) {
27231
+ console.error(`No run configuration found with name: ${name}`);
27232
+ console.error("Available configurations:");
27233
+ for (const r of configs) {
27234
+ console.error(` - ${r.name}`);
27035
27235
  }
27236
+ process.exit(1);
27237
+ }
27238
+ function exitWithAmbiguousConfig(name, matches) {
27239
+ console.error(`Ambiguous run configuration: ${name}`);
27240
+ console.error("Did you mean:");
27241
+ for (const r of matches) {
27242
+ console.error(` - ${r.name}`);
27243
+ }
27244
+ process.exit(1);
27245
+ }
27246
+ function requireRunConfigs() {
27247
+ const { run: run4 } = loadConfig();
27248
+ const configs = resolveRunConfigs(run4, getConfigDir());
27249
+ if (configs.length === 0) return exitNoRunConfigs();
27250
+ return configs;
27251
+ }
27252
+ function lookupRunConfig(name) {
27253
+ const configs = requireRunConfigs();
27254
+ const exact = configs.find((r) => r.name === name);
27255
+ if (exact) return { kind: "match", config: exact };
27256
+ const suffixMatches = configs.filter((r) => r.name.endsWith(`:${name}`));
27257
+ if (suffixMatches.length === 1)
27258
+ return { kind: "match", config: suffixMatches[0] };
27259
+ if (suffixMatches.length > 1)
27260
+ return { kind: "ambiguous", matches: suffixMatches };
27261
+ return { kind: "not-found" };
27262
+ }
27263
+ function findRunConfig(name) {
27264
+ const result = lookupRunConfig(name);
27265
+ if (result.kind === "match") return result.config;
27266
+ if (result.kind === "ambiguous")
27267
+ return exitWithAmbiguousConfig(name, result.matches);
27268
+ return exitWithConfigNotFound(name, requireRunConfigs());
27269
+ }
27270
+
27271
+ // src/commands/run/resolveParams.ts
27272
+ function resolveParams(params, cliArgs) {
27273
+ if (!params || params.length === 0) return cliArgs;
27274
+ const resolved = [];
27275
+ const missing = [];
27276
+ for (let i = 0; i < params.length; i++) {
27277
+ const param = params[i];
27278
+ const value = cliArgs[i] ?? param.default;
27279
+ if (value !== void 0) {
27280
+ resolved.push(value);
27281
+ } else if (param.required) {
27282
+ missing.push(param.name);
27283
+ }
27284
+ }
27285
+ if (missing.length > 0) {
27286
+ const s = missing.length > 1 ? "s" : "";
27287
+ const names = missing.map((n) => `"${n}"`).join(", ");
27288
+ console.error(`Missing required param${s}: ${names}`);
27289
+ process.exit(1);
27290
+ }
27291
+ resolved.push(...cliArgs.slice(params.length));
27292
+ return resolved;
27293
+ }
27294
+
27295
+ // src/commands/run/runCommandToCompletion.ts
27296
+ import { execFileSync as execFileSync11, spawn as spawn9 } from "child_process";
27297
+ import { existsSync as existsSync58 } from "fs";
27298
+ import { dirname as dirname31, join as join68, resolve as resolve16 } from "path";
27299
+ function resolveCommand2(command) {
27300
+ if (process.platform !== "win32" || command !== "bash") return command;
27036
27301
  try {
27037
- return {
27038
- branch: branch2,
27039
- upstream: runGit2(
27040
- ["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"],
27041
- cwd
27042
- )
27043
- };
27302
+ const gitPath = execFileSync11("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
27303
+ const gitRoot = resolve16(dirname31(gitPath), "..");
27304
+ const gitBash = join68(gitRoot, "bin", "bash.exe");
27305
+ if (existsSync58(gitBash)) return gitBash;
27044
27306
  } catch {
27045
- throw new Error(
27046
- `branch "${branch2}" has no upstream \u2014 set one with: git push -u origin ${branch2}`
27047
- );
27307
+ return command;
27048
27308
  }
27309
+ return command;
27310
+ }
27311
+ function runCommandToCompletion(command, args, env, cwd, quiet) {
27312
+ return new Promise((resolveResult) => {
27313
+ const child = spawn9(resolveCommand2(command), args, {
27314
+ stdio: quiet ? "pipe" : "inherit",
27315
+ env: env ? { ...process.env, ...expandEnv(env) } : void 0,
27316
+ cwd
27317
+ });
27318
+ const chunks = [];
27319
+ if (quiet) {
27320
+ child.stdout?.on("data", (data) => chunks.push(data));
27321
+ child.stderr?.on("data", (data) => chunks.push(data));
27322
+ }
27323
+ child.on("close", (code) => {
27324
+ resolveResult({
27325
+ kind: "completed",
27326
+ exitCode: code ?? 0,
27327
+ output: Buffer.concat(chunks).toString()
27328
+ });
27329
+ });
27330
+ child.on("error", (err) => {
27331
+ resolveResult({
27332
+ kind: "failed",
27333
+ message: `Failed to execute command: ${err.message}`
27334
+ });
27335
+ });
27336
+ });
27049
27337
  }
27050
27338
 
27051
- // src/commands/watch/pullFastForward.ts
27052
- function pullFastForward(cwd) {
27053
- try {
27054
- runGit2(["pull", "--ff-only"], cwd);
27055
- return { kind: "fast-forwarded", sha: runGit2(["rev-parse", "@"], cwd) };
27056
- } catch (error) {
27057
- return { kind: "blocked", reason: gitFailureReason(error) };
27339
+ // src/commands/run/runPreCommands.ts
27340
+ import { execSync as execSync60 } from "child_process";
27341
+ function runPreCommands(pre, cwd) {
27342
+ for (const cmd of pre) {
27343
+ try {
27344
+ execSync60(cmd, { stdio: "inherit", cwd });
27345
+ } catch (error) {
27346
+ const code = error && typeof error === "object" && "status" in error ? error.status : 1;
27347
+ process.exit(code);
27348
+ }
27058
27349
  }
27059
27350
  }
27060
27351
 
27352
+ // src/commands/watch/runWatchBuild.ts
27353
+ async function runWatchBuild(entry) {
27354
+ const config = findRunConfig(entry);
27355
+ const cwd = config.cwd ? resolve17(getConfigDir(), config.cwd) : void 0;
27356
+ if (config.pre) runPreCommands(config.pre, cwd);
27357
+ const result = await runCommandToCompletion(
27358
+ config.command,
27359
+ [...config.args ?? [], ...resolveParams(config.params, [])],
27360
+ config.env,
27361
+ cwd,
27362
+ config.quiet
27363
+ );
27364
+ if (result.kind === "failed")
27365
+ return { kind: "failed", exitCode: 1, output: result.message };
27366
+ if (result.exitCode !== 0)
27367
+ return { kind: "failed", exitCode: result.exitCode, output: result.output };
27368
+ return { kind: "built" };
27369
+ }
27370
+
27371
+ // src/commands/watch/reportBuildOrExit.ts
27372
+ async function reportBuildOrExit(entry) {
27373
+ const outcome = await runWatchBuild(entry);
27374
+ if (outcome.kind === "built") {
27375
+ console.log(`built with "${entry}"`);
27376
+ return;
27377
+ }
27378
+ if (outcome.output.length > 0) process.stdout.write(outcome.output);
27379
+ console.error(`build "${entry}" failed with exit code ${outcome.exitCode}`);
27380
+ process.exit(4);
27381
+ }
27382
+
27061
27383
  // src/commands/watch/fetchQuietly.ts
27062
- import { execFileSync as execFileSync11 } from "child_process";
27384
+ import { execFileSync as execFileSync12 } from "child_process";
27063
27385
  function fetchQuietly(cwd, timeoutMs) {
27064
27386
  try {
27065
- execFileSync11("git", ["fetch", "--quiet"], {
27387
+ execFileSync12("git", ["fetch", "--quiet"], {
27066
27388
  stdio: ["pipe", "pipe", "pipe"],
27067
27389
  cwd,
27068
27390
  timeout: timeoutMs
@@ -27090,26 +27412,12 @@ function readMovement(cwd) {
27090
27412
  }
27091
27413
  }
27092
27414
 
27093
- // src/commands/watch/waitForUpstream.ts
27415
+ // src/commands/watch/pollForMovement.ts
27094
27416
  var MIN_FETCH_TIMEOUT_MS = 6e4;
27095
- function waitForUpstream(options2) {
27096
- const { intervalMs, timeoutMs, timeout, cwd, onStart } = options2;
27097
- let upstream;
27098
- try {
27099
- upstream = resolveUpstream(cwd).upstream;
27100
- } catch (error) {
27101
- return Promise.resolve({
27102
- kind: "unavailable",
27103
- reason: error instanceof Error ? error.message : String(error)
27104
- });
27105
- }
27106
- onStart?.(upstream);
27107
- const moved = readMovement(cwd);
27108
- if (moved) {
27109
- return Promise.resolve({ kind: "moved", upstream, ...moved });
27110
- }
27417
+ function pollForMovement(options2) {
27418
+ const { upstream, intervalMs, timeoutMs, timeout, cwd } = options2;
27111
27419
  const fetchTimeoutMs = Math.max(intervalMs, MIN_FETCH_TIMEOUT_MS);
27112
- return new Promise((resolve21) => {
27420
+ return new Promise((resolve22) => {
27113
27421
  let settled = false;
27114
27422
  const finish = (outcome) => {
27115
27423
  if (settled) return;
@@ -27117,7 +27425,7 @@ function waitForUpstream(options2) {
27117
27425
  clearInterval(ticker);
27118
27426
  clearTimeout(deadline);
27119
27427
  process.off("SIGINT", onInterrupt);
27120
- resolve21(outcome);
27428
+ resolve22(outcome);
27121
27429
  };
27122
27430
  const onInterrupt = () => finish({ kind: "interrupted" });
27123
27431
  const ticker = setInterval(() => {
@@ -27125,7 +27433,7 @@ function waitForUpstream(options2) {
27125
27433
  const found = readMovement(cwd);
27126
27434
  if (found) finish({ kind: "moved", upstream, ...found });
27127
27435
  }, intervalMs);
27128
- const deadline = setTimeout(
27436
+ const deadline = timeoutMs === void 0 ? void 0 : setTimeout(
27129
27437
  () => finish({ kind: "timeout", upstream, timeout }),
27130
27438
  timeoutMs
27131
27439
  );
@@ -27133,22 +27441,35 @@ function waitForUpstream(options2) {
27133
27441
  });
27134
27442
  }
27135
27443
 
27136
- // src/commands/watch/watchWait.ts
27137
- function parseOrExit(value) {
27444
+ // src/commands/watch/waitForUpstream.ts
27445
+ function waitForUpstream(options2) {
27446
+ const { intervalMs, timeoutMs, timeout, cwd, onStart } = options2;
27447
+ let upstream;
27138
27448
  try {
27139
- return parseDuration(value);
27449
+ upstream = resolveUpstream(cwd).upstream;
27140
27450
  } catch (error) {
27141
- console.error(error instanceof Error ? error.message : String(error));
27142
- return process.exit(1);
27451
+ return Promise.resolve({
27452
+ kind: "unavailable",
27453
+ reason: error instanceof Error ? error.message : String(error)
27454
+ });
27143
27455
  }
27456
+ onStart?.(upstream);
27457
+ const moved = readMovement(cwd);
27458
+ if (moved) return Promise.resolve({ kind: "moved", upstream, ...moved });
27459
+ return pollForMovement({ upstream, intervalMs, timeoutMs, timeout, cwd });
27144
27460
  }
27461
+
27462
+ // src/commands/watch/watchWait.ts
27463
+ var DEFAULT_BUILD_ENTRY = "auto-build";
27145
27464
  function report({ exitCode, message: message3 }) {
27146
27465
  if (exitCode === 0) console.log(message3);
27147
27466
  else console.error(message3);
27148
27467
  }
27149
27468
  async function watchWait(options2) {
27150
- const intervalMs = parseOrExit(options2.interval);
27151
- const timeoutMs = parseOrExit(options2.timeout);
27469
+ const { intervalMs, timeoutMs } = parseWatchDurations(
27470
+ options2.interval,
27471
+ options2.timeout
27472
+ );
27152
27473
  const outcome = await waitForUpstream({
27153
27474
  intervalMs,
27154
27475
  timeoutMs,
@@ -27157,29 +27478,47 @@ async function watchWait(options2) {
27157
27478
  });
27158
27479
  const waitReport = describeOutcome(outcome);
27159
27480
  report(waitReport);
27160
- if (outcome.kind === "moved" && options2.pull) {
27161
- const pullReport = describePull(pullFastForward());
27162
- report(pullReport);
27163
- process.exit(pullReport.exitCode);
27481
+ if (outcome.kind !== "moved" || !options2.pull)
27482
+ return process.exit(waitReport.exitCode);
27483
+ const pullResult = pullFastForward();
27484
+ const pullReport = describePull(pullResult);
27485
+ report(pullReport);
27486
+ if (pullResult.kind !== "fast-forwarded")
27487
+ return process.exit(pullReport.exitCode);
27488
+ console.log(`
27489
+ ${buildWatchReport(outcome.from)}`);
27490
+ if (options2.build) {
27491
+ await reportBuildOrExit(
27492
+ typeof options2.build === "string" ? options2.build : DEFAULT_BUILD_ENTRY
27493
+ );
27164
27494
  }
27165
- process.exit(waitReport.exitCode);
27495
+ process.exit(0);
27166
27496
  }
27167
27497
 
27168
27498
  // src/commands/registerWatch.ts
27169
27499
  function registerWatch(program2) {
27170
27500
  const watchCommand = program2.command("watch").description("Wait on upstream movement for the current branch");
27171
27501
  watchCommand.command("wait").description(
27172
- "Block until the current branch's upstream gains commits, then exit 0 (2 on timeout, 3 when --pull is not a fast-forward, 1 when waiting is impossible, 130 on interrupt)"
27502
+ "Block until the current branch's upstream gains commits, then exit 0 (2 on timeout, 3 when --pull hits genuine divergence, 4 when --build fails, 1 when waiting is impossible, 130 on interrupt)"
27173
27503
  ).option("--interval <duration>", "How often to fetch (e.g. 30s, 2m)", "30s").option(
27174
27504
  "--timeout <duration>",
27175
- "Give up and exit 2 after this long (e.g. 60m, 2h)",
27176
- "60m"
27505
+ "Give up and exit 2 after this long (e.g. 60m, 2h), or none to wait indefinitely",
27506
+ "none"
27177
27507
  ).option(
27178
27508
  "--pull",
27179
- "On movement, fast-forward with git pull --ff-only; exit 3 with git's reason if it is not a clean fast-forward"
27509
+ "On movement, fast-forward with git pull --ff-only, recovering a dirty tree or a merely-behind branch; exit 3 with git's reason on genuine divergence"
27510
+ ).option(
27511
+ "--build [entry]",
27512
+ "After a successful pull, run this run entry (default auto-build); exit 4 with its output when it fails"
27180
27513
  ).action(
27181
27514
  (options2) => watchWait(options2)
27182
27515
  );
27516
+ watchCommand.command("report").description(
27517
+ "Print the built version, the last 10 commits as a markdown table, and the restarts the new commits make necessary"
27518
+ ).option(
27519
+ "--from <sha>",
27520
+ "Mark commits reachable from HEAD but not <sha> as new, and derive restart advice from the files they changed"
27521
+ ).action((options2) => watchReport(options2));
27183
27522
  }
27184
27523
 
27185
27524
  // src/commands/roam/auth.ts
@@ -27205,7 +27544,7 @@ function extractCode(url, expectedState) {
27205
27544
  return code;
27206
27545
  }
27207
27546
  function waitForCallback(port, expectedState) {
27208
- return new Promise((resolve21, reject) => {
27547
+ return new Promise((resolve22, reject) => {
27209
27548
  const timeout = setTimeout(() => {
27210
27549
  server.close();
27211
27550
  reject(new Error("Authorization timed out after 120 seconds"));
@@ -27222,7 +27561,7 @@ function waitForCallback(port, expectedState) {
27222
27561
  const code = extractCode(url, expectedState);
27223
27562
  respondHtml(res, 200, "Authorization successful!");
27224
27563
  server.close();
27225
- resolve21(code);
27564
+ resolve22(code);
27226
27565
  } catch (error) {
27227
27566
  respondHtml(res, 400, error.message);
27228
27567
  server.close();
@@ -27342,9 +27681,9 @@ async function auth() {
27342
27681
  }
27343
27682
 
27344
27683
  // src/commands/roam/postRoamActivity.ts
27345
- import { execFileSync as execFileSync12 } from "child_process";
27684
+ import { execFileSync as execFileSync13 } from "child_process";
27346
27685
  import { readdirSync as readdirSync12, readFileSync as readFileSync48, statSync as statSync10 } from "fs";
27347
- import { join as join67 } from "path";
27686
+ import { join as join69 } from "path";
27348
27687
  function findPortFile(roamDir) {
27349
27688
  let entries;
27350
27689
  try {
@@ -27353,7 +27692,7 @@ function findPortFile(roamDir) {
27353
27692
  return void 0;
27354
27693
  }
27355
27694
  const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
27356
- const path71 = join67(roamDir, name);
27695
+ const path71 = join69(roamDir, name);
27357
27696
  try {
27358
27697
  return { path: path71, mtimeMs: statSync10(path71).mtimeMs };
27359
27698
  } catch {
@@ -27365,7 +27704,7 @@ function findPortFile(roamDir) {
27365
27704
  function postRoamActivity(app, event) {
27366
27705
  const appData = process.env.APPDATA;
27367
27706
  if (!appData) return;
27368
- const portFile = findPortFile(join67(appData, "Roam"));
27707
+ const portFile = findPortFile(join69(appData, "Roam"));
27369
27708
  if (!portFile) return;
27370
27709
  let port;
27371
27710
  try {
@@ -27375,7 +27714,7 @@ function postRoamActivity(app, event) {
27375
27714
  }
27376
27715
  const url = `http://127.0.0.1:${port}/api/v1/activity/${app}/${event}?pid=${app === "codex" ? 99998 : 99999}`;
27377
27716
  try {
27378
- execFileSync12("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
27717
+ execFileSync13("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
27379
27718
  stdio: "ignore"
27380
27719
  });
27381
27720
  } catch {
@@ -27499,53 +27838,7 @@ var rootConfigHelp = {
27499
27838
  };
27500
27839
 
27501
27840
  // src/commands/run/index.ts
27502
- import { resolve as resolve17 } from "path";
27503
-
27504
- // src/commands/run/findRunConfig.ts
27505
- function exitNoRunConfigs() {
27506
- console.error("No run configurations found in assist.yml");
27507
- process.exit(1);
27508
- }
27509
- function exitWithConfigNotFound(name, configs) {
27510
- console.error(`No run configuration found with name: ${name}`);
27511
- console.error("Available configurations:");
27512
- for (const r of configs) {
27513
- console.error(` - ${r.name}`);
27514
- }
27515
- process.exit(1);
27516
- }
27517
- function exitWithAmbiguousConfig(name, matches) {
27518
- console.error(`Ambiguous run configuration: ${name}`);
27519
- console.error("Did you mean:");
27520
- for (const r of matches) {
27521
- console.error(` - ${r.name}`);
27522
- }
27523
- process.exit(1);
27524
- }
27525
- function requireRunConfigs() {
27526
- const { run: run4 } = loadConfig();
27527
- const configs = resolveRunConfigs(run4, getConfigDir());
27528
- if (configs.length === 0) return exitNoRunConfigs();
27529
- return configs;
27530
- }
27531
- function lookupRunConfig(name) {
27532
- const configs = requireRunConfigs();
27533
- const exact = configs.find((r) => r.name === name);
27534
- if (exact) return { kind: "match", config: exact };
27535
- const suffixMatches = configs.filter((r) => r.name.endsWith(`:${name}`));
27536
- if (suffixMatches.length === 1)
27537
- return { kind: "match", config: suffixMatches[0] };
27538
- if (suffixMatches.length > 1)
27539
- return { kind: "ambiguous", matches: suffixMatches };
27540
- return { kind: "not-found" };
27541
- }
27542
- function findRunConfig(name) {
27543
- const result = lookupRunConfig(name);
27544
- if (result.kind === "match") return result.config;
27545
- if (result.kind === "ambiguous")
27546
- return exitWithAmbiguousConfig(name, result.matches);
27547
- return exitWithConfigNotFound(name, requireRunConfigs());
27548
- }
27841
+ import { resolve as resolve18 } from "path";
27549
27842
 
27550
27843
  // src/commands/run/formatConfiguredCommands.ts
27551
27844
  function formatConfiguredCommands() {
@@ -27558,84 +27851,23 @@ Configured commands:
27558
27851
  ${names}`;
27559
27852
  }
27560
27853
 
27561
- // src/commands/run/resolveParams.ts
27562
- function resolveParams(params, cliArgs) {
27563
- if (!params || params.length === 0) return cliArgs;
27564
- const resolved = [];
27565
- const missing = [];
27566
- for (let i = 0; i < params.length; i++) {
27567
- const param = params[i];
27568
- const value = cliArgs[i] ?? param.default;
27569
- if (value !== void 0) {
27570
- resolved.push(value);
27571
- } else if (param.required) {
27572
- missing.push(param.name);
27573
- }
27574
- }
27575
- if (missing.length > 0) {
27576
- const s = missing.length > 1 ? "s" : "";
27577
- const names = missing.map((n) => `"${n}"`).join(", ");
27578
- console.error(`Missing required param${s}: ${names}`);
27579
- process.exit(1);
27580
- }
27581
- resolved.push(...cliArgs.slice(params.length));
27582
- return resolved;
27583
- }
27584
-
27585
- // src/commands/run/runPreCommands.ts
27586
- import { execSync as execSync60 } from "child_process";
27587
- function runPreCommands(pre, cwd) {
27588
- for (const cmd of pre) {
27589
- try {
27590
- execSync60(cmd, { stdio: "inherit", cwd });
27591
- } catch (error) {
27592
- const code = error && typeof error === "object" && "status" in error ? error.status : 1;
27593
- process.exit(code);
27594
- }
27595
- }
27596
- }
27597
-
27598
27854
  // src/commands/run/spawnRunCommand.ts
27599
- import { execFileSync as execFileSync13, spawn as spawn9 } from "child_process";
27600
- import { existsSync as existsSync58 } from "fs";
27601
- import { dirname as dirname31, join as join68, resolve as resolve16 } from "path";
27602
- function resolveCommand2(command) {
27603
- if (process.platform !== "win32" || command !== "bash") return command;
27604
- try {
27605
- const gitPath = execFileSync13("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
27606
- const gitRoot = resolve16(dirname31(gitPath), "..");
27607
- const gitBash = join68(gitRoot, "bin", "bash.exe");
27608
- if (existsSync58(gitBash)) return gitBash;
27609
- } catch {
27610
- }
27611
- return command;
27612
- }
27613
27855
  function spawnRunCommand(command, args, env, cwd, quiet) {
27614
27856
  const start3 = Date.now();
27615
- const child = spawn9(resolveCommand2(command), args, {
27616
- stdio: quiet ? "pipe" : "inherit",
27617
- env: env ? { ...process.env, ...expandEnv(env) } : void 0,
27618
- cwd
27619
- });
27620
- const chunks = [];
27621
- if (quiet) {
27622
- child.stdout?.on("data", (data) => chunks.push(data));
27623
- child.stderr?.on("data", (data) => chunks.push(data));
27624
- }
27625
- child.on("close", (code) => {
27626
- const exitCode = code ?? 0;
27627
- if (quiet && exitCode !== 0 && chunks.length > 0) {
27628
- process.stdout.write(Buffer.concat(chunks));
27857
+ void runCommandToCompletion(command, args, env, cwd, quiet).then((result) => {
27858
+ if (result.kind === "failed") {
27859
+ console.error(result.message);
27860
+ process.exit(1);
27861
+ }
27862
+ const { exitCode, output } = result;
27863
+ if (quiet && exitCode !== 0 && output.length > 0) {
27864
+ process.stdout.write(output);
27629
27865
  }
27630
27866
  const elapsed = formatElapsed(Date.now() - start3);
27631
27867
  if (!quiet || exitCode !== 0) console.log(`
27632
27868
  Done in ${elapsed}`);
27633
27869
  process.exit(exitCode);
27634
27870
  });
27635
- child.on("error", (err) => {
27636
- console.error(`Failed to execute command: ${err.message}`);
27637
- process.exit(1);
27638
- });
27639
27871
  }
27640
27872
 
27641
27873
  // src/commands/run/index.ts
@@ -27651,7 +27883,7 @@ function listRunConfigs(verbose) {
27651
27883
  }
27652
27884
  }
27653
27885
  function execRunConfig(config, args) {
27654
- const cwd = config.cwd ? resolve17(getConfigDir(), config.cwd) : void 0;
27886
+ const cwd = config.cwd ? resolve18(getConfigDir(), config.cwd) : void 0;
27655
27887
  if (config.pre) runPreCommands(config.pre, cwd);
27656
27888
  const resolved = resolveParams(config.params, args);
27657
27889
  spawnRunCommand(
@@ -27693,7 +27925,7 @@ async function run3(name, args) {
27693
27925
 
27694
27926
  // src/commands/run/add.ts
27695
27927
  import { mkdirSync as mkdirSync24, writeFileSync as writeFileSync41 } from "fs";
27696
- import { join as join69 } from "path";
27928
+ import { join as join70 } from "path";
27697
27929
 
27698
27930
  // src/commands/run/extractOption.ts
27699
27931
  function extractOption(args, flag) {
@@ -27754,7 +27986,7 @@ function saveNewRunConfig(name, command, args, cwd) {
27754
27986
  saveConfig(config);
27755
27987
  }
27756
27988
  function createCommandFile(name) {
27757
- const dir = join69(".claude", "commands");
27989
+ const dir = join70(".claude", "commands");
27758
27990
  mkdirSync24(dir, { recursive: true });
27759
27991
  const content = `---
27760
27992
  description: Run ${name}
@@ -27762,7 +27994,7 @@ description: Run ${name}
27762
27994
 
27763
27995
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
27764
27996
  `;
27765
- const filePath = join69(dir, `${name}.md`);
27997
+ const filePath = join70(dir, `${name}.md`);
27766
27998
  writeFileSync41(filePath, content);
27767
27999
  console.log(`Created command file: ${filePath}`);
27768
28000
  }
@@ -27819,7 +28051,7 @@ function link2() {
27819
28051
 
27820
28052
  // src/commands/run/remove.ts
27821
28053
  import { existsSync as existsSync59, unlinkSync as unlinkSync21 } from "fs";
27822
- import { join as join70 } from "path";
28054
+ import { join as join71 } from "path";
27823
28055
  function findRemoveIndex() {
27824
28056
  const idx = process.argv.indexOf("remove");
27825
28057
  if (idx === -1 || idx + 1 >= process.argv.length) return -1;
@@ -27834,7 +28066,7 @@ function parseRemoveName() {
27834
28066
  return process.argv[idx + 1];
27835
28067
  }
27836
28068
  function deleteCommandFile(name) {
27837
- const filePath = join70(".claude", "commands", `${name}.md`);
28069
+ const filePath = join71(".claude", "commands", `${name}.md`);
27838
28070
  if (existsSync59(filePath)) {
27839
28071
  unlinkSync21(filePath);
27840
28072
  console.log(`Deleted command file: ${filePath}`);
@@ -27891,7 +28123,7 @@ function registerRun(program2) {
27891
28123
  import { execSync as execSync61 } from "child_process";
27892
28124
  import { existsSync as existsSync60, mkdirSync as mkdirSync25, unlinkSync as unlinkSync22, writeFileSync as writeFileSync42 } from "fs";
27893
28125
  import { tmpdir as tmpdir8 } from "os";
27894
- import { join as join71, resolve as resolve18 } from "path";
28126
+ import { join as join72, resolve as resolve19 } from "path";
27895
28127
  import chalk209 from "chalk";
27896
28128
 
27897
28129
  // src/commands/screenshot/captureWindowPs1.ts
@@ -28025,10 +28257,10 @@ function buildOutputPath(outputDir, processName) {
28025
28257
  mkdirSync25(outputDir, { recursive: true });
28026
28258
  }
28027
28259
  const timestamp6 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
28028
- return resolve18(outputDir, `${processName}-${timestamp6}.png`);
28260
+ return resolve19(outputDir, `${processName}-${timestamp6}.png`);
28029
28261
  }
28030
28262
  function runPowerShellScript(processName, outputPath) {
28031
- const scriptPath = join71(tmpdir8(), `assist-screenshot-${Date.now()}.ps1`);
28263
+ const scriptPath = join72(tmpdir8(), `assist-screenshot-${Date.now()}.ps1`);
28032
28264
  writeFileSync42(scriptPath, captureWindowPs1, "utf8");
28033
28265
  try {
28034
28266
  execSync61(
@@ -28041,7 +28273,7 @@ function runPowerShellScript(processName, outputPath) {
28041
28273
  }
28042
28274
  function screenshot(processName) {
28043
28275
  const config = loadConfig();
28044
- const outputDir = resolve18(config.screenshot.outputDir);
28276
+ const outputDir = resolve19(config.screenshot.outputDir);
28045
28277
  const outputPath = buildOutputPath(outputDir, processName);
28046
28278
  console.log(chalk209.gray(`Capturing window for process "${processName}" ...`));
28047
28279
  try {
@@ -28074,18 +28306,18 @@ var STATUS_TIMEOUT_MS = 5e3;
28074
28306
  function queryDaemon(socket) {
28075
28307
  socket.write(`${JSON.stringify({ type: "ping" })}
28076
28308
  `);
28077
- return new Promise((resolve21) => {
28309
+ return new Promise((resolve22) => {
28078
28310
  const result = { sessions: [] };
28079
28311
  const pending = /* @__PURE__ */ new Set(["sessions", "pong"]);
28080
- const timer = setTimeout(() => resolve21(result), STATUS_TIMEOUT_MS);
28081
- const lines = createInterface5({ input: socket });
28082
- lines.on("error", () => {
28312
+ const timer = setTimeout(() => resolve22(result), STATUS_TIMEOUT_MS);
28313
+ const lines2 = createInterface5({ input: socket });
28314
+ lines2.on("error", () => {
28083
28315
  });
28084
- lines.on("line", (line) => {
28316
+ lines2.on("line", (line) => {
28085
28317
  applyLine(result, pending, line);
28086
28318
  if (pending.size === 0) {
28087
28319
  clearTimeout(timer);
28088
- resolve21(result);
28320
+ resolve22(result);
28089
28321
  }
28090
28322
  });
28091
28323
  });
@@ -28170,12 +28402,12 @@ function clearPersistedSessionsOnDrain() {
28170
28402
  }
28171
28403
 
28172
28404
  // src/commands/sessions/daemon/readDaemonMessage.ts
28173
- function readDaemonMessage(lines, timeoutMs, fallback, match) {
28174
- return new Promise((resolve21) => {
28405
+ function readDaemonMessage(lines2, timeoutMs, fallback, match) {
28406
+ return new Promise((resolve22) => {
28175
28407
  const finish = (value) => {
28176
28408
  clearTimeout(timer);
28177
- lines.off("line", onLine);
28178
- resolve21(value);
28409
+ lines2.off("line", onLine);
28410
+ resolve22(value);
28179
28411
  };
28180
28412
  const timer = setTimeout(() => finish(fallback), timeoutMs);
28181
28413
  const onLine = (line) => {
@@ -28185,7 +28417,7 @@ function readDaemonMessage(lines, timeoutMs, fallback, match) {
28185
28417
  } catch {
28186
28418
  }
28187
28419
  };
28188
- lines.on("line", onLine);
28420
+ lines2.on("line", onLine);
28189
28421
  });
28190
28422
  }
28191
28423
 
@@ -28200,10 +28432,10 @@ async function drainDaemon(options2 = {}) {
28200
28432
  clearPersistedSessionsOnDrain();
28201
28433
  return;
28202
28434
  }
28203
- const lines = createInterface6({ input: socket });
28204
- lines.on("error", () => {
28435
+ const lines2 = createInterface6({ input: socket });
28436
+ lines2.on("error", () => {
28205
28437
  });
28206
- const live = await liveSessions(lines);
28438
+ const live = await liveSessions(lines2);
28207
28439
  if (live.length > 0 && options2.yes !== true) {
28208
28440
  reportLive(live);
28209
28441
  if (!await confirmDrain()) {
@@ -28211,7 +28443,7 @@ async function drainDaemon(options2 = {}) {
28211
28443
  return;
28212
28444
  }
28213
28445
  }
28214
- const count8 = await requestDrain(socket, lines);
28446
+ const count8 = await requestDrain(socket, lines2);
28215
28447
  socket.destroy();
28216
28448
  console.log(`Drained ${count8} session(s)`);
28217
28449
  }
@@ -28230,9 +28462,9 @@ async function confirmDrain() {
28230
28462
  console.log("Drain cancelled");
28231
28463
  return false;
28232
28464
  }
28233
- function liveSessions(lines) {
28465
+ function liveSessions(lines2) {
28234
28466
  return readDaemonMessage(
28235
- lines,
28467
+ lines2,
28236
28468
  LIST_TIMEOUT_MS,
28237
28469
  [],
28238
28470
  (data) => data.type === "sessions" ? (data.sessions ?? []).filter(
@@ -28240,11 +28472,11 @@ function liveSessions(lines) {
28240
28472
  ) : void 0
28241
28473
  );
28242
28474
  }
28243
- function requestDrain(socket, lines) {
28475
+ function requestDrain(socket, lines2) {
28244
28476
  socket.write(`${JSON.stringify({ type: "drain" })}
28245
28477
  `);
28246
28478
  return readDaemonMessage(
28247
- lines,
28479
+ lines2,
28248
28480
  DRAIN_TIMEOUT_MS,
28249
28481
  0,
28250
28482
  (data) => data.type === "drained" ? data.count ?? 0 : void 0
@@ -28709,12 +28941,12 @@ import { basename as basename18 } from "path";
28709
28941
 
28710
28942
  // src/commands/sessions/daemon/worktree/deleteStrandedTree.ts
28711
28943
  import { existsSync as existsSync63 } from "fs";
28712
- import { join as join74 } from "path";
28944
+ import { join as join75 } from "path";
28713
28945
 
28714
28946
  // src/commands/sessions/daemon/worktree/deleteTreeDirectly.ts
28715
28947
  import { statSync as statSync12 } from "fs";
28716
28948
  import { rm as rm2 } from "fs/promises";
28717
- import { join as join73 } from "path";
28949
+ import { join as join74 } from "path";
28718
28950
  async function deleteTreeDirectly(clone, worktreePath, why) {
28719
28951
  if (holdsAGitDirectoryRatherThanALink(worktreePath)) {
28720
28952
  daemonLog(
@@ -28741,7 +28973,7 @@ async function deleteTreeDirectly(clone, worktreePath, why) {
28741
28973
  return true;
28742
28974
  }
28743
28975
  function holdsAGitDirectoryRatherThanALink(worktreePath) {
28744
- return statSync12(join73(worktreePath, ".git"), {
28976
+ return statSync12(join74(worktreePath, ".git"), {
28745
28977
  throwIfNoEntry: false
28746
28978
  })?.isDirectory() === true;
28747
28979
  }
@@ -28777,7 +29009,7 @@ async function deleteStrandedTree(clone, worktreePath, cause) {
28777
29009
  );
28778
29010
  }
28779
29011
  function strandedReason(worktreePath, cause) {
28780
- if (!existsSync63(join74(worktreePath, ".git")))
29012
+ if (!existsSync63(join75(worktreePath, ".git")))
28781
29013
  return "its .git link is already gone";
28782
29014
  if (/not a working tree|not a git repository/i.test(reason2(cause)))
28783
29015
  return "git no longer recognises it as a working tree";
@@ -30000,9 +30232,9 @@ async function recordWindowTokens(db, window, resetsAt, tokensUp, tokensDown) {
30000
30232
 
30001
30233
  // src/commands/sessions/shared/transcriptUsage.ts
30002
30234
  import * as fs38 from "fs";
30003
- function transcriptUsage(lines) {
30235
+ function transcriptUsage(lines2) {
30004
30236
  const byId = /* @__PURE__ */ new Map();
30005
- for (const line of lines) {
30237
+ for (const line of lines2) {
30006
30238
  if (!line.trim()) continue;
30007
30239
  let entry;
30008
30240
  try {
@@ -30701,29 +30933,29 @@ async function describeHeldWork(path71, reason4) {
30701
30933
  }
30702
30934
  async function changedFiles(path71) {
30703
30935
  const status3 = await gitResult(path71, ["status", "--porcelain"]);
30704
- const lines = status3.ok ? nonEmptyLines(status3.out) : [];
30936
+ const lines2 = status3.ok ? nonEmptyLines(status3.out) : [];
30705
30937
  return {
30706
- summary: `${lines.length} uncommitted ${lines.length === 1 ? "file" : "files"}`,
30707
- items: capped(lines)
30938
+ summary: `${lines2.length} uncommitted ${lines2.length === 1 ? "file" : "files"}`,
30939
+ items: capped(lines2)
30708
30940
  };
30709
30941
  }
30710
30942
  async function unpushedCommits(path71, reason4) {
30711
30943
  const log2 = await gitResult(path71, ["log", "--oneline", "@{upstream}..HEAD"]);
30712
30944
  if (!log2.ok) return { summary: reason4, items: [] };
30713
- const lines = nonEmptyLines(log2.out);
30945
+ const lines2 = nonEmptyLines(log2.out);
30714
30946
  return {
30715
- summary: `${lines.length} unpushed ${lines.length === 1 ? "commit" : "commits"}`,
30716
- items: capped(lines)
30947
+ summary: `${lines2.length} unpushed ${lines2.length === 1 ? "commit" : "commits"}`,
30948
+ items: capped(lines2)
30717
30949
  };
30718
30950
  }
30719
30951
  function nonEmptyLines(out) {
30720
30952
  return out.split("\n").map((line) => line.trim()).filter((line) => line !== "");
30721
30953
  }
30722
- function capped(lines) {
30723
- if (lines.length <= MAX_ITEMS) return lines;
30954
+ function capped(lines2) {
30955
+ if (lines2.length <= MAX_ITEMS) return lines2;
30724
30956
  return [
30725
- ...lines.slice(0, MAX_ITEMS),
30726
- `\u2026 and ${lines.length - MAX_ITEMS} more`
30957
+ ...lines2.slice(0, MAX_ITEMS),
30958
+ `\u2026 and ${lines2.length - MAX_ITEMS} more`
30727
30959
  ];
30728
30960
  }
30729
30961
 
@@ -31204,7 +31436,7 @@ function windowsDaemonHost() {
31204
31436
  var CONNECT_TIMEOUT_MS = 2e3;
31205
31437
  var KEEPALIVE_PROBE_MS = 1e4;
31206
31438
  function connectToWindowsDaemon() {
31207
- return new Promise((resolve21, reject) => {
31439
+ return new Promise((resolve22, reject) => {
31208
31440
  const socket = net2.connect(windowsDaemonPort(), windowsDaemonHost());
31209
31441
  socket.setTimeout(CONNECT_TIMEOUT_MS);
31210
31442
  socket.once("timeout", () => {
@@ -31214,7 +31446,7 @@ function connectToWindowsDaemon() {
31214
31446
  socket.once("connect", () => {
31215
31447
  socket.setTimeout(0);
31216
31448
  socket.setKeepAlive(true, KEEPALIVE_PROBE_MS);
31217
- resolve21(socket);
31449
+ resolve22(socket);
31218
31450
  });
31219
31451
  socket.once("error", reject);
31220
31452
  });
@@ -31235,9 +31467,9 @@ import { spawn as spawn11 } from "child_process";
31235
31467
  import { createInterface as createInterface7 } from "readline";
31236
31468
  function logChildStream(stream, label2) {
31237
31469
  if (!stream) return;
31238
- const lines = createInterface7({ input: stream });
31239
- lines.on("line", (line) => daemonLog(`[${label2}] ${line}`));
31240
- lines.on("error", () => {
31470
+ const lines2 = createInterface7({ input: stream });
31471
+ lines2.on("line", (line) => daemonLog(`[${label2}] ${line}`));
31472
+ lines2.on("error", () => {
31241
31473
  });
31242
31474
  }
31243
31475
 
@@ -31292,7 +31524,7 @@ async function waitForWindowsDaemon() {
31292
31524
  );
31293
31525
  }
31294
31526
  function delay2(ms) {
31295
- return new Promise((resolve21) => setTimeout(resolve21, ms));
31527
+ return new Promise((resolve22) => setTimeout(resolve22, ms));
31296
31528
  }
31297
31529
 
31298
31530
  // src/commands/sessions/daemon/defaultConnect.ts
@@ -31576,7 +31808,7 @@ async function healWindowsDaemon() {
31576
31808
  daemonLog("windows daemon: auto-heal: stale daemon stopped");
31577
31809
  }
31578
31810
  function runOnWindowsHost(command, timeoutMs) {
31579
- return new Promise((resolve21, reject) => {
31811
+ return new Promise((resolve22, reject) => {
31580
31812
  const child = spawn12("pwsh.exe", ["-Command", command], {
31581
31813
  stdio: ["ignore", "pipe", "pipe"]
31582
31814
  });
@@ -31596,7 +31828,7 @@ function runOnWindowsHost(command, timeoutMs) {
31596
31828
  });
31597
31829
  child.on("exit", (code) => {
31598
31830
  clearTimeout(timer);
31599
- if (code === 0) resolve21();
31831
+ if (code === 0) resolve22();
31600
31832
  else
31601
31833
  reject(
31602
31834
  new Error(
@@ -31707,10 +31939,10 @@ var WindowsConnection = class {
31707
31939
  return socket;
31708
31940
  }
31709
31941
  wire(socket) {
31710
- const lines = createInterface8({ input: socket });
31711
- lines.on("error", () => {
31942
+ const lines2 = createInterface8({ input: socket });
31943
+ lines2.on("error", () => {
31712
31944
  });
31713
- lines.on("line", (line) => this.deps.onLine(line));
31945
+ lines2.on("line", (line) => this.deps.onLine(line));
31714
31946
  socket.on("error", () => {
31715
31947
  });
31716
31948
  socket.on("close", () => {
@@ -32309,9 +32541,9 @@ async function parseTranscript(sessionId) {
32309
32541
  return [];
32310
32542
  }
32311
32543
  }
32312
- function parseTranscriptLines(lines) {
32544
+ function parseTranscriptLines(lines2) {
32313
32545
  const messages = [];
32314
- for (const line of lines) {
32546
+ for (const line of lines2) {
32315
32547
  const entry = line.trim() ? safeParse2(line) : null;
32316
32548
  if (!entry || entry.isSidechain || entry.isMeta) continue;
32317
32549
  messages.push(...entryMessages(entry));
@@ -32493,10 +32725,10 @@ function handleConnection(socket, manager) {
32493
32725
  };
32494
32726
  manager.addClient(client);
32495
32727
  manager.clients.greet(client);
32496
- const lines = createInterface9({ input: socket });
32497
- lines.on("error", () => {
32728
+ const lines2 = createInterface9({ input: socket });
32729
+ lines2.on("error", () => {
32498
32730
  });
32499
- lines.on("line", (line) => {
32731
+ lines2.on("line", (line) => {
32500
32732
  let data;
32501
32733
  try {
32502
32734
  data = JSON.parse(line);
@@ -32957,9 +33189,9 @@ function buildLimitsSegment(rateLimits) {
32957
33189
 
32958
33190
  // src/commands/readGitBranch.ts
32959
33191
  import { readFileSync as readFileSync54, statSync as statSync14 } from "fs";
32960
- import { isAbsolute as isAbsolute4, join as join76, resolve as resolve19 } from "path";
33192
+ import { isAbsolute as isAbsolute4, join as join77, resolve as resolve20 } from "path";
32961
33193
  function resolveGitDir(cwd) {
32962
- const dotGit = join76(cwd, ".git");
33194
+ const dotGit = join77(cwd, ".git");
32963
33195
  let stat3;
32964
33196
  try {
32965
33197
  stat3 = statSync14(dotGit);
@@ -32980,7 +33212,7 @@ function resolveGitDir(cwd) {
32980
33212
  return null;
32981
33213
  }
32982
33214
  const gitDir = match[1].trim();
32983
- return isAbsolute4(gitDir) ? gitDir : resolve19(cwd, gitDir);
33215
+ return isAbsolute4(gitDir) ? gitDir : resolve20(cwd, gitDir);
32984
33216
  }
32985
33217
  function readGitBranch(cwd) {
32986
33218
  const gitDir = resolveGitDir(cwd);
@@ -32989,7 +33221,7 @@ function readGitBranch(cwd) {
32989
33221
  }
32990
33222
  let head;
32991
33223
  try {
32992
- head = readFileSync54(join76(gitDir, "HEAD"), "utf8");
33224
+ head = readFileSync54(join77(gitDir, "HEAD"), "utf8");
32993
33225
  } catch {
32994
33226
  return null;
32995
33227
  }