deepcode-ai 1.1.24 → 1.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +191 -163
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10360,6 +10360,163 @@ async function initCommand(cwd) {
|
|
|
10360
10360
|
const filePath = await new ConfigLoader().init(cwd);
|
|
10361
10361
|
await writeStdoutLine(`DeepCode config created at ${filePath}`);
|
|
10362
10362
|
}
|
|
10363
|
+
function resolveSessionTarget(config, overrides = {}) {
|
|
10364
|
+
const requestedProvider = parseProviderId(overrides.provider);
|
|
10365
|
+
const fallback = resolveUsableProviderTarget(config, [
|
|
10366
|
+
requestedProvider,
|
|
10367
|
+
config.defaultProvider
|
|
10368
|
+
]);
|
|
10369
|
+
const parsedSelection = overrides.model ? parseModelSelection(overrides.model, requestedProvider ?? fallback.provider) : null;
|
|
10370
|
+
if (overrides.model && !parsedSelection) {
|
|
10371
|
+
throw new Error(
|
|
10372
|
+
`Invalid model selection: ${overrides.model}. Use "<model>" or "<provider>/<model>".`
|
|
10373
|
+
);
|
|
10374
|
+
}
|
|
10375
|
+
const provider = parsedSelection?.provider ?? requestedProvider ?? fallback.provider;
|
|
10376
|
+
const model = parsedSelection?.model ?? resolveConfiguredModelForProvider(config, provider) ?? (provider === fallback.provider ? fallback.model : void 0);
|
|
10377
|
+
return { provider, model };
|
|
10378
|
+
}
|
|
10379
|
+
function parseProviderId(value) {
|
|
10380
|
+
if (!value) return void 0;
|
|
10381
|
+
const parsed = ProviderIdSchema.safeParse(value);
|
|
10382
|
+
if (parsed.success) return parsed.data;
|
|
10383
|
+
throw new Error(`Invalid provider: ${value}. Expected one of: ${PROVIDER_IDS.join(", ")}`);
|
|
10384
|
+
}
|
|
10385
|
+
var DIFF_MAX_CHARS = 2e4;
|
|
10386
|
+
function truncateDiff(raw, maxChars = DIFF_MAX_CHARS) {
|
|
10387
|
+
const fileChunks = raw.split(/(?=^diff --git )/m).filter(Boolean);
|
|
10388
|
+
const totalFiles = fileChunks.length;
|
|
10389
|
+
let result = "";
|
|
10390
|
+
let included = 0;
|
|
10391
|
+
for (const chunk of fileChunks) {
|
|
10392
|
+
if (result.length + chunk.length > maxChars) break;
|
|
10393
|
+
result += chunk;
|
|
10394
|
+
included++;
|
|
10395
|
+
}
|
|
10396
|
+
if (!result && fileChunks.length > 0) {
|
|
10397
|
+
result = fileChunks[0].slice(0, maxChars);
|
|
10398
|
+
included = 1;
|
|
10399
|
+
}
|
|
10400
|
+
return { diff: result.trimEnd(), omittedFiles: totalFiles - included, totalFiles };
|
|
10401
|
+
}
|
|
10402
|
+
async function runGit(cwd, args) {
|
|
10403
|
+
const result = await execFileAsync("git", args, { cwd, timeoutMs: 3e4 });
|
|
10404
|
+
if (result.exitCode !== 0) {
|
|
10405
|
+
throw new Error(result.stderr || `git ${args.join(" ")} failed`);
|
|
10406
|
+
}
|
|
10407
|
+
return result.stdout;
|
|
10408
|
+
}
|
|
10409
|
+
async function isGitRepo(cwd) {
|
|
10410
|
+
const result = await execFileAsync(
|
|
10411
|
+
"git",
|
|
10412
|
+
["rev-parse", "--is-inside-work-tree"],
|
|
10413
|
+
{ cwd, timeoutMs: 5e3 }
|
|
10414
|
+
);
|
|
10415
|
+
return result.exitCode === 0;
|
|
10416
|
+
}
|
|
10417
|
+
function buildDiffArgs(options) {
|
|
10418
|
+
if (options.staged) {
|
|
10419
|
+
const args2 = ["diff", "--cached"];
|
|
10420
|
+
if (options.file) args2.push("--", options.file);
|
|
10421
|
+
return { args: args2, label: "staged changes" };
|
|
10422
|
+
}
|
|
10423
|
+
if (options.ref) {
|
|
10424
|
+
const args2 = ["diff", options.ref];
|
|
10425
|
+
if (options.file) args2.push("--", options.file);
|
|
10426
|
+
return { args: args2, label: `diff vs ${options.ref}` };
|
|
10427
|
+
}
|
|
10428
|
+
const args = ["diff", "HEAD"];
|
|
10429
|
+
if (options.file) args.push("--", options.file);
|
|
10430
|
+
return { args, label: options.file ? `local changes in ${options.file}` : "local changes vs HEAD" };
|
|
10431
|
+
}
|
|
10432
|
+
function buildPrompt(diff, label, focus, truncation) {
|
|
10433
|
+
const focusLine = focus.length > 0 ? `
|
|
10434
|
+
Focus areas: ${focus.join(", ")}.` : "";
|
|
10435
|
+
const truncationNote = truncation.omittedFiles > 0 ? `
|
|
10436
|
+
(Showing ${truncation.totalFiles - truncation.omittedFiles} of ${truncation.totalFiles} changed files; ${truncation.omittedFiles} file(s) omitted due to size.)
|
|
10437
|
+
` : "";
|
|
10438
|
+
return [
|
|
10439
|
+
`Review the following local git diff (${label}).`,
|
|
10440
|
+
"Do not modify any files. Output the review only.",
|
|
10441
|
+
focusLine,
|
|
10442
|
+
"",
|
|
10443
|
+
`\`\`\`diff`,
|
|
10444
|
+
diff,
|
|
10445
|
+
`\`\`\``,
|
|
10446
|
+
truncationNote,
|
|
10447
|
+
"Produce a structured code review:",
|
|
10448
|
+
"1. **Summary** \u2014 what changed (inferred from the diff)",
|
|
10449
|
+
"2. **Issues** \u2014 bugs, security concerns, logic errors, missing error handling; quote the relevant lines",
|
|
10450
|
+
"3. **Suggestions** \u2014 improvements and nitpicks",
|
|
10451
|
+
"4. **Verdict** \u2014 Looks good / Has issues, with a one-line rationale"
|
|
10452
|
+
].filter((l) => l !== void 0).join("\n");
|
|
10453
|
+
}
|
|
10454
|
+
async function reviewCommand(options) {
|
|
10455
|
+
if (!await isGitRepo(options.cwd)) {
|
|
10456
|
+
await writeStderrLine("error: not inside a git repository");
|
|
10457
|
+
process.exit(1);
|
|
10458
|
+
}
|
|
10459
|
+
const { args, label } = buildDiffArgs(options);
|
|
10460
|
+
let rawDiff;
|
|
10461
|
+
try {
|
|
10462
|
+
rawDiff = await runGit(options.cwd, args);
|
|
10463
|
+
} catch (err) {
|
|
10464
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10465
|
+
await writeStderrLine(`error: ${msg}`);
|
|
10466
|
+
process.exit(1);
|
|
10467
|
+
}
|
|
10468
|
+
const trimmed = rawDiff.trim();
|
|
10469
|
+
if (!trimmed) {
|
|
10470
|
+
await writeStdoutLine(`No changes to review (${label}).`);
|
|
10471
|
+
return;
|
|
10472
|
+
}
|
|
10473
|
+
const truncation = truncateDiff(trimmed);
|
|
10474
|
+
const runtime = await createRuntime({
|
|
10475
|
+
cwd: options.cwd,
|
|
10476
|
+
configPath: options.config,
|
|
10477
|
+
interactive: Boolean(options.yes)
|
|
10478
|
+
});
|
|
10479
|
+
if (options.yes) {
|
|
10480
|
+
runtime.events.on("approval:request", (request) => {
|
|
10481
|
+
runtime.events.emit("approval:decision", {
|
|
10482
|
+
requestId: request.id,
|
|
10483
|
+
decision: { allowed: true }
|
|
10484
|
+
});
|
|
10485
|
+
});
|
|
10486
|
+
}
|
|
10487
|
+
const target = resolveSessionTarget(runtime.config, {
|
|
10488
|
+
provider: options.provider,
|
|
10489
|
+
model: options.model
|
|
10490
|
+
});
|
|
10491
|
+
const session = runtime.sessions.create({
|
|
10492
|
+
provider: target.provider,
|
|
10493
|
+
model: target.model
|
|
10494
|
+
});
|
|
10495
|
+
const prompt = buildPrompt(truncation.diff, label, options.focus ?? [], truncation);
|
|
10496
|
+
const secretValues = collectSecretValues(runtime.config);
|
|
10497
|
+
await writeStdoutLine(`Reviewing ${label}\u2026
|
|
10498
|
+
`);
|
|
10499
|
+
let streamed = false;
|
|
10500
|
+
try {
|
|
10501
|
+
const output = await runtime.agent.run({
|
|
10502
|
+
session,
|
|
10503
|
+
input: prompt,
|
|
10504
|
+
mode: "plan",
|
|
10505
|
+
provider: target.provider,
|
|
10506
|
+
onChunk: (text) => {
|
|
10507
|
+
streamed = true;
|
|
10508
|
+
process.stdout.write(redactText(text, secretValues));
|
|
10509
|
+
}
|
|
10510
|
+
});
|
|
10511
|
+
if (!streamed && output) {
|
|
10512
|
+
process.stdout.write(redactText(output, secretValues));
|
|
10513
|
+
}
|
|
10514
|
+
if (!streamed || !output) process.stdout.write("\n");
|
|
10515
|
+
} finally {
|
|
10516
|
+
await runtime.sessions.persist(session.id).catch(() => {
|
|
10517
|
+
});
|
|
10518
|
+
}
|
|
10519
|
+
}
|
|
10363
10520
|
async function githubLoginCommand(options) {
|
|
10364
10521
|
const loader = new ConfigLoader();
|
|
10365
10522
|
const loadOptions = { cwd: options.cwd, configPath: options.config };
|
|
@@ -10539,8 +10696,8 @@ async function solveIssueCommand(issueNumber, options) {
|
|
|
10539
10696
|
const issue = await client.getIssue({ ...repo, number: issueNumber });
|
|
10540
10697
|
const base = options.base ?? "main";
|
|
10541
10698
|
const branch = `deepcode/issue-${issueNumber}-${slugify(issue.title)}`.slice(0, 80);
|
|
10542
|
-
await
|
|
10543
|
-
await
|
|
10699
|
+
await runGit2(options.cwd, ["fetch", "origin", base]);
|
|
10700
|
+
await runGit2(options.cwd, ["checkout", "-B", branch, `origin/${base}`]);
|
|
10544
10701
|
const target = resolveUsableProviderTarget(runtime.config, [runtime.config.defaultProvider]);
|
|
10545
10702
|
const session = runtime.sessions.create({
|
|
10546
10703
|
provider: target.provider,
|
|
@@ -10565,16 +10722,16 @@ async function solveIssueCommand(issueNumber, options) {
|
|
|
10565
10722
|
onChunk: (text) => void writeStdout(redactText(text, secretValues))
|
|
10566
10723
|
});
|
|
10567
10724
|
await writeStdout("\n");
|
|
10568
|
-
const status = await
|
|
10569
|
-
const aheadLog = await
|
|
10725
|
+
const status = await runGit2(options.cwd, ["status", "--porcelain"]);
|
|
10726
|
+
const aheadLog = await runGit2(options.cwd, ["log", `origin/${base}..HEAD`, "--oneline"]);
|
|
10570
10727
|
const hasUncommitted = Boolean(status.stdout.trim());
|
|
10571
10728
|
const hasCommits = Boolean(aheadLog.stdout.trim());
|
|
10572
10729
|
if (!hasUncommitted && !hasCommits) {
|
|
10573
10730
|
throw new Error("Agent completed without file changes; no PR was created.");
|
|
10574
10731
|
}
|
|
10575
10732
|
if (hasUncommitted) {
|
|
10576
|
-
await
|
|
10577
|
-
await
|
|
10733
|
+
await runGit2(options.cwd, ["add", "."]);
|
|
10734
|
+
await runGit2(options.cwd, [
|
|
10578
10735
|
"commit",
|
|
10579
10736
|
"-m",
|
|
10580
10737
|
`fix: resolve issue #${issue.number}`,
|
|
@@ -10584,7 +10741,7 @@ async function solveIssueCommand(issueNumber, options) {
|
|
|
10584
10741
|
Closes #${issue.number}`
|
|
10585
10742
|
]);
|
|
10586
10743
|
}
|
|
10587
|
-
await
|
|
10744
|
+
await runGit2(options.cwd, ["push", "-u", "origin", branch]);
|
|
10588
10745
|
const pr = await client.createPullRequest({
|
|
10589
10746
|
...repo,
|
|
10590
10747
|
title: `Fix: ${issue.title}`,
|
|
@@ -10623,17 +10780,23 @@ async function reviewPrCommand(prNumber, options) {
|
|
|
10623
10780
|
]);
|
|
10624
10781
|
const focusLine = options.focus && options.focus.length > 0 ? `
|
|
10625
10782
|
Focus areas: ${options.focus.join(", ")}.` : "";
|
|
10783
|
+
const truncation = truncateDiff(diff.trim());
|
|
10784
|
+
const truncationNote = truncation.omittedFiles > 0 ? `
|
|
10785
|
+
(Showing ${truncation.totalFiles - truncation.omittedFiles} of ${truncation.totalFiles} changed files; ${truncation.omittedFiles} file(s) omitted due to size.)
|
|
10786
|
+
` : "";
|
|
10626
10787
|
const prompt = [
|
|
10627
10788
|
`Review PR #${pr.number}: ${pr.title}`,
|
|
10628
10789
|
`Branch: ${pr.head ?? "?"} \u2192 ${pr.base ?? "?"}`,
|
|
10790
|
+
"Do not modify any files. Output the review only.",
|
|
10629
10791
|
"",
|
|
10630
10792
|
pr.body ? `Description:
|
|
10631
10793
|
${pr.body}` : "No description provided.",
|
|
10632
10794
|
"",
|
|
10633
10795
|
`Diff:
|
|
10634
10796
|
\`\`\`diff
|
|
10635
|
-
${diff}
|
|
10797
|
+
${truncation.diff}
|
|
10636
10798
|
\`\`\``,
|
|
10799
|
+
truncationNote,
|
|
10637
10800
|
"",
|
|
10638
10801
|
`Produce a structured code review with:${focusLine}`,
|
|
10639
10802
|
"1. **Summary** \u2014 what the PR does",
|
|
@@ -10641,21 +10804,30 @@ ${diff}
|
|
|
10641
10804
|
"3. **Suggestions** \u2014 improvements and nitpicks",
|
|
10642
10805
|
"4. **Verdict** \u2014 Approve / Request Changes / Neutral with a one-line rationale"
|
|
10643
10806
|
].join("\n");
|
|
10644
|
-
const target =
|
|
10807
|
+
const target = resolveSessionTarget(runtime.config, {
|
|
10808
|
+
provider: options.provider,
|
|
10809
|
+
model: options.model
|
|
10810
|
+
});
|
|
10645
10811
|
const session = runtime.sessions.create({
|
|
10646
10812
|
provider: target.provider,
|
|
10647
10813
|
model: target.model
|
|
10648
10814
|
});
|
|
10649
10815
|
const secretValues = collectSecretValues(runtime.config);
|
|
10650
10816
|
await writeStdoutLine(`Reviewing PR #${pr.number}: ${pr.title}`);
|
|
10651
|
-
|
|
10652
|
-
|
|
10653
|
-
|
|
10654
|
-
|
|
10655
|
-
|
|
10817
|
+
try {
|
|
10818
|
+
await runtime.agent.run({
|
|
10819
|
+
session,
|
|
10820
|
+
input: prompt,
|
|
10821
|
+
mode: "plan",
|
|
10822
|
+
onChunk: (text) => void writeStdout(redactText(text, secretValues))
|
|
10823
|
+
});
|
|
10824
|
+
} finally {
|
|
10825
|
+
await runtime.sessions.persist(session.id).catch(() => {
|
|
10826
|
+
});
|
|
10827
|
+
}
|
|
10656
10828
|
await writeStdout("\n");
|
|
10657
10829
|
}
|
|
10658
|
-
async function
|
|
10830
|
+
async function runGit2(cwd, args) {
|
|
10659
10831
|
const result = await execFileAsync("git", args, { cwd, timeoutMs: 18e4 });
|
|
10660
10832
|
if (result.exitCode !== 0) {
|
|
10661
10833
|
throw new Error(result.stderr || result.stdout || `git ${args.join(" ")} failed`);
|
|
@@ -10665,28 +10837,6 @@ async function runGit(cwd, args) {
|
|
|
10665
10837
|
function slugify(input) {
|
|
10666
10838
|
return input.toLowerCase().normalize("NFKD").replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-").replace(/-+/g, "-").slice(0, 48);
|
|
10667
10839
|
}
|
|
10668
|
-
function resolveSessionTarget(config, overrides = {}) {
|
|
10669
|
-
const requestedProvider = parseProviderId(overrides.provider);
|
|
10670
|
-
const fallback = resolveUsableProviderTarget(config, [
|
|
10671
|
-
requestedProvider,
|
|
10672
|
-
config.defaultProvider
|
|
10673
|
-
]);
|
|
10674
|
-
const parsedSelection = overrides.model ? parseModelSelection(overrides.model, requestedProvider ?? fallback.provider) : null;
|
|
10675
|
-
if (overrides.model && !parsedSelection) {
|
|
10676
|
-
throw new Error(
|
|
10677
|
-
`Invalid model selection: ${overrides.model}. Use "<model>" or "<provider>/<model>".`
|
|
10678
|
-
);
|
|
10679
|
-
}
|
|
10680
|
-
const provider = parsedSelection?.provider ?? requestedProvider ?? fallback.provider;
|
|
10681
|
-
const model = parsedSelection?.model ?? resolveConfiguredModelForProvider(config, provider) ?? (provider === fallback.provider ? fallback.model : void 0);
|
|
10682
|
-
return { provider, model };
|
|
10683
|
-
}
|
|
10684
|
-
function parseProviderId(value) {
|
|
10685
|
-
if (!value) return void 0;
|
|
10686
|
-
const parsed = ProviderIdSchema.safeParse(value);
|
|
10687
|
-
if (parsed.success) return parsed.data;
|
|
10688
|
-
throw new Error(`Invalid provider: ${value}. Expected one of: ${PROVIDER_IDS.join(", ")}`);
|
|
10689
|
-
}
|
|
10690
10840
|
async function runCommand(input, options) {
|
|
10691
10841
|
if (options.mode && options.mode !== "plan" && options.mode !== "build") {
|
|
10692
10842
|
throw new Error(`Invalid mode: ${options.mode}. Expected plan or build.`);
|
|
@@ -10983,130 +11133,6 @@ async function projectsCommand(options) {
|
|
|
10983
11133
|
);
|
|
10984
11134
|
await waitUntilExit();
|
|
10985
11135
|
}
|
|
10986
|
-
var DIFF_MAX_CHARS = 2e4;
|
|
10987
|
-
async function runGit2(cwd, args) {
|
|
10988
|
-
const result = await execFileAsync("git", args, { cwd, timeoutMs: 3e4 });
|
|
10989
|
-
if (result.exitCode !== 0) {
|
|
10990
|
-
throw new Error(result.stderr || `git ${args.join(" ")} failed`);
|
|
10991
|
-
}
|
|
10992
|
-
return result.stdout;
|
|
10993
|
-
}
|
|
10994
|
-
async function isGitRepo(cwd) {
|
|
10995
|
-
const result = await execFileAsync(
|
|
10996
|
-
"git",
|
|
10997
|
-
["rev-parse", "--is-inside-work-tree"],
|
|
10998
|
-
{ cwd, timeoutMs: 5e3 }
|
|
10999
|
-
);
|
|
11000
|
-
return result.exitCode === 0;
|
|
11001
|
-
}
|
|
11002
|
-
function buildDiffArgs(options) {
|
|
11003
|
-
if (options.staged) {
|
|
11004
|
-
const args2 = ["diff", "--cached"];
|
|
11005
|
-
if (options.file) args2.push("--", options.file);
|
|
11006
|
-
return { args: args2, label: "staged changes" };
|
|
11007
|
-
}
|
|
11008
|
-
if (options.ref) {
|
|
11009
|
-
const args2 = ["diff", options.ref];
|
|
11010
|
-
if (options.file) args2.push("--", options.file);
|
|
11011
|
-
return { args: args2, label: `diff vs ${options.ref}` };
|
|
11012
|
-
}
|
|
11013
|
-
const args = ["diff", "HEAD"];
|
|
11014
|
-
if (options.file) args.push("--", options.file);
|
|
11015
|
-
return { args, label: options.file ? `local changes in ${options.file}` : "local changes vs HEAD" };
|
|
11016
|
-
}
|
|
11017
|
-
function buildPrompt(diff, label, focus, truncated) {
|
|
11018
|
-
const focusLine = focus.length > 0 ? `
|
|
11019
|
-
Focus areas: ${focus.join(", ")}.` : "";
|
|
11020
|
-
const truncationNote = truncated ? `
|
|
11021
|
-
(Diff truncated at ${DIFF_MAX_CHARS} characters; some changes are not shown.)
|
|
11022
|
-
` : "";
|
|
11023
|
-
return [
|
|
11024
|
-
`Review the following local git diff (${label}).`,
|
|
11025
|
-
"Do not modify any files. Output the review only.",
|
|
11026
|
-
focusLine,
|
|
11027
|
-
"",
|
|
11028
|
-
`\`\`\`diff`,
|
|
11029
|
-
diff,
|
|
11030
|
-
`\`\`\``,
|
|
11031
|
-
truncationNote,
|
|
11032
|
-
"Produce a structured code review:",
|
|
11033
|
-
"1. **Summary** \u2014 what changed (inferred from the diff)",
|
|
11034
|
-
"2. **Issues** \u2014 bugs, security concerns, logic errors, missing error handling; quote the relevant lines",
|
|
11035
|
-
"3. **Suggestions** \u2014 improvements and nitpicks",
|
|
11036
|
-
"4. **Verdict** \u2014 Looks good / Has issues, with a one-line rationale"
|
|
11037
|
-
].filter((l) => l !== void 0).join("\n");
|
|
11038
|
-
}
|
|
11039
|
-
async function reviewCommand(options) {
|
|
11040
|
-
if (!await isGitRepo(options.cwd)) {
|
|
11041
|
-
await writeStderrLine("error: not inside a git repository");
|
|
11042
|
-
process.exit(1);
|
|
11043
|
-
}
|
|
11044
|
-
const { args, label } = buildDiffArgs(options);
|
|
11045
|
-
let rawDiff;
|
|
11046
|
-
try {
|
|
11047
|
-
rawDiff = await runGit2(options.cwd, args);
|
|
11048
|
-
} catch (err) {
|
|
11049
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
11050
|
-
await writeStderrLine(`error: ${msg}`);
|
|
11051
|
-
process.exit(1);
|
|
11052
|
-
}
|
|
11053
|
-
const trimmed = rawDiff.trim();
|
|
11054
|
-
if (!trimmed) {
|
|
11055
|
-
await writeStdoutLine(`No changes to review (${label}).`);
|
|
11056
|
-
return;
|
|
11057
|
-
}
|
|
11058
|
-
let diff = trimmed;
|
|
11059
|
-
let truncated = false;
|
|
11060
|
-
if (diff.length > DIFF_MAX_CHARS) {
|
|
11061
|
-
diff = diff.slice(0, DIFF_MAX_CHARS);
|
|
11062
|
-
truncated = true;
|
|
11063
|
-
}
|
|
11064
|
-
const runtime = await createRuntime({
|
|
11065
|
-
cwd: options.cwd,
|
|
11066
|
-
configPath: options.config,
|
|
11067
|
-
interactive: Boolean(options.yes)
|
|
11068
|
-
});
|
|
11069
|
-
if (options.yes) {
|
|
11070
|
-
runtime.events.on("approval:request", (request) => {
|
|
11071
|
-
runtime.events.emit("approval:decision", {
|
|
11072
|
-
requestId: request.id,
|
|
11073
|
-
decision: { allowed: true }
|
|
11074
|
-
});
|
|
11075
|
-
});
|
|
11076
|
-
}
|
|
11077
|
-
const target = resolveSessionTarget(runtime.config, {
|
|
11078
|
-
provider: options.provider,
|
|
11079
|
-
model: options.model
|
|
11080
|
-
});
|
|
11081
|
-
const session = runtime.sessions.create({
|
|
11082
|
-
provider: target.provider,
|
|
11083
|
-
model: target.model
|
|
11084
|
-
});
|
|
11085
|
-
const prompt = buildPrompt(diff, label, options.focus ?? [], truncated);
|
|
11086
|
-
const secretValues = collectSecretValues(runtime.config);
|
|
11087
|
-
await writeStdoutLine(`Reviewing ${label}\u2026
|
|
11088
|
-
`);
|
|
11089
|
-
let streamed = false;
|
|
11090
|
-
try {
|
|
11091
|
-
const output = await runtime.agent.run({
|
|
11092
|
-
session,
|
|
11093
|
-
input: prompt,
|
|
11094
|
-
mode: "build",
|
|
11095
|
-
provider: target.provider,
|
|
11096
|
-
onChunk: (text) => {
|
|
11097
|
-
streamed = true;
|
|
11098
|
-
process.stdout.write(redactText(text, secretValues));
|
|
11099
|
-
}
|
|
11100
|
-
});
|
|
11101
|
-
if (!streamed && output) {
|
|
11102
|
-
process.stdout.write(redactText(output, secretValues));
|
|
11103
|
-
}
|
|
11104
|
-
if (!streamed || !output) process.stdout.write("\n");
|
|
11105
|
-
} finally {
|
|
11106
|
-
await runtime.sessions.persist(session.id).catch(() => {
|
|
11107
|
-
});
|
|
11108
|
-
}
|
|
11109
|
-
}
|
|
11110
11136
|
function sessionLabel(session) {
|
|
11111
11137
|
const name = typeof session.metadata["name"] === "string" ? session.metadata["name"] : void 0;
|
|
11112
11138
|
const firstUser = session.messages.find((m) => m.role === "user");
|
|
@@ -31477,7 +31503,7 @@ function createProgram() {
|
|
|
31477
31503
|
"focus area: security, performance, correctness, style; repeat for multiple",
|
|
31478
31504
|
collectOption,
|
|
31479
31505
|
[]
|
|
31480
|
-
).action(async (number, options) => {
|
|
31506
|
+
).option("--provider <provider>", "provider override").option("--model <model>", "model override").action(async (number, options) => {
|
|
31481
31507
|
const prNumber = Number.parseInt(number, 10);
|
|
31482
31508
|
if (!Number.isInteger(prNumber) || prNumber <= 0) {
|
|
31483
31509
|
throw new Error(`Invalid PR number: ${number}`);
|
|
@@ -31485,7 +31511,9 @@ function createProgram() {
|
|
|
31485
31511
|
await reviewPrCommand(prNumber, {
|
|
31486
31512
|
cwd: program.opts().cwd,
|
|
31487
31513
|
config: program.opts().config,
|
|
31488
|
-
focus: options.focus
|
|
31514
|
+
focus: options.focus,
|
|
31515
|
+
provider: options.provider,
|
|
31516
|
+
model: options.model
|
|
31489
31517
|
});
|
|
31490
31518
|
});
|
|
31491
31519
|
github.command("solve").description("solve a GitHub issue end-to-end with branch, commit, push, and PR").argument("<number>", "issue number").option("--base <base>", "base branch", "main").option("-y, --yes", "approve commit/push/PR workflow").action(async (number, options) => {
|