@polka-codes/cli 0.9.3 → 0.9.4
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 +181 -33
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -39731,7 +39731,7 @@ var {
|
|
|
39731
39731
|
Help
|
|
39732
39732
|
} = import__.default;
|
|
39733
39733
|
// package.json
|
|
39734
|
-
var version = "0.9.
|
|
39734
|
+
var version = "0.9.4";
|
|
39735
39735
|
|
|
39736
39736
|
// ../../node_modules/@inquirer/core/dist/esm/lib/key.js
|
|
39737
39737
|
var isUpKey = (key) => key.name === "up" || key.name === "k" || key.ctrl && key.name === "p";
|
|
@@ -76672,21 +76672,27 @@ ${instance.prompt}`;
|
|
|
76672
76672
|
const requestTimeoutSeconds = this.config.requestTimeoutSeconds ?? 90;
|
|
76673
76673
|
let respMessages = [];
|
|
76674
76674
|
for (let i = 0;i < retryCount; i++) {
|
|
76675
|
+
if (this.#aborted) {
|
|
76676
|
+
break;
|
|
76677
|
+
}
|
|
76675
76678
|
respMessages = [];
|
|
76676
76679
|
let timeout;
|
|
76680
|
+
let requestAbortController;
|
|
76681
|
+
requestAbortController = new AbortController;
|
|
76682
|
+
this.#abortController = requestAbortController;
|
|
76677
76683
|
const resetTimeout = () => {
|
|
76678
76684
|
if (timeout) {
|
|
76679
76685
|
clearTimeout(timeout);
|
|
76680
76686
|
}
|
|
76681
|
-
if (requestTimeoutSeconds > 0) {
|
|
76687
|
+
if (requestTimeoutSeconds > 0 && requestAbortController) {
|
|
76682
76688
|
timeout = setTimeout(() => {
|
|
76683
|
-
console.debug(`
|
|
76684
|
-
|
|
76689
|
+
console.debug(`Request timeout after ${requestTimeoutSeconds} seconds. Canceling current request attempt ${i + 1}/${retryCount}.`);
|
|
76690
|
+
requestAbortController?.abort();
|
|
76685
76691
|
}, requestTimeoutSeconds * 1000);
|
|
76686
76692
|
}
|
|
76687
76693
|
};
|
|
76688
|
-
this.#abortController = new AbortController;
|
|
76689
76694
|
try {
|
|
76695
|
+
resetTimeout();
|
|
76690
76696
|
const streamTextOptions = {
|
|
76691
76697
|
model: this.ai,
|
|
76692
76698
|
messages,
|
|
@@ -76708,7 +76714,7 @@ ${instance.prompt}`;
|
|
|
76708
76714
|
onError: async (error81) => {
|
|
76709
76715
|
console.error("Error in stream:", error81);
|
|
76710
76716
|
},
|
|
76711
|
-
abortSignal:
|
|
76717
|
+
abortSignal: requestAbortController.signal
|
|
76712
76718
|
};
|
|
76713
76719
|
if (this.config.toolFormat === "native") {
|
|
76714
76720
|
streamTextOptions.tools = this.#toolSet;
|
|
@@ -76721,11 +76727,19 @@ ${instance.prompt}`;
|
|
|
76721
76727
|
});
|
|
76722
76728
|
const resp = await stream.response;
|
|
76723
76729
|
respMessages = resp.messages;
|
|
76730
|
+
if (timeout) {
|
|
76731
|
+
clearTimeout(timeout);
|
|
76732
|
+
timeout = undefined;
|
|
76733
|
+
}
|
|
76724
76734
|
} catch (error81) {
|
|
76725
76735
|
if (error81 instanceof Error && error81.name === "AbortError") {
|
|
76726
|
-
|
|
76736
|
+
if (this.#aborted) {
|
|
76737
|
+
break;
|
|
76738
|
+
}
|
|
76739
|
+
console.debug(`Request attempt ${i + 1} timed out, will retry`);
|
|
76740
|
+
} else {
|
|
76741
|
+
console.error("Error in stream:", error81);
|
|
76727
76742
|
}
|
|
76728
|
-
console.error("Error in stream:", error81);
|
|
76729
76743
|
} finally {
|
|
76730
76744
|
if (timeout) {
|
|
76731
76745
|
clearTimeout(timeout);
|
|
@@ -76737,13 +76751,15 @@ ${instance.prompt}`;
|
|
|
76737
76751
|
if (this.#aborted) {
|
|
76738
76752
|
break;
|
|
76739
76753
|
}
|
|
76740
|
-
|
|
76754
|
+
if (i < retryCount - 1) {
|
|
76755
|
+
console.debug(`Retrying request ${i + 2} of ${retryCount}`);
|
|
76756
|
+
}
|
|
76741
76757
|
}
|
|
76742
76758
|
if (respMessages.length === 0) {
|
|
76743
76759
|
if (this.#aborted) {
|
|
76744
76760
|
return [];
|
|
76745
76761
|
}
|
|
76746
|
-
throw new Error("No assistant message received");
|
|
76762
|
+
throw new Error("No assistant message received after all retry attempts");
|
|
76747
76763
|
}
|
|
76748
76764
|
this.#messages.push(...respMessages);
|
|
76749
76765
|
if (this.config.toolFormat === "native") {
|
|
@@ -76754,7 +76770,7 @@ ${instance.prompt}`;
|
|
|
76754
76770
|
return [{ type: "text", content }];
|
|
76755
76771
|
}
|
|
76756
76772
|
return content.flatMap((part) => {
|
|
76757
|
-
if (part.type === "text") {
|
|
76773
|
+
if (part.type === "text" || part.type === "reasoning") {
|
|
76758
76774
|
return [{ type: "text", content: part.text }];
|
|
76759
76775
|
}
|
|
76760
76776
|
if (part.type === "tool-call") {
|
|
@@ -78151,37 +78167,48 @@ var prompt5 = `
|
|
|
78151
78167
|
|
|
78152
78168
|
You are a senior software engineer reviewing code changes.
|
|
78153
78169
|
|
|
78170
|
+
## Critical Instructions
|
|
78171
|
+
**ONLY review the actual changes shown in the diff.** Do not comment on existing code that wasn't modified.
|
|
78172
|
+
|
|
78154
78173
|
## Viewing Changes
|
|
78155
|
-
- Use
|
|
78156
|
-
- **Pull request**: use the provided commit range.
|
|
78157
|
-
- **Local changes**: diff staged or unstaged files.
|
|
78174
|
+
- **Use git_diff** to inspect the actual code changes for each relevant file.
|
|
78175
|
+
- **Pull request**: use the provided commit range for the git_diff tool.
|
|
78176
|
+
- **Local changes**: diff staged or unstaged files using the git_diff tool.
|
|
78158
78177
|
- If a pull request is present you may receive:
|
|
78159
78178
|
- <pr_title>
|
|
78160
78179
|
- <pr_description>
|
|
78161
78180
|
- <commit_messages>
|
|
78162
78181
|
- A <review_instructions> tag tells you the focus of the review.
|
|
78182
|
+
- File status information is provided in <file_status> - use this to understand which files were modified, added, deleted, or renamed.
|
|
78183
|
+
|
|
78184
|
+
## Review Guidelines
|
|
78185
|
+
Focus exclusively on the changed lines (+ additions, - deletions, modified lines):
|
|
78186
|
+
- **Specific issues**: Point to exact problems in the changed code with line references
|
|
78187
|
+
- **Actionable fixes**: Provide concrete solutions, not vague suggestions
|
|
78188
|
+
- **Clear reasoning**: Explain why each issue matters and how to fix it
|
|
78189
|
+
- **Avoid generic advice**: No generic suggestions like "add more tests", "improve documentation", or "follow best practices" unless directly related to a specific problem in the diff
|
|
78163
78190
|
|
|
78164
|
-
##
|
|
78165
|
-
-
|
|
78166
|
-
-
|
|
78167
|
-
-
|
|
78168
|
-
-
|
|
78169
|
-
- Best-practice adherence
|
|
78191
|
+
## What NOT to review
|
|
78192
|
+
- Existing unchanged code
|
|
78193
|
+
- Overall project structure or architecture (unless directly impacted by changes)
|
|
78194
|
+
- Generic best practices unrelated to the specific changes
|
|
78195
|
+
- Missing features or functionality not part of this diff
|
|
78170
78196
|
|
|
78171
78197
|
## Output Format
|
|
78172
78198
|
Do **not** include praise or positive feedback. Ignore generated files such as lock files.
|
|
78199
|
+
Only include reviews for actual issues found in the changed code.
|
|
78173
78200
|
|
|
78174
78201
|
Return your review as a JSON object inside a \`\`\`json block, wrapped like:
|
|
78175
78202
|
<tool_attempt_completion>
|
|
78176
78203
|
<tool_parameter_result>
|
|
78177
78204
|
\`\`\`json
|
|
78178
78205
|
{
|
|
78179
|
-
"overview": "Summary of
|
|
78206
|
+
"overview": "Summary of specific issues found in the diff changes, or 'No issues found' if the changes look good.",
|
|
78180
78207
|
"specificReviews": [
|
|
78181
78208
|
{
|
|
78182
78209
|
"file": "path/filename.ext",
|
|
78183
78210
|
"lines": "N or N-M",
|
|
78184
|
-
"review": "
|
|
78211
|
+
"review": "Specific issue with the changed code and exact actionable fix."
|
|
78185
78212
|
}
|
|
78186
78213
|
]
|
|
78187
78214
|
}
|
|
@@ -78209,14 +78236,21 @@ ${params.pullRequestDescription}
|
|
|
78209
78236
|
parts.push(`<commit_messages>
|
|
78210
78237
|
${params.commitMessages}
|
|
78211
78238
|
</commit_messages>`);
|
|
78239
|
+
}
|
|
78240
|
+
if (params.changedFiles && params.changedFiles.length > 0) {
|
|
78241
|
+
const fileList = params.changedFiles.map((file3) => `${file3.status}: ${file3.path}`).join(`
|
|
78242
|
+
`);
|
|
78243
|
+
parts.push(`<file_status>
|
|
78244
|
+
${fileList}
|
|
78245
|
+
</file_status>`);
|
|
78212
78246
|
}
|
|
78213
78247
|
let instructions = "";
|
|
78214
78248
|
if (params.commitRange) {
|
|
78215
|
-
instructions = `Review the pull request.
|
|
78249
|
+
instructions = `Review the pull request. Use the git_diff tool with commit range '${params.commitRange}' to inspect the actual code changes. File status information is already provided above.`;
|
|
78216
78250
|
} else if (params.staged) {
|
|
78217
|
-
instructions = "Review the staged changes.
|
|
78251
|
+
instructions = "Review the staged changes. Use the git_diff tool with staged: true to inspect the actual code changes. File status information is already provided above.";
|
|
78218
78252
|
} else {
|
|
78219
|
-
instructions = "Review the unstaged changes.
|
|
78253
|
+
instructions = "Review the unstaged changes. Use the git_diff tool to inspect the actual code changes. File status information is already provided above.";
|
|
78220
78254
|
}
|
|
78221
78255
|
parts.push(`<review_instructions>
|
|
78222
78256
|
${instructions}
|
|
@@ -103767,13 +103801,14 @@ var getModel = (config5, debugLogging = false) => {
|
|
|
103767
103801
|
console.dir(requestBody, { depth: null });
|
|
103768
103802
|
}
|
|
103769
103803
|
if (TRACING_FILE) {
|
|
103770
|
-
appendFileSync(TRACING_FILE, JSON.stringify({
|
|
103804
|
+
appendFileSync(TRACING_FILE, `${JSON.stringify({
|
|
103771
103805
|
type: "request",
|
|
103772
103806
|
timestamp: new Date().toISOString(),
|
|
103773
103807
|
url: url4,
|
|
103774
103808
|
headers: options?.headers,
|
|
103775
103809
|
body: requestBody
|
|
103776
|
-
}, null, 2)
|
|
103810
|
+
}, null, 2)}
|
|
103811
|
+
`);
|
|
103777
103812
|
}
|
|
103778
103813
|
const res = await fetch(url4, options);
|
|
103779
103814
|
if (debugLogging) {
|
|
@@ -110522,6 +110557,89 @@ var prCommand = new Command("pr").description("Create a GitHub pull request").ar
|
|
|
110522
110557
|
// src/commands/review.ts
|
|
110523
110558
|
import { execSync as execSync3 } from "node:child_process";
|
|
110524
110559
|
var import_lodash9 = __toESM(require_lodash(), 1);
|
|
110560
|
+
function parseGitStatus(statusOutput) {
|
|
110561
|
+
const statusLines = statusOutput.split(`
|
|
110562
|
+
`).filter((line) => line);
|
|
110563
|
+
const files = [];
|
|
110564
|
+
for (const line of statusLines) {
|
|
110565
|
+
const indexStatus = line[0];
|
|
110566
|
+
const workingTreeStatus = line[1];
|
|
110567
|
+
const filepath = line.slice(3);
|
|
110568
|
+
const statuses = [];
|
|
110569
|
+
if (indexStatus !== " " && indexStatus !== "?") {
|
|
110570
|
+
switch (indexStatus) {
|
|
110571
|
+
case "A":
|
|
110572
|
+
statuses.push("Added (staged)");
|
|
110573
|
+
break;
|
|
110574
|
+
case "M":
|
|
110575
|
+
statuses.push("Modified (staged)");
|
|
110576
|
+
break;
|
|
110577
|
+
case "D":
|
|
110578
|
+
statuses.push("Deleted (staged)");
|
|
110579
|
+
break;
|
|
110580
|
+
case "R":
|
|
110581
|
+
statuses.push("Renamed (staged)");
|
|
110582
|
+
break;
|
|
110583
|
+
case "C":
|
|
110584
|
+
statuses.push("Copied (staged)");
|
|
110585
|
+
break;
|
|
110586
|
+
default:
|
|
110587
|
+
statuses.push("Changed (staged)");
|
|
110588
|
+
}
|
|
110589
|
+
}
|
|
110590
|
+
if (workingTreeStatus !== " ") {
|
|
110591
|
+
switch (workingTreeStatus) {
|
|
110592
|
+
case "M":
|
|
110593
|
+
statuses.push("Modified (unstaged)");
|
|
110594
|
+
break;
|
|
110595
|
+
case "D":
|
|
110596
|
+
statuses.push("Deleted (unstaged)");
|
|
110597
|
+
break;
|
|
110598
|
+
case "?":
|
|
110599
|
+
statuses.push("Untracked");
|
|
110600
|
+
break;
|
|
110601
|
+
default:
|
|
110602
|
+
statuses.push("Changed (unstaged)");
|
|
110603
|
+
}
|
|
110604
|
+
}
|
|
110605
|
+
if (statuses.length > 0) {
|
|
110606
|
+
files.push({ path: filepath, status: statuses.join(", ") });
|
|
110607
|
+
}
|
|
110608
|
+
}
|
|
110609
|
+
return files;
|
|
110610
|
+
}
|
|
110611
|
+
function parseGitDiffNameStatus(diffOutput) {
|
|
110612
|
+
const lines = diffOutput.split(`
|
|
110613
|
+
`).filter((line) => line.trim());
|
|
110614
|
+
return lines.map((line) => {
|
|
110615
|
+
const [status, ...pathParts] = line.split("\t");
|
|
110616
|
+
const path = pathParts.join("\t");
|
|
110617
|
+
let statusDescription;
|
|
110618
|
+
switch (status[0]) {
|
|
110619
|
+
case "A":
|
|
110620
|
+
statusDescription = "Added";
|
|
110621
|
+
break;
|
|
110622
|
+
case "M":
|
|
110623
|
+
statusDescription = "Modified";
|
|
110624
|
+
break;
|
|
110625
|
+
case "D":
|
|
110626
|
+
statusDescription = "Deleted";
|
|
110627
|
+
break;
|
|
110628
|
+
case "R":
|
|
110629
|
+
statusDescription = "Renamed";
|
|
110630
|
+
break;
|
|
110631
|
+
case "C":
|
|
110632
|
+
statusDescription = "Copied";
|
|
110633
|
+
break;
|
|
110634
|
+
case "T":
|
|
110635
|
+
statusDescription = "Type changed";
|
|
110636
|
+
break;
|
|
110637
|
+
default:
|
|
110638
|
+
statusDescription = "Unknown";
|
|
110639
|
+
}
|
|
110640
|
+
return { path, status: statusDescription };
|
|
110641
|
+
});
|
|
110642
|
+
}
|
|
110525
110643
|
var reviewCommand = new Command("review").description("Review a GitHub pull request or local changes").option("--pr <pr>", "The pull request number or URL to review").option("--json", "Output the review in JSON format", false).action(async (options, command) => {
|
|
110526
110644
|
const parentOptions = command.parent?.opts() ?? {};
|
|
110527
110645
|
const { providerConfig, config: config6 } = parseOptions(parentOptions);
|
|
@@ -110604,12 +110722,21 @@ async function reviewPR(prIdentifier, spinner, sharedAiOptions, isJsonOutput) {
|
|
|
110604
110722
|
const commitMessages = prDetails.commits.map((c) => c.messageBody).join(`
|
|
110605
110723
|
---
|
|
110606
110724
|
`);
|
|
110725
|
+
spinner.text = "Getting file changes...";
|
|
110726
|
+
let changedFiles = [];
|
|
110727
|
+
try {
|
|
110728
|
+
const diffNameStatus = execSync3(`git diff --name-status --no-color ${defaultBranch}...HEAD`, { encoding: "utf-8" });
|
|
110729
|
+
changedFiles = parseGitDiffNameStatus(diffNameStatus);
|
|
110730
|
+
} catch (_error) {
|
|
110731
|
+
console.warn("Warning: Could not retrieve file changes list");
|
|
110732
|
+
}
|
|
110607
110733
|
spinner.text = "Generating review...";
|
|
110608
110734
|
const result = await reviewDiff(sharedAiOptions, {
|
|
110609
110735
|
commitRange: `${defaultBranch}...HEAD`,
|
|
110610
110736
|
pullRequestTitle: prDetails.title,
|
|
110611
110737
|
pullRequestDescription: prDetails.body,
|
|
110612
|
-
commitMessages
|
|
110738
|
+
commitMessages,
|
|
110739
|
+
changedFiles
|
|
110613
110740
|
});
|
|
110614
110741
|
spinner.succeed("Review generated successfully");
|
|
110615
110742
|
if (isJsonOutput) {
|
|
@@ -110619,10 +110746,19 @@ async function reviewPR(prIdentifier, spinner, sharedAiOptions, isJsonOutput) {
|
|
|
110619
110746
|
}
|
|
110620
110747
|
}
|
|
110621
110748
|
async function reviewLocal(spinner, sharedAiOptions, isJsonOutput) {
|
|
110622
|
-
const
|
|
110749
|
+
const gitStatus = execSync3("git status --porcelain=v1", { encoding: "utf-8" }).trim();
|
|
110750
|
+
const statusLines = gitStatus.split(`
|
|
110751
|
+
`).filter((line) => line);
|
|
110752
|
+
const hasStagedChanges = statusLines.some((line) => "MARC".includes(line[0]));
|
|
110753
|
+
const hasUnstagedChanges = statusLines.some((line) => "MARCDU".includes(line[1]));
|
|
110754
|
+
const changedFiles = parseGitStatus(gitStatus);
|
|
110623
110755
|
if (hasStagedChanges) {
|
|
110624
110756
|
spinner.text = "Generating review for staged changes...";
|
|
110625
|
-
const
|
|
110757
|
+
const stagedFiles = changedFiles.filter((file4) => file4.status.includes("staged"));
|
|
110758
|
+
const result2 = await reviewDiff(sharedAiOptions, {
|
|
110759
|
+
staged: true,
|
|
110760
|
+
changedFiles: stagedFiles
|
|
110761
|
+
});
|
|
110626
110762
|
spinner.succeed("Review generated successfully");
|
|
110627
110763
|
if (isJsonOutput) {
|
|
110628
110764
|
console.log(JSON.stringify(result2, null, 2));
|
|
@@ -110631,10 +110767,13 @@ async function reviewLocal(spinner, sharedAiOptions, isJsonOutput) {
|
|
|
110631
110767
|
}
|
|
110632
110768
|
return;
|
|
110633
110769
|
}
|
|
110634
|
-
const hasUnstagedChanges = execSync3('git diff --quiet || echo "unstaged"', { encoding: "utf-8" }).trim() === "unstaged";
|
|
110635
110770
|
if (hasUnstagedChanges) {
|
|
110636
110771
|
spinner.text = "Generating review for unstaged changes...";
|
|
110637
|
-
const
|
|
110772
|
+
const unstagedFiles = changedFiles.filter((file4) => file4.status.includes("unstaged") || file4.status.includes("Untracked"));
|
|
110773
|
+
const result2 = await reviewDiff(sharedAiOptions, {
|
|
110774
|
+
staged: false,
|
|
110775
|
+
changedFiles: unstagedFiles
|
|
110776
|
+
});
|
|
110638
110777
|
spinner.succeed("Review generated successfully");
|
|
110639
110778
|
if (isJsonOutput) {
|
|
110640
110779
|
console.log(JSON.stringify(result2, null, 2));
|
|
@@ -110659,9 +110798,18 @@ async function reviewLocal(spinner, sharedAiOptions, isJsonOutput) {
|
|
|
110659
110798
|
spinner.succeed(`No changes to review. You are on the default branch ('${defaultBranch}').`);
|
|
110660
110799
|
process.exit(0);
|
|
110661
110800
|
}
|
|
110801
|
+
spinner.text = "Getting file changes...";
|
|
110802
|
+
let branchChangedFiles = [];
|
|
110803
|
+
try {
|
|
110804
|
+
const diffNameStatus = execSync3(`git diff --name-status --no-color ${defaultBranch}...${currentBranch}`, { encoding: "utf-8" });
|
|
110805
|
+
branchChangedFiles = parseGitDiffNameStatus(diffNameStatus);
|
|
110806
|
+
} catch (_error) {
|
|
110807
|
+
console.warn("Warning: Could not retrieve file changes list");
|
|
110808
|
+
}
|
|
110662
110809
|
spinner.text = `Generating review for changes between '${defaultBranch}' and '${currentBranch}'...`;
|
|
110663
110810
|
const result = await reviewDiff(sharedAiOptions, {
|
|
110664
|
-
commitRange: `${defaultBranch}...${currentBranch}
|
|
110811
|
+
commitRange: `${defaultBranch}...${currentBranch}`,
|
|
110812
|
+
changedFiles: branchChangedFiles
|
|
110665
110813
|
});
|
|
110666
110814
|
spinner.succeed("Review generated successfully");
|
|
110667
110815
|
if (isJsonOutput) {
|