@staff0rd/assist 0.576.0 → 0.578.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.576.0",
9
+ version: "0.578.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -14914,12 +14914,12 @@ async function link(fromId, toId, opts) {
14914
14914
  const { orm } = await getReady();
14915
14915
  const fromItem = await loadItem(orm, fromNum);
14916
14916
  if (!fromItem) return void fail4(`Item ${from} not found.`);
14917
- const toItem = await loadItem(orm, toNum);
14918
- 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.`);
14919
14919
  if (!validateLinkTarget(fromItem, fromNum, toNum, linkType)) return;
14920
14920
  if (await createsCycle(orm, linkType, fromNum, toNum)) return;
14921
14921
  await orm.insert(links).values({ itemId: fromNum, type: linkType, targetId: toNum });
14922
- console.log(chalk85.green(`Linked ${from} ${linkType} ${to} (${toItem.name})`));
14922
+ console.log(chalk85.green(`Linked ${from} ${linkType} ${to} (${toItem2.name})`));
14923
14923
  }
14924
14924
 
14925
14925
  // src/commands/backlog/unlink.ts
@@ -16820,6 +16820,12 @@ function findBuiltinDenyRaw(rawCommand) {
16820
16820
  // src/shared/isApprovedRead.ts
16821
16821
  import { resolve as resolve13, sep } from "path";
16822
16822
 
16823
+ // src/shared/appliesFixStructure.ts
16824
+ var APPLY_RE = /^assist\s+github\s+issue\s+fix-structure\b.*\s--apply\b/;
16825
+ function appliesFixStructure(command) {
16826
+ return APPLY_RE.test(command);
16827
+ }
16828
+
16823
16829
  // src/shared/tokenize.ts
16824
16830
  function tokenize(command) {
16825
16831
  const tokens = [];
@@ -17046,6 +17052,7 @@ function isApprovedRead(command, toolName = "Bash") {
17046
17052
  if (isCdToCwd(command)) return "cd to current directory";
17047
17053
  const cdRead = isCdToReadAllowedDir(command);
17048
17054
  if (cdRead) return cdRead;
17055
+ if (appliesFixStructure(command)) return void 0;
17049
17056
  const matchedRead = findCliRead(command);
17050
17057
  if (matchedRead) return `Read-only CLI command: ${matchedRead}`;
17051
17058
  const matchedWrite = findCliWrite(command);
@@ -20695,309 +20702,178 @@ function parseTopCount(value) {
20695
20702
  return Number.parseInt(value, 10);
20696
20703
  }
20697
20704
 
20698
- // src/commands/github/issue/commentIssue.ts
20699
- import { execFileSync as execFileSync6 } from "child_process";
20705
+ // src/commands/github/issue/fixStructure/applyAndVerifySubtree.ts
20706
+ import chalk163 from "chalk";
20700
20707
 
20701
- // src/shared/validateProposedContent.ts
20702
- function validateProposedContent(labels, title, body) {
20703
- const { subject, context } = labels;
20704
- if (title.toLowerCase().includes("claude")) {
20705
- console.error(`Error: ${subject} title must not reference Claude`);
20706
- process.exit(1);
20707
- }
20708
- if (body.toLowerCase().includes("claude")) {
20709
- console.error(`Error: ${subject} body must not reference Claude`);
20710
- process.exit(1);
20711
- }
20712
- const titleBacklogIds = findBacklogRefs(title);
20713
- if (titleBacklogIds.length > 0) {
20714
- console.error(
20715
- backlogRefError(`${subject} title`, context, titleBacklogIds)
20716
- );
20717
- process.exit(1);
20718
- }
20719
- const bodyBacklogIds = findBacklogRefs(body);
20720
- if (bodyBacklogIds.length > 0) {
20721
- console.error(backlogRefError(`${subject} body`, context, bodyBacklogIds));
20722
- process.exit(1);
20723
- }
20724
- }
20708
+ // src/commands/github/issue/fixStructure/applyFixStructurePlan.ts
20709
+ import chalk162 from "chalk";
20725
20710
 
20726
- // src/commands/github/issue/reviewProposedIssueComment.ts
20727
- import { randomUUID as randomUUID7 } from "crypto";
20728
- async function reviewProposedIssueComment(title, body) {
20729
- const sessionId = process.env.ASSIST_SESSION_ID;
20730
- if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
20731
- await awaitPreviewApproval("GitHub issue comment preview", {
20732
- sessionId,
20733
- requestId: randomUUID7(),
20734
- title,
20735
- body,
20736
- prNumber: null,
20737
- kind: "github-issue-comment"
20711
+ // src/shared/runGhGraphqlJson.ts
20712
+ import { spawnSync as spawnSync5 } from "child_process";
20713
+ function runGhGraphqlJson(query, vars = {}) {
20714
+ const result = spawnSync5("gh", ["api", "graphql", "--input", "-"], {
20715
+ encoding: "utf8",
20716
+ windowsHide: true,
20717
+ input: JSON.stringify({ query, variables: vars }),
20718
+ maxBuffer: 64 * 1024 * 1024
20738
20719
  });
20720
+ if (result.status !== 0) throw new Error(result.stderr || result.stdout);
20721
+ throwOnGraphqlErrors(result.stdout);
20722
+ return result.stdout;
20739
20723
  }
20740
20724
 
20741
- // src/commands/github/issue/commentIssue.ts
20742
- var USAGE = "Usage: assist github issue comment <number> --body <body> [-R <owner>/<repo>]";
20743
- async function commentIssue(numberArg, options2) {
20744
- const number = Number.parseInt(numberArg, 10);
20745
- if (!Number.isInteger(number) || number <= 0 || !options2.body) {
20746
- console.error(USAGE);
20747
- process.exit(1);
20748
- }
20749
- const { body } = options2;
20750
- const target = options2.repo ? `${options2.repo}#${number}` : `issue #${number}`;
20751
- validateProposedContent(
20752
- { subject: "Comment", context: "GitHub issues" },
20753
- "",
20754
- body
20755
- );
20756
- await reviewProposedIssueComment(`Comment on ${target}`, body);
20757
- const args = ["issue", "comment", String(number), "--body", body];
20758
- if (options2.repo) args.push("--repo", options2.repo);
20759
- try {
20760
- execFileSync6("gh", args, { stdio: "inherit" });
20761
- } catch {
20762
- process.exit(1);
20763
- }
20764
- console.log(`Comment posted to ${target}`);
20725
+ // src/commands/github/issue/fixStructure/removeIssueLabels.ts
20726
+ var MUTATION = `mutation($labelableId: ID!, $labelIds: [ID!]!) {
20727
+ removeLabelsFromLabelable(input: { labelableId: $labelableId, labelIds: $labelIds }) {
20728
+ labelable { __typename }
20729
+ }
20730
+ }`;
20731
+ function removeIssueLabels(issueId, labelIds) {
20732
+ runGhGraphqlJson(MUTATION, { labelableId: issueId, labelIds });
20765
20733
  }
20766
20734
 
