@staff0rd/assist 0.576.0 → 0.578.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/commands/sessions/web/bundle.js +1 -1
- package/dist/index.js +1021 -704
- package/package.json +1 -1
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.
|
|
9
|
+
version: "0.578.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -14914,12 +14914,12 @@ async function link(fromId, toId, opts) {
|
|
|
14914
14914
|
const { orm } = await getReady();
|
|
14915
14915
|
const fromItem = await loadItem(orm, fromNum);
|
|
14916
14916
|
if (!fromItem) return void fail4(`Item ${from} not found.`);
|
|
14917
|
-
const
|
|
14918
|
-
if (!
|
|
14917
|
+
const toItem2 = await loadItem(orm, toNum);
|
|
14918
|
+
if (!toItem2) return void fail4(`Item ${to} not found.`);
|
|
14919
14919
|
if (!validateLinkTarget(fromItem, fromNum, toNum, linkType)) return;
|
|
14920
14920
|
if (await createsCycle(orm, linkType, fromNum, toNum)) return;
|
|
14921
14921
|
await orm.insert(links).values({ itemId: fromNum, type: linkType, targetId: toNum });
|
|
14922
|
-
console.log(chalk85.green(`Linked ${from} ${linkType} ${to} (${
|
|
14922
|
+
console.log(chalk85.green(`Linked ${from} ${linkType} ${to} (${toItem2.name})`));
|
|
14923
14923
|
}
|
|
14924
14924
|
|
|
14925
14925
|
// src/commands/backlog/unlink.ts
|
|
@@ -16820,6 +16820,12 @@ function findBuiltinDenyRaw(rawCommand) {
|
|
|
16820
16820
|
// src/shared/isApprovedRead.ts
|
|
16821
16821
|
import { resolve as resolve13, sep } from "path";
|
|
16822
16822
|
|
|
16823
|
+
// src/shared/appliesFixStructure.ts
|
|
16824
|
+
var APPLY_RE = /^assist\s+github\s+issue\s+fix-structure\b.*\s--apply\b/;
|
|
16825
|
+
function appliesFixStructure(command) {
|
|
16826
|
+
return APPLY_RE.test(command);
|
|
16827
|
+
}
|
|
16828
|
+
|
|
16823
16829
|
// src/shared/tokenize.ts
|
|
16824
16830
|
function tokenize(command) {
|
|
16825
16831
|
const tokens = [];
|
|
@@ -17046,6 +17052,7 @@ function isApprovedRead(command, toolName = "Bash") {
|
|
|
17046
17052
|
if (isCdToCwd(command)) return "cd to current directory";
|
|
17047
17053
|
const cdRead = isCdToReadAllowedDir(command);
|
|
17048
17054
|
if (cdRead) return cdRead;
|
|
17055
|
+
if (appliesFixStructure(command)) return void 0;
|
|
17049
17056
|
const matchedRead = findCliRead(command);
|
|
17050
17057
|
if (matchedRead) return `Read-only CLI command: ${matchedRead}`;
|
|
17051
17058
|
const matchedWrite = findCliWrite(command);
|
|
@@ -20695,309 +20702,178 @@ function parseTopCount(value) {
|
|
|
20695
20702
|
return Number.parseInt(value, 10);
|
|
20696
20703
|
}
|
|
20697
20704
|
|
|
20698
|
-
// src/commands/github/issue/
|
|
20699
|
-
import
|
|
20705
|
+
// src/commands/github/issue/fixStructure/applyAndVerifySubtree.ts
|
|
20706
|
+
import chalk163 from "chalk";
|
|
20700
20707
|
|
|
20701
|
-
// src/
|
|
20702
|
-
|
|
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/
|
|
20727
|
-
import {
|
|
20728
|
-
|
|
20729
|
-
const
|
|
20730
|
-
|
|
20731
|
-
|
|
20732
|
-
|
|
20733
|
-
|
|
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/
|
|
20742
|
-
var
|
|
20743
|
-
|
|
20744
|
-
|
|
20745
|
-
|
|
20746
|
-
|
|
20747
|
-
|
|
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/
|
|
20768
|
-
|
|
20769
|
-
|
|
20770
|
-
|
|
20771
|
-
|
|
20772
|
-
|
|
20773
|
-
|
|
20774
|
-
|
|
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/
|
|
20786
|
-
|
|
20787
|
-
|
|
20788
|
-
|
|
20789
|
-
|
|
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
|
-
|
|
20751
|
+
writeSync2(1, text18);
|
|
20803
20752
|
} catch {
|
|
20804
|
-
process.
|
|
20753
|
+
process.stdout.write(text18);
|
|
20805
20754
|
}
|
|
20806
20755
|
}
|
|
20807
20756
|
|
|
20808
|
-
// src/commands/
|
|
20809
|
-
function
|
|
20810
|
-
|
|
20811
|
-
}
|
|
20812
|
-
|
|
20813
|
-
|
|
20814
|
-
|
|
20815
|
-
|
|
20816
|
-
|
|
20817
|
-
|
|
20818
|
-
|
|
20819
|
-
|
|
20820
|
-
|
|
20821
|
-
|
|
20822
|
-
|
|
20823
|
-
|
|
20824
|
-
|
|
20825
|
-
|
|
20826
|
-
|
|
20827
|
-
|
|
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/
|
|
20840
|
-
|
|
20841
|
-
|
|
20842
|
-
|
|
20843
|
-
|
|
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
|
-
|
|
20868
|
-
|
|
20869
|
-
|
|
20870
|
-
|
|
20871
|
-
|
|
20872
|
-
|
|
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/
|
|
20877
|
-
|
|
20878
|
-
|
|
20879
|
-
const
|
|
20880
|
-
|
|
20881
|
-
|
|
20882
|
-
|
|
20883
|
-
|
|
20884
|
-
|
|
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/
|
|
20891
|
-
|
|
20892
|
-
|
|
20893
|
-
|
|
20894
|
-
|
|
20895
|
-
|
|
20896
|
-
|
|
20897
|
-
|
|
20898
|
-
|
|
20899
|
-
|
|
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/
|
|
20917
|
-
|
|
20918
|
-
|
|
20919
|
-
const
|
|
20920
|
-
|
|
20921
|
-
|
|
20922
|
-
|
|
20923
|
-
|
|
20924
|
-
|
|
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
|
-
|
|
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
|
-
|
|
20937
|
-
|
|
20938
|
-
|
|
20939
|
-
|
|
20940
|
-
|
|
20941
|
-
|
|
20942
|
-
|
|
20943
|
-
|
|
20944
|
-
|
|
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/
|
|
20964
|
-
|
|
20965
|
-
|
|
20966
|
-
|
|
20967
|
-
|
|
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
|
-
|
|
20976
|
-
|
|
20977
|
-
|
|
20978
|
-
|
|
20979
|
-
|
|
20980
|
-
|
|
20981
|
-
|
|
20982
|
-
|
|
20983
|
-
|
|
20984
|
-
|
|
20985
|
-
|
|
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
|
-
|
|
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/
|
|
21099
|
-
|
|
21100
|
-
|
|
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
|
-
|
|
21113
|
-
|
|
21114
|
-
|
|
21115
|
-
|
|
21116
|
-
|
|
21117
|
-
|
|
21118
|
-
|
|
21119
|
-
|
|
21120
|
-
|
|
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
|
-
|
|
21134
|
-
|
|
21135
|
-
|
|
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/
|
|
21150
|
-
|
|
21151
|
-
|
|
21152
|
-
|
|
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
|
-
|
|
21156
|
-
|
|
21157
|
-
|
|
21158
|
-
|
|
21159
|
-
|
|
21160
|
-
|
|
21161
|
-
|
|
21162
|
-
|
|
21163
|
-
|
|
21164
|
-
|
|
21165
|
-
|
|
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
|
|
21039
|
+
import chalk164 from "chalk";
|
|
21173
21040
|
function annotate(entry) {
|
|
21174
21041
|
const notes = [];
|
|
21175
21042
|
if (entry.level === null) {
|
|
21176
|
-
notes.push(
|
|
21043
|
+
notes.push(chalk164.red("deeper than the leaf level"));
|
|
21177
21044
|
} else if (entry.typeChange) {
|
|
21178
21045
|
notes.push(
|
|
21179
|
-
|
|
21046
|
+
chalk164.yellow(
|
|
21180
21047
|
`${entry.typeChange.from ?? "no type"} -> ${entry.typeChange.to}`
|
|
21181
21048
|
)
|
|
21182
21049
|
);
|
|
21183
21050
|
} else {
|
|
21184
|
-
notes.push(
|
|
21051
|
+
notes.push(chalk164.dim(entry.issue.typeName ?? "no type"));
|
|
21185
21052
|
}
|
|
21186
21053
|
for (const label2 of entry.labelRemovals) {
|
|
21187
|
-
notes.push(
|
|
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
|
-
|
|
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 =
|
|
21199
|
-
|
|
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
|
-
|
|
21071
|
+
writeLineNow(chalk164.green("Nothing to change"));
|
|
21213
21072
|
return;
|
|
21214
21073
|
}
|
|
21215
|
-
|
|
21074
|
+
writeLineNow(
|
|
21216
21075
|
`${formatCount(plan2.typeChangeCount, "type change")}, ${formatCount(plan2.labelRemovalCount, "label removal")} planned`
|
|
21217
21076
|
);
|
|
21218
|
-
|
|
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
|
|
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(
|
|
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
|
|
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
|
-
|
|
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("
|
|
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
|
-
|
|
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/
|
|
21414
|
-
|
|
21415
|
-
|
|
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
|
-
|
|
21434
|
-
|
|
21435
|
-
|
|
21436
|
-
|
|
21437
|
-
|
|
21438
|
-
|
|
21439
|
-
)
|
|
21440
|
-
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
22766
|
+
import chalk169 from "chalk";
|
|
22631
22767
|
|
|
22632
22768
|
// src/commands/mermaid/renderBlock.ts
|
|
22633
|
-
import
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
22803
|
+
chalk169.gray(
|
|
22668
22804
|
`${file} \u2014 rendering diagram ${onlyIndex} of ${blocks.length}`
|
|
22669
22805
|
)
|
|
22670
22806
|
);
|
|
22671
22807
|
} else {
|
|
22672
|
-
console.log(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
22843
|
+
console.log(chalk170.gray("No markdown files found in current directory."));
|
|
22708
22844
|
return;
|
|
22709
22845
|
}
|
|
22710
22846
|
for (const f of files) {
|
|
@@ -22727,11 +22863,191 @@ function registerMermaid(program2) {
|
|
|
22727
22863
|
configHelp(cmd, mermaidConfigHelp);
|
|
22728
22864
|
}
|
|
22729
22865
|
|
|
22866
|
+
// src/commands/miro/runExtract.ts
|
|
22867
|
+
import { stringify } from "yaml";
|
|
22868
|
+
|
|
22869
|
+
// src/commands/miro/MiroExtractError.ts
|
|
22870
|
+
var MiroExtractError = class extends Error {
|
|
22871
|
+
constructor(message3) {
|
|
22872
|
+
super(message3);
|
|
22873
|
+
this.name = "MiroExtractError";
|
|
22874
|
+
}
|
|
22875
|
+
};
|
|
22876
|
+
|
|
22877
|
+
// src/commands/miro/stripHtml.ts
|
|
22878
|
+
var namedEntities = {
|
|
22879
|
+
amp: "&",
|
|
22880
|
+
apos: "'",
|
|
22881
|
+
gt: ">",
|
|
22882
|
+
lt: "<",
|
|
22883
|
+
nbsp: " ",
|
|
22884
|
+
quot: '"'
|
|
22885
|
+
};
|
|
22886
|
+
function decodeEntity(_match, entity) {
|
|
22887
|
+
if (entity.startsWith("#")) {
|
|
22888
|
+
const code = entity.startsWith("#x") || entity.startsWith("#X") ? Number.parseInt(entity.slice(2), 16) : Number.parseInt(entity.slice(1), 10);
|
|
22889
|
+
return Number.isNaN(code) ? _match : String.fromCodePoint(code);
|
|
22890
|
+
}
|
|
22891
|
+
return namedEntities[entity.toLowerCase()] ?? _match;
|
|
22892
|
+
}
|
|
22893
|
+
function stripHtml2(content) {
|
|
22894
|
+
return content.replace(/<br\s*\/?>/gi, " ").replace(/<\/(?:p|div|li|h[1-6])>/gi, " ").replace(/<[^>]*>/g, "").replace(/&(#[0-9a-f]+|[a-z]+);/gi, decodeEntity).replace(/\s+/g, " ").trim();
|
|
22895
|
+
}
|
|
22896
|
+
|
|
22897
|
+
// src/commands/miro/normaliseItems.ts
|
|
22898
|
+
var frameCoordinates = "parent_top_left";
|
|
22899
|
+
function describe4(item) {
|
|
22900
|
+
return ` ${item.id ?? "(no id)"} (${item.type ?? "unknown type"}): relativeTo=${item.position?.relativeTo ?? "missing"}`;
|
|
22901
|
+
}
|
|
22902
|
+
function coordinateSpaceError(rejected) {
|
|
22903
|
+
return new MiroExtractError(
|
|
22904
|
+
`${rejected.length} item(s) are not in frame coordinates (position.relativeTo must be "${frameCoordinates}"):
|
|
22905
|
+
${rejected.slice(0, 5).map(describe4).join(
|
|
22906
|
+
"\n"
|
|
22907
|
+
)}
|
|
22908
|
+
|
|
22909
|
+
Dump the frame with board_list_items using ?moveToWidget=<frame id> so every item shares one coordinate space.`
|
|
22910
|
+
);
|
|
22911
|
+
}
|
|
22912
|
+
function toItem(item) {
|
|
22913
|
+
const halfWidth = (item.geometry?.width ?? 0) / 2;
|
|
22914
|
+
const halfHeight = (item.geometry?.height ?? 0) / 2;
|
|
22915
|
+
const x = item.position?.x ?? 0;
|
|
22916
|
+
const y = item.position?.y ?? 0;
|
|
22917
|
+
return {
|
|
22918
|
+
id: item.id ?? "",
|
|
22919
|
+
type: item.type ?? "",
|
|
22920
|
+
text: stripHtml2(item.data?.content ?? ""),
|
|
22921
|
+
left: x - halfWidth,
|
|
22922
|
+
top: y - halfHeight,
|
|
22923
|
+
right: x + halfWidth,
|
|
22924
|
+
bottom: y + halfHeight
|
|
22925
|
+
};
|
|
22926
|
+
}
|
|
22927
|
+
function normaliseItems(items2) {
|
|
22928
|
+
const rejected = items2.filter(
|
|
22929
|
+
(item) => item.position?.relativeTo !== frameCoordinates
|
|
22930
|
+
);
|
|
22931
|
+
if (rejected.length > 0) throw coordinateSpaceError(rejected);
|
|
22932
|
+
return items2.map(toItem);
|
|
22933
|
+
}
|
|
22934
|
+
|
|
22935
|
+
// src/commands/miro/parseAnchorId.ts
|
|
22936
|
+
function parseAnchorId(value) {
|
|
22937
|
+
const trimmed = value.trim();
|
|
22938
|
+
const link3 = /[?&]moveToWidget=([^&#]+)/.exec(trimmed);
|
|
22939
|
+
return link3 ? decodeURIComponent(link3[1]).trim() : trimmed;
|
|
22940
|
+
}
|
|
22941
|
+
|
|
22942
|
+
// src/commands/miro/readMiroItems.ts
|
|
22943
|
+
import { readFileSync as readFileSync40 } from "fs";
|
|
22944
|
+
function tryParse(text18) {
|
|
22945
|
+
try {
|
|
22946
|
+
return JSON.parse(text18);
|
|
22947
|
+
} catch {
|
|
22948
|
+
return void 0;
|
|
22949
|
+
}
|
|
22950
|
+
}
|
|
22951
|
+
function toPage(value) {
|
|
22952
|
+
const record = value ?? {};
|
|
22953
|
+
if (Array.isArray(record.data)) return { data: record.data };
|
|
22954
|
+
return record.id ? { data: [record] } : {};
|
|
22955
|
+
}
|
|
22956
|
+
function parseJsonLines(raw, file) {
|
|
22957
|
+
return raw.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => {
|
|
22958
|
+
const parsed = tryParse(line);
|
|
22959
|
+
if (parsed === void 0)
|
|
22960
|
+
throw new MiroExtractError(
|
|
22961
|
+
`${file} is not valid JSON or JSON lines. Save the raw board_list_items response pages without editing them.`
|
|
22962
|
+
);
|
|
22963
|
+
return toPage(parsed);
|
|
22964
|
+
});
|
|
22965
|
+
}
|
|
22966
|
+
function parsePages(raw, file) {
|
|
22967
|
+
const parsed = tryParse(raw);
|
|
22968
|
+
if (parsed === void 0) return parseJsonLines(raw, file);
|
|
22969
|
+
return Array.isArray(parsed) ? parsed.map(toPage) : [toPage(parsed)];
|
|
22970
|
+
}
|
|
22971
|
+
function readMiroItems(file) {
|
|
22972
|
+
const items2 = parsePages(readFileSync40(file, "utf8"), file).flatMap(
|
|
22973
|
+
(page) => page.data ?? []
|
|
22974
|
+
);
|
|
22975
|
+
if (items2.length === 0)
|
|
22976
|
+
throw new MiroExtractError(
|
|
22977
|
+
`No board items found in ${file}. Dump the frame with board_list_items, paging until has_more is false.`
|
|
22978
|
+
);
|
|
22979
|
+
return items2;
|
|
22980
|
+
}
|
|
22981
|
+
|
|
22982
|
+
// src/commands/miro/selectBoxes.ts
|
|
22983
|
+
var boxTypes = /* @__PURE__ */ new Set(["shape", "sticky_note"]);
|
|
22984
|
+
function findAnchor(items2, id) {
|
|
22985
|
+
const anchor = items2.find((item) => item.id === id);
|
|
22986
|
+
if (!anchor)
|
|
22987
|
+
throw new MiroExtractError(
|
|
22988
|
+
`No item with id ${id} in the supplied items. Re-dump the frame so the anchor is included, then try again.`
|
|
22989
|
+
);
|
|
22990
|
+
return anchor;
|
|
22991
|
+
}
|
|
22992
|
+
function isBox(item) {
|
|
22993
|
+
return boxTypes.has(item.type) && item.text.length > 0;
|
|
22994
|
+
}
|
|
22995
|
+
function centreInside(rect, item) {
|
|
22996
|
+
const x = (item.left + item.right) / 2;
|
|
22997
|
+
const y = (item.top + item.bottom) / 2;
|
|
22998
|
+
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
|
|
22999
|
+
}
|
|
23000
|
+
function selectBoxes(items2, topLeftId, bottomRightId) {
|
|
23001
|
+
const topLeft = findAnchor(items2, topLeftId);
|
|
23002
|
+
const bottomRight = findAnchor(items2, bottomRightId);
|
|
23003
|
+
const rect = {
|
|
23004
|
+
left: topLeft.left,
|
|
23005
|
+
top: topLeft.top,
|
|
23006
|
+
right: bottomRight.right,
|
|
23007
|
+
bottom: bottomRight.bottom
|
|
23008
|
+
};
|
|
23009
|
+
return items2.filter((item) => isBox(item) && centreInside(rect, item)).sort((a, b) => a.left - b.left || a.top - b.top);
|
|
23010
|
+
}
|
|
23011
|
+
|
|
23012
|
+
// src/commands/miro/runExtract.ts
|
|
23013
|
+
function requireItems(file) {
|
|
23014
|
+
if (!file)
|
|
23015
|
+
throw new MiroExtractError(
|
|
23016
|
+
"--items <file> is required: a file of raw board_list_items response pages."
|
|
23017
|
+
);
|
|
23018
|
+
return file;
|
|
23019
|
+
}
|
|
23020
|
+
function requireAnchors(options2) {
|
|
23021
|
+
if (!options2.topLeft || !options2.bottomRight)
|
|
23022
|
+
throw new MiroExtractError(
|
|
23023
|
+
"Both --top-left <id|link> and --bottom-right <id|link> are required."
|
|
23024
|
+
);
|
|
23025
|
+
return [parseAnchorId(options2.topLeft), parseAnchorId(options2.bottomRight)];
|
|
23026
|
+
}
|
|
23027
|
+
function runExtract(options2) {
|
|
23028
|
+
const [topLeft, bottomRight] = requireAnchors(options2);
|
|
23029
|
+
const items2 = normaliseItems(readMiroItems(requireItems(options2.items)));
|
|
23030
|
+
const boxes = selectBoxes(items2, topLeft, bottomRight);
|
|
23031
|
+
process.stdout.write(stringify(boxes.map((box) => box.text)));
|
|
23032
|
+
}
|
|
23033
|
+
|
|
23034
|
+
// src/commands/miro/registerMiro.ts
|
|
23035
|
+
function registerMiro(program2) {
|
|
23036
|
+
const miroCommand = program2.command("miro").description("Miro board utilities");
|
|
23037
|
+
miroCommand.command("extract").description("Print the text of every box inside a rectangle on a board").option("--items <file>", "File of raw board_list_items response pages").option(
|
|
23038
|
+
"--top-left <id>",
|
|
23039
|
+
"Widget id or ?moveToWidget=<id> link of the top-left box"
|
|
23040
|
+
).option(
|
|
23041
|
+
"--bottom-right <id>",
|
|
23042
|
+
"Widget id or ?moveToWidget=<id> link of the bottom-right box"
|
|
23043
|
+
).action(runExtract);
|
|
23044
|
+
}
|
|
23045
|
+
|
|
22730
23046
|
// src/commands/netcap/netcap.ts
|
|
22731
23047
|
import { mkdir as mkdir4 } from "fs/promises";
|
|
22732
23048
|
import { createServer as createServer2 } from "http";
|
|
22733
23049
|
import { dirname as dirname28 } from "path";
|
|
22734
|
-
import
|
|
23050
|
+
import chalk172 from "chalk";
|
|
22735
23051
|
|
|
22736
23052
|
// src/commands/netcap/corsHeaders.ts
|
|
22737
23053
|
var corsHeaders = {
|
|
@@ -22810,7 +23126,7 @@ function createNetcapHandler(options2) {
|
|
|
22810
23126
|
import { cp, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
22811
23127
|
import { networkInterfaces } from "os";
|
|
22812
23128
|
import { join as join58 } from "path";
|
|
22813
|
-
import
|
|
23129
|
+
import chalk171 from "chalk";
|
|
22814
23130
|
|
|
22815
23131
|
// src/commands/netcap/netcapExtensionDir.ts
|
|
22816
23132
|
import { dirname as dirname27, join as join57 } from "path";
|
|
@@ -22854,7 +23170,7 @@ async function prepareExtensionForLoad(port, filter = "") {
|
|
|
22854
23170
|
const host = lanIPv4();
|
|
22855
23171
|
if (!host) {
|
|
22856
23172
|
console.log(
|
|
22857
|
-
|
|
23173
|
+
chalk171.yellow("could not determine the WSL IP for the extension")
|
|
22858
23174
|
);
|
|
22859
23175
|
await configureBackground(source, "127.0.0.1", port, filter);
|
|
22860
23176
|
return source;
|
|
@@ -22865,7 +23181,7 @@ async function prepareExtensionForLoad(port, filter = "") {
|
|
|
22865
23181
|
return WSL_WINDOWS_PATH;
|
|
22866
23182
|
} catch {
|
|
22867
23183
|
console.log(
|
|
22868
|
-
|
|
23184
|
+
chalk171.yellow(`could not copy extension to ${WSL_WINDOWS_PATH}`)
|
|
22869
23185
|
);
|
|
22870
23186
|
return source;
|
|
22871
23187
|
}
|
|
@@ -22898,30 +23214,30 @@ async function netcap(options2) {
|
|
|
22898
23214
|
let count8 = 0;
|
|
22899
23215
|
const handler = createNetcapHandler({
|
|
22900
23216
|
outPath,
|
|
22901
|
-
onPing: () => console.log(
|
|
23217
|
+
onPing: () => console.log(chalk172.dim("ping from extension")),
|
|
22902
23218
|
onCapture: (entry) => {
|
|
22903
23219
|
count8 += 1;
|
|
22904
23220
|
console.log(
|
|
22905
|
-
|
|
22906
|
-
|
|
23221
|
+
chalk172.green(`captured #${count8}`),
|
|
23222
|
+
chalk172.dim(`${entry.method ?? "?"} ${entry.url ?? "?"}`)
|
|
22907
23223
|
);
|
|
22908
23224
|
}
|
|
22909
23225
|
});
|
|
22910
23226
|
const server = createServer2(handler);
|
|
22911
23227
|
server.listen(port, () => {
|
|
22912
23228
|
console.log(
|
|
22913
|
-
|
|
23229
|
+
chalk172.bold(`netcap receiver listening on http://127.0.0.1:${port}`)
|
|
22914
23230
|
);
|
|
22915
|
-
console.log(
|
|
23231
|
+
console.log(chalk172.dim(`appending captures to ${outPath}`));
|
|
22916
23232
|
if (filter)
|
|
22917
|
-
console.log(
|
|
22918
|
-
console.log(
|
|
22919
|
-
console.log(
|
|
23233
|
+
console.log(chalk172.dim(`forwarding only URLs matching "${filter}"`));
|
|
23234
|
+
console.log(chalk172.dim(`load the unpacked extension from ${extensionPath}`));
|
|
23235
|
+
console.log(chalk172.dim("press Ctrl-C to stop"));
|
|
22920
23236
|
});
|
|
22921
23237
|
process.on("SIGINT", () => {
|
|
22922
23238
|
server.close();
|
|
22923
23239
|
console.log(
|
|
22924
|
-
|
|
23240
|
+
chalk172.bold(
|
|
22925
23241
|
`
|
|
22926
23242
|
netcap stopped \u2014 captured ${count8} ${count8 === 1 ? "entry" : "entries"} to ${outPath}`
|
|
22927
23243
|
)
|
|
@@ -22933,10 +23249,10 @@ netcap stopped \u2014 captured ${count8} ${count8 === 1 ? "entry" : "entries"} t
|
|
|
22933
23249
|
// src/commands/netcap/netcapExtract.ts
|
|
22934
23250
|
import { writeFileSync as writeFileSync33 } from "fs";
|
|
22935
23251
|
import { join as join61 } from "path";
|
|
22936
|
-
import
|
|
23252
|
+
import chalk173 from "chalk";
|
|
22937
23253
|
|
|
22938
23254
|
// src/commands/netcap/extractPostsFromCapture.ts
|
|
22939
|
-
import { readFileSync as
|
|
23255
|
+
import { readFileSync as readFileSync41 } from "fs";
|
|
22940
23256
|
|
|
22941
23257
|
// src/commands/netcap/parseRscRows.ts
|
|
22942
23258
|
var isRscRef = (v) => typeof v === "string" && /^\$[0-9a-fL@]/.test(v);
|
|
@@ -23332,7 +23648,7 @@ function extractVoyagerPosts(body) {
|
|
|
23332
23648
|
|
|
23333
23649
|
// src/commands/netcap/extractPostsFromCapture.ts
|
|
23334
23650
|
function captureEntries(captureFile) {
|
|
23335
|
-
const lines2 =
|
|
23651
|
+
const lines2 = readFileSync41(captureFile, "utf8").split("\n").filter(Boolean);
|
|
23336
23652
|
const entries = [];
|
|
23337
23653
|
for (const line of lines2) {
|
|
23338
23654
|
let entry;
|
|
@@ -23381,8 +23697,8 @@ function netcapExtract(file) {
|
|
|
23381
23697
|
writeFileSync33(outFile, `${JSON.stringify(posts, null, 2)}
|
|
23382
23698
|
`);
|
|
23383
23699
|
console.log(
|
|
23384
|
-
|
|
23385
|
-
|
|
23700
|
+
chalk173.green(`extracted ${posts.length} posts`),
|
|
23701
|
+
chalk173.dim(`-> ${outFile}`)
|
|
23386
23702
|
);
|
|
23387
23703
|
}
|
|
23388
23704
|
|
|
@@ -23403,7 +23719,7 @@ function registerNetcap(program2) {
|
|
|
23403
23719
|
}
|
|
23404
23720
|
|
|
23405
23721
|
// src/commands/news/add/index.ts
|
|
23406
|
-
import
|
|
23722
|
+
import chalk174 from "chalk";
|
|
23407
23723
|
import enquirer8 from "enquirer";
|
|
23408
23724
|
async function add2(url) {
|
|
23409
23725
|
if (!url) {
|
|
@@ -23425,10 +23741,10 @@ async function add2(url) {
|
|
|
23425
23741
|
const { orm } = await getReady();
|
|
23426
23742
|
const added = await addFeed(orm, url);
|
|
23427
23743
|
if (!added) {
|
|
23428
|
-
console.log(
|
|
23744
|
+
console.log(chalk174.yellow("Feed already exists"));
|
|
23429
23745
|
return;
|
|
23430
23746
|
}
|
|
23431
|
-
console.log(
|
|
23747
|
+
console.log(chalk174.green(`Added feed: ${url}`));
|
|
23432
23748
|
}
|
|
23433
23749
|
|
|
23434
23750
|
// src/commands/registerNews.ts
|
|
@@ -23475,7 +23791,7 @@ function registerPiHook(program2) {
|
|
|
23475
23791
|
}
|
|
23476
23792
|
|
|
23477
23793
|
// src/commands/prompts/printPromptsTable.ts
|
|
23478
|
-
import
|
|
23794
|
+
import chalk175 from "chalk";
|
|
23479
23795
|
function truncate(str, max) {
|
|
23480
23796
|
if (str.length <= max) return str;
|
|
23481
23797
|
return `${str.slice(0, max - 1)}\u2026`;
|
|
@@ -23493,14 +23809,14 @@ function printPromptsTable(rows) {
|
|
|
23493
23809
|
"Command".padEnd(commandWidth),
|
|
23494
23810
|
"Repos"
|
|
23495
23811
|
].join(" ");
|
|
23496
|
-
console.log(
|
|
23497
|
-
console.log(
|
|
23812
|
+
console.log(chalk175.dim(header));
|
|
23813
|
+
console.log(chalk175.dim("-".repeat(header.length)));
|
|
23498
23814
|
for (const row of rows) {
|
|
23499
23815
|
const count8 = String(row.count).padStart(countWidth);
|
|
23500
23816
|
const tool = row.tool.padEnd(toolWidth);
|
|
23501
23817
|
const command = truncate(row.command, 60).padEnd(commandWidth);
|
|
23502
23818
|
console.log(
|
|
23503
|
-
`${
|
|
23819
|
+
`${chalk175.yellow(count8)} ${tool} ${command} ${chalk175.dim(row.repos)}`
|
|
23504
23820
|
);
|
|
23505
23821
|
}
|
|
23506
23822
|
}
|
|
@@ -23906,7 +24222,7 @@ import { tmpdir as tmpdir6 } from "os";
|
|
|
23906
24222
|
import { join as join63 } from "path";
|
|
23907
24223
|
|
|
23908
24224
|
// src/commands/prs/loadCommentsCache.ts
|
|
23909
|
-
import { existsSync as existsSync54, readFileSync as
|
|
24225
|
+
import { existsSync as existsSync54, readFileSync as readFileSync42, unlinkSync as unlinkSync13 } from "fs";
|
|
23910
24226
|
import { parse as parse2 } from "yaml";
|
|
23911
24227
|
|
|
23912
24228
|
// src/commands/prs/commentsCachePath.ts
|
|
@@ -23929,7 +24245,7 @@ function loadCommentsCache(org, repo, prNumber) {
|
|
|
23929
24245
|
if (!existsSync54(cachePath)) {
|
|
23930
24246
|
return null;
|
|
23931
24247
|
}
|
|
23932
|
-
const content =
|
|
24248
|
+
const content = readFileSync42(cachePath, "utf8");
|
|
23933
24249
|
return parse2(content);
|
|
23934
24250
|
}
|
|
23935
24251
|
function deleteCommentsCache(org, repo, prNumber) {
|
|
@@ -24121,7 +24437,7 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
|
|
|
24121
24437
|
// src/commands/prs/listComments/updateCommentsCache.ts
|
|
24122
24438
|
import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync36 } from "fs";
|
|
24123
24439
|
import { dirname as dirname29 } from "path";
|
|
24124
|
-
import { stringify } from "yaml";
|
|
24440
|
+
import { stringify as stringify2 } from "yaml";
|
|
24125
24441
|
|
|
24126
24442
|
// src/commands/prs/removeStaleCommentsCaches.ts
|
|
24127
24443
|
import { readdirSync as readdirSync12, unlinkSync as unlinkSync16 } from "fs";
|
|
@@ -24149,7 +24465,7 @@ function writeCommentsCache(org, repo, prNumber, comments3) {
|
|
|
24149
24465
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24150
24466
|
comments: comments3
|
|
24151
24467
|
};
|
|
24152
|
-
writeFileSync36(cachePath,
|
|
24468
|
+
writeFileSync36(cachePath, stringify2(cacheData));
|
|
24153
24469
|
}
|
|
24154
24470
|
function updateCommentsCache(org, repo, prNumber, comments3) {
|
|
24155
24471
|
removeStaleCommentsCaches();
|
|
@@ -24167,13 +24483,13 @@ function agentFooter(unresolvedCount) {
|
|
|
24167
24483
|
}
|
|
24168
24484
|
|
|
24169
24485
|
// src/commands/prs/listComments/commentStyle.ts
|
|
24170
|
-
import
|
|
24486
|
+
import chalk176 from "chalk";
|
|
24171
24487
|
var plain = (text18) => text18;
|
|
24172
24488
|
function colouredState(state) {
|
|
24173
24489
|
const label2 = `[${state}]`;
|
|
24174
|
-
if (state === "APPROVED") return
|
|
24175
|
-
if (state === "CHANGES_REQUESTED") return
|
|
24176
|
-
return
|
|
24490
|
+
if (state === "APPROVED") return chalk176.green(label2);
|
|
24491
|
+
if (state === "CHANGES_REQUESTED") return chalk176.red(label2);
|
|
24492
|
+
return chalk176.yellow(label2);
|
|
24177
24493
|
}
|
|
24178
24494
|
function commentStyle() {
|
|
24179
24495
|
if (isClaudeCode()) {
|
|
@@ -24187,9 +24503,9 @@ function commentStyle() {
|
|
|
24187
24503
|
};
|
|
24188
24504
|
}
|
|
24189
24505
|
return {
|
|
24190
|
-
cyan:
|
|
24191
|
-
bold:
|
|
24192
|
-
dim:
|
|
24506
|
+
cyan: chalk176.cyan,
|
|
24507
|
+
bold: chalk176.bold,
|
|
24508
|
+
dim: chalk176.dim,
|
|
24193
24509
|
state: colouredState,
|
|
24194
24510
|
diffHunk: true,
|
|
24195
24511
|
agent: false
|
|
@@ -24359,13 +24675,13 @@ import { execSync as execSync48 } from "child_process";
|
|
|
24359
24675
|
import enquirer9 from "enquirer";
|
|
24360
24676
|
|
|
24361
24677
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
24362
|
-
import
|
|
24678
|
+
import chalk177 from "chalk";
|
|
24363
24679
|
var STATUS_MAP = {
|
|
24364
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
24365
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
24680
|
+
MERGED: (pr) => pr.mergedAt ? { label: chalk177.magenta("merged"), date: pr.mergedAt } : null,
|
|
24681
|
+
CLOSED: (pr) => pr.closedAt ? { label: chalk177.red("closed"), date: pr.closedAt } : null
|
|
24366
24682
|
};
|
|
24367
24683
|
function defaultStatus(pr) {
|
|
24368
|
-
return { label:
|
|
24684
|
+
return { label: chalk177.green("opened"), date: pr.createdAt };
|
|
24369
24685
|
}
|
|
24370
24686
|
function getStatus2(pr) {
|
|
24371
24687
|
return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
|
|
@@ -24374,11 +24690,11 @@ function formatDate(dateStr) {
|
|
|
24374
24690
|
return new Date(dateStr).toISOString().split("T")[0];
|
|
24375
24691
|
}
|
|
24376
24692
|
function formatPrHeader(pr, status3) {
|
|
24377
|
-
return `${
|
|
24693
|
+
return `${chalk177.cyan(`#${pr.number}`)} ${pr.title} ${chalk177.dim(`(${pr.author.login},`)} ${status3.label} ${chalk177.dim(`${formatDate(status3.date)})`)}`;
|
|
24378
24694
|
}
|
|
24379
24695
|
function logPrDetails(pr) {
|
|
24380
24696
|
console.log(
|
|
24381
|
-
|
|
24697
|
+
chalk177.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
|
|
24382
24698
|
);
|
|
24383
24699
|
console.log();
|
|
24384
24700
|
}
|
|
@@ -25093,10 +25409,10 @@ function registerPrs(program2) {
|
|
|
25093
25409
|
}
|
|
25094
25410
|
|
|
25095
25411
|
// src/commands/ravendb/ravendbAuth.ts
|
|
25096
|
-
import
|
|
25412
|
+
import chalk183 from "chalk";
|
|
25097
25413
|
|
|
25098
25414
|
// src/shared/createConnectionAuth.ts
|
|
25099
|
-
import
|
|
25415
|
+
import chalk178 from "chalk";
|
|
25100
25416
|
function listConnections(connections, format) {
|
|
25101
25417
|
if (connections.length === 0) {
|
|
25102
25418
|
console.log("No connections configured.");
|
|
@@ -25109,7 +25425,7 @@ function listConnections(connections, format) {
|
|
|
25109
25425
|
function removeConnection(connections, name, save) {
|
|
25110
25426
|
const filtered = connections.filter((c) => c.name !== name);
|
|
25111
25427
|
if (filtered.length === connections.length) {
|
|
25112
|
-
console.error(
|
|
25428
|
+
console.error(chalk178.red(`Connection "${name}" not found.`));
|
|
25113
25429
|
process.exit(1);
|
|
25114
25430
|
}
|
|
25115
25431
|
save(filtered);
|
|
@@ -25155,15 +25471,15 @@ function saveConnections(connections) {
|
|
|
25155
25471
|
}
|
|
25156
25472
|
|
|
25157
25473
|
// src/commands/ravendb/promptConnection.ts
|
|
25158
|
-
import
|
|
25474
|
+
import chalk181 from "chalk";
|
|
25159
25475
|
|
|
25160
25476
|
// src/commands/ravendb/selectOpSecret.ts
|
|
25161
|
-
import
|
|
25477
|
+
import chalk180 from "chalk";
|
|
25162
25478
|
import Enquirer2 from "enquirer";
|
|
25163
25479
|
|
|
25164
25480
|
// src/commands/ravendb/searchItems.ts
|
|
25165
25481
|
import { execSync as execSync51 } from "child_process";
|
|
25166
|
-
import
|
|
25482
|
+
import chalk179 from "chalk";
|
|
25167
25483
|
function opExec(args) {
|
|
25168
25484
|
return execSync51(`op ${args}`, {
|
|
25169
25485
|
encoding: "utf8",
|
|
@@ -25176,7 +25492,7 @@ function searchItems(search2) {
|
|
|
25176
25492
|
items2 = JSON.parse(opExec("item list --format=json"));
|
|
25177
25493
|
} catch {
|
|
25178
25494
|
console.error(
|
|
25179
|
-
|
|
25495
|
+
chalk179.red(
|
|
25180
25496
|
"Failed to search 1Password. Ensure the CLI is installed and you are signed in."
|
|
25181
25497
|
)
|
|
25182
25498
|
);
|
|
@@ -25190,7 +25506,7 @@ function getItemFields(itemId2) {
|
|
|
25190
25506
|
const item = JSON.parse(opExec(`item get "${itemId2}" --format=json`));
|
|
25191
25507
|
return item.fields.filter((f) => f.reference && f.label);
|
|
25192
25508
|
} catch {
|
|
25193
|
-
console.error(
|
|
25509
|
+
console.error(chalk179.red("Failed to get item details from 1Password."));
|
|
25194
25510
|
process.exit(1);
|
|
25195
25511
|
}
|
|
25196
25512
|
}
|
|
@@ -25209,7 +25525,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
25209
25525
|
}).run();
|
|
25210
25526
|
const items2 = searchItems(search2);
|
|
25211
25527
|
if (items2.length === 0) {
|
|
25212
|
-
console.error(
|
|
25528
|
+
console.error(chalk180.red(`No items found matching "${search2}".`));
|
|
25213
25529
|
process.exit(1);
|
|
25214
25530
|
}
|
|
25215
25531
|
const itemId2 = await selectOne(
|
|
@@ -25218,7 +25534,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
25218
25534
|
);
|
|
25219
25535
|
const fields = getItemFields(itemId2);
|
|
25220
25536
|
if (fields.length === 0) {
|
|
25221
|
-
console.error(
|
|
25537
|
+
console.error(chalk180.red("No fields with references found on this item."));
|
|
25222
25538
|
process.exit(1);
|
|
25223
25539
|
}
|
|
25224
25540
|
const ref = await selectOne(
|
|
@@ -25232,7 +25548,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
25232
25548
|
async function promptConnection(existingNames) {
|
|
25233
25549
|
const name = await promptInput("name", "Connection name:");
|
|
25234
25550
|
if (existingNames.includes(name)) {
|
|
25235
|
-
console.error(
|
|
25551
|
+
console.error(chalk181.red(`Connection "${name}" already exists.`));
|
|
25236
25552
|
process.exit(1);
|
|
25237
25553
|
}
|
|
25238
25554
|
const url = await promptInput(
|
|
@@ -25241,22 +25557,22 @@ async function promptConnection(existingNames) {
|
|
|
25241
25557
|
);
|
|
25242
25558
|
const database = await promptInput("database", "Database name:");
|
|
25243
25559
|
if (!name || !url || !database) {
|
|
25244
|
-
console.error(
|
|
25560
|
+
console.error(chalk181.red("All fields are required."));
|
|
25245
25561
|
process.exit(1);
|
|
25246
25562
|
}
|
|
25247
25563
|
const apiKeyRef = await selectOpSecret();
|
|
25248
|
-
console.log(
|
|
25564
|
+
console.log(chalk181.dim(`Using: ${apiKeyRef}`));
|
|
25249
25565
|
return { name, url, database, apiKeyRef };
|
|
25250
25566
|
}
|
|
25251
25567
|
|
|
25252
25568
|
// src/commands/ravendb/ravendbSetConnection.ts
|
|
25253
|
-
import
|
|
25569
|
+
import chalk182 from "chalk";
|
|
25254
25570
|
function ravendbSetConnection(name) {
|
|
25255
25571
|
const raw = loadGlobalConfigRaw();
|
|
25256
25572
|
const ravendb = raw.ravendb ?? {};
|
|
25257
25573
|
const connections = ravendb.connections ?? [];
|
|
25258
25574
|
if (!connections.some((c) => c.name === name)) {
|
|
25259
|
-
console.error(
|
|
25575
|
+
console.error(chalk182.red(`Connection "${name}" not found.`));
|
|
25260
25576
|
console.error(
|
|
25261
25577
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
25262
25578
|
);
|
|
@@ -25272,16 +25588,16 @@ function ravendbSetConnection(name) {
|
|
|
25272
25588
|
var ravendbAuth = createConnectionAuth({
|
|
25273
25589
|
load: loadConnections,
|
|
25274
25590
|
save: saveConnections,
|
|
25275
|
-
format: (c) => `${
|
|
25591
|
+
format: (c) => `${chalk183.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
|
|
25276
25592
|
promptNew: promptConnection,
|
|
25277
25593
|
onFirst: (c) => ravendbSetConnection(c.name)
|
|
25278
25594
|
});
|
|
25279
25595
|
|
|
25280
25596
|
// src/commands/ravendb/ravendbCollections.ts
|
|
25281
|
-
import
|
|
25597
|
+
import chalk187 from "chalk";
|
|
25282
25598
|
|
|
25283
25599
|
// src/commands/ravendb/ravenFetch.ts
|
|
25284
|
-
import
|
|
25600
|
+
import chalk185 from "chalk";
|
|
25285
25601
|
|
|
25286
25602
|
// src/commands/ravendb/getAccessToken.ts
|
|
25287
25603
|
var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
|
|
@@ -25318,10 +25634,10 @@ ${errorText}`
|
|
|
25318
25634
|
|
|
25319
25635
|
// src/commands/ravendb/resolveOpSecret.ts
|
|
25320
25636
|
import { execSync as execSync52 } from "child_process";
|
|
25321
|
-
import
|
|
25637
|
+
import chalk184 from "chalk";
|
|
25322
25638
|
function resolveOpSecret(reference) {
|
|
25323
25639
|
if (!reference.startsWith("op://")) {
|
|
25324
|
-
console.error(
|
|
25640
|
+
console.error(chalk184.red(`Invalid secret reference: must start with op://`));
|
|
25325
25641
|
process.exit(1);
|
|
25326
25642
|
}
|
|
25327
25643
|
try {
|
|
@@ -25331,7 +25647,7 @@ function resolveOpSecret(reference) {
|
|
|
25331
25647
|
}).trim();
|
|
25332
25648
|
} catch {
|
|
25333
25649
|
console.error(
|
|
25334
|
-
|
|
25650
|
+
chalk184.red(
|
|
25335
25651
|
"Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
|
|
25336
25652
|
)
|
|
25337
25653
|
);
|
|
@@ -25358,7 +25674,7 @@ async function ravenFetch(connection, path80) {
|
|
|
25358
25674
|
if (!response.ok) {
|
|
25359
25675
|
const body = await response.text();
|
|
25360
25676
|
console.error(
|
|
25361
|
-
|
|
25677
|
+
chalk185.red(`RavenDB error: ${response.status} ${response.statusText}`)
|
|
25362
25678
|
);
|
|
25363
25679
|
console.error(body.substring(0, 500));
|
|
25364
25680
|
process.exit(1);
|
|
@@ -25367,7 +25683,7 @@ async function ravenFetch(connection, path80) {
|
|
|
25367
25683
|
}
|
|
25368
25684
|
|
|
25369
25685
|
// src/commands/ravendb/resolveConnection.ts
|
|
25370
|
-
import
|
|
25686
|
+
import chalk186 from "chalk";
|
|
25371
25687
|
function loadRavendb() {
|
|
25372
25688
|
const raw = loadGlobalConfigRaw();
|
|
25373
25689
|
const ravendb = raw.ravendb;
|
|
@@ -25381,7 +25697,7 @@ function resolveConnection(name) {
|
|
|
25381
25697
|
const connectionName = name ?? defaultConnection;
|
|
25382
25698
|
if (!connectionName) {
|
|
25383
25699
|
console.error(
|
|
25384
|
-
|
|
25700
|
+
chalk186.red(
|
|
25385
25701
|
"No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
|
|
25386
25702
|
)
|
|
25387
25703
|
);
|
|
@@ -25389,7 +25705,7 @@ function resolveConnection(name) {
|
|
|
25389
25705
|
}
|
|
25390
25706
|
const connection = connections.find((c) => c.name === connectionName);
|
|
25391
25707
|
if (!connection) {
|
|
25392
|
-
console.error(
|
|
25708
|
+
console.error(chalk186.red(`Connection "${connectionName}" not found.`));
|
|
25393
25709
|
console.error(
|
|
25394
25710
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
25395
25711
|
);
|
|
@@ -25420,15 +25736,15 @@ async function ravendbCollections(connectionName) {
|
|
|
25420
25736
|
return;
|
|
25421
25737
|
}
|
|
25422
25738
|
for (const c of collections) {
|
|
25423
|
-
console.log(`${
|
|
25739
|
+
console.log(`${chalk187.bold(c.Name)} ${c.CountOfDocuments} docs`);
|
|
25424
25740
|
}
|
|
25425
25741
|
}
|
|
25426
25742
|
|
|
25427
25743
|
// src/commands/ravendb/ravendbQuery.ts
|
|
25428
|
-
import
|
|
25744
|
+
import chalk189 from "chalk";
|
|
25429
25745
|
|
|
25430
25746
|
// src/commands/ravendb/fetchAllPages.ts
|
|
25431
|
-
import
|
|
25747
|
+
import chalk188 from "chalk";
|
|
25432
25748
|
|
|
25433
25749
|
// src/commands/ravendb/buildQueryPath.ts
|
|
25434
25750
|
function buildQueryPath(opts) {
|
|
@@ -25466,7 +25782,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
25466
25782
|
allResults.push(...results);
|
|
25467
25783
|
start3 += results.length;
|
|
25468
25784
|
process.stderr.write(
|
|
25469
|
-
`\r${
|
|
25785
|
+
`\r${chalk188.dim(`Fetched ${allResults.length}/${totalResults}`)}`
|
|
25470
25786
|
);
|
|
25471
25787
|
if (start3 >= totalResults) break;
|
|
25472
25788
|
if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
|
|
@@ -25481,7 +25797,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
25481
25797
|
async function ravendbQuery(connectionName, collection, options2) {
|
|
25482
25798
|
const resolved = resolveArgs(connectionName, collection);
|
|
25483
25799
|
if (!resolved.collection && !options2.query) {
|
|
25484
|
-
console.error(
|
|
25800
|
+
console.error(chalk189.red("Provide a collection name or --query filter."));
|
|
25485
25801
|
process.exit(1);
|
|
25486
25802
|
}
|
|
25487
25803
|
const { collection: col } = resolved;
|
|
@@ -25520,7 +25836,7 @@ import { spawn as spawn6 } from "child_process";
|
|
|
25520
25836
|
import * as path42 from "path";
|
|
25521
25837
|
|
|
25522
25838
|
// src/commands/refactor/logViolations.ts
|
|
25523
|
-
import
|
|
25839
|
+
import chalk190 from "chalk";
|
|
25524
25840
|
var DEFAULT_MAX_LINES2 = 100;
|
|
25525
25841
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES2) {
|
|
25526
25842
|
if (violations.length === 0) {
|
|
@@ -25529,43 +25845,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES2) {
|
|
|
25529
25845
|
}
|
|
25530
25846
|
return;
|
|
25531
25847
|
}
|
|
25532
|
-
console.error(
|
|
25848
|
+
console.error(chalk190.red(`
|
|
25533
25849
|
Refactor check failed:
|
|
25534
25850
|
`));
|
|
25535
|
-
console.error(
|
|
25851
|
+
console.error(chalk190.red(` The following files exceed ${maxLines} lines:
|
|
25536
25852
|
`));
|
|
25537
25853
|
for (const violation of violations) {
|
|
25538
|
-
console.error(
|
|
25854
|
+
console.error(chalk190.red(` ${violation.file} (${violation.lines} lines)`));
|
|
25539
25855
|
}
|
|
25540
25856
|
console.error(
|
|
25541
|
-
|
|
25857
|
+
chalk190.yellow(
|
|
25542
25858
|
`
|
|
25543
25859
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
25544
25860
|
way to refactor it, ignore it with:
|
|
25545
25861
|
`
|
|
25546
25862
|
)
|
|
25547
25863
|
);
|
|
25548
|
-
console.error(
|
|
25864
|
+
console.error(chalk190.gray(` assist refactor ignore <file>
|
|
25549
25865
|
`));
|
|
25550
25866
|
if (process.env.CLAUDECODE) {
|
|
25551
|
-
console.error(
|
|
25867
|
+
console.error(chalk190.cyan(`
|
|
25552
25868
|
## Extracting Code to New Files
|
|
25553
25869
|
`));
|
|
25554
25870
|
console.error(
|
|
25555
|
-
|
|
25871
|
+
chalk190.cyan(
|
|
25556
25872
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
25557
25873
|
`
|
|
25558
25874
|
)
|
|
25559
25875
|
);
|
|
25560
25876
|
console.error(
|
|
25561
|
-
|
|
25877
|
+
chalk190.cyan(
|
|
25562
25878
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
25563
25879
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
25564
25880
|
`
|
|
25565
25881
|
)
|
|
25566
25882
|
);
|
|
25567
25883
|
console.error(
|
|
25568
|
-
|
|
25884
|
+
chalk190.cyan(
|
|
25569
25885
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
25570
25886
|
domains, move it to a common/shared folder.
|
|
25571
25887
|
`
|
|
@@ -25721,7 +26037,7 @@ async function check(pattern2, options2) {
|
|
|
25721
26037
|
|
|
25722
26038
|
// src/commands/refactor/extract/index.ts
|
|
25723
26039
|
import path50 from "path";
|
|
25724
|
-
import
|
|
26040
|
+
import chalk193 from "chalk";
|
|
25725
26041
|
|
|
25726
26042
|
// src/commands/refactor/extract/applyExtraction.ts
|
|
25727
26043
|
import { SyntaxKind as SyntaxKind4 } from "ts-morph";
|
|
@@ -26320,23 +26636,23 @@ function buildPlan2(functionName, sourceFile, sourcePath, destPath, project) {
|
|
|
26320
26636
|
|
|
26321
26637
|
// src/commands/refactor/extract/displayPlan.ts
|
|
26322
26638
|
import path46 from "path";
|
|
26323
|
-
import
|
|
26639
|
+
import chalk191 from "chalk";
|
|
26324
26640
|
function section2(title) {
|
|
26325
26641
|
return `
|
|
26326
|
-
${
|
|
26642
|
+
${chalk191.cyan(title)}`;
|
|
26327
26643
|
}
|
|
26328
26644
|
function displayImporters(plan2, cwd) {
|
|
26329
26645
|
if (plan2.importersToUpdate.length === 0) return;
|
|
26330
26646
|
console.log(section2("Update importers:"));
|
|
26331
26647
|
for (const imp of plan2.importersToUpdate) {
|
|
26332
26648
|
const rel = path46.relative(cwd, imp.file.getFilePath());
|
|
26333
|
-
console.log(` ${
|
|
26649
|
+
console.log(` ${chalk191.dim(rel)}: \u2192 import from "${imp.relPath}"`);
|
|
26334
26650
|
}
|
|
26335
26651
|
}
|
|
26336
26652
|
function displayPlan(functionName, relDest, plan2, cwd) {
|
|
26337
|
-
console.log(
|
|
26653
|
+
console.log(chalk191.bold(`Extract: ${functionName} \u2192 ${relDest}
|
|
26338
26654
|
`));
|
|
26339
|
-
console.log(` ${
|
|
26655
|
+
console.log(` ${chalk191.cyan("Functions to move:")}`);
|
|
26340
26656
|
for (const name of plan2.extractedNames) {
|
|
26341
26657
|
console.log(` ${name}`);
|
|
26342
26658
|
}
|
|
@@ -26370,7 +26686,7 @@ function displayPlan(functionName, relDest, plan2, cwd) {
|
|
|
26370
26686
|
|
|
26371
26687
|
// src/commands/refactor/extract/loadProjectFile.ts
|
|
26372
26688
|
import path49 from "path";
|
|
26373
|
-
import
|
|
26689
|
+
import chalk192 from "chalk";
|
|
26374
26690
|
import { Project as Project4 } from "ts-morph";
|
|
26375
26691
|
|
|
26376
26692
|
// src/commands/refactor/extract/findTsConfig.ts
|
|
@@ -26462,7 +26778,7 @@ function loadProjectFile(file) {
|
|
|
26462
26778
|
});
|
|
26463
26779
|
const sourceFile = project.getSourceFile(sourcePath);
|
|
26464
26780
|
if (!sourceFile) {
|
|
26465
|
-
console.log(
|
|
26781
|
+
console.log(chalk192.red(`File not found in project: ${file}`));
|
|
26466
26782
|
process.exit(1);
|
|
26467
26783
|
}
|
|
26468
26784
|
return { project, sourceFile };
|
|
@@ -26485,19 +26801,19 @@ async function extract(file, functionName, destination, options2 = {}) {
|
|
|
26485
26801
|
displayPlan(functionName, relDest, plan2, cwd);
|
|
26486
26802
|
if (options2.apply) {
|
|
26487
26803
|
await applyExtraction(functionName, sourceFile, destPath, plan2, project);
|
|
26488
|
-
console.log(
|
|
26804
|
+
console.log(chalk193.green("\nExtraction complete"));
|
|
26489
26805
|
} else {
|
|
26490
|
-
console.log(
|
|
26806
|
+
console.log(chalk193.dim("\nDry run. Use --apply to execute."));
|
|
26491
26807
|
}
|
|
26492
26808
|
}
|
|
26493
26809
|
|
|
26494
26810
|
// src/commands/refactor/ignore.ts
|
|
26495
26811
|
import fs33 from "fs";
|
|
26496
|
-
import
|
|
26812
|
+
import chalk194 from "chalk";
|
|
26497
26813
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
26498
26814
|
function ignore2(file) {
|
|
26499
26815
|
if (!fs33.existsSync(file)) {
|
|
26500
|
-
console.error(
|
|
26816
|
+
console.error(chalk194.red(`Error: File does not exist: ${file}`));
|
|
26501
26817
|
process.exit(1);
|
|
26502
26818
|
}
|
|
26503
26819
|
const content = fs33.readFileSync(file, "utf8");
|
|
@@ -26513,7 +26829,7 @@ function ignore2(file) {
|
|
|
26513
26829
|
fs33.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
26514
26830
|
}
|
|
26515
26831
|
console.log(
|
|
26516
|
-
|
|
26832
|
+
chalk194.green(
|
|
26517
26833
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
26518
26834
|
)
|
|
26519
26835
|
);
|
|
@@ -26522,12 +26838,12 @@ function ignore2(file) {
|
|
|
26522
26838
|
// src/commands/refactor/rename/index.ts
|
|
26523
26839
|
import fs36 from "fs";
|
|
26524
26840
|
import path55 from "path";
|
|
26525
|
-
import
|
|
26841
|
+
import chalk197 from "chalk";
|
|
26526
26842
|
|
|
26527
26843
|
// src/commands/refactor/rename/applyRename.ts
|
|
26528
26844
|
import fs35 from "fs";
|
|
26529
26845
|
import path52 from "path";
|
|
26530
|
-
import
|
|
26846
|
+
import chalk195 from "chalk";
|
|
26531
26847
|
|
|
26532
26848
|
// src/commands/refactor/restructure/computeRewrites/index.ts
|
|
26533
26849
|
import path51 from "path";
|
|
@@ -26632,13 +26948,13 @@ function applyRename(rewrites, sourcePath, destPath, cwd) {
|
|
|
26632
26948
|
const updatedContents = applyRewrites(rewrites);
|
|
26633
26949
|
for (const [file, content] of updatedContents) {
|
|
26634
26950
|
fs35.writeFileSync(file, content, "utf8");
|
|
26635
|
-
console.log(
|
|
26951
|
+
console.log(chalk195.cyan(` Updated imports in ${path52.relative(cwd, file)}`));
|
|
26636
26952
|
}
|
|
26637
26953
|
const destDir = path52.dirname(destPath);
|
|
26638
26954
|
if (!fs35.existsSync(destDir)) fs35.mkdirSync(destDir, { recursive: true });
|
|
26639
26955
|
fs35.renameSync(sourcePath, destPath);
|
|
26640
26956
|
console.log(
|
|
26641
|
-
|
|
26957
|
+
chalk195.white(
|
|
26642
26958
|
` Moved ${path52.relative(cwd, sourcePath)} \u2192 ${path52.relative(cwd, destPath)}`
|
|
26643
26959
|
)
|
|
26644
26960
|
);
|
|
@@ -26725,16 +27041,16 @@ function computeRenameRewrites(sourcePath, destPath) {
|
|
|
26725
27041
|
|
|
26726
27042
|
// src/commands/refactor/rename/printRenamePreview.ts
|
|
26727
27043
|
import path54 from "path";
|
|
26728
|
-
import
|
|
27044
|
+
import chalk196 from "chalk";
|
|
26729
27045
|
function printRenamePreview(rewrites, cwd) {
|
|
26730
27046
|
for (const rewrite of rewrites) {
|
|
26731
27047
|
console.log(
|
|
26732
|
-
|
|
27048
|
+
chalk196.dim(
|
|
26733
27049
|
` ${path54.relative(cwd, rewrite.file)}: ${rewrite.oldSpecifier} \u2192 ${rewrite.newSpecifier}`
|
|
26734
27050
|
)
|
|
26735
27051
|
);
|
|
26736
27052
|
}
|
|
26737
|
-
console.log(
|
|
27053
|
+
console.log(chalk196.dim("Dry run. Use --apply to execute."));
|
|
26738
27054
|
}
|
|
26739
27055
|
|
|
26740
27056
|
// src/commands/refactor/rename/index.ts
|
|
@@ -26745,20 +27061,20 @@ async function rename(source, destination, options2 = {}) {
|
|
|
26745
27061
|
const relSource = path55.relative(cwd, sourcePath);
|
|
26746
27062
|
const relDest = path55.relative(cwd, destPath);
|
|
26747
27063
|
if (!fs36.existsSync(sourcePath)) {
|
|
26748
|
-
console.log(
|
|
27064
|
+
console.log(chalk197.red(`File not found: ${source}`));
|
|
26749
27065
|
process.exit(1);
|
|
26750
27066
|
}
|
|
26751
27067
|
if (destPath !== sourcePath && fs36.existsSync(destPath)) {
|
|
26752
|
-
console.log(
|
|
27068
|
+
console.log(chalk197.red(`Destination already exists: ${destination}`));
|
|
26753
27069
|
process.exit(1);
|
|
26754
27070
|
}
|
|
26755
|
-
console.log(
|
|
26756
|
-
console.log(
|
|
26757
|
-
console.log(
|
|
27071
|
+
console.log(chalk197.bold(`Rename: ${relSource} \u2192 ${relDest}`));
|
|
27072
|
+
console.log(chalk197.dim("Loading project..."));
|
|
27073
|
+
console.log(chalk197.dim("Scanning imports across the project..."));
|
|
26758
27074
|
const rewrites = computeRenameRewrites(sourcePath, destPath);
|
|
26759
27075
|
const affectedFiles = new Set(rewrites.map((r) => r.file)).size;
|
|
26760
27076
|
console.log(
|
|
26761
|
-
|
|
27077
|
+
chalk197.dim(
|
|
26762
27078
|
`${rewrites.length} import path(s) to update across ${affectedFiles} file(s)`
|
|
26763
27079
|
)
|
|
26764
27080
|
);
|
|
@@ -26767,11 +27083,11 @@ async function rename(source, destination, options2 = {}) {
|
|
|
26767
27083
|
return;
|
|
26768
27084
|
}
|
|
26769
27085
|
applyRename(rewrites, sourcePath, destPath, cwd);
|
|
26770
|
-
console.log(
|
|
27086
|
+
console.log(chalk197.green("Done"));
|
|
26771
27087
|
}
|
|
26772
27088
|
|
|
26773
27089
|
// src/commands/refactor/renameSymbol/index.ts
|
|
26774
|
-
import
|
|
27090
|
+
import chalk198 from "chalk";
|
|
26775
27091
|
|
|
26776
27092
|
// src/commands/refactor/renameSymbol/findSymbol.ts
|
|
26777
27093
|
import { SyntaxKind as SyntaxKind15 } from "ts-morph";
|
|
@@ -26817,33 +27133,33 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
|
|
|
26817
27133
|
const { project, sourceFile } = loadProjectFile(file);
|
|
26818
27134
|
const symbol = findSymbol(sourceFile, oldName);
|
|
26819
27135
|
if (!symbol) {
|
|
26820
|
-
console.log(
|
|
27136
|
+
console.log(chalk198.red(`Symbol "${oldName}" not found in ${file}`));
|
|
26821
27137
|
process.exit(1);
|
|
26822
27138
|
}
|
|
26823
27139
|
const grouped = groupReferences(symbol, cwd);
|
|
26824
27140
|
const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
|
|
26825
27141
|
console.log(
|
|
26826
|
-
|
|
27142
|
+
chalk198.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
|
|
26827
27143
|
`)
|
|
26828
27144
|
);
|
|
26829
27145
|
for (const [refFile, lines2] of grouped) {
|
|
26830
27146
|
console.log(
|
|
26831
|
-
` ${
|
|
27147
|
+
` ${chalk198.dim(refFile)}: lines ${chalk198.cyan(lines2.join(", "))}`
|
|
26832
27148
|
);
|
|
26833
27149
|
}
|
|
26834
27150
|
if (options2.apply) {
|
|
26835
27151
|
symbol.rename(newName);
|
|
26836
27152
|
await project.save();
|
|
26837
|
-
console.log(
|
|
27153
|
+
console.log(chalk198.green(`
|
|
26838
27154
|
Renamed ${oldName} \u2192 ${newName}`));
|
|
26839
27155
|
} else {
|
|
26840
|
-
console.log(
|
|
27156
|
+
console.log(chalk198.dim("\nDry run. Use --apply to execute."));
|
|
26841
27157
|
}
|
|
26842
27158
|
}
|
|
26843
27159
|
|
|
26844
27160
|
// src/commands/refactor/restructure/index.ts
|
|
26845
27161
|
import path63 from "path";
|
|
26846
|
-
import
|
|
27162
|
+
import chalk201 from "chalk";
|
|
26847
27163
|
|
|
26848
27164
|
// src/commands/refactor/restructure/clusterDirectories.ts
|
|
26849
27165
|
import path57 from "path";
|
|
@@ -26922,50 +27238,50 @@ function clusterFiles(graph) {
|
|
|
26922
27238
|
|
|
26923
27239
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
26924
27240
|
import path59 from "path";
|
|
26925
|
-
import
|
|
27241
|
+
import chalk199 from "chalk";
|
|
26926
27242
|
function relPath(filePath) {
|
|
26927
27243
|
return path59.relative(process.cwd(), filePath);
|
|
26928
27244
|
}
|
|
26929
27245
|
function displayMoves(plan2) {
|
|
26930
27246
|
if (plan2.moves.length === 0) return;
|
|
26931
|
-
console.log(
|
|
27247
|
+
console.log(chalk199.bold("\nFile moves:"));
|
|
26932
27248
|
for (const move2 of plan2.moves) {
|
|
26933
27249
|
console.log(
|
|
26934
|
-
` ${
|
|
27250
|
+
` ${chalk199.red(relPath(move2.from))} \u2192 ${chalk199.green(relPath(move2.to))}`
|
|
26935
27251
|
);
|
|
26936
|
-
console.log(
|
|
27252
|
+
console.log(chalk199.dim(` ${move2.reason}`));
|
|
26937
27253
|
}
|
|
26938
27254
|
}
|
|
26939
27255
|
function displayRewrites(rewrites) {
|
|
26940
27256
|
if (rewrites.length === 0) return;
|
|
26941
27257
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
26942
|
-
console.log(
|
|
27258
|
+
console.log(chalk199.bold(`
|
|
26943
27259
|
Import rewrites (${affectedFiles.size} files):`));
|
|
26944
27260
|
for (const file of affectedFiles) {
|
|
26945
|
-
console.log(` ${
|
|
27261
|
+
console.log(` ${chalk199.cyan(relPath(file))}:`);
|
|
26946
27262
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
26947
27263
|
(r) => r.file === file
|
|
26948
27264
|
)) {
|
|
26949
27265
|
console.log(
|
|
26950
|
-
` ${
|
|
27266
|
+
` ${chalk199.red(`"${oldSpecifier}"`)} \u2192 ${chalk199.green(`"${newSpecifier}"`)}`
|
|
26951
27267
|
);
|
|
26952
27268
|
}
|
|
26953
27269
|
}
|
|
26954
27270
|
}
|
|
26955
27271
|
function displayPlan2(plan2) {
|
|
26956
27272
|
if (plan2.warnings.length > 0) {
|
|
26957
|
-
console.log(
|
|
26958
|
-
for (const w of plan2.warnings) console.log(
|
|
27273
|
+
console.log(chalk199.yellow("\nWarnings:"));
|
|
27274
|
+
for (const w of plan2.warnings) console.log(chalk199.yellow(` ${w}`));
|
|
26959
27275
|
}
|
|
26960
27276
|
if (plan2.newDirectories.length > 0) {
|
|
26961
|
-
console.log(
|
|
27277
|
+
console.log(chalk199.bold("\nNew directories:"));
|
|
26962
27278
|
for (const dir of plan2.newDirectories)
|
|
26963
|
-
console.log(
|
|
27279
|
+
console.log(chalk199.green(` ${dir}/`));
|
|
26964
27280
|
}
|
|
26965
27281
|
displayMoves(plan2);
|
|
26966
27282
|
displayRewrites(plan2.rewrites);
|
|
26967
27283
|
console.log(
|
|
26968
|
-
|
|
27284
|
+
chalk199.dim(
|
|
26969
27285
|
`
|
|
26970
27286
|
Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports rewritten`
|
|
26971
27287
|
)
|
|
@@ -26975,18 +27291,18 @@ Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports r
|
|
|
26975
27291
|
// src/commands/refactor/restructure/executePlan.ts
|
|
26976
27292
|
import fs37 from "fs";
|
|
26977
27293
|
import path60 from "path";
|
|
26978
|
-
import
|
|
27294
|
+
import chalk200 from "chalk";
|
|
26979
27295
|
function executePlan(plan2) {
|
|
26980
27296
|
const updatedContents = applyRewrites(plan2.rewrites);
|
|
26981
27297
|
for (const [file, content] of updatedContents) {
|
|
26982
27298
|
fs37.writeFileSync(file, content, "utf8");
|
|
26983
27299
|
console.log(
|
|
26984
|
-
|
|
27300
|
+
chalk200.cyan(` Rewrote imports in ${path60.relative(process.cwd(), file)}`)
|
|
26985
27301
|
);
|
|
26986
27302
|
}
|
|
26987
27303
|
for (const dir of plan2.newDirectories) {
|
|
26988
27304
|
fs37.mkdirSync(dir, { recursive: true });
|
|
26989
|
-
console.log(
|
|
27305
|
+
console.log(chalk200.green(` Created ${path60.relative(process.cwd(), dir)}/`));
|
|
26990
27306
|
}
|
|
26991
27307
|
for (const move2 of plan2.moves) {
|
|
26992
27308
|
const targetDir = path60.dirname(move2.to);
|
|
@@ -26995,7 +27311,7 @@ function executePlan(plan2) {
|
|
|
26995
27311
|
}
|
|
26996
27312
|
fs37.renameSync(move2.from, move2.to);
|
|
26997
27313
|
console.log(
|
|
26998
|
-
|
|
27314
|
+
chalk200.white(
|
|
26999
27315
|
` Moved ${path60.relative(process.cwd(), move2.from)} \u2192 ${path60.relative(process.cwd(), move2.to)}`
|
|
27000
27316
|
)
|
|
27001
27317
|
);
|
|
@@ -27010,7 +27326,7 @@ function removeEmptyDirectories(dirs) {
|
|
|
27010
27326
|
if (entries.length === 0) {
|
|
27011
27327
|
fs37.rmdirSync(dir);
|
|
27012
27328
|
console.log(
|
|
27013
|
-
|
|
27329
|
+
chalk200.dim(
|
|
27014
27330
|
` Removed empty directory ${path60.relative(process.cwd(), dir)}`
|
|
27015
27331
|
)
|
|
27016
27332
|
);
|
|
@@ -27143,22 +27459,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
27143
27459
|
const targetPattern = pattern2 ?? "src";
|
|
27144
27460
|
const files = findSourceFiles2(targetPattern);
|
|
27145
27461
|
if (files.length === 0) {
|
|
27146
|
-
console.log(
|
|
27462
|
+
console.log(chalk201.yellow("No files found matching pattern"));
|
|
27147
27463
|
return;
|
|
27148
27464
|
}
|
|
27149
27465
|
const tsConfigPath = findTsConfig(path63.resolve(files[0]));
|
|
27150
27466
|
const plan2 = buildPlan3(files, tsConfigPath);
|
|
27151
27467
|
if (plan2.moves.length === 0) {
|
|
27152
|
-
console.log(
|
|
27468
|
+
console.log(chalk201.green("No restructuring needed"));
|
|
27153
27469
|
return;
|
|
27154
27470
|
}
|
|
27155
27471
|
displayPlan2(plan2);
|
|
27156
27472
|
if (options2.apply) {
|
|
27157
|
-
console.log(
|
|
27473
|
+
console.log(chalk201.bold("\nApplying changes..."));
|
|
27158
27474
|
executePlan(plan2);
|
|
27159
|
-
console.log(
|
|
27475
|
+
console.log(chalk201.green("\nRestructuring complete"));
|
|
27160
27476
|
} else {
|
|
27161
|
-
console.log(
|
|
27477
|
+
console.log(chalk201.dim("\nDry run. Use --apply to execute."));
|
|
27162
27478
|
}
|
|
27163
27479
|
}
|
|
27164
27480
|
|
|
@@ -27481,7 +27797,7 @@ function gatherContext() {
|
|
|
27481
27797
|
}
|
|
27482
27798
|
|
|
27483
27799
|
// src/commands/review/postReviewToPr.ts
|
|
27484
|
-
import { readFileSync as
|
|
27800
|
+
import { readFileSync as readFileSync43 } from "fs";
|
|
27485
27801
|
|
|
27486
27802
|
// src/commands/review/carriedUnanchoredFindings.ts
|
|
27487
27803
|
function carriedUnanchoredFindings(unanchored) {
|
|
@@ -27685,15 +28001,15 @@ function runReviewSubmission(mutation, body) {
|
|
|
27685
28001
|
}
|
|
27686
28002
|
|
|
27687
28003
|
// src/commands/review/submitBodyOnlyReview.ts
|
|
27688
|
-
var
|
|
28004
|
+
var MUTATION3 = `mutation($prId: ID!, $body: String) { addPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
|
|
27689
28005
|
function submitBodyOnlyReview(body) {
|
|
27690
|
-
runReviewSubmission(
|
|
28006
|
+
runReviewSubmission(MUTATION3, body);
|
|
27691
28007
|
}
|
|
27692
28008
|
|
|
27693
28009
|
// src/commands/review/submitPendingReview.ts
|
|
27694
|
-
var
|
|
28010
|
+
var MUTATION4 = `mutation($prId: ID!, $body: String) { submitPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
|
|
27695
28011
|
function submitPendingReview(body) {
|
|
27696
|
-
runReviewSubmission(
|
|
28012
|
+
runReviewSubmission(MUTATION4, body);
|
|
27697
28013
|
}
|
|
27698
28014
|
|
|
27699
28015
|
// src/commands/review/postAndMaybeSubmit.ts
|
|
@@ -27816,18 +28132,18 @@ function partitionFindingsByDiff(findings, index3) {
|
|
|
27816
28132
|
}
|
|
27817
28133
|
|
|
27818
28134
|
// src/commands/review/warnOutOfDiff.ts
|
|
27819
|
-
import
|
|
28135
|
+
import chalk202 from "chalk";
|
|
27820
28136
|
function warnOutOfDiff(outOfDiff) {
|
|
27821
28137
|
if (outOfDiff.length === 0) return;
|
|
27822
28138
|
console.warn(
|
|
27823
|
-
|
|
28139
|
+
chalk202.yellow(
|
|
27824
28140
|
`Moved ${outOfDiff.length} finding(s) whose lines fall outside the PR diff into the review body (GitHub cannot anchor a comment on these):`
|
|
27825
28141
|
)
|
|
27826
28142
|
);
|
|
27827
28143
|
for (const finding of outOfDiff) {
|
|
27828
28144
|
const range = finding.startLine !== void 0 ? `${finding.startLine}-${finding.line}` : `${finding.line}`;
|
|
27829
28145
|
console.warn(
|
|
27830
|
-
` ${
|
|
28146
|
+
` ${chalk202.yellow("\xB7")} ${finding.title} ${chalk202.dim(
|
|
27831
28147
|
`(${finding.file}:${range})`
|
|
27832
28148
|
)}`
|
|
27833
28149
|
);
|
|
@@ -27851,18 +28167,18 @@ function selectInDiffFindings(lineBound, prDiff) {
|
|
|
27851
28167
|
}
|
|
27852
28168
|
|
|
27853
28169
|
// src/commands/review/warnUnlocated.ts
|
|
27854
|
-
import
|
|
28170
|
+
import chalk203 from "chalk";
|
|
27855
28171
|
function warnUnlocated(unlocated) {
|
|
27856
28172
|
if (unlocated.length === 0) return;
|
|
27857
28173
|
console.warn(
|
|
27858
|
-
|
|
28174
|
+
chalk203.yellow(
|
|
27859
28175
|
`Moved ${unlocated.length} finding(s) without a parseable file:line into the review body:`
|
|
27860
28176
|
)
|
|
27861
28177
|
);
|
|
27862
28178
|
for (const finding of unlocated) {
|
|
27863
|
-
const where = finding.location ||
|
|
28179
|
+
const where = finding.location || chalk203.dim("missing");
|
|
27864
28180
|
console.warn(
|
|
27865
|
-
` ${
|
|
28181
|
+
` ${chalk203.yellow("\xB7")} ${finding.title} ${chalk203.dim(`(${where})`)}`
|
|
27866
28182
|
);
|
|
27867
28183
|
}
|
|
27868
28184
|
}
|
|
@@ -27929,7 +28245,7 @@ async function confirmPost(prNumber, work, options2) {
|
|
|
27929
28245
|
return promptConfirm(`Post ${work} to PR #${prNumber}?`, false);
|
|
27930
28246
|
}
|
|
27931
28247
|
async function postFindingsToPr(prInfo, synthesisPath, options2) {
|
|
27932
|
-
const markdown =
|
|
28248
|
+
const markdown = readFileSync43(synthesisPath, "utf8");
|
|
27933
28249
|
const { inDiff, unanchored } = selectPostableFindings(markdown, prInfo);
|
|
27934
28250
|
const carried = carriedUnanchoredFindings(unanchored);
|
|
27935
28251
|
if (inDiff.length === 0 && carried.length === 0) return NOTHING_POSTED;
|
|
@@ -28818,7 +29134,7 @@ async function runReviewers(reviewDir, claudePath, codexPath, stdinPrompt, optio
|
|
|
28818
29134
|
}
|
|
28819
29135
|
|
|
28820
29136
|
// src/commands/review/synthesise.ts
|
|
28821
|
-
import { readFileSync as
|
|
29137
|
+
import { readFileSync as readFileSync44 } from "fs";
|
|
28822
29138
|
|
|
28823
29139
|
// src/commands/review/buildSynthesisStdin.ts
|
|
28824
29140
|
var SYNTHESIS_PROMPT = `You are consolidating two independent code reviews of the same change. The original review request is in request.md. The two reviews are in claude.md and codex.md in the current working directory.
|
|
@@ -28883,7 +29199,7 @@ Files:
|
|
|
28883
29199
|
|
|
28884
29200
|
// src/commands/review/synthesise.ts
|
|
28885
29201
|
function printSummary2(synthesisPath) {
|
|
28886
|
-
const markdown =
|
|
29202
|
+
const markdown = readFileSync44(synthesisPath, "utf8");
|
|
28887
29203
|
console.log("");
|
|
28888
29204
|
console.log(buildReviewSummary(markdown));
|
|
28889
29205
|
console.log("");
|
|
@@ -29117,7 +29433,7 @@ function registerReview(program2) {
|
|
|
29117
29433
|
}
|
|
29118
29434
|
|
|
29119
29435
|
// src/commands/seq/seqAuth.ts
|
|
29120
|
-
import
|
|
29436
|
+
import chalk205 from "chalk";
|
|
29121
29437
|
|
|
29122
29438
|
// src/commands/seq/loadConnections.ts
|
|
29123
29439
|
function loadConnections2() {
|
|
@@ -29146,10 +29462,10 @@ function setDefaultConnection(name) {
|
|
|
29146
29462
|
}
|
|
29147
29463
|
|
|
29148
29464
|
// src/shared/assertUniqueName.ts
|
|
29149
|
-
import
|
|
29465
|
+
import chalk204 from "chalk";
|
|
29150
29466
|
function assertUniqueName(existingNames, name) {
|
|
29151
29467
|
if (existingNames.includes(name)) {
|
|
29152
|
-
console.error(
|
|
29468
|
+
console.error(chalk204.red(`Connection "${name}" already exists.`));
|
|
29153
29469
|
process.exit(1);
|
|
29154
29470
|
}
|
|
29155
29471
|
}
|
|
@@ -29167,16 +29483,16 @@ async function promptConnection2(existingNames) {
|
|
|
29167
29483
|
var seqAuth = createConnectionAuth({
|
|
29168
29484
|
load: loadConnections2,
|
|
29169
29485
|
save: saveConnections2,
|
|
29170
|
-
format: (c) => `${
|
|
29486
|
+
format: (c) => `${chalk205.bold(c.name)} ${c.url}`,
|
|
29171
29487
|
promptNew: promptConnection2,
|
|
29172
29488
|
onFirst: (c) => setDefaultConnection(c.name)
|
|
29173
29489
|
});
|
|
29174
29490
|
|
|
29175
29491
|
// src/commands/seq/seqQuery.ts
|
|
29176
|
-
import
|
|
29492
|
+
import chalk209 from "chalk";
|
|
29177
29493
|
|
|
29178
29494
|
// src/commands/seq/fetchSeq.ts
|
|
29179
|
-
import
|
|
29495
|
+
import chalk206 from "chalk";
|
|
29180
29496
|
async function fetchSeq(conn, path80, params) {
|
|
29181
29497
|
const url = `${conn.url}${path80}?${params}`;
|
|
29182
29498
|
const response = await fetch(url, {
|
|
@@ -29187,7 +29503,7 @@ async function fetchSeq(conn, path80, params) {
|
|
|
29187
29503
|
});
|
|
29188
29504
|
if (!response.ok) {
|
|
29189
29505
|
const body = await response.text();
|
|
29190
|
-
console.error(
|
|
29506
|
+
console.error(chalk206.red(`Seq returned ${response.status}: ${body}`));
|
|
29191
29507
|
process.exit(1);
|
|
29192
29508
|
}
|
|
29193
29509
|
return response;
|
|
@@ -29246,23 +29562,23 @@ async function fetchSeqEvents(conn, params) {
|
|
|
29246
29562
|
}
|
|
29247
29563
|
|
|
29248
29564
|
// src/commands/seq/formatEvent.ts
|
|
29249
|
-
import
|
|
29565
|
+
import chalk207 from "chalk";
|
|
29250
29566
|
function levelColor(level) {
|
|
29251
29567
|
switch (level) {
|
|
29252
29568
|
case "Fatal":
|
|
29253
|
-
return
|
|
29569
|
+
return chalk207.bgRed.white;
|
|
29254
29570
|
case "Error":
|
|
29255
|
-
return
|
|
29571
|
+
return chalk207.red;
|
|
29256
29572
|
case "Warning":
|
|
29257
|
-
return
|
|
29573
|
+
return chalk207.yellow;
|
|
29258
29574
|
case "Information":
|
|
29259
|
-
return
|
|
29575
|
+
return chalk207.cyan;
|
|
29260
29576
|
case "Debug":
|
|
29261
|
-
return
|
|
29577
|
+
return chalk207.gray;
|
|
29262
29578
|
case "Verbose":
|
|
29263
|
-
return
|
|
29579
|
+
return chalk207.dim;
|
|
29264
29580
|
default:
|
|
29265
|
-
return
|
|
29581
|
+
return chalk207.white;
|
|
29266
29582
|
}
|
|
29267
29583
|
}
|
|
29268
29584
|
function levelAbbrev(level) {
|
|
@@ -29303,12 +29619,12 @@ function formatTimestamp(iso) {
|
|
|
29303
29619
|
function formatEvent(event) {
|
|
29304
29620
|
const color = levelColor(event.Level);
|
|
29305
29621
|
const abbrev = levelAbbrev(event.Level);
|
|
29306
|
-
const ts8 =
|
|
29622
|
+
const ts8 = chalk207.dim(formatTimestamp(event.Timestamp));
|
|
29307
29623
|
const msg = renderMessage(event);
|
|
29308
29624
|
const lines2 = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
|
|
29309
29625
|
if (event.Exception) {
|
|
29310
29626
|
for (const line of event.Exception.split("\n")) {
|
|
29311
|
-
lines2.push(
|
|
29627
|
+
lines2.push(chalk207.red(` ${line}`));
|
|
29312
29628
|
}
|
|
29313
29629
|
}
|
|
29314
29630
|
return lines2.join("\n");
|
|
@@ -29341,11 +29657,11 @@ function rejectTimestampFilter(filter) {
|
|
|
29341
29657
|
}
|
|
29342
29658
|
|
|
29343
29659
|
// src/shared/resolveNamedConnection.ts
|
|
29344
|
-
import
|
|
29660
|
+
import chalk208 from "chalk";
|
|
29345
29661
|
function resolveNamedConnection(connections, requested, defaultName, kind, authCommand) {
|
|
29346
29662
|
if (connections.length === 0) {
|
|
29347
29663
|
console.error(
|
|
29348
|
-
|
|
29664
|
+
chalk208.red(
|
|
29349
29665
|
`No ${kind} connections configured. Run '${authCommand}' first.`
|
|
29350
29666
|
)
|
|
29351
29667
|
);
|
|
@@ -29354,7 +29670,7 @@ function resolveNamedConnection(connections, requested, defaultName, kind, authC
|
|
|
29354
29670
|
const target = requested ?? defaultName ?? connections[0].name;
|
|
29355
29671
|
const connection = connections.find((c) => c.name === target);
|
|
29356
29672
|
if (!connection) {
|
|
29357
|
-
console.error(
|
|
29673
|
+
console.error(chalk208.red(`${kind} connection "${target}" not found.`));
|
|
29358
29674
|
process.exit(1);
|
|
29359
29675
|
}
|
|
29360
29676
|
return connection;
|
|
@@ -29383,7 +29699,7 @@ async function seqQuery(filter, options2) {
|
|
|
29383
29699
|
new URLSearchParams({ filter, count: String(count8) })
|
|
29384
29700
|
);
|
|
29385
29701
|
if (events.length === 0) {
|
|
29386
|
-
console.log(
|
|
29702
|
+
console.log(chalk209.yellow("No events found."));
|
|
29387
29703
|
return;
|
|
29388
29704
|
}
|
|
29389
29705
|
if (options2.json) {
|
|
@@ -29394,11 +29710,11 @@ async function seqQuery(filter, options2) {
|
|
|
29394
29710
|
for (const event of chronological) {
|
|
29395
29711
|
console.log(formatEvent(event));
|
|
29396
29712
|
}
|
|
29397
|
-
console.log(
|
|
29713
|
+
console.log(chalk209.dim(`
|
|
29398
29714
|
${events.length} events`));
|
|
29399
29715
|
if (events.length >= count8) {
|
|
29400
29716
|
console.log(
|
|
29401
|
-
|
|
29717
|
+
chalk209.yellow(
|
|
29402
29718
|
`Results limited to ${count8}. Use --count to retrieve more.`
|
|
29403
29719
|
)
|
|
29404
29720
|
);
|
|
@@ -29406,10 +29722,10 @@ ${events.length} events`));
|
|
|
29406
29722
|
}
|
|
29407
29723
|
|
|
29408
29724
|
// src/shared/setNamedDefaultConnection.ts
|
|
29409
|
-
import
|
|
29725
|
+
import chalk210 from "chalk";
|
|
29410
29726
|
function setNamedDefaultConnection(connections, name, setDefault, kind) {
|
|
29411
29727
|
if (!connections.find((c) => c.name === name)) {
|
|
29412
|
-
console.error(
|
|
29728
|
+
console.error(chalk210.red(`Connection "${name}" not found.`));
|
|
29413
29729
|
process.exit(1);
|
|
29414
29730
|
}
|
|
29415
29731
|
setDefault(name);
|
|
@@ -29458,7 +29774,7 @@ function registerSignal(program2) {
|
|
|
29458
29774
|
}
|
|
29459
29775
|
|
|
29460
29776
|
// src/commands/sql/sqlAuth.ts
|
|
29461
|
-
import
|
|
29777
|
+
import chalk212 from "chalk";
|
|
29462
29778
|
|
|
29463
29779
|
// src/commands/sql/loadConnections.ts
|
|
29464
29780
|
function loadConnections3() {
|
|
@@ -29487,7 +29803,7 @@ function setDefaultConnection2(name) {
|
|
|
29487
29803
|
}
|
|
29488
29804
|
|
|
29489
29805
|
// src/commands/sql/promptConnection.ts
|
|
29490
|
-
import
|
|
29806
|
+
import chalk211 from "chalk";
|
|
29491
29807
|
async function promptConnection3(existingNames) {
|
|
29492
29808
|
const name = await promptInput("name", "Connection name:", "default");
|
|
29493
29809
|
assertUniqueName(existingNames, name);
|
|
@@ -29495,7 +29811,7 @@ async function promptConnection3(existingNames) {
|
|
|
29495
29811
|
const portStr = await promptInput("port", "Port:", "1433");
|
|
29496
29812
|
const port = Number.parseInt(portStr, 10);
|
|
29497
29813
|
if (!Number.isFinite(port)) {
|
|
29498
|
-
console.error(
|
|
29814
|
+
console.error(chalk211.red(`Invalid port "${portStr}".`));
|
|
29499
29815
|
process.exit(1);
|
|
29500
29816
|
}
|
|
29501
29817
|
const user = await promptInput("user", "User:");
|
|
@@ -29508,13 +29824,13 @@ async function promptConnection3(existingNames) {
|
|
|
29508
29824
|
var sqlAuth = createConnectionAuth({
|
|
29509
29825
|
load: loadConnections3,
|
|
29510
29826
|
save: saveConnections3,
|
|
29511
|
-
format: (c) => `${
|
|
29827
|
+
format: (c) => `${chalk212.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
|
|
29512
29828
|
promptNew: promptConnection3,
|
|
29513
29829
|
onFirst: (c) => setDefaultConnection2(c.name)
|
|
29514
29830
|
});
|
|
29515
29831
|
|
|
29516
29832
|
// src/commands/sql/printTable.ts
|
|
29517
|
-
import
|
|
29833
|
+
import chalk213 from "chalk";
|
|
29518
29834
|
function formatCell(value) {
|
|
29519
29835
|
if (value === null || value === void 0) return "";
|
|
29520
29836
|
if (value instanceof Date) return value.toISOString();
|
|
@@ -29523,7 +29839,7 @@ function formatCell(value) {
|
|
|
29523
29839
|
}
|
|
29524
29840
|
function printTable(rows) {
|
|
29525
29841
|
if (rows.length === 0) {
|
|
29526
|
-
console.log(
|
|
29842
|
+
console.log(chalk213.yellow("(no rows)"));
|
|
29527
29843
|
return;
|
|
29528
29844
|
}
|
|
29529
29845
|
const columns = Object.keys(rows[0]);
|
|
@@ -29531,13 +29847,13 @@ function printTable(rows) {
|
|
|
29531
29847
|
(col) => Math.max(col.length, ...rows.map((r) => formatCell(r[col]).length))
|
|
29532
29848
|
);
|
|
29533
29849
|
const header = columns.map((c, i) => c.padEnd(widths[i])).join(" ");
|
|
29534
|
-
console.log(
|
|
29535
|
-
console.log(
|
|
29850
|
+
console.log(chalk213.dim(header));
|
|
29851
|
+
console.log(chalk213.dim("-".repeat(header.length)));
|
|
29536
29852
|
for (const row of rows) {
|
|
29537
29853
|
const line = columns.map((c, i) => formatCell(row[c]).padEnd(widths[i])).join(" ");
|
|
29538
29854
|
console.log(line);
|
|
29539
29855
|
}
|
|
29540
|
-
console.log(
|
|
29856
|
+
console.log(chalk213.dim(`
|
|
29541
29857
|
${rows.length} row${rows.length === 1 ? "" : "s"}`));
|
|
29542
29858
|
}
|
|
29543
29859
|
|
|
@@ -29597,7 +29913,7 @@ async function sqlColumns(table, connectionName) {
|
|
|
29597
29913
|
}
|
|
29598
29914
|
|
|
29599
29915
|
// src/commands/sql/sqlMutate.ts
|
|
29600
|
-
import
|
|
29916
|
+
import chalk214 from "chalk";
|
|
29601
29917
|
|
|
29602
29918
|
// src/commands/sql/isMutation.ts
|
|
29603
29919
|
var MUTATION_KEYWORDS = [
|
|
@@ -29631,7 +29947,7 @@ function isMutation(sql25) {
|
|
|
29631
29947
|
async function sqlMutate(query, connectionName) {
|
|
29632
29948
|
if (!isMutation(query)) {
|
|
29633
29949
|
console.error(
|
|
29634
|
-
|
|
29950
|
+
chalk214.red(
|
|
29635
29951
|
"assist sql mutate refuses non-mutating statements. Use `assist sql query` instead."
|
|
29636
29952
|
)
|
|
29637
29953
|
);
|
|
@@ -29641,18 +29957,18 @@ async function sqlMutate(query, connectionName) {
|
|
|
29641
29957
|
const pool = await sqlConnect(conn);
|
|
29642
29958
|
try {
|
|
29643
29959
|
const result = await pool.request().query(query);
|
|
29644
|
-
console.log(
|
|
29960
|
+
console.log(chalk214.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
|
|
29645
29961
|
} finally {
|
|
29646
29962
|
await pool.close();
|
|
29647
29963
|
}
|
|
29648
29964
|
}
|
|
29649
29965
|
|
|
29650
29966
|
// src/commands/sql/sqlQuery.ts
|
|
29651
|
-
import
|
|
29967
|
+
import chalk215 from "chalk";
|
|
29652
29968
|
async function sqlQuery(query, connectionName) {
|
|
29653
29969
|
if (isMutation(query)) {
|
|
29654
29970
|
console.error(
|
|
29655
|
-
|
|
29971
|
+
chalk215.red(
|
|
29656
29972
|
"assist sql query refuses mutating statements. Use `assist sql mutate` instead."
|
|
29657
29973
|
)
|
|
29658
29974
|
);
|
|
@@ -29667,7 +29983,7 @@ async function sqlQuery(query, connectionName) {
|
|
|
29667
29983
|
printTable(rows);
|
|
29668
29984
|
} else {
|
|
29669
29985
|
console.log(
|
|
29670
|
-
|
|
29986
|
+
chalk215.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
|
|
29671
29987
|
);
|
|
29672
29988
|
}
|
|
29673
29989
|
} finally {
|
|
@@ -29812,7 +30128,7 @@ function reportPrune(label2, result, force) {
|
|
|
29812
30128
|
// src/commands/sync/syncClaudeMd.ts
|
|
29813
30129
|
import * as fs41 from "fs";
|
|
29814
30130
|
import * as path66 from "path";
|
|
29815
|
-
import
|
|
30131
|
+
import chalk216 from "chalk";
|
|
29816
30132
|
async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
29817
30133
|
const source = path66.join(claudeDir, "CLAUDE.md");
|
|
29818
30134
|
const target = path66.join(targetBase, "CLAUDE.md");
|
|
@@ -29821,14 +30137,14 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
|
29821
30137
|
const targetContent = fs41.readFileSync(target, "utf8");
|
|
29822
30138
|
if (sourceContent !== targetContent) {
|
|
29823
30139
|
console.log(
|
|
29824
|
-
|
|
30140
|
+
chalk216.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
29825
30141
|
);
|
|
29826
30142
|
console.log();
|
|
29827
30143
|
printDiff(targetContent, sourceContent);
|
|
29828
30144
|
if (!options2?.yes) {
|
|
29829
30145
|
printAutoConfirmHint();
|
|
29830
30146
|
const confirm = await promptConfirm(
|
|
29831
|
-
|
|
30147
|
+
chalk216.red("Overwrite existing CLAUDE.md?"),
|
|
29832
30148
|
false
|
|
29833
30149
|
);
|
|
29834
30150
|
if (!confirm) {
|
|
@@ -30061,7 +30377,7 @@ function syncPi(claudeDir, options2) {
|
|
|
30061
30377
|
// src/commands/sync/syncSettings.ts
|
|
30062
30378
|
import * as fs47 from "fs";
|
|
30063
30379
|
import * as path73 from "path";
|
|
30064
|
-
import
|
|
30380
|
+
import chalk217 from "chalk";
|
|
30065
30381
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
30066
30382
|
const source = path73.join(claudeDir, "settings.json");
|
|
30067
30383
|
const target = path73.join(targetBase, "settings.json");
|
|
@@ -30080,7 +30396,7 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
30080
30396
|
if (mergedContent !== normalizedTarget) {
|
|
30081
30397
|
if (!options2?.yes) {
|
|
30082
30398
|
console.log(
|
|
30083
|
-
|
|
30399
|
+
chalk217.yellow(
|
|
30084
30400
|
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
30085
30401
|
)
|
|
30086
30402
|
);
|
|
@@ -30088,7 +30404,7 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
30088
30404
|
printDiff(targetContent, mergedContent);
|
|
30089
30405
|
printAutoConfirmHint();
|
|
30090
30406
|
const confirm = await promptConfirm(
|
|
30091
|
-
|
|
30407
|
+
chalk217.red("Overwrite existing settings.json?"),
|
|
30092
30408
|
false
|
|
30093
30409
|
);
|
|
30094
30410
|
if (!confirm) {
|
|
@@ -30246,7 +30562,7 @@ function list4() {
|
|
|
30246
30562
|
import {
|
|
30247
30563
|
existsSync as existsSync63,
|
|
30248
30564
|
mkdirSync as mkdirSync26,
|
|
30249
|
-
readFileSync as
|
|
30565
|
+
readFileSync as readFileSync49,
|
|
30250
30566
|
renameSync as renameSync2,
|
|
30251
30567
|
writeFileSync as writeFileSync42
|
|
30252
30568
|
} from "fs";
|
|
@@ -30458,7 +30774,7 @@ function formatChatLog(messages) {
|
|
|
30458
30774
|
// src/commands/transcript/move.ts
|
|
30459
30775
|
var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
30460
30776
|
function convertVttToMarkdown(inputPath) {
|
|
30461
|
-
const cues = parseVtt(
|
|
30777
|
+
const cues = parseVtt(readFileSync49(inputPath, "utf8"));
|
|
30462
30778
|
const messages = cuesToChatMessages(deduplicateCues(cues));
|
|
30463
30779
|
return formatChatLog(messages);
|
|
30464
30780
|
}
|
|
@@ -30605,14 +30921,14 @@ function devices() {
|
|
|
30605
30921
|
}
|
|
30606
30922
|
|
|
30607
30923
|
// src/commands/voice/logs.ts
|
|
30608
|
-
import { existsSync as existsSync64, readFileSync as
|
|
30924
|
+
import { existsSync as existsSync64, readFileSync as readFileSync50 } from "fs";
|
|
30609
30925
|
function logs(options2) {
|
|
30610
30926
|
if (!existsSync64(voicePaths.log)) {
|
|
30611
30927
|
console.log("No voice log file found");
|
|
30612
30928
|
return;
|
|
30613
30929
|
}
|
|
30614
30930
|
const count8 = Number.parseInt(options2.lines ?? "150", 10);
|
|
30615
|
-
const content =
|
|
30931
|
+
const content = readFileSync50(voicePaths.log, "utf8").trim();
|
|
30616
30932
|
if (!content) {
|
|
30617
30933
|
console.log("Voice log is empty");
|
|
30618
30934
|
return;
|
|
@@ -30639,7 +30955,7 @@ import { join as join82 } from "path";
|
|
|
30639
30955
|
|
|
30640
30956
|
// src/commands/voice/checkLockFile.ts
|
|
30641
30957
|
import { execSync as execSync58 } from "child_process";
|
|
30642
|
-
import { existsSync as existsSync65, mkdirSync as mkdirSync27, readFileSync as
|
|
30958
|
+
import { existsSync as existsSync65, mkdirSync as mkdirSync27, readFileSync as readFileSync51, writeFileSync as writeFileSync43 } from "fs";
|
|
30643
30959
|
import { join as join81 } from "path";
|
|
30644
30960
|
function isProcessAlive2(pid) {
|
|
30645
30961
|
try {
|
|
@@ -30653,7 +30969,7 @@ function checkLockFile() {
|
|
|
30653
30969
|
const lockFile = getLockFile();
|
|
30654
30970
|
if (!existsSync65(lockFile)) return;
|
|
30655
30971
|
try {
|
|
30656
|
-
const lock2 = JSON.parse(
|
|
30972
|
+
const lock2 = JSON.parse(readFileSync51(lockFile, "utf8"));
|
|
30657
30973
|
if (lock2.pid && isProcessAlive2(lock2.pid)) {
|
|
30658
30974
|
console.error(
|
|
30659
30975
|
`Voice daemon already running (PID ${lock2.pid}, env: ${lock2.env}). Stop it first with: assist voice stop`
|
|
@@ -30755,7 +31071,7 @@ function start2(options2) {
|
|
|
30755
31071
|
}
|
|
30756
31072
|
|
|
30757
31073
|
// src/commands/voice/status.ts
|
|
30758
|
-
import { existsSync as existsSync66, readFileSync as
|
|
31074
|
+
import { existsSync as existsSync66, readFileSync as readFileSync52 } from "fs";
|
|
30759
31075
|
function isProcessAlive3(pid) {
|
|
30760
31076
|
try {
|
|
30761
31077
|
process.kill(pid, 0);
|
|
@@ -30766,7 +31082,7 @@ function isProcessAlive3(pid) {
|
|
|
30766
31082
|
}
|
|
30767
31083
|
function readRecentLogs(count8) {
|
|
30768
31084
|
if (!existsSync66(voicePaths.log)) return [];
|
|
30769
|
-
const lines2 =
|
|
31085
|
+
const lines2 = readFileSync52(voicePaths.log, "utf8").trim().split("\n");
|
|
30770
31086
|
return lines2.slice(-count8);
|
|
30771
31087
|
}
|
|
30772
31088
|
function status2() {
|
|
@@ -30774,7 +31090,7 @@ function status2() {
|
|
|
30774
31090
|
console.log("Voice daemon: not running (no PID file)");
|
|
30775
31091
|
return;
|
|
30776
31092
|
}
|
|
30777
|
-
const pid = Number.parseInt(
|
|
31093
|
+
const pid = Number.parseInt(readFileSync52(voicePaths.pid, "utf8").trim(), 10);
|
|
30778
31094
|
const alive = isProcessAlive3(pid);
|
|
30779
31095
|
console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
|
|
30780
31096
|
const recent = readRecentLogs(5);
|
|
@@ -30793,13 +31109,13 @@ function status2() {
|
|
|
30793
31109
|
}
|
|
30794
31110
|
|
|
30795
31111
|
// src/commands/voice/stop.ts
|
|
30796
|
-
import { existsSync as existsSync67, readFileSync as
|
|
31112
|
+
import { existsSync as existsSync67, readFileSync as readFileSync53, unlinkSync as unlinkSync20 } from "fs";
|
|
30797
31113
|
function stop2() {
|
|
30798
31114
|
if (!existsSync67(voicePaths.pid)) {
|
|
30799
31115
|
console.log("Voice daemon is not running (no PID file)");
|
|
30800
31116
|
return;
|
|
30801
31117
|
}
|
|
30802
|
-
const pid = Number.parseInt(
|
|
31118
|
+
const pid = Number.parseInt(readFileSync53(voicePaths.pid, "utf8").trim(), 10);
|
|
30803
31119
|
try {
|
|
30804
31120
|
process.kill(pid, "SIGTERM");
|
|
30805
31121
|
console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
|
|
@@ -31515,7 +31831,7 @@ function registerWatch(program2) {
|
|
|
31515
31831
|
|
|
31516
31832
|
// src/commands/roam/auth.ts
|
|
31517
31833
|
import { randomBytes } from "crypto";
|
|
31518
|
-
import
|
|
31834
|
+
import chalk218 from "chalk";
|
|
31519
31835
|
|
|
31520
31836
|
// src/commands/roam/waitForCallback.ts
|
|
31521
31837
|
import { createServer as createServer3 } from "http";
|
|
@@ -31646,13 +31962,13 @@ async function auth() {
|
|
|
31646
31962
|
saveGlobalConfig(config);
|
|
31647
31963
|
const state = randomBytes(16).toString("hex");
|
|
31648
31964
|
console.log(
|
|
31649
|
-
|
|
31965
|
+
chalk218.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
31650
31966
|
);
|
|
31651
|
-
console.log(
|
|
31652
|
-
console.log(
|
|
31653
|
-
console.log(
|
|
31967
|
+
console.log(chalk218.white("http://localhost:14523/callback\n"));
|
|
31968
|
+
console.log(chalk218.blue("Opening browser for authorization..."));
|
|
31969
|
+
console.log(chalk218.dim("Waiting for authorization callback..."));
|
|
31654
31970
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
31655
|
-
console.log(
|
|
31971
|
+
console.log(chalk218.dim("Exchanging code for tokens..."));
|
|
31656
31972
|
const tokens = await exchangeToken({
|
|
31657
31973
|
code,
|
|
31658
31974
|
clientId,
|
|
@@ -31668,13 +31984,13 @@ async function auth() {
|
|
|
31668
31984
|
};
|
|
31669
31985
|
saveGlobalConfig(config);
|
|
31670
31986
|
console.log(
|
|
31671
|
-
|
|
31987
|
+
chalk218.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
31672
31988
|
);
|
|
31673
31989
|
}
|
|
31674
31990
|
|
|
31675
31991
|
// src/commands/roam/postRoamActivity.ts
|
|
31676
31992
|
import { execFileSync as execFileSync18 } from "child_process";
|
|
31677
|
-
import { readdirSync as readdirSync20, readFileSync as
|
|
31993
|
+
import { readdirSync as readdirSync20, readFileSync as readFileSync54, statSync as statSync11 } from "fs";
|
|
31678
31994
|
import { join as join86 } from "path";
|
|
31679
31995
|
function findPortFile(roamDir) {
|
|
31680
31996
|
let entries;
|
|
@@ -31700,7 +32016,7 @@ function postRoamActivity(app, event) {
|
|
|
31700
32016
|
if (!portFile) return;
|
|
31701
32017
|
let port;
|
|
31702
32018
|
try {
|
|
31703
|
-
port =
|
|
32019
|
+
port = readFileSync54(portFile, "utf8").trim();
|
|
31704
32020
|
} catch {
|
|
31705
32021
|
return;
|
|
31706
32022
|
}
|
|
@@ -32019,7 +32335,7 @@ import { execSync as execSync60 } from "child_process";
|
|
|
32019
32335
|
import { existsSync as existsSync72, mkdirSync as mkdirSync31, unlinkSync as unlinkSync22, writeFileSync as writeFileSync46 } from "fs";
|
|
32020
32336
|
import { tmpdir as tmpdir8 } from "os";
|
|
32021
32337
|
import { join as join89, resolve as resolve20 } from "path";
|
|
32022
|
-
import
|
|
32338
|
+
import chalk219 from "chalk";
|
|
32023
32339
|
|
|
32024
32340
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
32025
32341
|
var captureWindowPs1 = `
|
|
@@ -32170,13 +32486,13 @@ function screenshot(processName) {
|
|
|
32170
32486
|
const config = loadConfig();
|
|
32171
32487
|
const outputDir = resolve20(config.screenshot.outputDir);
|
|
32172
32488
|
const outputPath = buildOutputPath(outputDir, processName);
|
|
32173
|
-
console.log(
|
|
32489
|
+
console.log(chalk219.gray(`Capturing window for process "${processName}" ...`));
|
|
32174
32490
|
try {
|
|
32175
32491
|
runPowerShellScript(processName, outputPath);
|
|
32176
|
-
console.log(
|
|
32492
|
+
console.log(chalk219.green(`Screenshot saved: ${outputPath}`));
|
|
32177
32493
|
} catch (error) {
|
|
32178
32494
|
const msg = error instanceof Error ? error.message : String(error);
|
|
32179
|
-
console.error(
|
|
32495
|
+
console.error(chalk219.red(`Failed to capture screenshot: ${msg}`));
|
|
32180
32496
|
process.exit(1);
|
|
32181
32497
|
}
|
|
32182
32498
|
}
|
|
@@ -32232,11 +32548,11 @@ function applyLine(result, pending, line) {
|
|
|
32232
32548
|
}
|
|
32233
32549
|
|
|
32234
32550
|
// src/commands/sessions/daemon/readDaemonPidFile.ts
|
|
32235
|
-
import { readFileSync as
|
|
32551
|
+
import { readFileSync as readFileSync55 } from "fs";
|
|
32236
32552
|
function readDaemonPidFile() {
|
|
32237
32553
|
try {
|
|
32238
32554
|
const pid = Number.parseInt(
|
|
32239
|
-
|
|
32555
|
+
readFileSync55(daemonPaths.pid, "utf8").trim(),
|
|
32240
32556
|
10
|
|
32241
32557
|
);
|
|
32242
32558
|
return Number.isInteger(pid) ? pid : void 0;
|
|
@@ -36267,14 +36583,14 @@ async function defaultConnect() {
|
|
|
36267
36583
|
}
|
|
36268
36584
|
|
|
36269
36585
|
// src/commands/sessions/daemon/hasPersistedWindowsSessions.ts
|
|
36270
|
-
import { existsSync as existsSync84, readFileSync as
|
|
36586
|
+
import { existsSync as existsSync84, readFileSync as readFileSync57 } from "fs";
|
|
36271
36587
|
import { posix as posix3 } from "path";
|
|
36272
36588
|
function hasPersistedWindowsSessions() {
|
|
36273
36589
|
const sessionsFile = windowsSessionsFileFromWsl();
|
|
36274
36590
|
if (!sessionsFile) return false;
|
|
36275
36591
|
try {
|
|
36276
36592
|
if (!existsSync84(sessionsFile)) return false;
|
|
36277
|
-
const data = JSON.parse(
|
|
36593
|
+
const data = JSON.parse(readFileSync57(sessionsFile, "utf8"));
|
|
36278
36594
|
return Array.isArray(data) && data.length > 0;
|
|
36279
36595
|
} catch (error) {
|
|
36280
36596
|
const message3 = error instanceof Error ? error.message : String(error);
|
|
@@ -37692,7 +38008,7 @@ function handleConnection(socket, manager) {
|
|
|
37692
38008
|
import { unlinkSync as unlinkSync23, writeFileSync as writeFileSync47 } from "fs";
|
|
37693
38009
|
|
|
37694
38010
|
// src/commands/sessions/daemon/startPidFileWatchdog.ts
|
|
37695
|
-
import { readFileSync as
|
|
38011
|
+
import { readFileSync as readFileSync58 } from "fs";
|
|
37696
38012
|
var WATCHDOG_INTERVAL_MS = 5e3;
|
|
37697
38013
|
function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
|
|
37698
38014
|
const timer = setInterval(() => {
|
|
@@ -37703,7 +38019,7 @@ function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
|
|
|
37703
38019
|
}
|
|
37704
38020
|
function ownsPidFile() {
|
|
37705
38021
|
try {
|
|
37706
|
-
return
|
|
38022
|
+
return readFileSync58(daemonPaths.pid, "utf8").trim() === String(process.pid);
|
|
37707
38023
|
} catch {
|
|
37708
38024
|
return false;
|
|
37709
38025
|
}
|
|
@@ -37953,7 +38269,7 @@ function registerSetStatusCommand(cmd) {
|
|
|
37953
38269
|
|
|
37954
38270
|
// src/commands/sessions/summarise/index.ts
|
|
37955
38271
|
import * as fs56 from "fs";
|
|
37956
|
-
import
|
|
38272
|
+
import chalk220 from "chalk";
|
|
37957
38273
|
|
|
37958
38274
|
// src/commands/sessions/summarise/shared.ts
|
|
37959
38275
|
import * as fs55 from "fs";
|
|
@@ -38012,22 +38328,22 @@ ${firstMessage}`);
|
|
|
38012
38328
|
async function summarise2(options2) {
|
|
38013
38329
|
const files = await discoverSessionFiles();
|
|
38014
38330
|
if (files.length === 0) {
|
|
38015
|
-
console.log(
|
|
38331
|
+
console.log(chalk220.yellow("No sessions found."));
|
|
38016
38332
|
return;
|
|
38017
38333
|
}
|
|
38018
38334
|
const toProcess = selectCandidates(files, options2);
|
|
38019
38335
|
if (toProcess.length === 0) {
|
|
38020
|
-
console.log(
|
|
38336
|
+
console.log(chalk220.green("All sessions already summarised."));
|
|
38021
38337
|
return;
|
|
38022
38338
|
}
|
|
38023
38339
|
console.log(
|
|
38024
|
-
|
|
38340
|
+
chalk220.cyan(
|
|
38025
38341
|
`Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
|
|
38026
38342
|
)
|
|
38027
38343
|
);
|
|
38028
38344
|
const { succeeded, failed: failed2 } = processSessions(toProcess);
|
|
38029
38345
|
console.log(
|
|
38030
|
-
|
|
38346
|
+
chalk220.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk220.yellow(`, ${failed2} skipped`) : "")
|
|
38031
38347
|
);
|
|
38032
38348
|
}
|
|
38033
38349
|
function selectCandidates(files, options2) {
|
|
@@ -38047,16 +38363,16 @@ function processSessions(files) {
|
|
|
38047
38363
|
let failed2 = 0;
|
|
38048
38364
|
for (let i = 0; i < files.length; i++) {
|
|
38049
38365
|
const file = files[i];
|
|
38050
|
-
process.stdout.write(
|
|
38366
|
+
process.stdout.write(chalk220.dim(` [${i + 1}/${files.length}] `));
|
|
38051
38367
|
const summary = summariseSession(file);
|
|
38052
38368
|
if (summary) {
|
|
38053
38369
|
writeSummary(file, summary);
|
|
38054
38370
|
succeeded++;
|
|
38055
|
-
process.stdout.write(`${
|
|
38371
|
+
process.stdout.write(`${chalk220.green("\u2713")} ${summary}
|
|
38056
38372
|
`);
|
|
38057
38373
|
} else {
|
|
38058
38374
|
failed2++;
|
|
38059
|
-
process.stdout.write(` ${
|
|
38375
|
+
process.stdout.write(` ${chalk220.yellow("skip")}
|
|
38060
38376
|
`);
|
|
38061
38377
|
}
|
|
38062
38378
|
}
|
|
@@ -38077,7 +38393,7 @@ function registerSessions(program2) {
|
|
|
38077
38393
|
}
|
|
38078
38394
|
|
|
38079
38395
|
// src/commands/statusLine.ts
|
|
38080
|
-
import
|
|
38396
|
+
import chalk222 from "chalk";
|
|
38081
38397
|
|
|
38082
38398
|
// src/shared/contextLevel.ts
|
|
38083
38399
|
function contextLevel(pct) {
|
|
@@ -38087,7 +38403,7 @@ function contextLevel(pct) {
|
|
|
38087
38403
|
}
|
|
38088
38404
|
|
|
38089
38405
|
// src/commands/buildLimitsSegment.ts
|
|
38090
|
-
import
|
|
38406
|
+
import chalk221 from "chalk";
|
|
38091
38407
|
|
|
38092
38408
|
// src/shared/rateLimitLevel.ts
|
|
38093
38409
|
var FIVE_HOUR_SECONDS = 5 * 3600;
|
|
@@ -38125,9 +38441,9 @@ function rateLimitLevel(pct, resetsAt, windowSeconds, now) {
|
|
|
38125
38441
|
|
|
38126
38442
|
// src/commands/buildLimitsSegment.ts
|
|
38127
38443
|
var LEVEL_COLOR = {
|
|
38128
|
-
ok:
|
|
38129
|
-
warn:
|
|
38130
|
-
over:
|
|
38444
|
+
ok: chalk221.green,
|
|
38445
|
+
warn: chalk221.yellow,
|
|
38446
|
+
over: chalk221.red
|
|
38131
38447
|
};
|
|
38132
38448
|
function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel, now) {
|
|
38133
38449
|
const level = rateLimitLevel(pct, resetsAt, windowSeconds, now);
|
|
@@ -38158,7 +38474,7 @@ function buildLimitsSegment(rateLimits) {
|
|
|
38158
38474
|
}
|
|
38159
38475
|
|
|
38160
38476
|
// src/commands/readGitBranch.ts
|
|
38161
|
-
import { readFileSync as
|
|
38477
|
+
import { readFileSync as readFileSync60, statSync as statSync15 } from "fs";
|
|
38162
38478
|
import { isAbsolute as isAbsolute4, join as join95, resolve as resolve22 } from "path";
|
|
38163
38479
|
function resolveGitDir(cwd) {
|
|
38164
38480
|
const dotGit = join95(cwd, ".git");
|
|
@@ -38173,7 +38489,7 @@ function resolveGitDir(cwd) {
|
|
|
38173
38489
|
}
|
|
38174
38490
|
let contents;
|
|
38175
38491
|
try {
|
|
38176
|
-
contents =
|
|
38492
|
+
contents = readFileSync60(dotGit, "utf8");
|
|
38177
38493
|
} catch {
|
|
38178
38494
|
return null;
|
|
38179
38495
|
}
|
|
@@ -38191,7 +38507,7 @@ function readGitBranch(cwd) {
|
|
|
38191
38507
|
}
|
|
38192
38508
|
let head;
|
|
38193
38509
|
try {
|
|
38194
|
-
head =
|
|
38510
|
+
head = readFileSync60(join95(gitDir, "HEAD"), "utf8");
|
|
38195
38511
|
} catch {
|
|
38196
38512
|
return null;
|
|
38197
38513
|
}
|
|
@@ -38223,7 +38539,7 @@ async function relayUsage(claudeSessionId, transcriptPath2, usedPct) {
|
|
|
38223
38539
|
}
|
|
38224
38540
|
|
|
38225
38541
|
// src/commands/statusLine.ts
|
|
38226
|
-
|
|
38542
|
+
chalk222.level = 3;
|
|
38227
38543
|
function formatNumber(num) {
|
|
38228
38544
|
return num.toLocaleString("en-US");
|
|
38229
38545
|
}
|
|
@@ -38231,9 +38547,9 @@ function colorizePercent(pct) {
|
|
|
38231
38547
|
const label2 = `${Math.round(pct)}%`;
|
|
38232
38548
|
switch (contextLevel(pct)) {
|
|
38233
38549
|
case "red":
|
|
38234
|
-
return
|
|
38550
|
+
return chalk222.red(label2);
|
|
38235
38551
|
case "yellow":
|
|
38236
|
-
return
|
|
38552
|
+
return chalk222.yellow(label2);
|
|
38237
38553
|
default:
|
|
38238
38554
|
return label2;
|
|
38239
38555
|
}
|
|
@@ -38246,7 +38562,7 @@ async function statusLine() {
|
|
|
38246
38562
|
const usedPct = data.context_window.used_percentage ?? 0;
|
|
38247
38563
|
const dir = data.workspace?.current_dir ?? data.cwd;
|
|
38248
38564
|
const branch2 = dir ? readGitBranch(toGitCwd(dir)) : null;
|
|
38249
|
-
const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${
|
|
38565
|
+
const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${chalk222.cyan(branch2)} | ` : "";
|
|
38250
38566
|
console.log(
|
|
38251
38567
|
`${branchSegment}${model} | Tokens - ${formatNumber(totalIn)} \u2191 : ${formatNumber(totalOut)} \u2193 | Context - ${colorizePercent(usedPct)}${buildLimitsSegment(data.rate_limits)}`
|
|
38252
38568
|
);
|
|
@@ -38316,10 +38632,10 @@ async function update2() {
|
|
|
38316
38632
|
}
|
|
38317
38633
|
|
|
38318
38634
|
// src/reportCliError.ts
|
|
38319
|
-
import
|
|
38635
|
+
import chalk223 from "chalk";
|
|
38320
38636
|
function reportCliError(error) {
|
|
38321
|
-
if (error instanceof InvalidItemIdError || error instanceof AmbiguousRepoConfigError || error instanceof UnknownRepoConfigError || error instanceof MissingRunCwdError) {
|
|
38322
|
-
console.error(
|
|
38637
|
+
if (error instanceof InvalidItemIdError || error instanceof AmbiguousRepoConfigError || error instanceof UnknownRepoConfigError || error instanceof MissingRunCwdError || error instanceof MiroExtractError) {
|
|
38638
|
+
console.error(chalk223.red(error.message));
|
|
38323
38639
|
} else {
|
|
38324
38640
|
console.error(error);
|
|
38325
38641
|
}
|
|
@@ -38362,6 +38678,7 @@ registerGithub(program);
|
|
|
38362
38678
|
registerHandover(program);
|
|
38363
38679
|
registerJira(program);
|
|
38364
38680
|
registerMermaid(program);
|
|
38681
|
+
registerMiro(program);
|
|
38365
38682
|
registerPrs(program);
|
|
38366
38683
|
registerRoam(program);
|
|
38367
38684
|
registerBacklog(program);
|