@staff0rd/assist 0.265.0 → 0.267.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.265.0",
9
+ version: "0.267.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -89,6 +89,7 @@ var package_default = {
89
89
  "@types/ws": "^8.18.1",
90
90
  "@vitest/coverage-v8": "^4.1.2",
91
91
  "@xterm/addon-fit": "^0.11.0",
92
+ "@xterm/addon-web-links": "^0.12.0",
92
93
  "@xterm/xterm": "^6.0.0",
93
94
  esbuild: "^0.27.3",
94
95
  jscpd: "^4.0.5",
@@ -9445,6 +9446,21 @@ function buildArgs2(queryFile, vars) {
9445
9446
  }
9446
9447
  return args;
9447
9448
  }
9449
+ function throwOnGraphqlErrors(stdout) {
9450
+ let parsed;
9451
+ try {
9452
+ parsed = JSON.parse(stdout);
9453
+ } catch {
9454
+ return;
9455
+ }
9456
+ if (!parsed || typeof parsed !== "object") return;
9457
+ const errors = parsed.errors;
9458
+ if (!Array.isArray(errors) || errors.length === 0) return;
9459
+ const messages = errors.map(
9460
+ (entry) => entry && typeof entry === "object" && "message" in entry ? String(entry.message) : String(entry)
9461
+ ).join("; ");
9462
+ throw new Error(messages || "GraphQL request returned errors");
9463
+ }
9448
9464
  function runGhGraphql(mutation, vars) {
9449
9465
  const queryFile = join28(tmpdir4(), `gh-query-${Date.now()}.graphql`);
9450
9466
  writeFileSync19(queryFile, mutation);
@@ -9453,6 +9469,7 @@ function runGhGraphql(mutation, vars) {
9453
9469
  encoding: "utf-8"
9454
9470
  });
9455
9471
  if (result.status !== 0) throw new Error(result.stderr || result.stdout);
9472
+ throwOnGraphqlErrors(result.stdout);
9456
9473
  return result.stdout;
9457
9474
  } finally {
9458
9475
  unlinkSync7(queryFile);
@@ -10596,13 +10613,24 @@ function validateLine(line) {
10596
10613
  process.exit(1);
10597
10614
  }
10598
10615
  }
10616
+ function assertThreadCreated(stdout) {
10617
+ let parsed;
10618
+ try {
10619
+ parsed = JSON.parse(stdout);
10620
+ } catch {
10621
+ throw new Error(`GitHub returned an unparseable response: ${stdout}`);
10622
+ }
10623
+ const id = parsed.data?.addPullRequestReviewThread?.thread?.id;
10624
+ if (typeof id !== "string" || id.length === 0) {
10625
+ throw new Error(
10626
+ "GitHub did not create a review thread (no thread id returned); the line is likely outside the PR diff."
10627
+ );
10628
+ }
10629
+ }
10599
10630
  function postComment(vars) {
10600
10631
  const { startLine, ...base } = vars;
10601
- if (startLine === void 0) {
10602
- runGhGraphql(MUTATION_SINGLE, base);
10603
- return;
10604
- }
10605
- runGhGraphql(MUTATION_MULTI, { ...base, startLine });
10632
+ const stdout = startLine === void 0 ? runGhGraphql(MUTATION_SINGLE, base) : runGhGraphql(MUTATION_MULTI, { ...base, startLine });
10633
+ assertThreadCreated(stdout);
10606
10634
  }