20767
- // src/commands/github/issue/createIssue.ts
20768
- import { execFileSync as execFileSync7 } from "child_process";
20769
-
20770
- // src/commands/github/issue/reviewProposedIssue.ts
20771
- import { randomUUID as randomUUID8 } from "crypto";
20772
- async function reviewProposedIssue(title, body) {
20773
- const sessionId = process.env.ASSIST_SESSION_ID;
20774
- if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
20775
- await awaitPreviewApproval("GitHub issue preview", {
20776
- sessionId,
20777
- requestId: randomUUID8(),
20778
- title,
20779
- body,
20780
- prNumber: null,
20781
- kind: "github-issue"
20782
- });
20735
+ // src/commands/github/issue/fixStructure/updateIssueType.ts
20736
+ var MUTATION2 = `mutation($issueId: ID!, $issueTypeId: ID!) {
20737
+ updateIssueIssueType(input: { issueId: $issueId, issueTypeId: $issueTypeId }) {
20738
+ issue { id }
20739
+ }
20740
+ }`;
20741
+ function updateIssueType(issueId, issueTypeId) {
20742
+ runGhGraphqlJson(MUTATION2, { issueId, issueTypeId });
20783
20743
  }
20784
20744
 
20785
- // src/commands/github/issue/createIssue.ts
20786
- var USAGE2 = "Usage: assist github issue create --title <title> --body <body> [-R <owner>/<repo>]";
20787
- async function createIssue(options2) {
20788
- if (!options2.title || !options2.body) {
20789
- console.error(USAGE2);
20790
- process.exit(1);
20791
- }
20792
- const { title, body } = options2;
20793
- validateProposedContent(
20794
- { subject: "Issue", context: "GitHub issues" },
20795
- title,
20796
- body
20797
- );
20798
- await reviewProposedIssue(title, body);
20799
- const args = ["issue", "create", "--title", title, "--body", body];
20800
- if (options2.repo) args.push("--repo", options2.repo);
20745
+ // src/commands/github/issue/fixStructure/writeLineNow.ts
20746
+ import { writeSync as writeSync2 } from "fs";
20747
+ function writeLineNow(line) {
20748
+ const text18 = `${line}
20749
+ `;
20801
20750
  try {
20802
- execFileSync7("gh", args, { stdio: "inherit" });
20751
+ writeSync2(1, text18);
20803
20752
  } catch {
20804
- process.exit(1);
20753
+ process.stdout.write(text18);
20805
20754
  }
20806
20755
  }
20807
20756
 
20808
- // src/commands/sessions/shared/inWebSession.ts
20809
- function inWebSession() {
20810
- return process.env.ASSIST_SESSION === "1" && !!process.env.ASSIST_SESSION_ID;
20811
- }
20812
-
20813
- // src/commands/github/issue/fetchIssue.ts
20814
- import { execFileSync as execFileSync8 } from "child_process";
20815
- function fetchIssue2(number, repo) {
20816
- const args = [
20817
- "issue",
20818
- "view",
20819
- String(number),
20820
- "--json",
20821
- "title,body,updatedAt,url"
20822
- ];
20823
- if (repo) args.push("--repo", repo);
20824
- let raw;
20825
- try {
20826
- raw = execFileSync8("gh", args, { encoding: "utf8" });
20827
- } catch {
20828
- console.error(`Could not fetch issue #${number} with gh issue view`);
20829
- process.exit(1);
20830
- }
20831
- try {
20832
- return JSON.parse(raw);
20833
- } catch {
20834
- console.error(`Could not parse the gh issue view output for #${number}`);
20835
- process.exit(1);
20757
+ // src/commands/github/issue/fixStructure/applyFixStructurePlan.ts
20758
+ function applyFixStructurePlan(plan2) {
20759
+ for (const entry of plan2.entries) {
20760
+ const where = chalk162.cyan(`${entry.issue.repo}#${entry.issue.number}`);
20761
+ const { typeChange, labelRemovals } = entry;
20762
+ if (typeChange) {
20763
+ writeLineNow(
20764
+ `${where} type ${typeChange.from ?? "no type"} -> ${typeChange.to}`
20765
+ );
20766
+ updateIssueType(entry.issue.id, typeChange.typeId);
20767
+ }
20768
+ if (labelRemovals.length > 0) {
20769
+ writeLineNow(
20770
+ `${where} removing ${labelRemovals.map((label2) => label2.name).join(", ")}`
20771
+ );
20772
+ removeIssueLabels(
20773
+ entry.issue.id,
20774
+ labelRemovals.map((label2) => label2.id)
20775
+ );
20776
+ }
20836
20777
  }
20837
20778
  }
20838
20779
 
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
- }
20780
+ // src/commands/github/issue/fixStructure/assertNothingTooDeep.ts
20781
+ function describe2(entry, leaf) {
20782
+ const parent = entry.parent;
20783
+ const under = parent ? ` under ${parent.repo}#${parent.number}` : "";
20784
+ return `${entry.issue.repo}#${entry.issue.number}${under} sits below ${leaf}, the leaf level`;
20865
20785
  }
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
20786
+ function assertNothingTooDeep(tooDeep, chain2) {
20787
+ if (tooDeep.length === 0) return;
20788
+ const leaf = chain2[chain2.length - 1] ?? "the leaf";
20789
+ throw new Error(
20790
+ [
20791
+ ...tooDeep.map((entry) => describe2(entry, leaf)),
20792
+ "Re-parent those issues or aim the run at a deeper target"
20793
+ ].join("\n")
20873
20794
  );
20874
20795
  }
20875
20796
 
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
- `
20797
+ // src/commands/github/issue/fixStructure/assertNoResidualDrift.ts
20798
+ function describe3(entry) {
20799
+ const where = `${entry.issue.repo}#${entry.issue.number}`;
20800
+ const notes = [];
20801
+ if (entry.typeChange) {
20802
+ notes.push(
20803
+ `${where} is still ${entry.typeChange.from ?? "untyped"}, not ${entry.typeChange.to}`
20804
+ );
20805
+ }
20806
+ for (const label2 of entry.labelRemovals) {
20807
+ notes.push(`${where} still carries ${label2.name}`);
20808
+ }
20809
+ return notes;
20810
+ }
20811
+ function assertNoResidualDrift(plan2, chain2) {
20812
+ assertNothingTooDeep(plan2.tooDeep, chain2);
20813
+ const residual = plan2.entries.flatMap(describe3);
20814
+ if (residual.length === 0) return;
20815
+ throw new Error(
20816
+ ["The subtree still drifts after applying:", ...residual].join("\n")
20886
20817
  );
20887
- return bodyPath;
20888
20818
  }
20889
20819
 
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
- }
20820
+ // src/commands/github/issue/fixStructure/issueFieldsFragment.ts
20821
+ var issueFieldsFragment = `fragment issueFields on Issue {
20822
+ id
20823
+ number
20824
+ title
20825
+ issueType { name }
20826
+ repository { nameWithOwner }
20827
+ labels(first: 100) { nodes { id name } pageInfo { hasNextPage } }
20828
+ subIssues(first: 100) { nodes { id } pageInfo { hasNextPage } }
20829
+ }`;
20915
20830
 
20916
- // src/commands/github/issue/pushIssueBody.ts
20917
- import { execFileSync as execFileSync9 } from "child_process";
20918
- function pushIssueBody(number, repo, bodyPath) {
20919
- const args = ["issue", "edit", String(number), "--body-file", bodyPath];
20920
- if (repo) args.push("--repo", repo);
20921
- try {
20922
- execFileSync9("gh", args, { stdio: "inherit" });
20923
- } catch {
20924
- process.exit(1);
20831
+ // src/commands/github/issue/fixStructure/parseIssueNode.ts
20832
+ function parseIssueNode(node) {
20833
+ const raw = node;
20834
+ const repo = raw.repository?.nameWithOwner ?? "";
20835
+ const where = `${repo}#${raw.number}`;
20836
+ if (raw.labels?.pageInfo?.hasNextPage) {
20837
+ throw new Error(
20838
+ `${where} carries more than 100 labels, which is not supported`
20839
+ );
20925
20840
  }
20926
- }
20927
-
20928
- // src/commands/github/issue/pushUnchangedIssue.ts
20929
- function pushUnchangedIssue(number, repo, target, fetchedAt, bodyPath) {
20930
- if (fetchIssue2(number, repo).updatedAt !== fetchedAt) {
20931
- console.error(
20932
- `${target} was updated on GitHub after it was fetched. Nothing was pushed; the markdown is at ${bodyPath}`
20841
+ if (raw.subIssues?.pageInfo?.hasNextPage) {
20842
+ throw new Error(
20843
+ `${where} has more than 100 sub-issues, which is not supported`
20933
20844
  );
20934
- process.exit(1);
20935
20845
  }
20936
- pushIssueBody(number, repo, bodyPath);
20937
- console.log(`Issue body updated on ${target}`);
20938
- }
20939
-
20940
- // src/commands/github/issue/reviewProposedIssueEdit.ts
20941
- import { randomUUID as randomUUID9 } from "crypto";
20942
- async function reviewProposedIssueEdit(title, body, working) {
20943
- const sessionId = process.env.ASSIST_SESSION_ID;
20944
- if (process.env.ASSIST_SESSION !== "1" || !sessionId) return body;
20945
- const decision = await awaitPreviewApproval(
20946
- "GitHub issue edit preview",
20947
- {
20948
- sessionId,
20949
- requestId: randomUUID9(),
20950
- title,
20951
- body,
20952
- prNumber: null,
20953
- kind: "github-issue-edit"
20954
- },
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
- }
20959
- );
20960
- return decision.body ?? body;
20846
+ return {
20847
+ id: raw.id,
20848
+ number: raw.number,
20849
+ title: raw.title,
20850
+ repo,
20851
+ typeName: raw.issueType?.name ?? null,
20852
+ labels: (raw.labels?.nodes ?? []).filter((label2) => label2 !== null),
20853
+ childIds: (raw.subIssues?.nodes ?? []).filter((child) => child !== null).map((child) => child.id)
20854
+ };
20961
20855
  }
20962
20856
 
20963
- // src/commands/github/issue/viewIssue.ts
20964
- import { execFileSync as execFileSync10 } from "child_process";
20965
- function viewIssue(number, repo) {
20966
- const args = ["issue", "view", String(number)];
20967
- if (repo) args.push("--repo", repo);
20968
- try {
20969
- execFileSync10("gh", args, { stdio: "inherit" });
20970
- } catch {
20971
- process.exit(1);
20972
- }
20857
+ // src/commands/github/issue/fixStructure/fetchRootIssue.ts
20858
+ var QUERY = `query($owner: String!, $repo: String!, $number: Int!) {
20859
+ repository(owner: $owner, name: $repo) {
20860
+ issue(number: $number) { ...issueFields }
20861
+ }
20973
20862
  }
20974
-
20975
- // src/commands/github/issue/editIssue.ts
20976
- var USAGE3 = "Usage: assist github issue edit <number> [-R <owner>/<repo>]";
20977
- async function editIssue(numberArg, options2) {
20978
- const number = Number.parseInt(numberArg, 10);
20979
- if (!Number.isInteger(number) || number <= 0) {
20980
- console.error(USAGE3);
20981
- process.exit(1);
20982
- }
20983
- if (!inWebSession()) {
20984
- viewIssue(number, options2.repo);
20985
- return;
20863
+ ${issueFieldsFragment}`;
20864
+ function fetchRootIssue(target) {
20865
+ const raw = runGhGraphqlJson(QUERY, {
20866
+ owner: target.owner,
20867
+ repo: target.repo,
20868
+ number: target.number
20869
+ });
20870
+ const issue = JSON.parse(raw).data?.repository?.issue;
20871
+ if (!issue) {
20872
+ throw new Error(
20873
+ `No issue ${target.owner}/${target.repo}#${target.number} could be read`
20874
+ );
20986
20875
  }
20987
- const issue = prepareIssueEdit(number, options2.repo, options2.fresh);
20988
- const edited = await reviewProposedIssueEdit(
20989
- `Edit ${issue.target}: ${issue.title}`,
20990
- issue.body,
20991
- { path: issue.bodyPath, save: issue.save }
20992
- );
20993
- validateIssueBody(issue.title, edited);
20994
- pushUnchangedIssue(
20995
- number,
20996
- options2.repo,
20997
- issue.target,
20998
- issue.updatedAt,
20999
- issue.bodyPath
21000
- );
20876
+ return parseIssueNode(issue);
21001
20877
  }
21002
20878
 
21003
20879
  // src/commands/github/issue/fixStructure/matchedLabels.ts
@@ -21095,127 +20971,110 @@ function buildFixStructurePlan(issues, options2) {
21095
20971
  };
21096
20972
  }
21097
20973
 
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;
20974
+ // src/commands/github/issue/fixStructure/fetchSubtreeIssues.ts
20975
+ var QUERY2 = `query($ids: [ID!]!) {
20976
+ nodes(ids: $ids) { ... on Issue { ...issueFields } }
21110
20977
  }
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
- );
20978
+ ${issueFieldsFragment}`;
20979
+ var BATCH = 50;
20980
+ function fetchSubtreeIssues(ids) {
20981
+ const issues = [];
20982
+ for (let start3 = 0; start3 < ids.length; start3 += BATCH) {
20983
+ const raw = runGhGraphqlJson(QUERY2, {
20984
+ ids: ids.slice(start3, start3 + BATCH)
20985
+ });
20986
+ const nodes = JSON.parse(raw).data?.nodes ?? [];
20987
+ for (const node of nodes) {
20988
+ if (node) issues.push(parseIssueNode(node));
20989
+ }
21132
20990
  }
21133
- if (raw.subIssues?.pageInfo?.hasNextPage) {
21134
- throw new Error(
21135
- `${where} has more than 100 sub-issues, which is not supported`
21136
- );
20991
+ return issues;
20992
+ }
20993
+
20994
+ // src/commands/github/issue/fixStructure/walkSubtree.ts
20995
+ function walkSubtree(root, maxDepth, fetchIssues = fetchSubtreeIssues) {
20996
+ const placed = [{ ...root, depth: 0, parentId: null }];
20997
+ const seen = /* @__PURE__ */ new Set([root.id]);
20998
+ let frontier = placed;
20999
+ for (let depth = 1; depth <= maxDepth && frontier.length > 0; depth += 1) {
21000
+ const parentOf2 = /* @__PURE__ */ new Map();
21001
+ for (const parent of frontier) {
21002
+ for (const childId of parent.childIds) {
21003
+ if (seen.has(childId)) continue;
21004
+ seen.add(childId);
21005
+ parentOf2.set(childId, parent.id);
21006
+ }
21007
+ }
21008
+ if (parentOf2.size === 0) break;
21009
+ const children = fetchIssues([...parentOf2.keys()]).map((issue) => ({
21010
+ ...issue,
21011
+ depth,
21012
+ parentId: parentOf2.get(issue.id) ?? null
21013
+ }));
21014
+ placed.push(...children);
21015
+ frontier = children;
21137
21016
  }
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
- };
21017
+ return placed;
21147
21018
  }
21148
21019
 
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
- }
21020
+ // src/commands/github/issue/fixStructure/planSubtree.ts
21021
+ function planSubtree(root, context) {
21022
+ const depth = context.chain.length - context.rootLevelIndex;
21023
+ return buildFixStructurePlan(walkSubtree(root, depth), context);
21154
21024
  }
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);
21025
+
21026
+ // src/commands/github/issue/fixStructure/applyAndVerifySubtree.ts
21027
+ function applyAndVerifySubtree(target, plan2, context) {
21028
+ if (plan2.typeChangeCount === 0 && plan2.labelRemovalCount === 0) return;
21029
+ applyFixStructurePlan(plan2);
21030
+ writeLineNow(chalk163.dim("Re-walking the subtree to confirm"));
21031
+ assertNoResidualDrift(
21032
+ planSubtree(fetchRootIssue(target), context),
21033
+ context.chain
21034
+ );
21035
+ writeLineNow(chalk163.green("Subtree normalised"));
21169
21036
  }
21170
21037
 
21171
21038
  // src/commands/github/issue/fixStructure/printFixStructurePlan.ts
21172
- import chalk162 from "chalk";
21039
+ import chalk164 from "chalk";
21173
21040
  function annotate(entry) {
21174
21041
  const notes = [];
21175
21042
  if (entry.level === null) {
21176
- notes.push(chalk162.red("deeper than the leaf level"));
21043
+ notes.push(chalk164.red("deeper than the leaf level"));
21177
21044
  } else if (entry.typeChange) {
21178
21045
  notes.push(
21179
- chalk162.yellow(
21046
+ chalk164.yellow(
21180
21047
  `${entry.typeChange.from ?? "no type"} -> ${entry.typeChange.to}`
21181
21048
  )
21182
21049
  );
21183
21050
  } else {
21184
- notes.push(chalk162.dim(entry.issue.typeName ?? "no type"));
21051
+ notes.push(chalk164.dim(entry.issue.typeName ?? "no type"));
21185
21052
  }
21186
21053
  for (const label2 of entry.labelRemovals) {
21187
- notes.push(chalk162.yellow(`-${label2.name}`));
21054
+ notes.push(chalk164.yellow(`-${label2.name}`));
21188
21055
  }
21189
21056
  return notes;
21190
21057
  }
21191
21058
  function formatCount(count8, noun) {
21192
21059
  return `${count8} ${noun}${count8 === 1 ? "" : "s"}`;
21193
21060
  }
21194
- function printFixStructurePlan(plan2, chain2) {
21195
- console.log(chalk162.dim(`chain: ${chain2.join(" > ")}`));
21061
+ function printFixStructurePlan(plan2, chain2, apply) {
21062
+ writeLineNow(chalk164.dim(`chain: ${chain2.join(" > ")}`));
21196
21063
  for (const entry of plan2.entries) {
21197
21064
  const indent3 = " ".repeat(entry.issue.depth);
21198
- const name = chalk162.cyan(`${entry.issue.repo}#${entry.issue.number}`);
21199
- console.log(
21065
+ const name = chalk164.cyan(`${entry.issue.repo}#${entry.issue.number}`);
21066
+ writeLineNow(
21200
21067
  `${indent3}${name} ${entry.issue.title} [${annotate(entry).join(", ")}]`
21201
21068
  );
21202
21069
  }
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
21070
  if (plan2.typeChangeCount === 0 && plan2.labelRemovalCount === 0) {
21212
- console.log(chalk162.green("Nothing to change"));
21071
+ writeLineNow(chalk164.green("Nothing to change"));
21213
21072
  return;
21214
21073
  }
21215
- console.log(
21074
+ writeLineNow(
21216
21075
  `${formatCount(plan2.typeChangeCount, "type change")}, ${formatCount(plan2.labelRemovalCount, "label removal")} planned`
21217
21076
  );
21218
- console.log(chalk162.dim("Dry run \u2014 nothing written"));
21077
+ if (!apply) writeLineNow(chalk164.dim("Dry run \u2014 nothing written"));
21219
21078
  }
21220
21079
 
21221
21080
  // src/commands/github/issue/fixStructure/resolveFixStructureTarget.ts
@@ -21251,7 +21110,7 @@ function resolveFixStructureTarget(target, repo) {
21251
21110
  }
21252
21111
 
21253
21112
  // src/commands/github/issue/fixStructure/resolveOrgIssueTypes.ts
21254
- var QUERY2 = `query($owner: String!) {
21113
+ var QUERY3 = `query($owner: String!) {
21255
21114
  organization(login: $owner) {
21256
21115
  issueTypes(first: 50) { nodes { id name } }
21257
21116
  }
@@ -21264,7 +21123,7 @@ function missingOrg(owner) {
21264
21123
  function resolveOrgIssueTypes(owner) {
21265
21124
  let raw;
21266
21125
  try {
21267
- raw = runGhGraphqlJson(QUERY2, { owner });
21126
+ raw = runGhGraphqlJson(QUERY3, { owner });
21268
21127
  } catch (error) {
21269
21128
  const message3 = error instanceof Error ? error.message : String(error);
21270
21129
  if (message3.includes("Could not resolve to an Organization")) {
@@ -21307,52 +21166,6 @@ function resolveRootLevelIndex(chain2, targetTypeName, level) {
21307
21166
  // src/commands/github/issue/fixStructure/types.ts
21308
21167
  var defaultTypeChain = ["Epic", "Story", "Subtask"];
21309
21168
 
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
21169
  // src/commands/github/issue/fixStructure/fixStructure.ts
21357
21170
  function fixStructure(target, options2) {
21358
21171
  const chain2 = defaultTypeChain;
@@ -21364,15 +21177,17 @@ function fixStructure(target, options2) {
21364
21177
  root.typeName,
21365
21178
  options2.level
21366
21179
  );
21367
- const issueTypes = resolveOrgIssueTypes(resolved.owner);
21368
- const issues = walkSubtree(root, chain2.length - index3);
21369
- const plan2 = buildFixStructurePlan(issues, {
21180
+ const context = {
21370
21181
  chain: chain2,
21371
21182
  rootLevelIndex: index3,
21372
21183
  rootAsserted: asserted,
21373
- issueTypes
21374
- });
21375
- printFixStructurePlan(plan2, chain2);
21184
+ issueTypes: resolveOrgIssueTypes(resolved.owner),
21185
+ stripLabels: []
21186
+ };
21187
+ const plan2 = planSubtree(root, context);
21188
+ printFixStructurePlan(plan2, chain2, options2.apply === true);
21189
+ assertNothingTooDeep(plan2.tooDeep, chain2);
21190
+ if (options2.apply) applyAndVerifySubtree(resolved, plan2, context);
21376
21191
  } catch (error) {
21377
21192
  console.error(error instanceof Error ? error.message : String(error));
21378
21193
  process.exit(1);
@@ -21383,19 +21198,20 @@ function fixStructure(target, options2) {
21383
21198
  var chain = defaultTypeChain.join(" > ");
21384
21199
  var levels = defaultTypeChain.map((name) => name.toLowerCase()).join("|");
21385
21200
  function registerFixStructure(issueCommand) {
21386
- issueCommand.command("fix-structure <target>").description("Report the issue type drift across one issue subtree").option(
21201
+ issueCommand.command("fix-structure <target>").description("Normalise the issue types across one issue subtree").option(
21387
21202
  "-R, --repo <owner/repo>",
21388
21203
  "Repository a bare issue number belongs to"
21389
21204
  ).option(
21390
21205
  "--level <level>",
21391
21206
  `The target's own position in the ${chain} chain, when it cannot be inferred from its type`
21392
- ).addHelpText(
21207
+ ).option("--apply", "Write the planned changes instead of reporting them").addHelpText(
21393
21208
  "after",
21394
21209
  `
21395
21210
  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
21211
  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
21212
  The target is owner/repo#number, a github.com issue URL, or a bare number with --repo.
21398
- This reports only; nothing is written.`
21213
+ Without --apply nothing is written. With --apply each write is announced before it is issued, and the subtree is re-walked afterwards so any residual drift fails the run.
21214
+ Anything nested below the leaf level fails the run before a single write, naming the offender and its parent.`
21399
21215
  ).action(fixStructure);
21400
21216
  }
21401
21217
 
@@ -21410,9 +21226,136 @@ async function readBodyArgument(value) {
21410
21226
  return body;
21411
21227
  }
21412
21228
 
21413
- // src/commands/registerGithubIssue.ts
21414
- function registerGithubIssue(githubCommand) {
21415
- const issueCommand = githubCommand.command("issue").description("GitHub issue utilities");
21229
+ // src/commands/github/issue/commentIssue.ts
21230
+ import { execFileSync as execFileSync6 } from "child_process";
21231
+
21232
+ // src/shared/validateProposedContent.ts
21233
+ function validateProposedContent(labels, title, body) {
21234
+ const { subject, context } = labels;
21235
+ if (title.toLowerCase().includes("claude")) {
21236
+ console.error(`Error: ${subject} title must not reference Claude`);
21237
+ process.exit(1);
21238
+ }
21239
+ if (body.toLowerCase().includes("claude")) {
21240
+ console.error(`Error: ${subject} body must not reference Claude`);
21241
+ process.exit(1);
21242
+ }
21243
+ const titleBacklogIds = findBacklogRefs(title);
21244
+ if (titleBacklogIds.length > 0) {
21245
+ console.error(
21246
+ backlogRefError(`${subject} title`, context, titleBacklogIds)
21247
+ );
21248
+ process.exit(1);
21249
+ }
21250
+ const bodyBacklogIds = findBacklogRefs(body);
21251
+ if (bodyBacklogIds.length > 0) {
21252
+ console.error(backlogRefError(`${subject} body`, context, bodyBacklogIds));
21253
+ process.exit(1);
21254
+ }
21255
+ }
21256
+
21257
+ // src/commands/github/issue/reviewProposedIssueComment.ts
21258
+ import { randomUUID as randomUUID7 } from "crypto";
21259
+ async function reviewProposedIssueComment(title, body) {
21260
+ const sessionId = process.env.ASSIST_SESSION_ID;
21261
+ if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
21262
+ await awaitPreviewApproval("GitHub issue comment preview", {
21263
+ sessionId,
21264
+ requestId: randomUUID7(),
21265
+ title,
21266
+ body,
21267
+ prNumber: null,
21268
+ kind: "github-issue-comment"
21269
+ });
21270
+ }
21271
+
21272
+ // src/commands/github/issue/commentIssue.ts
21273
+ var USAGE = "Usage: assist github issue comment <number> --body <body> [-R <owner>/<repo>]";
21274
+ async function commentIssue(numberArg, options2) {
21275
+ const number = Number.parseInt(numberArg, 10);
21276
+ if (!Number.isInteger(number) || number <= 0 || !options2.body) {
21277
+ console.error(USAGE);
21278
+ process.exit(1);
21279
+ }
21280
+ const { body } = options2;
21281
+ const target = options2.repo ? `${options2.repo}#${number}` : `issue #${number}`;
21282
+ validateProposedContent(
21283
+ { subject: "Comment", context: "GitHub issues" },
21284
+ "",
21285
+ body
21286
+ );
21287
+ await reviewProposedIssueComment(`Comment on ${target}`, body);
21288
+ const args = ["issue", "comment", String(number), "--body", body];
21289
+ if (options2.repo) args.push("--repo", options2.repo);
21290
+ try {
21291
+ execFileSync6("gh", args, { stdio: "inherit" });
21292
+ } catch {
21293
+ process.exit(1);
21294
+ }
21295
+ console.log(`Comment posted to ${target}`);
21296
+ }
21297
+
21298
+ // src/commands/github/issue/registerCommentIssue.ts
21299
+ function registerCommentIssue(issueCommand) {
21300
+ 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(
21301
+ "-R, --repo <owner/repo>",
21302
+ "Target repository (defaults to the current repo)"
21303
+ ).addHelpText(
21304
+ "after",
21305
+ "\nThe comment is outward-facing: write it for the repo's readers, not the team. It is rejected if it references Claude or an assist backlog item.\nIn an assist web session the body is previewed for approve/reject first (with inline comments); nothing is posted until it is approved."
21306
+ ).action(
21307
+ async (number, options2) => {
21308
+ await commentIssue(number, {
21309
+ ...options2,
21310
+ body: options2.body ? await readBodyArgument(options2.body) : void 0
21311
+ });
21312
+ }
21313
+ );
21314
+ }
21315
+
21316
+ // src/commands/github/issue/createIssue.ts
21317
+ import { execFileSync as execFileSync7 } from "child_process";
21318
+
21319
+ // src/commands/github/issue/reviewProposedIssue.ts
21320
+ import { randomUUID as randomUUID8 } from "crypto";
21321
+ async function reviewProposedIssue(title, body) {
21322
+ const sessionId = process.env.ASSIST_SESSION_ID;
21323
+ if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
21324
+ await awaitPreviewApproval("GitHub issue preview", {
21325
+ sessionId,
21326
+ requestId: randomUUID8(),
21327
+ title,
21328
+ body,
21329
+ prNumber: null,
21330
+ kind: "github-issue"
21331
+ });
21332
+ }
21333
+
21334
+ // src/commands/github/issue/createIssue.ts
21335
+ var USAGE2 = "Usage: assist github issue create --title <title> --body <body> [-R <owner>/<repo>]";
21336
+ async function createIssue(options2) {
21337
+ if (!options2.title || !options2.body) {
21338
+ console.error(USAGE2);
21339
+ process.exit(1);
21340
+ }
21341
+ const { title, body } = options2;
21342
+ validateProposedContent(
21343
+ { subject: "Issue", context: "GitHub issues" },
21344
+ title,
21345
+ body
21346
+ );
21347
+ await reviewProposedIssue(title, body);
21348
+ const args = ["issue", "create", "--title", title, "--body", body];
21349
+ if (options2.repo) args.push("--repo", options2.repo);
21350
+ try {
21351
+ execFileSync7("gh", args, { stdio: "inherit" });
21352
+ } catch {
21353
+ process.exit(1);
21354
+ }
21355
+ }
21356
+
21357
+ // src/commands/github/issue/registerCreateIssue.ts
21358
+ function registerCreateIssue(issueCommand) {
21416
21359
  issueCommand.command("create").description("Create a GitHub issue").option("--title <title>", "Issue title").option("--body <body>", "Issue body").option(
21417
21360
  "-R, --repo <owner/repo>",
21418
21361
  "Target repository (defaults to the current repo)"
@@ -21420,6 +21363,205 @@ function registerGithubIssue(githubCommand) {
21420
21363
  "after",
21421
21364
  "\nThere is no What/Why/How template: an issue reports a problem, and the target repo's own issue template is unknowable from here. Write the body as the repo's maintainers would expect.\nIn an assist web session the title and body are previewed for approve/reject first (with inline comments); nothing is created until it is approved."
21422
21365
  ).action(createIssue);
21366
+ }
21367
+
21368
+ // src/commands/sessions/shared/inWebSession.ts
21369
+ function inWebSession() {
21370
+ return process.env.ASSIST_SESSION === "1" && !!process.env.ASSIST_SESSION_ID;
21371
+ }
21372
+
21373
+ // src/commands/github/issue/fetchIssue.ts
21374
+ import { execFileSync as execFileSync8 } from "child_process";
21375
+ function fetchIssue2(number, repo) {
21376
+ const args = [
21377
+ "issue",
21378
+ "view",
21379
+ String(number),
21380
+ "--json",
21381
+ "title,body,updatedAt,url"
21382
+ ];
21383
+ if (repo) args.push("--repo", repo);
21384
+ let raw;
21385
+ try {
21386
+ raw = execFileSync8("gh", args, { encoding: "utf8" });
21387
+ } catch {
21388
+ console.error(`Could not fetch issue #${number} with gh issue view`);
21389
+ process.exit(1);
21390
+ }
21391
+ try {
21392
+ return JSON.parse(raw);
21393
+ } catch {
21394
+ console.error(`Could not parse the gh issue view output for #${number}`);
21395
+ process.exit(1);
21396
+ }
21397
+ }
21398
+
21399
+ // src/commands/github/issue/resumeIssueBody.ts
21400
+ import { existsSync as existsSync48, readFileSync as readFileSync37 } from "fs";
21401
+
21402
+ // src/commands/github/issue/issueWorkingFile.ts
21403
+ import { join as join50 } from "path";
21404
+ function issueWorkingFile(slug, number) {
21405
+ const [owner = "unknown", repo = "unknown"] = slug.split("/");
21406
+ const dir = join50(getStoreDir(), "github-issues", owner, repo);
21407
+ return {
21408
+ dir,
21409
+ bodyPath: join50(dir, `${number}.md`),
21410
+ metaPath: join50(dir, `${number}.json`)
21411
+ };
21412
+ }
21413
+
21414
+ // src/commands/github/issue/resumeIssueBody.ts
21415
+ function resumeIssueBody(slug, number, updatedAt) {
21416
+ const { bodyPath, metaPath } = issueWorkingFile(slug, number);
21417
+ if (!existsSync48(bodyPath) || !existsSync48(metaPath)) return void 0;
21418
+ try {
21419
+ const meta = JSON.parse(readFileSync37(metaPath, "utf8"));
21420
+ if (meta.updatedAt !== updatedAt) return void 0;
21421
+ return readFileSync37(bodyPath, "utf8");
21422
+ } catch {
21423
+ return void 0;
21424
+ }
21425
+ }
21426
+
21427
+ // src/commands/github/issue/validateIssueBody.ts
21428
+ function validateIssueBody(title, body) {
21429
+ validateProposedContent(
21430
+ { subject: "Issue", context: "GitHub issues" },
21431
+ title,
21432
+ body
21433
+ );
21434
+ }
21435
+
21436
+ // src/commands/github/issue/writeIssueWorkingFile.ts
21437
+ import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync31 } from "fs";
21438
+ function writeIssueWorkingFile(slug, number, target, updatedAt, body) {
21439
+ const { dir, bodyPath, metaPath } = issueWorkingFile(slug, number);
21440
+ mkdirSync16(dir, { recursive: true });
21441
+ writeFileSync31(bodyPath, body);
21442
+ writeFileSync31(
21443
+ metaPath,
21444
+ `${JSON.stringify({ target, updatedAt }, null, 2)}
21445
+ `
21446
+ );
21447
+ return bodyPath;
21448
+ }
21449
+
21450
+ // src/commands/github/issue/prepareIssueEdit.ts
21451
+ function slugFromUrl(url) {
21452
+ const match = /github\.com\/([^/]+\/[^/]+)\//.exec(url ?? "");
21453
+ return match ? match[1] : "unknown/unknown";
21454
+ }
21455
+ function prepareIssueEdit(number, repo, fresh) {
21456
+ const issue = fetchIssue2(number, repo);
21457
+ const slug = repo ?? slugFromUrl(issue.url);
21458
+ const target = `${slug}#${number}`;
21459
+ const resumed = fresh ? void 0 : resumeIssueBody(slug, number, issue.updatedAt);
21460
+ const body = resumed ?? issue.body;
21461
+ validateIssueBody(issue.title, body);
21462
+ const save = (markdown) => writeIssueWorkingFile(slug, number, target, issue.updatedAt, markdown);
21463
+ const bodyPath = save(body);
21464
+ if (resumed !== void 0)
21465
+ console.log(`Previewing the in-progress markdown from ${bodyPath}`);
21466
+ return {
21467
+ title: issue.title,
21468
+ target,
21469
+ updatedAt: issue.updatedAt,
21470
+ body,
21471
+ bodyPath,
21472
+ save
21473
+ };
21474
+ }
21475
+
21476
+ // src/commands/github/issue/pushIssueBody.ts
21477
+ import { execFileSync as execFileSync9 } from "child_process";
21478
+ function pushIssueBody(number, repo, bodyPath) {
21479
+ const args = ["issue", "edit", String(number), "--body-file", bodyPath];
21480
+ if (repo) args.push("--repo", repo);
21481
+ try {
21482
+ execFileSync9("gh", args, { stdio: "inherit" });
21483
+ } catch {
21484
+ process.exit(1);
21485
+ }
21486
+ }
21487
+
21488
+ // src/commands/github/issue/pushUnchangedIssue.ts
21489
+ function pushUnchangedIssue(number, repo, target, fetchedAt, bodyPath) {
21490
+ if (fetchIssue2(number, repo).updatedAt !== fetchedAt) {
21491
+ console.error(
21492
+ `${target} was updated on GitHub after it was fetched. Nothing was pushed; the markdown is at ${bodyPath}`
21493
+ );
21494
+ process.exit(1);
21495
+ }
21496
+ pushIssueBody(number, repo, bodyPath);
21497
+ console.log(`Issue body updated on ${target}`);
21498
+ }
21499
+
21500
+ // src/commands/github/issue/reviewProposedIssueEdit.ts
21501
+ import { randomUUID as randomUUID9 } from "crypto";
21502
+ async function reviewProposedIssueEdit(title, body, working) {
21503
+ const sessionId = process.env.ASSIST_SESSION_ID;
21504
+ if (process.env.ASSIST_SESSION !== "1" || !sessionId) return body;
21505
+ const decision = await awaitPreviewApproval(
21506
+ "GitHub issue edit preview",
21507
+ {
21508
+ sessionId,
21509
+ requestId: randomUUID9(),
21510
+ title,
21511
+ body,
21512
+ prNumber: null,
21513
+ kind: "github-issue-edit"
21514
+ },
21515
+ {
21516
+ saveEditedBody: working.save,
21517
+ 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.`
21518
+ }
21519
+ );
21520
+ return decision.body ?? body;
21521
+ }
21522
+
21523
+ // src/commands/github/issue/viewIssue.ts
21524
+ import { execFileSync as execFileSync10 } from "child_process";
21525
+ function viewIssue(number, repo) {
21526
+ const args = ["issue", "view", String(number)];
21527
+ if (repo) args.push("--repo", repo);
21528
+ try {
21529
+ execFileSync10("gh", args, { stdio: "inherit" });
21530
+ } catch {
21531
+ process.exit(1);
21532
+ }
21533
+ }
21534
+
21535
+ // src/commands/github/issue/editIssue.ts
21536
+ var USAGE3 = "Usage: assist github issue edit <number> [-R <owner>/<repo>]";
21537
+ async function editIssue(numberArg, options2) {
21538
+ const number = Number.parseInt(numberArg, 10);
21539
+ if (!Number.isInteger(number) || number <= 0) {
21540
+ console.error(USAGE3);
21541
+ process.exit(1);
21542
+ }
21543
+ if (!inWebSession()) {
21544
+ viewIssue(number, options2.repo);
21545
+ return;
21546
+ }
21547
+ const issue = prepareIssueEdit(number, options2.repo, options2.fresh);
21548
+ const edited = await reviewProposedIssueEdit(
21549
+ `Edit ${issue.target}: ${issue.title}`,
21550
+ issue.body,
21551
+ { path: issue.bodyPath, save: issue.save }
21552
+ );
21553
+ validateIssueBody(issue.title, edited);
21554
+ pushUnchangedIssue(
21555
+ number,
21556
+ options2.repo,
21557
+ issue.target,
21558
+ issue.updatedAt,
21559
+ issue.bodyPath
21560
+ );
21561
+ }
21562
+
21563
+ // src/commands/github/issue/registerEditIssue.ts
21564
+ function registerEditIssue(issueCommand) {
21423
21565
  issueCommand.command("edit <number>").description("Edit an existing GitHub issue's body in the preview pane").option(
21424
21566
  "-R, --repo <owner/repo>",
21425
21567
  "Target repository (defaults to the current repo)"
@@ -21430,20 +21572,14 @@ function registerGithubIssue(githubCommand) {
21430
21572
  "after",
21431
21573
  "\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."
21432
21574
  ).action(editIssue);
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(
21434
- "-R, --repo <owner/repo>",
21435
- "Target repository (defaults to the current repo)"
21436
- ).addHelpText(
21437
- "after",
21438
- "\nThe comment is outward-facing: write it for the repo's readers, not the team. It is rejected if it references Claude or an assist backlog item.\nIn an assist web session the body is previewed for approve/reject first (with inline comments); nothing is posted until it is approved."
21439
- ).action(
21440
- async (number, options2) => {
21441
- await commentIssue(number, {
21442
- ...options2,
21443
- body: options2.body ? await readBodyArgument(options2.body) : void 0
21444
- });
21445
- }
21446
- );
21575
+ }
21576
+
21577
+ // src/commands/registerGithubIssue.ts
21578
+ function registerGithubIssue(githubCommand) {
21579
+ const issueCommand = githubCommand.command("issue").description("GitHub issue utilities");
21580
+ registerCreateIssue(issueCommand);
21581
+ registerEditIssue(issueCommand);
21582
+ registerCommentIssue(issueCommand);
21447
21583
  registerFixStructure(issueCommand);
21448
21584
  }
21449
21585
 
@@ -21684,7 +21820,7 @@ function registerHandover(program2) {
21684
21820
  }
21685
21821
 
21686
21822
  // src/commands/jira/acceptanceCriteria.ts
21687
- import chalk163 from "chalk";
21823
+ import chalk165 from "chalk";
21688
21824
 
21689
21825
  // src/commands/jira/adfToText.ts
21690
21826
  function renderInline(node) {
@@ -21751,7 +21887,7 @@ function acceptanceCriteria(issueKey) {
21751
21887
  const parsed = fetchIssue(issueKey, field);
21752
21888
  const acValue = parsed?.fields?.[field];
21753
21889
  if (!acValue) {
21754
- console.log(chalk163.yellow(`No acceptance criteria found on ${issueKey}.`));
21890
+ console.log(chalk165.yellow(`No acceptance criteria found on ${issueKey}.`));
21755
21891
  return;
21756
21892
  }
21757
21893
  if (typeof acValue === "string") {
@@ -21817,14 +21953,14 @@ async function jiraAuth() {
21817
21953
  }
21818
21954
 
21819
21955
  // src/commands/jira/viewIssue.ts
21820
- import chalk164 from "chalk";
21956
+ import chalk166 from "chalk";
21821
21957
  function viewIssue2(issueKey) {
21822
21958
  const parsed = fetchIssue(issueKey, "summary,description");
21823
21959
  const fields = parsed?.fields;
21824
21960
  const summary = fields?.summary;
21825
21961
  const description = fields?.description;
21826
21962
  if (summary) {
21827
- console.log(chalk164.bold(summary));
21963
+ console.log(chalk166.bold(summary));
21828
21964
  }
21829
21965
  if (description) {
21830
21966
  if (summary) console.log();
@@ -21838,7 +21974,7 @@ function viewIssue2(issueKey) {
21838
21974
  }
21839
21975
  if (!summary && !description) {
21840
21976
  console.log(
21841
- chalk164.yellow(`No summary or description found on ${issueKey}.`)
21977
+ chalk166.yellow(`No summary or description found on ${issueKey}.`)
21842
21978
  );
21843
21979
  }
21844
21980
  }
@@ -21873,7 +22009,7 @@ import { randomUUID as randomUUID10 } from "crypto";
21873
22009
 
21874
22010
  // src/commands/review/checkoutPr.ts
21875
22011
  import { execFileSync as execFileSync12 } from "child_process";
21876
- import chalk165 from "chalk";
22012
+ import chalk167 from "chalk";
21877
22013
 
21878
22014
  // src/commands/sessions/daemon/daemonLog.ts
21879
22015
  var RING_CAPACITY = 1e3;
@@ -22485,7 +22621,7 @@ async function checkoutPr(number) {
22485
22621
  try {
22486
22622
  execFileSync12("gh", ["pr", "checkout", number], { stdio: "inherit" });
22487
22623
  } catch {
22488
- console.error(chalk165.red(`gh pr checkout ${number} failed; aborting.`));
22624
+ console.error(chalk167.red(`gh pr checkout ${number} failed; aborting.`));
22489
22625
  process.exit(1);
22490
22626
  }
22491
22627
  }
@@ -22622,15 +22758,15 @@ function registerList(program2) {
22622
22758
  // src/commands/mermaid/index.ts
22623
22759
  import { mkdirSync as mkdirSync18, readdirSync as readdirSync11 } from "fs";
22624
22760
  import { resolve as resolve16 } from "path";
22625
- import chalk168 from "chalk";
22761
+ import chalk170 from "chalk";
22626
22762
 
22627
22763
  // src/commands/mermaid/exportFile.ts
22628
22764
  import { readFileSync as readFileSync39, writeFileSync as writeFileSync32 } from "fs";
22629
22765
  import { basename as basename17, extname as extname2, resolve as resolve15 } from "path";
22630
- import chalk167 from "chalk";
22766
+ import chalk169 from "chalk";
22631
22767
 
22632
22768
  // src/commands/mermaid/renderBlock.ts
22633
- import chalk166 from "chalk";
22769
+ import chalk168 from "chalk";
22634
22770
  async function renderBlock(krokiUrl, source) {
22635
22771
  const response = await fetch(`${krokiUrl}/mermaid/svg`, {
22636
22772
  method: "POST",
@@ -22639,7 +22775,7 @@ async function renderBlock(krokiUrl, source) {
22639
22775
  });
22640
22776
  if (!response.ok) {
22641
22777
  console.error(
22642
- chalk166.red(
22778
+ chalk168.red(
22643
22779
  `Kroki request failed: ${response.status} ${response.statusText}`
22644
22780
  )
22645
22781
  );
@@ -22657,19 +22793,19 @@ async function exportFile(file, outDir, krokiUrl, onlyIndex) {
22657
22793
  if (onlyIndex !== void 0) {
22658
22794
  if (onlyIndex < 1 || onlyIndex > blocks.length) {
22659
22795
  console.error(
22660
- chalk167.red(
22796
+ chalk169.red(
22661
22797
  `${file}: --index ${onlyIndex} out of range (file has ${blocks.length} diagram(s))`
22662
22798
  )
22663
22799
  );
22664
22800
  process.exit(1);
22665
22801
  }
22666
22802
  console.log(
22667
- chalk167.gray(
22803
+ chalk169.gray(
22668
22804
  `${file} \u2014 rendering diagram ${onlyIndex} of ${blocks.length}`
22669
22805
  )
22670
22806
  );
22671
22807
  } else {
22672
- console.log(chalk167.gray(`${file} \u2014 ${blocks.length} diagram(s)`));
22808
+ console.log(chalk169.gray(`${file} \u2014 ${blocks.length} diagram(s)`));
22673
22809
  }
22674
22810
  for (const [i, source] of blocks.entries()) {
22675
22811
  const idx = i + 1;
@@ -22677,7 +22813,7 @@ async function exportFile(file, outDir, krokiUrl, onlyIndex) {
22677
22813
  const outPath = resolve15(outDir, `${stem}-${idx}.svg`);
22678
22814
  const svg = await renderBlock(krokiUrl, source);
22679
22815
  writeFileSync32(outPath, svg, "utf8");
22680
- console.log(chalk167.green(` \u2192 ${outPath}`));
22816
+ console.log(chalk169.green(` \u2192 ${outPath}`));
22681
22817
  }
22682
22818
  }
22683
22819
  function extractMermaidBlocks(markdown) {
@@ -22693,18 +22829,18 @@ async function mermaidExport(file, options2 = {}) {
22693
22829
  if (options2.index !== void 0) {
22694
22830
  if (!Number.isInteger(options2.index) || options2.index < 1) {
22695
22831
  console.error(
22696
- chalk168.red(`--index must be a positive integer (got ${options2.index})`)
22832
+ chalk170.red(`--index must be a positive integer (got ${options2.index})`)
22697
22833
  );
22698
22834
  process.exit(1);
22699
22835
  }
22700
22836
  if (!file) {
22701
- console.error(chalk168.red("--index requires a file argument"));
22837
+ console.error(chalk170.red("--index requires a file argument"));
22702
22838
  process.exit(1);
22703
22839
  }
22704
22840
  }
22705
22841
  const files = file ? [file] : readdirSync11(process.cwd()).filter((name) => name.toLowerCase().endsWith(".md")).sort();
22706
22842
  if (files.length === 0) {
22707
- console.log(chalk168.gray("No markdown files found in current directory."));
22843
+ console.log(chalk170.gray("No markdown files found in current directory."));
22708
22844
  return;
22709
22845
  }
22710
22846
  for (const f of files) {
@@ -22727,11 +22863,191 @@ function registerMermaid(program2) {
22727
22863
  configHelp(cmd, mermaidConfigHelp);
22728
22864
  }
22729
22865
 
22866
+ // src/commands/miro/runExtract.ts
22867
+ import { stringify } from "yaml";
22868
+
22869
+ // src/commands/miro/MiroExtractError.ts
22870
+ var MiroExtractError = class extends Error {
22871
+ constructor(message3) {
22872
+ super(message3);
22873
+ this.name = "MiroExtractError";
22874
+ }
22875
+ };
22876
+
22877
+ // src/commands/miro/stripHtml.ts
22878
+ var namedEntities = {
22879
+ amp: "&",
22880
+ apos: "'",
22881
+ gt: ">",
22882
+ lt: "<",
22883
+ nbsp: " ",
22884
+ quot: '"'
22885
+ };
22886
+ function decodeEntity(_match, entity) {
22887
+ if (entity.startsWith("#")) {
22888
+ const code = entity.startsWith("#x") || entity.startsWith("#X") ? Number.parseInt(entity.slice(2), 16) : Number.parseInt(entity.slice(1), 10);
22889
+ return Number.isNaN(code) ? _match : String.fromCodePoint(code);
22890
+ }
22891
+ return namedEntities[entity.toLowerCase()] ?? _match;
22892
+ }
22893
+ function stripHtml2(content) {
22894
+ 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();
22895
+ }
22896
+
22897
+ // src/commands/miro/normaliseItems.ts
22898
+ var frameCoordinates = "parent_top_left";
22899
+ function describe4(item) {
22900
+ return ` ${item.id ?? "(no id)"} (${item.type ?? "unknown type"}): relativeTo=${item.position?.relativeTo ?? "missing"}`;
22901
+ }
22902
+ function coordinateSpaceError(rejected) {
22903
+ return new MiroExtractError(
22904
+ `${rejected.length} item(s) are not in frame coordinates (position.relativeTo must be "${frameCoordinates}"):
22905
+ ${rejected.slice(0, 5).map(describe4).join(
22906
+ "\n"
22907
+ )}
22908
+
22909
+ Dump the frame with board_list_items using ?moveToWidget=<frame id> so every item shares one coordinate space.`
22910
+ );
22911
+ }
22912
+ function toItem(item) {
22913
+ const halfWidth = (item.geometry?.width ?? 0) / 2;
22914
+ const halfHeight = (item.geometry?.height ?? 0) / 2;
22915
+ const x = item.position?.x ?? 0;
22916
+ const y = item.position?.y ?? 0;
22917
+ return {
22918
+ id: item.id ?? "",
22919
+ type: item.type ?? "",
22920
+ text: stripHtml2(item.data?.content ?? ""),
22921
+ left: x - halfWidth,
22922
+ top: y - halfHeight,
22923
+ right: x + halfWidth,
22924
+ bottom: y + halfHeight
22925
+ };
22926
+ }
22927
+ function normaliseItems(items2) {
22928
+ const rejected = items2.filter(
22929
+ (item) => item.position?.relativeTo !== frameCoordinates
22930
+ );
22931
+ if (rejected.length > 0) throw coordinateSpaceError(rejected);
22932
+ return items2.map(toItem);
22933
+ }
22934
+
22935
+ // src/commands/miro/parseAnchorId.ts
22936
+ function parseAnchorId(value) {
22937
+ const trimmed = value.trim();
22938
+ const link3 = /[?&]moveToWidget=([^&#]+)/.exec(trimmed);
22939
+ return link3 ? decodeURIComponent(link3[1]).trim() : trimmed;
22940
+ }
22941
+
22942
+ // src/commands/miro/readMiroItems.ts
22943
+ import { readFileSync as readFileSync40 } from "fs";
22944
+ function tryParse(text18) {
22945
+ try {
22946
+ return JSON.parse(text18);
22947
+ } catch {
22948
+ return void 0;
22949
+ }
22950
+ }
22951
+ function toPage(value) {
22952
+ const record = value ?? {};
22953
+ if (Array.isArray(record.data)) return { data: record.data };
22954
+ return record.id ? { data: [record] } : {};
22955
+ }
22956
+ function parseJsonLines(raw, file) {
22957
+ return raw.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => {
22958
+ const parsed = tryParse(line);
22959
+ if (parsed === void 0)
22960
+ throw new MiroExtractError(
22961
+ `${file} is not valid JSON or JSON lines. Save the raw board_list_items response pages without editing them.`
22962
+ );
22963
+ return toPage(parsed);
22964
+ });
22965
+ }
22966
+ function parsePages(raw, file) {
22967
+ const parsed = tryParse(raw);
22968
+ if (parsed === void 0) return parseJsonLines(raw, file);
22969
+ return Array.isArray(parsed) ? parsed.map(toPage) : [toPage(parsed)];
22970
+ }
22971
+ function readMiroItems(file) {
22972
+ const items2 = parsePages(readFileSync40(file, "utf8"), file).flatMap(
22973
+ (page) => page.data ?? []
22974
+ );
22975
+ if (items2.length === 0)
22976
+ throw new MiroExtractError(
22977
+ `No board items found in ${file}. Dump the frame with board_list_items, paging until has_more is false.`
22978
+ );
22979
+ return items2;
22980
+ }
22981
+
22982
+ // src/commands/miro/selectBoxes.ts
22983
+ var boxTypes = /* @__PURE__ */ new Set(["shape", "sticky_note"]);
22984
+ function findAnchor(items2, id) {
22985
+ const anchor = items2.find((item) => item.id === id);
22986
+ if (!anchor)
22987
+ throw new MiroExtractError(
22988
+ `No item with id ${id} in the supplied items. Re-dump the frame so the anchor is included, then try again.`
22989
+ );
22990
+ return anchor;
22991
+ }
22992
+ function isBox(item) {
22993
+ return boxTypes.has(item.type) && item.text.length > 0;
22994
+ }
22995
+ function centreInside(rect, item) {
22996
+ const x = (item.left + item.right) / 2;
22997
+ const y = (item.top + item.bottom) / 2;
22998
+ return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
22999
+ }
23000
+ function selectBoxes(items2, topLeftId, bottomRightId) {
23001
+ const topLeft = findAnchor(items2, topLeftId);
23002
+ const bottomRight = findAnchor(items2, bottomRightId);
23003
+ const rect = {
23004
+ left: topLeft.left,
23005
+ top: topLeft.top,
23006
+ right: bottomRight.right,
23007
+ bottom: bottomRight.bottom
23008
+ };
23009
+ return items2.filter((item) => isBox(item) && centreInside(rect, item)).sort((a, b) => a.left - b.left || a.top - b.top);
23010
+ }
23011
+
23012
+ // src/commands/miro/runExtract.ts
23013
+ function requireItems(file) {
23014
+ if (!file)
23015
+ throw new MiroExtractError(
23016
+ "--items <file> is required: a file of raw board_list_items response pages."
23017
+ );
23018
+ return file;
23019
+ }
23020
+ function requireAnchors(options2) {
23021
+ if (!options2.topLeft || !options2.bottomRight)
23022
+ throw new MiroExtractError(
23023
+ "Both --top-left <id|link> and --bottom-right <id|link> are required."
23024
+ );
23025
+ return [parseAnchorId(options2.topLeft), parseAnchorId(options2.bottomRight)];
23026
+ }
23027
+ function runExtract(options2) {
23028
+ const [topLeft, bottomRight] = requireAnchors(options2);
23029
+ const items2 = normaliseItems(readMiroItems(requireItems(options2.items)));
23030
+ const boxes = selectBoxes(items2, topLeft, bottomRight);
23031
+ process.stdout.write(stringify(boxes.map((box) => box.text)));
23032
+ }
23033
+
23034
+ // src/commands/miro/registerMiro.ts
23035
+ function registerMiro(program2) {
23036
+ const miroCommand = program2.command("miro").description("Miro board utilities");
23037
+ 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(
23038
+ "--top-left <id>",
23039
+ "Widget id or ?moveToWidget=<id> link of the top-left box"
23040
+ ).option(
23041
+ "--bottom-right <id>",
23042
+ "Widget id or ?moveToWidget=<id> link of the bottom-right box"
23043
+ ).action(runExtract);
23044
+ }
23045
+
22730
23046
  // src/commands/netcap/netcap.ts
22731
23047
  import { mkdir as mkdir4 } from "fs/promises";
22732
23048
  import { createServer as createServer2 } from "http";
22733
23049
  import { dirname as dirname28 } from "path";
22734
- import chalk170 from "chalk";
23050
+ import chalk172 from "chalk";
22735
23051
 
22736
23052
  // src/commands/netcap/corsHeaders.ts
22737
23053
  var corsHeaders = {
@@ -22810,7 +23126,7 @@ function createNetcapHandler(options2) {
22810
23126
  import { cp, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
22811
23127
  import { networkInterfaces } from "os";
22812
23128
  import { join as join58 } from "path";
22813
- import chalk169 from "chalk";
23129
+ import chalk171 from "chalk";
22814
23130
 
22815
23131
  // src/commands/netcap/netcapExtensionDir.ts
22816
23132
  import { dirname as dirname27, join as join57 } from "path";
@@ -22854,7 +23170,7 @@ async function prepareExtensionForLoad(port, filter = "") {
22854
23170
  const host = lanIPv4();
22855
23171
  if (!host) {
22856
23172
  console.log(
22857
- chalk169.yellow("could not determine the WSL IP for the extension")
23173
+ chalk171.yellow("could not determine the WSL IP for the extension")
22858
23174
  );
22859
23175
  await configureBackground(source, "127.0.0.1", port, filter);
22860
23176
  return source;
@@ -22865,7 +23181,7 @@ async function prepareExtensionForLoad(port, filter = "") {
22865
23181
  return WSL_WINDOWS_PATH;
22866
23182
  } catch {
22867
23183
  console.log(
22868
- chalk169.yellow(`could not copy extension to ${WSL_WINDOWS_PATH}`)
23184
+ chalk171.yellow(`could not copy extension to ${WSL_WINDOWS_PATH}`)
22869
23185
  );
22870
23186
  return source;
22871
23187
  }
@@ -22898,30 +23214,30 @@ async function netcap(options2) {
22898
23214
  let count8 = 0;
22899
23215
  const handler = createNetcapHandler({
22900
23216
  outPath,
22901
- onPing: () => console.log(chalk170.dim("ping from extension")),
23217
+ onPing: () => console.log(chalk172.dim("ping from extension")),
22902
23218
  onCapture: (entry) => {
22903
23219
  count8 += 1;
22904
23220
  console.log(
22905
- chalk170.green(`captured #${count8}`),
22906
- chalk170.dim(`${entry.method ?? "?"} ${entry.url ?? "?"}`)
23221
+ chalk172.green(`captured #${count8}`),
23222
+ chalk172.dim(`${entry.method ?? "?"} ${entry.url ?? "?"}`)
22907
23223
  );
22908
23224
  }
22909
23225
  });
22910
23226
  const server = createServer2(handler);
22911
23227
  server.listen(port, () => {
22912
23228
  console.log(
22913
- chalk170.bold(`netcap receiver listening on http://127.0.0.1:${port}`)
23229
+ chalk172.bold(`netcap receiver listening on http://127.0.0.1:${port}`)
22914
23230
  );
22915
- console.log(chalk170.dim(`appending captures to ${outPath}`));
23231
+ console.log(chalk172.dim(`appending captures to ${outPath}`));
22916
23232
  if (filter)
22917
- console.log(chalk170.dim(`forwarding only URLs matching "${filter}"`));
22918
- console.log(chalk170.dim(`load the unpacked extension from ${extensionPath}`));
22919
- console.log(chalk170.dim("press Ctrl-C to stop"));
23233
+ console.log(chalk172.dim(`forwarding only URLs matching "${filter}"`));
23234
+ console.log(chalk172.dim(`load the unpacked extension from ${extensionPath}`));
23235
+ console.log(chalk172.dim("press Ctrl-C to stop"));
22920
23236
  });
22921
23237
  process.on("SIGINT", () => {
22922
23238
  server.close();
22923
23239
  console.log(
22924
- chalk170.bold(
23240
+ chalk172.bold(
22925
23241
  `
22926
23242
  netcap stopped \u2014 captured ${count8} ${count8 === 1 ? "entry" : "entries"} to ${outPath}`
22927
23243
  )
@@ -22933,10 +23249,10 @@ netcap stopped \u2014 captured ${count8} ${count8 === 1 ? "entry" : "entries"} t
22933
23249
  // src/commands/netcap/netcapExtract.ts
22934
23250
  import { writeFileSync as writeFileSync33 } from "fs";
22935
23251
  import { join as join61 } from "path";
22936
- import chalk171 from "chalk";
23252
+ import chalk173 from "chalk";
22937
23253
 
22938
23254
  // src/commands/netcap/extractPostsFromCapture.ts
22939
- import { readFileSync as readFileSync40 } from "fs";
23255
+ import { readFileSync as readFileSync41 } from "fs";
22940
23256
 
22941
23257
  // src/commands/netcap/parseRscRows.ts
22942
23258
  var isRscRef = (v) => typeof v === "string" && /^\$[0-9a-fL@]/.test(v);
@@ -23332,7 +23648,7 @@ function extractVoyagerPosts(body) {
23332
23648
 
23333
23649
  // src/commands/netcap/extractPostsFromCapture.ts
23334
23650
  function captureEntries(captureFile) {
23335
- const lines2 = readFileSync40(captureFile, "utf8").split("\n").filter(Boolean);
23651
+ const lines2 = readFileSync41(captureFile, "utf8").split("\n").filter(Boolean);
23336
23652
  const entries = [];
23337
23653
  for (const line of lines2) {
23338
23654
  let entry;
@@ -23381,8 +23697,8 @@ function netcapExtract(file) {
23381
23697
  writeFileSync33(outFile, `${JSON.stringify(posts, null, 2)}
23382
23698
  `);
23383
23699
  console.log(
23384
- chalk171.green(`extracted ${posts.length} posts`),
23385
- chalk171.dim(`-> ${outFile}`)
23700
+ chalk173.green(`extracted ${posts.length} posts`),
23701
+ chalk173.dim(`-> ${outFile}`)
23386
23702
  );
23387
23703
  }
23388
23704
 
@@ -23403,7 +23719,7 @@ function registerNetcap(program2) {
23403
23719
  }
23404
23720
 
23405
23721
  // src/commands/news/add/index.ts
23406
- import chalk172 from "chalk";
23722
+ import chalk174 from "chalk";
23407
23723
  import enquirer8 from "enquirer";
23408
23724
  async function add2(url) {
23409
23725
  if (!url) {
@@ -23425,10 +23741,10 @@ async function add2(url) {
23425
23741
  const { orm } = await getReady();
23426
23742
  const added = await addFeed(orm, url);
23427
23743
  if (!added) {
23428
- console.log(chalk172.yellow("Feed already exists"));
23744
+ console.log(chalk174.yellow("Feed already exists"));
23429
23745
  return;
23430
23746
  }
23431
- console.log(chalk172.green(`Added feed: ${url}`));
23747
+ console.log(chalk174.green(`Added feed: ${url}`));
23432
23748
  }
23433
23749
 
23434
23750
  // src/commands/registerNews.ts
@@ -23475,7 +23791,7 @@ function registerPiHook(program2) {
23475
23791
  }
23476
23792
 
23477
23793
  // src/commands/prompts/printPromptsTable.ts
23478
- import chalk173 from "chalk";
23794
+ import chalk175 from "chalk";
23479
23795
  function truncate(str, max) {
23480
23796
  if (str.length <= max) return str;
23481
23797
  return `${str.slice(0, max - 1)}\u2026`;
@@ -23493,14 +23809,14 @@ function printPromptsTable(rows) {
23493
23809
  "Command".padEnd(commandWidth),
23494
23810
  "Repos"
23495
23811
  ].join(" ");
23496
- console.log(chalk173.dim(header));
23497
- console.log(chalk173.dim("-".repeat(header.length)));
23812
+ console.log(chalk175.dim(header));
23813
+ console.log(chalk175.dim("-".repeat(header.length)));
23498
23814
  for (const row of rows) {
23499
23815
  const count8 = String(row.count).padStart(countWidth);
23500
23816
  const tool = row.tool.padEnd(toolWidth);
23501
23817
  const command = truncate(row.command, 60).padEnd(commandWidth);
23502
23818
  console.log(
23503
- `${chalk173.yellow(count8)} ${tool} ${command} ${chalk173.dim(row.repos)}`
23819
+ `${chalk175.yellow(count8)} ${tool} ${command} ${chalk175.dim(row.repos)}`
23504
23820
  );
23505
23821
  }
23506
23822
  }
@@ -23906,7 +24222,7 @@ import { tmpdir as tmpdir6 } from "os";
23906
24222
  import { join as join63 } from "path";
23907
24223
 
23908
24224
  // src/commands/prs/loadCommentsCache.ts
23909
- import { existsSync as existsSync54, readFileSync as readFileSync41, unlinkSync as unlinkSync13 } from "fs";
24225
+ import { existsSync as existsSync54, readFileSync as readFileSync42, unlinkSync as unlinkSync13 } from "fs";
23910
24226
  import { parse as parse2 } from "yaml";
23911
24227
 
23912
24228
  // src/commands/prs/commentsCachePath.ts
@@ -23929,7 +24245,7 @@ function loadCommentsCache(org, repo, prNumber) {
23929
24245
  if (!existsSync54(cachePath)) {
23930
24246
  return null;
23931
24247
  }
23932
- const content = readFileSync41(cachePath, "utf8");
24248
+ const content = readFileSync42(cachePath, "utf8");
23933
24249
  return parse2(content);
23934
24250
  }
23935
24251
  function deleteCommentsCache(org, repo, prNumber) {
@@ -24121,7 +24437,7 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
24121
24437
  // src/commands/prs/listComments/updateCommentsCache.ts
24122
24438
  import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync36 } from "fs";
24123
24439
  import { dirname as dirname29 } from "path";
24124
- import { stringify } from "yaml";
24440
+ import { stringify as stringify2 } from "yaml";
24125
24441
 
24126
24442
  // src/commands/prs/removeStaleCommentsCaches.ts
24127
24443
  import { readdirSync as readdirSync12, unlinkSync as unlinkSync16 } from "fs";
@@ -24149,7 +24465,7 @@ function writeCommentsCache(org, repo, prNumber, comments3) {
24149
24465
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
24150
24466
  comments: comments3
24151
24467
  };
24152
- writeFileSync36(cachePath, stringify(cacheData));
24468
+ writeFileSync36(cachePath, stringify2(cacheData));
24153
24469
  }
24154
24470
  function updateCommentsCache(org, repo, prNumber, comments3) {
24155
24471
  removeStaleCommentsCaches();
@@ -24167,13 +24483,13 @@ function agentFooter(unresolvedCount) {
24167
24483
  }
24168
24484
 
24169
24485
  // src/commands/prs/listComments/commentStyle.ts
24170
- import chalk174 from "chalk";
24486
+ import chalk176 from "chalk";
24171
24487
  var plain = (text18) => text18;
24172
24488
  function colouredState(state) {
24173
24489
  const label2 = `[${state}]`;
24174
- if (state === "APPROVED") return chalk174.green(label2);
24175
- if (state === "CHANGES_REQUESTED") return chalk174.red(label2);
24176
- return chalk174.yellow(label2);
24490
+ if (state === "APPROVED") return chalk176.green(label2);
24491
+ if (state === "CHANGES_REQUESTED") return chalk176.red(label2);
24492
+ return chalk176.yellow(label2);
24177
24493
  }
24178
24494
  function commentStyle() {
24179
24495
  if (isClaudeCode()) {
@@ -24187,9 +24503,9 @@ function commentStyle() {
24187
24503
  };
24188
24504
  }
24189
24505
  return {
24190
- cyan: chalk174.cyan,
24191
- bold: chalk174.bold,
24192
- dim: chalk174.dim,
24506
+ cyan: chalk176.cyan,
24507
+ bold: chalk176.bold,
24508
+ dim: chalk176.dim,
24193
24509
  state: colouredState,
24194
24510
  diffHunk: true,
24195
24511
  agent: false
@@ -24359,13 +24675,13 @@ import { execSync as execSync48 } from "child_process";
24359
24675
  import enquirer9 from "enquirer";
24360
24676
 
24361
24677
  // src/commands/prs/prs/displayPaginated/printPr.ts
24362
- import chalk175 from "chalk";
24678
+ import chalk177 from "chalk";
24363
24679
  var STATUS_MAP = {
24364
- MERGED: (pr) => pr.mergedAt ? { label: chalk175.magenta("merged"), date: pr.mergedAt } : null,
24365
- CLOSED: (pr) => pr.closedAt ? { label: chalk175.red("closed"), date: pr.closedAt } : null
24680
+ MERGED: (pr) => pr.mergedAt ? { label: chalk177.magenta("merged"), date: pr.mergedAt } : null,
24681
+ CLOSED: (pr) => pr.closedAt ? { label: chalk177.red("closed"), date: pr.closedAt } : null
24366
24682
  };
24367
24683
  function defaultStatus(pr) {
24368
- return { label: chalk175.green("opened"), date: pr.createdAt };
24684
+ return { label: chalk177.green("opened"), date: pr.createdAt };
24369
24685
  }
24370
24686
  function getStatus2(pr) {
24371
24687
  return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
@@ -24374,11 +24690,11 @@ function formatDate(dateStr) {
24374
24690
  return new Date(dateStr).toISOString().split("T")[0];
24375
24691
  }
24376
24692
  function formatPrHeader(pr, status3) {
24377
- return `${chalk175.cyan(`#${pr.number}`)} ${pr.title} ${chalk175.dim(`(${pr.author.login},`)} ${status3.label} ${chalk175.dim(`${formatDate(status3.date)})`)}`;
24693
+ return `${chalk177.cyan(`#${pr.number}`)} ${pr.title} ${chalk177.dim(`(${pr.author.login},`)} ${status3.label} ${chalk177.dim(`${formatDate(status3.date)})`)}`;
24378
24694
  }
24379
24695
  function logPrDetails(pr) {
24380
24696
  console.log(
24381
- chalk175.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
24697
+ chalk177.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
24382
24698
  );
24383
24699
  console.log();
24384
24700
  }
@@ -25093,10 +25409,10 @@ function registerPrs(program2) {
25093
25409
  }
25094
25410
 
25095
25411
  // src/commands/ravendb/ravendbAuth.ts
25096
- import chalk181 from "chalk";
25412
+ import chalk183 from "chalk";
25097
25413
 
25098
25414
  // src/shared/createConnectionAuth.ts
25099
- import chalk176 from "chalk";
25415
+ import chalk178 from "chalk";
25100
25416
  function listConnections(connections, format) {
25101
25417
  if (connections.length === 0) {
25102
25418
  console.log("No connections configured.");
@@ -25109,7 +25425,7 @@ function listConnections(connections, format) {
25109
25425
  function removeConnection(connections, name, save) {
25110
25426
  const filtered = connections.filter((c) => c.name !== name);
25111
25427
  if (filtered.length === connections.length) {
25112
- console.error(chalk176.red(`Connection "${name}" not found.`));
25428
+ console.error(chalk178.red(`Connection "${name}" not found.`));
25113
25429
  process.exit(1);
25114
25430
  }
25115
25431
  save(filtered);
@@ -25155,15 +25471,15 @@ function saveConnections(connections) {
25155
25471
  }
25156
25472
 
25157
25473
  // src/commands/ravendb/promptConnection.ts
25158
- import chalk179 from "chalk";
25474
+ import chalk181 from "chalk";
25159
25475
 
25160
25476
  // src/commands/ravendb/selectOpSecret.ts
25161
- import chalk178 from "chalk";
25477
+ import chalk180 from "chalk";
25162
25478
  import Enquirer2 from "enquirer";
25163
25479
 
25164
25480
  // src/commands/ravendb/searchItems.ts
25165
25481
  import { execSync as execSync51 } from "child_process";
25166
- import chalk177 from "chalk";
25482
+ import chalk179 from "chalk";
25167
25483
  function opExec(args) {
25168
25484
  return execSync51(`op ${args}`, {
25169
25485
  encoding: "utf8",
@@ -25176,7 +25492,7 @@ function searchItems(search2) {
25176
25492
  items2 = JSON.parse(opExec("item list --format=json"));
25177
25493
  } catch {
25178
25494
  console.error(
25179
- chalk177.red(
25495
+ chalk179.red(
25180
25496
  "Failed to search 1Password. Ensure the CLI is installed and you are signed in."
25181
25497
  )
25182
25498
  );
@@ -25190,7 +25506,7 @@ function getItemFields(itemId2) {
25190
25506
  const item = JSON.parse(opExec(`item get "${itemId2}" --format=json`));
25191
25507
  return item.fields.filter((f) => f.reference && f.label);
25192
25508
  } catch {
25193
- console.error(chalk177.red("Failed to get item details from 1Password."));
25509
+ console.error(chalk179.red("Failed to get item details from 1Password."));
25194
25510
  process.exit(1);
25195
25511
  }
25196
25512
  }
@@ -25209,7 +25525,7 @@ async function selectOpSecret(searchTerm) {
25209
25525
  }).run();
25210
25526
  const items2 = searchItems(search2);
25211
25527
  if (items2.length === 0) {
25212
- console.error(chalk178.red(`No items found matching "${search2}".`));
25528
+ console.error(chalk180.red(`No items found matching "${search2}".`));
25213
25529
  process.exit(1);
25214
25530
  }
25215
25531
  const itemId2 = await selectOne(
@@ -25218,7 +25534,7 @@ async function selectOpSecret(searchTerm) {
25218
25534
  );
25219
25535
  const fields = getItemFields(itemId2);
25220
25536
  if (fields.length === 0) {
25221
- console.error(chalk178.red("No fields with references found on this item."));
25537
+ console.error(chalk180.red("No fields with references found on this item."));
25222
25538
  process.exit(1);
25223
25539
  }
25224
25540
  const ref = await selectOne(
@@ -25232,7 +25548,7 @@ async function selectOpSecret(searchTerm) {
25232
25548
  async function promptConnection(existingNames) {
25233
25549
  const name = await promptInput("name", "Connection name:");
25234
25550
  if (existingNames.includes(name)) {
25235
- console.error(chalk179.red(`Connection "${name}" already exists.`));
25551
+ console.error(chalk181.red(`Connection "${name}" already exists.`));
25236
25552
  process.exit(1);
25237
25553
  }
25238
25554
  const url = await promptInput(
@@ -25241,22 +25557,22 @@ async function promptConnection(existingNames) {
25241
25557
  );
25242
25558
  const database = await promptInput("database", "Database name:");
25243
25559
  if (!name || !url || !database) {
25244
- console.error(chalk179.red("All fields are required."));
25560
+ console.error(chalk181.red("All fields are required."));
25245
25561
  process.exit(1);
25246
25562
  }
25247
25563
  const apiKeyRef = await selectOpSecret();
25248
- console.log(chalk179.dim(`Using: ${apiKeyRef}`));
25564
+ console.log(chalk181.dim(`Using: ${apiKeyRef}`));
25249
25565
  return { name, url, database, apiKeyRef };
25250
25566
  }
25251
25567
 
25252
25568
  // src/commands/ravendb/ravendbSetConnection.ts
25253
- import chalk180 from "chalk";
25569
+ import chalk182 from "chalk";
25254
25570
  function ravendbSetConnection(name) {
25255
25571
  const raw = loadGlobalConfigRaw();
25256
25572
  const ravendb = raw.ravendb ?? {};
25257
25573
  const connections = ravendb.connections ?? [];
25258
25574
  if (!connections.some((c) => c.name === name)) {
25259
- console.error(chalk180.red(`Connection "${name}" not found.`));
25575
+ console.error(chalk182.red(`Connection "${name}" not found.`));
25260
25576
  console.error(
25261
25577
  `Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
25262
25578
  );
@@ -25272,16 +25588,16 @@ function ravendbSetConnection(name) {
25272
25588
  var ravendbAuth = createConnectionAuth({
25273
25589
  load: loadConnections,
25274
25590
  save: saveConnections,
25275
- format: (c) => `${chalk181.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
25591
+ format: (c) => `${chalk183.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
25276
25592
  promptNew: promptConnection,
25277
25593
  onFirst: (c) => ravendbSetConnection(c.name)
25278
25594
  });
25279
25595
 
25280
25596
  // src/commands/ravendb/ravendbCollections.ts
25281
- import chalk185 from "chalk";
25597
+ import chalk187 from "chalk";
25282
25598
 
25283
25599
  // src/commands/ravendb/ravenFetch.ts
25284
- import chalk183 from "chalk";
25600
+ import chalk185 from "chalk";
25285
25601
 
25286
25602
  // src/commands/ravendb/getAccessToken.ts
25287
25603
  var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
@@ -25318,10 +25634,10 @@ ${errorText}`
25318
25634
 
25319
25635
  // src/commands/ravendb/resolveOpSecret.ts
25320
25636
  import { execSync as execSync52 } from "child_process";
25321
- import chalk182 from "chalk";
25637
+ import chalk184 from "chalk";
25322
25638
  function resolveOpSecret(reference) {
25323
25639
  if (!reference.startsWith("op://")) {
25324
- console.error(chalk182.red(`Invalid secret reference: must start with op://`));
25640
+ console.error(chalk184.red(`Invalid secret reference: must start with op://`));
25325
25641
  process.exit(1);
25326
25642
  }
25327
25643
  try {
@@ -25331,7 +25647,7 @@ function resolveOpSecret(reference) {
25331
25647
  }).trim();
25332
25648
  } catch {
25333
25649
  console.error(
25334
- chalk182.red(
25650
+ chalk184.red(
25335
25651
  "Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
25336
25652
  )
25337
25653
  );
@@ -25358,7 +25674,7 @@ async function ravenFetch(connection, path80) {
25358
25674
  if (!response.ok) {
25359
25675
  const body = await response.text();
25360
25676
  console.error(
25361
- chalk183.red(`RavenDB error: ${response.status} ${response.statusText}`)
25677
+ chalk185.red(`RavenDB error: ${response.status} ${response.statusText}`)
25362
25678
  );
25363
25679
  console.error(body.substring(0, 500));
25364
25680
  process.exit(1);
@@ -25367,7 +25683,7 @@ async function ravenFetch(connection, path80) {
25367
25683
  }
25368
25684
 
25369
25685
  // src/commands/ravendb/resolveConnection.ts
25370
- import chalk184 from "chalk";
25686
+ import chalk186 from "chalk";
25371
25687
  function loadRavendb() {
25372
25688
  const raw = loadGlobalConfigRaw();
25373
25689
  const ravendb = raw.ravendb;
@@ -25381,7 +25697,7 @@ function resolveConnection(name) {
25381
25697
  const connectionName = name ?? defaultConnection;
25382
25698
  if (!connectionName) {
25383
25699
  console.error(
25384
- chalk184.red(
25700
+ chalk186.red(
25385
25701
  "No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
25386
25702
  )
25387
25703
  );
@@ -25389,7 +25705,7 @@ function resolveConnection(name) {
25389
25705
  }
25390
25706
  const connection = connections.find((c) => c.name === connectionName);
25391
25707
  if (!connection) {
25392
- console.error(chalk184.red(`Connection "${connectionName}" not found.`));
25708
+ console.error(chalk186.red(`Connection "${connectionName}" not found.`));
25393
25709
  console.error(
25394
25710
  `Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
25395
25711
  );
@@ -25420,15 +25736,15 @@ async function ravendbCollections(connectionName) {
25420
25736
  return;
25421
25737
  }
25422
25738
  for (const c of collections) {
25423
- console.log(`${chalk185.bold(c.Name)} ${c.CountOfDocuments} docs`);
25739
+ console.log(`${chalk187.bold(c.Name)} ${c.CountOfDocuments} docs`);
25424
25740
  }
25425
25741
  }
25426
25742
 
25427
25743
  // src/commands/ravendb/ravendbQuery.ts
25428
- import chalk187 from "chalk";
25744
+ import chalk189 from "chalk";
25429
25745
 
25430
25746
  // src/commands/ravendb/fetchAllPages.ts
25431
- import chalk186 from "chalk";
25747
+ import chalk188 from "chalk";
25432
25748
 
25433
25749
  // src/commands/ravendb/buildQueryPath.ts
25434
25750
  function buildQueryPath(opts) {
@@ -25466,7 +25782,7 @@ async function fetchAllPages(connection, opts) {
25466
25782
  allResults.push(...results);
25467
25783
  start3 += results.length;
25468
25784
  process.stderr.write(
25469
- `\r${chalk186.dim(`Fetched ${allResults.length}/${totalResults}`)}`
25785
+ `\r${chalk188.dim(`Fetched ${allResults.length}/${totalResults}`)}`
25470
25786
  );
25471
25787
  if (start3 >= totalResults) break;
25472
25788
  if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
@@ -25481,7 +25797,7 @@ async function fetchAllPages(connection, opts) {
25481
25797
  async function ravendbQuery(connectionName, collection, options2) {
25482
25798
  const resolved = resolveArgs(connectionName, collection);
25483
25799
  if (!resolved.collection && !options2.query) {
25484
- console.error(chalk187.red("Provide a collection name or --query filter."));
25800
+ console.error(chalk189.red("Provide a collection name or --query filter."));
25485
25801
  process.exit(1);
25486
25802
  }
25487
25803
  const { collection: col } = resolved;
@@ -25520,7 +25836,7 @@ import { spawn as spawn6 } from "child_process";
25520
25836
  import * as path42 from "path";
25521
25837
 
25522
25838
  // src/commands/refactor/logViolations.ts
25523
- import chalk188 from "chalk";
25839
+ import chalk190 from "chalk";
25524
25840
  var DEFAULT_MAX_LINES2 = 100;
25525
25841
  function logViolations(violations, maxLines = DEFAULT_MAX_LINES2) {
25526
25842
  if (violations.length === 0) {
@@ -25529,43 +25845,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES2) {
25529
25845
  }
25530
25846
  return;
25531
25847
  }
25532
- console.error(chalk188.red(`
25848
+ console.error(chalk190.red(`
25533
25849
  Refactor check failed:
25534
25850
  `));
25535
- console.error(chalk188.red(` The following files exceed ${maxLines} lines:
25851
+ console.error(chalk190.red(` The following files exceed ${maxLines} lines:
25536
25852
  `));
25537
25853
  for (const violation of violations) {
25538
- console.error(chalk188.red(` ${violation.file} (${violation.lines} lines)`));
25854
+ console.error(chalk190.red(` ${violation.file} (${violation.lines} lines)`));
25539
25855
  }
25540
25856
  console.error(
25541
- chalk188.yellow(
25857
+ chalk190.yellow(
25542
25858
  `
25543
25859
  Each file needs to be sensibly refactored, or if there is no sensible
25544
25860
  way to refactor it, ignore it with:
25545
25861
  `
25546
25862
  )
25547
25863
  );
25548
- console.error(chalk188.gray(` assist refactor ignore <file>
25864
+ console.error(chalk190.gray(` assist refactor ignore <file>
25549
25865
  `));
25550
25866
  if (process.env.CLAUDECODE) {
25551
- console.error(chalk188.cyan(`
25867
+ console.error(chalk190.cyan(`
25552
25868
  ## Extracting Code to New Files
25553
25869
  `));
25554
25870
  console.error(
25555
- chalk188.cyan(
25871
+ chalk190.cyan(
25556
25872
  ` When extracting logic from one file to another, consider where the extracted code belongs:
25557
25873
  `
25558
25874
  )
25559
25875
  );
25560
25876
  console.error(
25561
- chalk188.cyan(
25877
+ chalk190.cyan(
25562
25878
  ` 1. Keep related logic together: If the extracted code is tightly coupled to the
25563
25879
  original file's domain, create a new folder containing both the original and extracted files.
25564
25880
  `
25565
25881
  )
25566
25882
  );
25567
25883
  console.error(
25568
- chalk188.cyan(
25884
+ chalk190.cyan(
25569
25885
  ` 2. Share common utilities: If the extracted code can be reused across multiple
25570
25886
  domains, move it to a common/shared folder.
25571
25887
  `
@@ -25721,7 +26037,7 @@ async function check(pattern2, options2) {
25721
26037
 
25722
26038
  // src/commands/refactor/extract/index.ts
25723
26039
  import path50 from "path";
25724
- import chalk191 from "chalk";
26040
+ import chalk193 from "chalk";
25725
26041
 
25726
26042
  // src/commands/refactor/extract/applyExtraction.ts
25727
26043
  import { SyntaxKind as SyntaxKind4 } from "ts-morph";
@@ -26320,23 +26636,23 @@ function buildPlan2(functionName, sourceFile, sourcePath, destPath, project) {
26320
26636
 
26321
26637
  // src/commands/refactor/extract/displayPlan.ts
26322
26638
  import path46 from "path";
26323
- import chalk189 from "chalk";
26639
+ import chalk191 from "chalk";
26324
26640
  function section2(title) {
26325
26641
  return `
26326
- ${chalk189.cyan(title)}`;
26642
+ ${chalk191.cyan(title)}`;
26327
26643
  }
26328
26644
  function displayImporters(plan2, cwd) {
26329
26645
  if (plan2.importersToUpdate.length === 0) return;
26330
26646
  console.log(section2("Update importers:"));
26331
26647
  for (const imp of plan2.importersToUpdate) {
26332
26648
  const rel = path46.relative(cwd, imp.file.getFilePath());
26333
- console.log(` ${chalk189.dim(rel)}: \u2192 import from "${imp.relPath}"`);
26649
+ console.log(` ${chalk191.dim(rel)}: \u2192 import from "${imp.relPath}"`);
26334
26650
  }
26335
26651
  }
26336
26652
  function displayPlan(functionName, relDest, plan2, cwd) {
26337
- console.log(chalk189.bold(`Extract: ${functionName} \u2192 ${relDest}
26653
+ console.log(chalk191.bold(`Extract: ${functionName} \u2192 ${relDest}
26338
26654
  `));
26339
- console.log(` ${chalk189.cyan("Functions to move:")}`);
26655
+ console.log(` ${chalk191.cyan("Functions to move:")}`);
26340
26656
  for (const name of plan2.extractedNames) {
26341
26657
  console.log(` ${name}`);
26342
26658
  }
@@ -26370,7 +26686,7 @@ function displayPlan(functionName, relDest, plan2, cwd) {
26370
26686
 
26371
26687
  // src/commands/refactor/extract/loadProjectFile.ts
26372
26688
  import path49 from "path";
26373
- import chalk190 from "chalk";
26689
+ import chalk192 from "chalk";
26374
26690
  import { Project as Project4 } from "ts-morph";
26375
26691
 
26376
26692
  // src/commands/refactor/extract/findTsConfig.ts
@@ -26462,7 +26778,7 @@ function loadProjectFile(file) {
26462
26778
  });
26463
26779
  const sourceFile = project.getSourceFile(sourcePath);
26464
26780
  if (!sourceFile) {
26465
- console.log(chalk190.red(`File not found in project: ${file}`));
26781
+ console.log(chalk192.red(`File not found in project: ${file}`));
26466
26782
  process.exit(1);
26467
26783
  }
26468
26784
  return { project, sourceFile };
@@ -26485,19 +26801,19 @@ async function extract(file, functionName, destination, options2 = {}) {
26485
26801
  displayPlan(functionName, relDest, plan2, cwd);
26486
26802
  if (options2.apply) {
26487
26803
  await applyExtraction(functionName, sourceFile, destPath, plan2, project);
26488
- console.log(chalk191.green("\nExtraction complete"));
26804
+ console.log(chalk193.green("\nExtraction complete"));
26489
26805
  } else {
26490
- console.log(chalk191.dim("\nDry run. Use --apply to execute."));
26806
+ console.log(chalk193.dim("\nDry run. Use --apply to execute."));
26491
26807
  }
26492
26808
  }
26493
26809
 
26494
26810
  // src/commands/refactor/ignore.ts
26495
26811
  import fs33 from "fs";
26496
- import chalk192 from "chalk";
26812
+ import chalk194 from "chalk";
26497
26813
  var REFACTOR_YML_PATH2 = "refactor.yml";
26498
26814
  function ignore2(file) {
26499
26815
  if (!fs33.existsSync(file)) {
26500
- console.error(chalk192.red(`Error: File does not exist: ${file}`));
26816
+ console.error(chalk194.red(`Error: File does not exist: ${file}`));
26501
26817
  process.exit(1);
26502
26818
  }
26503
26819
  const content = fs33.readFileSync(file, "utf8");
@@ -26513,7 +26829,7 @@ function ignore2(file) {
26513
26829
  fs33.writeFileSync(REFACTOR_YML_PATH2, entry);
26514
26830
  }
26515
26831
  console.log(
26516
- chalk192.green(
26832
+ chalk194.green(
26517
26833
  `Added ${file} to refactor ignore list (max ${maxLines} lines)`
26518
26834
  )
26519
26835
  );
@@ -26522,12 +26838,12 @@ function ignore2(file) {
26522
26838
  // src/commands/refactor/rename/index.ts
26523
26839
  import fs36 from "fs";
26524
26840
  import path55 from "path";
26525
- import chalk195 from "chalk";
26841
+ import chalk197 from "chalk";
26526
26842
 
26527
26843
  // src/commands/refactor/rename/applyRename.ts
26528
26844
  import fs35 from "fs";
26529
26845
  import path52 from "path";
26530
- import chalk193 from "chalk";
26846
+ import chalk195 from "chalk";
26531
26847
 
26532
26848
  // src/commands/refactor/restructure/computeRewrites/index.ts
26533
26849
  import path51 from "path";
@@ -26632,13 +26948,13 @@ function applyRename(rewrites, sourcePath, destPath, cwd) {
26632
26948
  const updatedContents = applyRewrites(rewrites);
26633
26949
  for (const [file, content] of updatedContents) {
26634
26950
  fs35.writeFileSync(file, content, "utf8");
26635
- console.log(chalk193.cyan(` Updated imports in ${path52.relative(cwd, file)}`));
26951
+ console.log(chalk195.cyan(` Updated imports in ${path52.relative(cwd, file)}`));
26636
26952
  }
26637
26953
  const destDir = path52.dirname(destPath);
26638
26954
  if (!fs35.existsSync(destDir)) fs35.mkdirSync(destDir, { recursive: true });
26639
26955
  fs35.renameSync(sourcePath, destPath);
26640
26956
  console.log(
26641
- chalk193.white(
26957
+ chalk195.white(
26642
26958
  ` Moved ${path52.relative(cwd, sourcePath)} \u2192 ${path52.relative(cwd, destPath)}`
26643
26959
  )
26644
26960
  );
@@ -26725,16 +27041,16 @@ function computeRenameRewrites(sourcePath, destPath) {
26725
27041
 
26726
27042
  // src/commands/refactor/rename/printRenamePreview.ts
26727
27043
  import path54 from "path";
26728
- import chalk194 from "chalk";
27044
+ import chalk196 from "chalk";
26729
27045
  function printRenamePreview(rewrites, cwd) {
26730
27046
  for (const rewrite of rewrites) {
26731
27047
  console.log(
26732
- chalk194.dim(
27048
+ chalk196.dim(
26733
27049
  ` ${path54.relative(cwd, rewrite.file)}: ${rewrite.oldSpecifier} \u2192 ${rewrite.newSpecifier}`
26734
27050
  )
26735
27051
  );
26736
27052
  }
26737
- console.log(chalk194.dim("Dry run. Use --apply to execute."));
27053
+ console.log(chalk196.dim("Dry run. Use --apply to execute."));
26738
27054
  }
26739
27055
 
26740
27056
  // src/commands/refactor/rename/index.ts
@@ -26745,20 +27061,20 @@ async function rename(source, destination, options2 = {}) {
26745
27061
  const relSource = path55.relative(cwd, sourcePath);
26746
27062
  const relDest = path55.relative(cwd, destPath);
26747
27063
  if (!fs36.existsSync(sourcePath)) {
26748
- console.log(chalk195.red(`File not found: ${source}`));
27064
+ console.log(chalk197.red(`File not found: ${source}`));
26749
27065
  process.exit(1);
26750
27066
  }
26751
27067
  if (destPath !== sourcePath && fs36.existsSync(destPath)) {
26752
- console.log(chalk195.red(`Destination already exists: ${destination}`));
27068
+ console.log(chalk197.red(`Destination already exists: ${destination}`));
26753
27069
  process.exit(1);
26754
27070
  }
26755
- console.log(chalk195.bold(`Rename: ${relSource} \u2192 ${relDest}`));
26756
- console.log(chalk195.dim("Loading project..."));
26757
- console.log(chalk195.dim("Scanning imports across the project..."));
27071
+ console.log(chalk197.bold(`Rename: ${relSource} \u2192 ${relDest}`));
27072
+ console.log(chalk197.dim("Loading project..."));
27073
+ console.log(chalk197.dim("Scanning imports across the project..."));
26758
27074
  const rewrites = computeRenameRewrites(sourcePath, destPath);
26759
27075
  const affectedFiles = new Set(rewrites.map((r) => r.file)).size;
26760
27076
  console.log(
26761
- chalk195.dim(
27077
+ chalk197.dim(
26762
27078
  `${rewrites.length} import path(s) to update across ${affectedFiles} file(s)`
26763
27079
  )
26764
27080
  );
@@ -26767,11 +27083,11 @@ async function rename(source, destination, options2 = {}) {
26767
27083
  return;
26768
27084
  }
26769
27085
  applyRename(rewrites, sourcePath, destPath, cwd);
26770
- console.log(chalk195.green("Done"));
27086
+ console.log(chalk197.green("Done"));
26771
27087
  }
26772
27088
 
26773
27089
  // src/commands/refactor/renameSymbol/index.ts
26774
- import chalk196 from "chalk";
27090
+ import chalk198 from "chalk";
26775
27091
 
26776
27092
  // src/commands/refactor/renameSymbol/findSymbol.ts
26777
27093
  import { SyntaxKind as SyntaxKind15 } from "ts-morph";
@@ -26817,33 +27133,33 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
26817
27133
  const { project, sourceFile } = loadProjectFile(file);
26818
27134
  const symbol = findSymbol(sourceFile, oldName);
26819
27135
  if (!symbol) {
26820
- console.log(chalk196.red(`Symbol "${oldName}" not found in ${file}`));
27136
+ console.log(chalk198.red(`Symbol "${oldName}" not found in ${file}`));
26821
27137
  process.exit(1);
26822
27138
  }
26823
27139
  const grouped = groupReferences(symbol, cwd);
26824
27140
  const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
26825
27141
  console.log(
26826
- chalk196.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
27142
+ chalk198.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
26827
27143
  `)
26828
27144
  );
26829
27145
  for (const [refFile, lines2] of grouped) {
26830
27146
  console.log(
26831
- ` ${chalk196.dim(refFile)}: lines ${chalk196.cyan(lines2.join(", "))}`
27147
+ ` ${chalk198.dim(refFile)}: lines ${chalk198.cyan(lines2.join(", "))}`
26832
27148
  );
26833
27149
  }
26834
27150
  if (options2.apply) {
26835
27151
  symbol.rename(newName);
26836
27152
  await project.save();
26837
- console.log(chalk196.green(`
27153
+ console.log(chalk198.green(`
26838
27154
  Renamed ${oldName} \u2192 ${newName}`));
26839
27155
  } else {
26840
- console.log(chalk196.dim("\nDry run. Use --apply to execute."));
27156
+ console.log(chalk198.dim("\nDry run. Use --apply to execute."));
26841
27157
  }
26842
27158
  }
26843
27159
 
26844
27160
  // src/commands/refactor/restructure/index.ts
26845
27161
  import path63 from "path";
26846
- import chalk199 from "chalk";
27162
+ import chalk201 from "chalk";
26847
27163
 
26848
27164
  // src/commands/refactor/restructure/clusterDirectories.ts
26849
27165
  import path57 from "path";
@@ -26922,50 +27238,50 @@ function clusterFiles(graph) {
26922
27238
 
26923
27239
  // src/commands/refactor/restructure/displayPlan.ts
26924
27240
  import path59 from "path";
26925
- import chalk197 from "chalk";
27241
+ import chalk199 from "chalk";
26926
27242
  function relPath(filePath) {
26927
27243
  return path59.relative(process.cwd(), filePath);
26928
27244
  }
26929
27245
  function displayMoves(plan2) {
26930
27246
  if (plan2.moves.length === 0) return;
26931
- console.log(chalk197.bold("\nFile moves:"));
27247
+ console.log(chalk199.bold("\nFile moves:"));
26932
27248
  for (const move2 of plan2.moves) {
26933
27249
  console.log(
26934
- ` ${chalk197.red(relPath(move2.from))} \u2192 ${chalk197.green(relPath(move2.to))}`
27250
+ ` ${chalk199.red(relPath(move2.from))} \u2192 ${chalk199.green(relPath(move2.to))}`
26935
27251
  );
26936
- console.log(chalk197.dim(` ${move2.reason}`));
27252
+ console.log(chalk199.dim(` ${move2.reason}`));
26937
27253
  }
26938
27254
  }
26939
27255
  function displayRewrites(rewrites) {
26940
27256
  if (rewrites.length === 0) return;
26941
27257
  const affectedFiles = new Set(rewrites.map((r) => r.file));
26942
- console.log(chalk197.bold(`
27258
+ console.log(chalk199.bold(`
26943
27259
  Import rewrites (${affectedFiles.size} files):`));
26944
27260
  for (const file of affectedFiles) {
26945
- console.log(` ${chalk197.cyan(relPath(file))}:`);
27261
+ console.log(` ${chalk199.cyan(relPath(file))}:`);
26946
27262
  for (const { oldSpecifier, newSpecifier } of rewrites.filter(
26947
27263
  (r) => r.file === file
26948
27264
  )) {
26949
27265
  console.log(
26950
- ` ${chalk197.red(`"${oldSpecifier}"`)} \u2192 ${chalk197.green(`"${newSpecifier}"`)}`
27266
+ ` ${chalk199.red(`"${oldSpecifier}"`)} \u2192 ${chalk199.green(`"${newSpecifier}"`)}`
26951
27267
  );
26952
27268
  }
26953
27269
  }
26954
27270
  }
26955
27271
  function displayPlan2(plan2) {
26956
27272
  if (plan2.warnings.length > 0) {
26957
- console.log(chalk197.yellow("\nWarnings:"));
26958
- for (const w of plan2.warnings) console.log(chalk197.yellow(` ${w}`));
27273
+ console.log(chalk199.yellow("\nWarnings:"));
27274
+ for (const w of plan2.warnings) console.log(chalk199.yellow(` ${w}`));
26959
27275
  }
26960
27276
  if (plan2.newDirectories.length > 0) {
26961
- console.log(chalk197.bold("\nNew directories:"));
27277
+ console.log(chalk199.bold("\nNew directories:"));
26962
27278
  for (const dir of plan2.newDirectories)
26963
- console.log(chalk197.green(` ${dir}/`));
27279
+ console.log(chalk199.green(` ${dir}/`));
26964
27280
  }
26965
27281
  displayMoves(plan2);
26966
27282
  displayRewrites(plan2.rewrites);
26967
27283
  console.log(
26968
- chalk197.dim(
27284
+ chalk199.dim(
26969
27285
  `
26970
27286
  Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports rewritten`
26971
27287
  )
@@ -26975,18 +27291,18 @@ Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports r
26975
27291
  // src/commands/refactor/restructure/executePlan.ts
26976
27292
  import fs37 from "fs";
26977
27293
  import path60 from "path";
26978
- import chalk198 from "chalk";
27294
+ import chalk200 from "chalk";
26979
27295
  function executePlan(plan2) {
26980
27296
  const updatedContents = applyRewrites(plan2.rewrites);
26981
27297
  for (const [file, content] of updatedContents) {
26982
27298
  fs37.writeFileSync(file, content, "utf8");
26983
27299
  console.log(
26984
- chalk198.cyan(` Rewrote imports in ${path60.relative(process.cwd(), file)}`)
27300
+ chalk200.cyan(` Rewrote imports in ${path60.relative(process.cwd(), file)}`)
26985
27301
  );
26986
27302
  }
26987
27303
  for (const dir of plan2.newDirectories) {
26988
27304
  fs37.mkdirSync(dir, { recursive: true });
26989
- console.log(chalk198.green(` Created ${path60.relative(process.cwd(), dir)}/`));
27305
+ console.log(chalk200.green(` Created ${path60.relative(process.cwd(), dir)}/`));
26990
27306
  }
26991
27307
  for (const move2 of plan2.moves) {
26992
27308
  const targetDir = path60.dirname(move2.to);
@@ -26995,7 +27311,7 @@ function executePlan(plan2) {
26995
27311
  }
26996
27312
  fs37.renameSync(move2.from, move2.to);
26997
27313
  console.log(
26998
- chalk198.white(
27314
+ chalk200.white(
26999
27315
  ` Moved ${path60.relative(process.cwd(), move2.from)} \u2192 ${path60.relative(process.cwd(), move2.to)}`
27000
27316
  )
27001
27317
  );
@@ -27010,7 +27326,7 @@ function removeEmptyDirectories(dirs) {
27010
27326
  if (entries.length === 0) {
27011
27327
  fs37.rmdirSync(dir);
27012
27328
  console.log(
27013
- chalk198.dim(
27329
+ chalk200.dim(
27014
27330
  ` Removed empty directory ${path60.relative(process.cwd(), dir)}`
27015
27331
  )
27016
27332
  );
@@ -27143,22 +27459,22 @@ async function restructure(pattern2, options2 = {}) {
27143
27459
  const targetPattern = pattern2 ?? "src";
27144
27460
  const files = findSourceFiles2(targetPattern);
27145
27461
  if (files.length === 0) {
27146
- console.log(chalk199.yellow("No files found matching pattern"));
27462
+ console.log(chalk201.yellow("No files found matching pattern"));
27147
27463
  return;
27148
27464
  }
27149
27465
  const tsConfigPath = findTsConfig(path63.resolve(files[0]));
27150
27466
  const plan2 = buildPlan3(files, tsConfigPath);
27151
27467
  if (plan2.moves.length === 0) {
27152
- console.log(chalk199.green("No restructuring needed"));
27468
+ console.log(chalk201.green("No restructuring needed"));
27153
27469
  return;
27154
27470
  }
27155
27471
  displayPlan2(plan2);
27156
27472
  if (options2.apply) {
27157
- console.log(chalk199.bold("\nApplying changes..."));
27473
+ console.log(chalk201.bold("\nApplying changes..."));
27158
27474
  executePlan(plan2);
27159
- console.log(chalk199.green("\nRestructuring complete"));
27475
+ console.log(chalk201.green("\nRestructuring complete"));
27160
27476
  } else {
27161
- console.log(chalk199.dim("\nDry run. Use --apply to execute."));
27477
+ console.log(chalk201.dim("\nDry run. Use --apply to execute."));
27162
27478
  }
27163
27479
  }
27164
27480
 
@@ -27481,7 +27797,7 @@ function gatherContext() {
27481
27797
  }
27482
27798
 
27483
27799
  // src/commands/review/postReviewToPr.ts
27484
- import { readFileSync as readFileSync42 } from "fs";
27800
+ import { readFileSync as readFileSync43 } from "fs";
27485
27801
 
27486
27802
  // src/commands/review/carriedUnanchoredFindings.ts
27487
27803
  function carriedUnanchoredFindings(unanchored) {
@@ -27685,15 +28001,15 @@ function runReviewSubmission(mutation, body) {
27685
28001
  }
27686
28002
 
27687
28003
  // src/commands/review/submitBodyOnlyReview.ts
27688
- var MUTATION = `mutation($prId: ID!, $body: String) { addPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
28004
+ var MUTATION3 = `mutation($prId: ID!, $body: String) { addPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
27689
28005
  function submitBodyOnlyReview(body) {
27690
- runReviewSubmission(MUTATION, body);
28006
+ runReviewSubmission(MUTATION3, body);
27691
28007
  }
27692
28008
 
27693
28009
  // src/commands/review/submitPendingReview.ts
27694
- var MUTATION2 = `mutation($prId: ID!, $body: String) { submitPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
28010
+ var MUTATION4 = `mutation($prId: ID!, $body: String) { submitPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
27695
28011
  function submitPendingReview(body) {
27696
- runReviewSubmission(MUTATION2, body);
28012
+ runReviewSubmission(MUTATION4, body);
27697
28013
  }
27698
28014
 
27699
28015
  // src/commands/review/postAndMaybeSubmit.ts
@@ -27816,18 +28132,18 @@ function partitionFindingsByDiff(findings, index3) {
27816
28132
  }
27817
28133
 
27818
28134
  // src/commands/review/warnOutOfDiff.ts
27819
- import chalk200 from "chalk";
28135
+ import chalk202 from "chalk";
27820
28136
  function warnOutOfDiff(outOfDiff) {
27821
28137
  if (outOfDiff.length === 0) return;
27822
28138
  console.warn(
27823
- chalk200.yellow(
28139
+ chalk202.yellow(
27824
28140
  `Moved ${outOfDiff.length} finding(s) whose lines fall outside the PR diff into the review body (GitHub cannot anchor a comment on these):`
27825
28141
  )
27826
28142
  );
27827
28143
  for (const finding of outOfDiff) {
27828
28144
  const range = finding.startLine !== void 0 ? `${finding.startLine}-${finding.line}` : `${finding.line}`;
27829
28145
  console.warn(
27830
- ` ${chalk200.yellow("\xB7")} ${finding.title} ${chalk200.dim(
28146
+ ` ${chalk202.yellow("\xB7")} ${finding.title} ${chalk202.dim(
27831
28147
  `(${finding.file}:${range})`
27832
28148
  )}`
27833
28149
  );
@@ -27851,18 +28167,18 @@ function selectInDiffFindings(lineBound, prDiff) {
27851
28167
  }
27852
28168
 
27853
28169
  // src/commands/review/warnUnlocated.ts
27854
- import chalk201 from "chalk";
28170
+ import chalk203 from "chalk";
27855
28171
  function warnUnlocated(unlocated) {
27856
28172
  if (unlocated.length === 0) return;
27857
28173
  console.warn(
27858
- chalk201.yellow(
28174
+ chalk203.yellow(
27859
28175
  `Moved ${unlocated.length} finding(s) without a parseable file:line into the review body:`
27860
28176
  )
27861
28177
  );
27862
28178
  for (const finding of unlocated) {
27863
- const where = finding.location || chalk201.dim("missing");
28179
+ const where = finding.location || chalk203.dim("missing");
27864
28180
  console.warn(
27865
- ` ${chalk201.yellow("\xB7")} ${finding.title} ${chalk201.dim(`(${where})`)}`
28181
+ ` ${chalk203.yellow("\xB7")} ${finding.title} ${chalk203.dim(`(${where})`)}`
27866
28182
  );
27867
28183
  }
27868
28184
  }
@@ -27929,7 +28245,7 @@ async function confirmPost(prNumber, work, options2) {
27929
28245
  return promptConfirm(`Post ${work} to PR #${prNumber}?`, false);
27930
28246
  }
27931
28247
  async function postFindingsToPr(prInfo, synthesisPath, options2) {
27932
- const markdown = readFileSync42(synthesisPath, "utf8");
28248
+ const markdown = readFileSync43(synthesisPath, "utf8");
27933
28249
  const { inDiff, unanchored } = selectPostableFindings(markdown, prInfo);
27934
28250
  const carried = carriedUnanchoredFindings(unanchored);
27935
28251
  if (inDiff.length === 0 && carried.length === 0) return NOTHING_POSTED;
@@ -28818,7 +29134,7 @@ async function runReviewers(reviewDir, claudePath, codexPath, stdinPrompt, optio
28818
29134
  }
28819
29135
 
28820
29136
  // src/commands/review/synthesise.ts
28821
- import { readFileSync as readFileSync43 } from "fs";
29137
+ import { readFileSync as readFileSync44 } from "fs";
28822
29138
 
28823
29139
  // src/commands/review/buildSynthesisStdin.ts
28824
29140
  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.
@@ -28883,7 +29199,7 @@ Files:
28883
29199
 
28884
29200
  // src/commands/review/synthesise.ts
28885
29201
  function printSummary2(synthesisPath) {
28886
- const markdown = readFileSync43(synthesisPath, "utf8");
29202
+ const markdown = readFileSync44(synthesisPath, "utf8");
28887
29203
  console.log("");
28888
29204
  console.log(buildReviewSummary(markdown));
28889
29205
  console.log("");
@@ -29117,7 +29433,7 @@ function registerReview(program2) {
29117
29433
  }
29118
29434
 
29119
29435
  // src/commands/seq/seqAuth.ts
29120
- import chalk203 from "chalk";
29436
+ import chalk205 from "chalk";
29121
29437
 
29122
29438
  // src/commands/seq/loadConnections.ts
29123
29439
  function loadConnections2() {
@@ -29146,10 +29462,10 @@ function setDefaultConnection(name) {
29146
29462
  }
29147
29463
 
29148
29464
  // src/shared/assertUniqueName.ts
29149
- import chalk202 from "chalk";
29465
+ import chalk204 from "chalk";
29150
29466
  function assertUniqueName(existingNames, name) {
29151
29467
  if (existingNames.includes(name)) {
29152
- console.error(chalk202.red(`Connection "${name}" already exists.`));
29468
+ console.error(chalk204.red(`Connection "${name}" already exists.`));
29153
29469
  process.exit(1);
29154
29470
  }
29155
29471
  }
@@ -29167,16 +29483,16 @@ async function promptConnection2(existingNames) {
29167
29483
  var seqAuth = createConnectionAuth({
29168
29484
  load: loadConnections2,
29169
29485
  save: saveConnections2,
29170
- format: (c) => `${chalk203.bold(c.name)} ${c.url}`,
29486
+ format: (c) => `${chalk205.bold(c.name)} ${c.url}`,
29171
29487
  promptNew: promptConnection2,
29172
29488
  onFirst: (c) => setDefaultConnection(c.name)
29173
29489
  });
29174
29490
 
29175
29491
  // src/commands/seq/seqQuery.ts
29176
- import chalk207 from "chalk";
29492
+ import chalk209 from "chalk";
29177
29493
 
29178
29494
  // src/commands/seq/fetchSeq.ts
29179
- import chalk204 from "chalk";
29495
+ import chalk206 from "chalk";
29180
29496
  async function fetchSeq(conn, path80, params) {
29181
29497
  const url = `${conn.url}${path80}?${params}`;
29182
29498
  const response = await fetch(url, {
@@ -29187,7 +29503,7 @@ async function fetchSeq(conn, path80, params) {
29187
29503
  });
29188
29504
  if (!response.ok) {
29189
29505
  const body = await response.text();
29190
- console.error(chalk204.red(`Seq returned ${response.status}: ${body}`));
29506
+ console.error(chalk206.red(`Seq returned ${response.status}: ${body}`));
29191
29507
  process.exit(1);
29192
29508
  }
29193
29509
  return response;
@@ -29246,23 +29562,23 @@ async function fetchSeqEvents(conn, params) {
29246
29562
  }
29247
29563
 
29248
29564
  // src/commands/seq/formatEvent.ts
29249
- import chalk205 from "chalk";
29565
+ import chalk207 from "chalk";
29250
29566
  function levelColor(level) {
29251
29567
  switch (level) {
29252
29568
  case "Fatal":
29253
- return chalk205.bgRed.white;
29569
+ return chalk207.bgRed.white;
29254
29570
  case "Error":
29255
- return chalk205.red;
29571
+ return chalk207.red;
29256
29572
  case "Warning":
29257
- return chalk205.yellow;
29573
+ return chalk207.yellow;
29258
29574
  case "Information":
29259
- return chalk205.cyan;
29575
+ return chalk207.cyan;
29260
29576
  case "Debug":
29261
- return chalk205.gray;
29577
+ return chalk207.gray;
29262
29578
  case "Verbose":
29263
- return chalk205.dim;
29579
+ return chalk207.dim;
29264
29580
  default:
29265
- return chalk205.white;
29581
+ return chalk207.white;
29266
29582
  }
29267
29583
  }
29268
29584
  function levelAbbrev(level) {
@@ -29303,12 +29619,12 @@ function formatTimestamp(iso) {
29303
29619
  function formatEvent(event) {
29304
29620
  const color = levelColor(event.Level);
29305
29621
  const abbrev = levelAbbrev(event.Level);
29306
- const ts8 = chalk205.dim(formatTimestamp(event.Timestamp));
29622
+ const ts8 = chalk207.dim(formatTimestamp(event.Timestamp));
29307
29623
  const msg = renderMessage(event);
29308
29624
  const lines2 = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
29309
29625
  if (event.Exception) {
29310
29626
  for (const line of event.Exception.split("\n")) {
29311
- lines2.push(chalk205.red(` ${line}`));
29627
+ lines2.push(chalk207.red(` ${line}`));
29312
29628
  }
29313
29629
  }
29314
29630
  return lines2.join("\n");
@@ -29341,11 +29657,11 @@ function rejectTimestampFilter(filter) {
29341
29657
  }
29342
29658
 
29343
29659
  // src/shared/resolveNamedConnection.ts
29344
- import chalk206 from "chalk";
29660
+ import chalk208 from "chalk";
29345
29661
  function resolveNamedConnection(connections, requested, defaultName, kind, authCommand) {
29346
29662
  if (connections.length === 0) {
29347
29663
  console.error(
29348
- chalk206.red(
29664
+ chalk208.red(
29349
29665
  `No ${kind} connections configured. Run '${authCommand}' first.`
29350
29666
  )
29351
29667
  );
@@ -29354,7 +29670,7 @@ function resolveNamedConnection(connections, requested, defaultName, kind, authC
29354
29670
  const target = requested ?? defaultName ?? connections[0].name;
29355
29671
  const connection = connections.find((c) => c.name === target);
29356
29672
  if (!connection) {
29357
- console.error(chalk206.red(`${kind} connection "${target}" not found.`));
29673
+ console.error(chalk208.red(`${kind} connection "${target}" not found.`));
29358
29674
  process.exit(1);
29359
29675
  }
29360
29676
  return connection;
@@ -29383,7 +29699,7 @@ async function seqQuery(filter, options2) {
29383
29699
  new URLSearchParams({ filter, count: String(count8) })
29384
29700
  );
29385
29701
  if (events.length === 0) {
29386
- console.log(chalk207.yellow("No events found."));
29702
+ console.log(chalk209.yellow("No events found."));
29387
29703
  return;
29388
29704
  }
29389
29705
  if (options2.json) {
@@ -29394,11 +29710,11 @@ async function seqQuery(filter, options2) {
29394
29710
  for (const event of chronological) {
29395
29711
  console.log(formatEvent(event));
29396
29712
  }
29397
- console.log(chalk207.dim(`
29713
+ console.log(chalk209.dim(`
29398
29714
  ${events.length} events`));
29399
29715
  if (events.length >= count8) {
29400
29716
  console.log(
29401
- chalk207.yellow(
29717
+ chalk209.yellow(
29402
29718
  `Results limited to ${count8}. Use --count to retrieve more.`
29403
29719
  )
29404
29720
  );
@@ -29406,10 +29722,10 @@ ${events.length} events`));
29406
29722
  }
29407
29723
 
29408
29724
  // src/shared/setNamedDefaultConnection.ts
29409
- import chalk208 from "chalk";
29725
+ import chalk210 from "chalk";
29410
29726
  function setNamedDefaultConnection(connections, name, setDefault, kind) {
29411
29727
  if (!connections.find((c) => c.name === name)) {
29412
- console.error(chalk208.red(`Connection "${name}" not found.`));
29728
+ console.error(chalk210.red(`Connection "${name}" not found.`));
29413
29729
  process.exit(1);
29414
29730
  }
29415
29731
  setDefault(name);
@@ -29458,7 +29774,7 @@ function registerSignal(program2) {
29458
29774
  }
29459
29775
 
29460
29776
  // src/commands/sql/sqlAuth.ts
29461
- import chalk210 from "chalk";
29777
+ import chalk212 from "chalk";
29462
29778
 
29463
29779
  // src/commands/sql/loadConnections.ts
29464
29780
  function loadConnections3() {
@@ -29487,7 +29803,7 @@ function setDefaultConnection2(name) {
29487
29803
  }
29488
29804
 
29489
29805
  // src/commands/sql/promptConnection.ts
29490
- import chalk209 from "chalk";
29806
+ import chalk211 from "chalk";
29491
29807
  async function promptConnection3(existingNames) {
29492
29808
  const name = await promptInput("name", "Connection name:", "default");
29493
29809
  assertUniqueName(existingNames, name);
@@ -29495,7 +29811,7 @@ async function promptConnection3(existingNames) {
29495
29811
  const portStr = await promptInput("port", "Port:", "1433");
29496
29812
  const port = Number.parseInt(portStr, 10);
29497
29813
  if (!Number.isFinite(port)) {
29498
- console.error(chalk209.red(`Invalid port "${portStr}".`));
29814
+ console.error(chalk211.red(`Invalid port "${portStr}".`));
29499
29815
  process.exit(1);
29500
29816
  }
29501
29817
  const user = await promptInput("user", "User:");
@@ -29508,13 +29824,13 @@ async function promptConnection3(existingNames) {
29508
29824
  var sqlAuth = createConnectionAuth({
29509
29825
  load: loadConnections3,
29510
29826
  save: saveConnections3,
29511
- format: (c) => `${chalk210.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
29827
+ format: (c) => `${chalk212.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
29512
29828
  promptNew: promptConnection3,
29513
29829
  onFirst: (c) => setDefaultConnection2(c.name)
29514
29830
  });
29515
29831
 
29516
29832
  // src/commands/sql/printTable.ts
29517
- import chalk211 from "chalk";
29833
+ import chalk213 from "chalk";
29518
29834
  function formatCell(value) {
29519
29835
  if (value === null || value === void 0) return "";
29520
29836
  if (value instanceof Date) return value.toISOString();
@@ -29523,7 +29839,7 @@ function formatCell(value) {
29523
29839
  }
29524
29840
  function printTable(rows) {
29525
29841
  if (rows.length === 0) {
29526
- console.log(chalk211.yellow("(no rows)"));
29842
+ console.log(chalk213.yellow("(no rows)"));
29527
29843
  return;
29528
29844
  }
29529
29845
  const columns = Object.keys(rows[0]);
@@ -29531,13 +29847,13 @@ function printTable(rows) {
29531
29847
  (col) => Math.max(col.length, ...rows.map((r) => formatCell(r[col]).length))
29532
29848
  );
29533
29849
  const header = columns.map((c, i) => c.padEnd(widths[i])).join(" ");
29534
- console.log(chalk211.dim(header));
29535
- console.log(chalk211.dim("-".repeat(header.length)));
29850
+ console.log(chalk213.dim(header));
29851
+ console.log(chalk213.dim("-".repeat(header.length)));
29536
29852
  for (const row of rows) {
29537
29853
  const line = columns.map((c, i) => formatCell(row[c]).padEnd(widths[i])).join(" ");
29538
29854
  console.log(line);
29539
29855
  }
29540
- console.log(chalk211.dim(`
29856
+ console.log(chalk213.dim(`
29541
29857
  ${rows.length} row${rows.length === 1 ? "" : "s"}`));
29542
29858
  }
29543
29859
 
@@ -29597,7 +29913,7 @@ async function sqlColumns(table, connectionName) {
29597
29913
  }
29598
29914
 
29599
29915
  // src/commands/sql/sqlMutate.ts
29600
- import chalk212 from "chalk";
29916
+ import chalk214 from "chalk";
29601
29917
 
29602
29918
  // src/commands/sql/isMutation.ts
29603
29919
  var MUTATION_KEYWORDS = [
@@ -29631,7 +29947,7 @@ function isMutation(sql25) {
29631
29947
  async function sqlMutate(query, connectionName) {
29632
29948
  if (!isMutation(query)) {
29633
29949
  console.error(
29634
- chalk212.red(
29950
+ chalk214.red(
29635
29951
  "assist sql mutate refuses non-mutating statements. Use `assist sql query` instead."
29636
29952
  )
29637
29953
  );
@@ -29641,18 +29957,18 @@ async function sqlMutate(query, connectionName) {
29641
29957
  const pool = await sqlConnect(conn);
29642
29958
  try {
29643
29959
  const result = await pool.request().query(query);
29644
- console.log(chalk212.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
29960
+ console.log(chalk214.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
29645
29961
  } finally {
29646
29962
  await pool.close();
29647
29963
  }
29648
29964
  }
29649
29965
 
29650
29966
  // src/commands/sql/sqlQuery.ts
29651
- import chalk213 from "chalk";
29967
+ import chalk215 from "chalk";
29652
29968
  async function sqlQuery(query, connectionName) {
29653
29969
  if (isMutation(query)) {
29654
29970
  console.error(
29655
- chalk213.red(
29971
+ chalk215.red(
29656
29972
  "assist sql query refuses mutating statements. Use `assist sql mutate` instead."
29657
29973
  )
29658
29974
  );
@@ -29667,7 +29983,7 @@ async function sqlQuery(query, connectionName) {
29667
29983
  printTable(rows);
29668
29984
  } else {
29669
29985
  console.log(
29670
- chalk213.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
29986
+ chalk215.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
29671
29987
  );
29672
29988
  }
29673
29989
  } finally {
@@ -29812,7 +30128,7 @@ function reportPrune(label2, result, force) {
29812
30128
  // src/commands/sync/syncClaudeMd.ts
29813
30129
  import * as fs41 from "fs";
29814
30130
  import * as path66 from "path";
29815
- import chalk214 from "chalk";
30131
+ import chalk216 from "chalk";
29816
30132
  async function syncClaudeMd(claudeDir, targetBase, options2) {
29817
30133
  const source = path66.join(claudeDir, "CLAUDE.md");
29818
30134
  const target = path66.join(targetBase, "CLAUDE.md");
@@ -29821,14 +30137,14 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
29821
30137
  const targetContent = fs41.readFileSync(target, "utf8");
29822
30138
  if (sourceContent !== targetContent) {
29823
30139
  console.log(
29824
- chalk214.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
30140
+ chalk216.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
29825
30141
  );
29826
30142
  console.log();
29827
30143
  printDiff(targetContent, sourceContent);
29828
30144
  if (!options2?.yes) {
29829
30145
  printAutoConfirmHint();
29830
30146
  const confirm = await promptConfirm(
29831
- chalk214.red("Overwrite existing CLAUDE.md?"),
30147
+ chalk216.red("Overwrite existing CLAUDE.md?"),
29832
30148
  false
29833
30149
  );
29834
30150
  if (!confirm) {
@@ -30061,7 +30377,7 @@ function syncPi(claudeDir, options2) {
30061
30377
  // src/commands/sync/syncSettings.ts
30062
30378
  import * as fs47 from "fs";
30063
30379
  import * as path73 from "path";
30064
- import chalk215 from "chalk";
30380
+ import chalk217 from "chalk";
30065
30381
  async function syncSettings(claudeDir, targetBase, options2) {
30066
30382
  const source = path73.join(claudeDir, "settings.json");
30067
30383
  const target = path73.join(targetBase, "settings.json");
@@ -30080,7 +30396,7 @@ async function syncSettings(claudeDir, targetBase, options2) {
30080
30396
  if (mergedContent !== normalizedTarget) {
30081
30397
  if (!options2?.yes) {
30082
30398
  console.log(
30083
- chalk215.yellow(
30399
+ chalk217.yellow(
30084
30400
  "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
30085
30401
  )
30086
30402
  );
@@ -30088,7 +30404,7 @@ async function syncSettings(claudeDir, targetBase, options2) {
30088
30404
  printDiff(targetContent, mergedContent);
30089
30405
  printAutoConfirmHint();
30090
30406
  const confirm = await promptConfirm(
30091
- chalk215.red("Overwrite existing settings.json?"),
30407
+ chalk217.red("Overwrite existing settings.json?"),
30092
30408
  false
30093
30409
  );
30094
30410
  if (!confirm) {
@@ -30246,7 +30562,7 @@ function list4() {
30246
30562
  import {
30247
30563
  existsSync as existsSync63,
30248
30564
  mkdirSync as mkdirSync26,
30249
- readFileSync as readFileSync48,
30565
+ readFileSync as readFileSync49,
30250
30566
  renameSync as renameSync2,
30251
30567
  writeFileSync as writeFileSync42
30252
30568
  } from "fs";
@@ -30458,7 +30774,7 @@ function formatChatLog(messages) {
30458
30774
  // src/commands/transcript/move.ts
30459
30775
  var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
30460
30776
  function convertVttToMarkdown(inputPath) {
30461
- const cues = parseVtt(readFileSync48(inputPath, "utf8"));
30777
+ const cues = parseVtt(readFileSync49(inputPath, "utf8"));
30462
30778
  const messages = cuesToChatMessages(deduplicateCues(cues));
30463
30779
  return formatChatLog(messages);
30464
30780
  }
@@ -30605,14 +30921,14 @@ function devices() {
30605
30921
  }
30606
30922
 
30607
30923
  // src/commands/voice/logs.ts
30608
- import { existsSync as existsSync64, readFileSync as readFileSync49 } from "fs";
30924
+ import { existsSync as existsSync64, readFileSync as readFileSync50 } from "fs";
30609
30925
  function logs(options2) {
30610
30926
  if (!existsSync64(voicePaths.log)) {
30611
30927
  console.log("No voice log file found");
30612
30928
  return;
30613
30929
  }
30614
30930
  const count8 = Number.parseInt(options2.lines ?? "150", 10);
30615
- const content = readFileSync49(voicePaths.log, "utf8").trim();
30931
+ const content = readFileSync50(voicePaths.log, "utf8").trim();
30616
30932
  if (!content) {
30617
30933
  console.log("Voice log is empty");
30618
30934
  return;
@@ -30639,7 +30955,7 @@ import { join as join82 } from "path";
30639
30955
 
30640
30956
  // src/commands/voice/checkLockFile.ts
30641
30957
  import { execSync as execSync58 } from "child_process";
30642
- import { existsSync as existsSync65, mkdirSync as mkdirSync27, readFileSync as readFileSync50, writeFileSync as writeFileSync43 } from "fs";
30958
+ import { existsSync as existsSync65, mkdirSync as mkdirSync27, readFileSync as readFileSync51, writeFileSync as writeFileSync43 } from "fs";
30643
30959
  import { join as join81 } from "path";
30644
30960
  function isProcessAlive2(pid) {
30645
30961
  try {
@@ -30653,7 +30969,7 @@ function checkLockFile() {
30653
30969
  const lockFile = getLockFile();
30654
30970
  if (!existsSync65(lockFile)) return;
30655
30971
  try {
30656
- const lock2 = JSON.parse(readFileSync50(lockFile, "utf8"));
30972
+ const lock2 = JSON.parse(readFileSync51(lockFile, "utf8"));
30657
30973
  if (lock2.pid && isProcessAlive2(lock2.pid)) {
30658
30974
  console.error(
30659
30975
  `Voice daemon already running (PID ${lock2.pid}, env: ${lock2.env}). Stop it first with: assist voice stop`
@@ -30755,7 +31071,7 @@ function start2(options2) {
30755
31071
  }
30756
31072
 
30757
31073
  // src/commands/voice/status.ts
30758
- import { existsSync as existsSync66, readFileSync as readFileSync51 } from "fs";
31074
+ import { existsSync as existsSync66, readFileSync as readFileSync52 } from "fs";
30759
31075
  function isProcessAlive3(pid) {
30760
31076
  try {
30761
31077
  process.kill(pid, 0);
@@ -30766,7 +31082,7 @@ function isProcessAlive3(pid) {
30766
31082
  }
30767
31083
  function readRecentLogs(count8) {
30768
31084
  if (!existsSync66(voicePaths.log)) return [];
30769
- const lines2 = readFileSync51(voicePaths.log, "utf8").trim().split("\n");
31085
+ const lines2 = readFileSync52(voicePaths.log, "utf8").trim().split("\n");
30770
31086
  return lines2.slice(-count8);
30771
31087
  }
30772
31088
  function status2() {
@@ -30774,7 +31090,7 @@ function status2() {
30774
31090
  console.log("Voice daemon: not running (no PID file)");
30775
31091
  return;
30776
31092
  }
30777
- const pid = Number.parseInt(readFileSync51(voicePaths.pid, "utf8").trim(), 10);
31093
+ const pid = Number.parseInt(readFileSync52(voicePaths.pid, "utf8").trim(), 10);
30778
31094
  const alive = isProcessAlive3(pid);
30779
31095
  console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
30780
31096
  const recent = readRecentLogs(5);
@@ -30793,13 +31109,13 @@ function status2() {
30793
31109
  }
30794
31110
 
30795
31111
  // src/commands/voice/stop.ts
30796
- import { existsSync as existsSync67, readFileSync as readFileSync52, unlinkSync as unlinkSync20 } from "fs";
31112
+ import { existsSync as existsSync67, readFileSync as readFileSync53, unlinkSync as unlinkSync20 } from "fs";
30797
31113
  function stop2() {
30798
31114
  if (!existsSync67(voicePaths.pid)) {
30799
31115
  console.log("Voice daemon is not running (no PID file)");
30800
31116
  return;
30801
31117
  }
30802
- const pid = Number.parseInt(readFileSync52(voicePaths.pid, "utf8").trim(), 10);
31118
+ const pid = Number.parseInt(readFileSync53(voicePaths.pid, "utf8").trim(), 10);
30803
31119
  try {
30804
31120
  process.kill(pid, "SIGTERM");
30805
31121
  console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
@@ -31515,7 +31831,7 @@ function registerWatch(program2) {
31515
31831
 
31516
31832
  // src/commands/roam/auth.ts
31517
31833
  import { randomBytes } from "crypto";
31518
- import chalk216 from "chalk";
31834
+ import chalk218 from "chalk";
31519
31835
 
31520
31836
  // src/commands/roam/waitForCallback.ts
31521
31837
  import { createServer as createServer3 } from "http";
@@ -31646,13 +31962,13 @@ async function auth() {
31646
31962
  saveGlobalConfig(config);
31647
31963
  const state = randomBytes(16).toString("hex");
31648
31964
  console.log(
31649
- chalk216.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
31965
+ chalk218.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
31650
31966
  );
31651
- console.log(chalk216.white("http://localhost:14523/callback\n"));
31652
- console.log(chalk216.blue("Opening browser for authorization..."));
31653
- console.log(chalk216.dim("Waiting for authorization callback..."));
31967
+ console.log(chalk218.white("http://localhost:14523/callback\n"));
31968
+ console.log(chalk218.blue("Opening browser for authorization..."));
31969
+ console.log(chalk218.dim("Waiting for authorization callback..."));
31654
31970
  const { code, redirectUri } = await authorizeInBrowser(clientId, state);
31655
- console.log(chalk216.dim("Exchanging code for tokens..."));
31971
+ console.log(chalk218.dim("Exchanging code for tokens..."));
31656
31972
  const tokens = await exchangeToken({
31657
31973
  code,
31658
31974
  clientId,
@@ -31668,13 +31984,13 @@ async function auth() {
31668
31984
  };
31669
31985
  saveGlobalConfig(config);
31670
31986
  console.log(
31671
- chalk216.green("Roam credentials and tokens saved to ~/.assist.yml")
31987
+ chalk218.green("Roam credentials and tokens saved to ~/.assist.yml")
31672
31988
  );
31673
31989
  }
31674
31990
 
31675
31991
  // src/commands/roam/postRoamActivity.ts
31676
31992
  import { execFileSync as execFileSync18 } from "child_process";
31677
- import { readdirSync as readdirSync20, readFileSync as readFileSync53, statSync as statSync11 } from "fs";
31993
+ import { readdirSync as readdirSync20, readFileSync as readFileSync54, statSync as statSync11 } from "fs";
31678
31994
  import { join as join86 } from "path";
31679
31995
  function findPortFile(roamDir) {
31680
31996
  let entries;
@@ -31700,7 +32016,7 @@ function postRoamActivity(app, event) {
31700
32016
  if (!portFile) return;
31701
32017
  let port;
31702
32018
  try {
31703
- port = readFileSync53(portFile, "utf8").trim();
32019
+ port = readFileSync54(portFile, "utf8").trim();
31704
32020
  } catch {
31705
32021
  return;
31706
32022
  }
@@ -32019,7 +32335,7 @@ import { execSync as execSync60 } from "child_process";
32019
32335
  import { existsSync as existsSync72, mkdirSync as mkdirSync31, unlinkSync as unlinkSync22, writeFileSync as writeFileSync46 } from "fs";
32020
32336
  import { tmpdir as tmpdir8 } from "os";
32021
32337
  import { join as join89, resolve as resolve20 } from "path";
32022
- import chalk217 from "chalk";
32338
+ import chalk219 from "chalk";
32023
32339
 
32024
32340
  // src/commands/screenshot/captureWindowPs1.ts
32025
32341
  var captureWindowPs1 = `
@@ -32170,13 +32486,13 @@ function screenshot(processName) {
32170
32486
  const config = loadConfig();
32171
32487
  const outputDir = resolve20(config.screenshot.outputDir);
32172
32488
  const outputPath = buildOutputPath(outputDir, processName);
32173
- console.log(chalk217.gray(`Capturing window for process "${processName}" ...`));
32489
+ console.log(chalk219.gray(`Capturing window for process "${processName}" ...`));
32174
32490
  try {
32175
32491
  runPowerShellScript(processName, outputPath);
32176
- console.log(chalk217.green(`Screenshot saved: ${outputPath}`));
32492
+ console.log(chalk219.green(`Screenshot saved: ${outputPath}`));
32177
32493
  } catch (error) {
32178
32494
  const msg = error instanceof Error ? error.message : String(error);
32179
- console.error(chalk217.red(`Failed to capture screenshot: ${msg}`));
32495
+ console.error(chalk219.red(`Failed to capture screenshot: ${msg}`));
32180
32496
  process.exit(1);
32181
32497
  }
32182
32498
  }
@@ -32232,11 +32548,11 @@ function applyLine(result, pending, line) {
32232
32548
  }
32233
32549
 
32234
32550
  // src/commands/sessions/daemon/readDaemonPidFile.ts
32235
- import { readFileSync as readFileSync54 } from "fs";
32551
+ import { readFileSync as readFileSync55 } from "fs";
32236
32552
  function readDaemonPidFile() {
32237
32553
  try {
32238
32554
  const pid = Number.parseInt(
32239
- readFileSync54(daemonPaths.pid, "utf8").trim(),
32555
+ readFileSync55(daemonPaths.pid, "utf8").trim(),
32240
32556
  10
32241
32557
  );
32242
32558
  return Number.isInteger(pid) ? pid : void 0;
@@ -36267,14 +36583,14 @@ async function defaultConnect() {
36267
36583
  }
36268
36584
 
36269
36585
  // src/commands/sessions/daemon/hasPersistedWindowsSessions.ts
36270
- import { existsSync as existsSync84, readFileSync as readFileSync56 } from "fs";
36586
+ import { existsSync as existsSync84, readFileSync as readFileSync57 } from "fs";
36271
36587
  import { posix as posix3 } from "path";
36272
36588
  function hasPersistedWindowsSessions() {
36273
36589
  const sessionsFile = windowsSessionsFileFromWsl();
36274
36590
  if (!sessionsFile) return false;
36275
36591
  try {
36276
36592
  if (!existsSync84(sessionsFile)) return false;
36277
- const data = JSON.parse(readFileSync56(sessionsFile, "utf8"));
36593
+ const data = JSON.parse(readFileSync57(sessionsFile, "utf8"));
36278
36594
  return Array.isArray(data) && data.length > 0;
36279
36595
  } catch (error) {
36280
36596
  const message3 = error instanceof Error ? error.message : String(error);
@@ -37692,7 +38008,7 @@ function handleConnection(socket, manager) {
37692
38008
  import { unlinkSync as unlinkSync23, writeFileSync as writeFileSync47 } from "fs";
37693
38009
 
37694
38010
  // src/commands/sessions/daemon/startPidFileWatchdog.ts
37695
- import { readFileSync as readFileSync57 } from "fs";
38011
+ import { readFileSync as readFileSync58 } from "fs";
37696
38012
  var WATCHDOG_INTERVAL_MS = 5e3;
37697
38013
  function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
37698
38014
  const timer = setInterval(() => {
@@ -37703,7 +38019,7 @@ function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
37703
38019
  }
37704
38020
  function ownsPidFile() {
37705
38021
  try {
37706
- return readFileSync57(daemonPaths.pid, "utf8").trim() === String(process.pid);
38022
+ return readFileSync58(daemonPaths.pid, "utf8").trim() === String(process.pid);
37707
38023
  } catch {
37708
38024
  return false;
37709
38025
  }
@@ -37953,7 +38269,7 @@ function registerSetStatusCommand(cmd) {
37953
38269
 
37954
38270
  // src/commands/sessions/summarise/index.ts
37955
38271
  import * as fs56 from "fs";
37956
- import chalk218 from "chalk";
38272
+ import chalk220 from "chalk";
37957
38273
 
37958
38274
  // src/commands/sessions/summarise/shared.ts
37959
38275
  import * as fs55 from "fs";
@@ -38012,22 +38328,22 @@ ${firstMessage}`);
38012
38328
  async function summarise2(options2) {
38013
38329
  const files = await discoverSessionFiles();
38014
38330
  if (files.length === 0) {
38015
- console.log(chalk218.yellow("No sessions found."));
38331
+ console.log(chalk220.yellow("No sessions found."));
38016
38332
  return;
38017
38333
  }
38018
38334
  const toProcess = selectCandidates(files, options2);
38019
38335
  if (toProcess.length === 0) {
38020
- console.log(chalk218.green("All sessions already summarised."));
38336
+ console.log(chalk220.green("All sessions already summarised."));
38021
38337
  return;
38022
38338
  }
38023
38339
  console.log(
38024
- chalk218.cyan(
38340
+ chalk220.cyan(
38025
38341
  `Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
38026
38342
  )
38027
38343
  );
38028
38344
  const { succeeded, failed: failed2 } = processSessions(toProcess);
38029
38345
  console.log(
38030
- chalk218.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk218.yellow(`, ${failed2} skipped`) : "")
38346
+ chalk220.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk220.yellow(`, ${failed2} skipped`) : "")
38031
38347
  );
38032
38348
  }
38033
38349
  function selectCandidates(files, options2) {
@@ -38047,16 +38363,16 @@ function processSessions(files) {
38047
38363
  let failed2 = 0;
38048
38364
  for (let i = 0; i < files.length; i++) {
38049
38365
  const file = files[i];
38050
- process.stdout.write(chalk218.dim(` [${i + 1}/${files.length}] `));
38366
+ process.stdout.write(chalk220.dim(` [${i + 1}/${files.length}] `));
38051
38367
  const summary = summariseSession(file);
38052
38368
  if (summary) {
38053
38369
  writeSummary(file, summary);
38054
38370
  succeeded++;
38055
- process.stdout.write(`${chalk218.green("\u2713")} ${summary}
38371
+ process.stdout.write(`${chalk220.green("\u2713")} ${summary}
38056
38372
  `);
38057
38373
  } else {
38058
38374
  failed2++;
38059
- process.stdout.write(` ${chalk218.yellow("skip")}
38375
+ process.stdout.write(` ${chalk220.yellow("skip")}
38060
38376
  `);
38061
38377
  }
38062
38378
  }
@@ -38077,7 +38393,7 @@ function registerSessions(program2) {
38077
38393
  }
38078
38394
 
38079
38395
  // src/commands/statusLine.ts
38080
- import chalk220 from "chalk";
38396
+ import chalk222 from "chalk";
38081
38397
 
38082
38398
  // src/shared/contextLevel.ts
38083
38399
  function contextLevel(pct) {
@@ -38087,7 +38403,7 @@ function contextLevel(pct) {
38087
38403
  }
38088
38404
 
38089
38405
  // src/commands/buildLimitsSegment.ts
38090
- import chalk219 from "chalk";
38406
+ import chalk221 from "chalk";
38091
38407
 
38092
38408
  // src/shared/rateLimitLevel.ts
38093
38409
  var FIVE_HOUR_SECONDS = 5 * 3600;
@@ -38125,9 +38441,9 @@ function rateLimitLevel(pct, resetsAt, windowSeconds, now) {
38125
38441
 
38126
38442
  // src/commands/buildLimitsSegment.ts
38127
38443
  var LEVEL_COLOR = {
38128
- ok: chalk219.green,
38129
- warn: chalk219.yellow,
38130
- over: chalk219.red
38444
+ ok: chalk221.green,
38445
+ warn: chalk221.yellow,
38446
+ over: chalk221.red
38131
38447
  };
38132
38448
  function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel, now) {
38133
38449
  const level = rateLimitLevel(pct, resetsAt, windowSeconds, now);
@@ -38158,7 +38474,7 @@ function buildLimitsSegment(rateLimits) {
38158
38474
  }
38159
38475
 
38160
38476
  // src/commands/readGitBranch.ts
38161
- import { readFileSync as readFileSync59, statSync as statSync15 } from "fs";
38477
+ import { readFileSync as readFileSync60, statSync as statSync15 } from "fs";
38162
38478
  import { isAbsolute as isAbsolute4, join as join95, resolve as resolve22 } from "path";
38163
38479
  function resolveGitDir(cwd) {
38164
38480
  const dotGit = join95(cwd, ".git");
@@ -38173,7 +38489,7 @@ function resolveGitDir(cwd) {
38173
38489
  }
38174
38490
  let contents;
38175
38491
  try {
38176
- contents = readFileSync59(dotGit, "utf8");
38492
+ contents = readFileSync60(dotGit, "utf8");
38177
38493
  } catch {
38178
38494
  return null;
38179
38495
  }
@@ -38191,7 +38507,7 @@ function readGitBranch(cwd) {
38191
38507
  }
38192
38508
  let head;
38193
38509
  try {
38194
- head = readFileSync59(join95(gitDir, "HEAD"), "utf8");
38510
+ head = readFileSync60(join95(gitDir, "HEAD"), "utf8");
38195
38511
  } catch {
38196
38512
  return null;
38197
38513
  }
@@ -38223,7 +38539,7 @@ async function relayUsage(claudeSessionId, transcriptPath2, usedPct) {
38223
38539
  }
38224
38540
 
38225
38541
  // src/commands/statusLine.ts
38226
- chalk220.level = 3;
38542
+ chalk222.level = 3;
38227
38543
  function formatNumber(num) {
38228
38544
  return num.toLocaleString("en-US");
38229
38545
  }
@@ -38231,9 +38547,9 @@ function colorizePercent(pct) {
38231
38547
  const label2 = `${Math.round(pct)}%`;
38232
38548
  switch (contextLevel(pct)) {
38233
38549
  case "red":
38234
- return chalk220.red(label2);
38550
+ return chalk222.red(label2);
38235
38551
  case "yellow":
38236
- return chalk220.yellow(label2);
38552
+ return chalk222.yellow(label2);
38237
38553
  default:
38238
38554
  return label2;
38239
38555
  }
@@ -38246,7 +38562,7 @@ async function statusLine() {
38246
38562
  const usedPct = data.context_window.used_percentage ?? 0;
38247
38563
  const dir = data.workspace?.current_dir ?? data.cwd;
38248
38564
  const branch2 = dir ? readGitBranch(toGitCwd(dir)) : null;
38249
- const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${chalk220.cyan(branch2)} | ` : "";
38565
+ const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${chalk222.cyan(branch2)} | ` : "";
38250
38566
  console.log(
38251
38567
  `${branchSegment}${model} | Tokens - ${formatNumber(totalIn)} \u2191 : ${formatNumber(totalOut)} \u2193 | Context - ${colorizePercent(usedPct)}${buildLimitsSegment(data.rate_limits)}`
38252
38568
  );
@@ -38316,10 +38632,10 @@ async function update2() {
38316
38632
  }
38317
38633
 
38318
38634
  // src/reportCliError.ts
38319
- import chalk221 from "chalk";
38635
+ import chalk223 from "chalk";
38320
38636
  function reportCliError(error) {
38321
- if (error instanceof InvalidItemIdError || error instanceof AmbiguousRepoConfigError || error instanceof UnknownRepoConfigError || error instanceof MissingRunCwdError) {
38322
- console.error(chalk221.red(error.message));
38637
+ if (error instanceof InvalidItemIdError || error instanceof AmbiguousRepoConfigError || error instanceof UnknownRepoConfigError || error instanceof MissingRunCwdError || error instanceof MiroExtractError) {
38638
+ console.error(chalk223.red(error.message));
38323
38639
  } else {
38324
38640
  console.error(error);
38325
38641
  }
@@ -38362,6 +38678,7 @@ registerGithub(program);
38362
38678
  registerHandover(program);
38363
38679
  registerJira(program);
38364
38680
  registerMermaid(program);
38681
+ registerMiro(program);
38365
38682
  registerPrs(program);
38366
38683
  registerRoam(program);
38367
38684
  registerBacklog(program);