@staff0rd/assist 0.577.0 → 0.579.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.577.0",
9
+ version: "0.579.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -13973,6 +13973,12 @@ ${quoted}
13973
13973
  }
13974
13974
 
13975
13975
  // src/commands/sessions/shared/toPreviewDecision.ts
13976
+ function toSelection(value) {
13977
+ const selection = value;
13978
+ if (typeof selection?.topLeft !== "string" || typeof selection.bottomRight !== "string")
13979
+ return void 0;
13980
+ return { topLeft: selection.topLeft, bottomRight: selection.bottomRight };
13981
+ }
13976
13982
  function toPreviewDecision(msg) {
13977
13983
  if (msg.decision !== "approve" && msg.decision !== "reject") return null;
13978
13984
  return {
@@ -13983,7 +13989,8 @@ function toPreviewDecision(msg) {
13983
13989
  body: typeof msg.body === "string" ? msg.body : void 0,
13984
13990
  reviewAfter: msg.reviewAfter === true,
13985
13991
  announceAfter: msg.announceAfter === true,
13986
- draft: typeof msg.draft === "boolean" ? msg.draft : void 0
13992
+ draft: typeof msg.draft === "boolean" ? msg.draft : void 0,
13993
+ selection: toSelection(msg.selection)
13987
13994
  };
13988
13995
  }
13989
13996
 
@@ -16820,6 +16827,12 @@ function findBuiltinDenyRaw(rawCommand) {
16820
16827
  // src/shared/isApprovedRead.ts
16821
16828
  import { resolve as resolve13, sep } from "path";
16822
16829
 
16830
+ // src/shared/appliesFixStructure.ts
16831
+ var APPLY_RE = /^assist\s+github\s+issue\s+fix-structure\b.*\s--apply\b/;
16832
+ function appliesFixStructure(command) {
16833
+ return APPLY_RE.test(command);
16834
+ }
16835
+
16823
16836
  // src/shared/tokenize.ts
16824
16837
  function tokenize(command) {
16825
16838
  const tokens = [];
@@ -17046,6 +17059,7 @@ function isApprovedRead(command, toolName = "Bash") {
17046
17059
  if (isCdToCwd(command)) return "cd to current directory";
17047
17060
  const cdRead = isCdToReadAllowedDir(command);
17048
17061
  if (cdRead) return cdRead;
17062
+ if (appliesFixStructure(command)) return void 0;
17049
17063
  const matchedRead = findCliRead(command);
17050
17064
  if (matchedRead) return `Read-only CLI command: ${matchedRead}`;
17051
17065
  const matchedWrite = findCliWrite(command);
@@ -20695,309 +20709,178 @@ function parseTopCount(value) {
20695
20709
  return Number.parseInt(value, 10);
20696
20710
  }
20697
20711
 
20698
- // src/commands/github/issue/commentIssue.ts
20699
- import { execFileSync as execFileSync6 } from "child_process";
20712
+ // src/commands/github/issue/fixStructure/applyAndVerifySubtree.ts
20713
+ import chalk163 from "chalk";
20700
20714
 
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
- }
20715
+ // src/commands/github/issue/fixStructure/applyFixStructurePlan.ts
20716
+ import chalk162 from "chalk";
20725
20717
 
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"
20718
+ // src/shared/runGhGraphqlJson.ts
20719
+ import { spawnSync as spawnSync5 } from "child_process";
20720
+ function runGhGraphqlJson(query, vars = {}) {
20721
+ const result = spawnSync5("gh", ["api", "graphql", "--input", "-"], {
20722
+ encoding: "utf8",
20723
+ windowsHide: true,
20724
+ input: JSON.stringify({ query, variables: vars }),
20725
+ maxBuffer: 64 * 1024 * 1024
20738
20726
  });
20727
+ if (result.status !== 0) throw new Error(result.stderr || result.stdout);
20728
+ throwOnGraphqlErrors(result.stdout);
20729
+ return result.stdout;
20739
20730
  }
20740
20731
 
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}`);
20732
+ // src/commands/github/issue/fixStructure/removeIssueLabels.ts
20733
+ var MUTATION = `mutation($labelableId: ID!, $labelIds: [ID!]!) {
20734
+ removeLabelsFromLabelable(input: { labelableId: $labelableId, labelIds: $labelIds }) {
20735
+ labelable { __typename }
20736
+ }
20737
+ }`;
20738
+ function removeIssueLabels(issueId, labelIds) {
20739
+ runGhGraphqlJson(MUTATION, { labelableId: issueId, labelIds });
20765
20740
  }
20766
20741
 
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
- });
20742
+ // src/commands/github/issue/fixStructure/updateIssueType.ts
20743
+ var MUTATION2 = `mutation($issueId: ID!, $issueTypeId: ID!) {
20744
+ updateIssueIssueType(input: { issueId: $issueId, issueTypeId: $issueTypeId }) {
20745
+ issue { id }
20746
+ }
20747
+ }`;
20748
+ function updateIssueType(issueId, issueTypeId) {
20749
+ runGhGraphqlJson(MUTATION2, { issueId, issueTypeId });
20783
20750
  }
20784
20751
 
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);
20752
+ // src/commands/github/issue/fixStructure/writeLineNow.ts
20753
+ import { writeSync as writeSync2 } from "fs";
20754
+ function writeLineNow(line) {
20755
+ const text18 = `${line}
20756
+ `;
20801
20757
  try {
20802
- execFileSync7("gh", args, { stdio: "inherit" });
20758
+ writeSync2(1, text18);
20803
20759
  } catch {
20804
- process.exit(1);
20760
+ process.stdout.write(text18);
20805
20761
  }
20806
20762
  }
20807
20763
 
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);
20764
+ // src/commands/github/issue/fixStructure/applyFixStructurePlan.ts
20765
+ function applyFixStructurePlan(plan2) {
20766
+ for (const entry of plan2.entries) {
20767
+ const where = chalk162.cyan(`${entry.issue.repo}#${entry.issue.number}`);
20768
+ const { typeChange, labelRemovals } = entry;
20769
+ if (typeChange) {
20770
+ writeLineNow(
20771
+ `${where} type ${typeChange.from ?? "no type"} -> ${typeChange.to}`
20772
+ );
20773
+ updateIssueType(entry.issue.id, typeChange.typeId);
20774
+ }
20775
+ if (labelRemovals.length > 0) {
20776
+ writeLineNow(
20777
+ `${where} removing ${labelRemovals.map((label2) => label2.name).join(", ")}`
20778
+ );
20779
+ removeIssueLabels(
20780
+ entry.issue.id,
20781
+ labelRemovals.map((label2) => label2.id)
20782
+ );
20783
+ }
20836
20784
  }
20837
20785
  }
20838
20786
 
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
- }
20787
+ // src/commands/github/issue/fixStructure/assertNothingTooDeep.ts
20788
+ function describe2(entry, leaf) {
20789
+ const parent = entry.parent;
20790
+ const under = parent ? ` under ${parent.repo}#${parent.number}` : "";
20791
+ return `${entry.issue.repo}#${entry.issue.number}${under} sits below ${leaf}, the leaf level`;
20865
20792
  }
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
20793
+ function assertNothingTooDeep(tooDeep, chain2) {
20794
+ if (tooDeep.length === 0) return;
20795
+ const leaf = chain2[chain2.length - 1] ?? "the leaf";
20796
+ throw new Error(
20797
+ [
20798
+ ...tooDeep.map((entry) => describe2(entry, leaf)),
20799
+ "Re-parent those issues or aim the run at a deeper target"
20800
+ ].join("\n")
20873
20801
  );
20874
20802
  }
20875
20803
 
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
- `
20804
+ // src/commands/github/issue/fixStructure/assertNoResidualDrift.ts
20805
+ function describe3(entry) {
20806
+ const where = `${entry.issue.repo}#${entry.issue.number}`;
20807
+ const notes = [];
20808
+ if (entry.typeChange) {
20809
+ notes.push(
20810
+ `${where} is still ${entry.typeChange.from ?? "untyped"}, not ${entry.typeChange.to}`
20811
+ );
20812
+ }
20813
+ for (const label2 of entry.labelRemovals) {
20814
+ notes.push(`${where} still carries ${label2.name}`);
20815
+ }
20816
+ return notes;
20817
+ }
20818
+ function assertNoResidualDrift(plan2, chain2) {
20819
+ assertNothingTooDeep(plan2.tooDeep, chain2);
20820
+ const residual = plan2.entries.flatMap(describe3);
20821
+ if (residual.length === 0) return;
20822
+ throw new Error(
20823
+ ["The subtree still drifts after applying:", ...residual].join("\n")
20886
20824
  );
20887
- return bodyPath;
20888
20825
  }
20889
20826
 
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
- }
20827
+ // src/commands/github/issue/fixStructure/issueFieldsFragment.ts
20828
+ var issueFieldsFragment = `fragment issueFields on Issue {
20829
+ id
20830
+ number
20831
+ title
20832
+ issueType { name }
20833
+ repository { nameWithOwner }
20834
+ labels(first: 100) { nodes { id name } pageInfo { hasNextPage } }
20835
+ subIssues(first: 100) { nodes { id } pageInfo { hasNextPage } }
20836
+ }`;
20915
20837
 
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);
20838
+ // src/commands/github/issue/fixStructure/parseIssueNode.ts
20839
+ function parseIssueNode(node) {
20840
+ const raw = node;
20841
+ const repo = raw.repository?.nameWithOwner ?? "";
20842
+ const where = `${repo}#${raw.number}`;
20843
+ if (raw.labels?.pageInfo?.hasNextPage) {
20844
+ throw new Error(
20845
+ `${where} carries more than 100 labels, which is not supported`
20846
+ );
20925
20847
  }
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}`
20848
+ if (raw.subIssues?.pageInfo?.hasNextPage) {
20849
+ throw new Error(
20850
+ `${where} has more than 100 sub-issues, which is not supported`
20933
20851
  );
20934
- process.exit(1);
20935
20852
  }
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;
20853
+ return {
20854
+ id: raw.id,
20855
+ number: raw.number,
20856
+ title: raw.title,
20857
+ repo,
20858
+ typeName: raw.issueType?.name ?? null,
20859
+ labels: (raw.labels?.nodes ?? []).filter((label2) => label2 !== null),
20860
+ childIds: (raw.subIssues?.nodes ?? []).filter((child) => child !== null).map((child) => child.id)
20861
+ };
20961
20862
  }
20962
20863
 
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
- }
20864
+ // src/commands/github/issue/fixStructure/fetchRootIssue.ts
20865
+ var QUERY = `query($owner: String!, $repo: String!, $number: Int!) {
20866
+ repository(owner: $owner, name: $repo) {
20867
+ issue(number: $number) { ...issueFields }
20868
+ }
20973
20869
  }
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;
20870
+ ${issueFieldsFragment}`;
20871
+ function fetchRootIssue(target) {
20872
+ const raw = runGhGraphqlJson(QUERY, {
20873
+ owner: target.owner,
20874
+ repo: target.repo,
20875
+ number: target.number
20876
+ });
20877
+ const issue = JSON.parse(raw).data?.repository?.issue;
20878
+ if (!issue) {
20879
+ throw new Error(
20880
+ `No issue ${target.owner}/${target.repo}#${target.number} could be read`
20881
+ );
20986
20882
  }
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
- );
20883
+ return parseIssueNode(issue);
21001
20884
  }
21002
20885
 
21003
20886
  // src/commands/github/issue/fixStructure/matchedLabels.ts
@@ -21095,127 +20978,110 @@ function buildFixStructurePlan(issues, options2) {
21095
20978
  };
21096
20979
  }
21097
20980
 
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;
20981
+ // src/commands/github/issue/fixStructure/fetchSubtreeIssues.ts
20982
+ var QUERY2 = `query($ids: [ID!]!) {
20983
+ nodes(ids: $ids) { ... on Issue { ...issueFields } }
21110
20984
  }
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
- );
20985
+ ${issueFieldsFragment}`;
20986
+ var BATCH = 50;
20987
+ function fetchSubtreeIssues(ids) {
20988
+ const issues = [];
20989
+ for (let start3 = 0; start3 < ids.length; start3 += BATCH) {
20990
+ const raw = runGhGraphqlJson(QUERY2, {
20991
+ ids: ids.slice(start3, start3 + BATCH)
20992
+ });
20993
+ const nodes = JSON.parse(raw).data?.nodes ?? [];
20994
+ for (const node of nodes) {
20995
+ if (node) issues.push(parseIssueNode(node));
20996
+ }
21132
20997
  }
21133
- if (raw.subIssues?.pageInfo?.hasNextPage) {
21134
- throw new Error(
21135
- `${where} has more than 100 sub-issues, which is not supported`
21136
- );
20998
+ return issues;
20999
+ }
21000
+
21001
+ // src/commands/github/issue/fixStructure/walkSubtree.ts
21002
+ function walkSubtree(root, maxDepth, fetchIssues = fetchSubtreeIssues) {
21003
+ const placed = [{ ...root, depth: 0, parentId: null }];
21004
+ const seen = /* @__PURE__ */ new Set([root.id]);
21005
+ let frontier = placed;
21006
+ for (let depth = 1; depth <= maxDepth && frontier.length > 0; depth += 1) {
21007
+ const parentOf2 = /* @__PURE__ */ new Map();
21008
+ for (const parent of frontier) {
21009
+ for (const childId of parent.childIds) {
21010
+ if (seen.has(childId)) continue;
21011
+ seen.add(childId);
21012
+ parentOf2.set(childId, parent.id);
21013
+ }
21014
+ }
21015
+ if (parentOf2.size === 0) break;
21016
+ const children = fetchIssues([...parentOf2.keys()]).map((issue) => ({
21017
+ ...issue,
21018
+ depth,
21019
+ parentId: parentOf2.get(issue.id) ?? null
21020
+ }));
21021
+ placed.push(...children);
21022
+ frontier = children;
21137
21023
  }
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
- };
21024
+ return placed;
21147
21025
  }
21148
21026
 
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
- }
21027
+ // src/commands/github/issue/fixStructure/planSubtree.ts
21028
+ function planSubtree(root, context) {
21029
+ const depth = context.chain.length - context.rootLevelIndex;
21030
+ return buildFixStructurePlan(walkSubtree(root, depth), context);
21154
21031
  }
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);
21032
+
21033
+ // src/commands/github/issue/fixStructure/applyAndVerifySubtree.ts
21034
+ function applyAndVerifySubtree(target, plan2, context) {
21035
+ if (plan2.typeChangeCount === 0 && plan2.labelRemovalCount === 0) return;
21036
+ applyFixStructurePlan(plan2);
21037
+ writeLineNow(chalk163.dim("Re-walking the subtree to confirm"));
21038
+ assertNoResidualDrift(
21039
+ planSubtree(fetchRootIssue(target), context),
21040
+ context.chain
21041
+ );
21042
+ writeLineNow(chalk163.green("Subtree normalised"));
21169
21043
  }
21170
21044
 
21171
21045
  // src/commands/github/issue/fixStructure/printFixStructurePlan.ts
