@staff0rd/assist 0.575.0 → 0.577.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.575.0",
9
+ version: "0.577.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -13949,7 +13949,7 @@ import chalk71 from "chalk";
13949
13949
  import { randomUUID as randomUUID2 } from "crypto";
13950
13950
 
13951
13951
  // src/commands/sessions/shared/reportPreviewRejection.ts
13952
- function reportPreviewRejection(subject, decision) {
13952
+ function reportPreviewRejection(subject, decision, advice) {
13953
13953
  console.error(
13954
13954
  `${subject} rejected${decision.reason ? `: ${decision.reason}` : "."}`
13955
13955
  );
@@ -13968,6 +13968,7 @@ ${quoted}
13968
13968
  `);
13969
13969
  }
13970
13970
  }
13971
+ if (advice) console.error(advice);
13971
13972
  process.exit(1);
13972
13973
  }
13973
13974
 
@@ -14030,7 +14031,7 @@ function requestPreviewDecision(request) {
14030
14031
  }
14031
14032
 
14032
14033
  // src/commands/sessions/shared/awaitPreviewApproval.ts
14033
- async function awaitPreviewApproval(subject, request, saveEditedBody) {
14034
+ async function awaitPreviewApproval(subject, request, options2 = {}) {
14034
14035
  console.log("Awaiting your approval in the assist web UI preview pane\u2026");
14035
14036
  let decision;
14036
14037
  try {
@@ -14041,8 +14042,9 @@ async function awaitPreviewApproval(subject, request, saveEditedBody) {
14041
14042
  );
14042
14043
  process.exit(1);
14043
14044
  }
14044
- if (decision.body !== void 0) saveEditedBody?.(decision.body);
14045
- if (decision.decision === "reject") reportPreviewRejection(subject, decision);
14045
+ if (decision.body !== void 0) options2.saveEditedBody?.(decision.body);
14046
+ if (decision.decision === "reject")
14047
+ reportPreviewRejection(subject, decision, options2.rejectionAdvice);
14046
14048
  return decision;
14047
14049
  }
14048
14050
 
@@ -14912,12 +14914,12 @@ async function link(fromId, toId, opts) {
14912
14914
  const { orm } = await getReady();
14913
14915
  const fromItem = await loadItem(orm, fromNum);
14914
14916
  if (!fromItem) return void fail4(`Item ${from} not found.`);
14915
- const toItem = await loadItem(orm, toNum);
14916
- if (!toItem) return void fail4(`Item ${to} not found.`);
14917
+ const toItem2 = await loadItem(orm, toNum);
14918
+ if (!toItem2) return void fail4(`Item ${to} not found.`);
14917
14919
  if (!validateLinkTarget(fromItem, fromNum, toNum, linkType)) return;
14918
14920
  if (await createsCycle(orm, linkType, fromNum, toNum)) return;
14919
14921
  await orm.insert(links).values({ itemId: fromNum, type: linkType, targetId: toNum });
14920
- console.log(chalk85.green(`Linked ${from} ${linkType} ${to} (${toItem.name})`));
14922
+ console.log(chalk85.green(`Linked ${from} ${linkType} ${to} (${toItem2.name})`));
14921
14923
  }
14922
14924
 
14923
14925
  // src/commands/backlog/unlink.ts
@@ -20500,14 +20502,8 @@ import { spawnSync as spawnSync4 } from "child_process";
20500
20502
  import { unlinkSync as unlinkSync12, writeFileSync as writeFileSync30 } from "fs";
20501
20503
  import { tmpdir as tmpdir5 } from "os";
20502
20504
  import { join as join49 } from "path";
20503
- function buildArgs2(queryFile, vars) {
20504
- const args = ["api", "graphql", "-F", `query=@${queryFile}`];
20505
- for (const [key, value] of Object.entries(vars)) {
20506
- const flag = typeof value === "number" ? "-F" : "-f";
20507
- args.push(flag, `${key}=${value}`);
20508
- }
20509
- return args;
20510
- }
20505
+
20506
+ // src/shared/throwOnGraphqlErrors.ts
20511
20507
  function throwOnGraphqlErrors(stdout) {
20512
20508
  let parsed;
20513
20509
  try {
@@ -20523,6 +20519,16 @@ function throwOnGraphqlErrors(stdout) {
20523
20519
  ).join("; ");
20524
20520
  throw new Error(messages || "GraphQL request returned errors");
20525
20521
  }
20522
+
20523
+ // src/shared/runGhGraphql.ts
20524
+ function buildArgs2(queryFile, vars) {
20525
+ const args = ["api", "graphql", "-F", `query=@${queryFile}`];
20526
+ for (const [key, value] of Object.entries(vars)) {
20527
+ const flag = typeof value === "number" ? "-F" : "-f";
20528
+ args.push(flag, `${key}=${value}`);
20529
+ }
20530
+ return args;
20531
+ }
20526
20532
  function runGhGraphql(mutation, vars) {
20527
20533
  const queryFile = join49(tmpdir5(), `gh-query-${Date.now()}.graphql`);
20528
20534
  writeFileSync30(queryFile, mutation);
@@ -20830,6 +20836,83 @@ function fetchIssue2(number, repo) {
20830
20836
  }
20831
20837
  }
20832
20838
 
20839
+ // src/commands/github/issue/resumeIssueBody.ts
20840
+ import { existsSync as existsSync48, readFileSync as readFileSync37 } from "fs";
20841
+
20842
+ // src/commands/github/issue/issueWorkingFile.ts
20843
+ import { join as join50 } from "path";
20844
+ function issueWorkingFile(slug, number) {
20845
+ const [owner = "unknown", repo = "unknown"] = slug.split("/");
20846
+ const dir = join50(getStoreDir(), "github-issues", owner, repo);
20847
+ return {
20848
+ dir,
20849
+ bodyPath: join50(dir, `${number}.md`),
20850
+ metaPath: join50(dir, `${number}.json`)
20851
+ };
20852
+ }
20853
+
20854
+ // src/commands/github/issue/resumeIssueBody.ts
20855
+ function resumeIssueBody(slug, number, updatedAt) {
20856
+ const { bodyPath, metaPath } = issueWorkingFile(slug, number);
20857
+ if (!existsSync48(bodyPath) || !existsSync48(metaPath)) return void 0;
20858
+ try {
20859
+ const meta = JSON.parse(readFileSync37(metaPath, "utf8"));
20860
+ if (meta.updatedAt !== updatedAt) return void 0;
20861
+ return readFileSync37(bodyPath, "utf8");
20862
+ } catch {
20863
+ return void 0;
20864
+ }
20865
+ }
20866
+
20867
+ // src/commands/github/issue/validateIssueBody.ts
20868
+ function validateIssueBody(title, body) {
20869
+ validateProposedContent(
20870
+ { subject: "Issue", context: "GitHub issues" },
20871
+ title,
20872
+ body
20873
+ );
20874
+ }
20875
+
20876
+ // src/commands/github/issue/writeIssueWorkingFile.ts
20877
+ import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync31 } from "fs";
20878
+ function writeIssueWorkingFile(slug, number, target, updatedAt, body) {
20879
+ const { dir, bodyPath, metaPath } = issueWorkingFile(slug, number);
20880
+ mkdirSync16(dir, { recursive: true });
20881
+ writeFileSync31(bodyPath, body);
20882
+ writeFileSync31(
20883
+ metaPath,
20884
+ `${JSON.stringify({ target, updatedAt }, null, 2)}
20885
+ `
20886
+ );
20887
+ return bodyPath;
20888
+ }
20889
+
20890
+ // src/commands/github/issue/prepareIssueEdit.ts
20891
+ function slugFromUrl(url) {
20892
+ const match = /github\.com\/([^/]+\/[^/]+)\//.exec(url ?? "");
20893
+ return match ? match[1] : "unknown/unknown";
20894
+ }
20895
+ function prepareIssueEdit(number, repo, fresh) {
20896
+ const issue = fetchIssue2(number, repo);
20897
+ const slug = repo ?? slugFromUrl(issue.url);
20898
+ const target = `${slug}#${number}`;
20899
+ const resumed = fresh ? void 0 : resumeIssueBody(slug, number, issue.updatedAt);
20900
+ const body = resumed ?? issue.body;
20901
+ validateIssueBody(issue.title, body);
20902
+ const save = (markdown) => writeIssueWorkingFile(slug, number, target, issue.updatedAt, markdown);
20903
+ const bodyPath = save(body);
20904
+ if (resumed !== void 0)
20905
+ console.log(`Previewing the in-progress markdown from ${bodyPath}`);
20906
+ return {
20907
+ title: issue.title,
20908
+ target,
20909
+ updatedAt: issue.updatedAt,
20910
+ body,
20911
+ bodyPath,
20912
+ save
20913
+ };
20914
+ }
20915
+
20833
20916
  // src/commands/github/issue/pushIssueBody.ts
20834
20917
  import { execFileSync as execFileSync9 } from "child_process";
20835
20918
  function pushIssueBody(number, repo, bodyPath) {
@@ -20856,7 +20939,7 @@ function pushUnchangedIssue(number, repo, target, fetchedAt, bodyPath) {
20856
20939
 
20857
20940
  // src/commands/github/issue/reviewProposedIssueEdit.ts
20858
20941
  import { randomUUID as randomUUID9 } from "crypto";
20859
- async function reviewProposedIssueEdit(title, body, saveEditedBody) {
20942
+ async function reviewProposedIssueEdit(title, body, working) {
20860
20943
  const sessionId = process.env.ASSIST_SESSION_ID;
20861
20944
  if (process.env.ASSIST_SESSION !== "1" || !sessionId) return body;
20862
20945
  const decision = await awaitPreviewApproval(
@@ -20869,7 +20952,10 @@ async function reviewProposedIssueEdit(title, body, saveEditedBody) {
20869
20952
  prNumber: null,
20870
20953
  kind: "github-issue-edit"
20871
20954
  },
20872
- saveEditedBody
20955
+ {
20956
+ saveEditedBody: working.save,
20957
+ rejectionAdvice: `Nothing was pushed. The pane's markdown, including any collapses already applied, is at ${working.path}. Revise that file in place \u2014 do not recompose the body from scratch \u2014 then re-run this command to preview the revision.`
20958
+ }
20873
20959
  );
20874
20960
  return decision.body ?? body;
20875
20961
  }
@@ -20886,40 +20972,8 @@ function viewIssue(number, repo) {
20886
20972
  }
20887
20973
  }
20888
20974
 
20889
- // src/commands/github/issue/writeIssueWorkingFile.ts
20890
- import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync31 } from "fs";
20891
-
20892
- // src/commands/github/issue/issueWorkingFile.ts
20893
- import { join as join50 } from "path";
20894
- function issueWorkingFile(slug, number) {
20895
- const [owner = "unknown", repo = "unknown"] = slug.split("/");
20896
- const dir = join50(getStoreDir(), "github-issues", owner, repo);
20897
- return {
20898
- dir,
20899
- bodyPath: join50(dir, `${number}.md`),
20900
- metaPath: join50(dir, `${number}.json`)
20901
- };
20902
- }
20903
-
20904
- // src/commands/github/issue/writeIssueWorkingFile.ts
20905
- function writeIssueWorkingFile(slug, number, target, updatedAt, body) {
20906
- const { dir, bodyPath, metaPath } = issueWorkingFile(slug, number);
20907
- mkdirSync16(dir, { recursive: true });
20908
- writeFileSync31(bodyPath, body);
20909
- writeFileSync31(
20910
- metaPath,
20911
- `${JSON.stringify({ target, updatedAt }, null, 2)}
20912
- `
20913
- );
20914
- return bodyPath;
20915
- }
20916
-
20917
20975
  // src/commands/github/issue/editIssue.ts
20918
20976
  var USAGE3 = "Usage: assist github issue edit <number> [-R <owner>/<repo>]";
20919
- function slugFromUrl(url) {
20920
- const match = /github\.com\/([^/]+\/[^/]+)\//.exec(url ?? "");
20921
- return match ? match[1] : "unknown/unknown";
20922
- }
20923
20977
  async function editIssue(numberArg, options2) {
20924
20978
  const number = Number.parseInt(numberArg, 10);
20925
20979
  if (!Number.isInteger(number) || number <= 0) {
@@ -20930,27 +20984,419 @@ async function editIssue(numberArg, options2) {
20930
20984
  viewIssue(number, options2.repo);
20931
20985
  return;
20932
20986
  }
20933
- const issue = fetchIssue2(number, options2.repo);
20934
- const slug = options2.repo ?? slugFromUrl(issue.url);
20935
- const target = `${slug}#${number}`;
20936
- validateProposedContent(
20937
- { subject: "Issue", context: "GitHub issues" },
20938
- issue.title,
20939
- issue.body
20940
- );
20941
- const save = (markdown) => writeIssueWorkingFile(slug, number, target, issue.updatedAt, markdown);
20942
- const bodyPath = save(issue.body);
20987
+ const issue = prepareIssueEdit(number, options2.repo, options2.fresh);
20943
20988
  const edited = await reviewProposedIssueEdit(
20944
- `Edit ${target}: ${issue.title}`,
20989
+ `Edit ${issue.target}: ${issue.title}`,
20945
20990
  issue.body,
20946
- save
20991
+ { path: issue.bodyPath, save: issue.save }
20947
20992
  );
20948
- validateProposedContent(
20949
- { subject: "Issue", context: "GitHub issues" },
20950
- issue.title,
20951
- edited
20993
+ validateIssueBody(issue.title, edited);
20994
+ pushUnchangedIssue(
20995
+ number,
20996
+ options2.repo,
20997
+ issue.target,
20998
+ issue.updatedAt,
20999
+ issue.bodyPath
20952
21000
  );
20953
- pushUnchangedIssue(number, options2.repo, target, issue.updatedAt, bodyPath);
21001
+ }
21002
+
21003
+ // src/commands/github/issue/fixStructure/matchedLabels.ts
21004
+ function matchedLabels(labels, stripLabels) {
21005
+ if (stripLabels.length === 0) return [];
21006
+ const wanted = new Set(stripLabels.map((name) => name.trim().toLowerCase()));
21007
+ return labels.filter((label2) => wanted.has(label2.name.trim().toLowerCase()));
21008
+ }
21009
+
21010
+ // src/commands/github/issue/fixStructure/normaliseTypeName.ts
21011
+ function normaliseTypeName(name) {
21012
+ return name.toLowerCase().replace(/[^a-z0-9]/g, "");
21013
+ }
21014
+
21015
+ // src/commands/github/issue/fixStructure/resolveIssueType.ts
21016
+ function resolveIssueType(issueTypes, levelName) {
21017
+ const wanted = normaliseTypeName(levelName);
21018
+ const match = issueTypes.find(
21019
+ (type) => normaliseTypeName(type.name) === wanted
21020
+ );
21021
+ if (!match) {
21022
+ throw new Error(
21023
+ `The organisation has no ${levelName} issue type. It has ${issueTypes.map((type) => type.name).join(", ")}`
21024
+ );
21025
+ }
21026
+ return match;
21027
+ }
21028
+
21029
+ // src/commands/github/issue/fixStructure/resolveLevelIndex.ts
21030
+ function resolveLevelIndex(chain2, name) {
21031
+ if (!name) return -1;
21032
+ const wanted = normaliseTypeName(name);
21033
+ return chain2.findIndex((level) => normaliseTypeName(level) === wanted);
21034
+ }
21035
+
21036
+ // src/commands/github/issue/fixStructure/buildPlanEntry.ts
21037
+ function buildPlanEntry(issue, context) {
21038
+ const labelRemovals = matchedLabels(issue.labels, context.stripLabels);
21039
+ const level = context.chain[context.rootLevelIndex + issue.depth];
21040
+ if (level === void 0) {
21041
+ return { issue, level: null, typeChange: null, labelRemovals };
21042
+ }
21043
+ const settled = resolveLevelIndex([level], issue.typeName) === 0 || issue.depth === 0 && !context.rootAsserted;
21044
+ if (settled) return { issue, level, typeChange: null, labelRemovals };
21045
+ const target = resolveIssueType(context.issueTypes, level);
21046
+ return {
21047
+ issue,
21048
+ level,
21049
+ typeChange: { from: issue.typeName, to: target.name, typeId: target.id },
21050
+ labelRemovals
21051
+ };
21052
+ }
21053
+
21054
+ // src/commands/github/issue/fixStructure/orderDepthFirst.ts
21055
+ function orderDepthFirst(issues) {
21056
+ const byParent = /* @__PURE__ */ new Map();
21057
+ for (const issue of issues) {
21058
+ const siblings = byParent.get(issue.parentId) ?? [];
21059
+ siblings.push(issue);
21060
+ byParent.set(issue.parentId, siblings);
21061
+ }
21062
+ const ordered = [];
21063
+ const visit = (issue) => {
21064
+ ordered.push(issue);
21065
+ for (const child of byParent.get(issue.id) ?? []) visit(child);
21066
+ };
21067
+ for (const root of byParent.get(null) ?? []) visit(root);
21068
+ return ordered;
21069
+ }
21070
+
21071
+ // src/commands/github/issue/fixStructure/buildFixStructurePlan.ts
21072
+ function buildFixStructurePlan(issues, options2) {
21073
+ const context = { ...options2, stripLabels: options2.stripLabels ?? [] };
21074
+ const byId = new Map(issues.map((issue) => [issue.id, issue]));
21075
+ const entries = [];
21076
+ const tooDeep = [];
21077
+ for (const issue of orderDepthFirst(issues)) {
21078
+ const entry = buildPlanEntry(issue, context);
21079
+ entries.push(entry);
21080
+ if (entry.level === null) {
21081
+ tooDeep.push({
21082
+ issue,
21083
+ parent: issue.parentId ? byId.get(issue.parentId) ?? null : null
21084
+ });
21085
+ }
21086
+ }
21087
+ return {
21088
+ entries,
21089
+ tooDeep,
21090
+ typeChangeCount: entries.filter((entry) => entry.typeChange).length,
21091
+ labelRemovalCount: entries.reduce(
21092
+ (total, entry) => total + entry.labelRemovals.length,
21093
+ 0
21094
+ )
21095
+ };
21096
+ }
21097
+
21098
+ // src/shared/runGhGraphqlJson.ts
21099
+ import { spawnSync as spawnSync5 } from "child_process";
21100
+ function runGhGraphqlJson(query, vars = {}) {
21101
+ const result = spawnSync5("gh", ["api", "graphql", "--input", "-"], {
21102
+ encoding: "utf8",
21103
+ windowsHide: true,
21104
+ input: JSON.stringify({ query, variables: vars }),
21105
+ maxBuffer: 64 * 1024 * 1024
21106
+ });
21107
+ if (result.status !== 0) throw new Error(result.stderr || result.stdout);
21108
+ throwOnGraphqlErrors(result.stdout);
21109
+ return result.stdout;
21110
+ }
21111
+
21112
+ // src/commands/github/issue/fixStructure/issueFieldsFragment.ts
21113
+ var issueFieldsFragment = `fragment issueFields on Issue {
21114
+ id
21115
+ number
21116
+ title
21117
+ issueType { name }
21118
+ repository { nameWithOwner }
21119
+ labels(first: 100) { nodes { id name } pageInfo { hasNextPage } }
21120
+ subIssues(first: 100) { nodes { id } pageInfo { hasNextPage } }
21121
+ }`;
21122
+
21123
+ // src/commands/github/issue/fixStructure/parseIssueNode.ts
21124
+ function parseIssueNode(node) {
21125
+ const raw = node;
21126
+ const repo = raw.repository?.nameWithOwner ?? "";
21127
+ const where = `${repo}#${raw.number}`;
21128
+ if (raw.labels?.pageInfo?.hasNextPage) {
21129
+ throw new Error(
21130
+ `${where} carries more than 100 labels, which is not supported`
21131
+ );
21132
+ }
21133
+ if (raw.subIssues?.pageInfo?.hasNextPage) {
21134
+ throw new Error(
21135
+ `${where} has more than 100 sub-issues, which is not supported`
21136
+ );
21137
+ }
21138
+ return {
21139
+ id: raw.id,
21140
+ number: raw.number,
21141
+ title: raw.title,
21142
+ repo,
21143
+ typeName: raw.issueType?.name ?? null,
21144
+ labels: (raw.labels?.nodes ?? []).filter((label2) => label2 !== null),
21145
+ childIds: (raw.subIssues?.nodes ?? []).filter((child) => child !== null).map((child) => child.id)
21146
+ };
21147
+ }
21148
+
21149
+ // src/commands/github/issue/fixStructure/fetchRootIssue.ts
21150
+ var QUERY = `query($owner: String!, $repo: String!, $number: Int!) {
21151
+ repository(owner: $owner, name: $repo) {
21152
+ issue(number: $number) { ...issueFields }
21153
+ }
21154
+ }
21155
+ ${issueFieldsFragment}`;
21156
+ function fetchRootIssue(target) {
21157
+ const raw = runGhGraphqlJson(QUERY, {
21158
+ owner: target.owner,
21159
+ repo: target.repo,
21160
+ number: target.number
21161
+ });
21162
+ const issue = JSON.parse(raw).data?.repository?.issue;
21163
+ if (!issue) {
21164
+ throw new Error(
21165
+ `No issue ${target.owner}/${target.repo}#${target.number} could be read`
21166
+ );
21167
+ }
21168
+ return parseIssueNode(issue);
21169
+ }
21170
+
21171
+ // src/commands/github/issue/fixStructure/printFixStructurePlan.ts
21172
+ import chalk162 from "chalk";
21173
+ function annotate(entry) {
21174
+ const notes = [];
21175
+ if (entry.level === null) {
21176
+ notes.push(chalk162.red("deeper than the leaf level"));
21177
+ } else if (entry.typeChange) {
21178
+ notes.push(
21179
+ chalk162.yellow(
21180
+ `${entry.typeChange.from ?? "no type"} -> ${entry.typeChange.to}`
21181
+ )
21182
+ );
21183
+ } else {
21184
+ notes.push(chalk162.dim(entry.issue.typeName ?? "no type"));
21185
+ }
21186
+ for (const label2 of entry.labelRemovals) {
21187
+ notes.push(chalk162.yellow(`-${label2.name}`));
21188
+ }
21189
+ return notes;
21190
+ }
21191
+ function formatCount(count8, noun) {
21192
+ return `${count8} ${noun}${count8 === 1 ? "" : "s"}`;
21193
+ }
21194
+ function printFixStructurePlan(plan2, chain2) {
21195
+ console.log(chalk162.dim(`chain: ${chain2.join(" > ")}`));
21196
+ for (const entry of plan2.entries) {
21197
+ const indent3 = " ".repeat(entry.issue.depth);
21198
+ const name = chalk162.cyan(`${entry.issue.repo}#${entry.issue.number}`);
21199
+ console.log(
21200
+ `${indent3}${name} ${entry.issue.title} [${annotate(entry).join(", ")}]`
21201
+ );
21202
+ }
21203
+ for (const { issue, parent } of plan2.tooDeep) {
21204
+ const where = parent ? ` under ${parent.repo}#${parent.number}` : "";
21205
+ console.error(
21206
+ chalk162.red(
21207
+ `${issue.repo}#${issue.number}${where} sits below ${chain2[chain2.length - 1]}, the leaf level`
21208
+ )
21209
+ );
21210
+ }
21211
+ if (plan2.typeChangeCount === 0 && plan2.labelRemovalCount === 0) {
21212
+ console.log(chalk162.green("Nothing to change"));
21213
+ return;
21214
+ }
21215
+ console.log(
21216
+ `${formatCount(plan2.typeChangeCount, "type change")}, ${formatCount(plan2.labelRemovalCount, "label removal")} planned`
21217
+ );
21218
+ console.log(chalk162.dim("Dry run \u2014 nothing written"));
21219
+ }
21220
+
21221
+ // src/commands/github/issue/fixStructure/resolveFixStructureTarget.ts
21222
+ var BARE_NUMBER = /^#?(\d+)$/;
21223
+ var REPO_SLUG = /^([^/\s]+)\/([^/\s]+)$/;
21224
+ function resolveFixStructureTarget(target, repo) {
21225
+ const shorthand = normalizeGithubIssue(target);
21226
+ if (shorthand) {
21227
+ const [slug2, number] = shorthand.split("#");
21228
+ const [owner, name] = (slug2 ?? "").split("/");
21229
+ return { owner: owner ?? "", repo: name ?? "", number: Number(number) };
21230
+ }
21231
+ const bare = BARE_NUMBER.exec(target.trim());
21232
+ if (!bare) {
21233
+ throw new Error(
21234
+ `Could not read "${target}" as a GitHub issue. Pass owner/repo#number, a github.com issue URL, or a bare number with --repo owner/repo`
21235
+ );
21236
+ }
21237
+ if (!repo) {
21238
+ throw new Error(
21239
+ `A bare issue number needs a repository. Re-run with --repo owner/repo, or pass the issue as owner/repo#${bare[1]}`
21240
+ );
21241
+ }
21242
+ const slug = REPO_SLUG.exec(repo.trim());
21243
+ if (!slug) {
21244
+ throw new Error(`--repo must be owner/repo, not "${repo}"`);
21245
+ }
21246
+ return {
21247
+ owner: slug[1] ?? "",
21248
+ repo: slug[2] ?? "",
21249
+ number: Number(bare[1])
21250
+ };
21251
+ }
21252
+
21253
+ // src/commands/github/issue/fixStructure/resolveOrgIssueTypes.ts
21254
+ var QUERY2 = `query($owner: String!) {
21255
+ organization(login: $owner) {
21256
+ issueTypes(first: 50) { nodes { id name } }
21257
+ }
21258
+ }`;
21259
+ function missingOrg(owner) {
21260
+ return new Error(
21261
+ `Issue types live on the organisation, and ${owner} is not one this token can read`
21262
+ );
21263
+ }
21264
+ function resolveOrgIssueTypes(owner) {
21265
+ let raw;
21266
+ try {
21267
+ raw = runGhGraphqlJson(QUERY2, { owner });
21268
+ } catch (error) {
21269
+ const message3 = error instanceof Error ? error.message : String(error);
21270
+ if (message3.includes("Could not resolve to an Organization")) {
21271
+ throw missingOrg(owner);
21272
+ }
21273
+ throw error;
21274
+ }
21275
+ const organization = JSON.parse(raw).data?.organization;
21276
+ if (!organization) throw missingOrg(owner);
21277
+ const types = (organization.issueTypes?.nodes ?? []).filter(
21278
+ (type) => type !== null
21279
+ );
21280
+ if (types.length === 0) {
21281
+ throw new Error(`The ${owner} organisation has no issue types defined`);
21282
+ }
21283
+ return types;
21284
+ }
21285
+
21286
+ // src/commands/github/issue/fixStructure/resolveRootLevelIndex.ts
21287
+ function resolveRootLevelIndex(chain2, targetTypeName, level) {
21288
+ if (level) {
21289
+ const index4 = resolveLevelIndex(chain2, level);
21290
+ if (index4 === -1) {
21291
+ throw new Error(
21292
+ `--level must name one of ${chain2.join(", ")}, not "${level}"`
21293
+ );
21294
+ }
21295
+ return { index: index4, asserted: true };
21296
+ }
21297
+ const index3 = resolveLevelIndex(chain2, targetTypeName);
21298
+ if (index3 === -1) {
21299
+ const has = targetTypeName ? `has the type ${targetTypeName}, which is not in the ${chain2.join(" > ")} chain` : "has no issue type";
21300
+ throw new Error(
21301
+ `The target ${has}, so its level cannot be inferred. Re-run with --level ${chain2.map((name) => name.toLowerCase()).join("|")} to assert where it sits.`
21302
+ );
21303
+ }
21304
+ return { index: index3, asserted: false };
21305
+ }
21306
+
21307
+ // src/commands/github/issue/fixStructure/types.ts
21308
+ var defaultTypeChain = ["Epic", "Story", "Subtask"];
21309
+
21310
+ // src/commands/github/issue/fixStructure/fetchSubtreeIssues.ts
21311
+ var QUERY3 = `query($ids: [ID!]!) {
21312
+ nodes(ids: $ids) { ... on Issue { ...issueFields } }
21313
+ }
21314
+ ${issueFieldsFragment}`;
21315
+ var BATCH = 50;
21316
+ function fetchSubtreeIssues(ids) {
21317
+ const issues = [];
21318
+ for (let start3 = 0; start3 < ids.length; start3 += BATCH) {
21319
+ const raw = runGhGraphqlJson(QUERY3, {
21320
+ ids: ids.slice(start3, start3 + BATCH)
21321
+ });
21322
+ const nodes = JSON.parse(raw).data?.nodes ?? [];
21323
+ for (const node of nodes) {
21324
+ if (node) issues.push(parseIssueNode(node));
21325
+ }
21326
+ }
21327
+ return issues;
21328
+ }
21329
+
21330
+ // src/commands/github/issue/fixStructure/walkSubtree.ts
21331
+ function walkSubtree(root, maxDepth, fetchIssues = fetchSubtreeIssues) {
21332
+ const placed = [{ ...root, depth: 0, parentId: null }];
21333
+ const seen = /* @__PURE__ */ new Set([root.id]);
21334
+ let frontier = placed;
21335
+ for (let depth = 1; depth <= maxDepth && frontier.length > 0; depth += 1) {
21336
+ const parentOf2 = /* @__PURE__ */ new Map();
21337
+ for (const parent of frontier) {
21338
+ for (const childId of parent.childIds) {
21339
+ if (seen.has(childId)) continue;
21340
+ seen.add(childId);
21341
+ parentOf2.set(childId, parent.id);
21342
+ }
21343
+ }
21344
+ if (parentOf2.size === 0) break;
21345
+ const children = fetchIssues([...parentOf2.keys()]).map((issue) => ({
21346
+ ...issue,
21347
+ depth,
21348
+ parentId: parentOf2.get(issue.id) ?? null
21349
+ }));
21350
+ placed.push(...children);
21351
+ frontier = children;
21352
+ }
21353
+ return placed;
21354
+ }
21355
+
21356
+ // src/commands/github/issue/fixStructure/fixStructure.ts
21357
+ function fixStructure(target, options2) {
21358
+ const chain2 = defaultTypeChain;
21359
+ try {
21360
+ const resolved = resolveFixStructureTarget(target, options2.repo);
21361
+ const root = fetchRootIssue(resolved);
21362
+ const { index: index3, asserted } = resolveRootLevelIndex(
21363
+ chain2,
21364
+ root.typeName,
21365
+ options2.level
21366
+ );
21367
+ const issueTypes = resolveOrgIssueTypes(resolved.owner);
21368
+ const issues = walkSubtree(root, chain2.length - index3);
21369
+ const plan2 = buildFixStructurePlan(issues, {
21370
+ chain: chain2,
21371
+ rootLevelIndex: index3,
21372
+ rootAsserted: asserted,
21373
+ issueTypes
21374
+ });
21375
+ printFixStructurePlan(plan2, chain2);
21376
+ } catch (error) {
21377
+ console.error(error instanceof Error ? error.message : String(error));
21378
+ process.exit(1);
21379
+ }
21380
+ }
21381
+
21382
+ // src/commands/github/issue/fixStructure/registerFixStructure.ts
21383
+ var chain = defaultTypeChain.join(" > ");
21384
+ var levels = defaultTypeChain.map((name) => name.toLowerCase()).join("|");
21385
+ function registerFixStructure(issueCommand) {
21386
+ issueCommand.command("fix-structure <target>").description("Report the issue type drift across one issue subtree").option(
21387
+ "-R, --repo <owner/repo>",
21388
+ "Repository a bare issue number belongs to"
21389
+ ).option(
21390
+ "--level <level>",
21391
+ `The target's own position in the ${chain} chain, when it cannot be inferred from its type`
21392
+ ).addHelpText(
21393
+ "after",
21394
+ `
21395
+ Walks the subtree reachable from <target> via sub-issues and reports the type each issue should carry: every level below the target is typed to the next level down the ${chain} chain. Nothing outside the subtree is ever read or written.
21396
+ The target's own level is inferred from its issue type, so aiming at a story types its children as subtasks. When the target's type is not in the chain the level cannot be inferred, and --level ${levels} asserts it instead \u2014 which also plans the target's own type.
21397
+ The target is owner/repo#number, a github.com issue URL, or a bare number with --repo.
21398
+ This reports only; nothing is written.`
21399
+ ).action(fixStructure);
20954
21400
  }
20955
21401
 
20956
21402
  // src/commands/prs/readBodyArgument.ts
@@ -20977,9 +21423,12 @@ function registerGithubIssue(githubCommand) {
20977
21423
  issueCommand.command("edit <number>").description("Edit an existing GitHub issue's body in the preview pane").option(
20978
21424
  "-R, --repo <owner/repo>",
20979
21425
  "Target repository (defaults to the current repo)"
21426
+ ).option(
21427
+ "--fresh",
21428
+ "Discard any working file for the issue and re-fetch its body from GitHub"
20980
21429
  ).addHelpText(
20981
21430
  "after",
20982
- "\nFetches the issue's current body and opens it in the assist web preview pane, where it can be reworked before it is pushed back. Approving pushes the pane's markdown to the issue; nothing is pushed if the issue moved on GitHub after it was fetched, or outside a web session.\nOnly the body is touched \u2014 the title, labels, assignees and state are left alone."
21431
+ "\nFetches the issue's current body and opens it in the assist web preview pane, where it can be reworked before it is pushed back. Approving pushes the pane's markdown to the issue; nothing is pushed if the issue moved on GitHub after it was fetched, or outside a web session.\nRejecting writes the pane's markdown to a working file and names it: revise that file in place and re-run to preview the revision, which keeps any collapses already applied. A re-run resumes from the working file while the issue has not moved on GitHub; --fresh discards it and re-fetches.\nOnly the body is touched \u2014 the title, labels, assignees and state are left alone."
20983
21432
  ).action(editIssue);
20984
21433
  issueCommand.command("comment <number>").description("Comment on a GitHub issue (body of - reads it from stdin)").option("--body <body>", "Comment body (- reads it from stdin)").option(
20985
21434
  "-R, --repo <owner/repo>",
@@ -20995,6 +21444,7 @@ function registerGithubIssue(githubCommand) {
20995
21444
  });
20996
21445
  }
20997
21446
  );
21447
+ registerFixStructure(issueCommand);
20998
21448
  }
20999
21449
 
21000
21450
  // src/commands/registerGithub.ts
@@ -21021,9 +21471,9 @@ async function countPendingHandovers(orm, origin) {
21021
21471
 
21022
21472
  // src/commands/handover/migrateDiskHandovers.ts
21023
21473
  import {
21024
- existsSync as existsSync48,
21474
+ existsSync as existsSync49,
21025
21475
  readdirSync as readdirSync10,
21026
- readFileSync as readFileSync37,
21476
+ readFileSync as readFileSync38,
21027
21477
  rmSync as rmSync3,
21028
21478
  statSync as statSync8
21029
21479
  } from "fs";
@@ -21076,7 +21526,7 @@ function summariseHandoverContent(content) {
21076
21526
 
21077
21527
  // src/commands/handover/migrateDiskHandovers.ts
21078
21528
  function collectMarkdown(dir) {
21079
- if (!existsSync48(dir)) return [];
21529
+ if (!existsSync49(dir)) return [];
21080
21530
  const out = [];
21081
21531
  for (const entry of readdirSync10(dir, { withFileTypes: true })) {
21082
21532
  const full = join53(dir, entry.name);
@@ -21086,7 +21536,7 @@ function collectMarkdown(dir) {
21086
21536
  return out;
21087
21537
  }
21088
21538
  async function migrateFile(orm, origin, file, createdAt) {
21089
- const content = readFileSync37(file, "utf8");
21539
+ const content = readFileSync38(file, "utf8");
21090
21540
  await saveHandover(orm, {
21091
21541
  origin,
21092
21542
  summary: summariseHandoverContent(content),
@@ -21103,7 +21553,7 @@ async function migrateDiskHandovers(orm, origin, cwd = process.cwd()) {
21103
21553
  migrated++;
21104
21554
  }
21105
21555
  const handoverPath = getHandoverPath(cwd);
21106
- if (existsSync48(handoverPath)) {
21556
+ if (existsSync49(handoverPath)) {
21107
21557
  await migrateFile(orm, origin, handoverPath, statSync8(handoverPath).mtime);
21108
21558
  migrated++;
21109
21559
  }
@@ -21234,7 +21684,7 @@ function registerHandover(program2) {
21234
21684
  }
21235
21685
 
21236
21686
  // src/commands/jira/acceptanceCriteria.ts
21237
- import chalk162 from "chalk";
21687
+ import chalk163 from "chalk";
21238
21688
 
21239
21689
  // src/commands/jira/adfToText.ts
21240
21690
  function renderInline(node) {
@@ -21301,7 +21751,7 @@ function acceptanceCriteria(issueKey) {
21301
21751
  const parsed = fetchIssue(issueKey, field);
21302
21752
  const acValue = parsed?.fields?.[field];
21303
21753
  if (!acValue) {
21304
- console.log(chalk162.yellow(`No acceptance criteria found on ${issueKey}.`));
21754
+ console.log(chalk163.yellow(`No acceptance criteria found on ${issueKey}.`));
21305
21755
  return;
21306
21756
  }
21307
21757
  if (typeof acValue === "string") {
@@ -21367,14 +21817,14 @@ async function jiraAuth() {
21367
21817
  }
21368
21818
 
21369
21819
  // src/commands/jira/viewIssue.ts
21370
- import chalk163 from "chalk";
21820
+ import chalk164 from "chalk";
21371
21821
  function viewIssue2(issueKey) {
21372
21822
  const parsed = fetchIssue(issueKey, "summary,description");
21373
21823
  const fields = parsed?.fields;
21374
21824
  const summary = fields?.summary;
21375
21825
  const description = fields?.description;
21376
21826
  if (summary) {
21377
- console.log(chalk163.bold(summary));
21827
+ console.log(chalk164.bold(summary));
21378
21828
  }
21379
21829
  if (description) {
21380
21830
  if (summary) console.log();
@@ -21388,7 +21838,7 @@ function viewIssue2(issueKey) {
21388
21838
  }
21389
21839
  if (!summary && !description) {
21390
21840
  console.log(
21391
- chalk163.yellow(`No summary or description found on ${issueKey}.`)
21841
+ chalk164.yellow(`No summary or description found on ${issueKey}.`)
21392
21842
  );
21393
21843
  }
21394
21844
  }
@@ -21423,7 +21873,7 @@ import { randomUUID as randomUUID10 } from "crypto";
21423
21873
 
21424
21874
  // src/commands/review/checkoutPr.ts
21425
21875
  import { execFileSync as execFileSync12 } from "child_process";
21426
- import chalk164 from "chalk";
21876
+ import chalk165 from "chalk";
21427
21877
 
21428
21878
  // src/commands/sessions/daemon/daemonLog.ts
21429
21879
  var RING_CAPACITY = 1e3;
@@ -21460,7 +21910,7 @@ function canonicalTreePath(path80) {
21460
21910
  }
21461
21911
 
21462
21912
  // src/commands/sessions/daemon/worktree/createWorktree.ts
21463
- import { existsSync as existsSync49 } from "fs";
21913
+ import { existsSync as existsSync50 } from "fs";
21464
21914
  import { basename as basename16, dirname as dirname25 } from "path";
21465
21915
 
21466
21916
  // src/commands/sessions/daemon/worktree/planAllocation.ts
@@ -21507,7 +21957,7 @@ function createWorktree(clone, strategy, boundTreeRoots2, preferredPath) {
21507
21957
  const base = strategy.root ? expandTilde2(strategy.root) : dirname25(clone);
21508
21958
  const registered = new Set(listWorktreePaths(clone));
21509
21959
  const branches = new Set(listLocalBranches(clone));
21510
- const isTaken = (candidate) => registered.has(candidate) || existsSync49(candidate) || boundTreeRoots2.has(candidate) || branches.has(basename16(candidate));
21960
+ const isTaken = (candidate) => registered.has(candidate) || existsSync50(candidate) || boundTreeRoots2.has(candidate) || branches.has(basename16(candidate));
21511
21961
  const path80 = preferredPath && !isTaken(preferredPath) ? preferredPath : nextWorktreePath(clone, base, isTaken);
21512
21962
  const start3 = worktreeStartPoint(clone, strategy.trunk);
21513
21963
  gitSync(clone, [
@@ -21533,7 +21983,7 @@ function keptInTree(cwd, reason4) {
21533
21983
  }
21534
21984
 
21535
21985
  // src/commands/sessions/daemon/worktree/treeDurability.ts
21536
- import { existsSync as existsSync50 } from "fs";
21986
+ import { existsSync as existsSync51 } from "fs";
21537
21987
  var treeIsGone = { durable: true, gone: true };
21538
21988
  function treeDurability(state) {
21539
21989
  if (state.dirty) return { durable: false, reason: "uncommitted changes" };
@@ -21564,14 +22014,14 @@ function* durabilityProbes() {
21564
22014
  });
21565
22015
  }
21566
22016
  async function checkDurability(cwd) {
21567
- if (!existsSync50(cwd)) return treeIsGone;
22017
+ if (!existsSync51(cwd)) return treeIsGone;
21568
22018
  const probes = durabilityProbes();
21569
22019
  let step2 = probes.next();
21570
22020
  while (!step2.done) step2 = probes.next(await gitResult(cwd, step2.value));
21571
22021
  return step2.value;
21572
22022
  }
21573
22023
  function checkDurabilitySync(cwd) {
21574
- if (!existsSync50(cwd)) return treeIsGone;
22024
+ if (!existsSync51(cwd)) return treeIsGone;
21575
22025
  const probes = durabilityProbes();
21576
22026
  let step2 = probes.next();
21577
22027
  while (!step2.done) step2 = probes.next(gitSyncResult(cwd, step2.value));
@@ -21814,20 +22264,20 @@ function persistedTreeRoots() {
21814
22264
  }
21815
22265
 
21816
22266
  // src/commands/sessions/daemon/worktree/seedWorktree.ts
21817
- import { copyFileSync, existsSync as existsSync52, mkdirSync as mkdirSync17 } from "fs";
22267
+ import { copyFileSync, existsSync as existsSync53, mkdirSync as mkdirSync17 } from "fs";
21818
22268
  import { dirname as dirname26, join as join56 } from "path";
21819
22269
 
21820
22270
  // src/commands/sessions/daemon/worktree/runInstall.ts
21821
22271
  import { spawn as spawn5 } from "child_process";
21822
22272
 
21823
22273
  // src/commands/sessions/daemon/worktree/resolveInstallCommand.ts
21824
- import { existsSync as existsSync51 } from "fs";
22274
+ import { existsSync as existsSync52 } from "fs";
21825
22275
  import { join as join55 } from "path";
21826
22276
  function detectInstallCommand(repoRoot2) {
21827
- if (!existsSync51(join55(repoRoot2, "package.json"))) return null;
21828
- if (existsSync51(join55(repoRoot2, "pnpm-lock.yaml"))) return "pnpm install";
21829
- if (existsSync51(join55(repoRoot2, "yarn.lock"))) return "yarn install";
21830
- if (existsSync51(join55(repoRoot2, "bun.lockb"))) return "bun install";
22277
+ if (!existsSync52(join55(repoRoot2, "package.json"))) return null;
22278
+ if (existsSync52(join55(repoRoot2, "pnpm-lock.yaml"))) return "pnpm install";
22279
+ if (existsSync52(join55(repoRoot2, "yarn.lock"))) return "yarn install";
22280
+ if (existsSync52(join55(repoRoot2, "bun.lockb"))) return "bun install";
21831
22281
  return "npm install";
21832
22282
  }
21833
22283
  function resolveInstallCommand(repoRoot2, install) {
@@ -21940,7 +22390,7 @@ function seedWorktree(worktreePath, clone, onSeeded = () => {
21940
22390
  function copyConfigFiles(worktreePath, clone, copy) {
21941
22391
  for (const rel of copy) {
21942
22392
  const src = join56(clone, rel);
21943
- if (!existsSync52(src)) continue;
22393
+ if (!existsSync53(src)) continue;
21944
22394
  const dest = join56(worktreePath, rel);
21945
22395
  try {
21946
22396
  mkdirSync17(dirname26(dest), { recursive: true });
@@ -22035,7 +22485,7 @@ async function checkoutPr(number) {
22035
22485
  try {
22036
22486
  execFileSync12("gh", ["pr", "checkout", number], { stdio: "inherit" });
22037
22487
  } catch {
22038
- console.error(chalk164.red(`gh pr checkout ${number} failed; aborting.`));
22488
+ console.error(chalk165.red(`gh pr checkout ${number} failed; aborting.`));
22039
22489
  process.exit(1);
22040
22490
  }
22041
22491
  }
@@ -22172,15 +22622,15 @@ function registerList(program2) {
22172
22622
  // src/commands/mermaid/index.ts
22173
22623
  import { mkdirSync as mkdirSync18, readdirSync as readdirSync11 } from "fs";
22174
22624
  import { resolve as resolve16 } from "path";
22175
- import chalk167 from "chalk";
22625
+ import chalk168 from "chalk";
22176
22626
 
22177
22627
  // src/commands/mermaid/exportFile.ts
22178
- import { readFileSync as readFileSync38, writeFileSync as writeFileSync32 } from "fs";
22628
+ import { readFileSync as readFileSync39, writeFileSync as writeFileSync32 } from "fs";
22179
22629
  import { basename as basename17, extname as extname2, resolve as resolve15 } from "path";
22180
- import chalk166 from "chalk";
22630
+ import chalk167 from "chalk";
22181
22631
 
22182
22632
  // src/commands/mermaid/renderBlock.ts
22183
- import chalk165 from "chalk";
22633
+ import chalk166 from "chalk";
22184
22634
  async function renderBlock(krokiUrl, source) {
22185
22635
  const response = await fetch(`${krokiUrl}/mermaid/svg`, {
22186
22636
  method: "POST",
@@ -22189,7 +22639,7 @@ async function renderBlock(krokiUrl, source) {
22189
22639
  });
22190
22640
  if (!response.ok) {
22191
22641
  console.error(
22192
- chalk165.red(
22642
+ chalk166.red(
22193
22643
  `Kroki request failed: ${response.status} ${response.statusText}`
22194
22644
  )
22195
22645
  );
@@ -22201,25 +22651,25 @@ async function renderBlock(krokiUrl, source) {
22201
22651
 
22202
22652
  // src/commands/mermaid/exportFile.ts
22203
22653
  async function exportFile(file, outDir, krokiUrl, onlyIndex) {
22204
- const content = readFileSync38(file, "utf8");
22654
+ const content = readFileSync39(file, "utf8");
22205
22655
  const blocks = extractMermaidBlocks(content);
22206
22656
  const stem = basename17(file, extname2(file));
22207
22657
  if (onlyIndex !== void 0) {
22208
22658
  if (onlyIndex < 1 || onlyIndex > blocks.length) {
22209
22659
  console.error(
22210
- chalk166.red(
22660
+ chalk167.red(
22211
22661
  `${file}: --index ${onlyIndex} out of range (file has ${blocks.length} diagram(s))`
22212
22662
  )
22213
22663
  );
22214
22664
  process.exit(1);
22215
22665
  }
22216
22666
  console.log(
22217
- chalk166.gray(
22667
+ chalk167.gray(
22218
22668
  `${file} \u2014 rendering diagram ${onlyIndex} of ${blocks.length}`
22219
22669
  )
22220
22670
  );
22221
22671
  } else {
22222
- console.log(chalk166.gray(`${file} \u2014 ${blocks.length} diagram(s)`));
22672
+ console.log(chalk167.gray(`${file} \u2014 ${blocks.length} diagram(s)`));
22223
22673
  }
22224
22674
  for (const [i, source] of blocks.entries()) {
22225
22675
  const idx = i + 1;
@@ -22227,7 +22677,7 @@ async function exportFile(file, outDir, krokiUrl, onlyIndex) {
22227
22677
  const outPath = resolve15(outDir, `${stem}-${idx}.svg`);
22228
22678
  const svg = await renderBlock(krokiUrl, source);
22229
22679
  writeFileSync32(outPath, svg, "utf8");
22230
- console.log(chalk166.green(` \u2192 ${outPath}`));
22680
+ console.log(chalk167.green(` \u2192 ${outPath}`));
22231
22681
  }
22232
22682
  }
22233
22683
  function extractMermaidBlocks(markdown) {
@@ -22243,18 +22693,18 @@ async function mermaidExport(file, options2 = {}) {
22243
22693
  if (options2.index !== void 0) {
22244
22694
  if (!Number.isInteger(options2.index) || options2.index < 1) {
22245
22695
  console.error(
22246
- chalk167.red(`--index must be a positive integer (got ${options2.index})`)
22696
+ chalk168.red(`--index must be a positive integer (got ${options2.index})`)
22247
22697
  );
22248
22698
  process.exit(1);
22249
22699
  }
22250
22700
  if (!file) {
22251
- console.error(chalk167.red("--index requires a file argument"));
22701
+ console.error(chalk168.red("--index requires a file argument"));
22252
22702
  process.exit(1);
22253
22703
  }
22254
22704
  }
22255
22705
  const files = file ? [file] : readdirSync11(process.cwd()).filter((name) => name.toLowerCase().endsWith(".md")).sort();
22256
22706
  if (files.length === 0) {
22257
- console.log(chalk167.gray("No markdown files found in current directory."));
22707
+ console.log(chalk168.gray("No markdown files found in current directory."));
22258
22708
  return;
22259
22709
  }
22260
22710
  for (const f of files) {
@@ -22277,11 +22727,191 @@ function registerMermaid(program2) {
22277
22727
  configHelp(cmd, mermaidConfigHelp);
22278
22728
  }
22279
22729
 
22730
+ // src/commands/miro/runExtract.ts
22731
+ import { stringify } from "yaml";
22732
+
22733
+ // src/commands/miro/MiroExtractError.ts
22734
+ var MiroExtractError = class extends Error {
22735
+ constructor(message3) {
22736
+ super(message3);
22737
+ this.name = "MiroExtractError";
22738
+ }
22739
+ };
22740
+
22741
+ // src/commands/miro/stripHtml.ts
22742
+ var namedEntities = {
22743
+ amp: "&",
22744
+ apos: "'",
22745
+ gt: ">",
22746
+ lt: "<",
22747
+ nbsp: " ",
22748
+ quot: '"'
22749
+ };
22750
+ function decodeEntity(_match, entity) {
22751
+ if (entity.startsWith("#")) {
22752
+ const code = entity.startsWith("#x") || entity.startsWith("#X") ? Number.parseInt(entity.slice(2), 16) : Number.parseInt(entity.slice(1), 10);
22753
+ return Number.isNaN(code) ? _match : String.fromCodePoint(code);
22754
+ }
22755
+ return namedEntities[entity.toLowerCase()] ?? _match;
22756
+ }
22757
+ function stripHtml2(content) {
22758
+ return content.replace(/<br\s*\/?>/gi, " ").replace(/<\/(?:p|div|li|h[1-6])>/gi, " ").replace(/<[^>]*>/g, "").replace(/&(#[0-9a-f]+|[a-z]+);/gi, decodeEntity).replace(/\s+/g, " ").trim();
22759
+ }
22760
+
22761
+ // src/commands/miro/normaliseItems.ts
22762
+ var frameCoordinates = "parent_top_left";
22763
+ function describe2(item) {
22764
+ return ` ${item.id ?? "(no id)"} (${item.type ?? "unknown type"}): relativeTo=${item.position?.relativeTo ?? "missing"}`;
22765
+ }
22766
+ function coordinateSpaceError(rejected) {
22767
+ return new MiroExtractError(
22768
+ `${rejected.length} item(s) are not in frame coordinates (position.relativeTo must be "${frameCoordinates}"):
22769
+ ${rejected.slice(0, 5).map(describe2).join(
22770
+ "\n"
22771
+ )}
22772
+
22773
+ Dump the frame with board_list_items using ?moveToWidget=<frame id> so every item shares one coordinate space.`
22774
+ );
22775
+ }
22776
+ function toItem(item) {
22777
+ const halfWidth = (item.geometry?.width ?? 0) / 2;
22778
+ const halfHeight = (item.geometry?.height ?? 0) / 2;
22779
+ const x = item.position?.x ?? 0;
22780
+ const y = item.position?.y ?? 0;
22781
+ return {
22782
+ id: item.id ?? "",
22783
+ type: item.type ?? "",
22784
+ text: stripHtml2(item.data?.content ?? ""),
22785
+ left: x - halfWidth,
22786
+ top: y - halfHeight,
22787
+ right: x + halfWidth,
22788
+ bottom: y + halfHeight
22789
+ };
22790
+ }
22791
+ function normaliseItems(items2) {
22792
+ const rejected = items2.filter(
22793
+ (item) => item.position?.relativeTo !== frameCoordinates
22794
+ );
22795
+ if (rejected.length > 0) throw coordinateSpaceError(rejected);
22796
+ return items2.map(toItem);
22797
+ }
22798
+
22799
+ // src/commands/miro/parseAnchorId.ts
22800
+ function parseAnchorId(value) {
22801
+ const trimmed = value.trim();
22802
+ const link3 = /[?&]moveToWidget=([^&#]+)/.exec(trimmed);
22803
+ return link3 ? decodeURIComponent(link3[1]).trim() : trimmed;
22804
+ }
22805
+
22806
+ // src/commands/miro/readMiroItems.ts
22807
+ import { readFileSync as readFileSync40 } from "fs";
22808
+ function tryParse(text18) {
22809
+ try {
22810
+ return JSON.parse(text18);
22811
+ } catch {
22812
+ return void 0;
22813
+ }
22814
+ }
22815
+ function toPage(value) {
22816
+ const record = value ?? {};
22817
+ if (Array.isArray(record.data)) return { data: record.data };
22818
+ return record.id ? { data: [record] } : {};
22819
+ }
22820
+ function parseJsonLines(raw, file) {
22821
+ return raw.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => {
22822
+ const parsed = tryParse(line);
22823
+ if (parsed === void 0)
22824
+ throw new MiroExtractError(
22825
+ `${file} is not valid JSON or JSON lines. Save the raw board_list_items response pages without editing them.`
22826
+ );
22827
+ return toPage(parsed);
22828
+ });
22829
+ }
22830
+ function parsePages(raw, file) {
22831
+ const parsed = tryParse(raw);
22832
+ if (parsed === void 0) return parseJsonLines(raw, file);
22833
+ return Array.isArray(parsed) ? parsed.map(toPage) : [toPage(parsed)];
22834
+ }
22835
+ function readMiroItems(file) {
22836
+ const items2 = parsePages(readFileSync40(file, "utf8"), file).flatMap(
22837
+ (page) => page.data ?? []
22838
+ );
22839
+ if (items2.length === 0)
22840
+ throw new MiroExtractError(
22841
+ `No board items found in ${file}. Dump the frame with board_list_items, paging until has_more is false.`
22842
+ );
22843
+ return items2;
22844
+ }
22845
+
22846
+ // src/commands/miro/selectBoxes.ts
22847
+ var boxTypes = /* @__PURE__ */ new Set(["shape", "sticky_note"]);
22848
+ function findAnchor(items2, id) {
22849
+ const anchor = items2.find((item) => item.id === id);
22850
+ if (!anchor)
22851
+ throw new MiroExtractError(
22852
+ `No item with id ${id} in the supplied items. Re-dump the frame so the anchor is included, then try again.`
22853
+ );
22854
+ return anchor;
22855
+ }
22856
+ function isBox(item) {
22857
+ return boxTypes.has(item.type) && item.text.length > 0;
22858
+ }
22859
+ function centreInside(rect, item) {
22860
+ const x = (item.left + item.right) / 2;
22861
+ const y = (item.top + item.bottom) / 2;
22862
+ return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
22863
+ }
22864
+ function selectBoxes(items2, topLeftId, bottomRightId) {
22865
+ const topLeft = findAnchor(items2, topLeftId);
22866
+ const bottomRight = findAnchor(items2, bottomRightId);
22867
+ const rect = {
22868
+ left: topLeft.left,
22869
+ top: topLeft.top,
22870
+ right: bottomRight.right,
22871
+ bottom: bottomRight.bottom
22872
+ };
22873
+ return items2.filter((item) => isBox(item) && centreInside(rect, item)).sort((a, b) => a.left - b.left || a.top - b.top);
22874
+ }
22875
+
22876
+ // src/commands/miro/runExtract.ts
22877
+ function requireItems(file) {
22878
+ if (!file)
22879
+ throw new MiroExtractError(
22880
+ "--items <file> is required: a file of raw board_list_items response pages."
22881
+ );
22882
+ return file;
22883
+ }
22884
+ function requireAnchors(options2) {
22885
+ if (!options2.topLeft || !options2.bottomRight)
22886
+ throw new MiroExtractError(
22887
+ "Both --top-left <id|link> and --bottom-right <id|link> are required."
22888
+ );
22889
+ return [parseAnchorId(options2.topLeft), parseAnchorId(options2.bottomRight)];
22890
+ }
22891
+ function runExtract(options2) {
22892
+ const [topLeft, bottomRight] = requireAnchors(options2);
22893
+ const items2 = normaliseItems(readMiroItems(requireItems(options2.items)));
22894
+ const boxes = selectBoxes(items2, topLeft, bottomRight);
22895
+ process.stdout.write(stringify(boxes.map((box) => box.text)));
22896
+ }
22897
+
22898
+ // src/commands/miro/registerMiro.ts
22899
+ function registerMiro(program2) {
22900
+ const miroCommand = program2.command("miro").description("Miro board utilities");
22901
+ miroCommand.command("extract").description("Print the text of every box inside a rectangle on a board").option("--items <file>", "File of raw board_list_items response pages").option(
22902
+ "--top-left <id>",
22903
+ "Widget id or ?moveToWidget=<id> link of the top-left box"
22904
+ ).option(
22905
+ "--bottom-right <id>",
22906
+ "Widget id or ?moveToWidget=<id> link of the bottom-right box"
22907
+ ).action(runExtract);
22908
+ }
22909
+
22280
22910
  // src/commands/netcap/netcap.ts
22281
22911
  import { mkdir as mkdir4 } from "fs/promises";
22282
22912
  import { createServer as createServer2 } from "http";
22283
22913
  import { dirname as dirname28 } from "path";
22284
- import chalk169 from "chalk";
22914
+ import chalk170 from "chalk";
22285
22915
 
22286
22916
  // src/commands/netcap/corsHeaders.ts
22287
22917
  var corsHeaders = {
@@ -22360,7 +22990,7 @@ function createNetcapHandler(options2) {
22360
22990
  import { cp, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
22361
22991
  import { networkInterfaces } from "os";
22362
22992
  import { join as join58 } from "path";
22363
- import chalk168 from "chalk";
22993
+ import chalk169 from "chalk";
22364
22994
 
22365
22995
  // src/commands/netcap/netcapExtensionDir.ts
22366
22996
  import { dirname as dirname27, join as join57 } from "path";
@@ -22404,7 +23034,7 @@ async function prepareExtensionForLoad(port, filter = "") {
22404
23034
  const host = lanIPv4();
22405
23035
  if (!host) {
22406
23036
  console.log(
22407
- chalk168.yellow("could not determine the WSL IP for the extension")
23037
+ chalk169.yellow("could not determine the WSL IP for the extension")
22408
23038
  );
22409
23039
  await configureBackground(source, "127.0.0.1", port, filter);
22410
23040
  return source;
@@ -22415,7 +23045,7 @@ async function prepareExtensionForLoad(port, filter = "") {
22415
23045
  return WSL_WINDOWS_PATH;
22416
23046
  } catch {
22417
23047
  console.log(
22418
- chalk168.yellow(`could not copy extension to ${WSL_WINDOWS_PATH}`)
23048
+ chalk169.yellow(`could not copy extension to ${WSL_WINDOWS_PATH}`)
22419
23049
  );
22420
23050
  return source;
22421
23051
  }
@@ -22448,30 +23078,30 @@ async function netcap(options2) {
22448
23078
  let count8 = 0;
22449
23079
  const handler = createNetcapHandler({
22450
23080
  outPath,
22451
- onPing: () => console.log(chalk169.dim("ping from extension")),
23081
+ onPing: () => console.log(chalk170.dim("ping from extension")),
22452
23082
  onCapture: (entry) => {
22453
23083
  count8 += 1;
22454
23084
  console.log(
22455
- chalk169.green(`captured #${count8}`),
22456
- chalk169.dim(`${entry.method ?? "?"} ${entry.url ?? "?"}`)
23085
+ chalk170.green(`captured #${count8}`),
23086
+ chalk170.dim(`${entry.method ?? "?"} ${entry.url ?? "?"}`)
22457
23087
  );
22458
23088
  }
22459
23089
  });
22460
23090
  const server = createServer2(handler);
22461
23091
  server.listen(port, () => {
22462
23092
  console.log(
22463
- chalk169.bold(`netcap receiver listening on http://127.0.0.1:${port}`)
23093
+ chalk170.bold(`netcap receiver listening on http://127.0.0.1:${port}`)
22464
23094
  );
22465
- console.log(chalk169.dim(`appending captures to ${outPath}`));
23095
+ console.log(chalk170.dim(`appending captures to ${outPath}`));
22466
23096
  if (filter)
22467
- console.log(chalk169.dim(`forwarding only URLs matching "${filter}"`));
22468
- console.log(chalk169.dim(`load the unpacked extension from ${extensionPath}`));
22469
- console.log(chalk169.dim("press Ctrl-C to stop"));
23097
+ console.log(chalk170.dim(`forwarding only URLs matching "${filter}"`));
23098
+ console.log(chalk170.dim(`load the unpacked extension from ${extensionPath}`));
23099
+ console.log(chalk170.dim("press Ctrl-C to stop"));
22470
23100
  });
22471
23101
  process.on("SIGINT", () => {
22472
23102
  server.close();
22473
23103
  console.log(
22474
- chalk169.bold(
23104
+ chalk170.bold(
22475
23105
  `
22476
23106
  netcap stopped \u2014 captured ${count8} ${count8 === 1 ? "entry" : "entries"} to ${outPath}`
22477
23107
  )
@@ -22483,10 +23113,10 @@ netcap stopped \u2014 captured ${count8} ${count8 === 1 ? "entry" : "entries"} t
22483
23113
  // src/commands/netcap/netcapExtract.ts
22484
23114
  import { writeFileSync as writeFileSync33 } from "fs";
22485
23115
  import { join as join61 } from "path";
22486
- import chalk170 from "chalk";
23116
+ import chalk171 from "chalk";
22487
23117
 
22488
23118
  // src/commands/netcap/extractPostsFromCapture.ts
22489
- import { readFileSync as readFileSync39 } from "fs";
23119
+ import { readFileSync as readFileSync41 } from "fs";
22490
23120
 
22491
23121
  // src/commands/netcap/parseRscRows.ts
22492
23122
  var isRscRef = (v) => typeof v === "string" && /^\$[0-9a-fL@]/.test(v);
@@ -22882,7 +23512,7 @@ function extractVoyagerPosts(body) {
22882
23512
 
22883
23513
  // src/commands/netcap/extractPostsFromCapture.ts
22884
23514
  function captureEntries(captureFile) {
22885
- const lines2 = readFileSync39(captureFile, "utf8").split("\n").filter(Boolean);
23515
+ const lines2 = readFileSync41(captureFile, "utf8").split("\n").filter(Boolean);
22886
23516
  const entries = [];
22887
23517
  for (const line of lines2) {
22888
23518
  let entry;
@@ -22931,8 +23561,8 @@ function netcapExtract(file) {
22931
23561
  writeFileSync33(outFile, `${JSON.stringify(posts, null, 2)}
22932
23562
  `);
22933
23563
  console.log(
22934
- chalk170.green(`extracted ${posts.length} posts`),
22935
- chalk170.dim(`-> ${outFile}`)
23564
+ chalk171.green(`extracted ${posts.length} posts`),
23565
+ chalk171.dim(`-> ${outFile}`)
22936
23566
  );
22937
23567
  }
22938
23568
 
@@ -22953,7 +23583,7 @@ function registerNetcap(program2) {
22953
23583
  }
22954
23584
 
22955
23585
  // src/commands/news/add/index.ts
22956
- import chalk171 from "chalk";
23586
+ import chalk172 from "chalk";
22957
23587
  import enquirer8 from "enquirer";
22958
23588
  async function add2(url) {
22959
23589
  if (!url) {
@@ -22975,10 +23605,10 @@ async function add2(url) {
22975
23605
  const { orm } = await getReady();
22976
23606
  const added = await addFeed(orm, url);
22977
23607
  if (!added) {
22978
- console.log(chalk171.yellow("Feed already exists"));
23608
+ console.log(chalk172.yellow("Feed already exists"));
22979
23609
  return;
22980
23610
  }
22981
- console.log(chalk171.green(`Added feed: ${url}`));
23611
+ console.log(chalk172.green(`Added feed: ${url}`));
22982
23612
  }
22983
23613
 
22984
23614
  // src/commands/registerNews.ts
@@ -23025,7 +23655,7 @@ function registerPiHook(program2) {
23025
23655
  }
23026
23656
 
23027
23657
  // src/commands/prompts/printPromptsTable.ts
23028
- import chalk172 from "chalk";
23658
+ import chalk173 from "chalk";
23029
23659
  function truncate(str, max) {
23030
23660
  if (str.length <= max) return str;
23031
23661
  return `${str.slice(0, max - 1)}\u2026`;
@@ -23043,14 +23673,14 @@ function printPromptsTable(rows) {
23043
23673
  "Command".padEnd(commandWidth),
23044
23674
  "Repos"
23045
23675
  ].join(" ");
23046
- console.log(chalk172.dim(header));
23047
- console.log(chalk172.dim("-".repeat(header.length)));
23676
+ console.log(chalk173.dim(header));
23677
+ console.log(chalk173.dim("-".repeat(header.length)));
23048
23678
  for (const row of rows) {
23049
23679
  const count8 = String(row.count).padStart(countWidth);
23050
23680
  const tool = row.tool.padEnd(toolWidth);
23051
23681
  const command = truncate(row.command, 60).padEnd(commandWidth);
23052
23682
  console.log(
23053
- `${chalk172.yellow(count8)} ${tool} ${command} ${chalk172.dim(row.repos)}`
23683
+ `${chalk173.yellow(count8)} ${tool} ${command} ${chalk173.dim(row.repos)}`
23054
23684
  );
23055
23685
  }
23056
23686
  }
@@ -23456,7 +24086,7 @@ import { tmpdir as tmpdir6 } from "os";
23456
24086
  import { join as join63 } from "path";
23457
24087
 
23458
24088
  // src/commands/prs/loadCommentsCache.ts
23459
- import { existsSync as existsSync53, readFileSync as readFileSync40, unlinkSync as unlinkSync13 } from "fs";
24089
+ import { existsSync as existsSync54, readFileSync as readFileSync42, unlinkSync as unlinkSync13 } from "fs";
23460
24090
  import { parse as parse2 } from "yaml";
23461
24091
 
23462
24092
  // src/commands/prs/commentsCachePath.ts
@@ -23476,24 +24106,24 @@ function commentsCachePath(org, repo, prNumber) {
23476
24106
  // src/commands/prs/loadCommentsCache.ts
23477
24107
  function loadCommentsCache(org, repo, prNumber) {
23478
24108
  const cachePath = commentsCachePath(org, repo, prNumber);
23479
- if (!existsSync53(cachePath)) {
24109
+ if (!existsSync54(cachePath)) {
23480
24110
  return null;
23481
24111
  }
23482
- const content = readFileSync40(cachePath, "utf8");
24112
+ const content = readFileSync42(cachePath, "utf8");
23483
24113
  return parse2(content);
23484
24114
  }
23485
24115
  function deleteCommentsCache(org, repo, prNumber) {
23486
24116
  const cachePath = commentsCachePath(org, repo, prNumber);
23487
- if (existsSync53(cachePath)) {
24117
+ if (existsSync54(cachePath)) {
23488
24118
  unlinkSync13(cachePath);
23489
24119
  console.log("No more unresolved line comments. Cache dropped.");
23490
24120
  }
23491
24121
  }
23492
24122
 
23493
24123
  // src/commands/prs/replyToComment.ts
23494
- import { spawnSync as spawnSync5 } from "child_process";
24124
+ import { spawnSync as spawnSync6 } from "child_process";
23495
24125
  function replyToComment(org, repo, prNumber, commentId, message3) {
23496
- const result = spawnSync5(
24126
+ const result = spawnSync6(
23497
24127
  "gh",
23498
24128
  [
23499
24129
  "api",
@@ -23671,7 +24301,7 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
23671
24301
  // src/commands/prs/listComments/updateCommentsCache.ts
23672
24302
  import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync36 } from "fs";
23673
24303
  import { dirname as dirname29 } from "path";
23674
- import { stringify } from "yaml";
24304
+ import { stringify as stringify2 } from "yaml";
23675
24305
 
23676
24306
  // src/commands/prs/removeStaleCommentsCaches.ts
23677
24307
  import { readdirSync as readdirSync12, unlinkSync as unlinkSync16 } from "fs";
@@ -23699,7 +24329,7 @@ function writeCommentsCache(org, repo, prNumber, comments3) {
23699
24329
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
23700
24330
  comments: comments3
23701
24331
  };
23702
- writeFileSync36(cachePath, stringify(cacheData));
24332
+ writeFileSync36(cachePath, stringify2(cacheData));
23703
24333
  }
23704
24334
  function updateCommentsCache(org, repo, prNumber, comments3) {
23705
24335
  removeStaleCommentsCaches();
@@ -23717,13 +24347,13 @@ function agentFooter(unresolvedCount) {
23717
24347
  }
23718
24348
 
23719
24349
  // src/commands/prs/listComments/commentStyle.ts
23720
- import chalk173 from "chalk";
24350
+ import chalk174 from "chalk";
23721
24351
  var plain = (text18) => text18;
23722
24352
  function colouredState(state) {
23723
24353
  const label2 = `[${state}]`;
23724
- if (state === "APPROVED") return chalk173.green(label2);
23725
- if (state === "CHANGES_REQUESTED") return chalk173.red(label2);
23726
- return chalk173.yellow(label2);
24354
+ if (state === "APPROVED") return chalk174.green(label2);
24355
+ if (state === "CHANGES_REQUESTED") return chalk174.red(label2);
24356
+ return chalk174.yellow(label2);
23727
24357
  }
23728
24358
  function commentStyle() {
23729
24359
  if (isClaudeCode()) {
@@ -23737,9 +24367,9 @@ function commentStyle() {
23737
24367
  };
23738
24368
  }
23739
24369
  return {
23740
- cyan: chalk173.cyan,
23741
- bold: chalk173.bold,
23742
- dim: chalk173.dim,
24370
+ cyan: chalk174.cyan,
24371
+ bold: chalk174.bold,
24372
+ dim: chalk174.dim,
23743
24373
  state: colouredState,
23744
24374
  diffHunk: true,
23745
24375
  agent: false
@@ -23909,13 +24539,13 @@ import { execSync as execSync48 } from "child_process";
23909
24539
  import enquirer9 from "enquirer";
23910
24540
 
23911
24541
  // src/commands/prs/prs/displayPaginated/printPr.ts
23912
- import chalk174 from "chalk";
24542
+ import chalk175 from "chalk";
23913
24543
  var STATUS_MAP = {
23914
- MERGED: (pr) => pr.mergedAt ? { label: chalk174.magenta("merged"), date: pr.mergedAt } : null,
23915
- CLOSED: (pr) => pr.closedAt ? { label: chalk174.red("closed"), date: pr.closedAt } : null
24544
+ MERGED: (pr) => pr.mergedAt ? { label: chalk175.magenta("merged"), date: pr.mergedAt } : null,
24545
+ CLOSED: (pr) => pr.closedAt ? { label: chalk175.red("closed"), date: pr.closedAt } : null
23916
24546
  };
23917
24547
  function defaultStatus(pr) {
23918
- return { label: chalk174.green("opened"), date: pr.createdAt };
24548
+ return { label: chalk175.green("opened"), date: pr.createdAt };
23919
24549
  }
23920
24550
  function getStatus2(pr) {
23921
24551
  return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
@@ -23924,11 +24554,11 @@ function formatDate(dateStr) {
23924
24554
  return new Date(dateStr).toISOString().split("T")[0];
23925
24555
  }
23926
24556
  function formatPrHeader(pr, status3) {
23927
- return `${chalk174.cyan(`#${pr.number}`)} ${pr.title} ${chalk174.dim(`(${pr.author.login},`)} ${status3.label} ${chalk174.dim(`${formatDate(status3.date)})`)}`;
24557
+ return `${chalk175.cyan(`#${pr.number}`)} ${pr.title} ${chalk175.dim(`(${pr.author.login},`)} ${status3.label} ${chalk175.dim(`${formatDate(status3.date)})`)}`;
23928
24558
  }
23929
24559
  function logPrDetails(pr) {
23930
24560
  console.log(
23931
- chalk174.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
24561
+ chalk175.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
23932
24562
  );
23933
24563
  console.log();
23934
24564
  }
@@ -24643,10 +25273,10 @@ function registerPrs(program2) {
24643
25273
  }
24644
25274
 
24645
25275
  // src/commands/ravendb/ravendbAuth.ts
24646
- import chalk180 from "chalk";
25276
+ import chalk181 from "chalk";
24647
25277
 
24648
25278
  // src/shared/createConnectionAuth.ts
24649
- import chalk175 from "chalk";
25279
+ import chalk176 from "chalk";
24650
25280
  function listConnections(connections, format) {
24651
25281
  if (connections.length === 0) {
24652
25282
  console.log("No connections configured.");
@@ -24659,7 +25289,7 @@ function listConnections(connections, format) {
24659
25289
  function removeConnection(connections, name, save) {
24660
25290
  const filtered = connections.filter((c) => c.name !== name);
24661
25291
  if (filtered.length === connections.length) {
24662
- console.error(chalk175.red(`Connection "${name}" not found.`));
25292
+ console.error(chalk176.red(`Connection "${name}" not found.`));
24663
25293
  process.exit(1);
24664
25294
  }
24665
25295
  save(filtered);
@@ -24705,15 +25335,15 @@ function saveConnections(connections) {
24705
25335
  }
24706
25336
 
24707
25337
  // src/commands/ravendb/promptConnection.ts
24708
- import chalk178 from "chalk";
25338
+ import chalk179 from "chalk";
24709
25339
 
24710
25340
  // src/commands/ravendb/selectOpSecret.ts
24711
- import chalk177 from "chalk";
25341
+ import chalk178 from "chalk";
24712
25342
  import Enquirer2 from "enquirer";
24713
25343
 
24714
25344
  // src/commands/ravendb/searchItems.ts
24715
25345
  import { execSync as execSync51 } from "child_process";
24716
- import chalk176 from "chalk";
25346
+ import chalk177 from "chalk";
24717
25347
  function opExec(args) {
24718
25348
  return execSync51(`op ${args}`, {
24719
25349
  encoding: "utf8",
@@ -24726,7 +25356,7 @@ function searchItems(search2) {
24726
25356
  items2 = JSON.parse(opExec("item list --format=json"));
24727
25357
  } catch {
24728
25358
  console.error(
24729
- chalk176.red(
25359
+ chalk177.red(
24730
25360
  "Failed to search 1Password. Ensure the CLI is installed and you are signed in."
24731
25361
  )
24732
25362
  );
@@ -24740,7 +25370,7 @@ function getItemFields(itemId2) {
24740
25370
  const item = JSON.parse(opExec(`item get "${itemId2}" --format=json`));
24741
25371
  return item.fields.filter((f) => f.reference && f.label);
24742
25372
  } catch {
24743
- console.error(chalk176.red("Failed to get item details from 1Password."));
25373
+ console.error(chalk177.red("Failed to get item details from 1Password."));
24744
25374
  process.exit(1);
24745
25375
  }
24746
25376
  }
@@ -24759,7 +25389,7 @@ async function selectOpSecret(searchTerm) {
24759
25389
  }).run();
24760
25390
  const items2 = searchItems(search2);
24761
25391
  if (items2.length === 0) {
24762
- console.error(chalk177.red(`No items found matching "${search2}".`));
25392
+ console.error(chalk178.red(`No items found matching "${search2}".`));
24763
25393
  process.exit(1);
24764
25394
  }
24765
25395
  const itemId2 = await selectOne(
@@ -24768,7 +25398,7 @@ async function selectOpSecret(searchTerm) {
24768
25398
  );
24769
25399
  const fields = getItemFields(itemId2);
24770
25400
  if (fields.length === 0) {
24771
- console.error(chalk177.red("No fields with references found on this item."));
25401
+ console.error(chalk178.red("No fields with references found on this item."));
24772
25402
  process.exit(1);
24773
25403
  }
24774
25404
  const ref = await selectOne(
@@ -24782,7 +25412,7 @@ async function selectOpSecret(searchTerm) {
24782
25412
  async function promptConnection(existingNames) {
24783
25413
  const name = await promptInput("name", "Connection name:");
24784
25414
  if (existingNames.includes(name)) {
24785
- console.error(chalk178.red(`Connection "${name}" already exists.`));
25415
+ console.error(chalk179.red(`Connection "${name}" already exists.`));
24786
25416
  process.exit(1);
24787
25417
  }
24788
25418
  const url = await promptInput(
@@ -24791,22 +25421,22 @@ async function promptConnection(existingNames) {
24791
25421
  );
24792
25422
  const database = await promptInput("database", "Database name:");
24793
25423
  if (!name || !url || !database) {
24794
- console.error(chalk178.red("All fields are required."));
25424
+ console.error(chalk179.red("All fields are required."));
24795
25425
  process.exit(1);
24796
25426
  }
24797
25427
  const apiKeyRef = await selectOpSecret();
24798
- console.log(chalk178.dim(`Using: ${apiKeyRef}`));
25428
+ console.log(chalk179.dim(`Using: ${apiKeyRef}`));
24799
25429
  return { name, url, database, apiKeyRef };
24800
25430
  }
24801
25431
 
24802
25432
  // src/commands/ravendb/ravendbSetConnection.ts
24803
- import chalk179 from "chalk";
25433
+ import chalk180 from "chalk";
24804
25434
  function ravendbSetConnection(name) {
24805
25435
  const raw = loadGlobalConfigRaw();
24806
25436
  const ravendb = raw.ravendb ?? {};
24807
25437
  const connections = ravendb.connections ?? [];
24808
25438
  if (!connections.some((c) => c.name === name)) {
24809
- console.error(chalk179.red(`Connection "${name}" not found.`));
25439
+ console.error(chalk180.red(`Connection "${name}" not found.`));
24810
25440
  console.error(
24811
25441
  `Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
24812
25442
  );
@@ -24822,16 +25452,16 @@ function ravendbSetConnection(name) {
24822
25452
  var ravendbAuth = createConnectionAuth({
24823
25453
  load: loadConnections,
24824
25454
  save: saveConnections,
24825
- format: (c) => `${chalk180.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
25455
+ format: (c) => `${chalk181.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
24826
25456
  promptNew: promptConnection,
24827
25457
  onFirst: (c) => ravendbSetConnection(c.name)
24828
25458
  });
24829
25459
 
24830
25460
  // src/commands/ravendb/ravendbCollections.ts
24831
- import chalk184 from "chalk";
25461
+ import chalk185 from "chalk";
24832
25462
 
24833
25463
  // src/commands/ravendb/ravenFetch.ts
24834
- import chalk182 from "chalk";
25464
+ import chalk183 from "chalk";
24835
25465
 
24836
25466
  // src/commands/ravendb/getAccessToken.ts
24837
25467
  var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
@@ -24868,10 +25498,10 @@ ${errorText}`
24868
25498
 
24869
25499
  // src/commands/ravendb/resolveOpSecret.ts
24870
25500
  import { execSync as execSync52 } from "child_process";
24871
- import chalk181 from "chalk";
25501
+ import chalk182 from "chalk";
24872
25502
  function resolveOpSecret(reference) {
24873
25503
  if (!reference.startsWith("op://")) {
24874
- console.error(chalk181.red(`Invalid secret reference: must start with op://`));
25504
+ console.error(chalk182.red(`Invalid secret reference: must start with op://`));
24875
25505
  process.exit(1);
24876
25506
  }
24877
25507
  try {
@@ -24881,7 +25511,7 @@ function resolveOpSecret(reference) {
24881
25511
  }).trim();
24882
25512
  } catch {
24883
25513
  console.error(
24884
- chalk181.red(
25514
+ chalk182.red(
24885
25515
  "Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
24886
25516
  )
24887
25517
  );
@@ -24908,7 +25538,7 @@ async function ravenFetch(connection, path80) {
24908
25538
  if (!response.ok) {
24909
25539
  const body = await response.text();
24910
25540
  console.error(
24911
- chalk182.red(`RavenDB error: ${response.status} ${response.statusText}`)
25541
+ chalk183.red(`RavenDB error: ${response.status} ${response.statusText}`)
24912
25542
  );
24913
25543
  console.error(body.substring(0, 500));
24914
25544
  process.exit(1);
@@ -24917,7 +25547,7 @@ async function ravenFetch(connection, path80) {
24917
25547
  }
24918
25548
 
24919
25549
  // src/commands/ravendb/resolveConnection.ts
24920
- import chalk183 from "chalk";
25550
+ import chalk184 from "chalk";
24921
25551
  function loadRavendb() {
24922
25552
  const raw = loadGlobalConfigRaw();
24923
25553
  const ravendb = raw.ravendb;
@@ -24931,7 +25561,7 @@ function resolveConnection(name) {
24931
25561
  const connectionName = name ?? defaultConnection;
24932
25562
  if (!connectionName) {
24933
25563
  console.error(
24934
- chalk183.red(
25564
+ chalk184.red(
24935
25565
  "No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
24936
25566
  )
24937
25567
  );
@@ -24939,7 +25569,7 @@ function resolveConnection(name) {
24939
25569
  }
24940
25570
  const connection = connections.find((c) => c.name === connectionName);
24941
25571
  if (!connection) {
24942
- console.error(chalk183.red(`Connection "${connectionName}" not found.`));
25572
+ console.error(chalk184.red(`Connection "${connectionName}" not found.`));
24943
25573
  console.error(
24944
25574
  `Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
24945
25575
  );
@@ -24970,15 +25600,15 @@ async function ravendbCollections(connectionName) {
24970
25600
  return;
24971
25601
  }
24972
25602
  for (const c of collections) {
24973
- console.log(`${chalk184.bold(c.Name)} ${c.CountOfDocuments} docs`);
25603
+ console.log(`${chalk185.bold(c.Name)} ${c.CountOfDocuments} docs`);
24974
25604
  }
24975
25605
  }
24976
25606
 
24977
25607
  // src/commands/ravendb/ravendbQuery.ts
24978
- import chalk186 from "chalk";
25608
+ import chalk187 from "chalk";
24979
25609
 
24980
25610
  // src/commands/ravendb/fetchAllPages.ts
24981
- import chalk185 from "chalk";
25611
+ import chalk186 from "chalk";
24982
25612
 
24983
25613
  // src/commands/ravendb/buildQueryPath.ts
24984
25614
  function buildQueryPath(opts) {
@@ -25016,7 +25646,7 @@ async function fetchAllPages(connection, opts) {
25016
25646
  allResults.push(...results);
25017
25647
  start3 += results.length;
25018
25648
  process.stderr.write(
25019
- `\r${chalk185.dim(`Fetched ${allResults.length}/${totalResults}`)}`
25649
+ `\r${chalk186.dim(`Fetched ${allResults.length}/${totalResults}`)}`
25020
25650
  );
25021
25651
  if (start3 >= totalResults) break;
25022
25652
  if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
@@ -25031,7 +25661,7 @@ async function fetchAllPages(connection, opts) {
25031
25661
  async function ravendbQuery(connectionName, collection, options2) {
25032
25662
  const resolved = resolveArgs(connectionName, collection);
25033
25663
  if (!resolved.collection && !options2.query) {
25034
- console.error(chalk186.red("Provide a collection name or --query filter."));
25664
+ console.error(chalk187.red("Provide a collection name or --query filter."));
25035
25665
  process.exit(1);
25036
25666
  }
25037
25667
  const { collection: col } = resolved;
@@ -25070,7 +25700,7 @@ import { spawn as spawn6 } from "child_process";
25070
25700
  import * as path42 from "path";
25071
25701
 
25072
25702
  // src/commands/refactor/logViolations.ts
25073
- import chalk187 from "chalk";
25703
+ import chalk188 from "chalk";
25074
25704
  var DEFAULT_MAX_LINES2 = 100;
25075
25705
  function logViolations(violations, maxLines = DEFAULT_MAX_LINES2) {
25076
25706
  if (violations.length === 0) {
@@ -25079,43 +25709,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES2) {
25079
25709
  }
25080
25710
  return;
25081
25711
  }
25082
- console.error(chalk187.red(`
25712
+ console.error(chalk188.red(`
25083
25713
  Refactor check failed:
25084
25714
  `));
25085
- console.error(chalk187.red(` The following files exceed ${maxLines} lines:
25715
+ console.error(chalk188.red(` The following files exceed ${maxLines} lines:
25086
25716
  `));
25087
25717
  for (const violation of violations) {
25088
- console.error(chalk187.red(` ${violation.file} (${violation.lines} lines)`));
25718
+ console.error(chalk188.red(` ${violation.file} (${violation.lines} lines)`));
25089
25719
  }
25090
25720
  console.error(
25091
- chalk187.yellow(
25721
+ chalk188.yellow(
25092
25722
  `
25093
25723
  Each file needs to be sensibly refactored, or if there is no sensible
25094
25724
  way to refactor it, ignore it with:
25095
25725
  `
25096
25726
  )
25097
25727
  );
25098
- console.error(chalk187.gray(` assist refactor ignore <file>
25728
+ console.error(chalk188.gray(` assist refactor ignore <file>
25099
25729
  `));
25100
25730
  if (process.env.CLAUDECODE) {
25101
- console.error(chalk187.cyan(`
25731
+ console.error(chalk188.cyan(`
25102
25732
  ## Extracting Code to New Files
25103
25733
  `));
25104
25734
  console.error(
25105
- chalk187.cyan(
25735
+ chalk188.cyan(
25106
25736
  ` When extracting logic from one file to another, consider where the extracted code belongs:
25107
25737
  `
25108
25738
  )
25109
25739
  );
25110
25740
  console.error(
25111
- chalk187.cyan(
25741
+ chalk188.cyan(
25112
25742
  ` 1. Keep related logic together: If the extracted code is tightly coupled to the
25113
25743
  original file's domain, create a new folder containing both the original and extracted files.
25114
25744
  `
25115
25745
  )
25116
25746
  );
25117
25747
  console.error(
25118
- chalk187.cyan(
25748
+ chalk188.cyan(
25119
25749
  ` 2. Share common utilities: If the extracted code can be reused across multiple
25120
25750
  domains, move it to a common/shared folder.
25121
25751
  `
@@ -25271,7 +25901,7 @@ async function check(pattern2, options2) {
25271
25901
 
25272
25902
  // src/commands/refactor/extract/index.ts
25273
25903
  import path50 from "path";
25274
- import chalk190 from "chalk";
25904
+ import chalk191 from "chalk";
25275
25905
 
25276
25906
  // src/commands/refactor/extract/applyExtraction.ts
25277
25907
  import { SyntaxKind as SyntaxKind4 } from "ts-morph";
@@ -25870,23 +26500,23 @@ function buildPlan2(functionName, sourceFile, sourcePath, destPath, project) {
25870
26500
 
25871
26501
  // src/commands/refactor/extract/displayPlan.ts
25872
26502
  import path46 from "path";
25873
- import chalk188 from "chalk";
26503
+ import chalk189 from "chalk";
25874
26504
  function section2(title) {
25875
26505
  return `
25876
- ${chalk188.cyan(title)}`;
26506
+ ${chalk189.cyan(title)}`;
25877
26507
  }
25878
26508
  function displayImporters(plan2, cwd) {
25879
26509
  if (plan2.importersToUpdate.length === 0) return;
25880
26510
  console.log(section2("Update importers:"));
25881
26511
  for (const imp of plan2.importersToUpdate) {
25882
26512
  const rel = path46.relative(cwd, imp.file.getFilePath());
25883
- console.log(` ${chalk188.dim(rel)}: \u2192 import from "${imp.relPath}"`);
26513
+ console.log(` ${chalk189.dim(rel)}: \u2192 import from "${imp.relPath}"`);
25884
26514
  }
25885
26515
  }
25886
26516
  function displayPlan(functionName, relDest, plan2, cwd) {
25887
- console.log(chalk188.bold(`Extract: ${functionName} \u2192 ${relDest}
26517
+ console.log(chalk189.bold(`Extract: ${functionName} \u2192 ${relDest}
25888
26518
  `));
25889
- console.log(` ${chalk188.cyan("Functions to move:")}`);
26519
+ console.log(` ${chalk189.cyan("Functions to move:")}`);
25890
26520
  for (const name of plan2.extractedNames) {
25891
26521
  console.log(` ${name}`);
25892
26522
  }
@@ -25920,7 +26550,7 @@ function displayPlan(functionName, relDest, plan2, cwd) {
25920
26550
 
25921
26551
  // src/commands/refactor/extract/loadProjectFile.ts
25922
26552
  import path49 from "path";
25923
- import chalk189 from "chalk";
26553
+ import chalk190 from "chalk";
25924
26554
  import { Project as Project4 } from "ts-morph";
25925
26555
 
25926
26556
  // src/commands/refactor/extract/findTsConfig.ts
@@ -26012,7 +26642,7 @@ function loadProjectFile(file) {
26012
26642
  });
26013
26643
  const sourceFile = project.getSourceFile(sourcePath);
26014
26644
  if (!sourceFile) {
26015
- console.log(chalk189.red(`File not found in project: ${file}`));
26645
+ console.log(chalk190.red(`File not found in project: ${file}`));
26016
26646
  process.exit(1);
26017
26647
  }
26018
26648
  return { project, sourceFile };
@@ -26035,19 +26665,19 @@ async function extract(file, functionName, destination, options2 = {}) {
26035
26665
  displayPlan(functionName, relDest, plan2, cwd);
26036
26666
  if (options2.apply) {
26037
26667
  await applyExtraction(functionName, sourceFile, destPath, plan2, project);
26038
- console.log(chalk190.green("\nExtraction complete"));
26668
+ console.log(chalk191.green("\nExtraction complete"));
26039
26669
  } else {
26040
- console.log(chalk190.dim("\nDry run. Use --apply to execute."));
26670
+ console.log(chalk191.dim("\nDry run. Use --apply to execute."));
26041
26671
  }
26042
26672
  }
26043
26673
 
26044
26674
  // src/commands/refactor/ignore.ts
26045
26675
  import fs33 from "fs";
26046
- import chalk191 from "chalk";
26676
+ import chalk192 from "chalk";
26047
26677
  var REFACTOR_YML_PATH2 = "refactor.yml";
26048
26678
  function ignore2(file) {
26049
26679
  if (!fs33.existsSync(file)) {
26050
- console.error(chalk191.red(`Error: File does not exist: ${file}`));
26680
+ console.error(chalk192.red(`Error: File does not exist: ${file}`));
26051
26681
  process.exit(1);
26052
26682
  }
26053
26683
  const content = fs33.readFileSync(file, "utf8");
@@ -26063,7 +26693,7 @@ function ignore2(file) {
26063
26693
  fs33.writeFileSync(REFACTOR_YML_PATH2, entry);
26064
26694
  }
26065
26695
  console.log(
26066
- chalk191.green(
26696
+ chalk192.green(
26067
26697
  `Added ${file} to refactor ignore list (max ${maxLines} lines)`
26068
26698
  )
26069
26699
  );
@@ -26072,12 +26702,12 @@ function ignore2(file) {
26072
26702
  // src/commands/refactor/rename/index.ts
26073
26703
  import fs36 from "fs";
26074
26704
  import path55 from "path";
26075
- import chalk194 from "chalk";
26705
+ import chalk195 from "chalk";
26076
26706
 
26077
26707
  // src/commands/refactor/rename/applyRename.ts
26078
26708
  import fs35 from "fs";
26079
26709
  import path52 from "path";
26080
- import chalk192 from "chalk";
26710
+ import chalk193 from "chalk";
26081
26711
 
26082
26712
  // src/commands/refactor/restructure/computeRewrites/index.ts
26083
26713
  import path51 from "path";
@@ -26182,13 +26812,13 @@ function applyRename(rewrites, sourcePath, destPath, cwd) {
26182
26812
  const updatedContents = applyRewrites(rewrites);
26183
26813
  for (const [file, content] of updatedContents) {
26184
26814
  fs35.writeFileSync(file, content, "utf8");
26185
- console.log(chalk192.cyan(` Updated imports in ${path52.relative(cwd, file)}`));
26815
+ console.log(chalk193.cyan(` Updated imports in ${path52.relative(cwd, file)}`));
26186
26816
  }
26187
26817
  const destDir = path52.dirname(destPath);
26188
26818
  if (!fs35.existsSync(destDir)) fs35.mkdirSync(destDir, { recursive: true });
26189
26819
  fs35.renameSync(sourcePath, destPath);
26190
26820
  console.log(
26191
- chalk192.white(
26821
+ chalk193.white(
26192
26822
  ` Moved ${path52.relative(cwd, sourcePath)} \u2192 ${path52.relative(cwd, destPath)}`
26193
26823
  )
26194
26824
  );
@@ -26275,16 +26905,16 @@ function computeRenameRewrites(sourcePath, destPath) {
26275
26905
 
26276
26906
  // src/commands/refactor/rename/printRenamePreview.ts
26277
26907
  import path54 from "path";
26278
- import chalk193 from "chalk";
26908
+ import chalk194 from "chalk";
26279
26909
  function printRenamePreview(rewrites, cwd) {
26280
26910
  for (const rewrite of rewrites) {
26281
26911
  console.log(
26282
- chalk193.dim(
26912
+ chalk194.dim(
26283
26913
  ` ${path54.relative(cwd, rewrite.file)}: ${rewrite.oldSpecifier} \u2192 ${rewrite.newSpecifier}`
26284
26914
  )
26285
26915
  );
26286
26916
  }
26287
- console.log(chalk193.dim("Dry run. Use --apply to execute."));
26917
+ console.log(chalk194.dim("Dry run. Use --apply to execute."));
26288
26918
  }
26289
26919
 
26290
26920
  // src/commands/refactor/rename/index.ts
@@ -26295,20 +26925,20 @@ async function rename(source, destination, options2 = {}) {
26295
26925
  const relSource = path55.relative(cwd, sourcePath);
26296
26926
  const relDest = path55.relative(cwd, destPath);
26297
26927
  if (!fs36.existsSync(sourcePath)) {
26298
- console.log(chalk194.red(`File not found: ${source}`));
26928
+ console.log(chalk195.red(`File not found: ${source}`));
26299
26929
  process.exit(1);
26300
26930
  }
26301
26931
  if (destPath !== sourcePath && fs36.existsSync(destPath)) {
26302
- console.log(chalk194.red(`Destination already exists: ${destination}`));
26932
+ console.log(chalk195.red(`Destination already exists: ${destination}`));
26303
26933
  process.exit(1);
26304
26934
  }
26305
- console.log(chalk194.bold(`Rename: ${relSource} \u2192 ${relDest}`));
26306
- console.log(chalk194.dim("Loading project..."));
26307
- console.log(chalk194.dim("Scanning imports across the project..."));
26935
+ console.log(chalk195.bold(`Rename: ${relSource} \u2192 ${relDest}`));
26936
+ console.log(chalk195.dim("Loading project..."));
26937
+ console.log(chalk195.dim("Scanning imports across the project..."));
26308
26938
  const rewrites = computeRenameRewrites(sourcePath, destPath);
26309
26939
  const affectedFiles = new Set(rewrites.map((r) => r.file)).size;
26310
26940
  console.log(
26311
- chalk194.dim(
26941
+ chalk195.dim(
26312
26942
  `${rewrites.length} import path(s) to update across ${affectedFiles} file(s)`
26313
26943
  )
26314
26944
  );
@@ -26317,11 +26947,11 @@ async function rename(source, destination, options2 = {}) {
26317
26947
  return;
26318
26948
  }
26319
26949
  applyRename(rewrites, sourcePath, destPath, cwd);
26320
- console.log(chalk194.green("Done"));
26950
+ console.log(chalk195.green("Done"));
26321
26951
  }
26322
26952
 
26323
26953
  // src/commands/refactor/renameSymbol/index.ts
26324
- import chalk195 from "chalk";
26954
+ import chalk196 from "chalk";
26325
26955
 
26326
26956
  // src/commands/refactor/renameSymbol/findSymbol.ts
26327
26957
  import { SyntaxKind as SyntaxKind15 } from "ts-morph";
@@ -26367,33 +26997,33 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
26367
26997
  const { project, sourceFile } = loadProjectFile(file);
26368
26998
  const symbol = findSymbol(sourceFile, oldName);
26369
26999
  if (!symbol) {
26370
- console.log(chalk195.red(`Symbol "${oldName}" not found in ${file}`));
27000
+ console.log(chalk196.red(`Symbol "${oldName}" not found in ${file}`));
26371
27001
  process.exit(1);
26372
27002
  }
26373
27003
  const grouped = groupReferences(symbol, cwd);
26374
27004
  const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
26375
27005
  console.log(
26376
- chalk195.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
27006
+ chalk196.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
26377
27007
  `)
26378
27008
  );
26379
27009
  for (const [refFile, lines2] of grouped) {
26380
27010
  console.log(
26381
- ` ${chalk195.dim(refFile)}: lines ${chalk195.cyan(lines2.join(", "))}`
27011
+ ` ${chalk196.dim(refFile)}: lines ${chalk196.cyan(lines2.join(", "))}`
26382
27012
  );
26383
27013
  }
26384
27014
  if (options2.apply) {
26385
27015
  symbol.rename(newName);
26386
27016
  await project.save();
26387
- console.log(chalk195.green(`
27017
+ console.log(chalk196.green(`
26388
27018
  Renamed ${oldName} \u2192 ${newName}`));
26389
27019
  } else {
26390
- console.log(chalk195.dim("\nDry run. Use --apply to execute."));
27020
+ console.log(chalk196.dim("\nDry run. Use --apply to execute."));
26391
27021
  }
26392
27022
  }
26393
27023
 
26394
27024
  // src/commands/refactor/restructure/index.ts
26395
27025
  import path63 from "path";
26396
- import chalk198 from "chalk";
27026
+ import chalk199 from "chalk";
26397
27027
 
26398
27028
  // src/commands/refactor/restructure/clusterDirectories.ts
26399
27029
  import path57 from "path";
@@ -26472,50 +27102,50 @@ function clusterFiles(graph) {
26472
27102
 
26473
27103
  // src/commands/refactor/restructure/displayPlan.ts
26474
27104
  import path59 from "path";
26475
- import chalk196 from "chalk";
27105
+ import chalk197 from "chalk";
26476
27106
  function relPath(filePath) {
26477
27107
  return path59.relative(process.cwd(), filePath);
26478
27108
  }
26479
27109
  function displayMoves(plan2) {
26480
27110
  if (plan2.moves.length === 0) return;
26481
- console.log(chalk196.bold("\nFile moves:"));
27111
+ console.log(chalk197.bold("\nFile moves:"));
26482
27112
  for (const move2 of plan2.moves) {
26483
27113
  console.log(
26484
- ` ${chalk196.red(relPath(move2.from))} \u2192 ${chalk196.green(relPath(move2.to))}`
27114
+ ` ${chalk197.red(relPath(move2.from))} \u2192 ${chalk197.green(relPath(move2.to))}`
26485
27115
  );
26486
- console.log(chalk196.dim(` ${move2.reason}`));
27116
+ console.log(chalk197.dim(` ${move2.reason}`));
26487
27117
  }
26488
27118
  }
26489
27119
  function displayRewrites(rewrites) {
26490
27120
  if (rewrites.length === 0) return;
26491
27121
  const affectedFiles = new Set(rewrites.map((r) => r.file));
26492
- console.log(chalk196.bold(`
27122
+ console.log(chalk197.bold(`
26493
27123
  Import rewrites (${affectedFiles.size} files):`));
26494
27124
  for (const file of affectedFiles) {
26495
- console.log(` ${chalk196.cyan(relPath(file))}:`);
27125
+ console.log(` ${chalk197.cyan(relPath(file))}:`);
26496
27126
  for (const { oldSpecifier, newSpecifier } of rewrites.filter(
26497
27127
  (r) => r.file === file
26498
27128
  )) {
26499
27129
  console.log(
26500
- ` ${chalk196.red(`"${oldSpecifier}"`)} \u2192 ${chalk196.green(`"${newSpecifier}"`)}`
27130
+ ` ${chalk197.red(`"${oldSpecifier}"`)} \u2192 ${chalk197.green(`"${newSpecifier}"`)}`
26501
27131
  );
26502
27132
  }
26503
27133
  }
26504
27134
  }
26505
27135
  function displayPlan2(plan2) {
26506
27136
  if (plan2.warnings.length > 0) {
26507
- console.log(chalk196.yellow("\nWarnings:"));
26508
- for (const w of plan2.warnings) console.log(chalk196.yellow(` ${w}`));
27137
+ console.log(chalk197.yellow("\nWarnings:"));
27138
+ for (const w of plan2.warnings) console.log(chalk197.yellow(` ${w}`));
26509
27139
  }
26510
27140
  if (plan2.newDirectories.length > 0) {
26511
- console.log(chalk196.bold("\nNew directories:"));
27141
+ console.log(chalk197.bold("\nNew directories:"));
26512
27142
  for (const dir of plan2.newDirectories)
26513
- console.log(chalk196.green(` ${dir}/`));
27143
+ console.log(chalk197.green(` ${dir}/`));
26514
27144
  }
26515
27145
  displayMoves(plan2);
26516
27146
  displayRewrites(plan2.rewrites);
26517
27147
  console.log(
26518
- chalk196.dim(
27148
+ chalk197.dim(
26519
27149
  `
26520
27150
  Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports rewritten`
26521
27151
  )
@@ -26525,18 +27155,18 @@ Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports r
26525
27155
  // src/commands/refactor/restructure/executePlan.ts
26526
27156
  import fs37 from "fs";
26527
27157
  import path60 from "path";
26528
- import chalk197 from "chalk";
27158
+ import chalk198 from "chalk";
26529
27159
  function executePlan(plan2) {
26530
27160
  const updatedContents = applyRewrites(plan2.rewrites);
26531
27161
  for (const [file, content] of updatedContents) {
26532
27162
  fs37.writeFileSync(file, content, "utf8");
26533
27163
  console.log(
26534
- chalk197.cyan(` Rewrote imports in ${path60.relative(process.cwd(), file)}`)
27164
+ chalk198.cyan(` Rewrote imports in ${path60.relative(process.cwd(), file)}`)
26535
27165
  );
26536
27166
  }
26537
27167
  for (const dir of plan2.newDirectories) {
26538
27168
  fs37.mkdirSync(dir, { recursive: true });
26539
- console.log(chalk197.green(` Created ${path60.relative(process.cwd(), dir)}/`));
27169
+ console.log(chalk198.green(` Created ${path60.relative(process.cwd(), dir)}/`));
26540
27170
  }
26541
27171
  for (const move2 of plan2.moves) {
26542
27172
  const targetDir = path60.dirname(move2.to);
@@ -26545,7 +27175,7 @@ function executePlan(plan2) {
26545
27175
  }
26546
27176
  fs37.renameSync(move2.from, move2.to);
26547
27177
  console.log(
26548
- chalk197.white(
27178
+ chalk198.white(
26549
27179
  ` Moved ${path60.relative(process.cwd(), move2.from)} \u2192 ${path60.relative(process.cwd(), move2.to)}`
26550
27180
  )
26551
27181
  );
@@ -26560,7 +27190,7 @@ function removeEmptyDirectories(dirs) {
26560
27190
  if (entries.length === 0) {
26561
27191
  fs37.rmdirSync(dir);
26562
27192
  console.log(
26563
- chalk197.dim(
27193
+ chalk198.dim(
26564
27194
  ` Removed empty directory ${path60.relative(process.cwd(), dir)}`
26565
27195
  )
26566
27196
  );
@@ -26693,22 +27323,22 @@ async function restructure(pattern2, options2 = {}) {
26693
27323
  const targetPattern = pattern2 ?? "src";
26694
27324
  const files = findSourceFiles2(targetPattern);
26695
27325
  if (files.length === 0) {
26696
- console.log(chalk198.yellow("No files found matching pattern"));
27326
+ console.log(chalk199.yellow("No files found matching pattern"));
26697
27327
  return;
26698
27328
  }
26699
27329
  const tsConfigPath = findTsConfig(path63.resolve(files[0]));
26700
27330
  const plan2 = buildPlan3(files, tsConfigPath);
26701
27331
  if (plan2.moves.length === 0) {
26702
- console.log(chalk198.green("No restructuring needed"));
27332
+ console.log(chalk199.green("No restructuring needed"));
26703
27333
  return;
26704
27334
  }
26705
27335
  displayPlan2(plan2);
26706
27336
  if (options2.apply) {
26707
- console.log(chalk198.bold("\nApplying changes..."));
27337
+ console.log(chalk199.bold("\nApplying changes..."));
26708
27338
  executePlan(plan2);
26709
- console.log(chalk198.green("\nRestructuring complete"));
27339
+ console.log(chalk199.green("\nRestructuring complete"));
26710
27340
  } else {
26711
- console.log(chalk198.dim("\nDry run. Use --apply to execute."));
27341
+ console.log(chalk199.dim("\nDry run. Use --apply to execute."));
26712
27342
  }
26713
27343
  }
26714
27344
 
@@ -27031,7 +27661,7 @@ function gatherContext() {
27031
27661
  }
27032
27662
 
27033
27663
  // src/commands/review/postReviewToPr.ts
27034
- import { readFileSync as readFileSync41 } from "fs";
27664
+ import { readFileSync as readFileSync43 } from "fs";
27035
27665
 
27036
27666
  // src/commands/review/carriedUnanchoredFindings.ts
27037
27667
  function carriedUnanchoredFindings(unanchored) {
@@ -27366,18 +27996,18 @@ function partitionFindingsByDiff(findings, index3) {
27366
27996
  }
27367
27997
 
27368
27998
  // src/commands/review/warnOutOfDiff.ts
27369
- import chalk199 from "chalk";
27999
+ import chalk200 from "chalk";
27370
28000
  function warnOutOfDiff(outOfDiff) {
27371
28001
  if (outOfDiff.length === 0) return;
27372
28002
  console.warn(
27373
- chalk199.yellow(
28003
+ chalk200.yellow(
27374
28004
  `Moved ${outOfDiff.length} finding(s) whose lines fall outside the PR diff into the review body (GitHub cannot anchor a comment on these):`
27375
28005
  )
27376
28006
  );
27377
28007
  for (const finding of outOfDiff) {
27378
28008
  const range = finding.startLine !== void 0 ? `${finding.startLine}-${finding.line}` : `${finding.line}`;
27379
28009
  console.warn(
27380
- ` ${chalk199.yellow("\xB7")} ${finding.title} ${chalk199.dim(
28010
+ ` ${chalk200.yellow("\xB7")} ${finding.title} ${chalk200.dim(
27381
28011
  `(${finding.file}:${range})`
27382
28012
  )}`
27383
28013
  );
@@ -27401,18 +28031,18 @@ function selectInDiffFindings(lineBound, prDiff) {
27401
28031
  }
27402
28032
 
27403
28033
  // src/commands/review/warnUnlocated.ts
27404
- import chalk200 from "chalk";
28034
+ import chalk201 from "chalk";
27405
28035
  function warnUnlocated(unlocated) {
27406
28036
  if (unlocated.length === 0) return;
27407
28037
  console.warn(
27408
- chalk200.yellow(
28038
+ chalk201.yellow(
27409
28039
  `Moved ${unlocated.length} finding(s) without a parseable file:line into the review body:`
27410
28040
  )
27411
28041
  );
27412
28042
  for (const finding of unlocated) {
27413
- const where = finding.location || chalk200.dim("missing");
28043
+ const where = finding.location || chalk201.dim("missing");
27414
28044
  console.warn(
27415
- ` ${chalk200.yellow("\xB7")} ${finding.title} ${chalk200.dim(`(${where})`)}`
28045
+ ` ${chalk201.yellow("\xB7")} ${finding.title} ${chalk201.dim(`(${where})`)}`
27416
28046
  );
27417
28047
  }
27418
28048
  }
@@ -27479,7 +28109,7 @@ async function confirmPost(prNumber, work, options2) {
27479
28109
  return promptConfirm(`Post ${work} to PR #${prNumber}?`, false);
27480
28110
  }
27481
28111
  async function postFindingsToPr(prInfo, synthesisPath, options2) {
27482
- const markdown = readFileSync41(synthesisPath, "utf8");
28112
+ const markdown = readFileSync43(synthesisPath, "utf8");
27483
28113
  const { inDiff, unanchored } = selectPostableFindings(markdown, prInfo);
27484
28114
  const carried = carriedUnanchoredFindings(unanchored);
27485
28115
  if (inDiff.length === 0 && carried.length === 0) return NOTHING_POSTED;
@@ -27615,10 +28245,10 @@ async function handlePostSynthesis(synthesisPath, prInfo, options2) {
27615
28245
  }
27616
28246
 
27617
28247
  // src/commands/review/prepareReviewDir.ts
27618
- import { existsSync as existsSync54, mkdirSync as mkdirSync20, unlinkSync as unlinkSync17, writeFileSync as writeFileSync37 } from "fs";
28248
+ import { existsSync as existsSync55, mkdirSync as mkdirSync20, unlinkSync as unlinkSync17, writeFileSync as writeFileSync37 } from "fs";
27619
28249
  function clearReviewFiles(paths) {
27620
28250
  for (const path80 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
27621
- if (existsSync54(path80)) unlinkSync17(path80);
28251
+ if (existsSync55(path80)) unlinkSync17(path80);
27622
28252
  }
27623
28253
  }
27624
28254
  function prepareReviewDir(paths, requestBody, force) {
@@ -27744,9 +28374,9 @@ var MultiSpinner = class {
27744
28374
  };
27745
28375
 
27746
28376
  // src/commands/review/ensureCodexAvailable.ts
27747
- import { spawnSync as spawnSync6 } from "child_process";
28377
+ import { spawnSync as spawnSync7 } from "child_process";
27748
28378
  function runNpmInstall() {
27749
- const result = spawnSync6("npm", ["install", "-g", "@openai/codex"], {
28379
+ const result = spawnSync7("npm", ["install", "-g", "@openai/codex"], {
27750
28380
  stdio: "inherit",
27751
28381
  shell: true
27752
28382
  });
@@ -27845,7 +28475,7 @@ function printReviewerFailures(results) {
27845
28475
  }
27846
28476
 
27847
28477
  // src/commands/review/runAndSynthesise.ts
27848
- import { existsSync as existsSync56, unlinkSync as unlinkSync19 } from "fs";
28478
+ import { existsSync as existsSync57, unlinkSync as unlinkSync19 } from "fs";
27849
28479
 
27850
28480
  // src/commands/review/buildReviewerStdin.ts
27851
28481
  var REVIEW_PROMPT = `You are acting as a reviewer for a proposed code change made by another engineer. The full review request \u2014 branch, base, changed files, and unified diff \u2014 is in the request file whose absolute path is given below.
@@ -28274,7 +28904,7 @@ function resolveClaude(args) {
28274
28904
  }
28275
28905
 
28276
28906
  // src/commands/review/runCodexReviewer.ts
28277
- import { existsSync as existsSync55, unlinkSync as unlinkSync18 } from "fs";
28907
+ import { existsSync as existsSync56, unlinkSync as unlinkSync18 } from "fs";
28278
28908
 
28279
28909
  // src/commands/review/parseCodexEvent.ts
28280
28910
  function isItemStarted(value) {
@@ -28326,7 +28956,7 @@ async function runCodexReviewer(spec) {
28326
28956
  reportReviewerToolUse(spec.name, event, spinner);
28327
28957
  }
28328
28958
  });
28329
- if (result.exitCode !== 0 && existsSync55(spec.outputPath)) {
28959
+ if (result.exitCode !== 0 && existsSync56(spec.outputPath)) {
28330
28960
  unlinkSync18(spec.outputPath);
28331
28961
  }
28332
28962
  return finaliseReviewerRun({ ...spec, command }, spinner, result);
@@ -28368,7 +28998,7 @@ async function runReviewers(reviewDir, claudePath, codexPath, stdinPrompt, optio
28368
28998
  }
28369
28999
 
28370
29000
  // src/commands/review/synthesise.ts
28371
- import { readFileSync as readFileSync42 } from "fs";
29001
+ import { readFileSync as readFileSync44 } from "fs";
28372
29002
 
28373
29003
  // src/commands/review/buildSynthesisStdin.ts
28374
29004
  var SYNTHESIS_PROMPT = `You are consolidating two independent code reviews of the same change. The original review request is in request.md. The two reviews are in claude.md and codex.md in the current working directory.
@@ -28433,7 +29063,7 @@ Files:
28433
29063
 
28434
29064
  // src/commands/review/synthesise.ts
28435
29065
  function printSummary2(synthesisPath) {
28436
- const markdown = readFileSync42(synthesisPath, "utf8");
29066
+ const markdown = readFileSync44(synthesisPath, "utf8");
28437
29067
  console.log("");
28438
29068
  console.log(buildReviewSummary(markdown));
28439
29069
  console.log("");
@@ -28481,7 +29111,7 @@ async function runAndSynthesise(args) {
28481
29111
  console.error("Both reviewers failed; skipping synthesis.");
28482
29112
  return { ok: false, failures };
28483
29113
  }
28484
- if (anyFresh && existsSync56(paths.synthesisPath)) {
29114
+ if (anyFresh && existsSync57(paths.synthesisPath)) {
28485
29115
  unlinkSync19(paths.synthesisPath);
28486
29116
  }
28487
29117
  const synthesisResult = await synthesise(paths, { multi });
@@ -28667,7 +29297,7 @@ function registerReview(program2) {
28667
29297
  }
28668
29298
 
28669
29299
  // src/commands/seq/seqAuth.ts
28670
- import chalk202 from "chalk";
29300
+ import chalk203 from "chalk";
28671
29301
 
28672
29302
  // src/commands/seq/loadConnections.ts
28673
29303
  function loadConnections2() {
@@ -28696,10 +29326,10 @@ function setDefaultConnection(name) {
28696
29326
  }
28697
29327
 
28698
29328
  // src/shared/assertUniqueName.ts
28699
- import chalk201 from "chalk";
29329
+ import chalk202 from "chalk";
28700
29330
  function assertUniqueName(existingNames, name) {
28701
29331
  if (existingNames.includes(name)) {
28702
- console.error(chalk201.red(`Connection "${name}" already exists.`));
29332
+ console.error(chalk202.red(`Connection "${name}" already exists.`));
28703
29333
  process.exit(1);
28704
29334
  }
28705
29335
  }
@@ -28717,16 +29347,16 @@ async function promptConnection2(existingNames) {
28717
29347
  var seqAuth = createConnectionAuth({
28718
29348
  load: loadConnections2,
28719
29349
  save: saveConnections2,
28720
- format: (c) => `${chalk202.bold(c.name)} ${c.url}`,
29350
+ format: (c) => `${chalk203.bold(c.name)} ${c.url}`,
28721
29351
  promptNew: promptConnection2,
28722
29352
  onFirst: (c) => setDefaultConnection(c.name)
28723
29353
  });
28724
29354
 
28725
29355
  // src/commands/seq/seqQuery.ts
28726
- import chalk206 from "chalk";
29356
+ import chalk207 from "chalk";
28727
29357
 
28728
29358
  // src/commands/seq/fetchSeq.ts
28729
- import chalk203 from "chalk";
29359
+ import chalk204 from "chalk";
28730
29360
  async function fetchSeq(conn, path80, params) {
28731
29361
  const url = `${conn.url}${path80}?${params}`;
28732
29362
  const response = await fetch(url, {
@@ -28737,7 +29367,7 @@ async function fetchSeq(conn, path80, params) {
28737
29367
  });
28738
29368
  if (!response.ok) {
28739
29369
  const body = await response.text();
28740
- console.error(chalk203.red(`Seq returned ${response.status}: ${body}`));
29370
+ console.error(chalk204.red(`Seq returned ${response.status}: ${body}`));
28741
29371
  process.exit(1);
28742
29372
  }
28743
29373
  return response;
@@ -28796,23 +29426,23 @@ async function fetchSeqEvents(conn, params) {
28796
29426
  }
28797
29427
 
28798
29428
  // src/commands/seq/formatEvent.ts
28799
- import chalk204 from "chalk";
29429
+ import chalk205 from "chalk";
28800
29430
  function levelColor(level) {
28801
29431
  switch (level) {
28802
29432
  case "Fatal":
28803
- return chalk204.bgRed.white;
29433
+ return chalk205.bgRed.white;
28804
29434
  case "Error":
28805
- return chalk204.red;
29435
+ return chalk205.red;
28806
29436
  case "Warning":
28807
- return chalk204.yellow;
29437
+ return chalk205.yellow;
28808
29438
  case "Information":
28809
- return chalk204.cyan;
29439
+ return chalk205.cyan;
28810
29440
  case "Debug":
28811
- return chalk204.gray;
29441
+ return chalk205.gray;
28812
29442
  case "Verbose":
28813
- return chalk204.dim;
29443
+ return chalk205.dim;
28814
29444
  default:
28815
- return chalk204.white;
29445
+ return chalk205.white;
28816
29446
  }
28817
29447
  }
28818
29448
  function levelAbbrev(level) {
@@ -28853,12 +29483,12 @@ function formatTimestamp(iso) {
28853
29483
  function formatEvent(event) {
28854
29484
  const color = levelColor(event.Level);
28855
29485
  const abbrev = levelAbbrev(event.Level);
28856
- const ts8 = chalk204.dim(formatTimestamp(event.Timestamp));
29486
+ const ts8 = chalk205.dim(formatTimestamp(event.Timestamp));
28857
29487
  const msg = renderMessage(event);
28858
29488
  const lines2 = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
28859
29489
  if (event.Exception) {
28860
29490
  for (const line of event.Exception.split("\n")) {
28861
- lines2.push(chalk204.red(` ${line}`));
29491
+ lines2.push(chalk205.red(` ${line}`));
28862
29492
  }
28863
29493
  }
28864
29494
  return lines2.join("\n");
@@ -28891,11 +29521,11 @@ function rejectTimestampFilter(filter) {
28891
29521
  }
28892
29522
 
28893
29523
  // src/shared/resolveNamedConnection.ts
28894
- import chalk205 from "chalk";
29524
+ import chalk206 from "chalk";
28895
29525
  function resolveNamedConnection(connections, requested, defaultName, kind, authCommand) {
28896
29526
  if (connections.length === 0) {
28897
29527
  console.error(
28898
- chalk205.red(
29528
+ chalk206.red(
28899
29529
  `No ${kind} connections configured. Run '${authCommand}' first.`
28900
29530
  )
28901
29531
  );
@@ -28904,7 +29534,7 @@ function resolveNamedConnection(connections, requested, defaultName, kind, authC
28904
29534
  const target = requested ?? defaultName ?? connections[0].name;
28905
29535
  const connection = connections.find((c) => c.name === target);
28906
29536
  if (!connection) {
28907
- console.error(chalk205.red(`${kind} connection "${target}" not found.`));
29537
+ console.error(chalk206.red(`${kind} connection "${target}" not found.`));
28908
29538
  process.exit(1);
28909
29539
  }
28910
29540
  return connection;
@@ -28933,7 +29563,7 @@ async function seqQuery(filter, options2) {
28933
29563
  new URLSearchParams({ filter, count: String(count8) })
28934
29564
  );
28935
29565
  if (events.length === 0) {
28936
- console.log(chalk206.yellow("No events found."));
29566
+ console.log(chalk207.yellow("No events found."));
28937
29567
  return;
28938
29568
  }
28939
29569
  if (options2.json) {
@@ -28944,11 +29574,11 @@ async function seqQuery(filter, options2) {
28944
29574
  for (const event of chronological) {
28945
29575
  console.log(formatEvent(event));
28946
29576
  }
28947
- console.log(chalk206.dim(`
29577
+ console.log(chalk207.dim(`
28948
29578
  ${events.length} events`));
28949
29579
  if (events.length >= count8) {
28950
29580
  console.log(
28951
- chalk206.yellow(
29581
+ chalk207.yellow(
28952
29582
  `Results limited to ${count8}. Use --count to retrieve more.`
28953
29583
  )
28954
29584
  );
@@ -28956,10 +29586,10 @@ ${events.length} events`));
28956
29586
  }
28957
29587
 
28958
29588
  // src/shared/setNamedDefaultConnection.ts
28959
- import chalk207 from "chalk";
29589
+ import chalk208 from "chalk";
28960
29590
  function setNamedDefaultConnection(connections, name, setDefault, kind) {
28961
29591
  if (!connections.find((c) => c.name === name)) {
28962
- console.error(chalk207.red(`Connection "${name}" not found.`));
29592
+ console.error(chalk208.red(`Connection "${name}" not found.`));
28963
29593
  process.exit(1);
28964
29594
  }
28965
29595
  setDefault(name);
@@ -29008,7 +29638,7 @@ function registerSignal(program2) {
29008
29638
  }
29009
29639
 
29010
29640
  // src/commands/sql/sqlAuth.ts
29011
- import chalk209 from "chalk";
29641
+ import chalk210 from "chalk";
29012
29642
 
29013
29643
  // src/commands/sql/loadConnections.ts
29014
29644
  function loadConnections3() {
@@ -29037,7 +29667,7 @@ function setDefaultConnection2(name) {
29037
29667
  }
29038
29668
 
29039
29669
  // src/commands/sql/promptConnection.ts
29040
- import chalk208 from "chalk";
29670
+ import chalk209 from "chalk";
29041
29671
  async function promptConnection3(existingNames) {
29042
29672
  const name = await promptInput("name", "Connection name:", "default");
29043
29673
  assertUniqueName(existingNames, name);
@@ -29045,7 +29675,7 @@ async function promptConnection3(existingNames) {
29045
29675
  const portStr = await promptInput("port", "Port:", "1433");
29046
29676
  const port = Number.parseInt(portStr, 10);
29047
29677
  if (!Number.isFinite(port)) {
29048
- console.error(chalk208.red(`Invalid port "${portStr}".`));
29678
+ console.error(chalk209.red(`Invalid port "${portStr}".`));
29049
29679
  process.exit(1);
29050
29680
  }
29051
29681
  const user = await promptInput("user", "User:");
@@ -29058,13 +29688,13 @@ async function promptConnection3(existingNames) {
29058
29688
  var sqlAuth = createConnectionAuth({
29059
29689
  load: loadConnections3,
29060
29690
  save: saveConnections3,
29061
- format: (c) => `${chalk209.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
29691
+ format: (c) => `${chalk210.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
29062
29692
  promptNew: promptConnection3,
29063
29693
  onFirst: (c) => setDefaultConnection2(c.name)
29064
29694
  });
29065
29695
 
29066
29696
  // src/commands/sql/printTable.ts
29067
- import chalk210 from "chalk";
29697
+ import chalk211 from "chalk";
29068
29698
  function formatCell(value) {
29069
29699
  if (value === null || value === void 0) return "";
29070
29700
  if (value instanceof Date) return value.toISOString();
@@ -29073,7 +29703,7 @@ function formatCell(value) {
29073
29703
  }
29074
29704
  function printTable(rows) {
29075
29705
  if (rows.length === 0) {
29076
- console.log(chalk210.yellow("(no rows)"));
29706
+ console.log(chalk211.yellow("(no rows)"));
29077
29707
  return;
29078
29708
  }
29079
29709
  const columns = Object.keys(rows[0]);
@@ -29081,13 +29711,13 @@ function printTable(rows) {
29081
29711
  (col) => Math.max(col.length, ...rows.map((r) => formatCell(r[col]).length))
29082
29712
  );
29083
29713
  const header = columns.map((c, i) => c.padEnd(widths[i])).join(" ");
29084
- console.log(chalk210.dim(header));
29085
- console.log(chalk210.dim("-".repeat(header.length)));
29714
+ console.log(chalk211.dim(header));
29715
+ console.log(chalk211.dim("-".repeat(header.length)));
29086
29716
  for (const row of rows) {
29087
29717
  const line = columns.map((c, i) => formatCell(row[c]).padEnd(widths[i])).join(" ");
29088
29718
  console.log(line);
29089
29719
  }
29090
- console.log(chalk210.dim(`
29720
+ console.log(chalk211.dim(`
29091
29721
  ${rows.length} row${rows.length === 1 ? "" : "s"}`));
29092
29722
  }
29093
29723
 
@@ -29147,7 +29777,7 @@ async function sqlColumns(table, connectionName) {
29147
29777
  }
29148
29778
 
29149
29779
  // src/commands/sql/sqlMutate.ts
29150
- import chalk211 from "chalk";
29780
+ import chalk212 from "chalk";
29151
29781
 
29152
29782
  // src/commands/sql/isMutation.ts
29153
29783
  var MUTATION_KEYWORDS = [
@@ -29181,7 +29811,7 @@ function isMutation(sql25) {
29181
29811
  async function sqlMutate(query, connectionName) {
29182
29812
  if (!isMutation(query)) {
29183
29813
  console.error(
29184
- chalk211.red(
29814
+ chalk212.red(
29185
29815
  "assist sql mutate refuses non-mutating statements. Use `assist sql query` instead."
29186
29816
  )
29187
29817
  );
@@ -29191,18 +29821,18 @@ async function sqlMutate(query, connectionName) {
29191
29821
  const pool = await sqlConnect(conn);
29192
29822
  try {
29193
29823
  const result = await pool.request().query(query);
29194
- console.log(chalk211.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
29824
+ console.log(chalk212.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
29195
29825
  } finally {
29196
29826
  await pool.close();
29197
29827
  }
29198
29828
  }
29199
29829
 
29200
29830
  // src/commands/sql/sqlQuery.ts
29201
- import chalk212 from "chalk";
29831
+ import chalk213 from "chalk";
29202
29832
  async function sqlQuery(query, connectionName) {
29203
29833
  if (isMutation(query)) {
29204
29834
  console.error(
29205
- chalk212.red(
29835
+ chalk213.red(
29206
29836
  "assist sql query refuses mutating statements. Use `assist sql mutate` instead."
29207
29837
  )
29208
29838
  );
@@ -29217,7 +29847,7 @@ async function sqlQuery(query, connectionName) {
29217
29847
  printTable(rows);
29218
29848
  } else {
29219
29849
  console.log(
29220
- chalk212.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
29850
+ chalk213.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
29221
29851
  );
29222
29852
  }
29223
29853
  } finally {
@@ -29362,7 +29992,7 @@ function reportPrune(label2, result, force) {
29362
29992
  // src/commands/sync/syncClaudeMd.ts
29363
29993
  import * as fs41 from "fs";
29364
29994
  import * as path66 from "path";
29365
- import chalk213 from "chalk";
29995
+ import chalk214 from "chalk";
29366
29996
  async function syncClaudeMd(claudeDir, targetBase, options2) {
29367
29997
  const source = path66.join(claudeDir, "CLAUDE.md");
29368
29998
  const target = path66.join(targetBase, "CLAUDE.md");
@@ -29371,14 +30001,14 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
29371
30001
  const targetContent = fs41.readFileSync(target, "utf8");
29372
30002
  if (sourceContent !== targetContent) {
29373
30003
  console.log(
29374
- chalk213.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
30004
+ chalk214.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
29375
30005
  );
29376
30006
  console.log();
29377
30007
  printDiff(targetContent, sourceContent);
29378
30008
  if (!options2?.yes) {
29379
30009
  printAutoConfirmHint();
29380
30010
  const confirm = await promptConfirm(
29381
- chalk213.red("Overwrite existing CLAUDE.md?"),
30011
+ chalk214.red("Overwrite existing CLAUDE.md?"),
29382
30012
  false
29383
30013
  );
29384
30014
  if (!confirm) {
@@ -29611,7 +30241,7 @@ function syncPi(claudeDir, options2) {
29611
30241
  // src/commands/sync/syncSettings.ts
29612
30242
  import * as fs47 from "fs";
29613
30243
  import * as path73 from "path";
29614
- import chalk214 from "chalk";
30244
+ import chalk215 from "chalk";
29615
30245
  async function syncSettings(claudeDir, targetBase, options2) {
29616
30246
  const source = path73.join(claudeDir, "settings.json");
29617
30247
  const target = path73.join(targetBase, "settings.json");
@@ -29630,7 +30260,7 @@ async function syncSettings(claudeDir, targetBase, options2) {
29630
30260
  if (mergedContent !== normalizedTarget) {
29631
30261
  if (!options2?.yes) {
29632
30262
  console.log(
29633
- chalk214.yellow(
30263
+ chalk215.yellow(
29634
30264
  "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
29635
30265
  )
29636
30266
  );
@@ -29638,7 +30268,7 @@ async function syncSettings(claudeDir, targetBase, options2) {
29638
30268
  printDiff(targetContent, mergedContent);
29639
30269
  printAutoConfirmHint();
29640
30270
  const confirm = await promptConfirm(
29641
- chalk214.red("Overwrite existing settings.json?"),
30271
+ chalk215.red("Overwrite existing settings.json?"),
29642
30272
  false
29643
30273
  );
29644
30274
  if (!confirm) {
@@ -29780,11 +30410,11 @@ async function configure() {
29780
30410
  }
29781
30411
 
29782
30412
  // src/commands/transcript/list.ts
29783
- import { existsSync as existsSync61, readdirSync as readdirSync19, statSync as statSync10 } from "fs";
30413
+ import { existsSync as existsSync62, readdirSync as readdirSync19, statSync as statSync10 } from "fs";
29784
30414
  import { join as join77 } from "path";
29785
30415
  function list4() {
29786
30416
  const { vttDir } = getTranscriptConfig();
29787
- if (!existsSync61(vttDir)) return;
30417
+ if (!existsSync62(vttDir)) return;
29788
30418
  for (const entry of readdirSync19(vttDir)) {
29789
30419
  if (!entry.endsWith(".vtt")) continue;
29790
30420
  if (statSync10(join77(vttDir, entry)).isDirectory()) continue;
@@ -29794,9 +30424,9 @@ function list4() {
29794
30424
 
29795
30425
  // src/commands/transcript/move.ts
29796
30426
  import {
29797
- existsSync as existsSync62,
30427
+ existsSync as existsSync63,
29798
30428
  mkdirSync as mkdirSync26,
29799
- readFileSync as readFileSync47,
30429
+ readFileSync as readFileSync49,
29800
30430
  renameSync as renameSync2,
29801
30431
  writeFileSync as writeFileSync42
29802
30432
  } from "fs";
@@ -30008,7 +30638,7 @@ function formatChatLog(messages) {
30008
30638
  // src/commands/transcript/move.ts
30009
30639
  var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
30010
30640
  function convertVttToMarkdown(inputPath) {
30011
- const cues = parseVtt(readFileSync47(inputPath, "utf8"));
30641
+ const cues = parseVtt(readFileSync49(inputPath, "utf8"));
30012
30642
  const messages = cuesToChatMessages(deduplicateCues(cues));
30013
30643
  return formatChatLog(messages);
30014
30644
  }
@@ -30026,7 +30656,7 @@ function move(file, options2) {
30026
30656
  const { vttDir, transcriptsDir, summaryDir } = getTranscriptConfig();
30027
30657
  const filename = basename21(file);
30028
30658
  const sourcePath = join78(vttDir, filename);
30029
- if (!existsSync62(sourcePath)) {
30659
+ if (!existsSync63(sourcePath)) {
30030
30660
  console.error(`Error: VTT file not found: ${sourcePath}`);
30031
30661
  process.exit(1);
30032
30662
  }
@@ -30118,7 +30748,7 @@ function registerVerify(program2) {
30118
30748
  }
30119
30749
 
30120
30750
  // src/commands/voice/devices.ts
30121
- import { spawnSync as spawnSync7 } from "child_process";
30751
+ import { spawnSync as spawnSync8 } from "child_process";
30122
30752
  import { join as join80 } from "path";
30123
30753
 
30124
30754
  // src/commands/voice/shared.ts
@@ -30151,18 +30781,18 @@ function getLockFile() {
30151
30781
  // src/commands/voice/devices.ts
30152
30782
  function devices() {
30153
30783
  const script = join80(getPythonDir(), "list_devices.py");
30154
- spawnSync7(getVenvPython(), [script], { stdio: "inherit" });
30784
+ spawnSync8(getVenvPython(), [script], { stdio: "inherit" });
30155
30785
  }
30156
30786
 
30157
30787
  // src/commands/voice/logs.ts
30158
- import { existsSync as existsSync63, readFileSync as readFileSync48 } from "fs";
30788
+ import { existsSync as existsSync64, readFileSync as readFileSync50 } from "fs";
30159
30789
  function logs(options2) {
30160
- if (!existsSync63(voicePaths.log)) {
30790
+ if (!existsSync64(voicePaths.log)) {
30161
30791
  console.log("No voice log file found");
30162
30792
  return;
30163
30793
  }
30164
30794
  const count8 = Number.parseInt(options2.lines ?? "150", 10);
30165
- const content = readFileSync48(voicePaths.log, "utf8").trim();
30795
+ const content = readFileSync50(voicePaths.log, "utf8").trim();
30166
30796
  if (!content) {
30167
30797
  console.log("Voice log is empty");
30168
30798
  return;
@@ -30183,13 +30813,13 @@ function logs(options2) {
30183
30813
  }
30184
30814
 
30185
30815
  // src/commands/voice/setup.ts
30186
- import { spawnSync as spawnSync8 } from "child_process";
30816
+ import { spawnSync as spawnSync9 } from "child_process";
30187
30817
  import { mkdirSync as mkdirSync28 } from "fs";
30188
30818
  import { join as join82 } from "path";
30189
30819
 
30190
30820
  // src/commands/voice/checkLockFile.ts
30191
30821
  import { execSync as execSync58 } from "child_process";
30192
- import { existsSync as existsSync64, mkdirSync as mkdirSync27, readFileSync as readFileSync49, writeFileSync as writeFileSync43 } from "fs";
30822
+ import { existsSync as existsSync65, mkdirSync as mkdirSync27, readFileSync as readFileSync51, writeFileSync as writeFileSync43 } from "fs";
30193
30823
  import { join as join81 } from "path";
30194
30824
  function isProcessAlive2(pid) {
30195
30825
  try {
@@ -30201,9 +30831,9 @@ function isProcessAlive2(pid) {
30201
30831
  }
30202
30832
  function checkLockFile() {
30203
30833
  const lockFile = getLockFile();
30204
- if (!existsSync64(lockFile)) return;
30834
+ if (!existsSync65(lockFile)) return;
30205
30835
  try {
30206
- const lock2 = JSON.parse(readFileSync49(lockFile, "utf8"));
30836
+ const lock2 = JSON.parse(readFileSync51(lockFile, "utf8"));
30207
30837
  if (lock2.pid && isProcessAlive2(lock2.pid)) {
30208
30838
  console.error(
30209
30839
  `Voice daemon already running (PID ${lock2.pid}, env: ${lock2.env}). Stop it first with: assist voice stop`
@@ -30214,7 +30844,7 @@ function checkLockFile() {
30214
30844
  }
30215
30845
  }
30216
30846
  function bootstrapVenv() {
30217
- if (existsSync64(getVenvPython())) return;
30847
+ if (existsSync65(getVenvPython())) return;
30218
30848
  console.log("Setting up Python environment...");
30219
30849
  const pythonDir = getPythonDir();
30220
30850
  execSync58(
@@ -30244,7 +30874,7 @@ function setup() {
30244
30874
  bootstrapVenv();
30245
30875
  console.log("\nDownloading models...\n");
30246
30876
  const script = join82(getPythonDir(), "setup_models.py");
30247
- const result = spawnSync8(getVenvPython(), [script], {
30877
+ const result = spawnSync9(getVenvPython(), [script], {
30248
30878
  stdio: "inherit",
30249
30879
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
30250
30880
  });
@@ -30305,7 +30935,7 @@ function start2(options2) {
30305
30935
  }
30306
30936
 
30307
30937
  // src/commands/voice/status.ts
30308
- import { existsSync as existsSync65, readFileSync as readFileSync50 } from "fs";
30938
+ import { existsSync as existsSync66, readFileSync as readFileSync52 } from "fs";
30309
30939
  function isProcessAlive3(pid) {
30310
30940
  try {
30311
30941
  process.kill(pid, 0);
@@ -30315,16 +30945,16 @@ function isProcessAlive3(pid) {
30315
30945
  }
30316
30946
  }
30317
30947
  function readRecentLogs(count8) {
30318
- if (!existsSync65(voicePaths.log)) return [];
30319
- const lines2 = readFileSync50(voicePaths.log, "utf8").trim().split("\n");
30948
+ if (!existsSync66(voicePaths.log)) return [];
30949
+ const lines2 = readFileSync52(voicePaths.log, "utf8").trim().split("\n");
30320
30950
  return lines2.slice(-count8);
30321
30951
  }
30322
30952
  function status2() {
30323
- if (!existsSync65(voicePaths.pid)) {
30953
+ if (!existsSync66(voicePaths.pid)) {
30324
30954
  console.log("Voice daemon: not running (no PID file)");
30325
30955
  return;
30326
30956
  }
30327
- const pid = Number.parseInt(readFileSync50(voicePaths.pid, "utf8").trim(), 10);
30957
+ const pid = Number.parseInt(readFileSync52(voicePaths.pid, "utf8").trim(), 10);
30328
30958
  const alive = isProcessAlive3(pid);
30329
30959
  console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
30330
30960
  const recent = readRecentLogs(5);
@@ -30343,13 +30973,13 @@ function status2() {
30343
30973
  }
30344
30974
 
30345
30975
  // src/commands/voice/stop.ts
30346
- import { existsSync as existsSync66, readFileSync as readFileSync51, unlinkSync as unlinkSync20 } from "fs";
30976
+ import { existsSync as existsSync67, readFileSync as readFileSync53, unlinkSync as unlinkSync20 } from "fs";
30347
30977
  function stop2() {
30348
- if (!existsSync66(voicePaths.pid)) {
30978
+ if (!existsSync67(voicePaths.pid)) {
30349
30979
  console.log("Voice daemon is not running (no PID file)");
30350
30980
  return;
30351
30981
  }
30352
- const pid = Number.parseInt(readFileSync51(voicePaths.pid, "utf8").trim(), 10);
30982
+ const pid = Number.parseInt(readFileSync53(voicePaths.pid, "utf8").trim(), 10);
30353
30983
  try {
30354
30984
  process.kill(pid, "SIGTERM");
30355
30985
  console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
@@ -30362,7 +30992,7 @@ function stop2() {
30362
30992
  }
30363
30993
  try {
30364
30994
  const lockFile = getLockFile();
30365
- if (existsSync66(lockFile)) unlinkSync20(lockFile);
30995
+ if (existsSync67(lockFile)) unlinkSync20(lockFile);
30366
30996
  } catch {
30367
30997
  }
30368
30998
  console.log("Voice daemon stopped");
@@ -30380,9 +31010,6 @@ function registerVoice(program2) {
30380
31010
  configHelp(voiceCommand, voiceConfigHelp);
30381
31011
  }
30382
31012
 
30383
- // src/commands/watch/readBuiltVersion.ts
30384
- import { join as join84 } from "path";
30385
-
30386
31013
  // src/commands/watch/resolveUpstream.ts
30387
31014
  import { execFileSync as execFileSync15 } from "child_process";
30388
31015
  function runGit3(args, cwd) {
@@ -30423,7 +31050,13 @@ function resolveUpstream(cwd) {
30423
31050
  }
30424
31051
  }
30425
31052
 
31053
+ // src/commands/watch/changedPaths.ts
31054
+ function changedPaths(from, cwd) {
31055
+ return runGit3(["diff", "--name-only", `${from}..HEAD`], cwd).split("\n").filter((line) => line.length > 0);
31056
+ }
31057
+
30426
31058
  // src/commands/watch/readBuiltVersion.ts
31059
+ import { join as join84 } from "path";
30427
31060
  function readBuiltVersion(cwd) {
30428
31061
  try {
30429
31062
  const root = runGit3(["rev-parse", "--show-toplevel"], cwd);
@@ -30534,12 +31167,11 @@ function syncAdvice(paths) {
30534
31167
  // src/commands/watch/buildWatchReport.ts
30535
31168
  var lines = (output) => output.split("\n").filter((line) => line.length > 0);
30536
31169
  function buildWatchReport(from, cwd) {
30537
- const range = from ? `${from}..HEAD` : void 0;
30538
- const changed = range ? lines(runGit3(["diff", "--name-only", range], cwd)) : [];
31170
+ const changed = from ? changedPaths(from, cwd) : [];
30539
31171
  return renderWatchReport({
30540
31172
  version: readBuiltVersion(cwd),
30541
31173
  commits: readRecentCommits(10, cwd),
30542
- newShas: range ? lines(runGit3(["rev-list", range], cwd)) : [],
31174
+ newShas: from ? lines(runGit3(["rev-list", `${from}..HEAD`], cwd)) : [],
30543
31175
  restarts: restartAdvice(changed),
30544
31176
  syncs: syncAdvice(changed)
30545
31177
  });
@@ -30765,7 +31397,7 @@ function resolveParams(params, cliArgs) {
30765
31397
  }
30766
31398
 
30767
31399
  // src/commands/run/resolveRunCwd.ts
30768
- import { existsSync as existsSync67 } from "fs";
31400
+ import { existsSync as existsSync68 } from "fs";
30769
31401
  import { resolve as resolve18 } from "path";
30770
31402
  var MissingRunCwdError = class extends Error {
30771
31403
  constructor(runName, cwd) {
@@ -30778,17 +31410,17 @@ var MissingRunCwdError = class extends Error {
30778
31410
  function resolveRunCwd(config, baseDir = runConfigBaseDir()) {
30779
31411
  if (!config.cwd) return void 0;
30780
31412
  const cwd = resolve18(baseDir, config.cwd);
30781
- if (!existsSync67(cwd)) throw new MissingRunCwdError(config.name, cwd);
31413
+ if (!existsSync68(cwd)) throw new MissingRunCwdError(config.name, cwd);
30782
31414
  return cwd;
30783
31415
  }
30784
31416
 
30785
31417
  // src/commands/run/runCommandToCompletion.ts
30786
31418
  import { spawn as spawn9 } from "child_process";
30787
- import { existsSync as existsSync69 } from "fs";
31419
+ import { existsSync as existsSync70 } from "fs";
30788
31420
 
30789
31421
  // src/commands/run/resolveCommand.ts
30790
31422
  import { execFileSync as execFileSync16 } from "child_process";
30791
- import { existsSync as existsSync68 } from "fs";
31423
+ import { existsSync as existsSync69 } from "fs";
30792
31424
  import { dirname as dirname35, join as join85, resolve as resolve19 } from "path";
30793
31425
  function resolveCommand2(command) {
30794
31426
  if (process.platform !== "win32" || command !== "bash") return command;
@@ -30796,7 +31428,7 @@ function resolveCommand2(command) {
30796
31428
  const gitPath = execFileSync16("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
30797
31429
  const gitRoot = resolve19(dirname35(gitPath), "..");
30798
31430
  const gitBash = join85(gitRoot, "bin", "bash.exe");
30799
- if (existsSync68(gitBash)) return gitBash;
31431
+ if (existsSync69(gitBash)) return gitBash;
30800
31432
  } catch {
30801
31433
  return command;
30802
31434
  }
@@ -30806,7 +31438,7 @@ function resolveCommand2(command) {
30806
31438
  // src/commands/run/runCommandToCompletion.ts
30807
31439
  function runCommandToCompletion(command, args, env, cwd, quiet) {
30808
31440
  return new Promise((resolveResult) => {
30809
- if (cwd && !existsSync69(cwd)) {
31441
+ if (cwd && !existsSync70(cwd)) {
30810
31442
  resolveResult({
30811
31443
  kind: "failed",
30812
31444
  message: `Failed to execute command: cwd ${cwd} does not exist`
@@ -30852,6 +31484,15 @@ function runPreCommands(pre, cwd) {
30852
31484
  }
30853
31485
  }
30854
31486
 
31487
+ // src/commands/watch/toBuildOutcome.ts
31488
+ function toBuildOutcome(result) {
31489
+ if (result.kind === "failed")
31490
+ return { kind: "failed", exitCode: 1, output: result.message };
31491
+ if (result.exitCode !== 0)
31492
+ return { kind: "failed", exitCode: result.exitCode, output: result.output };
31493
+ return { kind: "built" };
31494
+ }
31495
+
30855
31496
  // src/commands/watch/runWatchBuild.ts
30856
31497
  async function runWatchBuild(entry) {
30857
31498
  const config = findRunConfig(entry);
@@ -30863,18 +31504,15 @@ async function runWatchBuild(entry) {
30863
31504
  return { kind: "failed", exitCode: 1, output: error.message };
30864
31505
  }
30865
31506
  if (config.pre) runPreCommands(config.pre, cwd);
30866
- const result = await runCommandToCompletion(
30867
- config.command,
30868
- [...config.args ?? [], ...resolveParams(config.params, [])],
30869
- config.env,
30870
- cwd,
30871
- config.quiet
31507
+ return toBuildOutcome(
31508
+ await runCommandToCompletion(
31509
+ config.command,
31510
+ [...config.args ?? [], ...resolveParams(config.params, [])],
31511
+ config.env,
31512
+ cwd,
31513
+ config.quiet
31514
+ )
30872
31515
  );
30873
- if (result.kind === "failed")
30874
- return { kind: "failed", exitCode: 1, output: result.message };
30875
- if (result.exitCode !== 0)
30876
- return { kind: "failed", exitCode: result.exitCode, output: result.output };
30877
- return { kind: "built" };
30878
31516
  }
30879
31517
 
30880
31518
  // src/commands/watch/reportBuildOrExit.ts
@@ -30889,6 +31527,25 @@ async function reportBuildOrExit(entry) {
30889
31527
  process.exit(4);
30890
31528
  }
30891
31529
 
31530
+ // src/commands/watch/runPostBuildSync.ts
31531
+ async function runPostBuildSync() {
31532
+ return toBuildOutcome(
31533
+ await runCommandToCompletion("assist", ["sync", "--yes"])
31534
+ );
31535
+ }
31536
+
31537
+ // src/commands/watch/reportSyncOrExit.ts
31538
+ async function reportSyncOrExit() {
31539
+ const outcome = await runPostBuildSync();
31540
+ if (outcome.kind === "built") {
31541
+ console.log("synced ~/.claude");
31542
+ return;
31543
+ }
31544
+ if (outcome.output.length > 0) process.stdout.write(outcome.output);
31545
+ console.error(`sync failed with exit code ${outcome.exitCode}`);
31546
+ process.exit(4);
31547
+ }
31548
+
30892
31549
  // src/commands/watch/fetchQuietly.ts
30893
31550
  import { execFileSync as execFileSync17 } from "child_process";
30894
31551
  var MIN_FETCH_TIMEOUT_MS = 6e4;
@@ -31000,6 +31657,8 @@ ${buildWatchReport(outcome.from)}`);
31000
31657
  await reportBuildOrExit(
31001
31658
  typeof options2.build === "string" ? options2.build : DEFAULT_BUILD_ENTRY
31002
31659
  );
31660
+ if (syncAdvice(changedPaths(outcome.from)).length > 0)
31661
+ await reportSyncOrExit();
31003
31662
  }
31004
31663
  process.exit(0);
31005
31664
  }
@@ -31008,7 +31667,7 @@ ${buildWatchReport(outcome.from)}`);
31008
31667
  function registerWatch(program2) {
31009
31668
  const watchCommand = program2.command("watch").description("Wait on upstream movement for the current branch");
31010
31669
  watchCommand.command("wait").description(
31011
- "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)"
31670
+ "Block until the current branch's upstream gains commits, then exit 0 (2 on timeout, 3 when --pull hits genuine divergence, 4 when --build or the post-build sync fails, 1 when waiting is impossible, 130 on interrupt)"
31012
31671
  ).option(
31013
31672
  "--interval <duration>",
31014
31673
  "How often to fetch after the fetch at startup (e.g. 30s, 2m)",
@@ -31022,7 +31681,7 @@ function registerWatch(program2) {
31022
31681
  "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"
31023
31682
  ).option(
31024
31683
  "--build [entry]",
31025
- "After a successful pull, run this run entry (default auto-build); exit 4 with its output when it fails"
31684
+ "After a successful pull, run this run entry (default auto-build), then run assist sync --yes when the pulled commits touched the files sync installs; exit 4 with the output of whichever fails"
31026
31685
  ).action(
31027
31686
  (options2) => watchWait(options2)
31028
31687
  );
@@ -31036,7 +31695,7 @@ function registerWatch(program2) {
31036
31695
 
31037
31696
  // src/commands/roam/auth.ts
31038
31697
  import { randomBytes } from "crypto";
31039
- import chalk215 from "chalk";
31698
+ import chalk216 from "chalk";
31040
31699
 
31041
31700
  // src/commands/roam/waitForCallback.ts
31042
31701
  import { createServer as createServer3 } from "http";
@@ -31167,13 +31826,13 @@ async function auth() {
31167
31826
  saveGlobalConfig(config);
31168
31827
  const state = randomBytes(16).toString("hex");
31169
31828
  console.log(
31170
- chalk215.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
31829
+ chalk216.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
31171
31830
  );
31172
- console.log(chalk215.white("http://localhost:14523/callback\n"));
31173
- console.log(chalk215.blue("Opening browser for authorization..."));
31174
- console.log(chalk215.dim("Waiting for authorization callback..."));
31831
+ console.log(chalk216.white("http://localhost:14523/callback\n"));
31832
+ console.log(chalk216.blue("Opening browser for authorization..."));
31833
+ console.log(chalk216.dim("Waiting for authorization callback..."));
31175
31834
  const { code, redirectUri } = await authorizeInBrowser(clientId, state);
31176
- console.log(chalk215.dim("Exchanging code for tokens..."));
31835
+ console.log(chalk216.dim("Exchanging code for tokens..."));
31177
31836
  const tokens = await exchangeToken({
31178
31837
  code,
31179
31838
  clientId,
@@ -31189,13 +31848,13 @@ async function auth() {
31189
31848
  };
31190
31849
  saveGlobalConfig(config);
31191
31850
  console.log(
31192
- chalk215.green("Roam credentials and tokens saved to ~/.assist.yml")
31851
+ chalk216.green("Roam credentials and tokens saved to ~/.assist.yml")
31193
31852
  );
31194
31853
  }
31195
31854
 
31196
31855
  // src/commands/roam/postRoamActivity.ts
31197
31856
  import { execFileSync as execFileSync18 } from "child_process";
31198
- import { readdirSync as readdirSync20, readFileSync as readFileSync52, statSync as statSync11 } from "fs";
31857
+ import { readdirSync as readdirSync20, readFileSync as readFileSync54, statSync as statSync11 } from "fs";
31199
31858
  import { join as join86 } from "path";
31200
31859
  function findPortFile(roamDir) {
31201
31860
  let entries;
@@ -31221,7 +31880,7 @@ function postRoamActivity(app, event) {
31221
31880
  if (!portFile) return;
31222
31881
  let port;
31223
31882
  try {
31224
- port = readFileSync52(portFile, "utf8").trim();
31883
+ port = readFileSync54(portFile, "utf8").trim();
31225
31884
  } catch {
31226
31885
  return;
31227
31886
  }
@@ -31475,7 +32134,7 @@ function link2() {
31475
32134
  }
31476
32135
 
31477
32136
  // src/commands/run/remove.ts
31478
- import { existsSync as existsSync70, unlinkSync as unlinkSync21 } from "fs";
32137
+ import { existsSync as existsSync71, unlinkSync as unlinkSync21 } from "fs";
31479
32138
  import { join as join88 } from "path";
31480
32139
  function findRemoveIndex() {
31481
32140
  const idx = process.argv.indexOf("remove");
@@ -31492,7 +32151,7 @@ function parseRemoveName() {
31492
32151
  }
31493
32152
  function deleteCommandFile(name) {
31494
32153
  const filePath = join88(".claude", "commands", `${name}.md`);
31495
- if (existsSync70(filePath)) {
32154
+ if (existsSync71(filePath)) {
31496
32155
  unlinkSync21(filePath);
31497
32156
  console.log(`Deleted command file: ${filePath}`);
31498
32157
  }
@@ -31537,10 +32196,10 @@ function registerRun(program2) {
31537
32196
 
31538
32197
  // src/commands/screenshot/index.ts
31539
32198
  import { execSync as execSync60 } from "child_process";
31540
- import { existsSync as existsSync71, mkdirSync as mkdirSync31, unlinkSync as unlinkSync22, writeFileSync as writeFileSync46 } from "fs";
32199
+ import { existsSync as existsSync72, mkdirSync as mkdirSync31, unlinkSync as unlinkSync22, writeFileSync as writeFileSync46 } from "fs";
31541
32200
  import { tmpdir as tmpdir8 } from "os";
31542
32201
  import { join as join89, resolve as resolve20 } from "path";
31543
- import chalk216 from "chalk";
32202
+ import chalk217 from "chalk";
31544
32203
 
31545
32204
  // src/commands/screenshot/captureWindowPs1.ts
31546
32205
  var captureWindowPs1 = `
@@ -31669,7 +32328,7 @@ Write-Output $OutputPath
31669
32328
 
31670
32329
  // src/commands/screenshot/index.ts
31671
32330
  function buildOutputPath(outputDir, processName) {
31672
- if (!existsSync71(outputDir)) {
32331
+ if (!existsSync72(outputDir)) {
31673
32332
  mkdirSync31(outputDir, { recursive: true });
31674
32333
  }
31675
32334
  const timestamp6 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
@@ -31691,13 +32350,13 @@ function screenshot(processName) {
31691
32350
  const config = loadConfig();
31692
32351
  const outputDir = resolve20(config.screenshot.outputDir);
31693
32352
  const outputPath = buildOutputPath(outputDir, processName);
31694
- console.log(chalk216.gray(`Capturing window for process "${processName}" ...`));
32353
+ console.log(chalk217.gray(`Capturing window for process "${processName}" ...`));
31695
32354
  try {
31696
32355
  runPowerShellScript(processName, outputPath);
31697
- console.log(chalk216.green(`Screenshot saved: ${outputPath}`));
32356
+ console.log(chalk217.green(`Screenshot saved: ${outputPath}`));
31698
32357
  } catch (error) {
31699
32358
  const msg = error instanceof Error ? error.message : String(error);
31700
- console.error(chalk216.red(`Failed to capture screenshot: ${msg}`));
32359
+ console.error(chalk217.red(`Failed to capture screenshot: ${msg}`));
31701
32360
  process.exit(1);
31702
32361
  }
31703
32362
  }
@@ -31753,11 +32412,11 @@ function applyLine(result, pending, line) {
31753
32412
  }
31754
32413
 
31755
32414
  // src/commands/sessions/daemon/readDaemonPidFile.ts
31756
- import { readFileSync as readFileSync53 } from "fs";
32415
+ import { readFileSync as readFileSync55 } from "fs";
31757
32416
  function readDaemonPidFile() {
31758
32417
  try {
31759
32418
  const pid = Number.parseInt(
31760
- readFileSync53(daemonPaths.pid, "utf8").trim(),
32419
+ readFileSync55(daemonPaths.pid, "utf8").trim(),
31761
32420
  10
31762
32421
  );
31763
32422
  return Number.isInteger(pid) ? pid : void 0;
@@ -32014,12 +32673,12 @@ function toSessionRunInfo({
32014
32673
  }
32015
32674
 
32016
32675
  // src/commands/sessions/daemon/worktree/joinRefusal.ts
32017
- import { existsSync as existsSync72 } from "fs";
32676
+ import { existsSync as existsSync73 } from "fs";
32018
32677
  function joinRefusal(session) {
32019
32678
  if (session.commandType === "run") return "a server run has no agent stream";
32020
32679
  if (session.closing === true) return "the session is closing";
32021
32680
  if (!session.cwd) return "the session has no working directory";
32022
- if (!existsSync72(session.cwd))
32681
+ if (!existsSync73(session.cwd))
32023
32682
  return "the session's workspace no longer exists";
32024
32683
  return void 0;
32025
32684
  }
@@ -32183,11 +32842,11 @@ function sessionBase(id, status3) {
32183
32842
  }
32184
32843
 
32185
32844
  // src/commands/sessions/daemon/spawnPty.ts
32186
- import { existsSync as existsSync74 } from "fs";
32845
+ import { existsSync as existsSync75 } from "fs";
32187
32846
  import * as pty from "node-pty";
32188
32847
 
32189
32848
  // src/commands/sessions/daemon/ensureSpawnHelperExecutable.ts
32190
- import { chmodSync, existsSync as existsSync73, statSync as statSync12 } from "fs";
32849
+ import { chmodSync, existsSync as existsSync74, statSync as statSync12 } from "fs";
32191
32850
  import { createRequire as createRequire3 } from "module";
32192
32851
  import path75 from "path";
32193
32852
  var require4 = createRequire3(import.meta.url);
@@ -32202,7 +32861,7 @@ function ensureSpawnHelperExecutable() {
32202
32861
  `${process.platform}-${process.arch}`,
32203
32862
  "spawn-helper"
32204
32863
  );
32205
- if (!existsSync73(helper)) return;
32864
+ if (!existsSync74(helper)) return;
32206
32865
  const mode = statSync12(helper).mode;
32207
32866
  if ((mode & 73) === 0) chmodSync(helper, mode | 493);
32208
32867
  }
@@ -32238,7 +32897,7 @@ function spawnPty(args, cwd, sessionId, extraEnv) {
32238
32897
  });
32239
32898
  }
32240
32899
  function refuseMissingCwd(cwd, sessionId) {
32241
- if (!cwd || existsSync74(cwd)) return;
32900
+ if (!cwd || existsSync75(cwd)) return;
32242
32901
  daemonLog(
32243
32902
  `${sessionId ? `session ${sessionId}` : "pty"} not spawned: working directory ${cwd} no longer exists`
32244
32903
  );
@@ -32420,11 +33079,11 @@ function setStatus2(session, newStatus) {
32420
33079
  }
32421
33080
 
32422
33081
  // src/commands/sessions/daemon/worktree/reapWorktree.ts
32423
- import { existsSync as existsSync76 } from "fs";
33082
+ import { existsSync as existsSync77 } from "fs";
32424
33083
  import { basename as basename22 } from "path";
32425
33084
 
32426
33085
  // src/commands/sessions/daemon/worktree/deleteStrandedTree.ts
32427
- import { existsSync as existsSync75 } from "fs";
33086
+ import { existsSync as existsSync76 } from "fs";
32428
33087
  import { join as join92 } from "path";
32429
33088
 
32430
33089
  // src/commands/sessions/daemon/worktree/deleteTreeDirectly.ts
@@ -32494,7 +33153,7 @@ async function deleteStrandedTree(clone, worktreePath, cause) {
32494
33153
  );
32495
33154
  }
32496
33155
  function strandedReason(worktreePath, cause) {
32497
- if (!existsSync75(join92(worktreePath, ".git")))
33156
+ if (!existsSync76(join92(worktreePath, ".git")))
32498
33157
  return "its .git link is already gone";
32499
33158
  if (/not a working tree|not a git repository/i.test(reason2(cause)))
32500
33159
  return "git no longer recognises it as a working tree";
@@ -32546,7 +33205,7 @@ function reason3(error) {
32546
33205
 
32547
33206
  // src/commands/sessions/daemon/worktree/reapWorktree.ts
32548
33207
  async function reapWorktree(worktreePath, force = false) {
32549
- if (!existsSync76(worktreePath)) {
33208
+ if (!existsSync77(worktreePath)) {
32550
33209
  forgetWorktree(worktreePath);
32551
33210
  daemonLog(
32552
33211
  `worktree ${worktreePath} already gone; its record was forgotten`
@@ -32571,7 +33230,7 @@ async function reapWorktree(worktreePath, force = false) {
32571
33230
  }
32572
33231
  function owningClone(worktreePath) {
32573
33232
  const recorded = worktreeAttributionIncludingReaped(worktreePath)?.clone;
32574
- if (recorded && existsSync76(recorded)) return recorded;
33233
+ if (recorded && existsSync77(recorded)) return recorded;
32575
33234
  const detected = mainWorktree(worktreePath);
32576
33235
  if (detected) return detected;
32577
33236
  daemonLog(
@@ -32702,12 +33361,12 @@ function closeGateApplies(sessions, session) {
32702
33361
  }
32703
33362
 
32704
33363
  // src/commands/sessions/daemon/worktree/watchGitState.ts
32705
- import { existsSync as existsSync77, watch } from "fs";
33364
+ import { existsSync as existsSync78, watch } from "fs";
32706
33365
  var DEBOUNCE_MS = 500;
32707
33366
  var POLL_MS = 3e4;
32708
33367
  function watchGitState(cwd, onChange) {
32709
33368
  const common = gitCommonDir(cwd);
32710
- if (!common || !existsSync77(common)) return void 0;
33369
+ if (!common || !existsSync78(common)) return void 0;
32711
33370
  const watchers = [
32712
33371
  watchGitDir(common, onChange),
32713
33372
  pollGitState(cwd, onChange)
@@ -32882,9 +33541,9 @@ function flushPhaseActiveMs(session) {
32882
33541
  if (await persistPhaseActiveMs(phase.itemId, phase.phaseIdx, delta))
32883
33542
  session.activeMsFlushedForStretch = { since, ms: flushed + delta };
32884
33543
  };
32885
- const chain = (session.activeMsFlushChain ?? Promise.resolve()).then(run4);
32886
- session.activeMsFlushChain = chain;
32887
- return chain;
33544
+ const chain2 = (session.activeMsFlushChain ?? Promise.resolve()).then(run4);
33545
+ session.activeMsFlushChain = chain2;
33546
+ return chain2;
32888
33547
  }
32889
33548
 
32890
33549
  // src/commands/sessions/daemon/stripReplayQueries.ts
@@ -33182,10 +33841,10 @@ function emitSessionOutput(session, clients, data) {
33182
33841
  }
33183
33842
 
33184
33843
  // src/commands/sessions/daemon/exitReason.ts
33185
- import { existsSync as existsSync78 } from "fs";
33844
+ import { existsSync as existsSync79 } from "fs";
33186
33845
  import { resolve as resolve21 } from "path";
33187
33846
  function exitDetail(session) {
33188
- if (session.cwd && !existsSync78(session.cwd))
33847
+ if (session.cwd && !existsSync79(session.cwd))
33189
33848
  return `working directory ${session.cwd} no longer exists`;
33190
33849
  return missingRunConfigCwd(session);
33191
33850
  }
@@ -33199,7 +33858,7 @@ function missingRunConfigCwd(session) {
33199
33858
  const config = resolveRunConfig(session.runName, dir);
33200
33859
  if (!config?.cwd) return void 0;
33201
33860
  const configured = resolve21(runConfigBaseDirFrom(dir), config.cwd);
33202
- if (existsSync78(configured)) return void 0;
33861
+ if (existsSync79(configured)) return void 0;
33203
33862
  return `run config "${config.name}": cwd ${configured} does not exist`;
33204
33863
  }
33205
33864
 
@@ -33240,7 +33899,7 @@ function handleFailedResume(session, exitCode, onStatusChange) {
33240
33899
  }
33241
33900
 
33242
33901
  // src/commands/sessions/daemon/watchActivity.ts
33243
- import { existsSync as existsSync79, mkdirSync as mkdirSync32, watch as watch2 } from "fs";
33902
+ import { existsSync as existsSync80, mkdirSync as mkdirSync32, watch as watch2 } from "fs";
33244
33903
  import { dirname as dirname37 } from "path";
33245
33904
 
33246
33905
  // src/commands/sessions/daemon/applyActivityToSession.ts
@@ -33326,7 +33985,7 @@ function watchActivity(session, notify2, onClaudeSessionId) {
33326
33985
  if (timer) clearTimeout(timer);
33327
33986
  timer = setTimeout(read2, DEBOUNCE_MS2);
33328
33987
  });
33329
- if (existsSync79(path80)) read2();
33988
+ if (existsSync80(path80)) read2();
33330
33989
  }
33331
33990
  function refreshActivity(session) {
33332
33991
  if (session.commandType !== "assist" || !session.cwd) return;
@@ -34948,7 +35607,7 @@ function rearmStoppedSessions(sessions, notify2) {
34948
35607
  }
34949
35608
 
34950
35609
  // src/commands/sessions/daemon/worktree/reconcileWorktreesOnRestore.ts
34951
- import { existsSync as existsSync82 } from "fs";
35610
+ import { existsSync as existsSync83 } from "fs";
34952
35611
  import { basename as basename24 } from "path";
34953
35612
 
34954
35613
  // src/commands/sessions/daemon/worktree/accountedTrees.ts
@@ -35003,9 +35662,9 @@ function bindResumedWorktree(session, cwd, notify2) {
35003
35662
  }
35004
35663
 
35005
35664
  // src/commands/sessions/daemon/worktree/reclaimVanishedWorktrees.ts
35006
- import { existsSync as existsSync81 } from "fs";
35665
+ import { existsSync as existsSync82 } from "fs";
35007
35666
  async function reclaimVanishedWorktrees(clone, paths) {
35008
- if (!existsSync81(clone)) {
35667
+ if (!existsSync82(clone)) {
35009
35668
  for (const { path: path80 } of paths) forgetWorktree(path80);
35010
35669
  daemonLog(
35011
35670
  `clone ${clone} is gone; forgot ${paths.length} worktree record(s) it owned`
@@ -35171,7 +35830,7 @@ async function recoverOrphanedWorktrees(sessions, spawnWith, notify2) {
35171
35830
  );
35172
35831
  continue;
35173
35832
  }
35174
- if (!existsSync82(path80)) {
35833
+ if (!existsSync83(path80)) {
35175
35834
  logVanishedTree(sessions, path80);
35176
35835
  vanished.set(clone, [
35177
35836
  ...vanished.get(clone) ?? [],
@@ -35788,14 +36447,14 @@ async function defaultConnect() {
35788
36447
  }
35789
36448
 
35790
36449
  // src/commands/sessions/daemon/hasPersistedWindowsSessions.ts
35791
- import { existsSync as existsSync83, readFileSync as readFileSync55 } from "fs";
36450
+ import { existsSync as existsSync84, readFileSync as readFileSync57 } from "fs";
35792
36451
  import { posix as posix3 } from "path";
35793
36452
  function hasPersistedWindowsSessions() {
35794
36453
  const sessionsFile = windowsSessionsFileFromWsl();
35795
36454
  if (!sessionsFile) return false;
35796
36455
  try {
35797
- if (!existsSync83(sessionsFile)) return false;
35798
- const data = JSON.parse(readFileSync55(sessionsFile, "utf8"));
36456
+ if (!existsSync84(sessionsFile)) return false;
36457
+ const data = JSON.parse(readFileSync57(sessionsFile, "utf8"));
35799
36458
  return Array.isArray(data) && data.length > 0;
35800
36459
  } catch (error) {
35801
36460
  const message3 = error instanceof Error ? error.message : String(error);
@@ -36529,7 +37188,7 @@ function setAutoAdvance(sessions, id, enabled) {
36529
37188
  }
36530
37189
 
36531
37190
  // src/commands/sessions/daemon/worktree/resumeInTree.ts
36532
- import { existsSync as existsSync86 } from "fs";
37191
+ import { existsSync as existsSync87 } from "fs";
36533
37192
 
36534
37193
  // src/commands/sessions/daemon/resumeSession.ts
36535
37194
  function resumeSession(id, sessionId, cwd, name, holdPty, harness) {
@@ -36560,10 +37219,10 @@ function resumeSession(id, sessionId, cwd, name, holdPty, harness) {
36560
37219
  }
36561
37220
 
36562
37221
  // src/commands/sessions/daemon/worktree/resumeInReplacementTree.ts
36563
- import { existsSync as existsSync85 } from "fs";
37222
+ import { existsSync as existsSync86 } from "fs";
36564
37223
 
36565
37224
  // src/commands/sessions/daemon/worktree/carryTranscriptToTree.ts
36566
- import { copyFileSync as copyFileSync7, existsSync as existsSync84, mkdirSync as mkdirSync34 } from "fs";
37225
+ import { copyFileSync as copyFileSync7, existsSync as existsSync85, mkdirSync as mkdirSync34 } from "fs";
36567
37226
  import { join as join94 } from "path";
36568
37227
  function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
36569
37228
  const dir = projectDirForCwd(toCwd);
@@ -36574,7 +37233,7 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
36574
37233
  return;
36575
37234
  }
36576
37235
  const dest = join94(dir, `${claudeSessionId}.jsonl`);
36577
- if (existsSync84(dest)) {
37236
+ if (existsSync85(dest)) {
36578
37237
  daemonLog(`transcript ${claudeSessionId} already present in ${dir}`);
36579
37238
  return;
36580
37239
  }
@@ -36625,7 +37284,7 @@ function resumeInReplacementTree(ctx, claudeSessionId, missingCwd, name, harness
36625
37284
  }
36626
37285
  function cloneForReapedTree(missingCwd) {
36627
37286
  const clone = worktreeAttributionIncludingReaped(missingCwd)?.clone;
36628
- if (!clone || !existsSync85(clone))
37287
+ if (!clone || !existsSync86(clone))
36629
37288
  throw new Error(
36630
37289
  `working directory no longer exists and no clone is recorded to re-allocate from: ${missingCwd}`
36631
37290
  );
@@ -36634,7 +37293,7 @@ function cloneForReapedTree(missingCwd) {
36634
37293
 
36635
37294
  // src/commands/sessions/daemon/worktree/resumeInTree.ts
36636
37295
  function resumeInTree(ctx, sessionId, cwd, name, harness) {
36637
- if (!existsSync86(cwd))
37296
+ if (!existsSync87(cwd))
36638
37297
  return resumeInReplacementTree(ctx, sessionId, cwd, name, harness);
36639
37298
  const id = ctx.spawnWith(
36640
37299
  (sid) => resumeSession(sid, sessionId, cwd, name, void 0, harness)
@@ -37213,7 +37872,7 @@ function handleConnection(socket, manager) {
37213
37872
  import { unlinkSync as unlinkSync23, writeFileSync as writeFileSync47 } from "fs";
37214
37873
 
37215
37874
  // src/commands/sessions/daemon/startPidFileWatchdog.ts
37216
- import { readFileSync as readFileSync56 } from "fs";
37875
+ import { readFileSync as readFileSync58 } from "fs";
37217
37876
  var WATCHDOG_INTERVAL_MS = 5e3;
37218
37877
  function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
37219
37878
  const timer = setInterval(() => {
@@ -37224,7 +37883,7 @@ function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
37224
37883
  }
37225
37884
  function ownsPidFile() {
37226
37885
  try {
37227
- return readFileSync56(daemonPaths.pid, "utf8").trim() === String(process.pid);
37886
+ return readFileSync58(daemonPaths.pid, "utf8").trim() === String(process.pid);
37228
37887
  } catch {
37229
37888
  return false;
37230
37889
  }
@@ -37474,7 +38133,7 @@ function registerSetStatusCommand(cmd) {
37474
38133
 
37475
38134
  // src/commands/sessions/summarise/index.ts
37476
38135
  import * as fs56 from "fs";
37477
- import chalk217 from "chalk";
38136
+ import chalk218 from "chalk";
37478
38137
 
37479
38138
  // src/commands/sessions/summarise/shared.ts
37480
38139
  import * as fs55 from "fs";
@@ -37533,22 +38192,22 @@ ${firstMessage}`);
37533
38192
  async function summarise2(options2) {
37534
38193
  const files = await discoverSessionFiles();
37535
38194
  if (files.length === 0) {
37536
- console.log(chalk217.yellow("No sessions found."));
38195
+ console.log(chalk218.yellow("No sessions found."));
37537
38196
  return;
37538
38197
  }
37539
38198
  const toProcess = selectCandidates(files, options2);
37540
38199
  if (toProcess.length === 0) {
37541
- console.log(chalk217.green("All sessions already summarised."));
38200
+ console.log(chalk218.green("All sessions already summarised."));
37542
38201
  return;
37543
38202
  }
37544
38203
  console.log(
37545
- chalk217.cyan(
38204
+ chalk218.cyan(
37546
38205
  `Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
37547
38206
  )
37548
38207
  );
37549
38208
  const { succeeded, failed: failed2 } = processSessions(toProcess);
37550
38209
  console.log(
37551
- chalk217.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk217.yellow(`, ${failed2} skipped`) : "")
38210
+ chalk218.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk218.yellow(`, ${failed2} skipped`) : "")
37552
38211
  );
37553
38212
  }
37554
38213
  function selectCandidates(files, options2) {
@@ -37568,16 +38227,16 @@ function processSessions(files) {
37568
38227
  let failed2 = 0;
37569
38228
  for (let i = 0; i < files.length; i++) {
37570
38229
  const file = files[i];
37571
- process.stdout.write(chalk217.dim(` [${i + 1}/${files.length}] `));
38230
+ process.stdout.write(chalk218.dim(` [${i + 1}/${files.length}] `));
37572
38231
  const summary = summariseSession(file);
37573
38232
  if (summary) {
37574
38233
  writeSummary(file, summary);
37575
38234
  succeeded++;
37576
- process.stdout.write(`${chalk217.green("\u2713")} ${summary}
38235
+ process.stdout.write(`${chalk218.green("\u2713")} ${summary}
37577
38236
  `);
37578
38237
  } else {
37579
38238
  failed2++;
37580
- process.stdout.write(` ${chalk217.yellow("skip")}
38239
+ process.stdout.write(` ${chalk218.yellow("skip")}
37581
38240
  `);
37582
38241
  }
37583
38242
  }
@@ -37598,7 +38257,7 @@ function registerSessions(program2) {
37598
38257
  }
37599
38258
 
37600
38259
  // src/commands/statusLine.ts
37601
- import chalk219 from "chalk";
38260
+ import chalk220 from "chalk";
37602
38261
 
37603
38262
  // src/shared/contextLevel.ts
37604
38263
  function contextLevel(pct) {
@@ -37608,7 +38267,7 @@ function contextLevel(pct) {
37608
38267
  }
37609
38268
 
37610
38269
  // src/commands/buildLimitsSegment.ts
37611
- import chalk218 from "chalk";
38270
+ import chalk219 from "chalk";
37612
38271
 
37613
38272
  // src/shared/rateLimitLevel.ts
37614
38273
  var FIVE_HOUR_SECONDS = 5 * 3600;
@@ -37646,9 +38305,9 @@ function rateLimitLevel(pct, resetsAt, windowSeconds, now) {
37646
38305
 
37647
38306
  // src/commands/buildLimitsSegment.ts
37648
38307
  var LEVEL_COLOR = {
37649
- ok: chalk218.green,
37650
- warn: chalk218.yellow,
37651
- over: chalk218.red
38308
+ ok: chalk219.green,
38309
+ warn: chalk219.yellow,
38310
+ over: chalk219.red
37652
38311
  };
37653
38312
  function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel, now) {
37654
38313
  const level = rateLimitLevel(pct, resetsAt, windowSeconds, now);
@@ -37679,7 +38338,7 @@ function buildLimitsSegment(rateLimits) {
37679
38338
  }
37680
38339
 
37681
38340
  // src/commands/readGitBranch.ts
37682
- import { readFileSync as readFileSync58, statSync as statSync15 } from "fs";
38341
+ import { readFileSync as readFileSync60, statSync as statSync15 } from "fs";
37683
38342
  import { isAbsolute as isAbsolute4, join as join95, resolve as resolve22 } from "path";
37684
38343
  function resolveGitDir(cwd) {
37685
38344
  const dotGit = join95(cwd, ".git");
@@ -37694,7 +38353,7 @@ function resolveGitDir(cwd) {
37694
38353
  }
37695
38354
  let contents;
37696
38355
  try {
37697
- contents = readFileSync58(dotGit, "utf8");
38356
+ contents = readFileSync60(dotGit, "utf8");
37698
38357
  } catch {
37699
38358
  return null;
37700
38359
  }
@@ -37712,7 +38371,7 @@ function readGitBranch(cwd) {
37712
38371
  }
37713
38372
  let head;
37714
38373
  try {
37715
- head = readFileSync58(join95(gitDir, "HEAD"), "utf8");
38374
+ head = readFileSync60(join95(gitDir, "HEAD"), "utf8");
37716
38375
  } catch {
37717
38376
  return null;
37718
38377
  }
@@ -37744,7 +38403,7 @@ async function relayUsage(claudeSessionId, transcriptPath2, usedPct) {
37744
38403
  }
37745
38404
 
37746
38405
  // src/commands/statusLine.ts
37747
- chalk219.level = 3;
38406
+ chalk220.level = 3;
37748
38407
  function formatNumber(num) {
37749
38408
  return num.toLocaleString("en-US");
37750
38409
  }
@@ -37752,9 +38411,9 @@ function colorizePercent(pct) {
37752
38411
  const label2 = `${Math.round(pct)}%`;
37753
38412
  switch (contextLevel(pct)) {
37754
38413
  case "red":
37755
- return chalk219.red(label2);
38414
+ return chalk220.red(label2);
37756
38415
  case "yellow":
37757
- return chalk219.yellow(label2);
38416
+ return chalk220.yellow(label2);
37758
38417
  default:
37759
38418
  return label2;
37760
38419
  }
@@ -37767,7 +38426,7 @@ async function statusLine() {
37767
38426
  const usedPct = data.context_window.used_percentage ?? 0;
37768
38427
  const dir = data.workspace?.current_dir ?? data.cwd;
37769
38428
  const branch2 = dir ? readGitBranch(toGitCwd(dir)) : null;
37770
- const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${chalk219.cyan(branch2)} | ` : "";
38429
+ const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${chalk220.cyan(branch2)} | ` : "";
37771
38430
  console.log(
37772
38431
  `${branchSegment}${model} | Tokens - ${formatNumber(totalIn)} \u2191 : ${formatNumber(totalOut)} \u2193 | Context - ${colorizePercent(usedPct)}${buildLimitsSegment(data.rate_limits)}`
37773
38432
  );
@@ -37837,10 +38496,10 @@ async function update2() {
37837
38496
  }
37838
38497
 
37839
38498
  // src/reportCliError.ts
37840
- import chalk220 from "chalk";
38499
+ import chalk221 from "chalk";
37841
38500
  function reportCliError(error) {
37842
- if (error instanceof InvalidItemIdError || error instanceof AmbiguousRepoConfigError || error instanceof UnknownRepoConfigError || error instanceof MissingRunCwdError) {
37843
- console.error(chalk220.red(error.message));
38501
+ if (error instanceof InvalidItemIdError || error instanceof AmbiguousRepoConfigError || error instanceof UnknownRepoConfigError || error instanceof MissingRunCwdError || error instanceof MiroExtractError) {
38502
+ console.error(chalk221.red(error.message));
37844
38503
  } else {
37845
38504
  console.error(error);
37846
38505
  }
@@ -37883,6 +38542,7 @@ registerGithub(program);
37883
38542
  registerHandover(program);
37884
38543
  registerJira(program);
37885
38544
  registerMermaid(program);
38545
+ registerMiro(program);
37886
38546
  registerPrs(program);
37887
38547
  registerRoam(program);
37888
38548
  registerBacklog(program);