@staff0rd/assist 0.577.0 → 0.578.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@staff0rd/assist",
9
- version: "0.577.0",
9
+ version: "0.578.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -16820,6 +16820,12 @@ function findBuiltinDenyRaw(rawCommand) {
16820
16820
  // src/shared/isApprovedRead.ts
16821
16821
  import { resolve as resolve13, sep } from "path";
16822
16822
 
16823
+ // src/shared/appliesFixStructure.ts
16824
+ var APPLY_RE = /^assist\s+github\s+issue\s+fix-structure\b.*\s--apply\b/;
16825
+ function appliesFixStructure(command) {
16826
+ return APPLY_RE.test(command);
16827
+ }
16828
+
16823
16829
  // src/shared/tokenize.ts
16824
16830
  function tokenize(command) {
16825
16831
  const tokens = [];
@@ -17046,6 +17052,7 @@ function isApprovedRead(command, toolName = "Bash") {
17046
17052
  if (isCdToCwd(command)) return "cd to current directory";
17047
17053
  const cdRead = isCdToReadAllowedDir(command);
17048
17054
  if (cdRead) return cdRead;
17055
+ if (appliesFixStructure(command)) return void 0;
17049
17056
  const matchedRead = findCliRead(command);
17050
17057
  if (matchedRead) return `Read-only CLI command: ${matchedRead}`;
17051
17058
  const matchedWrite = findCliWrite(command);
@@ -20695,309 +20702,178 @@ function parseTopCount(value) {
20695
20702
  return Number.parseInt(value, 10);
20696
20703
  }
20697
20704
 
20698
- // src/commands/github/issue/commentIssue.ts
20699
- import { execFileSync as execFileSync6 } from "child_process";
20705
+ // src/commands/github/issue/fixStructure/applyAndVerifySubtree.ts
20706
+ import chalk163 from "chalk";
20700
20707
 
20701
- // src/shared/validateProposedContent.ts
20702
- function validateProposedContent(labels, title, body) {
20703
- const { subject, context } = labels;
20704
- if (title.toLowerCase().includes("claude")) {
20705
- console.error(`Error: ${subject} title must not reference Claude`);
20706
- process.exit(1);
20707
- }
20708
- if (body.toLowerCase().includes("claude")) {
20709
- console.error(`Error: ${subject} body must not reference Claude`);
20710
- process.exit(1);
20711
- }
20712
- const titleBacklogIds = findBacklogRefs(title);
20713
- if (titleBacklogIds.length > 0) {
20714
- console.error(
20715
- backlogRefError(`${subject} title`, context, titleBacklogIds)
20716
- );
20717
- process.exit(1);
20718
- }
20719
- const bodyBacklogIds = findBacklogRefs(body);
20720
- if (bodyBacklogIds.length > 0) {
20721
- console.error(backlogRefError(`${subject} body`, context, bodyBacklogIds));
20722
- process.exit(1);
20723
- }
20724
- }
20708
+ // src/commands/github/issue/fixStructure/applyFixStructurePlan.ts
20709
+ import chalk162 from "chalk";
20725
20710
 
20726
- // src/commands/github/issue/reviewProposedIssueComment.ts
20727
- import { randomUUID as randomUUID7 } from "crypto";
20728
- async function reviewProposedIssueComment(title, body) {
20729
- const sessionId = process.env.ASSIST_SESSION_ID;
20730
- if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
20731
- await awaitPreviewApproval("GitHub issue comment preview", {
20732
- sessionId,
20733
- requestId: randomUUID7(),
20734
- title,
20735
- body,
20736
- prNumber: null,
20737
- kind: "github-issue-comment"
20711
+ // src/shared/runGhGraphqlJson.ts
20712
+ import { spawnSync as spawnSync5 } from "child_process";
20713
+ function runGhGraphqlJson(query, vars = {}) {
20714
+ const result = spawnSync5("gh", ["api", "graphql", "--input", "-"], {
20715
+ encoding: "utf8",
20716
+ windowsHide: true,
20717
+ input: JSON.stringify({ query, variables: vars }),
20718
+ maxBuffer: 64 * 1024 * 1024
20738
20719
  });
20720
+ if (result.status !== 0) throw new Error(result.stderr || result.stdout);
20721
+ throwOnGraphqlErrors(result.stdout);
20722
+ return result.stdout;
20739
20723
  }
20740
20724
 
20741
- // src/commands/github/issue/commentIssue.ts
20742
- var USAGE = "Usage: assist github issue comment <number> --body <body> [-R <owner>/<repo>]";
20743
- async function commentIssue(numberArg, options2) {
20744
- const number = Number.parseInt(numberArg, 10);
20745
- if (!Number.isInteger(number) || number <= 0 || !options2.body) {
20746
- console.error(USAGE);
20747
- process.exit(1);
20748
- }
20749
- const { body } = options2;
20750
- const target = options2.repo ? `${options2.repo}#${number}` : `issue #${number}`;
20751
- validateProposedContent(
20752
- { subject: "Comment", context: "GitHub issues" },
20753
- "",
20754
- body
20755
- );
20756
- await reviewProposedIssueComment(`Comment on ${target}`, body);
20757
- const args = ["issue", "comment", String(number), "--body", body];
20758
- if (options2.repo) args.push("--repo", options2.repo);
20759
- try {
20760
- execFileSync6("gh", args, { stdio: "inherit" });
20761
- } catch {
20762
- process.exit(1);
20763
- }
20764
- console.log(`Comment posted to ${target}`);
20725
+ // src/commands/github/issue/fixStructure/removeIssueLabels.ts
20726
+ var MUTATION = `mutation($labelableId: ID!, $labelIds: [ID!]!) {
20727
+ removeLabelsFromLabelable(input: { labelableId: $labelableId, labelIds: $labelIds }) {
20728
+ labelable { __typename }
20729
+ }
20730
+ }`;
20731
+ function removeIssueLabels(issueId, labelIds) {
20732
+ runGhGraphqlJson(MUTATION, { labelableId: issueId, labelIds });
20765
20733
  }
20766
20734
 
20767
- // src/commands/github/issue/createIssue.ts
20768
- import { execFileSync as execFileSync7 } from "child_process";
20769
-
20770
- // src/commands/github/issue/reviewProposedIssue.ts
20771
- import { randomUUID as randomUUID8 } from "crypto";
20772
- async function reviewProposedIssue(title, body) {
20773
- const sessionId = process.env.ASSIST_SESSION_ID;
20774
- if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
20775
- await awaitPreviewApproval("GitHub issue preview", {
20776
- sessionId,
20777
- requestId: randomUUID8(),
20778
- title,
20779
- body,
20780
- prNumber: null,
20781
- kind: "github-issue"
20782
- });
20735
+ // src/commands/github/issue/fixStructure/updateIssueType.ts
20736
+ var MUTATION2 = `mutation($issueId: ID!, $issueTypeId: ID!) {
20737
+ updateIssueIssueType(input: { issueId: $issueId, issueTypeId: $issueTypeId }) {
20738
+ issue { id }
20739
+ }
20740
+ }`;
20741
+ function updateIssueType(issueId, issueTypeId) {
20742
+ runGhGraphqlJson(MUTATION2, { issueId, issueTypeId });
20783
20743
  }
20784
20744
 
20785
- // src/commands/github/issue/createIssue.ts
20786
- var USAGE2 = "Usage: assist github issue create --title <title> --body <body> [-R <owner>/<repo>]";
20787
- async function createIssue(options2) {
20788
- if (!options2.title || !options2.body) {
20789
- console.error(USAGE2);
20790
- process.exit(1);
20791
- }
20792
- const { title, body } = options2;
20793
- validateProposedContent(
20794
- { subject: "Issue", context: "GitHub issues" },
20795
- title,
20796
- body
20797
- );
20798
- await reviewProposedIssue(title, body);
20799
- const args = ["issue", "create", "--title", title, "--body", body];
20800
- if (options2.repo) args.push("--repo", options2.repo);
20745
+ // src/commands/github/issue/fixStructure/writeLineNow.ts
20746
+ import { writeSync as writeSync2 } from "fs";
20747
+ function writeLineNow(line) {
20748
+ const text18 = `${line}
20749
+ `;
20801
20750
  try {
20802
- execFileSync7("gh", args, { stdio: "inherit" });
20751
+ writeSync2(1, text18);
20803
20752
  } catch {
20804
- process.exit(1);
20753
+ process.stdout.write(text18);
20805
20754
  }
20806
20755
  }
20807
20756
 
20808
- // src/commands/sessions/shared/inWebSession.ts
20809
- function inWebSession() {
20810
- return process.env.ASSIST_SESSION === "1" && !!process.env.ASSIST_SESSION_ID;
20811
- }
20812
-
20813
- // src/commands/github/issue/fetchIssue.ts
20814
- import { execFileSync as execFileSync8 } from "child_process";
20815
- function fetchIssue2(number, repo) {
20816
- const args = [
20817
- "issue",
20818
- "view",
20819
- String(number),
20820
- "--json",
20821
- "title,body,updatedAt,url"
20822
- ];
20823
- if (repo) args.push("--repo", repo);
20824
- let raw;
20825
- try {
20826
- raw = execFileSync8("gh", args, { encoding: "utf8" });
20827
- } catch {
20828
- console.error(`Could not fetch issue #${number} with gh issue view`);
20829
- process.exit(1);
20830
- }
20831
- try {
20832
- return JSON.parse(raw);
20833
- } catch {
20834
- console.error(`Could not parse the gh issue view output for #${number}`);
20835
- process.exit(1);
20757
+ // src/commands/github/issue/fixStructure/applyFixStructurePlan.ts
20758
+ function applyFixStructurePlan(plan2) {
20759
+ for (const entry of plan2.entries) {
20760
+ const where = chalk162.cyan(`${entry.issue.repo}#${entry.issue.number}`);
20761
+ const { typeChange, labelRemovals } = entry;
20762
+ if (typeChange) {
20763
+ writeLineNow(
20764
+ `${where} type ${typeChange.from ?? "no type"} -> ${typeChange.to}`
20765
+ );
20766
+ updateIssueType(entry.issue.id, typeChange.typeId);
20767
+ }
20768
+ if (labelRemovals.length > 0) {
20769
+ writeLineNow(
20770
+ `${where} removing ${labelRemovals.map((label2) => label2.name).join(", ")}`
20771
+ );
20772
+ removeIssueLabels(
20773
+ entry.issue.id,
20774
+ labelRemovals.map((label2) => label2.id)
20775
+ );
20776
+ }
20836
20777
  }
20837
20778
  }
20838
20779
 
20839
- // src/commands/github/issue/resumeIssueBody.ts
20840
- import { existsSync as existsSync48, readFileSync as readFileSync37 } from "fs";
20841
-
20842
- // src/commands/github/issue/issueWorkingFile.ts
20843
- import { join as join50 } from "path";
20844
- function issueWorkingFile(slug, number) {
20845
- const [owner = "unknown", repo = "unknown"] = slug.split("/");
20846
- const dir = join50(getStoreDir(), "github-issues", owner, repo);
20847
- return {
20848
- dir,
20849
- bodyPath: join50(dir, `${number}.md`),
20850
- metaPath: join50(dir, `${number}.json`)
20851
- };
20852
- }
20853
-
20854
- // src/commands/github/issue/resumeIssueBody.ts
20855
- function resumeIssueBody(slug, number, updatedAt) {
20856
- const { bodyPath, metaPath } = issueWorkingFile(slug, number);
20857
- if (!existsSync48(bodyPath) || !existsSync48(metaPath)) return void 0;
20858
- try {
20859
- const meta = JSON.parse(readFileSync37(metaPath, "utf8"));
20860
- if (meta.updatedAt !== updatedAt) return void 0;
20861
- return readFileSync37(bodyPath, "utf8");
20862
- } catch {
20863
- return void 0;
20864
- }
20780
+ // src/commands/github/issue/fixStructure/assertNothingTooDeep.ts
20781
+ function describe2(entry, leaf) {
20782
+ const parent = entry.parent;
20783
+ const under = parent ? ` under ${parent.repo}#${parent.number}` : "";
20784
+ return `${entry.issue.repo}#${entry.issue.number}${under} sits below ${leaf}, the leaf level`;
20865
20785
  }
20866
-
20867
- // src/commands/github/issue/validateIssueBody.ts
20868
- function validateIssueBody(title, body) {
20869
- validateProposedContent(
20870
- { subject: "Issue", context: "GitHub issues" },
20871
- title,
20872
- body
20786
+ function assertNothingTooDeep(tooDeep, chain2) {
20787
+ if (tooDeep.length === 0) return;
20788
+ const leaf = chain2[chain2.length - 1] ?? "the leaf";
20789
+ throw new Error(
20790
+ [
20791
+ ...tooDeep.map((entry) => describe2(entry, leaf)),
20792
+ "Re-parent those issues or aim the run at a deeper target"
20793
+ ].join("\n")
20873
20794
  );
20874
20795
  }
20875
20796
 
20876
- // src/commands/github/issue/writeIssueWorkingFile.ts
20877
- import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync31 } from "fs";
20878
- function writeIssueWorkingFile(slug, number, target, updatedAt, body) {
20879
- const { dir, bodyPath, metaPath } = issueWorkingFile(slug, number);
20880
- mkdirSync16(dir, { recursive: true });
20881
- writeFileSync31(bodyPath, body);
20882
- writeFileSync31(
20883
- metaPath,
20884
- `${JSON.stringify({ target, updatedAt }, null, 2)}
20885
- `
20797
+ // src/commands/github/issue/fixStructure/assertNoResidualDrift.ts
20798
+ function describe3(entry) {
20799
+ const where = `${entry.issue.repo}#${entry.issue.number}`;
20800
+ const notes = [];
20801
+ if (entry.typeChange) {
20802
+ notes.push(
20803
+ `${where} is still ${entry.typeChange.from ?? "untyped"}, not ${entry.typeChange.to}`
20804
+ );
20805
+ }
20806
+ for (const label2 of entry.labelRemovals) {
20807
+ notes.push(`${where} still carries ${label2.name}`);
20808
+ }
20809
+ return notes;
20810
+ }
20811
+ function assertNoResidualDrift(plan2, chain2) {
20812
+ assertNothingTooDeep(plan2.tooDeep, chain2);
20813
+ const residual = plan2.entries.flatMap(describe3);
20814
+ if (residual.length === 0) return;
20815
+ throw new Error(
20816
+ ["The subtree still drifts after applying:", ...residual].join("\n")
20886
20817
  );
20887
- return bodyPath;
20888
20818
  }
20889
20819
 
20890
- // src/commands/github/issue/prepareIssueEdit.ts
20891
- function slugFromUrl(url) {
20892
- const match = /github\.com\/([^/]+\/[^/]+)\//.exec(url ?? "");
20893
- return match ? match[1] : "unknown/unknown";
20894
- }
20895
- function prepareIssueEdit(number, repo, fresh) {
20896
- const issue = fetchIssue2(number, repo);
20897
- const slug = repo ?? slugFromUrl(issue.url);
20898
- const target = `${slug}#${number}`;
20899
- const resumed = fresh ? void 0 : resumeIssueBody(slug, number, issue.updatedAt);
20900
- const body = resumed ?? issue.body;
20901
- validateIssueBody(issue.title, body);
20902
- const save = (markdown) => writeIssueWorkingFile(slug, number, target, issue.updatedAt, markdown);
20903
- const bodyPath = save(body);
20904
- if (resumed !== void 0)
20905
- console.log(`Previewing the in-progress markdown from ${bodyPath}`);
20906
- return {
20907
- title: issue.title,
20908
- target,
20909
- updatedAt: issue.updatedAt,
20910
- body,
20911
- bodyPath,
20912
- save
20913
- };
20914
- }
20820
+ // src/commands/github/issue/fixStructure/issueFieldsFragment.ts
20821
+ var issueFieldsFragment = `fragment issueFields on Issue {
20822
+ id
20823
+ number
20824
+ title
20825
+ issueType { name }
20826
+ repository { nameWithOwner }
20827
+ labels(first: 100) { nodes { id name } pageInfo { hasNextPage } }
20828
+ subIssues(first: 100) { nodes { id } pageInfo { hasNextPage } }
20829
+ }`;
20915
20830
 
20916
- // src/commands/github/issue/pushIssueBody.ts
20917
- import { execFileSync as execFileSync9 } from "child_process";
20918
- function pushIssueBody(number, repo, bodyPath) {
20919
- const args = ["issue", "edit", String(number), "--body-file", bodyPath];
20920
- if (repo) args.push("--repo", repo);
20921
- try {
20922
- execFileSync9("gh", args, { stdio: "inherit" });
20923
- } catch {
20924
- process.exit(1);
20831
+ // src/commands/github/issue/fixStructure/parseIssueNode.ts
20832
+ function parseIssueNode(node) {
20833
+ const raw = node;
20834
+ const repo = raw.repository?.nameWithOwner ?? "";
20835
+ const where = `${repo}#${raw.number}`;
20836
+ if (raw.labels?.pageInfo?.hasNextPage) {
20837
+ throw new Error(
20838
+ `${where} carries more than 100 labels, which is not supported`
20839
+ );
20925
20840
  }
20926
- }
20927
-
20928
- // src/commands/github/issue/pushUnchangedIssue.ts
20929
- function pushUnchangedIssue(number, repo, target, fetchedAt, bodyPath) {
20930
- if (fetchIssue2(number, repo).updatedAt !== fetchedAt) {
20931
- console.error(
20932
- `${target} was updated on GitHub after it was fetched. Nothing was pushed; the markdown is at ${bodyPath}`
20841
+ if (raw.subIssues?.pageInfo?.hasNextPage) {
20842
+ throw new Error(
20843
+ `${where} has more than 100 sub-issues, which is not supported`
20933
20844
  );
20934
- process.exit(1);
20935
20845
  }
20936
- pushIssueBody(number, repo, bodyPath);
20937
- console.log(`Issue body updated on ${target}`);
20938
- }
20939
-
20940
- // src/commands/github/issue/reviewProposedIssueEdit.ts
20941
- import { randomUUID as randomUUID9 } from "crypto";
20942
- async function reviewProposedIssueEdit(title, body, working) {
20943
- const sessionId = process.env.ASSIST_SESSION_ID;
20944
- if (process.env.ASSIST_SESSION !== "1" || !sessionId) return body;
20945
- const decision = await awaitPreviewApproval(
20946
- "GitHub issue edit preview",
20947
- {
20948
- sessionId,
20949
- requestId: randomUUID9(),
20950
- title,
20951
- body,
20952
- prNumber: null,
20953
- kind: "github-issue-edit"
20954
- },
20955
- {
20956
- saveEditedBody: working.save,
20957
- rejectionAdvice: `Nothing was pushed. The pane's markdown, including any collapses already applied, is at ${working.path}. Revise that file in place \u2014 do not recompose the body from scratch \u2014 then re-run this command to preview the revision.`
20958
- }
20959
- );
20960
- return decision.body ?? body;
20846
+ return {
20847
+ id: raw.id,
20848
+ number: raw.number,
20849
+ title: raw.title,
20850
+ repo,
20851
+ typeName: raw.issueType?.name ?? null,
20852
+ labels: (raw.labels?.nodes ?? []).filter((label2) => label2 !== null),
20853
+ childIds: (raw.subIssues?.nodes ?? []).filter((child) => child !== null).map((child) => child.id)
20854
+ };
20961
20855
  }
20962
20856
 
20963
- // src/commands/github/issue/viewIssue.ts
20964
- import { execFileSync as execFileSync10 } from "child_process";
20965
- function viewIssue(number, repo) {
20966
- const args = ["issue", "view", String(number)];
20967
- if (repo) args.push("--repo", repo);
20968
- try {
20969
- execFileSync10("gh", args, { stdio: "inherit" });
20970
- } catch {
20971
- process.exit(1);
20972
- }
20857
+ // src/commands/github/issue/fixStructure/fetchRootIssue.ts
20858
+ var QUERY = `query($owner: String!, $repo: String!, $number: Int!) {
20859
+ repository(owner: $owner, name: $repo) {
20860
+ issue(number: $number) { ...issueFields }
20861
+ }
20973
20862
  }
20974
-
20975
- // src/commands/github/issue/editIssue.ts
20976
- var USAGE3 = "Usage: assist github issue edit <number> [-R <owner>/<repo>]";
20977
- async function editIssue(numberArg, options2) {
20978
- const number = Number.parseInt(numberArg, 10);
20979
- if (!Number.isInteger(number) || number <= 0) {
20980
- console.error(USAGE3);
20981
- process.exit(1);
20982
- }
20983
- if (!inWebSession()) {
20984
- viewIssue(number, options2.repo);
20985
- return;
20863
+ ${issueFieldsFragment}`;
20864
+ function fetchRootIssue(target) {
20865
+ const raw = runGhGraphqlJson(QUERY, {
20866
+ owner: target.owner,
20867
+ repo: target.repo,
20868
+ number: target.number
20869
+ });
20870
+ const issue = JSON.parse(raw).data?.repository?.issue;
20871
+ if (!issue) {
20872
+ throw new Error(
20873
+ `No issue ${target.owner}/${target.repo}#${target.number} could be read`
20874
+ );
20986
20875
  }
20987
- const issue = prepareIssueEdit(number, options2.repo, options2.fresh);
20988
- const edited = await reviewProposedIssueEdit(
20989
- `Edit ${issue.target}: ${issue.title}`,
20990
- issue.body,
20991
- { path: issue.bodyPath, save: issue.save }
20992
- );
20993
- validateIssueBody(issue.title, edited);
20994
- pushUnchangedIssue(
20995
- number,
20996
- options2.repo,
20997
- issue.target,
20998
- issue.updatedAt,
20999
- issue.bodyPath
21000
- );
20876
+ return parseIssueNode(issue);
21001
20877
  }
21002
20878
 
21003
20879
  // src/commands/github/issue/fixStructure/matchedLabels.ts
@@ -21095,127 +20971,110 @@ function buildFixStructurePlan(issues, options2) {
21095
20971
  };
21096
20972
  }
21097
20973
 
21098
- // src/shared/runGhGraphqlJson.ts
21099
- import { spawnSync as spawnSync5 } from "child_process";
21100
- function runGhGraphqlJson(query, vars = {}) {
21101
- const result = spawnSync5("gh", ["api", "graphql", "--input", "-"], {
21102
- encoding: "utf8",
21103
- windowsHide: true,
21104
- input: JSON.stringify({ query, variables: vars }),
21105
- maxBuffer: 64 * 1024 * 1024
21106
- });
21107
- if (result.status !== 0) throw new Error(result.stderr || result.stdout);
21108
- throwOnGraphqlErrors(result.stdout);
21109
- return result.stdout;
20974
+ // src/commands/github/issue/fixStructure/fetchSubtreeIssues.ts
20975
+ var QUERY2 = `query($ids: [ID!]!) {
20976
+ nodes(ids: $ids) { ... on Issue { ...issueFields } }
21110
20977
  }
21111
-
21112
- // src/commands/github/issue/fixStructure/issueFieldsFragment.ts
21113
- var issueFieldsFragment = `fragment issueFields on Issue {
21114
- id
21115
- number
21116
- title
21117
- issueType { name }
21118
- repository { nameWithOwner }
21119
- labels(first: 100) { nodes { id name } pageInfo { hasNextPage } }
21120
- subIssues(first: 100) { nodes { id } pageInfo { hasNextPage } }
21121
- }`;
21122
-
21123
- // src/commands/github/issue/fixStructure/parseIssueNode.ts
21124
- function parseIssueNode(node) {
21125
- const raw = node;
21126
- const repo = raw.repository?.nameWithOwner ?? "";
21127
- const where = `${repo}#${raw.number}`;
21128
- if (raw.labels?.pageInfo?.hasNextPage) {
21129
- throw new Error(
21130
- `${where} carries more than 100 labels, which is not supported`
21131
- );
20978
+ ${issueFieldsFragment}`;
20979
+ var BATCH = 50;
20980
+ function fetchSubtreeIssues(ids) {
20981
+ const issues = [];
20982
+ for (let start3 = 0; start3 < ids.length; start3 += BATCH) {
20983
+ const raw = runGhGraphqlJson(QUERY2, {
20984
+ ids: ids.slice(start3, start3 + BATCH)
20985
+ });
20986
+ const nodes = JSON.parse(raw).data?.nodes ?? [];
20987
+ for (const node of nodes) {
20988
+ if (node) issues.push(parseIssueNode(node));
20989
+ }
21132
20990
  }
21133
- if (raw.subIssues?.pageInfo?.hasNextPage) {
21134
- throw new Error(
21135
- `${where} has more than 100 sub-issues, which is not supported`
21136
- );
20991
+ return issues;
20992
+ }
20993
+
20994
+ // src/commands/github/issue/fixStructure/walkSubtree.ts
20995
+ function walkSubtree(root, maxDepth, fetchIssues = fetchSubtreeIssues) {
20996
+ const placed = [{ ...root, depth: 0, parentId: null }];
20997
+ const seen = /* @__PURE__ */ new Set([root.id]);
20998
+ let frontier = placed;
20999
+ for (let depth = 1; depth <= maxDepth && frontier.length > 0; depth += 1) {
21000
+ const parentOf2 = /* @__PURE__ */ new Map();
21001
+ for (const parent of frontier) {
21002
+ for (const childId of parent.childIds) {
21003
+ if (seen.has(childId)) continue;
21004
+ seen.add(childId);
21005
+ parentOf2.set(childId, parent.id);
21006
+ }
21007
+ }
21008
+ if (parentOf2.size === 0) break;
21009
+ const children = fetchIssues([...parentOf2.keys()]).map((issue) => ({
21010
+ ...issue,
21011
+ depth,
21012
+ parentId: parentOf2.get(issue.id) ?? null
21013
+ }));
21014
+ placed.push(...children);
21015
+ frontier = children;
21137
21016
  }
21138
- return {
21139
- id: raw.id,
21140
- number: raw.number,
21141
- title: raw.title,
21142
- repo,
21143
- typeName: raw.issueType?.name ?? null,
21144
- labels: (raw.labels?.nodes ?? []).filter((label2) => label2 !== null),
21145
- childIds: (raw.subIssues?.nodes ?? []).filter((child) => child !== null).map((child) => child.id)
21146
- };
21017
+ return placed;
21147
21018
  }
21148
21019
 
21149
- // src/commands/github/issue/fixStructure/fetchRootIssue.ts
21150
- var QUERY = `query($owner: String!, $repo: String!, $number: Int!) {
21151
- repository(owner: $owner, name: $repo) {
21152
- issue(number: $number) { ...issueFields }
21153
- }
21020
+ // src/commands/github/issue/fixStructure/planSubtree.ts
21021
+ function planSubtree(root, context) {
21022
+ const depth = context.chain.length - context.rootLevelIndex;
21023
+ return buildFixStructurePlan(walkSubtree(root, depth), context);
21154
21024
  }
21155
- ${issueFieldsFragment}`;
21156
- function fetchRootIssue(target) {
21157
- const raw = runGhGraphqlJson(QUERY, {
21158
- owner: target.owner,
21159
- repo: target.repo,
21160
- number: target.number
21161
- });
21162
- const issue = JSON.parse(raw).data?.repository?.issue;
21163
- if (!issue) {
21164
- throw new Error(
21165
- `No issue ${target.owner}/${target.repo}#${target.number} could be read`
21166
- );
21167
- }
21168
- return parseIssueNode(issue);
21025
+
21026
+ // src/commands/github/issue/fixStructure/applyAndVerifySubtree.ts
21027
+ function applyAndVerifySubtree(target, plan2, context) {
21028
+ if (plan2.typeChangeCount === 0 && plan2.labelRemovalCount === 0) return;
21029
+ applyFixStructurePlan(plan2);
21030
+ writeLineNow(chalk163.dim("Re-walking the subtree to confirm"));
21031
+ assertNoResidualDrift(
21032
+ planSubtree(fetchRootIssue(target), context),
21033
+ context.chain
21034
+ );
21035
+ writeLineNow(chalk163.green("Subtree normalised"));
21169
21036
  }
21170
21037
 
21171
21038
  // src/commands/github/issue/fixStructure/printFixStructurePlan.ts
21172
- import chalk162 from "chalk";
21039
+ import chalk164 from "chalk";
21173
21040
  function annotate(entry) {
21174
21041
  const notes = [];
21175
21042
  if (entry.level === null) {
21176
- notes.push(chalk162.red("deeper than the leaf level"));
21043
+ notes.push(chalk164.red("deeper than the leaf level"));
21177
21044
  } else if (entry.typeChange) {
21178
21045
  notes.push(
21179
- chalk162.yellow(
21046
+ chalk164.yellow(
21180
21047
  `${entry.typeChange.from ?? "no type"} -> ${entry.typeChange.to}`
21181
21048
  )
21182
21049
  );
21183
21050
  } else {
21184
- notes.push(chalk162.dim(entry.issue.typeName ?? "no type"));
21051
+ notes.push(chalk164.dim(entry.issue.typeName ?? "no type"));
21185
21052
  }
21186
21053
  for (const label2 of entry.labelRemovals) {
21187
- notes.push(chalk162.yellow(`-${label2.name}`));
21054
+ notes.push(chalk164.yellow(`-${label2.name}`));
21188
21055
  }
21189
21056
  return notes;
21190
21057
  }
21191
21058
  function formatCount(count8, noun) {
21192
21059
  return `${count8} ${noun}${count8 === 1 ? "" : "s"}`;
21193
21060
  }
21194
- function printFixStructurePlan(plan2, chain2) {
21195
- console.log(chalk162.dim(`chain: ${chain2.join(" > ")}`));
21061
+ function printFixStructurePlan(plan2, chain2, apply) {
21062
+ writeLineNow(chalk164.dim(`chain: ${chain2.join(" > ")}`));
21196
21063
  for (const entry of plan2.entries) {
21197
21064
  const indent3 = " ".repeat(entry.issue.depth);
21198
- const name = chalk162.cyan(`${entry.issue.repo}#${entry.issue.number}`);
21199
- console.log(
21065
+ const name = chalk164.cyan(`${entry.issue.repo}#${entry.issue.number}`);
21066
+ writeLineNow(
21200
21067
  `${indent3}${name} ${entry.issue.title} [${annotate(entry).join(", ")}]`
21201
21068
  );
21202
21069
  }
21203
- for (const { issue, parent } of plan2.tooDeep) {
21204
- const where = parent ? ` under ${parent.repo}#${parent.number}` : "";
21205
- console.error(
21206
- chalk162.red(
21207
- `${issue.repo}#${issue.number}${where} sits below ${chain2[chain2.length - 1]}, the leaf level`
21208
- )
21209
- );
21210
- }
21211
21070
  if (plan2.typeChangeCount === 0 && plan2.labelRemovalCount === 0) {
21212
- console.log(chalk162.green("Nothing to change"));
21071
+ writeLineNow(chalk164.green("Nothing to change"));
21213
21072
  return;
21214
21073
  }
21215
- console.log(
21074
+ writeLineNow(
21216
21075
  `${formatCount(plan2.typeChangeCount, "type change")}, ${formatCount(plan2.labelRemovalCount, "label removal")} planned`
21217
21076
  );
21218
- console.log(chalk162.dim("Dry run \u2014 nothing written"));
21077
+ if (!apply) writeLineNow(chalk164.dim("Dry run \u2014 nothing written"));
21219
21078
  }
21220
21079
 
21221
21080
  // src/commands/github/issue/fixStructure/resolveFixStructureTarget.ts
@@ -21251,7 +21110,7 @@ function resolveFixStructureTarget(target, repo) {
21251
21110
  }
21252
21111
 
21253
21112
  // src/commands/github/issue/fixStructure/resolveOrgIssueTypes.ts
21254
- var QUERY2 = `query($owner: String!) {
21113
+ var QUERY3 = `query($owner: String!) {
21255
21114
  organization(login: $owner) {
21256
21115
  issueTypes(first: 50) { nodes { id name } }
21257
21116
  }
@@ -21264,7 +21123,7 @@ function missingOrg(owner) {
21264
21123
  function resolveOrgIssueTypes(owner) {
21265
21124
  let raw;
21266
21125
  try {
21267
- raw = runGhGraphqlJson(QUERY2, { owner });
21126
+ raw = runGhGraphqlJson(QUERY3, { owner });
21268
21127
  } catch (error) {
21269
21128
  const message3 = error instanceof Error ? error.message : String(error);
21270
21129
  if (message3.includes("Could not resolve to an Organization")) {
@@ -21307,52 +21166,6 @@ function resolveRootLevelIndex(chain2, targetTypeName, level) {
21307
21166
  // src/commands/github/issue/fixStructure/types.ts
21308
21167
  var defaultTypeChain = ["Epic", "Story", "Subtask"];
21309
21168
 
21310
- // src/commands/github/issue/fixStructure/fetchSubtreeIssues.ts
21311
- var QUERY3 = `query($ids: [ID!]!) {
21312
- nodes(ids: $ids) { ... on Issue { ...issueFields } }
21313
- }
21314
- ${issueFieldsFragment}`;
21315
- var BATCH = 50;
21316
- function fetchSubtreeIssues(ids) {
21317
- const issues = [];
21318
- for (let start3 = 0; start3 < ids.length; start3 += BATCH) {
21319
- const raw = runGhGraphqlJson(QUERY3, {
21320
- ids: ids.slice(start3, start3 + BATCH)
21321
- });
21322
- const nodes = JSON.parse(raw).data?.nodes ?? [];
21323
- for (const node of nodes) {
21324
- if (node) issues.push(parseIssueNode(node));
21325
- }
21326
- }
21327
- return issues;
21328
- }
21329
-
21330
- // src/commands/github/issue/fixStructure/walkSubtree.ts
21331
- function walkSubtree(root, maxDepth, fetchIssues = fetchSubtreeIssues) {
21332
- const placed = [{ ...root, depth: 0, parentId: null }];
21333
- const seen = /* @__PURE__ */ new Set([root.id]);
21334
- let frontier = placed;
21335
- for (let depth = 1; depth <= maxDepth && frontier.length > 0; depth += 1) {
21336
- const parentOf2 = /* @__PURE__ */ new Map();
21337
- for (const parent of frontier) {
21338
- for (const childId of parent.childIds) {
21339
- if (seen.has(childId)) continue;
21340
- seen.add(childId);
21341
- parentOf2.set(childId, parent.id);
21342
- }
21343
- }
21344
- if (parentOf2.size === 0) break;
21345
- const children = fetchIssues([...parentOf2.keys()]).map((issue) => ({
21346
- ...issue,
21347
- depth,
21348
- parentId: parentOf2.get(issue.id) ?? null
21349
- }));
21350
- placed.push(...children);
21351
- frontier = children;
21352
- }
21353
- return placed;
21354
- }
21355
-
21356
21169
  // src/commands/github/issue/fixStructure/fixStructure.ts
21357
21170
  function fixStructure(target, options2) {
21358
21171
  const chain2 = defaultTypeChain;
@@ -21364,15 +21177,17 @@ function fixStructure(target, options2) {
21364
21177
  root.typeName,
21365
21178
  options2.level
21366
21179
  );
21367
- const issueTypes = resolveOrgIssueTypes(resolved.owner);
21368
- const issues = walkSubtree(root, chain2.length - index3);
21369
- const plan2 = buildFixStructurePlan(issues, {
21180
+ const context = {
21370
21181
  chain: chain2,
21371
21182
  rootLevelIndex: index3,
21372
21183
  rootAsserted: asserted,
21373
- issueTypes
21374
- });
21375
- printFixStructurePlan(plan2, chain2);
21184
+ issueTypes: resolveOrgIssueTypes(resolved.owner),
21185
+ stripLabels: []
21186
+ };
21187
+ const plan2 = planSubtree(root, context);
21188
+ printFixStructurePlan(plan2, chain2, options2.apply === true);
21189
+ assertNothingTooDeep(plan2.tooDeep, chain2);
21190
+ if (options2.apply) applyAndVerifySubtree(resolved, plan2, context);
21376
21191
  } catch (error) {
21377
21192
  console.error(error instanceof Error ? error.message : String(error));
21378
21193
  process.exit(1);
@@ -21383,19 +21198,20 @@ function fixStructure(target, options2) {
21383
21198
  var chain = defaultTypeChain.join(" > ");
21384
21199
  var levels = defaultTypeChain.map((name) => name.toLowerCase()).join("|");
21385
21200
  function registerFixStructure(issueCommand) {
21386
- issueCommand.command("fix-structure <target>").description("Report the issue type drift across one issue subtree").option(
21201
+ issueCommand.command("fix-structure <target>").description("Normalise the issue types across one issue subtree").option(
21387
21202
  "-R, --repo <owner/repo>",
21388
21203
  "Repository a bare issue number belongs to"
21389
21204
  ).option(
21390
21205
  "--level <level>",
21391
21206
  `The target's own position in the ${chain} chain, when it cannot be inferred from its type`
21392
- ).addHelpText(
21207
+ ).option("--apply", "Write the planned changes instead of reporting them").addHelpText(
21393
21208
  "after",
21394
21209
  `
21395
21210
  Walks the subtree reachable from <target> via sub-issues and reports the type each issue should carry: every level below the target is typed to the next level down the ${chain} chain. Nothing outside the subtree is ever read or written.
21396
21211
  The target's own level is inferred from its issue type, so aiming at a story types its children as subtasks. When the target's type is not in the chain the level cannot be inferred, and --level ${levels} asserts it instead \u2014 which also plans the target's own type.
21397
21212
  The target is owner/repo#number, a github.com issue URL, or a bare number with --repo.
21398
- This reports only; nothing is written.`
21213
+ Without --apply nothing is written. With --apply each write is announced before it is issued, and the subtree is re-walked afterwards so any residual drift fails the run.
21214
+ Anything nested below the leaf level fails the run before a single write, naming the offender and its parent.`
21399
21215
  ).action(fixStructure);
21400
21216
  }
21401
21217
 
@@ -21410,9 +21226,136 @@ async function readBodyArgument(value) {
21410
21226
  return body;
21411
21227
  }
21412
21228
 
21413
- // src/commands/registerGithubIssue.ts
21414
- function registerGithubIssue(githubCommand) {
21415
- const issueCommand = githubCommand.command("issue").description("GitHub issue utilities");
21229
+ // src/commands/github/issue/commentIssue.ts
21230
+ import { execFileSync as execFileSync6 } from "child_process";
21231
+
21232
+ // src/shared/validateProposedContent.ts
21233
+ function validateProposedContent(labels, title, body) {
21234
+ const { subject, context } = labels;
21235
+ if (title.toLowerCase().includes("claude")) {
21236
+ console.error(`Error: ${subject} title must not reference Claude`);
21237
+ process.exit(1);
21238
+ }
21239
+ if (body.toLowerCase().includes("claude")) {
21240
+ console.error(`Error: ${subject} body must not reference Claude`);
21241
+ process.exit(1);
21242
+ }
21243
+ const titleBacklogIds = findBacklogRefs(title);
21244
+ if (titleBacklogIds.length > 0) {
21245
+ console.error(
21246
+ backlogRefError(`${subject} title`, context, titleBacklogIds)
21247
+ );
21248
+ process.exit(1);
21249
+ }
21250
+ const bodyBacklogIds = findBacklogRefs(body);
21251
+ if (bodyBacklogIds.length > 0) {
21252
+ console.error(backlogRefError(`${subject} body`, context, bodyBacklogIds));
21253
+ process.exit(1);
21254
+ }
21255
+ }
21256
+
21257
+ // src/commands/github/issue/reviewProposedIssueComment.ts
21258
+ import { randomUUID as randomUUID7 } from "crypto";
21259
+ async function reviewProposedIssueComment(title, body) {
21260
+ const sessionId = process.env.ASSIST_SESSION_ID;
21261
+ if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
21262
+ await awaitPreviewApproval("GitHub issue comment preview", {
21263
+ sessionId,
21264
+ requestId: randomUUID7(),
21265
+ title,
21266
+ body,
21267
+ prNumber: null,
21268
+ kind: "github-issue-comment"
21269
+ });
21270
+ }
21271
+
21272
+ // src/commands/github/issue/commentIssue.ts
21273
+ var USAGE = "Usage: assist github issue comment <number> --body <body> [-R <owner>/<repo>]";
21274
+ async function commentIssue(numberArg, options2) {
21275
+ const number = Number.parseInt(numberArg, 10);
21276
+ if (!Number.isInteger(number) || number <= 0 || !options2.body) {
21277
+ console.error(USAGE);
21278
+ process.exit(1);
21279
+ }
21280
+ const { body } = options2;
21281
+ const target = options2.repo ? `${options2.repo}#${number}` : `issue #${number}`;
21282
+ validateProposedContent(
21283
+ { subject: "Comment", context: "GitHub issues" },
21284
+ "",
21285
+ body
21286
+ );
21287
+ await reviewProposedIssueComment(`Comment on ${target}`, body);
21288
+ const args = ["issue", "comment", String(number), "--body", body];
21289
+ if (options2.repo) args.push("--repo", options2.repo);
21290
+ try {
21291
+ execFileSync6("gh", args, { stdio: "inherit" });
21292
+ } catch {
21293
+ process.exit(1);
21294
+ }
21295
+ console.log(`Comment posted to ${target}`);
21296
+ }
21297
+
21298
+ // src/commands/github/issue/registerCommentIssue.ts
21299
+ function registerCommentIssue(issueCommand) {
21300
+ issueCommand.command("comment <number>").description("Comment on a GitHub issue (body of - reads it from stdin)").option("--body <body>", "Comment body (- reads it from stdin)").option(
21301
+ "-R, --repo <owner/repo>",
21302
+ "Target repository (defaults to the current repo)"
21303
+ ).addHelpText(
21304
+ "after",
21305
+ "\nThe comment is outward-facing: write it for the repo's readers, not the team. It is rejected if it references Claude or an assist backlog item.\nIn an assist web session the body is previewed for approve/reject first (with inline comments); nothing is posted until it is approved."
21306
+ ).action(
21307
+ async (number, options2) => {
21308
+ await commentIssue(number, {
21309
+ ...options2,
21310
+ body: options2.body ? await readBodyArgument(options2.body) : void 0
21311
+ });
21312
+ }
21313
+ );
21314
+ }
21315
+
21316
+ // src/commands/github/issue/createIssue.ts
21317
+ import { execFileSync as execFileSync7 } from "child_process";
21318
+
21319
+ // src/commands/github/issue/reviewProposedIssue.ts
21320
+ import { randomUUID as randomUUID8 } from "crypto";
21321
+ async function reviewProposedIssue(title, body) {
21322
+ const sessionId = process.env.ASSIST_SESSION_ID;
21323
+ if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
21324
+ await awaitPreviewApproval("GitHub issue preview", {
21325
+ sessionId,
21326
+ requestId: randomUUID8(),
21327
+ title,
21328
+ body,
21329
+ prNumber: null,
21330
+ kind: "github-issue"
21331
+ });
21332
+ }
21333
+
21334
+ // src/commands/github/issue/createIssue.ts
21335
+ var USAGE2 = "Usage: assist github issue create --title <title> --body <body> [-R <owner>/<repo>]";
21336
+ async function createIssue(options2) {
21337
+ if (!options2.title || !options2.body) {
21338
+ console.error(USAGE2);
21339
+ process.exit(1);
21340
+ }
21341
+ const { title, body } = options2;
21342
+ validateProposedContent(
21343
+ { subject: "Issue", context: "GitHub issues" },
21344
+ title,
21345
+ body
21346
+ );
21347
+ await reviewProposedIssue(title, body);
21348
+ const args = ["issue", "create", "--title", title, "--body", body];
21349
+ if (options2.repo) args.push("--repo", options2.repo);
21350
+ try {
21351
+ execFileSync7("gh", args, { stdio: "inherit" });
21352
+ } catch {
21353
+ process.exit(1);
21354
+ }
21355
+ }
21356
+
21357
+ // src/commands/github/issue/registerCreateIssue.ts
21358
+ function registerCreateIssue(issueCommand) {
21416
21359
  issueCommand.command("create").description("Create a GitHub issue").option("--title <title>", "Issue title").option("--body <body>", "Issue body").option(
21417
21360
  "-R, --repo <owner/repo>",
21418
21361
  "Target repository (defaults to the current repo)"
@@ -21420,6 +21363,205 @@ function registerGithubIssue(githubCommand) {
21420
21363
  "after",
21421
21364
  "\nThere is no What/Why/How template: an issue reports a problem, and the target repo's own issue template is unknowable from here. Write the body as the repo's maintainers would expect.\nIn an assist web session the title and body are previewed for approve/reject first (with inline comments); nothing is created until it is approved."
21422
21365
  ).action(createIssue);
21366
+ }
21367
+
21368
+ // src/commands/sessions/shared/inWebSession.ts
21369
+ function inWebSession() {
21370
+ return process.env.ASSIST_SESSION === "1" && !!process.env.ASSIST_SESSION_ID;
21371
+ }
21372
+
21373
+ // src/commands/github/issue/fetchIssue.ts
21374
+ import { execFileSync as execFileSync8 } from "child_process";
21375
+ function fetchIssue2(number, repo) {
21376
+ const args = [
21377
+ "issue",
21378
+ "view",
21379
+ String(number),
21380
+ "--json",
21381
+ "title,body,updatedAt,url"
21382
+ ];
21383
+ if (repo) args.push("--repo", repo);
21384
+ let raw;
21385
+ try {
21386
+ raw = execFileSync8("gh", args, { encoding: "utf8" });
21387
+ } catch {
21388
+ console.error(`Could not fetch issue #${number} with gh issue view`);
21389
+ process.exit(1);
21390
+ }
21391
+ try {
21392
+ return JSON.parse(raw);
21393
+ } catch {
21394
+ console.error(`Could not parse the gh issue view output for #${number}`);
21395
+ process.exit(1);
21396
+ }
21397
+ }
21398
+
21399
+ // src/commands/github/issue/resumeIssueBody.ts
21400
+ import { existsSync as existsSync48, readFileSync as readFileSync37 } from "fs";
21401
+
21402
+ // src/commands/github/issue/issueWorkingFile.ts
21403
+ import { join as join50 } from "path";
21404
+ function issueWorkingFile(slug, number) {
21405
+ const [owner = "unknown", repo = "unknown"] = slug.split("/");
21406
+ const dir = join50(getStoreDir(), "github-issues", owner, repo);
21407
+ return {
21408
+ dir,
21409
+ bodyPath: join50(dir, `${number}.md`),
21410
+ metaPath: join50(dir, `${number}.json`)
21411
+ };
21412
+ }
21413
+
21414
+ // src/commands/github/issue/resumeIssueBody.ts
21415
+ function resumeIssueBody(slug, number, updatedAt) {
21416
+ const { bodyPath, metaPath } = issueWorkingFile(slug, number);
21417
+ if (!existsSync48(bodyPath) || !existsSync48(metaPath)) return void 0;
21418
+ try {
21419
+ const meta = JSON.parse(readFileSync37(metaPath, "utf8"));
21420
+ if (meta.updatedAt !== updatedAt) return void 0;
21421
+ return readFileSync37(bodyPath, "utf8");
21422
+ } catch {
21423
+ return void 0;
21424
+ }
21425
+ }
21426
+
21427
+ // src/commands/github/issue/validateIssueBody.ts
21428
+ function validateIssueBody(title, body) {
21429
+ validateProposedContent(
21430
+ { subject: "Issue", context: "GitHub issues" },
21431
+ title,
21432
+ body
21433
+ );
21434
+ }
21435
+
21436
+ // src/commands/github/issue/writeIssueWorkingFile.ts
21437
+ import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync31 } from "fs";
21438
+ function writeIssueWorkingFile(slug, number, target, updatedAt, body) {
21439
+ const { dir, bodyPath, metaPath } = issueWorkingFile(slug, number);
21440
+ mkdirSync16(dir, { recursive: true });
21441
+ writeFileSync31(bodyPath, body);
21442
+ writeFileSync31(
21443
+ metaPath,
21444
+ `${JSON.stringify({ target, updatedAt }, null, 2)}
21445
+ `
21446
+ );
21447
+ return bodyPath;
21448
+ }
21449
+
21450
+ // src/commands/github/issue/prepareIssueEdit.ts
21451
+ function slugFromUrl(url) {
21452
+ const match = /github\.com\/([^/]+\/[^/]+)\//.exec(url ?? "");
21453
+ return match ? match[1] : "unknown/unknown";
21454
+ }
21455
+ function prepareIssueEdit(number, repo, fresh) {
21456
+ const issue = fetchIssue2(number, repo);
21457
+ const slug = repo ?? slugFromUrl(issue.url);
21458
+ const target = `${slug}#${number}`;
21459
+ const resumed = fresh ? void 0 : resumeIssueBody(slug, number, issue.updatedAt);
21460
+ const body = resumed ?? issue.body;
21461
+ validateIssueBody(issue.title, body);
21462
+ const save = (markdown) => writeIssueWorkingFile(slug, number, target, issue.updatedAt, markdown);
21463
+ const bodyPath = save(body);
21464
+ if (resumed !== void 0)
21465
+ console.log(`Previewing the in-progress markdown from ${bodyPath}`);
21466
+ return {
21467
+ title: issue.title,
21468
+ target,
21469
+ updatedAt: issue.updatedAt,
21470
+ body,
21471
+ bodyPath,
21472
+ save
21473
+ };
21474
+ }
21475
+
21476
+ // src/commands/github/issue/pushIssueBody.ts
21477
+ import { execFileSync as execFileSync9 } from "child_process";
21478
+ function pushIssueBody(number, repo, bodyPath) {
21479
+ const args = ["issue", "edit", String(number), "--body-file", bodyPath];
21480
+ if (repo) args.push("--repo", repo);
21481
+ try {
21482
+ execFileSync9("gh", args, { stdio: "inherit" });
21483
+ } catch {
21484
+ process.exit(1);
21485
+ }
21486
+ }
21487
+
21488
+ // src/commands/github/issue/pushUnchangedIssue.ts
21489
+ function pushUnchangedIssue(number, repo, target, fetchedAt, bodyPath) {
21490
+ if (fetchIssue2(number, repo).updatedAt !== fetchedAt) {
21491
+ console.error(
21492
+ `${target} was updated on GitHub after it was fetched. Nothing was pushed; the markdown is at ${bodyPath}`
21493
+ );
21494
+ process.exit(1);
21495
+ }
21496
+ pushIssueBody(number, repo, bodyPath);
21497
+ console.log(`Issue body updated on ${target}`);
21498
+ }
21499
+
21500
+ // src/commands/github/issue/reviewProposedIssueEdit.ts
21501
+ import { randomUUID as randomUUID9 } from "crypto";
21502
+ async function reviewProposedIssueEdit(title, body, working) {
21503
+ const sessionId = process.env.ASSIST_SESSION_ID;
21504
+ if (process.env.ASSIST_SESSION !== "1" || !sessionId) return body;
21505
+ const decision = await awaitPreviewApproval(
21506
+ "GitHub issue edit preview",
21507
+ {
21508
+ sessionId,
21509
+ requestId: randomUUID9(),
21510
+ title,
21511
+ body,
21512
+ prNumber: null,
21513
+ kind: "github-issue-edit"
21514
+ },
21515
+ {
21516
+ saveEditedBody: working.save,
21517
+ rejectionAdvice: `Nothing was pushed. The pane's markdown, including any collapses already applied, is at ${working.path}. Revise that file in place \u2014 do not recompose the body from scratch \u2014 then re-run this command to preview the revision.`
21518
+ }
21519
+ );
21520
+ return decision.body ?? body;
21521
+ }
21522
+
21523
+ // src/commands/github/issue/viewIssue.ts
21524
+ import { execFileSync as execFileSync10 } from "child_process";
21525
+ function viewIssue(number, repo) {
21526
+ const args = ["issue", "view", String(number)];
21527
+ if (repo) args.push("--repo", repo);
21528
+ try {
21529
+ execFileSync10("gh", args, { stdio: "inherit" });
21530
+ } catch {
21531
+ process.exit(1);
21532
+ }
21533
+ }
21534
+
21535
+ // src/commands/github/issue/editIssue.ts
21536
+ var USAGE3 = "Usage: assist github issue edit <number> [-R <owner>/<repo>]";
21537
+ async function editIssue(numberArg, options2) {
21538
+ const number = Number.parseInt(numberArg, 10);
21539
+ if (!Number.isInteger(number) || number <= 0) {
21540
+ console.error(USAGE3);
21541
+ process.exit(1);
21542
+ }
21543
+ if (!inWebSession()) {
21544
+ viewIssue(number, options2.repo);
21545
+ return;
21546
+ }
21547
+ const issue = prepareIssueEdit(number, options2.repo, options2.fresh);
21548
+ const edited = await reviewProposedIssueEdit(
21549
+ `Edit ${issue.target}: ${issue.title}`,
21550
+ issue.body,
21551
+ { path: issue.bodyPath, save: issue.save }
21552
+ );
21553
+ validateIssueBody(issue.title, edited);
21554
+ pushUnchangedIssue(
21555
+ number,
21556
+ options2.repo,
21557
+ issue.target,
21558
+ issue.updatedAt,
21559
+ issue.bodyPath
21560
+ );
21561
+ }
21562
+
21563
+ // src/commands/github/issue/registerEditIssue.ts
21564
+ function registerEditIssue(issueCommand) {
21423
21565
  issueCommand.command("edit <number>").description("Edit an existing GitHub issue's body in the preview pane").option(
21424
21566
  "-R, --repo <owner/repo>",
21425
21567
  "Target repository (defaults to the current repo)"
@@ -21430,20 +21572,14 @@ function registerGithubIssue(githubCommand) {
21430
21572
  "after",
21431
21573
  "\nFetches the issue's current body and opens it in the assist web preview pane, where it can be reworked before it is pushed back. Approving pushes the pane's markdown to the issue; nothing is pushed if the issue moved on GitHub after it was fetched, or outside a web session.\nRejecting writes the pane's markdown to a working file and names it: revise that file in place and re-run to preview the revision, which keeps any collapses already applied. A re-run resumes from the working file while the issue has not moved on GitHub; --fresh discards it and re-fetches.\nOnly the body is touched \u2014 the title, labels, assignees and state are left alone."
21432
21574
  ).action(editIssue);
21433
- issueCommand.command("comment <number>").description("Comment on a GitHub issue (body of - reads it from stdin)").option("--body <body>", "Comment body (- reads it from stdin)").option(
21434
- "-R, --repo <owner/repo>",
21435
- "Target repository (defaults to the current repo)"
21436
- ).addHelpText(
21437
- "after",
21438
- "\nThe comment is outward-facing: write it for the repo's readers, not the team. It is rejected if it references Claude or an assist backlog item.\nIn an assist web session the body is previewed for approve/reject first (with inline comments); nothing is posted until it is approved."
21439
- ).action(
21440
- async (number, options2) => {
21441
- await commentIssue(number, {
21442
- ...options2,
21443
- body: options2.body ? await readBodyArgument(options2.body) : void 0
21444
- });
21445
- }
21446
- );
21575
+ }
21576
+
21577
+ // src/commands/registerGithubIssue.ts
21578
+ function registerGithubIssue(githubCommand) {
21579
+ const issueCommand = githubCommand.command("issue").description("GitHub issue utilities");
21580
+ registerCreateIssue(issueCommand);
21581
+ registerEditIssue(issueCommand);
21582
+ registerCommentIssue(issueCommand);
21447
21583
  registerFixStructure(issueCommand);
21448
21584
  }
21449
21585
 
@@ -21684,7 +21820,7 @@ function registerHandover(program2) {
21684
21820
  }
21685
21821
 
21686
21822
  // src/commands/jira/acceptanceCriteria.ts
21687
- import chalk163 from "chalk";
21823
+ import chalk165 from "chalk";
21688
21824
 
21689
21825
  // src/commands/jira/adfToText.ts
21690
21826
  function renderInline(node) {
@@ -21751,7 +21887,7 @@ function acceptanceCriteria(issueKey) {
21751
21887
  const parsed = fetchIssue(issueKey, field);
21752
21888
  const acValue = parsed?.fields?.[field];
21753
21889
  if (!acValue) {
21754
- console.log(chalk163.yellow(`No acceptance criteria found on ${issueKey}.`));
21890
+ console.log(chalk165.yellow(`No acceptance criteria found on ${issueKey}.`));
21755
21891
  return;
21756
21892
  }
21757
21893
  if (typeof acValue === "string") {
@@ -21817,14 +21953,14 @@ async function jiraAuth() {
21817
21953
  }
21818
21954
 
21819
21955
  // src/commands/jira/viewIssue.ts
21820
- import chalk164 from "chalk";
21956
+ import chalk166 from "chalk";
21821
21957
  function viewIssue2(issueKey) {
21822
21958
  const parsed = fetchIssue(issueKey, "summary,description");
21823
21959
  const fields = parsed?.fields;
21824
21960
  const summary = fields?.summary;
21825
21961
  const description = fields?.description;
21826
21962
  if (summary) {
21827
- console.log(chalk164.bold(summary));
21963
+ console.log(chalk166.bold(summary));
21828
21964
  }
21829
21965
  if (description) {
21830
21966
  if (summary) console.log();
@@ -21838,7 +21974,7 @@ function viewIssue2(issueKey) {
21838
21974
  }
21839
21975
  if (!summary && !description) {
21840
21976
  console.log(
21841
- chalk164.yellow(`No summary or description found on ${issueKey}.`)
21977
+ chalk166.yellow(`No summary or description found on ${issueKey}.`)
21842
21978
  );
21843
21979
  }
21844
21980
  }
@@ -21873,7 +22009,7 @@ import { randomUUID as randomUUID10 } from "crypto";
21873
22009
 
21874
22010
  // src/commands/review/checkoutPr.ts
21875
22011
  import { execFileSync as execFileSync12 } from "child_process";
21876
- import chalk165 from "chalk";
22012
+ import chalk167 from "chalk";
21877
22013
 
21878
22014
  // src/commands/sessions/daemon/daemonLog.ts
21879
22015
  var RING_CAPACITY = 1e3;
@@ -22485,7 +22621,7 @@ async function checkoutPr(number) {
22485
22621
  try {
22486
22622
  execFileSync12("gh", ["pr", "checkout", number], { stdio: "inherit" });
22487
22623
  } catch {
22488
- console.error(chalk165.red(`gh pr checkout ${number} failed; aborting.`));
22624
+ console.error(chalk167.red(`gh pr checkout ${number} failed; aborting.`));
22489
22625
  process.exit(1);
22490
22626
  }
22491
22627
  }
@@ -22622,15 +22758,15 @@ function registerList(program2) {
22622
22758
  // src/commands/mermaid/index.ts
22623
22759
  import { mkdirSync as mkdirSync18, readdirSync as readdirSync11 } from "fs";
22624
22760
  import { resolve as resolve16 } from "path";
22625
- import chalk168 from "chalk";
22761
+ import chalk170 from "chalk";
22626
22762
 
22627
22763
  // src/commands/mermaid/exportFile.ts
22628
22764
  import { readFileSync as readFileSync39, writeFileSync as writeFileSync32 } from "fs";
22629
22765
  import { basename as basename17, extname as extname2, resolve as resolve15 } from "path";
22630
- import chalk167 from "chalk";
22766
+ import chalk169 from "chalk";
22631
22767
 
22632
22768
  // src/commands/mermaid/renderBlock.ts
22633
- import chalk166 from "chalk";
22769
+ import chalk168 from "chalk";
22634
22770
  async function renderBlock(krokiUrl, source) {
22635
22771
  const response = await fetch(`${krokiUrl}/mermaid/svg`, {
22636
22772
  method: "POST",
@@ -22639,7 +22775,7 @@ async function renderBlock(krokiUrl, source) {
22639
22775
  });
22640
22776
  if (!response.ok) {
22641
22777
  console.error(
22642
- chalk166.red(
22778
+ chalk168.red(
22643
22779
  `Kroki request failed: ${response.status} ${response.statusText}`
22644
22780
  )
22645
22781
  );
@@ -22657,19 +22793,19 @@ async function exportFile(file, outDir, krokiUrl, onlyIndex) {
22657
22793
  if (onlyIndex !== void 0) {
22658
22794
  if (onlyIndex < 1 || onlyIndex > blocks.length) {
22659
22795
  console.error(
22660
- chalk167.red(
22796
+ chalk169.red(
22661
22797
  `${file}: --index ${onlyIndex} out of range (file has ${blocks.length} diagram(s))`
22662
22798
  )
22663
22799
  );
22664
22800
  process.exit(1);
22665
22801
  }
22666
22802
  console.log(
22667
- chalk167.gray(
22803
+ chalk169.gray(
22668
22804
  `${file} \u2014 rendering diagram ${onlyIndex} of ${blocks.length}`
22669
22805
  )
22670
22806
  );
22671
22807
  } else {
22672
- console.log(chalk167.gray(`${file} \u2014 ${blocks.length} diagram(s)`));
22808
+ console.log(chalk169.gray(`${file} \u2014 ${blocks.length} diagram(s)`));
22673
22809
  }
22674
22810
  for (const [i, source] of blocks.entries()) {
22675
22811
  const idx = i + 1;
@@ -22677,7 +22813,7 @@ async function exportFile(file, outDir, krokiUrl, onlyIndex) {
22677
22813
  const outPath = resolve15(outDir, `${stem}-${idx}.svg`);
22678
22814
  const svg = await renderBlock(krokiUrl, source);
22679
22815
  writeFileSync32(outPath, svg, "utf8");
22680
- console.log(chalk167.green(` \u2192 ${outPath}`));
22816
+ console.log(chalk169.green(` \u2192 ${outPath}`));
22681
22817
  }
22682
22818
  }
22683
22819
  function extractMermaidBlocks(markdown) {
@@ -22693,18 +22829,18 @@ async function mermaidExport(file, options2 = {}) {
22693
22829
  if (options2.index !== void 0) {
22694
22830
  if (!Number.isInteger(options2.index) || options2.index < 1) {
22695
22831
  console.error(
22696
- chalk168.red(`--index must be a positive integer (got ${options2.index})`)
22832
+ chalk170.red(`--index must be a positive integer (got ${options2.index})`)
22697
22833
  );
22698
22834
  process.exit(1);
22699
22835
  }
22700
22836
  if (!file) {
22701
- console.error(chalk168.red("--index requires a file argument"));
22837
+ console.error(chalk170.red("--index requires a file argument"));
22702
22838
  process.exit(1);
22703
22839
  }
22704
22840
  }
22705
22841
  const files = file ? [file] : readdirSync11(process.cwd()).filter((name) => name.toLowerCase().endsWith(".md")).sort();
22706
22842
  if (files.length === 0) {
22707
- console.log(chalk168.gray("No markdown files found in current directory."));
22843
+ console.log(chalk170.gray("No markdown files found in current directory."));
22708
22844
  return;
22709
22845
  }
22710
22846
  for (const f of files) {
@@ -22760,13 +22896,13 @@ function stripHtml2(content) {
22760
22896
 
22761
22897
  // src/commands/miro/normaliseItems.ts
22762
22898
  var frameCoordinates = "parent_top_left";
22763
- function describe2(item) {
22899
+ function describe4(item) {
22764
22900
  return ` ${item.id ?? "(no id)"} (${item.type ?? "unknown type"}): relativeTo=${item.position?.relativeTo ?? "missing"}`;
22765
22901
  }
22766
22902
  function coordinateSpaceError(rejected) {
22767
22903
  return new MiroExtractError(
22768
22904
  `${rejected.length} item(s) are not in frame coordinates (position.relativeTo must be "${frameCoordinates}"):
22769
- ${rejected.slice(0, 5).map(describe2).join(
22905
+ ${rejected.slice(0, 5).map(describe4).join(
22770
22906
  "\n"
22771
22907
  )}
22772
22908
 
@@ -22911,7 +23047,7 @@ function registerMiro(program2) {
22911
23047
  import { mkdir as mkdir4 } from "fs/promises";
22912
23048
  import { createServer as createServer2 } from "http";
22913
23049
  import { dirname as dirname28 } from "path";
22914
- import chalk170 from "chalk";
23050
+ import chalk172 from "chalk";
22915
23051
 
22916
23052
  // src/commands/netcap/corsHeaders.ts
22917
23053
  var corsHeaders = {
@@ -22990,7 +23126,7 @@ function createNetcapHandler(options2) {
22990
23126
  import { cp, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
22991
23127
  import { networkInterfaces } from "os";
22992
23128
  import { join as join58 } from "path";
22993
- import chalk169 from "chalk";
23129
+ import chalk171 from "chalk";
22994
23130
 
22995
23131
  // src/commands/netcap/netcapExtensionDir.ts
22996
23132
  import { dirname as dirname27, join as join57 } from "path";
@@ -23034,7 +23170,7 @@ async function prepareExtensionForLoad(port, filter = "") {
23034
23170
  const host = lanIPv4();
23035
23171
  if (!host) {
23036
23172
  console.log(
23037
- chalk169.yellow("could not determine the WSL IP for the extension")
23173
+ chalk171.yellow("could not determine the WSL IP for the extension")
23038
23174
  );
23039
23175
  await configureBackground(source, "127.0.0.1", port, filter);
23040
23176
  return source;
@@ -23045,7 +23181,7 @@ async function prepareExtensionForLoad(port, filter = "") {
23045
23181
  return WSL_WINDOWS_PATH;
23046
23182
  } catch {
23047
23183
  console.log(
23048
- chalk169.yellow(`could not copy extension to ${WSL_WINDOWS_PATH}`)
23184
+ chalk171.yellow(`could not copy extension to ${WSL_WINDOWS_PATH}`)
23049
23185
  );
23050
23186
  return source;
23051
23187
  }
@@ -23078,30 +23214,30 @@ async function netcap(options2) {
23078
23214
  let count8 = 0;
23079
23215
  const handler = createNetcapHandler({
23080
23216
  outPath,
23081
- onPing: () => console.log(chalk170.dim("ping from extension")),
23217
+ onPing: () => console.log(chalk172.dim("ping from extension")),
23082
23218
  onCapture: (entry) => {
23083
23219
  count8 += 1;
23084
23220
  console.log(
23085
- chalk170.green(`captured #${count8}`),
23086
- chalk170.dim(`${entry.method ?? "?"} ${entry.url ?? "?"}`)
23221
+ chalk172.green(`captured #${count8}`),
23222
+ chalk172.dim(`${entry.method ?? "?"} ${entry.url ?? "?"}`)
23087
23223
  );
23088
23224
  }
23089
23225
  });
23090
23226
  const server = createServer2(handler);
23091
23227
  server.listen(port, () => {
23092
23228
  console.log(
23093
- chalk170.bold(`netcap receiver listening on http://127.0.0.1:${port}`)
23229
+ chalk172.bold(`netcap receiver listening on http://127.0.0.1:${port}`)
23094
23230
  );
23095
- console.log(chalk170.dim(`appending captures to ${outPath}`));
23231
+ console.log(chalk172.dim(`appending captures to ${outPath}`));
23096
23232
  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"));
23233
+ console.log(chalk172.dim(`forwarding only URLs matching "${filter}"`));
23234
+ console.log(chalk172.dim(`load the unpacked extension from ${extensionPath}`));
23235
+ console.log(chalk172.dim("press Ctrl-C to stop"));
23100
23236
  });
23101
23237
  process.on("SIGINT", () => {
23102
23238
  server.close();
23103
23239
  console.log(
23104
- chalk170.bold(
23240
+ chalk172.bold(
23105
23241
  `
23106
23242
  netcap stopped \u2014 captured ${count8} ${count8 === 1 ? "entry" : "entries"} to ${outPath}`
23107
23243
  )
@@ -23113,7 +23249,7 @@ netcap stopped \u2014 captured ${count8} ${count8 === 1 ? "entry" : "entries"} t
23113
23249
  // src/commands/netcap/netcapExtract.ts
23114
23250
  import { writeFileSync as writeFileSync33 } from "fs";
23115
23251
  import { join as join61 } from "path";
23116
- import chalk171 from "chalk";
23252
+ import chalk173 from "chalk";
23117
23253
 
23118
23254
  // src/commands/netcap/extractPostsFromCapture.ts
23119
23255
  import { readFileSync as readFileSync41 } from "fs";
@@ -23561,8 +23697,8 @@ function netcapExtract(file) {
23561
23697
  writeFileSync33(outFile, `${JSON.stringify(posts, null, 2)}
23562
23698
  `);
23563
23699
  console.log(
23564
- chalk171.green(`extracted ${posts.length} posts`),
23565
- chalk171.dim(`-> ${outFile}`)
23700
+ chalk173.green(`extracted ${posts.length} posts`),
23701
+ chalk173.dim(`-> ${outFile}`)
23566
23702
  );
23567
23703
  }
23568
23704
 
@@ -23583,7 +23719,7 @@ function registerNetcap(program2) {
23583
23719
  }
23584
23720
 
23585
23721
  // src/commands/news/add/index.ts
23586
- import chalk172 from "chalk";
23722
+ import chalk174 from "chalk";
23587
23723
  import enquirer8 from "enquirer";
23588
23724
  async function add2(url) {
23589
23725
  if (!url) {
@@ -23605,10 +23741,10 @@ async function add2(url) {
23605
23741
  const { orm } = await getReady();
23606
23742
  const added = await addFeed(orm, url);
23607
23743
  if (!added) {
23608
- console.log(chalk172.yellow("Feed already exists"));
23744
+ console.log(chalk174.yellow("Feed already exists"));
23609
23745
  return;
23610
23746
  }
23611
- console.log(chalk172.green(`Added feed: ${url}`));
23747
+ console.log(chalk174.green(`Added feed: ${url}`));
23612
23748
  }
23613
23749
 
23614
23750
  // src/commands/registerNews.ts
@@ -23655,7 +23791,7 @@ function registerPiHook(program2) {
23655
23791
  }
23656
23792
 
23657
23793
  // src/commands/prompts/printPromptsTable.ts
23658
- import chalk173 from "chalk";
23794
+ import chalk175 from "chalk";
23659
23795
  function truncate(str, max) {
23660
23796
  if (str.length <= max) return str;
23661
23797
  return `${str.slice(0, max - 1)}\u2026`;
@@ -23673,14 +23809,14 @@ function printPromptsTable(rows) {
23673
23809
  "Command".padEnd(commandWidth),
23674
23810
  "Repos"
23675
23811
  ].join(" ");
23676
- console.log(chalk173.dim(header));
23677
- console.log(chalk173.dim("-".repeat(header.length)));
23812
+ console.log(chalk175.dim(header));
23813
+ console.log(chalk175.dim("-".repeat(header.length)));
23678
23814
  for (const row of rows) {
23679
23815
  const count8 = String(row.count).padStart(countWidth);
23680
23816
  const tool = row.tool.padEnd(toolWidth);
23681
23817
  const command = truncate(row.command, 60).padEnd(commandWidth);
23682
23818
  console.log(
23683
- `${chalk173.yellow(count8)} ${tool} ${command} ${chalk173.dim(row.repos)}`
23819
+ `${chalk175.yellow(count8)} ${tool} ${command} ${chalk175.dim(row.repos)}`
23684
23820
  );
23685
23821
  }
23686
23822
  }
@@ -24347,13 +24483,13 @@ function agentFooter(unresolvedCount) {
24347
24483
  }
24348
24484
 
24349
24485
  // src/commands/prs/listComments/commentStyle.ts
24350
- import chalk174 from "chalk";
24486
+ import chalk176 from "chalk";
24351
24487
  var plain = (text18) => text18;
24352
24488
  function colouredState(state) {
24353
24489
  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);
24490
+ if (state === "APPROVED") return chalk176.green(label2);
24491
+ if (state === "CHANGES_REQUESTED") return chalk176.red(label2);
24492
+ return chalk176.yellow(label2);
24357
24493
  }
24358
24494
  function commentStyle() {
24359
24495
  if (isClaudeCode()) {
@@ -24367,9 +24503,9 @@ function commentStyle() {
24367
24503
  };
24368
24504
  }
24369
24505
  return {
24370
- cyan: chalk174.cyan,
24371
- bold: chalk174.bold,
24372
- dim: chalk174.dim,
24506
+ cyan: chalk176.cyan,
24507
+ bold: chalk176.bold,
24508
+ dim: chalk176.dim,
24373
24509
  state: colouredState,
24374
24510
  diffHunk: true,
24375
24511
  agent: false
@@ -24539,13 +24675,13 @@ import { execSync as execSync48 } from "child_process";
24539
24675
  import enquirer9 from "enquirer";
24540
24676
 
24541
24677
  // src/commands/prs/prs/displayPaginated/printPr.ts
24542
- import chalk175 from "chalk";
24678
+ import chalk177 from "chalk";
24543
24679
  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
24680
+ MERGED: (pr) => pr.mergedAt ? { label: chalk177.magenta("merged"), date: pr.mergedAt } : null,
24681
+ CLOSED: (pr) => pr.closedAt ? { label: chalk177.red("closed"), date: pr.closedAt } : null
24546
24682
  };
24547
24683
  function defaultStatus(pr) {
24548
- return { label: chalk175.green("opened"), date: pr.createdAt };
24684
+ return { label: chalk177.green("opened"), date: pr.createdAt };
24549
24685
  }
24550
24686
  function getStatus2(pr) {
24551
24687
  return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
@@ -24554,11 +24690,11 @@ function formatDate(dateStr) {
24554
24690
  return new Date(dateStr).toISOString().split("T")[0];
24555
24691
  }
24556
24692
  function formatPrHeader(pr, status3) {
24557
- return `${chalk175.cyan(`#${pr.number}`)} ${pr.title} ${chalk175.dim(`(${pr.author.login},`)} ${status3.label} ${chalk175.dim(`${formatDate(status3.date)})`)}`;
24693
+ return `${chalk177.cyan(`#${pr.number}`)} ${pr.title} ${chalk177.dim(`(${pr.author.login},`)} ${status3.label} ${chalk177.dim(`${formatDate(status3.date)})`)}`;
24558
24694
  }
24559
24695
  function logPrDetails(pr) {
24560
24696
  console.log(
24561
- chalk175.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
24697
+ chalk177.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
24562
24698
  );
24563
24699
  console.log();
24564
24700
  }
@@ -25273,10 +25409,10 @@ function registerPrs(program2) {
25273
25409
  }
25274
25410
 
25275
25411
  // src/commands/ravendb/ravendbAuth.ts
25276
- import chalk181 from "chalk";
25412
+ import chalk183 from "chalk";
25277
25413
 
25278
25414
  // src/shared/createConnectionAuth.ts
25279
- import chalk176 from "chalk";
25415
+ import chalk178 from "chalk";
25280
25416
  function listConnections(connections, format) {
25281
25417
  if (connections.length === 0) {
25282
25418
  console.log("No connections configured.");
@@ -25289,7 +25425,7 @@ function listConnections(connections, format) {
25289
25425
  function removeConnection(connections, name, save) {
25290
25426
  const filtered = connections.filter((c) => c.name !== name);
25291
25427
  if (filtered.length === connections.length) {
25292
- console.error(chalk176.red(`Connection "${name}" not found.`));
25428
+ console.error(chalk178.red(`Connection "${name}" not found.`));
25293
25429
  process.exit(1);
25294
25430
  }
25295
25431
  save(filtered);
@@ -25335,15 +25471,15 @@ function saveConnections(connections) {
25335
25471
  }
25336
25472
 
25337
25473
  // src/commands/ravendb/promptConnection.ts
25338
- import chalk179 from "chalk";
25474
+ import chalk181 from "chalk";
25339
25475
 
25340
25476
  // src/commands/ravendb/selectOpSecret.ts
25341
- import chalk178 from "chalk";
25477
+ import chalk180 from "chalk";
25342
25478
  import Enquirer2 from "enquirer";
25343
25479
 
25344
25480
  // src/commands/ravendb/searchItems.ts
25345
25481
  import { execSync as execSync51 } from "child_process";
25346
- import chalk177 from "chalk";
25482
+ import chalk179 from "chalk";
25347
25483
  function opExec(args) {
25348
25484
  return execSync51(`op ${args}`, {
25349
25485
  encoding: "utf8",
@@ -25356,7 +25492,7 @@ function searchItems(search2) {
25356
25492
  items2 = JSON.parse(opExec("item list --format=json"));
25357
25493
  } catch {
25358
25494
  console.error(
25359
- chalk177.red(
25495
+ chalk179.red(
25360
25496
  "Failed to search 1Password. Ensure the CLI is installed and you are signed in."
25361
25497
  )
25362
25498
  );
@@ -25370,7 +25506,7 @@ function getItemFields(itemId2) {
25370
25506
  const item = JSON.parse(opExec(`item get "${itemId2}" --format=json`));
25371
25507
  return item.fields.filter((f) => f.reference && f.label);
25372
25508
  } catch {
25373
- console.error(chalk177.red("Failed to get item details from 1Password."));
25509
+ console.error(chalk179.red("Failed to get item details from 1Password."));
25374
25510
  process.exit(1);
25375
25511
  }
25376
25512
  }
@@ -25389,7 +25525,7 @@ async function selectOpSecret(searchTerm) {
25389
25525
  }).run();
25390
25526
  const items2 = searchItems(search2);
25391
25527
  if (items2.length === 0) {
25392
- console.error(chalk178.red(`No items found matching "${search2}".`));
25528
+ console.error(chalk180.red(`No items found matching "${search2}".`));
25393
25529
  process.exit(1);
25394
25530
  }
25395
25531
  const itemId2 = await selectOne(
@@ -25398,7 +25534,7 @@ async function selectOpSecret(searchTerm) {
25398
25534
  );
25399
25535
  const fields = getItemFields(itemId2);
25400
25536
  if (fields.length === 0) {
25401
- console.error(chalk178.red("No fields with references found on this item."));
25537
+ console.error(chalk180.red("No fields with references found on this item."));
25402
25538
  process.exit(1);
25403
25539
  }
25404
25540
  const ref = await selectOne(
@@ -25412,7 +25548,7 @@ async function selectOpSecret(searchTerm) {
25412
25548
  async function promptConnection(existingNames) {
25413
25549
  const name = await promptInput("name", "Connection name:");
25414
25550
  if (existingNames.includes(name)) {
25415
- console.error(chalk179.red(`Connection "${name}" already exists.`));
25551
+ console.error(chalk181.red(`Connection "${name}" already exists.`));
25416
25552
  process.exit(1);
25417
25553
  }
25418
25554
  const url = await promptInput(
@@ -25421,22 +25557,22 @@ async function promptConnection(existingNames) {
25421
25557
  );
25422
25558
  const database = await promptInput("database", "Database name:");
25423
25559
  if (!name || !url || !database) {
25424
- console.error(chalk179.red("All fields are required."));
25560
+ console.error(chalk181.red("All fields are required."));
25425
25561
  process.exit(1);
25426
25562
  }
25427
25563
  const apiKeyRef = await selectOpSecret();
25428
- console.log(chalk179.dim(`Using: ${apiKeyRef}`));
25564
+ console.log(chalk181.dim(`Using: ${apiKeyRef}`));
25429
25565
  return { name, url, database, apiKeyRef };
25430
25566
  }
25431
25567
 
25432
25568
  // src/commands/ravendb/ravendbSetConnection.ts
25433
- import chalk180 from "chalk";
25569
+ import chalk182 from "chalk";
25434
25570
  function ravendbSetConnection(name) {
25435
25571
  const raw = loadGlobalConfigRaw();
25436
25572
  const ravendb = raw.ravendb ?? {};
25437
25573
  const connections = ravendb.connections ?? [];
25438
25574
  if (!connections.some((c) => c.name === name)) {
25439
- console.error(chalk180.red(`Connection "${name}" not found.`));
25575
+ console.error(chalk182.red(`Connection "${name}" not found.`));
25440
25576
  console.error(
25441
25577
  `Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
25442
25578
  );
@@ -25452,16 +25588,16 @@ function ravendbSetConnection(name) {
25452
25588
  var ravendbAuth = createConnectionAuth({
25453
25589
  load: loadConnections,
25454
25590
  save: saveConnections,
25455
- format: (c) => `${chalk181.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
25591
+ format: (c) => `${chalk183.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
25456
25592
  promptNew: promptConnection,
25457
25593
  onFirst: (c) => ravendbSetConnection(c.name)
25458
25594
  });
25459
25595
 
25460
25596
  // src/commands/ravendb/ravendbCollections.ts
25461
- import chalk185 from "chalk";
25597
+ import chalk187 from "chalk";
25462
25598
 
25463
25599
  // src/commands/ravendb/ravenFetch.ts
25464
- import chalk183 from "chalk";
25600
+ import chalk185 from "chalk";
25465
25601
 
25466
25602
  // src/commands/ravendb/getAccessToken.ts
25467
25603
  var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
@@ -25498,10 +25634,10 @@ ${errorText}`
25498
25634
 
25499
25635
  // src/commands/ravendb/resolveOpSecret.ts
25500
25636
  import { execSync as execSync52 } from "child_process";
25501
- import chalk182 from "chalk";
25637
+ import chalk184 from "chalk";
25502
25638
  function resolveOpSecret(reference) {
25503
25639
  if (!reference.startsWith("op://")) {
25504
- console.error(chalk182.red(`Invalid secret reference: must start with op://`));
25640
+ console.error(chalk184.red(`Invalid secret reference: must start with op://`));
25505
25641
  process.exit(1);
25506
25642
  }
25507
25643
  try {
@@ -25511,7 +25647,7 @@ function resolveOpSecret(reference) {
25511
25647
  }).trim();
25512
25648
  } catch {
25513
25649
  console.error(
25514
- chalk182.red(
25650
+ chalk184.red(
25515
25651
  "Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
25516
25652
  )
25517
25653
  );
@@ -25538,7 +25674,7 @@ async function ravenFetch(connection, path80) {
25538
25674
  if (!response.ok) {
25539
25675
  const body = await response.text();
25540
25676
  console.error(
25541
- chalk183.red(`RavenDB error: ${response.status} ${response.statusText}`)
25677
+ chalk185.red(`RavenDB error: ${response.status} ${response.statusText}`)
25542
25678
  );
25543
25679
  console.error(body.substring(0, 500));
25544
25680
  process.exit(1);
@@ -25547,7 +25683,7 @@ async function ravenFetch(connection, path80) {
25547
25683
  }
25548
25684
 
25549
25685
  // src/commands/ravendb/resolveConnection.ts
25550
- import chalk184 from "chalk";
25686
+ import chalk186 from "chalk";
25551
25687
  function loadRavendb() {
25552
25688
  const raw = loadGlobalConfigRaw();
25553
25689
  const ravendb = raw.ravendb;
@@ -25561,7 +25697,7 @@ function resolveConnection(name) {
25561
25697
  const connectionName = name ?? defaultConnection;
25562
25698
  if (!connectionName) {
25563
25699
  console.error(
25564
- chalk184.red(
25700
+ chalk186.red(
25565
25701
  "No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
25566
25702
  )
25567
25703
  );
@@ -25569,7 +25705,7 @@ function resolveConnection(name) {
25569
25705
  }
25570
25706
  const connection = connections.find((c) => c.name === connectionName);
25571
25707
  if (!connection) {
25572
- console.error(chalk184.red(`Connection "${connectionName}" not found.`));
25708
+ console.error(chalk186.red(`Connection "${connectionName}" not found.`));
25573
25709
  console.error(
25574
25710
  `Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
25575
25711
  );
@@ -25600,15 +25736,15 @@ async function ravendbCollections(connectionName) {
25600
25736
  return;
25601
25737
  }
25602
25738
  for (const c of collections) {
25603
- console.log(`${chalk185.bold(c.Name)} ${c.CountOfDocuments} docs`);
25739
+ console.log(`${chalk187.bold(c.Name)} ${c.CountOfDocuments} docs`);
25604
25740
  }
25605
25741
  }
25606
25742
 
25607
25743
  // src/commands/ravendb/ravendbQuery.ts
25608
- import chalk187 from "chalk";
25744
+ import chalk189 from "chalk";
25609
25745
 
25610
25746
  // src/commands/ravendb/fetchAllPages.ts
25611
- import chalk186 from "chalk";
25747
+ import chalk188 from "chalk";
25612
25748
 
25613
25749
  // src/commands/ravendb/buildQueryPath.ts
25614
25750
  function buildQueryPath(opts) {
@@ -25646,7 +25782,7 @@ async function fetchAllPages(connection, opts) {
25646
25782
  allResults.push(...results);
25647
25783
  start3 += results.length;
25648
25784
  process.stderr.write(
25649
- `\r${chalk186.dim(`Fetched ${allResults.length}/${totalResults}`)}`
25785
+ `\r${chalk188.dim(`Fetched ${allResults.length}/${totalResults}`)}`
25650
25786
  );
25651
25787
  if (start3 >= totalResults) break;
25652
25788
  if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
@@ -25661,7 +25797,7 @@ async function fetchAllPages(connection, opts) {
25661
25797
  async function ravendbQuery(connectionName, collection, options2) {
25662
25798
  const resolved = resolveArgs(connectionName, collection);
25663
25799
  if (!resolved.collection && !options2.query) {
25664
- console.error(chalk187.red("Provide a collection name or --query filter."));
25800
+ console.error(chalk189.red("Provide a collection name or --query filter."));
25665
25801
  process.exit(1);
25666
25802
  }
25667
25803
  const { collection: col } = resolved;
@@ -25700,7 +25836,7 @@ import { spawn as spawn6 } from "child_process";
25700
25836
  import * as path42 from "path";
25701
25837
 
25702
25838
  // src/commands/refactor/logViolations.ts
25703
- import chalk188 from "chalk";
25839
+ import chalk190 from "chalk";
25704
25840
  var DEFAULT_MAX_LINES2 = 100;
25705
25841
  function logViolations(violations, maxLines = DEFAULT_MAX_LINES2) {
25706
25842
  if (violations.length === 0) {
@@ -25709,43 +25845,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES2) {
25709
25845
  }
25710
25846
  return;
25711
25847
  }
25712
- console.error(chalk188.red(`
25848
+ console.error(chalk190.red(`
25713
25849
  Refactor check failed:
25714
25850
  `));
25715
- console.error(chalk188.red(` The following files exceed ${maxLines} lines:
25851
+ console.error(chalk190.red(` The following files exceed ${maxLines} lines:
25716
25852
  `));
25717
25853
  for (const violation of violations) {
25718
- console.error(chalk188.red(` ${violation.file} (${violation.lines} lines)`));
25854
+ console.error(chalk190.red(` ${violation.file} (${violation.lines} lines)`));
25719
25855
  }
25720
25856
  console.error(
25721
- chalk188.yellow(
25857
+ chalk190.yellow(
25722
25858
  `
25723
25859
  Each file needs to be sensibly refactored, or if there is no sensible
25724
25860
  way to refactor it, ignore it with:
25725
25861
  `
25726
25862
  )
25727
25863
  );
25728
- console.error(chalk188.gray(` assist refactor ignore <file>
25864
+ console.error(chalk190.gray(` assist refactor ignore <file>
25729
25865
  `));
25730
25866
  if (process.env.CLAUDECODE) {
25731
- console.error(chalk188.cyan(`
25867
+ console.error(chalk190.cyan(`
25732
25868
  ## Extracting Code to New Files
25733
25869
  `));
25734
25870
  console.error(
25735
- chalk188.cyan(
25871
+ chalk190.cyan(
25736
25872
  ` When extracting logic from one file to another, consider where the extracted code belongs:
25737
25873
  `
25738
25874
  )
25739
25875
  );
25740
25876
  console.error(
25741
- chalk188.cyan(
25877
+ chalk190.cyan(
25742
25878
  ` 1. Keep related logic together: If the extracted code is tightly coupled to the
25743
25879
  original file's domain, create a new folder containing both the original and extracted files.
25744
25880
  `
25745
25881
  )
25746
25882
  );
25747
25883
  console.error(
25748
- chalk188.cyan(
25884
+ chalk190.cyan(
25749
25885
  ` 2. Share common utilities: If the extracted code can be reused across multiple
25750
25886
  domains, move it to a common/shared folder.
25751
25887
  `
@@ -25901,7 +26037,7 @@ async function check(pattern2, options2) {
25901
26037
 
25902
26038
  // src/commands/refactor/extract/index.ts
25903
26039
  import path50 from "path";
25904
- import chalk191 from "chalk";
26040
+ import chalk193 from "chalk";
25905
26041
 
25906
26042
  // src/commands/refactor/extract/applyExtraction.ts
25907
26043
  import { SyntaxKind as SyntaxKind4 } from "ts-morph";
@@ -26500,23 +26636,23 @@ function buildPlan2(functionName, sourceFile, sourcePath, destPath, project) {
26500
26636
 
26501
26637
  // src/commands/refactor/extract/displayPlan.ts
26502
26638
  import path46 from "path";
26503
- import chalk189 from "chalk";
26639
+ import chalk191 from "chalk";
26504
26640
  function section2(title) {
26505
26641
  return `
26506
- ${chalk189.cyan(title)}`;
26642
+ ${chalk191.cyan(title)}`;
26507
26643
  }
26508
26644
  function displayImporters(plan2, cwd) {
26509
26645
  if (plan2.importersToUpdate.length === 0) return;
26510
26646
  console.log(section2("Update importers:"));
26511
26647
  for (const imp of plan2.importersToUpdate) {
26512
26648
  const rel = path46.relative(cwd, imp.file.getFilePath());
26513
- console.log(` ${chalk189.dim(rel)}: \u2192 import from "${imp.relPath}"`);
26649
+ console.log(` ${chalk191.dim(rel)}: \u2192 import from "${imp.relPath}"`);
26514
26650
  }
26515
26651
  }
26516
26652
  function displayPlan(functionName, relDest, plan2, cwd) {
26517
- console.log(chalk189.bold(`Extract: ${functionName} \u2192 ${relDest}
26653
+ console.log(chalk191.bold(`Extract: ${functionName} \u2192 ${relDest}
26518
26654
  `));
26519
- console.log(` ${chalk189.cyan("Functions to move:")}`);
26655
+ console.log(` ${chalk191.cyan("Functions to move:")}`);
26520
26656
  for (const name of plan2.extractedNames) {
26521
26657
  console.log(` ${name}`);
26522
26658
  }
@@ -26550,7 +26686,7 @@ function displayPlan(functionName, relDest, plan2, cwd) {
26550
26686
 
26551
26687
  // src/commands/refactor/extract/loadProjectFile.ts
26552
26688
  import path49 from "path";
26553
- import chalk190 from "chalk";
26689
+ import chalk192 from "chalk";
26554
26690
  import { Project as Project4 } from "ts-morph";
26555
26691
 
26556
26692
  // src/commands/refactor/extract/findTsConfig.ts
@@ -26642,7 +26778,7 @@ function loadProjectFile(file) {
26642
26778
  });
26643
26779
  const sourceFile = project.getSourceFile(sourcePath);
26644
26780
  if (!sourceFile) {
26645
- console.log(chalk190.red(`File not found in project: ${file}`));
26781
+ console.log(chalk192.red(`File not found in project: ${file}`));
26646
26782
  process.exit(1);
26647
26783
  }
26648
26784
  return { project, sourceFile };
@@ -26665,19 +26801,19 @@ async function extract(file, functionName, destination, options2 = {}) {
26665
26801
  displayPlan(functionName, relDest, plan2, cwd);
26666
26802
  if (options2.apply) {
26667
26803
  await applyExtraction(functionName, sourceFile, destPath, plan2, project);
26668
- console.log(chalk191.green("\nExtraction complete"));
26804
+ console.log(chalk193.green("\nExtraction complete"));
26669
26805
  } else {
26670
- console.log(chalk191.dim("\nDry run. Use --apply to execute."));
26806
+ console.log(chalk193.dim("\nDry run. Use --apply to execute."));
26671
26807
  }
26672
26808
  }
26673
26809
 
26674
26810
  // src/commands/refactor/ignore.ts
26675
26811
  import fs33 from "fs";
26676
- import chalk192 from "chalk";
26812
+ import chalk194 from "chalk";
26677
26813
  var REFACTOR_YML_PATH2 = "refactor.yml";
26678
26814
  function ignore2(file) {
26679
26815
  if (!fs33.existsSync(file)) {
26680
- console.error(chalk192.red(`Error: File does not exist: ${file}`));
26816
+ console.error(chalk194.red(`Error: File does not exist: ${file}`));
26681
26817
  process.exit(1);
26682
26818
  }
26683
26819
  const content = fs33.readFileSync(file, "utf8");
@@ -26693,7 +26829,7 @@ function ignore2(file) {
26693
26829
  fs33.writeFileSync(REFACTOR_YML_PATH2, entry);
26694
26830
  }
26695
26831
  console.log(
26696
- chalk192.green(
26832
+ chalk194.green(
26697
26833
  `Added ${file} to refactor ignore list (max ${maxLines} lines)`
26698
26834
  )
26699
26835
  );
@@ -26702,12 +26838,12 @@ function ignore2(file) {
26702
26838
  // src/commands/refactor/rename/index.ts
26703
26839
  import fs36 from "fs";
26704
26840
  import path55 from "path";
26705
- import chalk195 from "chalk";
26841
+ import chalk197 from "chalk";
26706
26842
 
26707
26843
  // src/commands/refactor/rename/applyRename.ts
26708
26844
  import fs35 from "fs";
26709
26845
  import path52 from "path";
26710
- import chalk193 from "chalk";
26846
+ import chalk195 from "chalk";
26711
26847
 
26712
26848
  // src/commands/refactor/restructure/computeRewrites/index.ts
26713
26849
  import path51 from "path";
@@ -26812,13 +26948,13 @@ function applyRename(rewrites, sourcePath, destPath, cwd) {
26812
26948
  const updatedContents = applyRewrites(rewrites);
26813
26949
  for (const [file, content] of updatedContents) {
26814
26950
  fs35.writeFileSync(file, content, "utf8");
26815
- console.log(chalk193.cyan(` Updated imports in ${path52.relative(cwd, file)}`));
26951
+ console.log(chalk195.cyan(` Updated imports in ${path52.relative(cwd, file)}`));
26816
26952
  }
26817
26953
  const destDir = path52.dirname(destPath);
26818
26954
  if (!fs35.existsSync(destDir)) fs35.mkdirSync(destDir, { recursive: true });
26819
26955
  fs35.renameSync(sourcePath, destPath);
26820
26956
  console.log(
26821
- chalk193.white(
26957
+ chalk195.white(
26822
26958
  ` Moved ${path52.relative(cwd, sourcePath)} \u2192 ${path52.relative(cwd, destPath)}`
26823
26959
  )
26824
26960
  );
@@ -26905,16 +27041,16 @@ function computeRenameRewrites(sourcePath, destPath) {
26905
27041
 
26906
27042
  // src/commands/refactor/rename/printRenamePreview.ts
26907
27043
  import path54 from "path";
26908
- import chalk194 from "chalk";
27044
+ import chalk196 from "chalk";
26909
27045
  function printRenamePreview(rewrites, cwd) {
26910
27046
  for (const rewrite of rewrites) {
26911
27047
  console.log(
26912
- chalk194.dim(
27048
+ chalk196.dim(
26913
27049
  ` ${path54.relative(cwd, rewrite.file)}: ${rewrite.oldSpecifier} \u2192 ${rewrite.newSpecifier}`
26914
27050
  )
26915
27051
  );
26916
27052
  }
26917
- console.log(chalk194.dim("Dry run. Use --apply to execute."));
27053
+ console.log(chalk196.dim("Dry run. Use --apply to execute."));
26918
27054
  }
26919
27055
 
26920
27056
  // src/commands/refactor/rename/index.ts
@@ -26925,20 +27061,20 @@ async function rename(source, destination, options2 = {}) {
26925
27061
  const relSource = path55.relative(cwd, sourcePath);
26926
27062
  const relDest = path55.relative(cwd, destPath);
26927
27063
  if (!fs36.existsSync(sourcePath)) {
26928
- console.log(chalk195.red(`File not found: ${source}`));
27064
+ console.log(chalk197.red(`File not found: ${source}`));
26929
27065
  process.exit(1);
26930
27066
  }
26931
27067
  if (destPath !== sourcePath && fs36.existsSync(destPath)) {
26932
- console.log(chalk195.red(`Destination already exists: ${destination}`));
27068
+ console.log(chalk197.red(`Destination already exists: ${destination}`));
26933
27069
  process.exit(1);
26934
27070
  }
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..."));
27071
+ console.log(chalk197.bold(`Rename: ${relSource} \u2192 ${relDest}`));
27072
+ console.log(chalk197.dim("Loading project..."));
27073
+ console.log(chalk197.dim("Scanning imports across the project..."));
26938
27074
  const rewrites = computeRenameRewrites(sourcePath, destPath);
26939
27075
  const affectedFiles = new Set(rewrites.map((r) => r.file)).size;
26940
27076
  console.log(
26941
- chalk195.dim(
27077
+ chalk197.dim(
26942
27078
  `${rewrites.length} import path(s) to update across ${affectedFiles} file(s)`
26943
27079
  )
26944
27080
  );
@@ -26947,11 +27083,11 @@ async function rename(source, destination, options2 = {}) {
26947
27083
  return;
26948
27084
  }
26949
27085
  applyRename(rewrites, sourcePath, destPath, cwd);
26950
- console.log(chalk195.green("Done"));
27086
+ console.log(chalk197.green("Done"));
26951
27087
  }
26952
27088
 
26953
27089
  // src/commands/refactor/renameSymbol/index.ts
26954
- import chalk196 from "chalk";
27090
+ import chalk198 from "chalk";
26955
27091
 
26956
27092
  // src/commands/refactor/renameSymbol/findSymbol.ts
26957
27093
  import { SyntaxKind as SyntaxKind15 } from "ts-morph";
@@ -26997,33 +27133,33 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
26997
27133
  const { project, sourceFile } = loadProjectFile(file);
26998
27134
  const symbol = findSymbol(sourceFile, oldName);
26999
27135
  if (!symbol) {
27000
- console.log(chalk196.red(`Symbol "${oldName}" not found in ${file}`));
27136
+ console.log(chalk198.red(`Symbol "${oldName}" not found in ${file}`));
27001
27137
  process.exit(1);
27002
27138
  }
27003
27139
  const grouped = groupReferences(symbol, cwd);
27004
27140
  const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
27005
27141
  console.log(
27006
- chalk196.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
27142
+ chalk198.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
27007
27143
  `)
27008
27144
  );
27009
27145
  for (const [refFile, lines2] of grouped) {
27010
27146
  console.log(
27011
- ` ${chalk196.dim(refFile)}: lines ${chalk196.cyan(lines2.join(", "))}`
27147
+ ` ${chalk198.dim(refFile)}: lines ${chalk198.cyan(lines2.join(", "))}`
27012
27148
  );
27013
27149
  }
27014
27150
  if (options2.apply) {
27015
27151
  symbol.rename(newName);
27016
27152
  await project.save();
27017
- console.log(chalk196.green(`
27153
+ console.log(chalk198.green(`
27018
27154
  Renamed ${oldName} \u2192 ${newName}`));
27019
27155
  } else {
27020
- console.log(chalk196.dim("\nDry run. Use --apply to execute."));
27156
+ console.log(chalk198.dim("\nDry run. Use --apply to execute."));
27021
27157
  }
27022
27158
  }
27023
27159
 
27024
27160
  // src/commands/refactor/restructure/index.ts
27025
27161
  import path63 from "path";
27026
- import chalk199 from "chalk";
27162
+ import chalk201 from "chalk";
27027
27163
 
27028
27164
  // src/commands/refactor/restructure/clusterDirectories.ts
27029
27165
  import path57 from "path";
@@ -27102,50 +27238,50 @@ function clusterFiles(graph) {
27102
27238
 
27103
27239
  // src/commands/refactor/restructure/displayPlan.ts
27104
27240
  import path59 from "path";
27105
- import chalk197 from "chalk";
27241
+ import chalk199 from "chalk";
27106
27242
  function relPath(filePath) {
27107
27243
  return path59.relative(process.cwd(), filePath);
27108
27244
  }
27109
27245
  function displayMoves(plan2) {
27110
27246
  if (plan2.moves.length === 0) return;
27111
- console.log(chalk197.bold("\nFile moves:"));
27247
+ console.log(chalk199.bold("\nFile moves:"));
27112
27248
  for (const move2 of plan2.moves) {
27113
27249
  console.log(
27114
- ` ${chalk197.red(relPath(move2.from))} \u2192 ${chalk197.green(relPath(move2.to))}`
27250
+ ` ${chalk199.red(relPath(move2.from))} \u2192 ${chalk199.green(relPath(move2.to))}`
27115
27251
  );
27116
- console.log(chalk197.dim(` ${move2.reason}`));
27252
+ console.log(chalk199.dim(` ${move2.reason}`));
27117
27253
  }
27118
27254
  }
27119
27255
  function displayRewrites(rewrites) {
27120
27256
  if (rewrites.length === 0) return;
27121
27257
  const affectedFiles = new Set(rewrites.map((r) => r.file));
27122
- console.log(chalk197.bold(`
27258
+ console.log(chalk199.bold(`
27123
27259
  Import rewrites (${affectedFiles.size} files):`));
27124
27260
  for (const file of affectedFiles) {
27125
- console.log(` ${chalk197.cyan(relPath(file))}:`);
27261
+ console.log(` ${chalk199.cyan(relPath(file))}:`);
27126
27262
  for (const { oldSpecifier, newSpecifier } of rewrites.filter(
27127
27263
  (r) => r.file === file
27128
27264
  )) {
27129
27265
  console.log(
27130
- ` ${chalk197.red(`"${oldSpecifier}"`)} \u2192 ${chalk197.green(`"${newSpecifier}"`)}`
27266
+ ` ${chalk199.red(`"${oldSpecifier}"`)} \u2192 ${chalk199.green(`"${newSpecifier}"`)}`
27131
27267
  );
27132
27268
  }
27133
27269
  }
27134
27270
  }
27135
27271
  function displayPlan2(plan2) {
27136
27272
  if (plan2.warnings.length > 0) {
27137
- console.log(chalk197.yellow("\nWarnings:"));
27138
- for (const w of plan2.warnings) console.log(chalk197.yellow(` ${w}`));
27273
+ console.log(chalk199.yellow("\nWarnings:"));
27274
+ for (const w of plan2.warnings) console.log(chalk199.yellow(` ${w}`));
27139
27275
  }
27140
27276
  if (plan2.newDirectories.length > 0) {
27141
- console.log(chalk197.bold("\nNew directories:"));
27277
+ console.log(chalk199.bold("\nNew directories:"));
27142
27278
  for (const dir of plan2.newDirectories)
27143
- console.log(chalk197.green(` ${dir}/`));
27279
+ console.log(chalk199.green(` ${dir}/`));
27144
27280
  }
27145
27281
  displayMoves(plan2);
27146
27282
  displayRewrites(plan2.rewrites);
27147
27283
  console.log(
27148
- chalk197.dim(
27284
+ chalk199.dim(
27149
27285
  `
27150
27286
  Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports rewritten`
27151
27287
  )
@@ -27155,18 +27291,18 @@ Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports r
27155
27291
  // src/commands/refactor/restructure/executePlan.ts
27156
27292
  import fs37 from "fs";
27157
27293
  import path60 from "path";
27158
- import chalk198 from "chalk";
27294
+ import chalk200 from "chalk";
27159
27295
  function executePlan(plan2) {
27160
27296
  const updatedContents = applyRewrites(plan2.rewrites);
27161
27297
  for (const [file, content] of updatedContents) {
27162
27298
  fs37.writeFileSync(file, content, "utf8");
27163
27299
  console.log(
27164
- chalk198.cyan(` Rewrote imports in ${path60.relative(process.cwd(), file)}`)
27300
+ chalk200.cyan(` Rewrote imports in ${path60.relative(process.cwd(), file)}`)
27165
27301
  );
27166
27302
  }
27167
27303
  for (const dir of plan2.newDirectories) {
27168
27304
  fs37.mkdirSync(dir, { recursive: true });
27169
- console.log(chalk198.green(` Created ${path60.relative(process.cwd(), dir)}/`));
27305
+ console.log(chalk200.green(` Created ${path60.relative(process.cwd(), dir)}/`));
27170
27306
  }
27171
27307
  for (const move2 of plan2.moves) {
27172
27308
  const targetDir = path60.dirname(move2.to);
@@ -27175,7 +27311,7 @@ function executePlan(plan2) {
27175
27311
  }
27176
27312
  fs37.renameSync(move2.from, move2.to);
27177
27313
  console.log(
27178
- chalk198.white(
27314
+ chalk200.white(
27179
27315
  ` Moved ${path60.relative(process.cwd(), move2.from)} \u2192 ${path60.relative(process.cwd(), move2.to)}`
27180
27316
  )
27181
27317
  );
@@ -27190,7 +27326,7 @@ function removeEmptyDirectories(dirs) {
27190
27326
  if (entries.length === 0) {
27191
27327
  fs37.rmdirSync(dir);
27192
27328
  console.log(
27193
- chalk198.dim(
27329
+ chalk200.dim(
27194
27330
  ` Removed empty directory ${path60.relative(process.cwd(), dir)}`
27195
27331
  )
27196
27332
  );
@@ -27323,22 +27459,22 @@ async function restructure(pattern2, options2 = {}) {
27323
27459
  const targetPattern = pattern2 ?? "src";
27324
27460
  const files = findSourceFiles2(targetPattern);
27325
27461
  if (files.length === 0) {
27326
- console.log(chalk199.yellow("No files found matching pattern"));
27462
+ console.log(chalk201.yellow("No files found matching pattern"));
27327
27463
  return;
27328
27464
  }
27329
27465
  const tsConfigPath = findTsConfig(path63.resolve(files[0]));
27330
27466
  const plan2 = buildPlan3(files, tsConfigPath);
27331
27467
  if (plan2.moves.length === 0) {
27332
- console.log(chalk199.green("No restructuring needed"));
27468
+ console.log(chalk201.green("No restructuring needed"));
27333
27469
  return;
27334
27470
  }
27335
27471
  displayPlan2(plan2);
27336
27472
  if (options2.apply) {
27337
- console.log(chalk199.bold("\nApplying changes..."));
27473
+ console.log(chalk201.bold("\nApplying changes..."));
27338
27474
  executePlan(plan2);
27339
- console.log(chalk199.green("\nRestructuring complete"));
27475
+ console.log(chalk201.green("\nRestructuring complete"));
27340
27476
  } else {
27341
- console.log(chalk199.dim("\nDry run. Use --apply to execute."));
27477
+ console.log(chalk201.dim("\nDry run. Use --apply to execute."));
27342
27478
  }
27343
27479
  }
27344
27480
 
@@ -27865,15 +28001,15 @@ function runReviewSubmission(mutation, body) {
27865
28001
  }
27866
28002
 
27867
28003
  // src/commands/review/submitBodyOnlyReview.ts
27868
- var MUTATION = `mutation($prId: ID!, $body: String) { addPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
28004
+ var MUTATION3 = `mutation($prId: ID!, $body: String) { addPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
27869
28005
  function submitBodyOnlyReview(body) {
27870
- runReviewSubmission(MUTATION, body);
28006
+ runReviewSubmission(MUTATION3, body);
27871
28007
  }
27872
28008
 
27873
28009
  // src/commands/review/submitPendingReview.ts
27874
- var MUTATION2 = `mutation($prId: ID!, $body: String) { submitPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
28010
+ var MUTATION4 = `mutation($prId: ID!, $body: String) { submitPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
27875
28011
  function submitPendingReview(body) {
27876
- runReviewSubmission(MUTATION2, body);
28012
+ runReviewSubmission(MUTATION4, body);
27877
28013
  }
27878
28014
 
27879
28015
  // src/commands/review/postAndMaybeSubmit.ts
@@ -27996,18 +28132,18 @@ function partitionFindingsByDiff(findings, index3) {
27996
28132
  }
27997
28133
 
27998
28134
  // src/commands/review/warnOutOfDiff.ts
27999
- import chalk200 from "chalk";
28135
+ import chalk202 from "chalk";
28000
28136
  function warnOutOfDiff(outOfDiff) {
28001
28137
  if (outOfDiff.length === 0) return;
28002
28138
  console.warn(
28003
- chalk200.yellow(
28139
+ chalk202.yellow(
28004
28140
  `Moved ${outOfDiff.length} finding(s) whose lines fall outside the PR diff into the review body (GitHub cannot anchor a comment on these):`
28005
28141
  )
28006
28142
  );
28007
28143
  for (const finding of outOfDiff) {
28008
28144
  const range = finding.startLine !== void 0 ? `${finding.startLine}-${finding.line}` : `${finding.line}`;
28009
28145
  console.warn(
28010
- ` ${chalk200.yellow("\xB7")} ${finding.title} ${chalk200.dim(
28146
+ ` ${chalk202.yellow("\xB7")} ${finding.title} ${chalk202.dim(
28011
28147
  `(${finding.file}:${range})`
28012
28148
  )}`
28013
28149
  );
@@ -28031,18 +28167,18 @@ function selectInDiffFindings(lineBound, prDiff) {
28031
28167
  }
28032
28168
 
28033
28169
  // src/commands/review/warnUnlocated.ts
28034
- import chalk201 from "chalk";
28170
+ import chalk203 from "chalk";
28035
28171
  function warnUnlocated(unlocated) {
28036
28172
  if (unlocated.length === 0) return;
28037
28173
  console.warn(
28038
- chalk201.yellow(
28174
+ chalk203.yellow(
28039
28175
  `Moved ${unlocated.length} finding(s) without a parseable file:line into the review body:`
28040
28176
  )
28041
28177
  );
28042
28178
  for (const finding of unlocated) {
28043
- const where = finding.location || chalk201.dim("missing");
28179
+ const where = finding.location || chalk203.dim("missing");
28044
28180
  console.warn(
28045
- ` ${chalk201.yellow("\xB7")} ${finding.title} ${chalk201.dim(`(${where})`)}`
28181
+ ` ${chalk203.yellow("\xB7")} ${finding.title} ${chalk203.dim(`(${where})`)}`
28046
28182
  );
28047
28183
  }
28048
28184
  }
@@ -29297,7 +29433,7 @@ function registerReview(program2) {
29297
29433
  }
29298
29434
 
29299
29435
  // src/commands/seq/seqAuth.ts
29300
- import chalk203 from "chalk";
29436
+ import chalk205 from "chalk";
29301
29437
 
29302
29438
  // src/commands/seq/loadConnections.ts
29303
29439
  function loadConnections2() {
@@ -29326,10 +29462,10 @@ function setDefaultConnection(name) {
29326
29462
  }
29327
29463
 
29328
29464
  // src/shared/assertUniqueName.ts
29329
- import chalk202 from "chalk";
29465
+ import chalk204 from "chalk";
29330
29466
  function assertUniqueName(existingNames, name) {
29331
29467
  if (existingNames.includes(name)) {
29332
- console.error(chalk202.red(`Connection "${name}" already exists.`));
29468
+ console.error(chalk204.red(`Connection "${name}" already exists.`));
29333
29469
  process.exit(1);
29334
29470
  }
29335
29471
  }
@@ -29347,16 +29483,16 @@ async function promptConnection2(existingNames) {
29347
29483
  var seqAuth = createConnectionAuth({
29348
29484
  load: loadConnections2,
29349
29485
  save: saveConnections2,
29350
- format: (c) => `${chalk203.bold(c.name)} ${c.url}`,
29486
+ format: (c) => `${chalk205.bold(c.name)} ${c.url}`,
29351
29487
  promptNew: promptConnection2,
29352
29488
  onFirst: (c) => setDefaultConnection(c.name)
29353
29489
  });
29354
29490
 
29355
29491
  // src/commands/seq/seqQuery.ts
29356
- import chalk207 from "chalk";
29492
+ import chalk209 from "chalk";
29357
29493
 
29358
29494
  // src/commands/seq/fetchSeq.ts
29359
- import chalk204 from "chalk";
29495
+ import chalk206 from "chalk";
29360
29496
  async function fetchSeq(conn, path80, params) {
29361
29497
  const url = `${conn.url}${path80}?${params}`;
29362
29498
  const response = await fetch(url, {
@@ -29367,7 +29503,7 @@ async function fetchSeq(conn, path80, params) {
29367
29503
  });
29368
29504
  if (!response.ok) {
29369
29505
  const body = await response.text();
29370
- console.error(chalk204.red(`Seq returned ${response.status}: ${body}`));
29506
+ console.error(chalk206.red(`Seq returned ${response.status}: ${body}`));
29371
29507
  process.exit(1);
29372
29508
  }
29373
29509
  return response;
@@ -29426,23 +29562,23 @@ async function fetchSeqEvents(conn, params) {
29426
29562
  }
29427
29563
 
29428
29564
  // src/commands/seq/formatEvent.ts
29429
- import chalk205 from "chalk";
29565
+ import chalk207 from "chalk";
29430
29566
  function levelColor(level) {
29431
29567
  switch (level) {
29432
29568
  case "Fatal":
29433
- return chalk205.bgRed.white;
29569
+ return chalk207.bgRed.white;
29434
29570
  case "Error":
29435
- return chalk205.red;
29571
+ return chalk207.red;
29436
29572
  case "Warning":
29437
- return chalk205.yellow;
29573
+ return chalk207.yellow;
29438
29574
  case "Information":
29439
- return chalk205.cyan;
29575
+ return chalk207.cyan;
29440
29576
  case "Debug":
29441
- return chalk205.gray;
29577
+ return chalk207.gray;
29442
29578
  case "Verbose":
29443
- return chalk205.dim;
29579
+ return chalk207.dim;
29444
29580
  default:
29445
- return chalk205.white;
29581
+ return chalk207.white;
29446
29582
  }
29447
29583
  }
29448
29584
  function levelAbbrev(level) {
@@ -29483,12 +29619,12 @@ function formatTimestamp(iso) {
29483
29619
  function formatEvent(event) {
29484
29620
  const color = levelColor(event.Level);
29485
29621
  const abbrev = levelAbbrev(event.Level);
29486
- const ts8 = chalk205.dim(formatTimestamp(event.Timestamp));
29622
+ const ts8 = chalk207.dim(formatTimestamp(event.Timestamp));
29487
29623
  const msg = renderMessage(event);
29488
29624
  const lines2 = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
29489
29625
  if (event.Exception) {
29490
29626
  for (const line of event.Exception.split("\n")) {
29491
- lines2.push(chalk205.red(` ${line}`));
29627
+ lines2.push(chalk207.red(` ${line}`));
29492
29628
  }
29493
29629
  }
29494
29630
  return lines2.join("\n");
@@ -29521,11 +29657,11 @@ function rejectTimestampFilter(filter) {
29521
29657
  }
29522
29658
 
29523
29659
  // src/shared/resolveNamedConnection.ts
29524
- import chalk206 from "chalk";
29660
+ import chalk208 from "chalk";
29525
29661
  function resolveNamedConnection(connections, requested, defaultName, kind, authCommand) {
29526
29662
  if (connections.length === 0) {
29527
29663
  console.error(
29528
- chalk206.red(
29664
+ chalk208.red(
29529
29665
  `No ${kind} connections configured. Run '${authCommand}' first.`
29530
29666
  )
29531
29667
  );
@@ -29534,7 +29670,7 @@ function resolveNamedConnection(connections, requested, defaultName, kind, authC
29534
29670
  const target = requested ?? defaultName ?? connections[0].name;
29535
29671
  const connection = connections.find((c) => c.name === target);
29536
29672
  if (!connection) {
29537
- console.error(chalk206.red(`${kind} connection "${target}" not found.`));
29673
+ console.error(chalk208.red(`${kind} connection "${target}" not found.`));
29538
29674
  process.exit(1);
29539
29675
  }
29540
29676
  return connection;
@@ -29563,7 +29699,7 @@ async function seqQuery(filter, options2) {
29563
29699
  new URLSearchParams({ filter, count: String(count8) })
29564
29700
  );
29565
29701
  if (events.length === 0) {
29566
- console.log(chalk207.yellow("No events found."));
29702
+ console.log(chalk209.yellow("No events found."));
29567
29703
  return;
29568
29704
  }
29569
29705
  if (options2.json) {
@@ -29574,11 +29710,11 @@ async function seqQuery(filter, options2) {
29574
29710
  for (const event of chronological) {
29575
29711
  console.log(formatEvent(event));
29576
29712
  }
29577
- console.log(chalk207.dim(`
29713
+ console.log(chalk209.dim(`
29578
29714
  ${events.length} events`));
29579
29715
  if (events.length >= count8) {
29580
29716
  console.log(
29581
- chalk207.yellow(
29717
+ chalk209.yellow(
29582
29718
  `Results limited to ${count8}. Use --count to retrieve more.`
29583
29719
  )
29584
29720
  );
@@ -29586,10 +29722,10 @@ ${events.length} events`));
29586
29722
  }
29587
29723
 
29588
29724
  // src/shared/setNamedDefaultConnection.ts
29589
- import chalk208 from "chalk";
29725
+ import chalk210 from "chalk";
29590
29726
  function setNamedDefaultConnection(connections, name, setDefault, kind) {
29591
29727
  if (!connections.find((c) => c.name === name)) {
29592
- console.error(chalk208.red(`Connection "${name}" not found.`));
29728
+ console.error(chalk210.red(`Connection "${name}" not found.`));
29593
29729
  process.exit(1);
29594
29730
  }
29595
29731
  setDefault(name);
@@ -29638,7 +29774,7 @@ function registerSignal(program2) {
29638
29774
  }
29639
29775
 
29640
29776
  // src/commands/sql/sqlAuth.ts
29641
- import chalk210 from "chalk";
29777
+ import chalk212 from "chalk";
29642
29778
 
29643
29779
  // src/commands/sql/loadConnections.ts
29644
29780
  function loadConnections3() {
@@ -29667,7 +29803,7 @@ function setDefaultConnection2(name) {
29667
29803
  }
29668
29804
 
29669
29805
  // src/commands/sql/promptConnection.ts
29670
- import chalk209 from "chalk";
29806
+ import chalk211 from "chalk";
29671
29807
  async function promptConnection3(existingNames) {
29672
29808
  const name = await promptInput("name", "Connection name:", "default");
29673
29809
  assertUniqueName(existingNames, name);
@@ -29675,7 +29811,7 @@ async function promptConnection3(existingNames) {
29675
29811
  const portStr = await promptInput("port", "Port:", "1433");
29676
29812
  const port = Number.parseInt(portStr, 10);
29677
29813
  if (!Number.isFinite(port)) {
29678
- console.error(chalk209.red(`Invalid port "${portStr}".`));
29814
+ console.error(chalk211.red(`Invalid port "${portStr}".`));
29679
29815
  process.exit(1);
29680
29816
  }
29681
29817
  const user = await promptInput("user", "User:");
@@ -29688,13 +29824,13 @@ async function promptConnection3(existingNames) {
29688
29824
  var sqlAuth = createConnectionAuth({
29689
29825
  load: loadConnections3,
29690
29826
  save: saveConnections3,
29691
- format: (c) => `${chalk210.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
29827
+ format: (c) => `${chalk212.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
29692
29828
  promptNew: promptConnection3,
29693
29829
  onFirst: (c) => setDefaultConnection2(c.name)
29694
29830
  });
29695
29831
 
29696
29832
  // src/commands/sql/printTable.ts
29697
- import chalk211 from "chalk";
29833
+ import chalk213 from "chalk";
29698
29834
  function formatCell(value) {
29699
29835
  if (value === null || value === void 0) return "";
29700
29836
  if (value instanceof Date) return value.toISOString();
@@ -29703,7 +29839,7 @@ function formatCell(value) {
29703
29839
  }
29704
29840
  function printTable(rows) {
29705
29841
  if (rows.length === 0) {
29706
- console.log(chalk211.yellow("(no rows)"));
29842
+ console.log(chalk213.yellow("(no rows)"));
29707
29843
  return;
29708
29844
  }
29709
29845
  const columns = Object.keys(rows[0]);
@@ -29711,13 +29847,13 @@ function printTable(rows) {
29711
29847
  (col) => Math.max(col.length, ...rows.map((r) => formatCell(r[col]).length))
29712
29848
  );
29713
29849
  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)));
29850
+ console.log(chalk213.dim(header));
29851
+ console.log(chalk213.dim("-".repeat(header.length)));
29716
29852
  for (const row of rows) {
29717
29853
  const line = columns.map((c, i) => formatCell(row[c]).padEnd(widths[i])).join(" ");
29718
29854
  console.log(line);
29719
29855
  }
29720
- console.log(chalk211.dim(`
29856
+ console.log(chalk213.dim(`
29721
29857
  ${rows.length} row${rows.length === 1 ? "" : "s"}`));
29722
29858
  }
29723
29859
 
@@ -29777,7 +29913,7 @@ async function sqlColumns(table, connectionName) {
29777
29913
  }
29778
29914
 
29779
29915
  // src/commands/sql/sqlMutate.ts
29780
- import chalk212 from "chalk";
29916
+ import chalk214 from "chalk";
29781
29917
 
29782
29918
  // src/commands/sql/isMutation.ts
29783
29919
  var MUTATION_KEYWORDS = [
@@ -29811,7 +29947,7 @@ function isMutation(sql25) {
29811
29947
  async function sqlMutate(query, connectionName) {
29812
29948
  if (!isMutation(query)) {
29813
29949
  console.error(
29814
- chalk212.red(
29950
+ chalk214.red(
29815
29951
  "assist sql mutate refuses non-mutating statements. Use `assist sql query` instead."
29816
29952
  )
29817
29953
  );
@@ -29821,18 +29957,18 @@ async function sqlMutate(query, connectionName) {
29821
29957
  const pool = await sqlConnect(conn);
29822
29958
  try {
29823
29959
  const result = await pool.request().query(query);
29824
- console.log(chalk212.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
29960
+ console.log(chalk214.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
29825
29961
  } finally {
29826
29962
  await pool.close();
29827
29963
  }
29828
29964
  }
29829
29965
 
29830
29966
  // src/commands/sql/sqlQuery.ts
29831
- import chalk213 from "chalk";
29967
+ import chalk215 from "chalk";
29832
29968
  async function sqlQuery(query, connectionName) {
29833
29969
  if (isMutation(query)) {
29834
29970
  console.error(
29835
- chalk213.red(
29971
+ chalk215.red(
29836
29972
  "assist sql query refuses mutating statements. Use `assist sql mutate` instead."
29837
29973
  )
29838
29974
  );
@@ -29847,7 +29983,7 @@ async function sqlQuery(query, connectionName) {
29847
29983
  printTable(rows);
29848
29984
  } else {
29849
29985
  console.log(
29850
- chalk213.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
29986
+ chalk215.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
29851
29987
  );
29852
29988
  }
29853
29989
  } finally {
@@ -29992,7 +30128,7 @@ function reportPrune(label2, result, force) {
29992
30128
  // src/commands/sync/syncClaudeMd.ts
29993
30129
  import * as fs41 from "fs";
29994
30130
  import * as path66 from "path";
29995
- import chalk214 from "chalk";
30131
+ import chalk216 from "chalk";
29996
30132
  async function syncClaudeMd(claudeDir, targetBase, options2) {
29997
30133
  const source = path66.join(claudeDir, "CLAUDE.md");
29998
30134
  const target = path66.join(targetBase, "CLAUDE.md");
@@ -30001,14 +30137,14 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
30001
30137
  const targetContent = fs41.readFileSync(target, "utf8");
30002
30138
  if (sourceContent !== targetContent) {
30003
30139
  console.log(
30004
- chalk214.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
30140
+ chalk216.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
30005
30141
  );
30006
30142
  console.log();
30007
30143
  printDiff(targetContent, sourceContent);
30008
30144
  if (!options2?.yes) {
30009
30145
  printAutoConfirmHint();
30010
30146
  const confirm = await promptConfirm(
30011
- chalk214.red("Overwrite existing CLAUDE.md?"),
30147
+ chalk216.red("Overwrite existing CLAUDE.md?"),
30012
30148
  false
30013
30149
  );
30014
30150
  if (!confirm) {
@@ -30241,7 +30377,7 @@ function syncPi(claudeDir, options2) {
30241
30377
  // src/commands/sync/syncSettings.ts
30242
30378
  import * as fs47 from "fs";
30243
30379
  import * as path73 from "path";
30244
- import chalk215 from "chalk";
30380
+ import chalk217 from "chalk";
30245
30381
  async function syncSettings(claudeDir, targetBase, options2) {
30246
30382
  const source = path73.join(claudeDir, "settings.json");
30247
30383
  const target = path73.join(targetBase, "settings.json");
@@ -30260,7 +30396,7 @@ async function syncSettings(claudeDir, targetBase, options2) {
30260
30396
  if (mergedContent !== normalizedTarget) {
30261
30397
  if (!options2?.yes) {
30262
30398
  console.log(
30263
- chalk215.yellow(
30399
+ chalk217.yellow(
30264
30400
  "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
30265
30401
  )
30266
30402
  );
@@ -30268,7 +30404,7 @@ async function syncSettings(claudeDir, targetBase, options2) {
30268
30404
  printDiff(targetContent, mergedContent);
30269
30405
  printAutoConfirmHint();
30270
30406
  const confirm = await promptConfirm(
30271
- chalk215.red("Overwrite existing settings.json?"),
30407
+ chalk217.red("Overwrite existing settings.json?"),
30272
30408
  false
30273
30409
  );
30274
30410
  if (!confirm) {
@@ -31695,7 +31831,7 @@ function registerWatch(program2) {
31695
31831
 
31696
31832
  // src/commands/roam/auth.ts
31697
31833
  import { randomBytes } from "crypto";
31698
- import chalk216 from "chalk";
31834
+ import chalk218 from "chalk";
31699
31835
 
31700
31836
  // src/commands/roam/waitForCallback.ts
31701
31837
  import { createServer as createServer3 } from "http";
@@ -31826,13 +31962,13 @@ async function auth() {
31826
31962
  saveGlobalConfig(config);
31827
31963
  const state = randomBytes(16).toString("hex");
31828
31964
  console.log(
31829
- chalk216.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
31965
+ chalk218.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
31830
31966
  );
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..."));
31967
+ console.log(chalk218.white("http://localhost:14523/callback\n"));
31968
+ console.log(chalk218.blue("Opening browser for authorization..."));
31969
+ console.log(chalk218.dim("Waiting for authorization callback..."));
31834
31970
  const { code, redirectUri } = await authorizeInBrowser(clientId, state);
31835
- console.log(chalk216.dim("Exchanging code for tokens..."));
31971
+ console.log(chalk218.dim("Exchanging code for tokens..."));
31836
31972
  const tokens = await exchangeToken({
31837
31973
  code,
31838
31974
  clientId,
@@ -31848,7 +31984,7 @@ async function auth() {
31848
31984
  };
31849
31985
  saveGlobalConfig(config);
31850
31986
  console.log(
31851
- chalk216.green("Roam credentials and tokens saved to ~/.assist.yml")
31987
+ chalk218.green("Roam credentials and tokens saved to ~/.assist.yml")
31852
31988
  );
31853
31989
  }
31854
31990
 
@@ -32199,7 +32335,7 @@ import { execSync as execSync60 } from "child_process";
32199
32335
  import { existsSync as existsSync72, mkdirSync as mkdirSync31, unlinkSync as unlinkSync22, writeFileSync as writeFileSync46 } from "fs";
32200
32336
  import { tmpdir as tmpdir8 } from "os";
32201
32337
  import { join as join89, resolve as resolve20 } from "path";
32202
- import chalk217 from "chalk";
32338
+ import chalk219 from "chalk";
32203
32339
 
32204
32340
  // src/commands/screenshot/captureWindowPs1.ts
32205
32341
  var captureWindowPs1 = `
@@ -32350,13 +32486,13 @@ function screenshot(processName) {
32350
32486
  const config = loadConfig();
32351
32487
  const outputDir = resolve20(config.screenshot.outputDir);
32352
32488
  const outputPath = buildOutputPath(outputDir, processName);
32353
- console.log(chalk217.gray(`Capturing window for process "${processName}" ...`));
32489
+ console.log(chalk219.gray(`Capturing window for process "${processName}" ...`));
32354
32490
  try {
32355
32491
  runPowerShellScript(processName, outputPath);
32356
- console.log(chalk217.green(`Screenshot saved: ${outputPath}`));
32492
+ console.log(chalk219.green(`Screenshot saved: ${outputPath}`));
32357
32493
  } catch (error) {
32358
32494
  const msg = error instanceof Error ? error.message : String(error);
32359
- console.error(chalk217.red(`Failed to capture screenshot: ${msg}`));
32495
+ console.error(chalk219.red(`Failed to capture screenshot: ${msg}`));
32360
32496
  process.exit(1);
32361
32497
  }
32362
32498
  }
@@ -38133,7 +38269,7 @@ function registerSetStatusCommand(cmd) {
38133
38269
 
38134
38270
  // src/commands/sessions/summarise/index.ts
38135
38271
  import * as fs56 from "fs";
38136
- import chalk218 from "chalk";
38272
+ import chalk220 from "chalk";
38137
38273
 
38138
38274
  // src/commands/sessions/summarise/shared.ts
38139
38275
  import * as fs55 from "fs";
@@ -38192,22 +38328,22 @@ ${firstMessage}`);
38192
38328
  async function summarise2(options2) {
38193
38329
  const files = await discoverSessionFiles();
38194
38330
  if (files.length === 0) {
38195
- console.log(chalk218.yellow("No sessions found."));
38331
+ console.log(chalk220.yellow("No sessions found."));
38196
38332
  return;
38197
38333
  }
38198
38334
  const toProcess = selectCandidates(files, options2);
38199
38335
  if (toProcess.length === 0) {
38200
- console.log(chalk218.green("All sessions already summarised."));
38336
+ console.log(chalk220.green("All sessions already summarised."));
38201
38337
  return;
38202
38338
  }
38203
38339
  console.log(
38204
- chalk218.cyan(
38340
+ chalk220.cyan(
38205
38341
  `Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
38206
38342
  )
38207
38343
  );
38208
38344
  const { succeeded, failed: failed2 } = processSessions(toProcess);
38209
38345
  console.log(
38210
- chalk218.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk218.yellow(`, ${failed2} skipped`) : "")
38346
+ chalk220.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk220.yellow(`, ${failed2} skipped`) : "")
38211
38347
  );
38212
38348
  }
38213
38349
  function selectCandidates(files, options2) {
@@ -38227,16 +38363,16 @@ function processSessions(files) {
38227
38363
  let failed2 = 0;
38228
38364
  for (let i = 0; i < files.length; i++) {
38229
38365
  const file = files[i];
38230
- process.stdout.write(chalk218.dim(` [${i + 1}/${files.length}] `));
38366
+ process.stdout.write(chalk220.dim(` [${i + 1}/${files.length}] `));
38231
38367
  const summary = summariseSession(file);
38232
38368
  if (summary) {
38233
38369
  writeSummary(file, summary);
38234
38370
  succeeded++;
38235
- process.stdout.write(`${chalk218.green("\u2713")} ${summary}
38371
+ process.stdout.write(`${chalk220.green("\u2713")} ${summary}
38236
38372
  `);
38237
38373
  } else {
38238
38374
  failed2++;
38239
- process.stdout.write(` ${chalk218.yellow("skip")}
38375
+ process.stdout.write(` ${chalk220.yellow("skip")}
38240
38376
  `);
38241
38377
  }
38242
38378
  }
@@ -38257,7 +38393,7 @@ function registerSessions(program2) {
38257
38393
  }
38258
38394
 
38259
38395
  // src/commands/statusLine.ts
38260
- import chalk220 from "chalk";
38396
+ import chalk222 from "chalk";
38261
38397
 
38262
38398
  // src/shared/contextLevel.ts
38263
38399
  function contextLevel(pct) {
@@ -38267,7 +38403,7 @@ function contextLevel(pct) {
38267
38403
  }
38268
38404
 
38269
38405
  // src/commands/buildLimitsSegment.ts
38270
- import chalk219 from "chalk";
38406
+ import chalk221 from "chalk";
38271
38407
 
38272
38408
  // src/shared/rateLimitLevel.ts
38273
38409
  var FIVE_HOUR_SECONDS = 5 * 3600;
@@ -38305,9 +38441,9 @@ function rateLimitLevel(pct, resetsAt, windowSeconds, now) {
38305
38441
 
38306
38442
  // src/commands/buildLimitsSegment.ts
38307
38443
  var LEVEL_COLOR = {
38308
- ok: chalk219.green,
38309
- warn: chalk219.yellow,
38310
- over: chalk219.red
38444
+ ok: chalk221.green,
38445
+ warn: chalk221.yellow,
38446
+ over: chalk221.red
38311
38447
  };
38312
38448
  function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel, now) {
38313
38449
  const level = rateLimitLevel(pct, resetsAt, windowSeconds, now);
@@ -38403,7 +38539,7 @@ async function relayUsage(claudeSessionId, transcriptPath2, usedPct) {
38403
38539
  }
38404
38540
 
38405
38541
  // src/commands/statusLine.ts
38406
- chalk220.level = 3;
38542
+ chalk222.level = 3;
38407
38543
  function formatNumber(num) {
38408
38544
  return num.toLocaleString("en-US");
38409
38545
  }
@@ -38411,9 +38547,9 @@ function colorizePercent(pct) {
38411
38547
  const label2 = `${Math.round(pct)}%`;
38412
38548
  switch (contextLevel(pct)) {
38413
38549
  case "red":
38414
- return chalk220.red(label2);
38550
+ return chalk222.red(label2);
38415
38551
  case "yellow":
38416
- return chalk220.yellow(label2);
38552
+ return chalk222.yellow(label2);
38417
38553
  default:
38418
38554
  return label2;
38419
38555
  }
@@ -38426,7 +38562,7 @@ async function statusLine() {
38426
38562
  const usedPct = data.context_window.used_percentage ?? 0;
38427
38563
  const dir = data.workspace?.current_dir ?? data.cwd;
38428
38564
  const branch2 = dir ? readGitBranch(toGitCwd(dir)) : null;
38429
- const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${chalk220.cyan(branch2)} | ` : "";
38565
+ const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${chalk222.cyan(branch2)} | ` : "";
38430
38566
  console.log(
38431
38567
  `${branchSegment}${model} | Tokens - ${formatNumber(totalIn)} \u2191 : ${formatNumber(totalOut)} \u2193 | Context - ${colorizePercent(usedPct)}${buildLimitsSegment(data.rate_limits)}`
38432
38568
  );
@@ -38496,10 +38632,10 @@ async function update2() {
38496
38632
  }
38497
38633
 
38498
38634
  // src/reportCliError.ts
38499
- import chalk221 from "chalk";
38635
+ import chalk223 from "chalk";
38500
38636
  function reportCliError(error) {
38501
38637
  if (error instanceof InvalidItemIdError || error instanceof AmbiguousRepoConfigError || error instanceof UnknownRepoConfigError || error instanceof MissingRunCwdError || error instanceof MiroExtractError) {
38502
- console.error(chalk221.red(error.message));
38638
+ console.error(chalk223.red(error.message));
38503
38639
  } else {
38504
38640
  console.error(error);
38505
38641
  }