21172
- import chalk162 from "chalk";
21046
+ import chalk164 from "chalk";
21173
21047
  function annotate(entry) {
21174
21048
  const notes = [];
21175
21049
  if (entry.level === null) {
21176
- notes.push(chalk162.red("deeper than the leaf level"));
21050
+ notes.push(chalk164.red("deeper than the leaf level"));
21177
21051
  } else if (entry.typeChange) {
21178
21052
  notes.push(
21179
- chalk162.yellow(
21053
+ chalk164.yellow(
21180
21054
  `${entry.typeChange.from ?? "no type"} -> ${entry.typeChange.to}`
21181
21055
  )
21182
21056
  );
21183
21057
  } else {
21184
- notes.push(chalk162.dim(entry.issue.typeName ?? "no type"));
21058
+ notes.push(chalk164.dim(entry.issue.typeName ?? "no type"));
21185
21059
  }
21186
21060
  for (const label2 of entry.labelRemovals) {
21187
- notes.push(chalk162.yellow(`-${label2.name}`));
21061
+ notes.push(chalk164.yellow(`-${label2.name}`));
21188
21062
  }
21189
21063
  return notes;
21190
21064
  }
21191
21065
  function formatCount(count8, noun) {
21192
21066
  return `${count8} ${noun}${count8 === 1 ? "" : "s"}`;
21193
21067
  }
21194
- function printFixStructurePlan(plan2, chain2) {
21195
- console.log(chalk162.dim(`chain: ${chain2.join(" > ")}`));
21068
+ function printFixStructurePlan(plan2, chain2, apply) {
21069
+ writeLineNow(chalk164.dim(`chain: ${chain2.join(" > ")}`));
21196
21070
  for (const entry of plan2.entries) {
21197
21071
  const indent3 = " ".repeat(entry.issue.depth);
21198
- const name = chalk162.cyan(`${entry.issue.repo}#${entry.issue.number}`);
21199
- console.log(
21072
+ const name = chalk164.cyan(`${entry.issue.repo}#${entry.issue.number}`);
21073
+ writeLineNow(
21200
21074
  `${indent3}${name} ${entry.issue.title} [${annotate(entry).join(", ")}]`
21201
21075
  );
21202
21076
  }
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
21077
  if (plan2.typeChangeCount === 0 && plan2.labelRemovalCount === 0) {
21212
- console.log(chalk162.green("Nothing to change"));
21078
+ writeLineNow(chalk164.green("Nothing to change"));
21213
21079
  return;
21214
21080
  }
21215
- console.log(
21081
+ writeLineNow(
21216
21082
  `${formatCount(plan2.typeChangeCount, "type change")}, ${formatCount(plan2.labelRemovalCount, "label removal")} planned`
21217
21083
  );
21218
- console.log(chalk162.dim("Dry run \u2014 nothing written"));
21084
+ if (!apply) writeLineNow(chalk164.dim("Dry run \u2014 nothing written"));
21219
21085
  }
21220
21086
 
21221
21087
  // src/commands/github/issue/fixStructure/resolveFixStructureTarget.ts
@@ -21251,7 +21117,7 @@ function resolveFixStructureTarget(target, repo) {
21251
21117
  }
21252
21118
 
21253
21119
  // src/commands/github/issue/fixStructure/resolveOrgIssueTypes.ts
21254
- var QUERY2 = `query($owner: String!) {
21120
+ var QUERY3 = `query($owner: String!) {
21255
21121
  organization(login: $owner) {
21256
21122
  issueTypes(first: 50) { nodes { id name } }
21257
21123
  }
@@ -21264,7 +21130,7 @@ function missingOrg(owner) {
21264
21130
  function resolveOrgIssueTypes(owner) {
21265
21131
  let raw;
21266
21132
  try {
21267
- raw = runGhGraphqlJson(QUERY2, { owner });
21133
+ raw = runGhGraphqlJson(QUERY3, { owner });
21268
21134
  } catch (error) {
21269
21135
  const message3 = error instanceof Error ? error.message : String(error);
21270
21136
  if (message3.includes("Could not resolve to an Organization")) {
@@ -21307,52 +21173,6 @@ function resolveRootLevelIndex(chain2, targetTypeName, level) {
21307
21173
  // src/commands/github/issue/fixStructure/types.ts
21308
21174
  var defaultTypeChain = ["Epic", "Story", "Subtask"];
21309
21175
 
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
21176
  // src/commands/github/issue/fixStructure/fixStructure.ts
21357
21177
  function fixStructure(target, options2) {
21358
21178
  const chain2 = defaultTypeChain;
@@ -21364,15 +21184,17 @@ function fixStructure(target, options2) {
21364
21184
  root.typeName,
21365
21185
  options2.level
21366
21186
  );
21367
- const issueTypes = resolveOrgIssueTypes(resolved.owner);
21368
- const issues = walkSubtree(root, chain2.length - index3);
21369
- const plan2 = buildFixStructurePlan(issues, {
21187
+ const context = {
21370
21188
  chain: chain2,
21371
21189
  rootLevelIndex: index3,
21372
21190
  rootAsserted: asserted,
21373
- issueTypes
21374
- });
21375
- printFixStructurePlan(plan2, chain2);
21191
+ issueTypes: resolveOrgIssueTypes(resolved.owner),
21192
+ stripLabels: []
21193
+ };
21194
+ const plan2 = planSubtree(root, context);
21195
+ printFixStructurePlan(plan2, chain2, options2.apply === true);
21196
+ assertNothingTooDeep(plan2.tooDeep, chain2);
21197
+ if (options2.apply) applyAndVerifySubtree(resolved, plan2, context);
21376
21198
  } catch (error) {
21377
21199
  console.error(error instanceof Error ? error.message : String(error));
21378
21200
  process.exit(1);
@@ -21383,19 +21205,20 @@ function fixStructure(target, options2) {
21383
21205
  var chain = defaultTypeChain.join(" > ");
21384
21206
  var levels = defaultTypeChain.map((name) => name.toLowerCase()).join("|");
21385
21207
  function registerFixStructure(issueCommand) {
21386
- issueCommand.command("fix-structure <target>").description("Report the issue type drift across one issue subtree").option(
21208
+ issueCommand.command("fix-structure <target>").description("Normalise the issue types across one issue subtree").option(
21387
21209
  "-R, --repo <owner/repo>",
21388
21210
  "Repository a bare issue number belongs to"
21389
21211
  ).option(
21390
21212
  "--level <level>",
21391
21213
  `The target's own position in the ${chain} chain, when it cannot be inferred from its type`
21392
- ).addHelpText(
21214
+ ).option("--apply", "Write the planned changes instead of reporting them").addHelpText(
21393
21215
  "after",
21394
21216
  `
21395
21217
  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
21218
  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
21219
  The target is owner/repo#number, a github.com issue URL, or a bare number with --repo.
21398
- This reports only; nothing is written.`
21220
+ 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.
21221
+ Anything nested below the leaf level fails the run before a single write, naming the offender and its parent.`
21399
21222
  ).action(fixStructure);
21400
21223
  }
21401
21224
 
@@ -21410,9 +21233,136 @@ async function readBodyArgument(value) {
21410
21233
  return body;
21411
21234
  }
21412
21235
 
21413
- // src/commands/registerGithubIssue.ts
21414
- function registerGithubIssue(githubCommand) {
21415
- const issueCommand = githubCommand.command("issue").description("GitHub issue utilities");
21236
+ // src/commands/github/issue/commentIssue.ts
21237
+ import { execFileSync as execFileSync6 } from "child_process";
21238
+
21239
+ // src/shared/validateProposedContent.ts
21240
+ function validateProposedContent(labels, title, body) {
21241
+ const { subject, context } = labels;
21242
+ if (title.toLowerCase().includes("claude")) {
21243
+ console.error(`Error: ${subject} title must not reference Claude`);
21244
+ process.exit(1);
21245
+ }
21246
+ if (body.toLowerCase().includes("claude")) {
21247
+ console.error(`Error: ${subject} body must not reference Claude`);
21248
+ process.exit(1);
21249
+ }
21250
+ const titleBacklogIds = findBacklogRefs(title);
21251
+ if (titleBacklogIds.length > 0) {
21252
+ console.error(
21253
+ backlogRefError(`${subject} title`, context, titleBacklogIds)
21254
+ );
21255
+ process.exit(1);
21256
+ }
21257
+ const bodyBacklogIds = findBacklogRefs(body);
21258
+ if (bodyBacklogIds.length > 0) {
21259
+ console.error(backlogRefError(`${subject} body`, context, bodyBacklogIds));
21260
+ process.exit(1);
21261
+ }
21262
+ }
21263
+
21264
+ // src/commands/github/issue/reviewProposedIssueComment.ts
21265
+ import { randomUUID as randomUUID7 } from "crypto";
21266
+ async function reviewProposedIssueComment(title, body) {
21267
+ const sessionId = process.env.ASSIST_SESSION_ID;
21268
+ if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
21269
+ await awaitPreviewApproval("GitHub issue comment preview", {
21270
+ sessionId,
21271
+ requestId: randomUUID7(),
21272
+ title,
21273
+ body,
21274
+ prNumber: null,
21275
+ kind: "github-issue-comment"
21276
+ });
21277
+ }
21278
+
21279
+ // src/commands/github/issue/commentIssue.ts
21280
+ var USAGE = "Usage: assist github issue comment <number> --body <body> [-R <owner>/<repo>]";
21281
+ async function commentIssue(numberArg, options2) {
21282
+ const number = Number.parseInt(numberArg, 10);
21283
+ if (!Number.isInteger(number) || number <= 0 || !options2.body) {
21284
+ console.error(USAGE);
21285
+ process.exit(1);
21286
+ }
21287
+ const { body } = options2;
21288
+ const target = options2.repo ? `${options2.repo}#${number}` : `issue #${number}`;
21289
+ validateProposedContent(
21290
+ { subject: "Comment", context: "GitHub issues" },
21291
+ "",
21292
+ body
21293
+ );
21294
+ await reviewProposedIssueComment(`Comment on ${target}`, body);
21295
+ const args = ["issue", "comment", String(number), "--body", body];
21296
+ if (options2.repo) args.push("--repo", options2.repo);
21297
+ try {
21298
+ execFileSync6("gh", args, { stdio: "inherit" });
21299
+ } catch {
21300
+ process.exit(1);
21301
+ }
21302
+ console.log(`Comment posted to ${target}`);
21303
+ }
21304
+
21305
+ // src/commands/github/issue/registerCommentIssue.ts
21306
+ function registerCommentIssue(issueCommand) {
21307
+ 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(
21308
+ "-R, --repo <owner/repo>",
21309
+ "Target repository (defaults to the current repo)"
21310
+ ).addHelpText(
21311
+ "after",
21312
+ "\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."
21313
+ ).action(
21314
+ async (number, options2) => {
21315
+ await commentIssue(number, {
21316
+ ...options2,
21317
+ body: options2.body ? await readBodyArgument(options2.body) : void 0
21318
+ });
21319
+ }
21320
+ );
21321
+ }
21322
+
21323
+ // src/commands/github/issue/createIssue.ts
21324
+ import { execFileSync as execFileSync7 } from "child_process";
21325
+
21326
+ // src/commands/github/issue/reviewProposedIssue.ts
21327
+ import { randomUUID as randomUUID8 } from "crypto";
21328
+ async function reviewProposedIssue(title, body) {
21329
+ const sessionId = process.env.ASSIST_SESSION_ID;
21330
+ if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
21331
+ await awaitPreviewApproval("GitHub issue preview", {
21332
+ sessionId,
21333
+ requestId: randomUUID8(),
21334
+ title,
21335
+ body,
21336
+ prNumber: null,
21337
+ kind: "github-issue"
21338
+ });
21339
+ }
21340
+
21341
+ // src/commands/github/issue/createIssue.ts
21342
+ var USAGE2 = "Usage: assist github issue create --title <title> --body <body> [-R <owner>/<repo>]";
21343
+ async function createIssue(options2) {
21344
+ if (!options2.title || !options2.body) {
21345
+ console.error(USAGE2);
21346
+ process.exit(1);
21347
+ }
21348
+ const { title, body } = options2;
21349
+ validateProposedContent(
21350
+ { subject: "Issue", context: "GitHub issues" },
21351
+ title,
21352
+ body
21353
+ );
21354
+ await reviewProposedIssue(title, body);
21355
+ const args = ["issue", "create", "--title", title, "--body", body];
21356
+ if (options2.repo) args.push("--repo", options2.repo);
21357
+ try {
21358
+ execFileSync7("gh", args, { stdio: "inherit" });
21359
+ } catch {
21360
+ process.exit(1);
21361
+ }
21362
+ }
21363
+
21364
+ // src/commands/github/issue/registerCreateIssue.ts
21365
+ function registerCreateIssue(issueCommand) {
21416
21366
  issueCommand.command("create").description("Create a GitHub issue").option("--title <title>", "Issue title").option("--body <body>", "Issue body").option(
21417
21367
  "-R, --repo <owner/repo>",
21418
21368
  "Target repository (defaults to the current repo)"
@@ -21420,6 +21370,205 @@ function registerGithubIssue(githubCommand) {
21420
21370
  "after",
21421
21371
  "\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
21372
  ).action(createIssue);
21373
+ }
21374
+
21375
+ // src/commands/sessions/shared/inWebSession.ts
21376
+ function inWebSession() {
21377
+ return process.env.ASSIST_SESSION === "1" && !!process.env.ASSIST_SESSION_ID;
21378
+ }
21379
+
21380
+ // src/commands/github/issue/fetchIssue.ts
21381
+ import { execFileSync as execFileSync8 } from "child_process";
21382
+ function fetchIssue2(number, repo) {
21383
+ const args = [
21384
+ "issue",
21385
+ "view",
21386
+ String(number),
21387
+ "--json",
21388
+ "title,body,updatedAt,url"
21389
+ ];
21390
+ if (repo) args.push("--repo", repo);
21391
+ let raw;
21392
+ try {
21393
+ raw = execFileSync8("gh", args, { encoding: "utf8" });
21394
+ } catch {
21395
+ console.error(`Could not fetch issue #${number} with gh issue view`);
21396
+ process.exit(1);
21397
+ }
21398
+ try {
21399
+ return JSON.parse(raw);
21400
+ } catch {
21401
+ console.error(`Could not parse the gh issue view output for #${number}`);
21402
+ process.exit(1);
21403
+ }
21404
+ }
21405
+
21406
+ // src/commands/github/issue/resumeIssueBody.ts
21407
+ import { existsSync as existsSync48, readFileSync as readFileSync37 } from "fs";
21408
+
21409
+ // src/commands/github/issue/issueWorkingFile.ts
21410
+ import { join as join50 } from "path";
21411
+ function issueWorkingFile(slug, number) {
21412
+ const [owner = "unknown", repo = "unknown"] = slug.split("/");
21413
+ const dir = join50(getStoreDir(), "github-issues", owner, repo);
21414
+ return {
21415
+ dir,
21416
+ bodyPath: join50(dir, `${number}.md`),
21417
+ metaPath: join50(dir, `${number}.json`)
21418
+ };
21419
+ }
21420
+
21421
+ // src/commands/github/issue/resumeIssueBody.ts
21422
+ function resumeIssueBody(slug, number, updatedAt) {
21423
+ const { bodyPath, metaPath } = issueWorkingFile(slug, number);
21424
+ if (!existsSync48(bodyPath) || !existsSync48(metaPath)) return void 0;
21425
+ try {
21426
+ const meta = JSON.parse(readFileSync37(metaPath, "utf8"));
21427
+ if (meta.updatedAt !== updatedAt) return void 0;
21428
+ return readFileSync37(bodyPath, "utf8");
21429
+ } catch {
21430
+ return void 0;
21431
+ }
21432
+ }
21433
+
21434
+ // src/commands/github/issue/validateIssueBody.ts
21435
+ function validateIssueBody(title, body) {
21436
+ validateProposedContent(
21437
+ { subject: "Issue", context: "GitHub issues" },
21438
+ title,
21439
+ body
21440
+ );
21441
+ }
21442
+
21443
+ // src/commands/github/issue/writeIssueWorkingFile.ts
21444
+ import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync31 } from "fs";
21445
+ function writeIssueWorkingFile(slug, number, target, updatedAt, body) {
21446
+ const { dir, bodyPath, metaPath } = issueWorkingFile(slug, number);
21447
+ mkdirSync16(dir, { recursive: true });
21448
+ writeFileSync31(bodyPath, body);
21449
+ writeFileSync31(
21450
+ metaPath,
21451
+ `${JSON.stringify({ target, updatedAt }, null, 2)}
21452
+ `
21453
+ );
21454
+ return bodyPath;
21455
+ }
21456
+
21457
+ // src/commands/github/issue/prepareIssueEdit.ts
21458
+ function slugFromUrl(url) {
21459
+ const match = /github\.com\/([^/]+\/[^/]+)\//.exec(url ?? "");
21460
+ return match ? match[1] : "unknown/unknown";
21461
+ }
21462
+ function prepareIssueEdit(number, repo, fresh) {
21463
+ const issue = fetchIssue2(number, repo);
21464
+ const slug = repo ?? slugFromUrl(issue.url);
21465
+ const target = `${slug}#${number}`;
21466
+ const resumed = fresh ? void 0 : resumeIssueBody(slug, number, issue.updatedAt);
21467
+ const body = resumed ?? issue.body;
21468
+ validateIssueBody(issue.title, body);
21469
+ const save = (markdown) => writeIssueWorkingFile(slug, number, target, issue.updatedAt, markdown);
21470
+ const bodyPath = save(body);
21471
+ if (resumed !== void 0)
21472
+ console.log(`Previewing the in-progress markdown from ${bodyPath}`);
21473
+ return {
21474
+ title: issue.title,
21475
+ target,
21476
+ updatedAt: issue.updatedAt,
21477
+ body,
21478
+ bodyPath,
21479
+ save
21480
+ };
21481
+ }
21482
+
21483
+ // src/commands/github/issue/pushIssueBody.ts
21484
+ import { execFileSync as execFileSync9 } from "child_process";
21485
+ function pushIssueBody(number, repo, bodyPath) {
21486
+ const args = ["issue", "edit", String(number), "--body-file", bodyPath];
21487
+ if (repo) args.push("--repo", repo);
21488
+ try {
21489
+ execFileSync9("gh", args, { stdio: "inherit" });
21490
+ } catch {
21491
+ process.exit(1);
21492
+ }
21493
+ }
21494
+
21495
+ // src/commands/github/issue/pushUnchangedIssue.ts
21496
+ function pushUnchangedIssue(number, repo, target, fetchedAt, bodyPath) {
21497
+ if (fetchIssue2(number, repo).updatedAt !== fetchedAt) {
21498
+ console.error(
21499
+ `${target} was updated on GitHub after it was fetched. Nothing was pushed; the markdown is at ${bodyPath}`
21500
+ );
21501
+ process.exit(1);
21502
+ }
21503
+ pushIssueBody(number, repo, bodyPath);
21504
+ console.log(`Issue body updated on ${target}`);
21505
+ }
21506
+
21507
+ // src/commands/github/issue/reviewProposedIssueEdit.ts
21508
+ import { randomUUID as randomUUID9 } from "crypto";
21509
+ async function reviewProposedIssueEdit(title, body, working) {
21510
+ const sessionId = process.env.ASSIST_SESSION_ID;
21511
+ if (process.env.ASSIST_SESSION !== "1" || !sessionId) return body;
21512
+ const decision = await awaitPreviewApproval(
21513
+ "GitHub issue edit preview",
21514
+ {
21515
+ sessionId,
21516
+ requestId: randomUUID9(),
21517
+ title,
21518
+ body,
21519
+ prNumber: null,
21520
+ kind: "github-issue-edit"
21521
+ },
21522
+ {
21523
+ saveEditedBody: working.save,
21524
+ 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.`
21525
+ }
21526
+ );
21527
+ return decision.body ?? body;
21528
+ }
21529
+
21530
+ // src/commands/github/issue/viewIssue.ts
21531
+ import { execFileSync as execFileSync10 } from "child_process";
21532
+ function viewIssue(number, repo) {
21533
+ const args = ["issue", "view", String(number)];
21534
+ if (repo) args.push("--repo", repo);
21535
+ try {
21536
+ execFileSync10("gh", args, { stdio: "inherit" });
21537
+ } catch {
21538
+ process.exit(1);
21539
+ }
21540
+ }
21541
+
21542
+ // src/commands/github/issue/editIssue.ts
21543
+ var USAGE3 = "Usage: assist github issue edit <number> [-R <owner>/<repo>]";
21544
+ async function editIssue(numberArg, options2) {
21545
+ const number = Number.parseInt(numberArg, 10);
21546
+ if (!Number.isInteger(number) || number <= 0) {
21547
+ console.error(USAGE3);
21548
+ process.exit(1);
21549
+ }
21550
+ if (!inWebSession()) {
21551
+ viewIssue(number, options2.repo);
21552
+ return;
21553
+ }
21554
+ const issue = prepareIssueEdit(number, options2.repo, options2.fresh);
21555
+ const edited = await reviewProposedIssueEdit(
21556
+ `Edit ${issue.target}: ${issue.title}`,
21557
+ issue.body,
21558
+ { path: issue.bodyPath, save: issue.save }
21559
+ );
21560
+ validateIssueBody(issue.title, edited);
21561
+ pushUnchangedIssue(
21562
+ number,
21563
+ options2.repo,
21564
+ issue.target,
21565
+ issue.updatedAt,
21566
+ issue.bodyPath
21567
+ );
21568
+ }
21569
+
21570
+ // src/commands/github/issue/registerEditIssue.ts
21571
+ function registerEditIssue(issueCommand) {
21423
21572
  issueCommand.command("edit <number>").description("Edit an existing GitHub issue's body in the preview pane").option(
21424
21573
  "-R, --repo <owner/repo>",
21425
21574
  "Target repository (defaults to the current repo)"
@@ -21430,20 +21579,14 @@ function registerGithubIssue(githubCommand) {
21430
21579
  "after",
21431
21580
  "\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
21581
  ).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
- );
21582
+ }
21583
+
21584
+ // src/commands/registerGithubIssue.ts
21585
+ function registerGithubIssue(githubCommand) {
21586
+ const issueCommand = githubCommand.command("issue").description("GitHub issue utilities");
21587
+ registerCreateIssue(issueCommand);
21588
+ registerEditIssue(issueCommand);
21589
+ registerCommentIssue(issueCommand);
21447
21590
  registerFixStructure(issueCommand);
21448
21591
  }
21449
21592
 
@@ -21684,7 +21827,7 @@ function registerHandover(program2) {
21684
21827
  }
21685
21828
 
21686
21829
  // src/commands/jira/acceptanceCriteria.ts
21687
- import chalk163 from "chalk";
21830
+ import chalk165 from "chalk";
21688
21831
 
21689
21832
  // src/commands/jira/adfToText.ts
21690
21833
  function renderInline(node) {
@@ -21751,7 +21894,7 @@ function acceptanceCriteria(issueKey) {
21751
21894
  const parsed = fetchIssue(issueKey, field);
21752
21895
  const acValue = parsed?.fields?.[field];
21753
21896
  if (!acValue) {
21754
- console.log(chalk163.yellow(`No acceptance criteria found on ${issueKey}.`));
21897
+ console.log(chalk165.yellow(`No acceptance criteria found on ${issueKey}.`));
21755
21898
  return;
21756
21899
  }
21757
21900
  if (typeof acValue === "string") {
@@ -21817,14 +21960,14 @@ async function jiraAuth() {
21817
21960
  }
21818
21961
 
21819
21962
  // src/commands/jira/viewIssue.ts
21820
- import chalk164 from "chalk";
21963
+ import chalk166 from "chalk";
21821
21964
  function viewIssue2(issueKey) {
21822
21965
  const parsed = fetchIssue(issueKey, "summary,description");
21823
21966
  const fields = parsed?.fields;
21824
21967
  const summary = fields?.summary;
21825
21968
  const description = fields?.description;
21826
21969
  if (summary) {
21827
- console.log(chalk164.bold(summary));
21970
+ console.log(chalk166.bold(summary));
21828
21971
  }
21829
21972
  if (description) {
21830
21973
  if (summary) console.log();
@@ -21838,7 +21981,7 @@ function viewIssue2(issueKey) {
21838
21981
  }
21839
21982
  if (!summary && !description) {
21840
21983
  console.log(
21841
- chalk164.yellow(`No summary or description found on ${issueKey}.`)
21984
+ chalk166.yellow(`No summary or description found on ${issueKey}.`)
21842
21985
  );
21843
21986
  }
21844
21987
  }
@@ -21873,7 +22016,7 @@ import { randomUUID as randomUUID10 } from "crypto";
21873
22016
 
21874
22017
  // src/commands/review/checkoutPr.ts
21875
22018
  import { execFileSync as execFileSync12 } from "child_process";
21876
- import chalk165 from "chalk";
22019
+ import chalk167 from "chalk";
21877
22020
 
21878
22021
  // src/commands/sessions/daemon/daemonLog.ts
21879
22022
  var RING_CAPACITY = 1e3;
@@ -22485,7 +22628,7 @@ async function checkoutPr(number) {
22485
22628
  try {
22486
22629
  execFileSync12("gh", ["pr", "checkout", number], { stdio: "inherit" });
22487
22630
  } catch {
22488
- console.error(chalk165.red(`gh pr checkout ${number} failed; aborting.`));
22631
+ console.error(chalk167.red(`gh pr checkout ${number} failed; aborting.`));
22489
22632
  process.exit(1);
22490
22633
  }
22491
22634
  }
@@ -22622,15 +22765,15 @@ function registerList(program2) {
22622
22765
  // src/commands/mermaid/index.ts
22623
22766
  import { mkdirSync as mkdirSync18, readdirSync as readdirSync11 } from "fs";
22624
22767
  import { resolve as resolve16 } from "path";
22625
- import chalk168 from "chalk";
22768
+ import chalk170 from "chalk";
22626
22769
 
22627
22770
  // src/commands/mermaid/exportFile.ts
22628
22771
  import { readFileSync as readFileSync39, writeFileSync as writeFileSync32 } from "fs";
22629
22772
  import { basename as basename17, extname as extname2, resolve as resolve15 } from "path";
22630
- import chalk167 from "chalk";
22773
+ import chalk169 from "chalk";
22631
22774
 
22632
22775
  // src/commands/mermaid/renderBlock.ts
22633
- import chalk166 from "chalk";
22776
+ import chalk168 from "chalk";
22634
22777
  async function renderBlock(krokiUrl, source) {
22635
22778
  const response = await fetch(`${krokiUrl}/mermaid/svg`, {
22636
22779
  method: "POST",
@@ -22639,7 +22782,7 @@ async function renderBlock(krokiUrl, source) {
22639
22782
  });
22640
22783
  if (!response.ok) {
22641
22784
  console.error(
22642
- chalk166.red(
22785
+ chalk168.red(
22643
22786
  `Kroki request failed: ${response.status} ${response.statusText}`
22644
22787
  )
22645
22788
  );
@@ -22657,19 +22800,19 @@ async function exportFile(file, outDir, krokiUrl, onlyIndex) {
22657
22800
  if (onlyIndex !== void 0) {
22658
22801
  if (onlyIndex < 1 || onlyIndex > blocks.length) {
22659
22802
  console.error(
22660
- chalk167.red(
22803
+ chalk169.red(
22661
22804
  `${file}: --index ${onlyIndex} out of range (file has ${blocks.length} diagram(s))`
22662
22805
  )
22663
22806
  );
22664
22807
  process.exit(1);
22665
22808
  }
22666
22809
  console.log(
22667
- chalk167.gray(
22810
+ chalk169.gray(
22668
22811
  `${file} \u2014 rendering diagram ${onlyIndex} of ${blocks.length}`
22669
22812
  )
22670
22813
  );
22671
22814
  } else {
22672
- console.log(chalk167.gray(`${file} \u2014 ${blocks.length} diagram(s)`));
22815
+ console.log(chalk169.gray(`${file} \u2014 ${blocks.length} diagram(s)`));
22673
22816
  }
22674
22817
  for (const [i, source] of blocks.entries()) {
22675
22818
  const idx = i + 1;
@@ -22677,7 +22820,7 @@ async function exportFile(file, outDir, krokiUrl, onlyIndex) {
22677
22820
  const outPath = resolve15(outDir, `${stem}-${idx}.svg`);
22678
22821
  const svg = await renderBlock(krokiUrl, source);
22679
22822
  writeFileSync32(outPath, svg, "utf8");
22680
- console.log(chalk167.green(` \u2192 ${outPath}`));
22823
+ console.log(chalk169.green(` \u2192 ${outPath}`));
22681
22824
  }
22682
22825
  }
22683
22826
  function extractMermaidBlocks(markdown) {
@@ -22693,18 +22836,18 @@ async function mermaidExport(file, options2 = {}) {
22693
22836
  if (options2.index !== void 0) {
22694
22837
  if (!Number.isInteger(options2.index) || options2.index < 1) {
22695
22838
  console.error(
22696
- chalk168.red(`--index must be a positive integer (got ${options2.index})`)
22839
+ chalk170.red(`--index must be a positive integer (got ${options2.index})`)
22697
22840
  );
22698
22841
  process.exit(1);
22699
22842
  }
22700
22843
  if (!file) {
22701
- console.error(chalk168.red("--index requires a file argument"));
22844
+ console.error(chalk170.red("--index requires a file argument"));
22702
22845
  process.exit(1);
22703
22846
  }
22704
22847
  }
22705
22848
  const files = file ? [file] : readdirSync11(process.cwd()).filter((name) => name.toLowerCase().endsWith(".md")).sort();
22706
22849
  if (files.length === 0) {
22707
- console.log(chalk168.gray("No markdown files found in current directory."));
22850
+ console.log(chalk170.gray("No markdown files found in current directory."));
22708
22851
  return;
22709
22852
  }
22710
22853
  for (const f of files) {
@@ -22760,13 +22903,13 @@ function stripHtml2(content) {
22760
22903
 
22761
22904
  // src/commands/miro/normaliseItems.ts
22762
22905
  var frameCoordinates = "parent_top_left";
22763
- function describe2(item) {
22906
+ function describe4(item) {
22764
22907
  return ` ${item.id ?? "(no id)"} (${item.type ?? "unknown type"}): relativeTo=${item.position?.relativeTo ?? "missing"}`;
22765
22908
  }
22766
22909
  function coordinateSpaceError(rejected) {
22767
22910
  return new MiroExtractError(
22768
22911
  `${rejected.length} item(s) are not in frame coordinates (position.relativeTo must be "${frameCoordinates}"):
22769
- ${rejected.slice(0, 5).map(describe2).join(
22912
+ ${rejected.slice(0, 5).map(describe4).join(
22770
22913
  "\n"
22771
22914
  )}
22772
22915
 
@@ -22803,6 +22946,45 @@ function parseAnchorId(value) {
22803
22946
  return link3 ? decodeURIComponent(link3[1]).trim() : trimmed;
22804
22947
  }
22805
22948
 
22949
+ // src/commands/miro/pickAnchors.ts
22950
+ import { randomUUID as randomUUID12 } from "crypto";
22951
+
22952
+ // src/commands/miro/isBox.ts
22953
+ var boxTypes = /* @__PURE__ */ new Set(["shape", "sticky_note"]);
22954
+ function isBox(item) {
22955
+ return boxTypes.has(item.type) && item.text.length > 0;
22956
+ }
22957
+
22958
+ // src/commands/miro/encodeMiroBoardPreview.ts
22959
+ function encodeMiroBoardPreview(items2) {
22960
+ const preview = { boxes: items2.filter(isBox) };
22961
+ return JSON.stringify(preview);
22962
+ }
22963
+
22964
+ // src/commands/miro/pickAnchors.ts
22965
+ var skipAdvice = "Re-run with --top-left <id|link> --bottom-right <id|link> to skip the picker.";
22966
+ async function pickAnchors(sessionId, items2) {
22967
+ const decision = await awaitPreviewApproval(
22968
+ "Miro anchor selection",
22969
+ {
22970
+ sessionId,
22971
+ requestId: randomUUID12(),
22972
+ title: "Pick the top-left then the bottom-right box",
22973
+ body: encodeMiroBoardPreview(items2),
22974
+ prNumber: null,
22975
+ kind: "miro-board"
22976
+ },
22977
+ { rejectionAdvice: `Nothing was extracted. ${skipAdvice}` }
22978
+ );
22979
+ const selection = decision.selection;
22980
+ if (!selection)
22981
+ throw new MiroExtractError(`The picker returned no boxes. ${skipAdvice}`);
22982
+ console.log(
22983
+ `Anchors: --top-left ${selection.topLeft} --bottom-right ${selection.bottomRight}`
22984
+ );
22985
+ return [selection.topLeft, selection.bottomRight];
22986
+ }
22987
+
22806
22988
  // src/commands/miro/readMiroItems.ts
22807
22989
  import { readFileSync as readFileSync40 } from "fs";
22808
22990
  function tryParse(text18) {
@@ -22844,7 +23026,6 @@ function readMiroItems(file) {
22844
23026
  }
22845
23027
 
22846
23028
  // src/commands/miro/selectBoxes.ts
22847
- var boxTypes = /* @__PURE__ */ new Set(["shape", "sticky_note"]);
22848
23029
  function findAnchor(items2, id) {
22849
23030
  const anchor = items2.find((item) => item.id === id);
22850
23031
  if (!anchor)
@@ -22853,9 +23034,6 @@ function findAnchor(items2, id) {
22853
23034
  );
22854
23035
  return anchor;
22855
23036
  }
22856
- function isBox(item) {
22857
- return boxTypes.has(item.type) && item.text.length > 0;
22858
- }
22859
23037
  function centreInside(rect, item) {
22860
23038
  const x = (item.left + item.right) / 2;
22861
23039
  const y = (item.top + item.bottom) / 2;
@@ -22881,16 +23059,24 @@ function requireItems(file) {
22881
23059
  );
22882
23060
  return file;
22883
23061
  }
22884
- function requireAnchors(options2) {
22885
- if (!options2.topLeft || !options2.bottomRight)
23062
+ function anchorSource(options2) {
23063
+ if (options2.topLeft && options2.bottomRight)
23064
+ return {
23065
+ pick: false,
23066
+ topLeft: parseAnchorId(options2.topLeft),
23067
+ bottomRight: parseAnchorId(options2.bottomRight)
23068
+ };
23069
+ const sessionId = process.env.ASSIST_SESSION_ID;
23070
+ if (process.env.ASSIST_SESSION !== "1" || !sessionId)
22886
23071
  throw new MiroExtractError(
22887
- "Both --top-left <id|link> and --bottom-right <id|link> are required."
23072
+ "Both --top-left <id|link> and --bottom-right <id|link> are required: there is no assist session to host the picker pane."
22888
23073
  );
22889
- return [parseAnchorId(options2.topLeft), parseAnchorId(options2.bottomRight)];
23074
+ return { pick: true, sessionId };
22890
23075
  }
22891
- function runExtract(options2) {
22892
- const [topLeft, bottomRight] = requireAnchors(options2);
23076
+ async function runExtract(options2) {
23077
+ const source = anchorSource(options2);
22893
23078
  const items2 = normaliseItems(readMiroItems(requireItems(options2.items)));
23079
+ const [topLeft, bottomRight] = source.pick ? await pickAnchors(source.sessionId, items2) : [source.topLeft, source.bottomRight];
22894
23080
  const boxes = selectBoxes(items2, topLeft, bottomRight);
22895
23081
  process.stdout.write(stringify(boxes.map((box) => box.text)));
22896
23082
  }
@@ -22900,7 +23086,7 @@ function registerMiro(program2) {
22900
23086
  const miroCommand = program2.command("miro").description("Miro board utilities");
22901
23087
  miroCommand.command("extract").description("Print the text of every box inside a rectangle on a board").option("--items <file>", "File of raw board_list_items response pages").option(
22902
23088
  "--top-left <id>",
22903
- "Widget id or ?moveToWidget=<id> link of the top-left box"
23089
+ "Widget id or ?moveToWidget=<id> link of the top-left box (omit both anchors to pick them in the assist web UI)"
22904
23090
  ).option(
22905
23091
  "--bottom-right <id>",
22906
23092
  "Widget id or ?moveToWidget=<id> link of the bottom-right box"
@@ -22911,7 +23097,7 @@ function registerMiro(program2) {
22911
23097
  import { mkdir as mkdir4 } from "fs/promises";
22912
23098
  import { createServer as createServer2 } from "http";
22913
23099
  import { dirname as dirname28 } from "path";
22914
- import chalk170 from "chalk";
23100
+ import chalk172 from "chalk";
22915
23101
 
22916
23102
  // src/commands/netcap/corsHeaders.ts
22917
23103
  var corsHeaders = {
@@ -22990,7 +23176,7 @@ function createNetcapHandler(options2) {
22990
23176
  import { cp, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
22991
23177
  import { networkInterfaces } from "os";
22992
23178
  import { join as join58 } from "path";
22993
- import chalk169 from "chalk";
23179
+ import chalk171 from "chalk";
22994
23180
 
22995
23181
  // src/commands/netcap/netcapExtensionDir.ts
22996
23182
  import { dirname as dirname27, join as join57 } from "path";
@@ -23034,7 +23220,7 @@ async function prepareExtensionForLoad(port, filter = "") {
23034
23220
  const host = lanIPv4();
23035
23221
  if (!host) {
23036
23222
  console.log(
23037
- chalk169.yellow("could not determine the WSL IP for the extension")
23223
+ chalk171.yellow("could not determine the WSL IP for the extension")
23038
23224
  );
23039
23225
  await configureBackground(source, "127.0.0.1", port, filter);
23040
23226
  return source;
@@ -23045,7 +23231,7 @@ async function prepareExtensionForLoad(port, filter = "") {
23045
23231
  return WSL_WINDOWS_PATH;
23046
23232
  } catch {
23047
23233
  console.log(
23048
- chalk169.yellow(`could not copy extension to ${WSL_WINDOWS_PATH}`)
23234
+ chalk171.yellow(`could not copy extension to ${WSL_WINDOWS_PATH}`)
23049
23235
  );
23050
23236
  return source;
23051
23237
  }
@@ -23078,30 +23264,30 @@ async function netcap(options2) {
23078
23264
  let count8 = 0;
23079
23265
  const handler = createNetcapHandler({
23080
23266
  outPath,
23081
- onPing: () => console.log(chalk170.dim("ping from extension")),
23267
+ onPing: () => console.log(chalk172.dim("ping from extension")),
23082
23268
  onCapture: (entry) => {
23083
23269
  count8 += 1;
23084
23270
  console.log(
23085
- chalk170.green(`captured #${count8}`),
23086
- chalk170.dim(`${entry.method ?? "?"} ${entry.url ?? "?"}`)
23271
+ chalk172.green(`captured #${count8}`),
23272
+ chalk172.dim(`${entry.method ?? "?"} ${entry.url ?? "?"}`)
23087
23273
  );
23088
23274
  }
23089
23275
  });
23090
23276
  const server = createServer2(handler);
23091
23277
  server.listen(port, () => {
23092
23278
  console.log(
23093
- chalk170.bold(`netcap receiver listening on http://127.0.0.1:${port}`)
23279
+ chalk172.bold(`netcap receiver listening on http://127.0.0.1:${port}`)
23094
23280
  );
23095
- console.log(chalk170.dim(`appending captures to ${outPath}`));
23281
+ console.log(chalk172.dim(`appending captures to ${outPath}`));
23096
23282
  if (filter)
23097
- console.log(chalk170.dim(`forwarding only URLs matching "${filter}"`));
23098
- console.log(chalk170.dim(`load the unpacked extension from ${extensionPath}`));
23099
- console.log(chalk170.dim("press Ctrl-C to stop"));
23283
+ console.log(chalk172.dim(`forwarding only URLs matching "${filter}"`));
23284
+ console.log(chalk172.dim(`load the unpacked extension from ${extensionPath}`));
23285
+ console.log(chalk172.dim("press Ctrl-C to stop"));
23100
23286
  });
23101
23287
  process.on("SIGINT", () => {
23102
23288
  server.close();
23103
23289
  console.log(
23104
- chalk170.bold(
23290
+ chalk172.bold(
23105
23291
  `
23106
23292
  netcap stopped \u2014 captured ${count8} ${count8 === 1 ? "entry" : "entries"} to ${outPath}`
23107
23293
  )
@@ -23113,7 +23299,7 @@ netcap stopped \u2014 captured ${count8} ${count8 === 1 ? "entry" : "entries"} t
23113
23299
  // src/commands/netcap/netcapExtract.ts
23114
23300
  import { writeFileSync as writeFileSync33 } from "fs";
23115
23301
  import { join as join61 } from "path";
23116
- import chalk171 from "chalk";
23302
+ import chalk173 from "chalk";
23117
23303
 
23118
23304
  // src/commands/netcap/extractPostsFromCapture.ts
23119
23305
  import { readFileSync as readFileSync41 } from "fs";
@@ -23561,8 +23747,8 @@ function netcapExtract(file) {
23561
23747
  writeFileSync33(outFile, `${JSON.stringify(posts, null, 2)}
23562
23748
  `);
23563
23749
  console.log(
23564
- chalk171.green(`extracted ${posts.length} posts`),
23565
- chalk171.dim(`-> ${outFile}`)
23750
+ chalk173.green(`extracted ${posts.length} posts`),
23751
+ chalk173.dim(`-> ${outFile}`)
23566
23752
  );
23567
23753
  }
23568
23754
 
@@ -23583,7 +23769,7 @@ function registerNetcap(program2) {
23583
23769
  }
23584
23770
 
23585
23771
  // src/commands/news/add/index.ts
23586
- import chalk172 from "chalk";
23772
+ import chalk174 from "chalk";
23587
23773
  import enquirer8 from "enquirer";
23588
23774
  async function add2(url) {
23589
23775
  if (!url) {
@@ -23605,10 +23791,10 @@ async function add2(url) {
23605
23791
  const { orm } = await getReady();
23606
23792
  const added = await addFeed(orm, url);
23607
23793
  if (!added) {
23608
- console.log(chalk172.yellow("Feed already exists"));
23794
+ console.log(chalk174.yellow("Feed already exists"));
23609
23795
  return;
23610
23796
  }
23611
- console.log(chalk172.green(`Added feed: ${url}`));
23797
+ console.log(chalk174.green(`Added feed: ${url}`));
23612
23798
  }
23613
23799
 
23614
23800
  // src/commands/registerNews.ts
@@ -23655,7 +23841,7 @@ function registerPiHook(program2) {
23655
23841
  }
23656
23842
 
23657
23843
  // src/commands/prompts/printPromptsTable.ts
23658
- import chalk173 from "chalk";
23844
+ import chalk175 from "chalk";
23659
23845
  function truncate(str, max) {
23660
23846
  if (str.length <= max) return str;
23661
23847
  return `${str.slice(0, max - 1)}\u2026`;
@@ -23673,14 +23859,14 @@ function printPromptsTable(rows) {
23673
23859
  "Command".padEnd(commandWidth),
23674
23860
  "Repos"
23675
23861
  ].join(" ");
23676
- console.log(chalk173.dim(header));
23677
- console.log(chalk173.dim("-".repeat(header.length)));
23862
+ console.log(chalk175.dim(header));
23863
+ console.log(chalk175.dim("-".repeat(header.length)));
23678
23864
  for (const row of rows) {
23679
23865
  const count8 = String(row.count).padStart(countWidth);
23680
23866
  const tool = row.tool.padEnd(toolWidth);
23681
23867
  const command = truncate(row.command, 60).padEnd(commandWidth);
23682
23868
  console.log(
23683
- `${chalk173.yellow(count8)} ${tool} ${command} ${chalk173.dim(row.repos)}`
23869
+ `${chalk175.yellow(count8)} ${tool} ${command} ${chalk175.dim(row.repos)}`
23684
23870
  );
23685
23871
  }
23686
23872
  }
@@ -23732,13 +23918,13 @@ function postReviewComment(vars) {
23732
23918
  }
23733
23919
 
23734
23920
  // src/commands/prs/reviewProposedPrComment.ts
23735
- import { randomUUID as randomUUID12 } from "crypto";
23921
+ import { randomUUID as randomUUID13 } from "crypto";
23736
23922
  async function reviewProposedPrComment(title, body, prNumber) {
23737
23923
  const sessionId = process.env.ASSIST_SESSION_ID;
23738
23924
  if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
23739
23925
  await awaitPreviewApproval("PR comment preview", {
23740
23926
  sessionId,
23741
- requestId: randomUUID12(),
23927
+ requestId: randomUUID13(),
23742
23928
  title,
23743
23929
  body,
23744
23930
  prNumber,
@@ -23864,7 +24050,7 @@ async function comment2(path80, line, body, startLine) {
23864
24050
  }
23865
24051
 
23866
24052
  // src/commands/prs/edit.ts
23867
- import { randomUUID as randomUUID13 } from "crypto";
24053
+ import { randomUUID as randomUUID14 } from "crypto";
23868
24054
 
23869
24055
  // src/commands/prs/appendScreenshots.ts
23870
24056
  function appendScreenshots(body, screenshots) {
@@ -24061,7 +24247,7 @@ async function edit(options2) {
24061
24247
  if (process.env.ASSIST_SESSION === "1" && sessionId) {
24062
24248
  const decision = await awaitPreviewApproval("PR preview", {
24063
24249
  sessionId,
24064
- requestId: randomUUID13(),
24250
+ requestId: randomUUID14(),
24065
24251
  title: options2.title ?? title,
24066
24252
  body: newBody,
24067
24253
  prNumber: number
@@ -24347,13 +24533,13 @@ function agentFooter(unresolvedCount) {
24347
24533
  }
24348
24534
 
24349
24535
  // src/commands/prs/listComments/commentStyle.ts
24350
- import chalk174 from "chalk";
24536
+ import chalk176 from "chalk";
24351
24537
  var plain = (text18) => text18;
24352
24538
  function colouredState(state) {
24353
24539
  const label2 = `[${state}]`;
24354
- if (state === "APPROVED") return chalk174.green(label2);
24355
- if (state === "CHANGES_REQUESTED") return chalk174.red(label2);
24356
- return chalk174.yellow(label2);
24540
+ if (state === "APPROVED") return chalk176.green(label2);
24541
+ if (state === "CHANGES_REQUESTED") return chalk176.red(label2);
24542
+ return chalk176.yellow(label2);
24357
24543
  }
24358
24544
  function commentStyle() {
24359
24545
  if (isClaudeCode()) {
@@ -24367,9 +24553,9 @@ function commentStyle() {
24367
24553
  };
24368
24554
  }
24369
24555
  return {
24370
- cyan: chalk174.cyan,
24371
- bold: chalk174.bold,
24372
- dim: chalk174.dim,
24556
+ cyan: chalk176.cyan,
24557
+ bold: chalk176.bold,
24558
+ dim: chalk176.dim,
24373
24559
  state: colouredState,
24374
24560
  diffHunk: true,
24375
24561
  agent: false
@@ -24539,13 +24725,13 @@ import { execSync as execSync48 } from "child_process";
24539
24725
  import enquirer9 from "enquirer";
24540
24726
 
24541
24727
  // src/commands/prs/prs/displayPaginated/printPr.ts
24542
- import chalk175 from "chalk";
24728
+ import chalk177 from "chalk";
24543
24729
  var STATUS_MAP = {
24544
- MERGED: (pr) => pr.mergedAt ? { label: chalk175.magenta("merged"), date: pr.mergedAt } : null,
24545
- CLOSED: (pr) => pr.closedAt ? { label: chalk175.red("closed"), date: pr.closedAt } : null
24730
+ MERGED: (pr) => pr.mergedAt ? { label: chalk177.magenta("merged"), date: pr.mergedAt } : null,
24731
+ CLOSED: (pr) => pr.closedAt ? { label: chalk177.red("closed"), date: pr.closedAt } : null
24546
24732
  };
24547
24733
  function defaultStatus(pr) {
24548
- return { label: chalk175.green("opened"), date: pr.createdAt };
24734
+ return { label: chalk177.green("opened"), date: pr.createdAt };
24549
24735
  }
24550
24736
  function getStatus2(pr) {
24551
24737
  return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
@@ -24554,11 +24740,11 @@ function formatDate(dateStr) {
24554
24740
  return new Date(dateStr).toISOString().split("T")[0];
24555
24741
  }
24556
24742
  function formatPrHeader(pr, status3) {
24557
- return `${chalk175.cyan(`#${pr.number}`)} ${pr.title} ${chalk175.dim(`(${pr.author.login},`)} ${status3.label} ${chalk175.dim(`${formatDate(status3.date)})`)}`;
24743
+ return `${chalk177.cyan(`#${pr.number}`)} ${pr.title} ${chalk177.dim(`(${pr.author.login},`)} ${status3.label} ${chalk177.dim(`${formatDate(status3.date)})`)}`;
24558
24744
  }
24559
24745
  function logPrDetails(pr) {
24560
24746
  console.log(
24561
- chalk175.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
24747
+ chalk177.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
24562
24748
  );
24563
24749
  console.log();
24564
24750
  }
@@ -24772,7 +24958,7 @@ async function placePr(prNumber, title, body, options2) {
24772
24958
  }
24773
24959
 
24774
24960
  // src/commands/prs/previewAndPlace.ts
24775
- import { randomUUID as randomUUID14 } from "crypto";
24961
+ import { randomUUID as randomUUID15 } from "crypto";
24776
24962
 
24777
24963
  // src/commands/sessions/shared/requestSession.ts
24778
24964
  function parseIncoming(line, type) {
@@ -24907,7 +25093,7 @@ function warn(reason4) {
24907
25093
  async function previewAndPlace(args) {
24908
25094
  const decision = await awaitPreviewApproval("PR preview", {
24909
25095
  sessionId: args.sessionId,
24910
- requestId: randomUUID14(),
25096
+ requestId: randomUUID15(),
24911
25097
  title: args.title,
24912
25098
  body: args.body,
24913
25099
  prNumber: args.prNumber,
@@ -25273,10 +25459,10 @@ function registerPrs(program2) {
25273
25459
  }
25274
25460
 
25275
25461
  // src/commands/ravendb/ravendbAuth.ts
25276
- import chalk181 from "chalk";
25462
+ import chalk183 from "chalk";
25277
25463
 
25278
25464
  // src/shared/createConnectionAuth.ts
25279
- import chalk176 from "chalk";
25465
+ import chalk178 from "chalk";
25280
25466
  function listConnections(connections, format) {
25281
25467
  if (connections.length === 0) {
25282
25468
  console.log("No connections configured.");
@@ -25289,7 +25475,7 @@ function listConnections(connections, format) {
25289
25475
  function removeConnection(connections, name, save) {
25290
25476
  const filtered = connections.filter((c) => c.name !== name);
25291
25477
  if (filtered.length === connections.length) {
25292
- console.error(chalk176.red(`Connection "${name}" not found.`));
25478
+ console.error(chalk178.red(`Connection "${name}" not found.`));
25293
25479
  process.exit(1);
25294
25480
  }
25295
25481
  save(filtered);
@@ -25335,15 +25521,15 @@ function saveConnections(connections) {
25335
25521
  }
25336
25522
 
25337
25523
  // src/commands/ravendb/promptConnection.ts
25338
- import chalk179 from "chalk";
25524
+ import chalk181 from "chalk";
25339
25525
 
25340
25526
  // src/commands/ravendb/selectOpSecret.ts
25341
- import chalk178 from "chalk";
25527
+ import chalk180 from "chalk";
25342
25528
  import Enquirer2 from "enquirer";
25343
25529
 
25344
25530
  // src/commands/ravendb/searchItems.ts
25345
25531
  import { execSync as execSync51 } from "child_process";
25346
- import chalk177 from "chalk";
25532
+ import chalk179 from "chalk";
25347
25533
  function opExec(args) {
25348
25534
  return execSync51(`op ${args}`, {
25349
25535
  encoding: "utf8",
@@ -25356,7 +25542,7 @@ function searchItems(search2) {
25356
25542
  items2 = JSON.parse(opExec("item list --format=json"));
25357
25543
  } catch {
25358
25544
  console.error(
25359
- chalk177.red(
25545
+ chalk179.red(
25360
25546
  "Failed to search 1Password. Ensure the CLI is installed and you are signed in."
25361
25547
  )
25362
25548
  );
@@ -25370,7 +25556,7 @@ function getItemFields(itemId2) {
25370
25556
  const item = JSON.parse(opExec(`item get "${itemId2}" --format=json`));
25371
25557
  return item.fields.filter((f) => f.reference && f.label);
25372
25558
  } catch {
25373
- console.error(chalk177.red("Failed to get item details from 1Password."));
25559
+ console.error(chalk179.red("Failed to get item details from 1Password."));
25374
25560
  process.exit(1);
25375
25561
  }
25376
25562
  }
@@ -25389,7 +25575,7 @@ async function selectOpSecret(searchTerm) {
25389
25575
  }).run();
25390
25576
  const items2 = searchItems(search2);
25391
25577
  if (items2.length === 0) {
25392
- console.error(chalk178.red(`No items found matching "${search2}".`));
25578
+ console.error(chalk180.red(`No items found matching "${search2}".`));
25393
25579
  process.exit(1);
25394
25580
  }
25395
25581
  const itemId2 = await selectOne(
@@ -25398,7 +25584,7 @@ async function selectOpSecret(searchTerm) {
25398
25584
  );
25399
25585
  const fields = getItemFields(itemId2);
25400
25586
  if (fields.length === 0) {
25401
- console.error(chalk178.red("No fields with references found on this item."));
25587
+ console.error(chalk180.red("No fields with references found on this item."));
25402
25588
  process.exit(1);
25403
25589
  }
25404
25590
  const ref = await selectOne(
@@ -25412,7 +25598,7 @@ async function selectOpSecret(searchTerm) {
25412
25598
  async function promptConnection(existingNames) {
25413
25599
  const name = await promptInput("name", "Connection name:");
25414
25600
  if (existingNames.includes(name)) {
25415
- console.error(chalk179.red(`Connection "${name}" already exists.`));
25601
+ console.error(chalk181.red(`Connection "${name}" already exists.`));
25416
25602
  process.exit(1);
25417
25603
  }
25418
25604
  const url = await promptInput(
@@ -25421,22 +25607,22 @@ async function promptConnection(existingNames) {
25421
25607
  );
25422
25608
  const database = await promptInput("database", "Database name:");
25423
25609
  if (!name || !url || !database) {
25424
- console.error(chalk179.red("All fields are required."));
25610
+ console.error(chalk181.red("All fields are required."));
25425
25611
  process.exit(1);
25426
25612
  }
25427
25613
  const apiKeyRef = await selectOpSecret();
25428
- console.log(chalk179.dim(`Using: ${apiKeyRef}`));
25614
+ console.log(chalk181.dim(`Using: ${apiKeyRef}`));
25429
25615
  return { name, url, database, apiKeyRef };
25430
25616
  }
25431
25617
 
25432
25618
  // src/commands/ravendb/ravendbSetConnection.ts
25433
- import chalk180 from "chalk";
25619
+ import chalk182 from "chalk";
25434
25620
  function ravendbSetConnection(name) {
25435
25621
  const raw = loadGlobalConfigRaw();
25436
25622
  const ravendb = raw.ravendb ?? {};
25437
25623
  const connections = ravendb.connections ?? [];
25438
25624
  if (!connections.some((c) => c.name === name)) {
25439
- console.error(chalk180.red(`Connection "${name}" not found.`));
25625
+ console.error(chalk182.red(`Connection "${name}" not found.`));
25440
25626
  console.error(
25441
25627
  `Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
25442
25628
  );
@@ -25452,16 +25638,16 @@ function ravendbSetConnection(name) {
25452
25638
  var ravendbAuth = createConnectionAuth({
25453
25639
  load: loadConnections,
25454
25640
  save: saveConnections,
25455
- format: (c) => `${chalk181.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
25641
+ format: (c) => `${chalk183.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
25456
25642
  promptNew: promptConnection,
25457
25643
  onFirst: (c) => ravendbSetConnection(c.name)
25458
25644
  });
25459
25645
 
25460
25646
  // src/commands/ravendb/ravendbCollections.ts
25461
- import chalk185 from "chalk";
25647
+ import chalk187 from "chalk";
25462
25648
 
25463
25649
  // src/commands/ravendb/ravenFetch.ts
25464
- import chalk183 from "chalk";
25650
+ import chalk185 from "chalk";
25465
25651
 
25466
25652
  // src/commands/ravendb/getAccessToken.ts
25467
25653
  var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
@@ -25498,10 +25684,10 @@ ${errorText}`
25498
25684
 
25499
25685
  // src/commands/ravendb/resolveOpSecret.ts
25500
25686
  import { execSync as execSync52 } from "child_process";
25501
- import chalk182 from "chalk";
25687
+ import chalk184 from "chalk";
25502
25688
  function resolveOpSecret(reference) {
25503
25689
  if (!reference.startsWith("op://")) {
25504
- console.error(chalk182.red(`Invalid secret reference: must start with op://`));
25690
+ console.error(chalk184.red(`Invalid secret reference: must start with op://`));
25505
25691
  process.exit(1);
25506
25692
  }
25507
25693
  try {
@@ -25511,7 +25697,7 @@ function resolveOpSecret(reference) {
25511
25697
  }).trim();
25512
25698
  } catch {
25513
25699
  console.error(
25514
- chalk182.red(
25700
+ chalk184.red(
25515
25701
  "Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
25516
25702
  )
25517
25703
  );
@@ -25538,7 +25724,7 @@ async function ravenFetch(connection, path80) {
25538
25724
  if (!response.ok) {
25539
25725
  const body = await response.text();
25540
25726
  console.error(
25541
- chalk183.red(`RavenDB error: ${response.status} ${response.statusText}`)
25727
+ chalk185.red(`RavenDB error: ${response.status} ${response.statusText}`)
25542
25728
  );
25543
25729
  console.error(body.substring(0, 500));
25544
25730
  process.exit(1);
@@ -25547,7 +25733,7 @@ async function ravenFetch(connection, path80) {
25547
25733
  }
25548
25734
 
25549
25735
  // src/commands/ravendb/resolveConnection.ts
25550
- import chalk184 from "chalk";
25736
+ import chalk186 from "chalk";
25551
25737
  function loadRavendb() {
25552
25738
  const raw = loadGlobalConfigRaw();
25553
25739
  const ravendb = raw.ravendb;
@@ -25561,7 +25747,7 @@ function resolveConnection(name) {
25561
25747
  const connectionName = name ?? defaultConnection;
25562
25748
  if (!connectionName) {
25563
25749
  console.error(
25564
- chalk184.red(
25750
+ chalk186.red(
25565
25751
  "No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
25566
25752
  )
25567
25753
  );
@@ -25569,7 +25755,7 @@ function resolveConnection(name) {
25569
25755
  }
25570
25756
  const connection = connections.find((c) => c.name === connectionName);
25571
25757
  if (!connection) {
25572
- console.error(chalk184.red(`Connection "${connectionName}" not found.`));
25758
+ console.error(chalk186.red(`Connection "${connectionName}" not found.`));
25573
25759
  console.error(
25574
25760
  `Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
25575
25761
  );
@@ -25600,15 +25786,15 @@ async function ravendbCollections(connectionName) {
25600
25786
  return;
25601
25787
  }
25602
25788
  for (const c of collections) {
25603
- console.log(`${chalk185.bold(c.Name)} ${c.CountOfDocuments} docs`);
25789
+ console.log(`${chalk187.bold(c.Name)} ${c.CountOfDocuments} docs`);
25604
25790
  }
25605
25791
  }
25606
25792
 
25607
25793
  // src/commands/ravendb/ravendbQuery.ts
25608
- import chalk187 from "chalk";
25794
+ import chalk189 from "chalk";
25609
25795
 
25610
25796
  // src/commands/ravendb/fetchAllPages.ts
25611
- import chalk186 from "chalk";
25797
+ import chalk188 from "chalk";
25612
25798
 
25613
25799
  // src/commands/ravendb/buildQueryPath.ts
25614
25800
  function buildQueryPath(opts) {
@@ -25646,7 +25832,7 @@ async function fetchAllPages(connection, opts) {
25646
25832
  allResults.push(...results);
25647
25833
  start3 += results.length;
25648
25834
  process.stderr.write(
25649
- `\r${chalk186.dim(`Fetched ${allResults.length}/${totalResults}`)}`
25835
+ `\r${chalk188.dim(`Fetched ${allResults.length}/${totalResults}`)}`
25650
25836
  );
25651
25837
  if (start3 >= totalResults) break;
25652
25838
  if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
@@ -25661,7 +25847,7 @@ async function fetchAllPages(connection, opts) {
25661
25847
  async function ravendbQuery(connectionName, collection, options2) {
25662
25848
  const resolved = resolveArgs(connectionName, collection);
25663
25849
  if (!resolved.collection && !options2.query) {
25664
- console.error(chalk187.red("Provide a collection name or --query filter."));
25850
+ console.error(chalk189.red("Provide a collection name or --query filter."));
25665
25851
  process.exit(1);
25666
25852
  }
25667
25853
  const { collection: col } = resolved;
@@ -25700,7 +25886,7 @@ import { spawn as spawn6 } from "child_process";
25700
25886
  import * as path42 from "path";
25701
25887
 
25702
25888
  // src/commands/refactor/logViolations.ts
25703
- import chalk188 from "chalk";
25889
+ import chalk190 from "chalk";
25704
25890
  var DEFAULT_MAX_LINES2 = 100;
25705
25891
  function logViolations(violations, maxLines = DEFAULT_MAX_LINES2) {
25706
25892
  if (violations.length === 0) {
@@ -25709,43 +25895,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES2) {
25709
25895
  }
25710
25896
  return;
25711
25897
  }
25712
- console.error(chalk188.red(`
25898
+ console.error(chalk190.red(`
25713
25899
  Refactor check failed:
25714
25900
  `));
25715
- console.error(chalk188.red(` The following files exceed ${maxLines} lines:
25901
+ console.error(chalk190.red(` The following files exceed ${maxLines} lines:
25716
25902
  `));
25717
25903
  for (const violation of violations) {
25718
- console.error(chalk188.red(` ${violation.file} (${violation.lines} lines)`));
25904
+ console.error(chalk190.red(` ${violation.file} (${violation.lines} lines)`));
25719
25905
  }
25720
25906
  console.error(
25721
- chalk188.yellow(
25907
+ chalk190.yellow(
25722
25908
  `
25723
25909
  Each file needs to be sensibly refactored, or if there is no sensible
25724
25910
  way to refactor it, ignore it with:
25725
25911
  `
25726
25912
  )
25727
25913
  );
25728
- console.error(chalk188.gray(` assist refactor ignore <file>
25914
+ console.error(chalk190.gray(` assist refactor ignore <file>
25729
25915
  `));
25730
25916
  if (process.env.CLAUDECODE) {
25731
- console.error(chalk188.cyan(`
25917
+ console.error(chalk190.cyan(`
25732
25918
  ## Extracting Code to New Files
25733
25919
  `));
25734
25920
  console.error(
25735
- chalk188.cyan(
25921
+ chalk190.cyan(
25736
25922
  ` When extracting logic from one file to another, consider where the extracted code belongs:
25737
25923
  `
25738
25924
  )
25739
25925
  );
25740
25926
  console.error(
25741
- chalk188.cyan(
25927
+ chalk190.cyan(
25742
25928
  ` 1. Keep related logic together: If the extracted code is tightly coupled to the
25743
25929
  original file's domain, create a new folder containing both the original and extracted files.
25744
25930
  `
25745
25931
  )
25746
25932
  );
25747
25933
  console.error(
25748
- chalk188.cyan(
25934
+ chalk190.cyan(
25749
25935
  ` 2. Share common utilities: If the extracted code can be reused across multiple
25750
25936
  domains, move it to a common/shared folder.
25751
25937
  `
@@ -25901,7 +26087,7 @@ async function check(pattern2, options2) {
25901
26087
 
25902
26088
  // src/commands/refactor/extract/index.ts
25903
26089
  import path50 from "path";
25904
- import chalk191 from "chalk";
26090
+ import chalk193 from "chalk";
25905
26091
 
25906
26092
  // src/commands/refactor/extract/applyExtraction.ts
25907
26093
  import { SyntaxKind as SyntaxKind4 } from "ts-morph";
@@ -26500,23 +26686,23 @@ function buildPlan2(functionName, sourceFile, sourcePath, destPath, project) {
26500
26686
 
26501
26687
  // src/commands/refactor/extract/displayPlan.ts
26502
26688
  import path46 from "path";
26503
- import chalk189 from "chalk";
26689
+ import chalk191 from "chalk";
26504
26690
  function section2(title) {
26505
26691
  return `
26506
- ${chalk189.cyan(title)}`;
26692
+ ${chalk191.cyan(title)}`;
26507
26693
  }
26508
26694
  function displayImporters(plan2, cwd) {
26509
26695
  if (plan2.importersToUpdate.length === 0) return;
26510
26696
  console.log(section2("Update importers:"));
26511
26697
  for (const imp of plan2.importersToUpdate) {
26512
26698
  const rel = path46.relative(cwd, imp.file.getFilePath());
26513
- console.log(` ${chalk189.dim(rel)}: \u2192 import from "${imp.relPath}"`);
26699
+ console.log(` ${chalk191.dim(rel)}: \u2192 import from "${imp.relPath}"`);
26514
26700
  }
26515
26701
  }
26516
26702
  function displayPlan(functionName, relDest, plan2, cwd) {
26517
- console.log(chalk189.bold(`Extract: ${functionName} \u2192 ${relDest}
26703
+ console.log(chalk191.bold(`Extract: ${functionName} \u2192 ${relDest}
26518
26704
  `));
26519
- console.log(` ${chalk189.cyan("Functions to move:")}`);
26705
+ console.log(` ${chalk191.cyan("Functions to move:")}`);
26520
26706
  for (const name of plan2.extractedNames) {
26521
26707
  console.log(` ${name}`);
26522
26708
  }
@@ -26550,7 +26736,7 @@ function displayPlan(functionName, relDest, plan2, cwd) {
26550
26736
 
26551
26737
  // src/commands/refactor/extract/loadProjectFile.ts
26552
26738
  import path49 from "path";
26553
- import chalk190 from "chalk";
26739
+ import chalk192 from "chalk";
26554
26740
  import { Project as Project4 } from "ts-morph";
26555
26741
 
26556
26742
  // src/commands/refactor/extract/findTsConfig.ts
@@ -26642,7 +26828,7 @@ function loadProjectFile(file) {
26642
26828
  });
26643
26829
  const sourceFile = project.getSourceFile(sourcePath);
26644
26830
  if (!sourceFile) {
26645
- console.log(chalk190.red(`File not found in project: ${file}`));
26831
+ console.log(chalk192.red(`File not found in project: ${file}`));
26646
26832
  process.exit(1);
26647
26833
  }
26648
26834
  return { project, sourceFile };
@@ -26665,19 +26851,19 @@ async function extract(file, functionName, destination, options2 = {}) {
26665
26851
  displayPlan(functionName, relDest, plan2, cwd);
26666
26852
  if (options2.apply) {
26667
26853
  await applyExtraction(functionName, sourceFile, destPath, plan2, project);
26668
- console.log(chalk191.green("\nExtraction complete"));
26854
+ console.log(chalk193.green("\nExtraction complete"));
26669
26855
  } else {
26670
- console.log(chalk191.dim("\nDry run. Use --apply to execute."));
26856
+ console.log(chalk193.dim("\nDry run. Use --apply to execute."));
26671
26857
  }
26672
26858
  }
26673
26859
 
26674
26860
  // src/commands/refactor/ignore.ts
26675
26861
  import fs33 from "fs";
26676
- import chalk192 from "chalk";
26862
+ import chalk194 from "chalk";
26677
26863
  var REFACTOR_YML_PATH2 = "refactor.yml";
26678
26864
  function ignore2(file) {
26679
26865
  if (!fs33.existsSync(file)) {
26680
- console.error(chalk192.red(`Error: File does not exist: ${file}`));
26866
+ console.error(chalk194.red(`Error: File does not exist: ${file}`));
26681
26867
  process.exit(1);
26682
26868
  }
26683
26869
  const content = fs33.readFileSync(file, "utf8");
@@ -26693,7 +26879,7 @@ function ignore2(file) {
26693
26879
  fs33.writeFileSync(REFACTOR_YML_PATH2, entry);
26694
26880
  }
26695
26881
  console.log(
26696
- chalk192.green(
26882
+ chalk194.green(
26697
26883
  `Added ${file} to refactor ignore list (max ${maxLines} lines)`
26698
26884
  )
26699
26885
  );
@@ -26702,12 +26888,12 @@ function ignore2(file) {
26702
26888
  // src/commands/refactor/rename/index.ts
26703
26889
  import fs36 from "fs";
26704
26890
  import path55 from "path";
26705
- import chalk195 from "chalk";
26891
+ import chalk197 from "chalk";
26706
26892
 
26707
26893
  // src/commands/refactor/rename/applyRename.ts
26708
26894
  import fs35 from "fs";
26709
26895
  import path52 from "path";
26710
- import chalk193 from "chalk";
26896
+ import chalk195 from "chalk";
26711
26897
 
26712
26898
  // src/commands/refactor/restructure/computeRewrites/index.ts
26713
26899
  import path51 from "path";
@@ -26812,13 +26998,13 @@ function applyRename(rewrites, sourcePath, destPath, cwd) {
26812
26998
  const updatedContents = applyRewrites(rewrites);
26813
26999
  for (const [file, content] of updatedContents) {
26814
27000
  fs35.writeFileSync(file, content, "utf8");
26815
- console.log(chalk193.cyan(` Updated imports in ${path52.relative(cwd, file)}`));
27001
+ console.log(chalk195.cyan(` Updated imports in ${path52.relative(cwd, file)}`));
26816
27002
  }
26817
27003
  const destDir = path52.dirname(destPath);
26818
27004
  if (!fs35.existsSync(destDir)) fs35.mkdirSync(destDir, { recursive: true });
26819
27005
  fs35.renameSync(sourcePath, destPath);
26820
27006
  console.log(
26821
- chalk193.white(
27007
+ chalk195.white(
26822
27008
  ` Moved ${path52.relative(cwd, sourcePath)} \u2192 ${path52.relative(cwd, destPath)}`
26823
27009
  )
26824
27010
  );
@@ -26905,16 +27091,16 @@ function computeRenameRewrites(sourcePath, destPath) {
26905
27091
 
26906
27092
  // src/commands/refactor/rename/printRenamePreview.ts
26907
27093
  import path54 from "path";
26908
- import chalk194 from "chalk";
27094
+ import chalk196 from "chalk";
26909
27095
  function printRenamePreview(rewrites, cwd) {
26910
27096
  for (const rewrite of rewrites) {
26911
27097
  console.log(
26912
- chalk194.dim(
27098
+ chalk196.dim(
26913
27099
  ` ${path54.relative(cwd, rewrite.file)}: ${rewrite.oldSpecifier} \u2192 ${rewrite.newSpecifier}`
26914
27100
  )
26915
27101
  );
26916
27102
  }
26917
- console.log(chalk194.dim("Dry run. Use --apply to execute."));
27103
+ console.log(chalk196.dim("Dry run. Use --apply to execute."));
26918
27104
  }
26919
27105
 
26920
27106
  // src/commands/refactor/rename/index.ts
@@ -26925,20 +27111,20 @@ async function rename(source, destination, options2 = {}) {
26925
27111
  const relSource = path55.relative(cwd, sourcePath);
26926
27112
  const relDest = path55.relative(cwd, destPath);
26927
27113
  if (!fs36.existsSync(sourcePath)) {
26928
- console.log(chalk195.red(`File not found: ${source}`));
27114
+ console.log(chalk197.red(`File not found: ${source}`));
26929
27115
  process.exit(1);
26930
27116
  }
26931
27117
  if (destPath !== sourcePath && fs36.existsSync(destPath)) {
26932
- console.log(chalk195.red(`Destination already exists: ${destination}`));
27118
+ console.log(chalk197.red(`Destination already exists: ${destination}`));
26933
27119
  process.exit(1);
26934
27120
  }
26935
- console.log(chalk195.bold(`Rename: ${relSource} \u2192 ${relDest}`));
26936
- console.log(chalk195.dim("Loading project..."));
26937
- console.log(chalk195.dim("Scanning imports across the project..."));
27121
+ console.log(chalk197.bold(`Rename: ${relSource} \u2192 ${relDest}`));
27122
+ console.log(chalk197.dim("Loading project..."));
27123
+ console.log(chalk197.dim("Scanning imports across the project..."));
26938
27124
  const rewrites = computeRenameRewrites(sourcePath, destPath);
26939
27125
  const affectedFiles = new Set(rewrites.map((r) => r.file)).size;
26940
27126
  console.log(
26941
- chalk195.dim(
27127
+ chalk197.dim(
26942
27128
  `${rewrites.length} import path(s) to update across ${affectedFiles} file(s)`
26943
27129
  )
26944
27130
  );
@@ -26947,11 +27133,11 @@ async function rename(source, destination, options2 = {}) {
26947
27133
  return;
26948
27134
  }
26949
27135
  applyRename(rewrites, sourcePath, destPath, cwd);
26950
- console.log(chalk195.green("Done"));
27136
+ console.log(chalk197.green("Done"));
26951
27137
  }
26952
27138
 
26953
27139
  // src/commands/refactor/renameSymbol/index.ts
26954
- import chalk196 from "chalk";
27140
+ import chalk198 from "chalk";
26955
27141
 
26956
27142
  // src/commands/refactor/renameSymbol/findSymbol.ts
26957
27143
  import { SyntaxKind as SyntaxKind15 } from "ts-morph";
@@ -26997,33 +27183,33 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
26997
27183
  const { project, sourceFile } = loadProjectFile(file);
26998
27184
  const symbol = findSymbol(sourceFile, oldName);
26999
27185
  if (!symbol) {
27000
- console.log(chalk196.red(`Symbol "${oldName}" not found in ${file}`));
27186
+ console.log(chalk198.red(`Symbol "${oldName}" not found in ${file}`));
27001
27187
  process.exit(1);
27002
27188
  }
27003
27189
  const grouped = groupReferences(symbol, cwd);
27004
27190
  const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
27005
27191
  console.log(
27006
- chalk196.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
27192
+ chalk198.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
27007
27193
  `)
27008
27194
  );
27009
27195
  for (const [refFile, lines2] of grouped) {
27010
27196
  console.log(
27011
- ` ${chalk196.dim(refFile)}: lines ${chalk196.cyan(lines2.join(", "))}`
27197
+ ` ${chalk198.dim(refFile)}: lines ${chalk198.cyan(lines2.join(", "))}`
27012
27198
  );
27013
27199
  }
27014
27200
  if (options2.apply) {
27015
27201
  symbol.rename(newName);
27016
27202
  await project.save();
27017
- console.log(chalk196.green(`
27203
+ console.log(chalk198.green(`
27018
27204
  Renamed ${oldName} \u2192 ${newName}`));
27019
27205
  } else {
27020
- console.log(chalk196.dim("\nDry run. Use --apply to execute."));
27206
+ console.log(chalk198.dim("\nDry run. Use --apply to execute."));
27021
27207
  }
27022
27208
  }
27023
27209
 
27024
27210
  // src/commands/refactor/restructure/index.ts
27025
27211
  import path63 from "path";
27026
- import chalk199 from "chalk";
27212
+ import chalk201 from "chalk";
27027
27213
 
27028
27214
  // src/commands/refactor/restructure/clusterDirectories.ts
27029
27215
  import path57 from "path";
@@ -27102,50 +27288,50 @@ function clusterFiles(graph) {
27102
27288
 
27103
27289
  // src/commands/refactor/restructure/displayPlan.ts
27104
27290
  import path59 from "path";
27105
- import chalk197 from "chalk";
27291
+ import chalk199 from "chalk";
27106
27292
  function relPath(filePath) {
27107
27293
  return path59.relative(process.cwd(), filePath);
27108
27294
  }
27109
27295
  function displayMoves(plan2) {
27110
27296
  if (plan2.moves.length === 0) return;
27111
- console.log(chalk197.bold("\nFile moves:"));
27297
+ console.log(chalk199.bold("\nFile moves:"));
27112
27298
  for (const move2 of plan2.moves) {
27113
27299
  console.log(
27114
- ` ${chalk197.red(relPath(move2.from))} \u2192 ${chalk197.green(relPath(move2.to))}`
27300
+ ` ${chalk199.red(relPath(move2.from))} \u2192 ${chalk199.green(relPath(move2.to))}`
27115
27301
  );
27116
- console.log(chalk197.dim(` ${move2.reason}`));
27302
+ console.log(chalk199.dim(` ${move2.reason}`));
27117
27303
  }
27118
27304
  }
27119
27305
  function displayRewrites(rewrites) {
27120
27306
  if (rewrites.length === 0) return;
27121
27307
  const affectedFiles = new Set(rewrites.map((r) => r.file));
27122
- console.log(chalk197.bold(`
27308
+ console.log(chalk199.bold(`
27123
27309
  Import rewrites (${affectedFiles.size} files):`));
27124
27310
  for (const file of affectedFiles) {
27125
- console.log(` ${chalk197.cyan(relPath(file))}:`);
27311
+ console.log(` ${chalk199.cyan(relPath(file))}:`);
27126
27312
  for (const { oldSpecifier, newSpecifier } of rewrites.filter(
27127
27313
  (r) => r.file === file
27128
27314
  )) {
27129
27315
  console.log(
27130
- ` ${chalk197.red(`"${oldSpecifier}"`)} \u2192 ${chalk197.green(`"${newSpecifier}"`)}`
27316
+ ` ${chalk199.red(`"${oldSpecifier}"`)} \u2192 ${chalk199.green(`"${newSpecifier}"`)}`
27131
27317
  );
27132
27318
  }
27133
27319
  }
27134
27320
  }
27135
27321
  function displayPlan2(plan2) {
27136
27322
  if (plan2.warnings.length > 0) {
27137
- console.log(chalk197.yellow("\nWarnings:"));
27138
- for (const w of plan2.warnings) console.log(chalk197.yellow(` ${w}`));
27323
+ console.log(chalk199.yellow("\nWarnings:"));
27324
+ for (const w of plan2.warnings) console.log(chalk199.yellow(` ${w}`));
27139
27325
  }
27140
27326
  if (plan2.newDirectories.length > 0) {
27141
- console.log(chalk197.bold("\nNew directories:"));
27327
+ console.log(chalk199.bold("\nNew directories:"));
27142
27328
  for (const dir of plan2.newDirectories)
27143
- console.log(chalk197.green(` ${dir}/`));
27329
+ console.log(chalk199.green(` ${dir}/`));
27144
27330
  }
27145
27331
  displayMoves(plan2);
27146
27332
  displayRewrites(plan2.rewrites);
27147
27333
  console.log(
27148
- chalk197.dim(
27334
+ chalk199.dim(
27149
27335
  `
27150
27336
  Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports rewritten`
27151
27337
  )
@@ -27155,18 +27341,18 @@ Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports r
27155
27341
  // src/commands/refactor/restructure/executePlan.ts
27156
27342
  import fs37 from "fs";
27157
27343
  import path60 from "path";
27158
- import chalk198 from "chalk";
27344
+ import chalk200 from "chalk";
27159
27345
  function executePlan(plan2) {
27160
27346
  const updatedContents = applyRewrites(plan2.rewrites);
27161
27347
  for (const [file, content] of updatedContents) {
27162
27348
  fs37.writeFileSync(file, content, "utf8");
27163
27349
  console.log(
27164
- chalk198.cyan(` Rewrote imports in ${path60.relative(process.cwd(), file)}`)
27350
+ chalk200.cyan(` Rewrote imports in ${path60.relative(process.cwd(), file)}`)
27165
27351
  );
27166
27352
  }
27167
27353
  for (const dir of plan2.newDirectories) {
27168
27354
  fs37.mkdirSync(dir, { recursive: true });
27169
- console.log(chalk198.green(` Created ${path60.relative(process.cwd(), dir)}/`));
27355
+ console.log(chalk200.green(` Created ${path60.relative(process.cwd(), dir)}/`));
27170
27356
  }
27171
27357
  for (const move2 of plan2.moves) {
27172
27358
  const targetDir = path60.dirname(move2.to);
@@ -27175,7 +27361,7 @@ function executePlan(plan2) {
27175
27361
  }
27176
27362
  fs37.renameSync(move2.from, move2.to);
27177
27363
  console.log(
27178
- chalk198.white(
27364
+ chalk200.white(
27179
27365
  ` Moved ${path60.relative(process.cwd(), move2.from)} \u2192 ${path60.relative(process.cwd(), move2.to)}`
27180
27366
  )
27181
27367
  );
@@ -27190,7 +27376,7 @@ function removeEmptyDirectories(dirs) {
27190
27376
  if (entries.length === 0) {
27191
27377
  fs37.rmdirSync(dir);
27192
27378
  console.log(
27193
- chalk198.dim(
27379
+ chalk200.dim(
27194
27380
  ` Removed empty directory ${path60.relative(process.cwd(), dir)}`
27195
27381
  )
27196
27382
  );
@@ -27323,22 +27509,22 @@ async function restructure(pattern2, options2 = {}) {
27323
27509
  const targetPattern = pattern2 ?? "src";
27324
27510
  const files = findSourceFiles2(targetPattern);
27325
27511
  if (files.length === 0) {
27326
- console.log(chalk199.yellow("No files found matching pattern"));
27512
+ console.log(chalk201.yellow("No files found matching pattern"));
27327
27513
  return;
27328
27514
  }
27329
27515
  const tsConfigPath = findTsConfig(path63.resolve(files[0]));
27330
27516
  const plan2 = buildPlan3(files, tsConfigPath);
27331
27517
  if (plan2.moves.length === 0) {
27332
- console.log(chalk199.green("No restructuring needed"));
27518
+ console.log(chalk201.green("No restructuring needed"));
27333
27519
  return;
27334
27520
  }
27335
27521
  displayPlan2(plan2);
27336
27522
  if (options2.apply) {
27337
- console.log(chalk199.bold("\nApplying changes..."));
27523
+ console.log(chalk201.bold("\nApplying changes..."));
27338
27524
  executePlan(plan2);
27339
- console.log(chalk199.green("\nRestructuring complete"));
27525
+ console.log(chalk201.green("\nRestructuring complete"));
27340
27526
  } else {
27341
- console.log(chalk199.dim("\nDry run. Use --apply to execute."));
27527
+ console.log(chalk201.dim("\nDry run. Use --apply to execute."));
27342
27528
  }
27343
27529
  }
27344
27530
 
@@ -27379,10 +27565,10 @@ function registerRefactor(program2) {
27379
27565
  }
27380
27566
 
27381
27567
  // src/commands/review/checkoutOnlySession.ts
27382
- import { randomUUID as randomUUID15 } from "crypto";
27568
+ import { randomUUID as randomUUID16 } from "crypto";
27383
27569
  async function checkoutOnlySession(number) {
27384
27570
  await checkoutPr(number);
27385
- const claudeSessionId = randomUUID15();
27571
+ const claudeSessionId = randomUUID16();
27386
27572
  emitActivity({ kind: "command", name: "review", claudeSessionId });
27387
27573
  const { done: done2 } = spawnClaude("", {
27388
27574
  permissionMode: "acceptEdits",
@@ -27865,15 +28051,15 @@ function runReviewSubmission(mutation, body) {
27865
28051
  }
27866
28052
 
27867
28053
  // src/commands/review/submitBodyOnlyReview.ts
27868
- var MUTATION = `mutation($prId: ID!, $body: String) { addPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
28054
+ var MUTATION3 = `mutation($prId: ID!, $body: String) { addPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
27869
28055
  function submitBodyOnlyReview(body) {
27870
- runReviewSubmission(MUTATION, body);
28056
+ runReviewSubmission(MUTATION3, body);
27871
28057
  }
27872
28058
 
27873
28059
  // src/commands/review/submitPendingReview.ts
27874
- var MUTATION2 = `mutation($prId: ID!, $body: String) { submitPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
28060
+ var MUTATION4 = `mutation($prId: ID!, $body: String) { submitPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
27875
28061
  function submitPendingReview(body) {
27876
- runReviewSubmission(MUTATION2, body);
28062
+ runReviewSubmission(MUTATION4, body);
27877
28063
  }
27878
28064
 
27879
28065
  // src/commands/review/postAndMaybeSubmit.ts
@@ -27996,18 +28182,18 @@ function partitionFindingsByDiff(findings, index3) {
27996
28182
  }
27997
28183
 
27998
28184
  // src/commands/review/warnOutOfDiff.ts
27999
- import chalk200 from "chalk";
28185
+ import chalk202 from "chalk";
28000
28186
  function warnOutOfDiff(outOfDiff) {
28001
28187
  if (outOfDiff.length === 0) return;
28002
28188
  console.warn(
28003
- chalk200.yellow(
28189
+ chalk202.yellow(
28004
28190
  `Moved ${outOfDiff.length} finding(s) whose lines fall outside the PR diff into the review body (GitHub cannot anchor a comment on these):`
28005
28191
  )
28006
28192
  );
28007
28193
  for (const finding of outOfDiff) {
28008
28194
  const range = finding.startLine !== void 0 ? `${finding.startLine}-${finding.line}` : `${finding.line}`;
28009
28195
  console.warn(
28010
- ` ${chalk200.yellow("\xB7")} ${finding.title} ${chalk200.dim(
28196
+ ` ${chalk202.yellow("\xB7")} ${finding.title} ${chalk202.dim(
28011
28197
  `(${finding.file}:${range})`
28012
28198
  )}`
28013
28199
  );
@@ -28031,18 +28217,18 @@ function selectInDiffFindings(lineBound, prDiff) {
28031
28217
  }
28032
28218
 
28033
28219
  // src/commands/review/warnUnlocated.ts
28034
- import chalk201 from "chalk";
28220
+ import chalk203 from "chalk";
28035
28221
  function warnUnlocated(unlocated) {
28036
28222
  if (unlocated.length === 0) return;
28037
28223
  console.warn(
28038
- chalk201.yellow(
28224
+ chalk203.yellow(
28039
28225
  `Moved ${unlocated.length} finding(s) without a parseable file:line into the review body:`
28040
28226
  )
28041
28227
  );
28042
28228
  for (const finding of unlocated) {
28043
- const where = finding.location || chalk201.dim("missing");
28229
+ const where = finding.location || chalk203.dim("missing");
28044
28230
  console.warn(
28045
- ` ${chalk201.yellow("\xB7")} ${finding.title} ${chalk201.dim(`(${where})`)}`
28231
+ ` ${chalk203.yellow("\xB7")} ${finding.title} ${chalk203.dim(`(${where})`)}`
28046
28232
  );
28047
28233
  }
28048
28234
  }
@@ -29297,7 +29483,7 @@ function registerReview(program2) {
29297
29483
  }
29298
29484
 
29299
29485
  // src/commands/seq/seqAuth.ts
29300
- import chalk203 from "chalk";
29486
+ import chalk205 from "chalk";
29301
29487
 
29302
29488
  // src/commands/seq/loadConnections.ts
29303
29489
  function loadConnections2() {
@@ -29326,10 +29512,10 @@ function setDefaultConnection(name) {
29326
29512
  }
29327
29513
 
29328
29514
  // src/shared/assertUniqueName.ts
29329
- import chalk202 from "chalk";
29515
+ import chalk204 from "chalk";
29330
29516
  function assertUniqueName(existingNames, name) {
29331
29517
  if (existingNames.includes(name)) {
29332
- console.error(chalk202.red(`Connection "${name}" already exists.`));
29518
+ console.error(chalk204.red(`Connection "${name}" already exists.`));
29333
29519
  process.exit(1);
29334
29520
  }
29335
29521
  }
@@ -29347,16 +29533,16 @@ async function promptConnection2(existingNames) {
29347
29533
  var seqAuth = createConnectionAuth({
29348
29534
  load: loadConnections2,
29349
29535
  save: saveConnections2,
29350
- format: (c) => `${chalk203.bold(c.name)} ${c.url}`,
29536
+ format: (c) => `${chalk205.bold(c.name)} ${c.url}`,
29351
29537
  promptNew: promptConnection2,
29352
29538
  onFirst: (c) => setDefaultConnection(c.name)
29353
29539
  });
29354
29540
 
29355
29541
  // src/commands/seq/seqQuery.ts
29356
- import chalk207 from "chalk";
29542
+ import chalk209 from "chalk";
29357
29543
 
29358
29544
  // src/commands/seq/fetchSeq.ts
29359
- import chalk204 from "chalk";
29545
+ import chalk206 from "chalk";
29360
29546
  async function fetchSeq(conn, path80, params) {
29361
29547
  const url = `${conn.url}${path80}?${params}`;
29362
29548
  const response = await fetch(url, {
@@ -29367,7 +29553,7 @@ async function fetchSeq(conn, path80, params) {
29367
29553
  });
29368
29554
  if (!response.ok) {
29369
29555
  const body = await response.text();
29370
- console.error(chalk204.red(`Seq returned ${response.status}: ${body}`));
29556
+ console.error(chalk206.red(`Seq returned ${response.status}: ${body}`));
29371
29557
  process.exit(1);
29372
29558
  }
29373
29559
  return response;
@@ -29426,23 +29612,23 @@ async function fetchSeqEvents(conn, params) {
29426
29612
  }
29427
29613
 
29428
29614
  // src/commands/seq/formatEvent.ts
29429
- import chalk205 from "chalk";
29615
+ import chalk207 from "chalk";
29430
29616
  function levelColor(level) {
29431
29617
  switch (level) {
29432
29618
  case "Fatal":
29433
- return chalk205.bgRed.white;
29619
+ return chalk207.bgRed.white;
29434
29620
  case "Error":
29435
- return chalk205.red;
29621
+ return chalk207.red;
29436
29622
  case "Warning":
29437
- return chalk205.yellow;
29623
+ return chalk207.yellow;
29438
29624
  case "Information":
29439
- return chalk205.cyan;
29625
+ return chalk207.cyan;
29440
29626
  case "Debug":
29441
- return chalk205.gray;
29627
+ return chalk207.gray;
29442
29628
  case "Verbose":
29443
- return chalk205.dim;
29629
+ return chalk207.dim;
29444
29630
  default:
29445
- return chalk205.white;
29631
+ return chalk207.white;
29446
29632
  }
29447
29633
  }
29448
29634
  function levelAbbrev(level) {
@@ -29483,12 +29669,12 @@ function formatTimestamp(iso) {
29483
29669
  function formatEvent(event) {
29484
29670
  const color = levelColor(event.Level);
29485
29671
  const abbrev = levelAbbrev(event.Level);
29486
- const ts8 = chalk205.dim(formatTimestamp(event.Timestamp));
29672
+ const ts8 = chalk207.dim(formatTimestamp(event.Timestamp));
29487
29673
  const msg = renderMessage(event);
29488
29674
  const lines2 = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
29489
29675
  if (event.Exception) {
29490
29676
  for (const line of event.Exception.split("\n")) {
29491
- lines2.push(chalk205.red(` ${line}`));
29677
+ lines2.push(chalk207.red(` ${line}`));
29492
29678
  }
29493
29679
  }
29494
29680
  return lines2.join("\n");
@@ -29521,11 +29707,11 @@ function rejectTimestampFilter(filter) {
29521
29707
  }
29522
29708
 
29523
29709
  // src/shared/resolveNamedConnection.ts
29524
- import chalk206 from "chalk";
29710
+ import chalk208 from "chalk";
29525
29711
  function resolveNamedConnection(connections, requested, defaultName, kind, authCommand) {
29526
29712
  if (connections.length === 0) {
29527
29713
  console.error(
29528
- chalk206.red(
29714
+ chalk208.red(
29529
29715
  `No ${kind} connections configured. Run '${authCommand}' first.`
29530
29716
  )
29531
29717
  );
@@ -29534,7 +29720,7 @@ function resolveNamedConnection(connections, requested, defaultName, kind, authC
29534
29720
  const target = requested ?? defaultName ?? connections[0].name;
29535
29721
  const connection = connections.find((c) => c.name === target);
29536
29722
  if (!connection) {
29537
- console.error(chalk206.red(`${kind} connection "${target}" not found.`));
29723
+ console.error(chalk208.red(`${kind} connection "${target}" not found.`));
29538
29724
  process.exit(1);
29539
29725
  }
29540
29726
  return connection;
@@ -29563,7 +29749,7 @@ async function seqQuery(filter, options2) {
29563
29749
  new URLSearchParams({ filter, count: String(count8) })
29564
29750
  );
29565
29751
  if (events.length === 0) {
29566
- console.log(chalk207.yellow("No events found."));
29752
+ console.log(chalk209.yellow("No events found."));
29567
29753
  return;
29568
29754
  }
29569
29755
  if (options2.json) {
@@ -29574,11 +29760,11 @@ async function seqQuery(filter, options2) {
29574
29760
  for (const event of chronological) {
29575
29761
  console.log(formatEvent(event));
29576
29762
  }
29577
- console.log(chalk207.dim(`
29763
+ console.log(chalk209.dim(`
29578
29764
  ${events.length} events`));
29579
29765
  if (events.length >= count8) {
29580
29766
  console.log(
29581
- chalk207.yellow(
29767
+ chalk209.yellow(
29582
29768
  `Results limited to ${count8}. Use --count to retrieve more.`
29583
29769
  )
29584
29770
  );
@@ -29586,10 +29772,10 @@ ${events.length} events`));
29586
29772
  }
29587
29773
 
29588
29774
  // src/shared/setNamedDefaultConnection.ts
29589
- import chalk208 from "chalk";
29775
+ import chalk210 from "chalk";
29590
29776
  function setNamedDefaultConnection(connections, name, setDefault, kind) {
29591
29777
  if (!connections.find((c) => c.name === name)) {
29592
- console.error(chalk208.red(`Connection "${name}" not found.`));
29778
+ console.error(chalk210.red(`Connection "${name}" not found.`));
29593
29779
  process.exit(1);
29594
29780
  }
29595
29781
  setDefault(name);
@@ -29638,7 +29824,7 @@ function registerSignal(program2) {
29638
29824
  }
29639
29825
 
29640
29826
  // src/commands/sql/sqlAuth.ts
29641
- import chalk210 from "chalk";
29827
+ import chalk212 from "chalk";
29642
29828
 
29643
29829
  // src/commands/sql/loadConnections.ts
29644
29830
  function loadConnections3() {
@@ -29667,7 +29853,7 @@ function setDefaultConnection2(name) {
29667
29853
  }
29668
29854
 
29669
29855
  // src/commands/sql/promptConnection.ts
29670
- import chalk209 from "chalk";
29856
+ import chalk211 from "chalk";
29671
29857
  async function promptConnection3(existingNames) {
29672
29858
  const name = await promptInput("name", "Connection name:", "default");
29673
29859
  assertUniqueName(existingNames, name);
@@ -29675,7 +29861,7 @@ async function promptConnection3(existingNames) {
29675
29861
  const portStr = await promptInput("port", "Port:", "1433");
29676
29862
  const port = Number.parseInt(portStr, 10);
29677
29863
  if (!Number.isFinite(port)) {
29678
- console.error(chalk209.red(`Invalid port "${portStr}".`));
29864
+ console.error(chalk211.red(`Invalid port "${portStr}".`));
29679
29865
  process.exit(1);
29680
29866
  }
29681
29867
  const user = await promptInput("user", "User:");
@@ -29688,13 +29874,13 @@ async function promptConnection3(existingNames) {
29688
29874
  var sqlAuth = createConnectionAuth({
29689
29875
  load: loadConnections3,
29690
29876
  save: saveConnections3,
29691
- format: (c) => `${chalk210.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
29877
+ format: (c) => `${chalk212.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
29692
29878
  promptNew: promptConnection3,
29693
29879
  onFirst: (c) => setDefaultConnection2(c.name)
29694
29880
  });
29695
29881
 
29696
29882
  // src/commands/sql/printTable.ts
29697
- import chalk211 from "chalk";
29883
+ import chalk213 from "chalk";
29698
29884
  function formatCell(value) {
29699
29885
  if (value === null || value === void 0) return "";
29700
29886
  if (value instanceof Date) return value.toISOString();
@@ -29703,7 +29889,7 @@ function formatCell(value) {
29703
29889
  }
29704
29890
  function printTable(rows) {
29705
29891
  if (rows.length === 0) {
29706
- console.log(chalk211.yellow("(no rows)"));
29892
+ console.log(chalk213.yellow("(no rows)"));
29707
29893
  return;
29708
29894
  }
29709
29895
  const columns = Object.keys(rows[0]);
@@ -29711,13 +29897,13 @@ function printTable(rows) {
29711
29897
  (col) => Math.max(col.length, ...rows.map((r) => formatCell(r[col]).length))
29712
29898
  );
29713
29899
  const header = columns.map((c, i) => c.padEnd(widths[i])).join(" ");
29714
- console.log(chalk211.dim(header));
29715
- console.log(chalk211.dim("-".repeat(header.length)));
29900
+ console.log(chalk213.dim(header));
29901
+ console.log(chalk213.dim("-".repeat(header.length)));
29716
29902
  for (const row of rows) {
29717
29903
  const line = columns.map((c, i) => formatCell(row[c]).padEnd(widths[i])).join(" ");
29718
29904
  console.log(line);
29719
29905
  }
29720
- console.log(chalk211.dim(`
29906
+ console.log(chalk213.dim(`
29721
29907
  ${rows.length} row${rows.length === 1 ? "" : "s"}`));
29722
29908
  }
29723
29909
 
@@ -29777,7 +29963,7 @@ async function sqlColumns(table, connectionName) {
29777
29963
  }
29778
29964
 
29779
29965
  // src/commands/sql/sqlMutate.ts
29780
- import chalk212 from "chalk";
29966
+ import chalk214 from "chalk";
29781
29967
 
29782
29968
  // src/commands/sql/isMutation.ts
29783
29969
  var MUTATION_KEYWORDS = [
@@ -29811,7 +29997,7 @@ function isMutation(sql25) {
29811
29997
  async function sqlMutate(query, connectionName) {
29812
29998
  if (!isMutation(query)) {
29813
29999
  console.error(
29814
- chalk212.red(
30000
+ chalk214.red(
29815
30001
  "assist sql mutate refuses non-mutating statements. Use `assist sql query` instead."
29816
30002
  )
29817
30003
  );
@@ -29821,18 +30007,18 @@ async function sqlMutate(query, connectionName) {
29821
30007
  const pool = await sqlConnect(conn);
29822
30008
  try {
29823
30009
  const result = await pool.request().query(query);
29824
- console.log(chalk212.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
30010
+ console.log(chalk214.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
29825
30011
  } finally {
29826
30012
  await pool.close();
29827
30013
  }
29828
30014
  }
29829
30015
 
29830
30016
  // src/commands/sql/sqlQuery.ts
29831
- import chalk213 from "chalk";
30017
+ import chalk215 from "chalk";
29832
30018
  async function sqlQuery(query, connectionName) {
29833
30019
  if (isMutation(query)) {
29834
30020
  console.error(
29835
- chalk213.red(
30021
+ chalk215.red(
29836
30022
  "assist sql query refuses mutating statements. Use `assist sql mutate` instead."
29837
30023
  )
29838
30024
  );
@@ -29847,7 +30033,7 @@ async function sqlQuery(query, connectionName) {
29847
30033
  printTable(rows);
29848
30034
  } else {
29849
30035
  console.log(
29850
- chalk213.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
30036
+ chalk215.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
29851
30037
  );
29852
30038
  }
29853
30039
  } finally {
@@ -29992,7 +30178,7 @@ function reportPrune(label2, result, force) {
29992
30178
  // src/commands/sync/syncClaudeMd.ts
29993
30179
  import * as fs41 from "fs";
29994
30180
  import * as path66 from "path";
29995
- import chalk214 from "chalk";
30181
+ import chalk216 from "chalk";
29996
30182
  async function syncClaudeMd(claudeDir, targetBase, options2) {
29997
30183
  const source = path66.join(claudeDir, "CLAUDE.md");
29998
30184
  const target = path66.join(targetBase, "CLAUDE.md");
@@ -30001,14 +30187,14 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
30001
30187
  const targetContent = fs41.readFileSync(target, "utf8");
30002
30188
  if (sourceContent !== targetContent) {
30003
30189
  console.log(
30004
- chalk214.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
30190
+ chalk216.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
30005
30191
  );
30006
30192
  console.log();
30007
30193
  printDiff(targetContent, sourceContent);
30008
30194
  if (!options2?.yes) {
30009
30195
  printAutoConfirmHint();
30010
30196
  const confirm = await promptConfirm(
30011
- chalk214.red("Overwrite existing CLAUDE.md?"),
30197
+ chalk216.red("Overwrite existing CLAUDE.md?"),
30012
30198
  false
30013
30199
  );
30014
30200
  if (!confirm) {
@@ -30241,7 +30427,7 @@ function syncPi(claudeDir, options2) {
30241
30427
  // src/commands/sync/syncSettings.ts
30242
30428
  import * as fs47 from "fs";
30243
30429
  import * as path73 from "path";
30244
- import chalk215 from "chalk";
30430
+ import chalk217 from "chalk";
30245
30431
  async function syncSettings(claudeDir, targetBase, options2) {
30246
30432
  const source = path73.join(claudeDir, "settings.json");
30247
30433
  const target = path73.join(targetBase, "settings.json");
@@ -30260,7 +30446,7 @@ async function syncSettings(claudeDir, targetBase, options2) {
30260
30446
  if (mergedContent !== normalizedTarget) {
30261
30447
  if (!options2?.yes) {
30262
30448
  console.log(
30263
- chalk215.yellow(
30449
+ chalk217.yellow(
30264
30450
  "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
30265
30451
  )
30266
30452
  );
@@ -30268,7 +30454,7 @@ async function syncSettings(claudeDir, targetBase, options2) {
30268
30454
  printDiff(targetContent, mergedContent);
30269
30455
  printAutoConfirmHint();
30270
30456
  const confirm = await promptConfirm(
30271
- chalk215.red("Overwrite existing settings.json?"),
30457
+ chalk217.red("Overwrite existing settings.json?"),
30272
30458
  false
30273
30459
  );
30274
30460
  if (!confirm) {
@@ -31695,7 +31881,7 @@ function registerWatch(program2) {
31695
31881
 
31696
31882
  // src/commands/roam/auth.ts
31697
31883
  import { randomBytes } from "crypto";
31698
- import chalk216 from "chalk";
31884
+ import chalk218 from "chalk";
31699
31885
 
31700
31886
  // src/commands/roam/waitForCallback.ts
31701
31887
  import { createServer as createServer3 } from "http";
@@ -31826,13 +32012,13 @@ async function auth() {
31826
32012
  saveGlobalConfig(config);
31827
32013
  const state = randomBytes(16).toString("hex");
31828
32014
  console.log(
31829
- chalk216.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
32015
+ chalk218.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
31830
32016
  );
31831
- console.log(chalk216.white("http://localhost:14523/callback\n"));
31832
- console.log(chalk216.blue("Opening browser for authorization..."));
31833
- console.log(chalk216.dim("Waiting for authorization callback..."));
32017
+ console.log(chalk218.white("http://localhost:14523/callback\n"));
32018
+ console.log(chalk218.blue("Opening browser for authorization..."));
32019
+ console.log(chalk218.dim("Waiting for authorization callback..."));
31834
32020
  const { code, redirectUri } = await authorizeInBrowser(clientId, state);
31835
- console.log(chalk216.dim("Exchanging code for tokens..."));
32021
+ console.log(chalk218.dim("Exchanging code for tokens..."));
31836
32022
  const tokens = await exchangeToken({
31837
32023
  code,
31838
32024
  clientId,
@@ -31848,7 +32034,7 @@ async function auth() {
31848
32034
  };
31849
32035
  saveGlobalConfig(config);
31850
32036
  console.log(
31851
- chalk216.green("Roam credentials and tokens saved to ~/.assist.yml")
32037
+ chalk218.green("Roam credentials and tokens saved to ~/.assist.yml")
31852
32038
  );
31853
32039
  }
31854
32040
 
@@ -32199,7 +32385,7 @@ import { execSync as execSync60 } from "child_process";
32199
32385
  import { existsSync as existsSync72, mkdirSync as mkdirSync31, unlinkSync as unlinkSync22, writeFileSync as writeFileSync46 } from "fs";
32200
32386
  import { tmpdir as tmpdir8 } from "os";
32201
32387
  import { join as join89, resolve as resolve20 } from "path";
32202
- import chalk217 from "chalk";
32388
+ import chalk219 from "chalk";
32203
32389
 
32204
32390
  // src/commands/screenshot/captureWindowPs1.ts
32205
32391
  var captureWindowPs1 = `
@@ -32350,13 +32536,13 @@ function screenshot(processName) {
32350
32536
  const config = loadConfig();
32351
32537
  const outputDir = resolve20(config.screenshot.outputDir);
32352
32538
  const outputPath = buildOutputPath(outputDir, processName);
32353
- console.log(chalk217.gray(`Capturing window for process "${processName}" ...`));
32539
+ console.log(chalk219.gray(`Capturing window for process "${processName}" ...`));
32354
32540
  try {
32355
32541
  runPowerShellScript(processName, outputPath);
32356
- console.log(chalk217.green(`Screenshot saved: ${outputPath}`));
32542
+ console.log(chalk219.green(`Screenshot saved: ${outputPath}`));
32357
32543
  } catch (error) {
32358
32544
  const msg = error instanceof Error ? error.message : String(error);
32359
- console.error(chalk217.red(`Failed to capture screenshot: ${msg}`));
32545
+ console.error(chalk219.red(`Failed to capture screenshot: ${msg}`));
32360
32546
  process.exit(1);
32361
32547
  }
32362
32548
  }
@@ -32823,7 +33009,7 @@ var ClientHub = class extends Set {
32823
33009
  };
32824
33010
 
32825
33011
  // src/commands/sessions/daemon/createSession.ts
32826
- import { randomUUID as randomUUID16 } from "crypto";
33012
+ import { randomUUID as randomUUID17 } from "crypto";
32827
33013
 
32828
33014
  // src/commands/sessions/daemon/sessionBase.ts
32829
33015
  function sessionBase(id, status3) {
@@ -33019,7 +33205,7 @@ function spawnRun(opts) {
33019
33205
  function createSession(id, { prompt, cwd, design, auto, harness, holdPty } = {}) {
33020
33206
  if (harness && harness !== "claude")
33021
33207
  return createHarnessSession(id, harness, prompt, cwd, holdPty);
33022
- const claudeSessionId = randomUUID16();
33208
+ const claudeSessionId = randomUUID17();
33023
33209
  return {
33024
33210
  ...sessionBase(id, prompt ? "running" : "waiting"),
33025
33211
  name: `Session ${id}`,
@@ -33618,7 +33804,8 @@ var PREVIEW_KINDS = [
33618
33804
  "pr-comment",
33619
33805
  "github-issue",
33620
33806
  "github-issue-comment",
33621
- "github-issue-edit"
33807
+ "github-issue-edit",
33808
+ "miro-board"
33622
33809
  ];
33623
33810
  function isPreviewKind(value) {
33624
33811
  return PREVIEW_KINDS.includes(value);
@@ -33631,6 +33818,7 @@ function previewTargetLabel(kind, itemType, prNumber, draft) {
33631
33818
  if (kind === "github-issue-comment") return "github issue comment";
33632
33819
  if (kind === "github-issue-edit") return "github issue edit";
33633
33820
  if (kind === "github-issue") return "github issue";
33821
+ if (kind === "miro-board") return "miro anchors";
33634
33822
  if (kind === "backlog-item") return `backlog ${itemType}`;
33635
33823
  if (prNumber !== null) return `edit #${prNumber}`;
33636
33824
  return draft ? "create draft" : "create";
@@ -35090,7 +35278,7 @@ function codexRespawnPlan(session) {
35090
35278
  }
35091
35279
 
35092
35280
  // src/commands/sessions/daemon/interactiveRespawnPlan.ts
35093
- import { randomUUID as randomUUID17 } from "crypto";
35281
+ import { randomUUID as randomUUID18 } from "crypto";
35094
35282
  function interactiveRespawnPlan(session, resumes) {
35095
35283
  const { claudeSessionId, cwd, initialPrompt, design, auto } = session;
35096
35284
  if (!resumes) return null;
@@ -35110,7 +35298,7 @@ function interactiveRespawnPlan(session, resumes) {
35110
35298
  return null;
35111
35299
  }
35112
35300
  function freshClaudePlan(session, prompt, cwd) {
35113
- const claudeSessionId = randomUUID17();
35301
+ const claudeSessionId = randomUUID18();
35114
35302
  return {
35115
35303
  spawn: () => {
35116
35304
  session.claudeSessionId = claudeSessionId;
@@ -35995,10 +36183,10 @@ function startReusedRunPty(session, assistArgs, itemId2, hold, clients, onStatus
35995
36183
  }
35996
36184
 
35997
36185
  // src/commands/sessions/daemon/createWatcherSession.ts
35998
- import { randomUUID as randomUUID18 } from "crypto";
36186
+ import { randomUUID as randomUUID19 } from "crypto";
35999
36187
  var WATCH_PROMPT = "/watch";
36000
36188
  function createWatcherSession(id, cwd) {
36001
- const claudeSessionId = randomUUID18();
36189
+ const claudeSessionId = randomUUID19();
36002
36190
  return {
36003
36191
  ...sessionBase(id, "running"),
36004
36192
  name: `Session ${id}`,
@@ -38133,7 +38321,7 @@ function registerSetStatusCommand(cmd) {
38133
38321
 
38134
38322
  // src/commands/sessions/summarise/index.ts
38135
38323
  import * as fs56 from "fs";
38136
- import chalk218 from "chalk";
38324
+ import chalk220 from "chalk";
38137
38325
 
38138
38326
  // src/commands/sessions/summarise/shared.ts
38139
38327
  import * as fs55 from "fs";
@@ -38192,22 +38380,22 @@ ${firstMessage}`);
38192
38380
  async function summarise2(options2) {
38193
38381
  const files = await discoverSessionFiles();
38194
38382
  if (files.length === 0) {
38195
- console.log(chalk218.yellow("No sessions found."));
38383
+ console.log(chalk220.yellow("No sessions found."));
38196
38384
  return;
38197
38385
  }
38198
38386
  const toProcess = selectCandidates(files, options2);
38199
38387
  if (toProcess.length === 0) {
38200
- console.log(chalk218.green("All sessions already summarised."));
38388
+ console.log(chalk220.green("All sessions already summarised."));
38201
38389
  return;
38202
38390
  }
38203
38391
  console.log(
38204
- chalk218.cyan(
38392
+ chalk220.cyan(
38205
38393
  `Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
38206
38394
  )
38207
38395
  );
38208
38396
  const { succeeded, failed: failed2 } = processSessions(toProcess);
38209
38397
  console.log(
38210
- chalk218.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk218.yellow(`, ${failed2} skipped`) : "")
38398
+ chalk220.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk220.yellow(`, ${failed2} skipped`) : "")
38211
38399
  );
38212
38400
  }
38213
38401
  function selectCandidates(files, options2) {
@@ -38227,16 +38415,16 @@ function processSessions(files) {
38227
38415
  let failed2 = 0;
38228
38416
  for (let i = 0; i < files.length; i++) {
38229
38417
  const file = files[i];
38230
- process.stdout.write(chalk218.dim(` [${i + 1}/${files.length}] `));
38418
+ process.stdout.write(chalk220.dim(` [${i + 1}/${files.length}] `));
38231
38419
  const summary = summariseSession(file);
38232
38420
  if (summary) {
38233
38421
  writeSummary(file, summary);
38234
38422
  succeeded++;
38235
- process.stdout.write(`${chalk218.green("\u2713")} ${summary}
38423
+ process.stdout.write(`${chalk220.green("\u2713")} ${summary}
38236
38424
  `);
38237
38425
  } else {
38238
38426
  failed2++;
38239
- process.stdout.write(` ${chalk218.yellow("skip")}
38427
+ process.stdout.write(` ${chalk220.yellow("skip")}
38240
38428
  `);
38241
38429
  }
38242
38430
  }
@@ -38257,7 +38445,7 @@ function registerSessions(program2) {
38257
38445
  }
38258
38446
 
38259
38447
  // src/commands/statusLine.ts
38260
- import chalk220 from "chalk";
38448
+ import chalk222 from "chalk";
38261
38449
 
38262
38450
  // src/shared/contextLevel.ts
38263
38451
  function contextLevel(pct) {
@@ -38267,7 +38455,7 @@ function contextLevel(pct) {
38267
38455
  }
38268
38456
 
38269
38457
  // src/commands/buildLimitsSegment.ts
38270
- import chalk219 from "chalk";
38458
+ import chalk221 from "chalk";
38271
38459
 
38272
38460
  // src/shared/rateLimitLevel.ts
38273
38461
  var FIVE_HOUR_SECONDS = 5 * 3600;
@@ -38305,9 +38493,9 @@ function rateLimitLevel(pct, resetsAt, windowSeconds, now) {
38305
38493
 
38306
38494
  // src/commands/buildLimitsSegment.ts
38307
38495
  var LEVEL_COLOR = {
38308
- ok: chalk219.green,
38309
- warn: chalk219.yellow,
38310
- over: chalk219.red
38496
+ ok: chalk221.green,
38497
+ warn: chalk221.yellow,
38498
+ over: chalk221.red
38311
38499
  };
38312
38500
  function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel, now) {
38313
38501
  const level = rateLimitLevel(pct, resetsAt, windowSeconds, now);
@@ -38403,7 +38591,7 @@ async function relayUsage(claudeSessionId, transcriptPath2, usedPct) {
38403
38591
  }
38404
38592
 
38405
38593
  // src/commands/statusLine.ts
38406
- chalk220.level = 3;
38594
+ chalk222.level = 3;
38407
38595
  function formatNumber(num) {
38408
38596
  return num.toLocaleString("en-US");
38409
38597
  }
@@ -38411,9 +38599,9 @@ function colorizePercent(pct) {
38411
38599
  const label2 = `${Math.round(pct)}%`;
38412
38600
  switch (contextLevel(pct)) {
38413
38601
  case "red":
38414
- return chalk220.red(label2);
38602
+ return chalk222.red(label2);
38415
38603
  case "yellow":
38416
- return chalk220.yellow(label2);
38604
+ return chalk222.yellow(label2);
38417
38605
  default:
38418
38606
  return label2;
38419
38607
  }
@@ -38426,7 +38614,7 @@ async function statusLine() {
38426
38614
  const usedPct = data.context_window.used_percentage ?? 0;
38427
38615
  const dir = data.workspace?.current_dir ?? data.cwd;
38428
38616
  const branch2 = dir ? readGitBranch(toGitCwd(dir)) : null;
38429
- const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${chalk220.cyan(branch2)} | ` : "";
38617
+ const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${chalk222.cyan(branch2)} | ` : "";
38430
38618
  console.log(
38431
38619
  `${branchSegment}${model} | Tokens - ${formatNumber(totalIn)} \u2191 : ${formatNumber(totalOut)} \u2193 | Context - ${colorizePercent(usedPct)}${buildLimitsSegment(data.rate_limits)}`
38432
38620
  );
@@ -38496,10 +38684,10 @@ async function update2() {
38496
38684
  }
38497
38685
 
38498
38686
  // src/reportCliError.ts
38499
- import chalk221 from "chalk";
38687
+ import chalk223 from "chalk";
38500
38688
  function reportCliError(error) {
38501
38689
  if (error instanceof InvalidItemIdError || error instanceof AmbiguousRepoConfigError || error instanceof UnknownRepoConfigError || error instanceof MissingRunCwdError || error instanceof MiroExtractError) {
38502
- console.error(chalk221.red(error.message));
38690
+ console.error(chalk223.red(error.message));
38503
38691
  } else {
38504
38692
  console.error(error);
38505
38693
  }