@staff0rd/assist 0.219.0 → 0.220.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 +1 -1
- package/dist/index.js +218 -123
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -88,7 +88,7 @@ After installation, the `assist` command will be available globally. You can als
|
|
|
88
88
|
- `assist prs fixed <comment-id> <sha>` - Reply with commit link and resolve thread
|
|
89
89
|
- `assist prs wontfix <comment-id> <reason>` - Reply with reason and resolve thread
|
|
90
90
|
- `assist prs comment <path> <line> <body>` - Add a line comment to the pending review
|
|
91
|
-
- `assist review [--no-prompt] [--submit] [--force] [--refine] [--apply] [--verbose]` - Run Claude and Codex in parallel to review the open PR for the current branch. The diff is fetched from GitHub (base SHA → head SHA via `gh pr diff`), so stale local base branches don't pollute the review; fails fast if no PR is open. By default, prompts before posting line-bound comments and then prompts again to submit the pending review (defaulting to no). Cached `claude.md` / `codex.md` / `synthesis.md` are reused when present; if any reviewer is re-run, the synthesis is invalidated. `--no-prompt` skips all confirmations. `--submit` defaults the submit prompt to yes (or auto-submits when combined with `--no-prompt`). `--force` clears all cached files and re-runs every phase. `--refine` skips posting and instead launches an interactive Claude session that walks through `synthesis.md` and edits it in place; a subsequent `assist review` (no flag) reuses the refined file and posts only the surviving findings. `--apply` skips posting and instead launches an interactive Claude session that walks through each remaining finding asking apply/skip; applied findings have their code fix made in the working tree (unstaged) and are removed from `synthesis.md`, while skipped findings stay so a subsequent `assist review` posts them. `--apply` cannot be combined with `--refine`. `--verbose` disables the stacked-spinner UI and falls back to per-line log output (per-tool lines, starting/done lines); non-TTY environments (CI) automatically fall back to verbose-style output
|
|
91
|
+
- `assist review [sha] [--no-prompt] [--submit] [--force] [--refine] [--apply] [--verbose]` - Run Claude and Codex in parallel to review the open PR for the current branch. The diff is fetched from GitHub (base SHA → head SHA via `gh pr diff`), so stale local base branches don't pollute the review; fails fast if no PR is open. By default, prompts before posting line-bound comments and then prompts again to submit the pending review (defaulting to no). Cached `claude.md` / `codex.md` / `synthesis.md` are reused when present; if any reviewer is re-run, the synthesis is invalidated. `--no-prompt` skips all confirmations. `--submit` defaults the submit prompt to yes (or auto-submits when combined with `--no-prompt`). `--force` clears all cached files and re-runs every phase. `--refine` skips posting and instead launches an interactive Claude session that walks through `synthesis.md` and edits it in place; a subsequent `assist review` (no flag) reuses the refined file and posts only the surviving findings. `--apply` skips posting and instead launches an interactive Claude session that walks through each remaining finding asking apply/skip; applied findings have their code fix made in the working tree (unstaged) and are removed from `synthesis.md`, while skipped findings stay so a subsequent `assist review` posts them. `--apply` cannot be combined with `--refine`. `--verbose` disables the stacked-spinner UI and falls back to per-line log output (per-tool lines, starting/done lines); non-TTY environments (CI) automatically fall back to verbose-style output. Pass a commit `<sha>` to review that commit's diff (`sha^..sha`) instead; the review files land under `.assist/reviews/<shortSha>/`, no GitHub lookup or posting happens, and `--refine` / `--apply` / `--submit` are rejected.
|
|
92
92
|
- `assist news` - Start the news web UI showing latest RSS feed items (same as `news web`)
|
|
93
93
|
- `assist news add [url]` - Add an RSS feed URL to the config
|
|
94
94
|
- `assist news web [-p, --port <number>]` - Start a web view of the news feeds (default port 3001)
|
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.220.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -11639,60 +11639,6 @@ function registerRefactor(program2) {
|
|
|
11639
11639
|
registerRestructure(refactorCommand);
|
|
11640
11640
|
}
|
|
11641
11641
|
|
|
11642
|
-
// src/commands/review/buildRequest.ts
|
|
11643
|
-
import { execSync as execSync38 } from "child_process";
|
|
11644
|
-
|
|
11645
|
-
// src/commands/review/fetchPrDiffInfo.ts
|
|
11646
|
-
import { execSync as execSync37 } from "child_process";
|
|
11647
|
-
function getCurrentBranch2() {
|
|
11648
|
-
return execSync37("git rev-parse --abbrev-ref HEAD", {
|
|
11649
|
-
encoding: "utf-8"
|
|
11650
|
-
}).trim();
|
|
11651
|
-
}
|
|
11652
|
-
function fetchPrDiffInfo() {
|
|
11653
|
-
const { org, repo } = getRepoInfo();
|
|
11654
|
-
const branch = getCurrentBranch2();
|
|
11655
|
-
const fields = "number,baseRefName,baseRefOid,headRefName,headRefOid";
|
|
11656
|
-
let raw;
|
|
11657
|
-
try {
|
|
11658
|
-
raw = execSync37(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
|
|
11659
|
-
encoding: "utf-8",
|
|
11660
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
11661
|
-
});
|
|
11662
|
-
} catch (error) {
|
|
11663
|
-
if (error instanceof Error && error.message.includes("no pull requests")) {
|
|
11664
|
-
console.error(
|
|
11665
|
-
`Error: No open pull request found for branch \`${branch}\`. Open a PR for this branch before running \`assist review\`.`
|
|
11666
|
-
);
|
|
11667
|
-
process.exit(1);
|
|
11668
|
-
}
|
|
11669
|
-
throw error;
|
|
11670
|
-
}
|
|
11671
|
-
const parsed = JSON.parse(raw);
|
|
11672
|
-
return {
|
|
11673
|
-
prNumber: parsed.number,
|
|
11674
|
-
baseRef: parsed.baseRefName,
|
|
11675
|
-
baseSha: parsed.baseRefOid,
|
|
11676
|
-
headRef: parsed.headRefName,
|
|
11677
|
-
headSha: parsed.headRefOid
|
|
11678
|
-
};
|
|
11679
|
-
}
|
|
11680
|
-
function fetchPrChangedFiles(prNumber) {
|
|
11681
|
-
const { org, repo } = getRepoInfo();
|
|
11682
|
-
const out = execSync37(`gh pr diff ${prNumber} --name-only -R ${org}/${repo}`, {
|
|
11683
|
-
encoding: "utf-8",
|
|
11684
|
-
maxBuffer: 64 * 1024 * 1024
|
|
11685
|
-
});
|
|
11686
|
-
return out.trim().split("\n").filter(Boolean);
|
|
11687
|
-
}
|
|
11688
|
-
function fetchPrDiff(prNumber) {
|
|
11689
|
-
const { org, repo } = getRepoInfo();
|
|
11690
|
-
return execSync37(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
|
|
11691
|
-
encoding: "utf-8",
|
|
11692
|
-
maxBuffer: 256 * 1024 * 1024
|
|
11693
|
-
});
|
|
11694
|
-
}
|
|
11695
|
-
|
|
11696
11642
|
// src/commands/review/formatPriorComments.ts
|
|
11697
11643
|
function threadKey(c, byId) {
|
|
11698
11644
|
if (c.threadId) return c.threadId;
|
|
@@ -11743,30 +11689,6 @@ ${blocks.join("\n\n")}`;
|
|
|
11743
11689
|
}
|
|
11744
11690
|
|
|
11745
11691
|
// src/commands/review/buildRequest.ts
|
|
11746
|
-
function gatherContext() {
|
|
11747
|
-
const branch = execSync38("git rev-parse --abbrev-ref HEAD", {
|
|
11748
|
-
encoding: "utf-8"
|
|
11749
|
-
}).trim();
|
|
11750
|
-
const sha = execSync38("git rev-parse HEAD", { encoding: "utf-8" }).trim();
|
|
11751
|
-
const shortSha = execSync38("git rev-parse --short=7 HEAD", {
|
|
11752
|
-
encoding: "utf-8"
|
|
11753
|
-
}).trim();
|
|
11754
|
-
const prInfo = fetchPrDiffInfo();
|
|
11755
|
-
const changedFiles = fetchPrChangedFiles(prInfo.prNumber);
|
|
11756
|
-
const diff2 = fetchPrDiff(prInfo.prNumber);
|
|
11757
|
-
return {
|
|
11758
|
-
branch,
|
|
11759
|
-
sha,
|
|
11760
|
-
shortSha,
|
|
11761
|
-
prNumber: prInfo.prNumber,
|
|
11762
|
-
baseRef: prInfo.baseRef,
|
|
11763
|
-
baseSha: prInfo.baseSha,
|
|
11764
|
-
headRef: prInfo.headRef,
|
|
11765
|
-
headSha: prInfo.headSha,
|
|
11766
|
-
changedFiles,
|
|
11767
|
-
diff: diff2
|
|
11768
|
-
};
|
|
11769
|
-
}
|
|
11770
11692
|
function formatFiles(files) {
|
|
11771
11693
|
if (files.length === 0) return "(none)";
|
|
11772
11694
|
return files.map((file) => `- ${file}`).join("\n");
|
|
@@ -11790,6 +11712,23 @@ ${formatFiles(context.changedFiles)}
|
|
|
11790
11712
|
${priorBlock}
|
|
11791
11713
|
## Diff (PR #${context.prNumber}: ${context.baseSha}..${context.headSha})
|
|
11792
11714
|
|
|
11715
|
+
\`\`\`diff
|
|
11716
|
+
${context.diff.trimEnd()}
|
|
11717
|
+
\`\`\`
|
|
11718
|
+
`;
|
|
11719
|
+
}
|
|
11720
|
+
function buildShaRequest(context) {
|
|
11721
|
+
return `# Code review request
|
|
11722
|
+
|
|
11723
|
+
- Commit: \`${context.sha}\`
|
|
11724
|
+
- Parent: \`${context.parentSha}\`
|
|
11725
|
+
|
|
11726
|
+
## Changed files
|
|
11727
|
+
|
|
11728
|
+
${formatFiles(context.changedFiles)}
|
|
11729
|
+
|
|
11730
|
+
## Diff (commit ${context.sha}: ${context.parentSha}..${context.sha})
|
|
11731
|
+
|
|
11793
11732
|
\`\`\`diff
|
|
11794
11733
|
${context.diff.trimEnd()}
|
|
11795
11734
|
\`\`\`
|
|
@@ -11798,13 +11737,8 @@ ${context.diff.trimEnd()}
|
|
|
11798
11737
|
|
|
11799
11738
|
// src/commands/review/buildReviewPaths.ts
|
|
11800
11739
|
import { join as join35 } from "path";
|
|
11801
|
-
function buildReviewPaths(repoRoot,
|
|
11802
|
-
const reviewDir = join35(
|
|
11803
|
-
repoRoot,
|
|
11804
|
-
".assist",
|
|
11805
|
-
"reviews",
|
|
11806
|
-
`${branch}-${shortSha}`
|
|
11807
|
-
);
|
|
11740
|
+
function buildReviewPaths(repoRoot, key) {
|
|
11741
|
+
const reviewDir = join35(repoRoot, ".assist", "reviews", key);
|
|
11808
11742
|
return {
|
|
11809
11743
|
reviewDir,
|
|
11810
11744
|
requestPath: join35(reviewDir, "request.md"),
|
|
@@ -11815,9 +11749,9 @@ function buildReviewPaths(repoRoot, branch, shortSha) {
|
|
|
11815
11749
|
}
|
|
11816
11750
|
|
|
11817
11751
|
// src/commands/review/fetchExistingComments.ts
|
|
11818
|
-
import { execSync as
|
|
11752
|
+
import { execSync as execSync37 } from "child_process";
|
|
11819
11753
|
function fetchRawComments(org, repo, prNumber) {
|
|
11820
|
-
const out =
|
|
11754
|
+
const out = execSync37(
|
|
11821
11755
|
`gh api --paginate repos/${org}/${repo}/pulls/${prNumber}/comments`,
|
|
11822
11756
|
{ encoding: "utf-8", maxBuffer: 64 * 1024 * 1024 }
|
|
11823
11757
|
);
|
|
@@ -11847,6 +11781,86 @@ function fetchExistingComments() {
|
|
|
11847
11781
|
});
|
|
11848
11782
|
}
|
|
11849
11783
|
|
|
11784
|
+
// src/commands/review/gatherContext.ts
|
|
11785
|
+
import { execSync as execSync39 } from "child_process";
|
|
11786
|
+
|
|
11787
|
+
// src/commands/review/fetchPrDiffInfo.ts
|
|
11788
|
+
import { execSync as execSync38 } from "child_process";
|
|
11789
|
+
function getCurrentBranch2() {
|
|
11790
|
+
return execSync38("git rev-parse --abbrev-ref HEAD", {
|
|
11791
|
+
encoding: "utf-8"
|
|
11792
|
+
}).trim();
|
|
11793
|
+
}
|
|
11794
|
+
function fetchPrDiffInfo() {
|
|
11795
|
+
const { org, repo } = getRepoInfo();
|
|
11796
|
+
const branch = getCurrentBranch2();
|
|
11797
|
+
const fields = "number,baseRefName,baseRefOid,headRefName,headRefOid";
|
|
11798
|
+
let raw;
|
|
11799
|
+
try {
|
|
11800
|
+
raw = execSync38(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
|
|
11801
|
+
encoding: "utf-8",
|
|
11802
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
11803
|
+
});
|
|
11804
|
+
} catch (error) {
|
|
11805
|
+
if (error instanceof Error && error.message.includes("no pull requests")) {
|
|
11806
|
+
console.error(
|
|
11807
|
+
`Error: No open pull request found for branch \`${branch}\`. Open a PR for this branch before running \`assist review\`.`
|
|
11808
|
+
);
|
|
11809
|
+
process.exit(1);
|
|
11810
|
+
}
|
|
11811
|
+
throw error;
|
|
11812
|
+
}
|
|
11813
|
+
const parsed = JSON.parse(raw);
|
|
11814
|
+
return {
|
|
11815
|
+
prNumber: parsed.number,
|
|
11816
|
+
baseRef: parsed.baseRefName,
|
|
11817
|
+
baseSha: parsed.baseRefOid,
|
|
11818
|
+
headRef: parsed.headRefName,
|
|
11819
|
+
headSha: parsed.headRefOid
|
|
11820
|
+
};
|
|
11821
|
+
}
|
|
11822
|
+
function fetchPrChangedFiles(prNumber) {
|
|
11823
|
+
const { org, repo } = getRepoInfo();
|
|
11824
|
+
const out = execSync38(`gh pr diff ${prNumber} --name-only -R ${org}/${repo}`, {
|
|
11825
|
+
encoding: "utf-8",
|
|
11826
|
+
maxBuffer: 64 * 1024 * 1024
|
|
11827
|
+
});
|
|
11828
|
+
return out.trim().split("\n").filter(Boolean);
|
|
11829
|
+
}
|
|
11830
|
+
function fetchPrDiff(prNumber) {
|
|
11831
|
+
const { org, repo } = getRepoInfo();
|
|
11832
|
+
return execSync38(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
|
|
11833
|
+
encoding: "utf-8",
|
|
11834
|
+
maxBuffer: 256 * 1024 * 1024
|
|
11835
|
+
});
|
|
11836
|
+
}
|
|
11837
|
+
|
|
11838
|
+
// src/commands/review/gatherContext.ts
|
|
11839
|
+
function gatherContext() {
|
|
11840
|
+
const branch = execSync39("git rev-parse --abbrev-ref HEAD", {
|
|
11841
|
+
encoding: "utf-8"
|
|
11842
|
+
}).trim();
|
|
11843
|
+
const sha = execSync39("git rev-parse HEAD", { encoding: "utf-8" }).trim();
|
|
11844
|
+
const shortSha = execSync39("git rev-parse --short=7 HEAD", {
|
|
11845
|
+
encoding: "utf-8"
|
|
11846
|
+
}).trim();
|
|
11847
|
+
const prInfo = fetchPrDiffInfo();
|
|
11848
|
+
const changedFiles = fetchPrChangedFiles(prInfo.prNumber);
|
|
11849
|
+
const diff2 = fetchPrDiff(prInfo.prNumber);
|
|
11850
|
+
return {
|
|
11851
|
+
branch,
|
|
11852
|
+
sha,
|
|
11853
|
+
shortSha,
|
|
11854
|
+
prNumber: prInfo.prNumber,
|
|
11855
|
+
baseRef: prInfo.baseRef,
|
|
11856
|
+
baseSha: prInfo.baseSha,
|
|
11857
|
+
headRef: prInfo.headRef,
|
|
11858
|
+
headSha: prInfo.headSha,
|
|
11859
|
+
changedFiles,
|
|
11860
|
+
diff: diff2
|
|
11861
|
+
};
|
|
11862
|
+
}
|
|
11863
|
+
|
|
11850
11864
|
// src/commands/review/postReviewToPr.ts
|
|
11851
11865
|
import { readFileSync as readFileSync29 } from "fs";
|
|
11852
11866
|
|
|
@@ -12866,19 +12880,7 @@ async function runReviewPipeline(paths, options2) {
|
|
|
12866
12880
|
}
|
|
12867
12881
|
}
|
|
12868
12882
|
|
|
12869
|
-
// src/commands/review/
|
|
12870
|
-
function resolveRepoRoot() {
|
|
12871
|
-
const repoRoot = findRepoRoot(process.cwd());
|
|
12872
|
-
if (repoRoot) return repoRoot;
|
|
12873
|
-
console.error("Error: not inside a git repository.");
|
|
12874
|
-
process.exit(1);
|
|
12875
|
-
}
|
|
12876
|
-
function validateOptions(options2) {
|
|
12877
|
-
if (options2.apply && options2.refine) {
|
|
12878
|
-
console.error("Error: --apply cannot be combined with --refine.");
|
|
12879
|
-
process.exit(1);
|
|
12880
|
-
}
|
|
12881
|
-
}
|
|
12883
|
+
// src/commands/review/reviewPr.ts
|
|
12882
12884
|
function logPriorComments(count) {
|
|
12883
12885
|
if (count === 0) return;
|
|
12884
12886
|
console.log(`Including ${count} prior review comment(s) in request.md.`);
|
|
@@ -12892,7 +12894,10 @@ function gatherChangedContext() {
|
|
|
12892
12894
|
process.exit(1);
|
|
12893
12895
|
}
|
|
12894
12896
|
function setupReviewDir(repoRoot, context, force) {
|
|
12895
|
-
const paths = buildReviewPaths(
|
|
12897
|
+
const paths = buildReviewPaths(
|
|
12898
|
+
repoRoot,
|
|
12899
|
+
`${context.branch}-${context.shortSha}`
|
|
12900
|
+
);
|
|
12896
12901
|
const priorComments = fetchExistingComments();
|
|
12897
12902
|
logPriorComments(priorComments?.length ?? 0);
|
|
12898
12903
|
prepareReviewDir(paths, buildRequest(context, priorComments), force);
|
|
@@ -12910,9 +12915,7 @@ async function runPostSynthesis(synthesisPath, options2) {
|
|
|
12910
12915
|
submit: options2.submit ?? false
|
|
12911
12916
|
});
|
|
12912
12917
|
}
|
|
12913
|
-
async function
|
|
12914
|
-
validateOptions(options2);
|
|
12915
|
-
const repoRoot = resolveRepoRoot();
|
|
12918
|
+
async function reviewPr(repoRoot, options2) {
|
|
12916
12919
|
const context = gatherChangedContext();
|
|
12917
12920
|
const paths = setupReviewDir(repoRoot, context, options2.force ?? false);
|
|
12918
12921
|
const synthesisOk = await runReviewPipeline(paths, {
|
|
@@ -12922,10 +12925,100 @@ async function review(options2 = {}) {
|
|
|
12922
12925
|
console.log(`Done. Review folder: ${paths.reviewDir}`);
|
|
12923
12926
|
}
|
|
12924
12927
|
|
|
12928
|
+
// src/commands/review/gatherShaContext.ts
|
|
12929
|
+
import { execSync as execSync40 } from "child_process";
|
|
12930
|
+
function resolveSha(ref, format2) {
|
|
12931
|
+
const flag = format2 === "short" ? "--short=7 " : "";
|
|
12932
|
+
try {
|
|
12933
|
+
return execSync40(`git rev-parse --verify ${flag}${ref}^{commit}`, {
|
|
12934
|
+
encoding: "utf-8",
|
|
12935
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
12936
|
+
}).trim();
|
|
12937
|
+
} catch {
|
|
12938
|
+
console.error(`Error: could not resolve commit \`${ref}\`.`);
|
|
12939
|
+
process.exit(1);
|
|
12940
|
+
}
|
|
12941
|
+
}
|
|
12942
|
+
function gatherShaContext(ref) {
|
|
12943
|
+
const sha = resolveSha(ref, "long");
|
|
12944
|
+
const shortSha = resolveSha(sha, "short");
|
|
12945
|
+
const parentSha = resolveSha(`${sha}^`, "long");
|
|
12946
|
+
const range = `${parentSha}..${sha}`;
|
|
12947
|
+
const changedFiles = execSync40(`git diff --name-only ${range}`, {
|
|
12948
|
+
encoding: "utf-8",
|
|
12949
|
+
maxBuffer: 64 * 1024 * 1024
|
|
12950
|
+
}).trim().split("\n").filter(Boolean);
|
|
12951
|
+
const diff2 = execSync40(`git diff ${range}`, {
|
|
12952
|
+
encoding: "utf-8",
|
|
12953
|
+
maxBuffer: 256 * 1024 * 1024
|
|
12954
|
+
});
|
|
12955
|
+
return { sha, shortSha, parentSha, changedFiles, diff: diff2 };
|
|
12956
|
+
}
|
|
12957
|
+
|
|
12958
|
+
// src/commands/review/reviewSha.ts
|
|
12959
|
+
function gatherShaChangedContext(ref) {
|
|
12960
|
+
const context = gatherShaContext(ref);
|
|
12961
|
+
if (context.changedFiles.length > 0) return context;
|
|
12962
|
+
console.error(
|
|
12963
|
+
`Error: commit ${context.sha} has no changed files \u2014 nothing to review.`
|
|
12964
|
+
);
|
|
12965
|
+
process.exit(1);
|
|
12966
|
+
}
|
|
12967
|
+
function setupShaReviewDir(repoRoot, context, force) {
|
|
12968
|
+
const paths = buildReviewPaths(repoRoot, context.shortSha);
|
|
12969
|
+
prepareReviewDir(paths, buildShaRequest(context), force);
|
|
12970
|
+
console.log(`Review folder: ${paths.reviewDir}`);
|
|
12971
|
+
return paths;
|
|
12972
|
+
}
|
|
12973
|
+
async function reviewSha(repoRoot, options2) {
|
|
12974
|
+
const context = gatherShaChangedContext(options2.sha);
|
|
12975
|
+
const paths = setupShaReviewDir(repoRoot, context, options2.force ?? false);
|
|
12976
|
+
await runReviewPipeline(paths, { verbose: options2.verbose ?? false });
|
|
12977
|
+
console.log(`Done. Review folder: ${paths.reviewDir}`);
|
|
12978
|
+
}
|
|
12979
|
+
|
|
12980
|
+
// src/commands/review/review.ts
|
|
12981
|
+
function resolveRepoRoot() {
|
|
12982
|
+
const repoRoot = findRepoRoot(process.cwd());
|
|
12983
|
+
if (repoRoot) return repoRoot;
|
|
12984
|
+
console.error("Error: not inside a git repository.");
|
|
12985
|
+
process.exit(1);
|
|
12986
|
+
}
|
|
12987
|
+
function rejectShaFlag(flag) {
|
|
12988
|
+
console.error(`Error: ${flag} cannot be combined with a SHA argument.`);
|
|
12989
|
+
process.exit(1);
|
|
12990
|
+
}
|
|
12991
|
+
function validateOptions(options2) {
|
|
12992
|
+
if (options2.apply && options2.refine) {
|
|
12993
|
+
console.error("Error: --apply cannot be combined with --refine.");
|
|
12994
|
+
process.exit(1);
|
|
12995
|
+
}
|
|
12996
|
+
if (!options2.sha) return;
|
|
12997
|
+
if (options2.refine) rejectShaFlag("--refine");
|
|
12998
|
+
if (options2.apply) rejectShaFlag("--apply");
|
|
12999
|
+
if (options2.submit) rejectShaFlag("--submit");
|
|
13000
|
+
}
|
|
13001
|
+
async function review(options2 = {}) {
|
|
13002
|
+
validateOptions(options2);
|
|
13003
|
+
const repoRoot = resolveRepoRoot();
|
|
13004
|
+
if (options2.sha) {
|
|
13005
|
+
await reviewSha(repoRoot, {
|
|
13006
|
+
sha: options2.sha,
|
|
13007
|
+
force: options2.force,
|
|
13008
|
+
verbose: options2.verbose
|
|
13009
|
+
});
|
|
13010
|
+
return;
|
|
13011
|
+
}
|
|
13012
|
+
await reviewPr(repoRoot, options2);
|
|
13013
|
+
}
|
|
13014
|
+
|
|
12925
13015
|
// src/commands/registerReview.ts
|
|
12926
13016
|
function registerReview(program2) {
|
|
12927
13017
|
program2.command("review").description(
|
|
12928
|
-
"Run Claude and Codex in parallel to review the current branch"
|
|
13018
|
+
"Run Claude and Codex in parallel to review the current branch, or a single commit when a SHA is given"
|
|
13019
|
+
).argument(
|
|
13020
|
+
"[sha]",
|
|
13021
|
+
"Optional commit SHA to review (sha^..sha); when provided, no PR lookup or GitHub posting happens"
|
|
12929
13022
|
).option(
|
|
12930
13023
|
"--no-prompt",
|
|
12931
13024
|
"Skip confirmation prompts; use flag defaults non-interactively"
|
|
@@ -12944,7 +13037,9 @@ function registerReview(program2) {
|
|
|
12944
13037
|
).option(
|
|
12945
13038
|
"--verbose",
|
|
12946
13039
|
"Disable spinner UI and use per-line log output (per-tool lines, starting/done lines)"
|
|
12947
|
-
).action(
|
|
13040
|
+
).action(
|
|
13041
|
+
(sha, options2) => review({ ...options2, sha })
|
|
13042
|
+
);
|
|
12948
13043
|
}
|
|
12949
13044
|
|
|
12950
13045
|
// src/commands/seq/seqAuth.ts
|
|
@@ -14288,7 +14383,7 @@ import { mkdirSync as mkdirSync14 } from "fs";
|
|
|
14288
14383
|
import { join as join45 } from "path";
|
|
14289
14384
|
|
|
14290
14385
|
// src/commands/voice/checkLockFile.ts
|
|
14291
|
-
import { execSync as
|
|
14386
|
+
import { execSync as execSync41 } from "child_process";
|
|
14292
14387
|
import { existsSync as existsSync42, mkdirSync as mkdirSync13, readFileSync as readFileSync34, writeFileSync as writeFileSync29 } from "fs";
|
|
14293
14388
|
import { join as join44 } from "path";
|
|
14294
14389
|
function isProcessAlive2(pid) {
|
|
@@ -14317,7 +14412,7 @@ function bootstrapVenv() {
|
|
|
14317
14412
|
if (existsSync42(getVenvPython())) return;
|
|
14318
14413
|
console.log("Setting up Python environment...");
|
|
14319
14414
|
const pythonDir = getPythonDir();
|
|
14320
|
-
|
|
14415
|
+
execSync41(
|
|
14321
14416
|
`uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
|
|
14322
14417
|
{
|
|
14323
14418
|
stdio: "inherit",
|
|
@@ -14484,11 +14579,11 @@ import { randomBytes } from "crypto";
|
|
|
14484
14579
|
import chalk143 from "chalk";
|
|
14485
14580
|
|
|
14486
14581
|
// src/lib/openBrowser.ts
|
|
14487
|
-
import { execSync as
|
|
14582
|
+
import { execSync as execSync42 } from "child_process";
|
|
14488
14583
|
function tryExec(commands) {
|
|
14489
14584
|
for (const cmd of commands) {
|
|
14490
14585
|
try {
|
|
14491
|
-
|
|
14586
|
+
execSync42(cmd);
|
|
14492
14587
|
return true;
|
|
14493
14588
|
} catch {
|
|
14494
14589
|
}
|
|
@@ -14830,11 +14925,11 @@ function resolveParams(params, cliArgs) {
|
|
|
14830
14925
|
}
|
|
14831
14926
|
|
|
14832
14927
|
// src/commands/run/runPreCommands.ts
|
|
14833
|
-
import { execSync as
|
|
14928
|
+
import { execSync as execSync43 } from "child_process";
|
|
14834
14929
|
function runPreCommands(pre, cwd) {
|
|
14835
14930
|
for (const cmd of pre) {
|
|
14836
14931
|
try {
|
|
14837
|
-
|
|
14932
|
+
execSync43(cmd, { stdio: "inherit", cwd });
|
|
14838
14933
|
} catch (err) {
|
|
14839
14934
|
const code = err && typeof err === "object" && "status" in err ? err.status : 1;
|
|
14840
14935
|
process.exit(code);
|
|
@@ -15097,7 +15192,7 @@ function registerRun(program2) {
|
|
|
15097
15192
|
}
|
|
15098
15193
|
|
|
15099
15194
|
// src/commands/screenshot/index.ts
|
|
15100
|
-
import { execSync as
|
|
15195
|
+
import { execSync as execSync44 } from "child_process";
|
|
15101
15196
|
import { existsSync as existsSync47, mkdirSync as mkdirSync17, unlinkSync as unlinkSync15, writeFileSync as writeFileSync32 } from "fs";
|
|
15102
15197
|
import { tmpdir as tmpdir7 } from "os";
|
|
15103
15198
|
import { join as join51, resolve as resolve13 } from "path";
|
|
@@ -15240,7 +15335,7 @@ function runPowerShellScript(processName, outputPath) {
|
|
|
15240
15335
|
const scriptPath = join51(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
|
|
15241
15336
|
writeFileSync32(scriptPath, captureWindowPs1, "utf-8");
|
|
15242
15337
|
try {
|
|
15243
|
-
|
|
15338
|
+
execSync44(
|
|
15244
15339
|
`powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
|
|
15245
15340
|
{ stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }
|
|
15246
15341
|
);
|
|
@@ -15641,7 +15736,7 @@ function syncCommands(claudeDir, targetBase) {
|
|
|
15641
15736
|
}
|
|
15642
15737
|
|
|
15643
15738
|
// src/commands/update.ts
|
|
15644
|
-
import { execSync as
|
|
15739
|
+
import { execSync as execSync45 } from "child_process";
|
|
15645
15740
|
import * as path51 from "path";
|
|
15646
15741
|
function isGlobalNpmInstall(dir) {
|
|
15647
15742
|
try {
|
|
@@ -15649,7 +15744,7 @@ function isGlobalNpmInstall(dir) {
|
|
|
15649
15744
|
if (resolved.split(path51.sep).includes("node_modules")) {
|
|
15650
15745
|
return true;
|
|
15651
15746
|
}
|
|
15652
|
-
const globalPrefix =
|
|
15747
|
+
const globalPrefix = execSync45("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
15653
15748
|
return resolved.toLowerCase().startsWith(path51.resolve(globalPrefix).toLowerCase());
|
|
15654
15749
|
} catch {
|
|
15655
15750
|
return false;
|
|
@@ -15660,18 +15755,18 @@ async function update2() {
|
|
|
15660
15755
|
console.log(`Assist is installed at: ${installDir}`);
|
|
15661
15756
|
if (isGitRepo(installDir)) {
|
|
15662
15757
|
console.log("Detected git repo installation, pulling latest...");
|
|
15663
|
-
|
|
15758
|
+
execSync45("git pull", { cwd: installDir, stdio: "inherit" });
|
|
15664
15759
|
console.log("Installing dependencies...");
|
|
15665
|
-
|
|
15760
|
+
execSync45("npm i", { cwd: installDir, stdio: "inherit" });
|
|
15666
15761
|
console.log("Building...");
|
|
15667
|
-
|
|
15762
|
+
execSync45("npm run build", { cwd: installDir, stdio: "inherit" });
|
|
15668
15763
|
console.log("Syncing commands...");
|
|
15669
|
-
|
|
15764
|
+
execSync45("assist sync", { stdio: "inherit" });
|
|
15670
15765
|
} else if (isGlobalNpmInstall(installDir)) {
|
|
15671
15766
|
console.log("Detected global npm installation, updating...");
|
|
15672
|
-
|
|
15767
|
+
execSync45("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
|
|
15673
15768
|
console.log("Syncing commands...");
|
|
15674
|
-
|
|
15769
|
+
execSync45("assist sync", { stdio: "inherit" });
|
|
15675
15770
|
} else {
|
|
15676
15771
|
console.error(
|
|
15677
15772
|
"Could not determine installation method. Expected a git repo or global npm install."
|