10607
10635
  function comment2(path53, line, body, startLine) {
10608
10636
  validateBody(body);
@@ -13180,6 +13208,37 @@ function registerRefactor(program2) {
13180
13208
  // src/commands/review/review.ts
13181
13209
  import { execFileSync as execFileSync6 } from "child_process";
13182
13210
 
13211
+ // src/commands/review/annotateDiffWithLineNumbers.ts
13212
+ var FILE_HEADER2 = /^\+\+\+ (?:b\/)?(.+)$/;
13213
+ var HUNK_HEADER2 = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/;
13214
+ var GUTTER_WIDTH = 6;
13215
+ function gutter(lineNumber) {
13216
+ const label2 = lineNumber === null ? "" : String(lineNumber);
13217
+ return `${label2.padStart(GUTTER_WIDTH, " ")} `;
13218
+ }
13219
+ function annotateDiffWithLineNumbers(diff2) {
13220
+ let inFile = false;
13221
+ let newLine = 0;
13222
+ return diff2.split("\n").map((line) => {
13223
+ if (FILE_HEADER2.test(line)) {
13224
+ inFile = true;
13225
+ return gutter(null) + line;
13226
+ }
13227
+ const hunkMatch = line.match(HUNK_HEADER2);
13228
+ if (hunkMatch) {
13229
+ newLine = Number(hunkMatch[1]);
13230
+ return gutter(null) + line;
13231
+ }
13232
+ if (!inFile) return gutter(null) + line;
13233
+ if (line.startsWith("+") || line.startsWith(" ")) {
13234
+ const annotated = gutter(newLine) + line;
13235
+ newLine++;
13236
+ return annotated;
13237
+ }
13238
+ return gutter(null) + line;
13239
+ }).join("\n");
13240
+ }
13241
+
13183
13242
  // src/commands/review/formatPriorComments.ts
13184
13243
  function threadKey(c, byId) {
13185
13244
  if (c.threadId) return c.threadId;
@@ -13253,8 +13312,10 @@ ${formatFiles(context.changedFiles)}
13253
13312
  ${priorBlock}
13254
13313
  ## Diff (PR #${context.prNumber}: ${context.baseSha}..${context.headSha})
13255
13314
 
13315
+ Each added or context line is prefixed with a left gutter showing its line number in the new file. When citing a finding as \`file:line\`, use that gutter number \u2014 do **not** count lines in this document. Removed lines (\`-\`) and headers have a blank gutter and cannot be commented on.
13316
+
13256
13317
  \`\`\`diff
13257
- ${context.diff.trimEnd()}
13318
+ ${annotateDiffWithLineNumbers(context.diff.trimEnd())}
13258
13319
  \`\`\`
13259
13320
  `;
13260
13321
  }
@@ -13642,19 +13703,102 @@ async function postAndMaybeSubmit(lineBound, markdown, options2) {
13642
13703
  console.log("Leaving pending review unsubmitted.");
13643
13704
  }
13644
13705
 
13645
- // src/commands/review/warnUnlocated.ts
13706
+ // src/commands/review/buildDiffLineIndex.ts
13707
+ var FILE_HEADER3 = /^\+\+\+ (?:b\/)?(.+)$/;
13708
+ var HUNK_HEADER3 = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/;
13709
+ function buildDiffLineIndex(diff2) {
13710
+ const index2 = /* @__PURE__ */ new Map();
13711
+ let currentFile = null;
13712
+ let newLine = 0;
13713
+ for (const line of diff2.split("\n")) {
13714
+ const fileMatch = line.match(FILE_HEADER3);
13715
+ if (fileMatch) {
13716
+ currentFile = fileMatch[1] === "/dev/null" ? null : fileMatch[1];
13717
+ continue;
13718
+ }
13719
+ const hunkMatch = line.match(HUNK_HEADER3);
13720
+ if (hunkMatch) {
13721
+ newLine = Number(hunkMatch[1]);
13722
+ continue;
13723
+ }
13724
+ if (currentFile === null) continue;
13725
+ if (line.startsWith("-")) continue;
13726
+ if (line.startsWith("+") || line.startsWith(" ")) {
13727
+ let set = index2.get(currentFile);
13728
+ if (!set) {
13729
+ set = /* @__PURE__ */ new Set();
13730
+ index2.set(currentFile, set);
13731
+ }
13732
+ set.add(newLine);
13733
+ newLine++;
13734
+ }
13735
+ }
13736
+ return index2;
13737
+ }
13738
+
13739
+ // src/commands/review/partitionFindingsByDiff.ts
13740
+ function isWithinDiff(finding, index2) {
13741
+ const lines = index2.get(finding.file);
13742
+ if (!lines) return false;
13743
+ if (!lines.has(finding.line)) return false;
13744
+ if (finding.startLine !== void 0 && !lines.has(finding.startLine)) {
13745
+ return false;
13746
+ }
13747
+ return true;
13748
+ }
13749
+ function partitionFindingsByDiff(findings, index2) {
13750
+ const inDiff = [];
13751
+ const outOfDiff = [];
13752
+ for (const finding of findings) {
13753
+ if (isWithinDiff(finding, index2)) inDiff.push(finding);
13754
+ else outOfDiff.push(finding);
13755
+ }
13756
+ return { inDiff, outOfDiff };
13757
+ }
13758
+
13759
+ // src/commands/review/warnOutOfDiff.ts
13646
13760
  import chalk142 from "chalk";
13761
+ function warnOutOfDiff(outOfDiff) {
13762
+ if (outOfDiff.length === 0) return;
13763
+ console.warn(
13764
+ chalk142.yellow(
13765
+ `Skipped ${outOfDiff.length} finding(s) whose lines fall outside the PR diff (GitHub would silently drop these):`
13766
+ )
13767
+ );
13768
+ for (const finding of outOfDiff) {
13769
+ const range = finding.startLine !== void 0 ? `${finding.startLine}-${finding.line}` : `${finding.line}`;
13770
+ console.warn(
13771
+ ` ${chalk142.yellow("\xB7")} ${finding.title} ${chalk142.dim(
13772
+ `(${finding.file}:${range})`
13773
+ )}`
13774
+ );
13775
+ }
13776
+ }
13777
+
13778
+ // src/commands/review/selectInDiffFindings.ts
13779
+ function selectInDiffFindings(lineBound, prDiff) {
13780
+ const diff2 = fetchPrDiff(prDiff.prNumber, prDiff.baseSha, prDiff.headSha);
13781
+ const { inDiff, outOfDiff } = partitionFindingsByDiff(
13782
+ lineBound,
13783
+ buildDiffLineIndex(diff2)
13784
+ );
13785
+ warnOutOfDiff(outOfDiff);
13786
+ return inDiff;
13787
+ }
13788
+
13789
+ // src/commands/review/warnUnlocated.ts
13790
+ import chalk143 from "chalk";
13647
13791
  function warnUnlocated(unlocated) {
13648
13792
  if (unlocated.length === 0) return;
13649
13793
  console.warn(
13650
- chalk142.yellow(
13794
+ chalk143.yellow(
13651
13795
  `Skipped ${unlocated.length} finding(s) without a parseable file:line:`
13652
13796
  )
13653
13797
  );
13654
13798
  for (const finding of unlocated) {
13655
- const where = finding.location || chalk142.dim("missing");
13799
+ const where = finding.location || chalk143.dim("missing");
13656
13800
  console.warn(
13657
- ` ${chalk142.yellow("\xB7")} ${finding.title} ${chalk142.dim(`(${where})`)}`
13801
+ ` ${chalk143.yellow("\xB7")} ${finding.title} ${chalk143.dim(`(${where})`)}`
13658
13802
  );
13659
13803
  }
13660
13804
  }
@@ -13665,11 +13809,8 @@ async function confirmPost(prNumber, count6, options2) {
13665
13809
  return promptConfirm(`Post ${count6} comment(s) to PR #${prNumber}?`, false);
13666
13810
  }
13667
13811
  async function postReviewToPr(synthesisPath, options2) {
13668
- const prNumber = findCurrentPrNumber();
13669
- if (prNumber === null) {
13670
- console.log("No PR found for current branch; nothing posted.");
13671
- return;
13672
- }
13812
+ const prInfo = fetchPrDiffInfo();
13813
+ const prNumber = prInfo.prNumber;
13673
13814
  const markdown = readFileSync31(synthesisPath, "utf-8");
13674
13815
  const findings = parseFindings(markdown);
13675
13816
  if (findings.length === 0) {
@@ -13687,15 +13828,20 @@ async function postReviewToPr(synthesisPath, options2) {
13687
13828
  console.log("No line-bound findings to post.");
13688
13829
  return;
13689
13830
  }
13831
+ const inDiff = selectInDiffFindings(lineBound, prInfo);
13832
+ if (inDiff.length === 0) {
13833
+ console.log("No findings fall within the PR diff; nothing to post.");
13834
+ return;
13835
+ }
13690
13836
  console.log(
13691
- `Found PR #${prNumber} with ${lineBound.length} line-bound finding(s).`
13837
+ `Found PR #${prNumber} with ${inDiff.length} line-bound finding(s) in the diff.`
13692
13838
  );
13693
- const confirmed = await confirmPost(prNumber, lineBound.length, options2);
13839
+ const confirmed = await confirmPost(prNumber, inDiff.length, options2);
13694
13840
  if (!confirmed) {
13695
13841
  console.log("Skipped posting.");
13696
13842
  return;
13697
13843
  }
13698
- await postAndMaybeSubmit(lineBound, markdown, options2);
13844
+ await postAndMaybeSubmit(inDiff, markdown, options2);
13699
13845
  }
13700
13846
 
13701
13847
  // src/commands/review/runRefineSession.ts
@@ -14076,7 +14222,7 @@ List every finding that the original author would want to know about and fix. Do
14076
14222
 
14077
14223
  For each finding include:
14078
14224
  - Severity (blocker, major, minor, nit) \u2014 see rubric below
14079
- - File and line (e.g. \`src/foo.ts:42\`) when the finding is tied to a specific location
14225
+ - File and line (e.g. \`src/foo.ts:42\`) when the finding is tied to a specific location. Take the line number from the diff's left gutter (its line in the new file); never count lines in request.md.
14080
14226
  - Impact: what could go wrong, including the conditions under which it manifests
14081
14227
  - Recommendation: a concrete change
14082
14228
 
@@ -14826,7 +14972,7 @@ function registerReview(program2) {
14826
14972
  }
14827
14973
 
14828
14974
  // src/commands/seq/seqAuth.ts
14829
- import chalk144 from "chalk";
14975
+ import chalk145 from "chalk";
14830
14976
 
14831
14977
  // src/commands/seq/loadConnections.ts
14832
14978
  function loadConnections2() {
@@ -14855,10 +15001,10 @@ function setDefaultConnection(name) {
14855
15001
  }
14856
15002
 
14857
15003
  // src/shared/assertUniqueName.ts
14858
- import chalk143 from "chalk";
15004
+ import chalk144 from "chalk";
14859
15005
  function assertUniqueName(existingNames, name) {
14860
15006
  if (existingNames.includes(name)) {
14861
- console.error(chalk143.red(`Connection "${name}" already exists.`));
15007
+ console.error(chalk144.red(`Connection "${name}" already exists.`));
14862
15008
  process.exit(1);
14863
15009
  }
14864
15010
  }
@@ -14876,16 +15022,16 @@ async function promptConnection2(existingNames) {
14876
15022
  var seqAuth = createConnectionAuth({
14877
15023
  load: loadConnections2,
14878
15024
  save: saveConnections2,
14879
- format: (c) => `${chalk144.bold(c.name)} ${c.url}`,
15025
+ format: (c) => `${chalk145.bold(c.name)} ${c.url}`,
14880
15026
  promptNew: promptConnection2,
14881
15027
  onFirst: (c) => setDefaultConnection(c.name)
14882
15028
  });
14883
15029
 
14884
15030
  // src/commands/seq/seqQuery.ts
14885
- import chalk148 from "chalk";
15031
+ import chalk149 from "chalk";
14886
15032
 
14887
15033
  // src/commands/seq/fetchSeq.ts
14888
- import chalk145 from "chalk";
15034
+ import chalk146 from "chalk";
14889
15035
  async function fetchSeq(conn, path53, params) {
14890
15036
  const url = `${conn.url}${path53}?${params}`;
14891
15037
  const response = await fetch(url, {
@@ -14896,7 +15042,7 @@ async function fetchSeq(conn, path53, params) {
14896
15042
  });
14897
15043
  if (!response.ok) {
14898
15044
  const body = await response.text();
14899
- console.error(chalk145.red(`Seq returned ${response.status}: ${body}`));
15045
+ console.error(chalk146.red(`Seq returned ${response.status}: ${body}`));
14900
15046
  process.exit(1);
14901
15047
  }
14902
15048
  return response;
@@ -14951,23 +15097,23 @@ async function fetchSeqEvents(conn, params) {
14951
15097
  }
14952
15098
 
14953
15099
  // src/commands/seq/formatEvent.ts
14954
- import chalk146 from "chalk";
15100
+ import chalk147 from "chalk";
14955
15101
  function levelColor(level) {
14956
15102
  switch (level) {
14957
15103
  case "Fatal":
14958
- return chalk146.bgRed.white;
15104
+ return chalk147.bgRed.white;
14959
15105
  case "Error":
14960
- return chalk146.red;
15106
+ return chalk147.red;
14961
15107
  case "Warning":
14962
- return chalk146.yellow;
15108
+ return chalk147.yellow;
14963
15109
  case "Information":
14964
- return chalk146.cyan;
15110
+ return chalk147.cyan;
14965
15111
  case "Debug":
14966
- return chalk146.gray;
15112
+ return chalk147.gray;
14967
15113
  case "Verbose":
14968
- return chalk146.dim;
15114
+ return chalk147.dim;
14969
15115
  default:
14970
- return chalk146.white;
15116
+ return chalk147.white;
14971
15117
  }
14972
15118
  }
14973
15119
  function levelAbbrev(level) {
@@ -15008,12 +15154,12 @@ function formatTimestamp(iso) {
15008
15154
  function formatEvent(event) {
15009
15155
  const color = levelColor(event.Level);
15010
15156
  const abbrev = levelAbbrev(event.Level);
15011
- const ts8 = chalk146.dim(formatTimestamp(event.Timestamp));
15157
+ const ts8 = chalk147.dim(formatTimestamp(event.Timestamp));
15012
15158
  const msg = renderMessage(event);
15013
15159
  const lines = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
15014
15160
  if (event.Exception) {
15015
15161
  for (const line of event.Exception.split("\n")) {
15016
- lines.push(chalk146.red(` ${line}`));
15162
+ lines.push(chalk147.red(` ${line}`));
15017
15163
  }
15018
15164
  }
15019
15165
  return lines.join("\n");
@@ -15046,11 +15192,11 @@ function rejectTimestampFilter(filter) {
15046
15192
  }
15047
15193
 
15048
15194
  // src/shared/resolveNamedConnection.ts
15049
- import chalk147 from "chalk";
15195
+ import chalk148 from "chalk";
15050
15196
  function resolveNamedConnection(connections, requested, defaultName, kind, authCommand) {
15051
15197
  if (connections.length === 0) {
15052
15198
  console.error(
15053
- chalk147.red(
15199
+ chalk148.red(
15054
15200
  `No ${kind} connections configured. Run '${authCommand}' first.`
15055
15201
  )
15056
15202
  );
@@ -15059,7 +15205,7 @@ function resolveNamedConnection(connections, requested, defaultName, kind, authC
15059
15205
  const target = requested ?? defaultName ?? connections[0].name;
15060
15206
  const connection = connections.find((c) => c.name === target);
15061
15207
  if (!connection) {
15062
- console.error(chalk147.red(`${kind} connection "${target}" not found.`));
15208
+ console.error(chalk148.red(`${kind} connection "${target}" not found.`));
15063
15209
  process.exit(1);
15064
15210
  }
15065
15211
  return connection;
@@ -15088,7 +15234,7 @@ async function seqQuery(filter, options2) {
15088
15234
  new URLSearchParams({ filter, count: String(count6) })
15089
15235
  );
15090
15236
  if (events.length === 0) {
15091
- console.log(chalk148.yellow("No events found."));
15237
+ console.log(chalk149.yellow("No events found."));
15092
15238
  return;
15093
15239
  }
15094
15240
  if (options2.json) {
@@ -15099,11 +15245,11 @@ async function seqQuery(filter, options2) {
15099
15245
  for (const event of chronological) {
15100
15246
  console.log(formatEvent(event));
15101
15247
  }
15102
- console.log(chalk148.dim(`
15248
+ console.log(chalk149.dim(`
15103
15249
  ${events.length} events`));
15104
15250
  if (events.length >= count6) {
15105
15251
  console.log(
15106
- chalk148.yellow(
15252
+ chalk149.yellow(
15107
15253
  `Results limited to ${count6}. Use --count to retrieve more.`
15108
15254
  )
15109
15255
  );
@@ -15111,10 +15257,10 @@ ${events.length} events`));
15111
15257
  }
15112
15258
 
15113
15259
  // src/shared/setNamedDefaultConnection.ts
15114
- import chalk149 from "chalk";
15260
+ import chalk150 from "chalk";
15115
15261
  function setNamedDefaultConnection(connections, name, setDefault, kind) {
15116
15262
  if (!connections.find((c) => c.name === name)) {
15117
- console.error(chalk149.red(`Connection "${name}" not found.`));
15263
+ console.error(chalk150.red(`Connection "${name}" not found.`));
15118
15264
  process.exit(1);
15119
15265
  }
15120
15266
  setDefault(name);
@@ -15162,7 +15308,7 @@ function registerSignal(program2) {
15162
15308
  }
15163
15309
 
15164
15310
  // src/commands/sql/sqlAuth.ts
15165
- import chalk151 from "chalk";
15311
+ import chalk152 from "chalk";
15166
15312
 
15167
15313
  // src/commands/sql/loadConnections.ts
15168
15314
  function loadConnections3() {
@@ -15191,7 +15337,7 @@ function setDefaultConnection2(name) {
15191
15337
  }
15192
15338
 
15193
15339
  // src/commands/sql/promptConnection.ts
15194
- import chalk150 from "chalk";
15340
+ import chalk151 from "chalk";
15195
15341
  async function promptConnection3(existingNames) {
15196
15342
  const name = await promptInput("name", "Connection name:", "default");
15197
15343
  assertUniqueName(existingNames, name);
@@ -15199,7 +15345,7 @@ async function promptConnection3(existingNames) {
15199
15345
  const portStr = await promptInput("port", "Port:", "1433");
15200
15346
  const port = Number.parseInt(portStr, 10);
15201
15347
  if (!Number.isFinite(port)) {
15202
- console.error(chalk150.red(`Invalid port "${portStr}".`));
15348
+ console.error(chalk151.red(`Invalid port "${portStr}".`));
15203
15349
  process.exit(1);
15204
15350
  }
15205
15351
  const user = await promptInput("user", "User:");
@@ -15212,13 +15358,13 @@ async function promptConnection3(existingNames) {
15212
15358
  var sqlAuth = createConnectionAuth({
15213
15359
  load: loadConnections3,
15214
15360
  save: saveConnections3,
15215
- format: (c) => `${chalk151.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
15361
+ format: (c) => `${chalk152.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
15216
15362
  promptNew: promptConnection3,
15217
15363
  onFirst: (c) => setDefaultConnection2(c.name)
15218
15364
  });
15219
15365
 
15220
15366
  // src/commands/sql/printTable.ts
15221
- import chalk152 from "chalk";
15367
+ import chalk153 from "chalk";
15222
15368
  function formatCell(value) {
15223
15369
  if (value === null || value === void 0) return "";
15224
15370
  if (value instanceof Date) return value.toISOString();
@@ -15227,7 +15373,7 @@ function formatCell(value) {
15227
15373
  }
15228
15374
  function printTable(rows) {
15229
15375
  if (rows.length === 0) {
15230
- console.log(chalk152.yellow("(no rows)"));
15376
+ console.log(chalk153.yellow("(no rows)"));
15231
15377
  return;
15232
15378
  }
15233
15379
  const columns = Object.keys(rows[0]);
@@ -15235,13 +15381,13 @@ function printTable(rows) {
15235
15381
  (col) => Math.max(col.length, ...rows.map((r) => formatCell(r[col]).length))
15236
15382
  );
15237
15383
  const header = columns.map((c, i) => c.padEnd(widths[i])).join(" ");
15238
- console.log(chalk152.dim(header));
15239
- console.log(chalk152.dim("-".repeat(header.length)));
15384
+ console.log(chalk153.dim(header));
15385
+ console.log(chalk153.dim("-".repeat(header.length)));
15240
15386
  for (const row of rows) {
15241
15387
  const line = columns.map((c, i) => formatCell(row[c]).padEnd(widths[i])).join(" ");
15242
15388
  console.log(line);
15243
15389
  }
15244
- console.log(chalk152.dim(`
15390
+ console.log(chalk153.dim(`
15245
15391
  ${rows.length} row${rows.length === 1 ? "" : "s"}`));
15246
15392
  }
15247
15393
 
@@ -15301,7 +15447,7 @@ async function sqlColumns(table, connectionName) {
15301
15447
  }
15302
15448
 
15303
15449
  // src/commands/sql/sqlMutate.ts
15304
- import chalk153 from "chalk";
15450
+ import chalk154 from "chalk";
15305
15451
 
15306
15452
  // src/commands/sql/isMutation.ts
15307
15453
  var MUTATION_KEYWORDS = [
@@ -15335,7 +15481,7 @@ function isMutation(sql4) {
15335
15481
  async function sqlMutate(query, connectionName) {
15336
15482
  if (!isMutation(query)) {
15337
15483
  console.error(
15338
- chalk153.red(
15484
+ chalk154.red(
15339
15485
  "assist sql mutate refuses non-mutating statements. Use `assist sql query` instead."
15340
15486
  )
15341
15487
  );
@@ -15345,18 +15491,18 @@ async function sqlMutate(query, connectionName) {
15345
15491
  const pool = await sqlConnect(conn);
15346
15492
  try {
15347
15493
  const result = await pool.request().query(query);
15348
- console.log(chalk153.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
15494
+ console.log(chalk154.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
15349
15495
  } finally {
15350
15496
  await pool.close();
15351
15497
  }
15352
15498
  }
15353
15499
 
15354
15500
  // src/commands/sql/sqlQuery.ts
15355
- import chalk154 from "chalk";
15501
+ import chalk155 from "chalk";
15356
15502
  async function sqlQuery(query, connectionName) {
15357
15503
  if (isMutation(query)) {
15358
15504
  console.error(
15359
- chalk154.red(
15505
+ chalk155.red(
15360
15506
  "assist sql query refuses mutating statements. Use `assist sql mutate` instead."
15361
15507
  )
15362
15508
  );
@@ -15371,7 +15517,7 @@ async function sqlQuery(query, connectionName) {
15371
15517
  printTable(rows);
15372
15518
  } else {
15373
15519
  console.log(
15374
- chalk154.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
15520
+ chalk155.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
15375
15521
  );
15376
15522
  }
15377
15523
  } finally {
@@ -15951,14 +16097,14 @@ import {
15951
16097
  import { dirname as dirname22, join as join42 } from "path";
15952
16098
 
15953
16099
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
15954
- import chalk155 from "chalk";
16100
+ import chalk156 from "chalk";
15955
16101
  var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
15956
16102
  function validateStagedContent(filename, content) {
15957
16103
  const firstLine = content.split("\n")[0];
15958
16104
  const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
15959
16105
  if (!match) {
15960
16106
  console.error(
15961
- chalk155.red(
16107
+ chalk156.red(
15962
16108
  `Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
15963
16109
  )
15964
16110
  );
@@ -15967,7 +16113,7 @@ function validateStagedContent(filename, content) {
15967
16113
  const contentAfterLink = content.slice(firstLine.length).trim();
15968
16114
  if (!contentAfterLink) {
15969
16115
  console.error(
15970
- chalk155.red(
16116
+ chalk156.red(
15971
16117
  `Staged file ${filename} has no summary content after the transcript link.`
15972
16118
  )
15973
16119
  );
@@ -16364,7 +16510,7 @@ function registerVoice(program2) {
16364
16510
 
16365
16511
  // src/commands/roam/auth.ts
16366
16512
  import { randomBytes } from "crypto";
16367
- import chalk156 from "chalk";
16513
+ import chalk157 from "chalk";
16368
16514
 
16369
16515
  // src/lib/openBrowser.ts
16370
16516
  import { execSync as execSync46 } from "child_process";
@@ -16539,13 +16685,13 @@ async function auth() {
16539
16685
  saveGlobalConfig(config);
16540
16686
  const state = randomBytes(16).toString("hex");
16541
16687
  console.log(
16542
- chalk156.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
16688
+ chalk157.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
16543
16689
  );
16544
- console.log(chalk156.white("http://localhost:14523/callback\n"));
16545
- console.log(chalk156.blue("Opening browser for authorization..."));
16546
- console.log(chalk156.dim("Waiting for authorization callback..."));
16690
+ console.log(chalk157.white("http://localhost:14523/callback\n"));
16691
+ console.log(chalk157.blue("Opening browser for authorization..."));
16692
+ console.log(chalk157.dim("Waiting for authorization callback..."));
16547
16693
  const { code, redirectUri } = await authorizeInBrowser(clientId, state);
16548
- console.log(chalk156.dim("Exchanging code for tokens..."));
16694
+ console.log(chalk157.dim("Exchanging code for tokens..."));
16549
16695
  const tokens = await exchangeToken({
16550
16696
  code,
16551
16697
  clientId,
@@ -16561,7 +16707,7 @@ async function auth() {
16561
16707
  };
16562
16708
  saveGlobalConfig(config);
16563
16709
  console.log(
16564
- chalk156.green("Roam credentials and tokens saved to ~/.assist.yml")
16710
+ chalk157.green("Roam credentials and tokens saved to ~/.assist.yml")
16565
16711
  );
16566
16712
  }
16567
16713
 
@@ -17013,7 +17159,7 @@ import { execSync as execSync48 } from "child_process";
17013
17159
  import { existsSync as existsSync50, mkdirSync as mkdirSync20, unlinkSync as unlinkSync16, writeFileSync as writeFileSync32 } from "fs";
17014
17160
  import { tmpdir as tmpdir7 } from "os";
17015
17161
  import { join as join53, resolve as resolve13 } from "path";
17016
- import chalk157 from "chalk";
17162
+ import chalk158 from "chalk";
17017
17163
 
17018
17164
  // src/commands/screenshot/captureWindowPs1.ts
17019
17165
  var captureWindowPs1 = `
@@ -17164,13 +17310,13 @@ function screenshot(processName) {
17164
17310
  const config = loadConfig();
17165
17311
  const outputDir = resolve13(config.screenshot.outputDir);
17166
17312
  const outputPath = buildOutputPath(outputDir, processName);
17167
- console.log(chalk157.gray(`Capturing window for process "${processName}" ...`));
17313
+ console.log(chalk158.gray(`Capturing window for process "${processName}" ...`));
17168
17314
  try {
17169
17315
  runPowerShellScript(processName, outputPath);
17170
- console.log(chalk157.green(`Screenshot saved: ${outputPath}`));
17316
+ console.log(chalk158.green(`Screenshot saved: ${outputPath}`));
17171
17317
  } catch (error) {
17172
17318
  const msg = error instanceof Error ? error.message : String(error);
17173
- console.error(chalk157.red(`Failed to capture screenshot: ${msg}`));
17319
+ console.error(chalk158.red(`Failed to capture screenshot: ${msg}`));
17174
17320
  process.exit(1);
17175
17321
  }
17176
17322
  }
@@ -18316,7 +18462,7 @@ function registerDaemon(program2) {
18316
18462
 
18317
18463
  // src/commands/sessions/summarise/index.ts
18318
18464
  import * as fs30 from "fs";
18319
- import chalk158 from "chalk";
18465
+ import chalk159 from "chalk";
18320
18466
 
18321
18467
  // src/commands/sessions/summarise/shared.ts
18322
18468
  import * as fs28 from "fs";
@@ -18443,22 +18589,22 @@ ${firstMessage}`);
18443
18589
  async function summarise4(options2) {
18444
18590
  const files = await discoverSessionJsonlPaths();
18445
18591
  if (files.length === 0) {
18446
- console.log(chalk158.yellow("No sessions found."));
18592
+ console.log(chalk159.yellow("No sessions found."));
18447
18593
  return;
18448
18594
  }
18449
18595
  const toProcess = selectCandidates(files, options2);
18450
18596
  if (toProcess.length === 0) {
18451
- console.log(chalk158.green("All sessions already summarised."));
18597
+ console.log(chalk159.green("All sessions already summarised."));
18452
18598
  return;
18453
18599
  }
18454
18600
  console.log(
18455
- chalk158.cyan(
18601
+ chalk159.cyan(
18456
18602
  `Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
18457
18603
  )
18458
18604
  );
18459
18605
  const { succeeded, failed: failed2 } = processSessions(toProcess);
18460
18606
  console.log(
18461
- chalk158.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk158.yellow(`, ${failed2} skipped`) : "")
18607
+ chalk159.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk159.yellow(`, ${failed2} skipped`) : "")
18462
18608
  );
18463
18609
  }
18464
18610
  function selectCandidates(files, options2) {
@@ -18478,16 +18624,16 @@ function processSessions(files) {
18478
18624
  let failed2 = 0;
18479
18625
  for (let i = 0; i < files.length; i++) {
18480
18626
  const file = files[i];
18481
- process.stdout.write(chalk158.dim(` [${i + 1}/${files.length}] `));
18627
+ process.stdout.write(chalk159.dim(` [${i + 1}/${files.length}] `));
18482
18628
  const summary = summariseSession(file);
18483
18629
  if (summary) {
18484
18630
  writeSummary(file, summary);
18485
18631
  succeeded++;
18486
- process.stdout.write(`${chalk158.green("\u2713")} ${summary}
18632
+ process.stdout.write(`${chalk159.green("\u2713")} ${summary}
18487
18633
  `);
18488
18634
  } else {
18489
18635
  failed2++;
18490
- process.stdout.write(` ${chalk158.yellow("skip")}
18636
+ process.stdout.write(` ${chalk159.yellow("skip")}
18491
18637
  `);
18492
18638
  }
18493
18639
  }
@@ -18502,10 +18648,10 @@ function registerSessions(program2) {
18502
18648
  }
18503
18649
 
18504
18650
  // src/commands/statusLine.ts
18505
- import chalk160 from "chalk";
18651
+ import chalk161 from "chalk";
18506
18652
 
18507
18653
  // src/commands/buildLimitsSegment.ts
18508
- import chalk159 from "chalk";
18654
+ import chalk160 from "chalk";
18509
18655
  var FIVE_HOUR_SECONDS = 5 * 3600;
18510
18656
  var SEVEN_DAY_SECONDS = 7 * 86400;
18511
18657
  function formatTimeLeft(resetsAt) {
@@ -18528,10 +18674,10 @@ function projectUsage(pct, resetsAt, windowSeconds) {
18528
18674
  function colorizeRateLimit(pct, resetsAt, windowSeconds) {
18529
18675
  const label2 = `${Math.round(pct)}%`;
18530
18676
  const projected = projectUsage(pct, resetsAt, windowSeconds);
18531
- if (projected == null) return chalk159.green(label2);
18532
- if (projected > 100) return chalk159.red(label2);
18533
- if (projected > 75) return chalk159.yellow(label2);
18534
- return chalk159.green(label2);
18677
+ if (projected == null) return chalk160.green(label2);
18678
+ if (projected > 100) return chalk160.red(label2);
18679
+ if (projected > 75) return chalk160.yellow(label2);
18680
+ return chalk160.green(label2);
18535
18681
  }
18536
18682
  function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel) {
18537
18683
  const timeLabel = resetsAt ? formatTimeLeft(resetsAt) : fallbackLabel;
@@ -18557,14 +18703,14 @@ function buildLimitsSegment(rateLimits) {
18557
18703
  }
18558
18704
 
18559
18705
  // src/commands/statusLine.ts
18560
- chalk160.level = 3;
18706
+ chalk161.level = 3;
18561
18707
  function formatNumber(num) {
18562
18708
  return num.toLocaleString("en-US");
18563
18709
  }
18564
18710
  function colorizePercent(pct) {
18565
18711
  const label2 = `${Math.round(pct)}%`;
18566
- if (pct > 80) return chalk160.red(label2);
18567
- if (pct > 40) return chalk160.yellow(label2);
18712
+ if (pct > 80) return chalk161.red(label2);
18713
+ if (pct > 40) return chalk161.yellow(label2);
18568
18714
  return label2;
18569
18715
  }
18570
18716
  async function statusLine() {
@@ -18587,7 +18733,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
18587
18733
  // src/commands/sync/syncClaudeMd.ts
18588
18734
  import * as fs31 from "fs";
18589
18735
  import * as path49 from "path";
18590
- import chalk161 from "chalk";
18736
+ import chalk162 from "chalk";
18591
18737
  async function syncClaudeMd(claudeDir, targetBase, options2) {
18592
18738
  const source = path49.join(claudeDir, "CLAUDE.md");
18593
18739
  const target = path49.join(targetBase, "CLAUDE.md");
@@ -18596,12 +18742,12 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
18596
18742
  const targetContent = fs31.readFileSync(target, "utf-8");
18597
18743
  if (sourceContent !== targetContent) {
18598
18744
  console.log(
18599
- chalk161.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
18745
+ chalk162.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
18600
18746
  );
18601
18747
  console.log();
18602
18748
  printDiff(targetContent, sourceContent);
18603
18749
  const confirm = options2?.yes || await promptConfirm(
18604
- chalk161.red("Overwrite existing CLAUDE.md?"),
18750
+ chalk162.red("Overwrite existing CLAUDE.md?"),
18605
18751
  false
18606
18752
  );
18607
18753
  if (!confirm) {
@@ -18617,7 +18763,7 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
18617
18763
  // src/commands/sync/syncSettings.ts
18618
18764
  import * as fs32 from "fs";
18619
18765
  import * as path50 from "path";
18620
- import chalk162 from "chalk";
18766
+ import chalk163 from "chalk";
18621
18767
  async function syncSettings(claudeDir, targetBase, options2) {
18622
18768
  const source = path50.join(claudeDir, "settings.json");
18623
18769
  const target = path50.join(targetBase, "settings.json");
@@ -18633,14 +18779,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
18633
18779
  if (mergedContent !== normalizedTarget) {
18634
18780
  if (!options2?.yes) {
18635
18781
  console.log(
18636
- chalk162.yellow(
18782
+ chalk163.yellow(
18637
18783
  "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
18638
18784
  )
18639
18785
  );
18640
18786
  console.log();
18641
18787
  printDiff(targetContent, mergedContent);
18642
18788
  const confirm = await promptConfirm(
18643
- chalk162.red("Overwrite existing settings.json?"),
18789
+ chalk163.red("Overwrite existing settings.json?"),
18644
18790
  false
18645
18791
  );
18646
18792
  if (!confirm) {