@polka-codes/cli 0.9.3 → 0.9.5
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 +260 -75
- package/package.json +4 -4
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.5";
|
|
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";
|
|
@@ -52567,7 +52567,17 @@ var toolInfo7 = {
|
|
|
52567
52567
|
return true;
|
|
52568
52568
|
}
|
|
52569
52569
|
return val;
|
|
52570
|
-
}, exports_external.boolean().optional().default(true)).describe("Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.").meta({ usageValue: "true or false (optional)" })
|
|
52570
|
+
}, exports_external.boolean().optional().default(true)).describe("Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.").meta({ usageValue: "true or false (optional)" }),
|
|
52571
|
+
includeIgnored: exports_external.preprocess((val) => {
|
|
52572
|
+
if (typeof val === "string") {
|
|
52573
|
+
const lower = val.toLowerCase();
|
|
52574
|
+
if (lower === "false")
|
|
52575
|
+
return false;
|
|
52576
|
+
if (lower === "true")
|
|
52577
|
+
return true;
|
|
52578
|
+
}
|
|
52579
|
+
return val;
|
|
52580
|
+
}, exports_external.boolean().optional().default(false)).describe("Whether to include ignored files. Use true to include files ignored by .gitignore.").meta({ usageValue: "true or false (optional)" })
|
|
52571
52581
|
}).meta({
|
|
52572
52582
|
examples: [
|
|
52573
52583
|
{
|
|
@@ -52588,8 +52598,8 @@ var handler7 = async (provider, args) => {
|
|
|
52588
52598
|
message: "Not possible to list files. Abort."
|
|
52589
52599
|
};
|
|
52590
52600
|
}
|
|
52591
|
-
const { path, maxCount, recursive } = toolInfo7.parameters.parse(args);
|
|
52592
|
-
const [files, limitReached] = await provider.listFiles(path, recursive, maxCount);
|
|
52601
|
+
const { path, maxCount, recursive, includeIgnored } = toolInfo7.parameters.parse(args);
|
|
52602
|
+
const [files, limitReached] = await provider.listFiles(path, recursive, maxCount, includeIgnored);
|
|
52593
52603
|
return {
|
|
52594
52604
|
type: "Reply" /* Reply */,
|
|
52595
52605
|
message: `<list_files_path>${path}</list_files_path>
|
|
@@ -52618,7 +52628,17 @@ var toolInfo8 = {
|
|
|
52618
52628
|
return [];
|
|
52619
52629
|
const values = Array.isArray(val) ? val : [val];
|
|
52620
52630
|
return values.flatMap((i) => typeof i === "string" ? i.split(",") : []).filter((s) => s.length > 0);
|
|
52621
|
-
}, exports_external.array(exports_external.string())).describe("The path of the file to read").meta({ usageValue: "Comma separated paths here" })
|
|
52631
|
+
}, exports_external.array(exports_external.string())).describe("The path of the file to read").meta({ usageValue: "Comma separated paths here" }),
|
|
52632
|
+
includeIgnored: exports_external.preprocess((val) => {
|
|
52633
|
+
if (typeof val === "string") {
|
|
52634
|
+
const lower = val.toLowerCase();
|
|
52635
|
+
if (lower === "false")
|
|
52636
|
+
return false;
|
|
52637
|
+
if (lower === "true")
|
|
52638
|
+
return true;
|
|
52639
|
+
}
|
|
52640
|
+
return val;
|
|
52641
|
+
}, exports_external.boolean().optional().default(false)).describe("Whether to include ignored files. Use true to include files ignored by .gitignore.").meta({ usageValue: "true or false (optional)" })
|
|
52622
52642
|
}).meta({
|
|
52623
52643
|
examples: [
|
|
52624
52644
|
{
|
|
@@ -52644,10 +52664,10 @@ var handler8 = async (provider, args) => {
|
|
|
52644
52664
|
message: "Not possible to read file. Abort."
|
|
52645
52665
|
};
|
|
52646
52666
|
}
|
|
52647
|
-
const { path: paths } = toolInfo8.parameters.parse(args);
|
|
52667
|
+
const { path: paths, includeIgnored } = toolInfo8.parameters.parse(args);
|
|
52648
52668
|
const resp = [];
|
|
52649
52669
|
for (const path of paths) {
|
|
52650
|
-
const fileContent = await provider.readFile(path);
|
|
52670
|
+
const fileContent = await provider.readFile(path, includeIgnored);
|
|
52651
52671
|
if (!fileContent) {
|
|
52652
52672
|
resp.push(`<read_file_file_content path="${path}" file_not_found="true" />`);
|
|
52653
52673
|
} else {
|
|
@@ -52957,7 +52977,7 @@ var handler11 = async (provider, args) => {
|
|
|
52957
52977
|
}
|
|
52958
52978
|
try {
|
|
52959
52979
|
const { path, diff } = toolInfo11.parameters.parse(args);
|
|
52960
|
-
const fileContent = await provider.readFile(path);
|
|
52980
|
+
const fileContent = await provider.readFile(path, false);
|
|
52961
52981
|
if (fileContent == null) {
|
|
52962
52982
|
return {
|
|
52963
52983
|
type: "Error" /* Error */,
|
|
@@ -76672,23 +76692,30 @@ ${instance.prompt}`;
|
|
|
76672
76692
|
const requestTimeoutSeconds = this.config.requestTimeoutSeconds ?? 90;
|
|
76673
76693
|
let respMessages = [];
|
|
76674
76694
|
for (let i = 0;i < retryCount; i++) {
|
|
76695
|
+
if (this.#aborted) {
|
|
76696
|
+
break;
|
|
76697
|
+
}
|
|
76675
76698
|
respMessages = [];
|
|
76676
76699
|
let timeout;
|
|
76700
|
+
let requestAbortController;
|
|
76701
|
+
requestAbortController = new AbortController;
|
|
76702
|
+
this.#abortController = requestAbortController;
|
|
76677
76703
|
const resetTimeout = () => {
|
|
76678
76704
|
if (timeout) {
|
|
76679
76705
|
clearTimeout(timeout);
|
|
76680
76706
|
}
|
|
76681
|
-
if (requestTimeoutSeconds > 0) {
|
|
76707
|
+
if (requestTimeoutSeconds > 0 && requestAbortController) {
|
|
76682
76708
|
timeout = setTimeout(() => {
|
|
76683
|
-
console.debug(`
|
|
76684
|
-
|
|
76709
|
+
console.debug(`Request timeout after ${requestTimeoutSeconds} seconds. Canceling current request attempt ${i + 1}/${retryCount}.`);
|
|
76710
|
+
requestAbortController?.abort();
|
|
76685
76711
|
}, requestTimeoutSeconds * 1000);
|
|
76686
76712
|
}
|
|
76687
76713
|
};
|
|
76688
|
-
this.#abortController = new AbortController;
|
|
76689
76714
|
try {
|
|
76715
|
+
resetTimeout();
|
|
76690
76716
|
const streamTextOptions = {
|
|
76691
76717
|
model: this.ai,
|
|
76718
|
+
temperature: 0,
|
|
76692
76719
|
messages,
|
|
76693
76720
|
providerOptions: this.config.parameters?.providerOptions,
|
|
76694
76721
|
onChunk: async ({ chunk }) => {
|
|
@@ -76708,7 +76735,7 @@ ${instance.prompt}`;
|
|
|
76708
76735
|
onError: async (error81) => {
|
|
76709
76736
|
console.error("Error in stream:", error81);
|
|
76710
76737
|
},
|
|
76711
|
-
abortSignal:
|
|
76738
|
+
abortSignal: requestAbortController.signal
|
|
76712
76739
|
};
|
|
76713
76740
|
if (this.config.toolFormat === "native") {
|
|
76714
76741
|
streamTextOptions.tools = this.#toolSet;
|
|
@@ -76721,11 +76748,19 @@ ${instance.prompt}`;
|
|
|
76721
76748
|
});
|
|
76722
76749
|
const resp = await stream.response;
|
|
76723
76750
|
respMessages = resp.messages;
|
|
76751
|
+
if (timeout) {
|
|
76752
|
+
clearTimeout(timeout);
|
|
76753
|
+
timeout = undefined;
|
|
76754
|
+
}
|
|
76724
76755
|
} catch (error81) {
|
|
76725
76756
|
if (error81 instanceof Error && error81.name === "AbortError") {
|
|
76726
|
-
|
|
76757
|
+
if (this.#aborted) {
|
|
76758
|
+
break;
|
|
76759
|
+
}
|
|
76760
|
+
console.debug(`Request attempt ${i + 1} timed out, will retry`);
|
|
76761
|
+
} else {
|
|
76762
|
+
console.error("Error in stream:", error81);
|
|
76727
76763
|
}
|
|
76728
|
-
console.error("Error in stream:", error81);
|
|
76729
76764
|
} finally {
|
|
76730
76765
|
if (timeout) {
|
|
76731
76766
|
clearTimeout(timeout);
|
|
@@ -76737,16 +76772,26 @@ ${instance.prompt}`;
|
|
|
76737
76772
|
if (this.#aborted) {
|
|
76738
76773
|
break;
|
|
76739
76774
|
}
|
|
76740
|
-
|
|
76775
|
+
if (i < retryCount - 1) {
|
|
76776
|
+
console.debug(`Retrying request ${i + 2} of ${retryCount}`);
|
|
76777
|
+
}
|
|
76741
76778
|
}
|
|
76742
76779
|
if (respMessages.length === 0) {
|
|
76743
76780
|
if (this.#aborted) {
|
|
76744
76781
|
return [];
|
|
76745
76782
|
}
|
|
76746
|
-
throw new Error("No assistant message received");
|
|
76783
|
+
throw new Error("No assistant message received after all retry attempts");
|
|
76747
76784
|
}
|
|
76748
76785
|
this.#messages.push(...respMessages);
|
|
76749
76786
|
if (this.config.toolFormat === "native") {
|
|
76787
|
+
const assistantText = respMessages.map((msg) => {
|
|
76788
|
+
if (typeof msg.content === "string") {
|
|
76789
|
+
return msg.content;
|
|
76790
|
+
}
|
|
76791
|
+
return msg.content.map((part) => part.type === "text" || part.type === "reasoning" ? part.text : "").join("");
|
|
76792
|
+
}).join(`
|
|
76793
|
+
`);
|
|
76794
|
+
await this.#callback({ kind: "EndRequest" /* EndRequest */, agent: this, message: assistantText });
|
|
76750
76795
|
return respMessages.flatMap((msg) => {
|
|
76751
76796
|
if (msg.role === "assistant") {
|
|
76752
76797
|
const content = msg.content;
|
|
@@ -76754,7 +76799,7 @@ ${instance.prompt}`;
|
|
|
76754
76799
|
return [{ type: "text", content }];
|
|
76755
76800
|
}
|
|
76756
76801
|
return content.flatMap((part) => {
|
|
76757
|
-
if (part.type === "text") {
|
|
76802
|
+
if (part.type === "text" || part.type === "reasoning") {
|
|
76758
76803
|
return [{ type: "text", content: part.text }];
|
|
76759
76804
|
}
|
|
76760
76805
|
if (part.type === "tool-call") {
|
|
@@ -78151,37 +78196,48 @@ var prompt5 = `
|
|
|
78151
78196
|
|
|
78152
78197
|
You are a senior software engineer reviewing code changes.
|
|
78153
78198
|
|
|
78199
|
+
## Critical Instructions
|
|
78200
|
+
**ONLY review the actual changes shown in the diff.** Do not comment on existing code that wasn't modified.
|
|
78201
|
+
|
|
78154
78202
|
## Viewing Changes
|
|
78155
|
-
- Use
|
|
78156
|
-
- **Pull request**: use the provided commit range.
|
|
78157
|
-
- **Local changes**: diff staged or unstaged files.
|
|
78203
|
+
- **Use git_diff** to inspect the actual code changes for each relevant file.
|
|
78204
|
+
- **Pull request**: use the provided commit range for the git_diff tool.
|
|
78205
|
+
- **Local changes**: diff staged or unstaged files using the git_diff tool.
|
|
78158
78206
|
- If a pull request is present you may receive:
|
|
78159
78207
|
- <pr_title>
|
|
78160
78208
|
- <pr_description>
|
|
78161
78209
|
- <commit_messages>
|
|
78162
78210
|
- A <review_instructions> tag tells you the focus of the review.
|
|
78211
|
+
- File status information is provided in <file_status> - use this to understand which files were modified, added, deleted, or renamed.
|
|
78163
78212
|
|
|
78164
|
-
##
|
|
78165
|
-
-
|
|
78166
|
-
-
|
|
78167
|
-
-
|
|
78168
|
-
-
|
|
78169
|
-
-
|
|
78213
|
+
## Review Guidelines
|
|
78214
|
+
Focus exclusively on the changed lines (+ additions, - deletions, modified lines):
|
|
78215
|
+
- **Specific issues**: Point to exact problems in the changed code with line references
|
|
78216
|
+
- **Actionable fixes**: Provide concrete solutions, not vague suggestions
|
|
78217
|
+
- **Clear reasoning**: Explain why each issue matters and how to fix it
|
|
78218
|
+
- **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
|
|
78219
|
+
|
|
78220
|
+
## What NOT to review
|
|
78221
|
+
- Existing unchanged code
|
|
78222
|
+
- Overall project structure or architecture (unless directly impacted by changes)
|
|
78223
|
+
- Generic best practices unrelated to the specific changes
|
|
78224
|
+
- Missing features or functionality not part of this diff
|
|
78170
78225
|
|
|
78171
78226
|
## Output Format
|
|
78172
78227
|
Do **not** include praise or positive feedback. Ignore generated files such as lock files.
|
|
78228
|
+
Only include reviews for actual issues found in the changed code.
|
|
78173
78229
|
|
|
78174
78230
|
Return your review as a JSON object inside a \`\`\`json block, wrapped like:
|
|
78175
78231
|
<tool_attempt_completion>
|
|
78176
78232
|
<tool_parameter_result>
|
|
78177
78233
|
\`\`\`json
|
|
78178
78234
|
{
|
|
78179
|
-
"overview": "Summary of
|
|
78235
|
+
"overview": "Summary of specific issues found in the diff changes, or 'No issues found' if the changes look good.",
|
|
78180
78236
|
"specificReviews": [
|
|
78181
78237
|
{
|
|
78182
78238
|
"file": "path/filename.ext",
|
|
78183
78239
|
"lines": "N or N-M",
|
|
78184
|
-
"review": "
|
|
78240
|
+
"review": "Specific issue with the changed code and exact actionable fix."
|
|
78185
78241
|
}
|
|
78186
78242
|
]
|
|
78187
78243
|
}
|
|
@@ -78209,14 +78265,21 @@ ${params.pullRequestDescription}
|
|
|
78209
78265
|
parts.push(`<commit_messages>
|
|
78210
78266
|
${params.commitMessages}
|
|
78211
78267
|
</commit_messages>`);
|
|
78268
|
+
}
|
|
78269
|
+
if (params.changedFiles && params.changedFiles.length > 0) {
|
|
78270
|
+
const fileList = params.changedFiles.map((file3) => `${file3.status}: ${file3.path}`).join(`
|
|
78271
|
+
`);
|
|
78272
|
+
parts.push(`<file_status>
|
|
78273
|
+
${fileList}
|
|
78274
|
+
</file_status>`);
|
|
78212
78275
|
}
|
|
78213
78276
|
let instructions = "";
|
|
78214
78277
|
if (params.commitRange) {
|
|
78215
|
-
instructions = `Review the pull request.
|
|
78278
|
+
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
78279
|
} else if (params.staged) {
|
|
78217
|
-
instructions = "Review the staged changes.
|
|
78280
|
+
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
78281
|
} else {
|
|
78219
|
-
instructions = "Review the unstaged changes.
|
|
78282
|
+
instructions = "Review the unstaged changes. Use the git_diff tool to inspect the actual code changes. File status information is already provided above.";
|
|
78220
78283
|
}
|
|
78221
78284
|
parts.push(`<review_instructions>
|
|
78222
78285
|
${instructions}
|
|
@@ -78251,6 +78314,7 @@ ${output}`,
|
|
|
78251
78314
|
var executeTool = async (definition, ai, params, usageMeter) => {
|
|
78252
78315
|
const resp = await generateText({
|
|
78253
78316
|
model: ai,
|
|
78317
|
+
temperature: 0,
|
|
78254
78318
|
system: definition.prompt,
|
|
78255
78319
|
messages: [
|
|
78256
78320
|
{
|
|
@@ -86294,21 +86358,6 @@ var OpenRouterChatLanguageModel = class {
|
|
|
86294
86358
|
return;
|
|
86295
86359
|
}
|
|
86296
86360
|
const delta = choice.delta;
|
|
86297
|
-
if (delta.content != null) {
|
|
86298
|
-
if (!textStarted) {
|
|
86299
|
-
textId = openrouterResponseId || generateId2();
|
|
86300
|
-
controller.enqueue({
|
|
86301
|
-
type: "text-start",
|
|
86302
|
-
id: textId
|
|
86303
|
-
});
|
|
86304
|
-
textStarted = true;
|
|
86305
|
-
}
|
|
86306
|
-
controller.enqueue({
|
|
86307
|
-
type: "text-delta",
|
|
86308
|
-
delta: delta.content,
|
|
86309
|
-
id: textId || generateId2()
|
|
86310
|
-
});
|
|
86311
|
-
}
|
|
86312
86361
|
const emitReasoningChunk = (chunkText) => {
|
|
86313
86362
|
if (!reasoningStarted) {
|
|
86314
86363
|
reasoningId = openrouterResponseId || generateId2();
|
|
@@ -86324,9 +86373,6 @@ var OpenRouterChatLanguageModel = class {
|
|
|
86324
86373
|
id: reasoningId || generateId2()
|
|
86325
86374
|
});
|
|
86326
86375
|
};
|
|
86327
|
-
if (delta.reasoning != null) {
|
|
86328
|
-
emitReasoningChunk(delta.reasoning);
|
|
86329
|
-
}
|
|
86330
86376
|
if (delta.reasoning_details && delta.reasoning_details.length > 0) {
|
|
86331
86377
|
for (const detail of delta.reasoning_details) {
|
|
86332
86378
|
switch (detail.type) {
|
|
@@ -86353,6 +86399,23 @@ var OpenRouterChatLanguageModel = class {
|
|
|
86353
86399
|
}
|
|
86354
86400
|
}
|
|
86355
86401
|
}
|
|
86402
|
+
} else if (delta.reasoning != null) {
|
|
86403
|
+
emitReasoningChunk(delta.reasoning);
|
|
86404
|
+
}
|
|
86405
|
+
if (delta.content != null) {
|
|
86406
|
+
if (!textStarted) {
|
|
86407
|
+
textId = openrouterResponseId || generateId2();
|
|
86408
|
+
controller.enqueue({
|
|
86409
|
+
type: "text-start",
|
|
86410
|
+
id: textId
|
|
86411
|
+
});
|
|
86412
|
+
textStarted = true;
|
|
86413
|
+
}
|
|
86414
|
+
controller.enqueue({
|
|
86415
|
+
type: "text-delta",
|
|
86416
|
+
delta: delta.content,
|
|
86417
|
+
id: textId || generateId2()
|
|
86418
|
+
});
|
|
86356
86419
|
}
|
|
86357
86420
|
if (delta.tool_calls != null) {
|
|
86358
86421
|
for (const toolCallDelta of delta.tool_calls) {
|
|
@@ -86452,7 +86515,7 @@ var OpenRouterChatLanguageModel = class {
|
|
|
86452
86515
|
var _a16;
|
|
86453
86516
|
if (finishReason === "tool-calls") {
|
|
86454
86517
|
for (const toolCall of toolCalls) {
|
|
86455
|
-
if (!toolCall.sent) {
|
|
86518
|
+
if (toolCall && !toolCall.sent) {
|
|
86456
86519
|
controller.enqueue({
|
|
86457
86520
|
type: "tool-call",
|
|
86458
86521
|
toolCallId: (_a16 = toolCall.id) != null ? _a16 : generateId2(),
|
|
@@ -103767,13 +103830,14 @@ var getModel = (config5, debugLogging = false) => {
|
|
|
103767
103830
|
console.dir(requestBody, { depth: null });
|
|
103768
103831
|
}
|
|
103769
103832
|
if (TRACING_FILE) {
|
|
103770
|
-
appendFileSync(TRACING_FILE, JSON.stringify({
|
|
103833
|
+
appendFileSync(TRACING_FILE, `${JSON.stringify({
|
|
103771
103834
|
type: "request",
|
|
103772
103835
|
timestamp: new Date().toISOString(),
|
|
103773
103836
|
url: url4,
|
|
103774
103837
|
headers: options?.headers,
|
|
103775
103838
|
body: requestBody
|
|
103776
|
-
}, null, 2)
|
|
103839
|
+
}, null, 2)}
|
|
103840
|
+
`);
|
|
103777
103841
|
}
|
|
103778
103842
|
const res = await fetch(url4, options);
|
|
103779
103843
|
if (debugLogging) {
|
|
@@ -103795,11 +103859,12 @@ var getModel = (config5, debugLogging = false) => {
|
|
|
103795
103859
|
console.log("<- Stream chunk:", text2.replace(/\n/g, "\\n"));
|
|
103796
103860
|
}
|
|
103797
103861
|
if (TRACING_FILE) {
|
|
103798
|
-
appendFileSync(TRACING_FILE, JSON.stringify({
|
|
103862
|
+
appendFileSync(TRACING_FILE, `${JSON.stringify({
|
|
103799
103863
|
type: "response-chunk",
|
|
103800
103864
|
timestamp: new Date().toISOString(),
|
|
103801
103865
|
chunk: text2
|
|
103802
|
-
}, null, 2)
|
|
103866
|
+
}, null, 2)}
|
|
103867
|
+
`);
|
|
103803
103868
|
}
|
|
103804
103869
|
}
|
|
103805
103870
|
}
|
|
@@ -103816,13 +103881,14 @@ var getModel = (config5, debugLogging = false) => {
|
|
|
103816
103881
|
console.dir(responseBody, { depth: null });
|
|
103817
103882
|
}
|
|
103818
103883
|
if (TRACING_FILE) {
|
|
103819
|
-
appendFileSync(TRACING_FILE, JSON.stringify({
|
|
103884
|
+
appendFileSync(TRACING_FILE, `${JSON.stringify({
|
|
103820
103885
|
type: "response",
|
|
103821
103886
|
timestamp: new Date().toISOString(),
|
|
103822
103887
|
status: res.status,
|
|
103823
103888
|
headers: Object.fromEntries(res.headers.entries()),
|
|
103824
103889
|
body: responseBody
|
|
103825
|
-
}, null, 2)
|
|
103890
|
+
}, null, 2)}
|
|
103891
|
+
`);
|
|
103826
103892
|
}
|
|
103827
103893
|
return new Response(full, {
|
|
103828
103894
|
headers: res.headers,
|
|
@@ -108235,13 +108301,16 @@ async function extendPatterns(basePatterns, dirPath) {
|
|
|
108235
108301
|
function createIgnore(patterns) {
|
|
108236
108302
|
return import_ignore.default().add(patterns);
|
|
108237
108303
|
}
|
|
108238
|
-
async function listFiles(dirPath, recursive, maxCount, cwd, excludeFiles) {
|
|
108239
|
-
let rootPatterns = [...
|
|
108240
|
-
|
|
108241
|
-
|
|
108242
|
-
|
|
108243
|
-
|
|
108244
|
-
|
|
108304
|
+
async function listFiles(dirPath, recursive, maxCount, cwd, excludeFiles, includeIgnored) {
|
|
108305
|
+
let rootPatterns = [...excludeFiles || []];
|
|
108306
|
+
if (!includeIgnored) {
|
|
108307
|
+
rootPatterns.push(...DEFAULT_IGNORES);
|
|
108308
|
+
try {
|
|
108309
|
+
const rootGitignore = await fs.readFile(join2(cwd, ".gitignore"), "utf8");
|
|
108310
|
+
const lines = rootGitignore.split(/\r?\n/).filter(Boolean);
|
|
108311
|
+
rootPatterns = [...rootPatterns, ...lines];
|
|
108312
|
+
} catch {}
|
|
108313
|
+
}
|
|
108245
108314
|
const results = [];
|
|
108246
108315
|
const processedDirs = new Set;
|
|
108247
108316
|
const queue = [
|
|
@@ -108254,7 +108323,7 @@ async function listFiles(dirPath, recursive, maxCount, cwd, excludeFiles) {
|
|
|
108254
108323
|
while (queue.length > 0) {
|
|
108255
108324
|
const { path: currentPath, patterns: parentPatterns, relPath: currentRelPath } = queue.shift();
|
|
108256
108325
|
processedDirs.add(currentRelPath);
|
|
108257
|
-
const mergedPatterns = await extendPatterns(parentPatterns, currentPath);
|
|
108326
|
+
const mergedPatterns = includeIgnored ? parentPatterns : await extendPatterns(parentPatterns, currentPath);
|
|
108258
108327
|
const folderIg = createIgnore(mergedPatterns);
|
|
108259
108328
|
const entries = await fs.readdir(currentPath, { withFileTypes: true });
|
|
108260
108329
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -108350,8 +108419,8 @@ async function searchFiles(path, regex, filePattern, cwd, excludeFiles) {
|
|
|
108350
108419
|
var getProvider = (_agentName, _config, options = {}) => {
|
|
108351
108420
|
const ig = import_ignore2.default().add(options.excludeFiles ?? []);
|
|
108352
108421
|
const provider2 = {
|
|
108353
|
-
readFile: async (path) => {
|
|
108354
|
-
if (ig.ignores(path)) {
|
|
108422
|
+
readFile: async (path, includeIgnored) => {
|
|
108423
|
+
if (!includeIgnored && ig.ignores(path)) {
|
|
108355
108424
|
throw new Error(`Not allow to access file ${path}`);
|
|
108356
108425
|
}
|
|
108357
108426
|
try {
|
|
@@ -108379,8 +108448,8 @@ var getProvider = (_agentName, _config, options = {}) => {
|
|
|
108379
108448
|
}
|
|
108380
108449
|
return await rename(sourcePath, targetPath);
|
|
108381
108450
|
},
|
|
108382
|
-
listFiles: async (path, recursive, maxCount) => {
|
|
108383
|
-
return await listFiles(path, recursive, maxCount, process.cwd(), options.excludeFiles);
|
|
108451
|
+
listFiles: async (path, recursive, maxCount, includeIgnored) => {
|
|
108452
|
+
return await listFiles(path, recursive, maxCount, process.cwd(), options.excludeFiles, includeIgnored);
|
|
108384
108453
|
},
|
|
108385
108454
|
executeCommand: (command, _needApprove) => {
|
|
108386
108455
|
return new Promise((resolve3, reject) => {
|
|
@@ -109204,6 +109273,9 @@ function getProviderOptions(provider3, modelId, thinkingBudgetTokens, supportThi
|
|
|
109204
109273
|
};
|
|
109205
109274
|
break;
|
|
109206
109275
|
case "openrouter" /* OpenRouter */:
|
|
109276
|
+
if (modelId.startsWith("anthropic/")) {
|
|
109277
|
+
break;
|
|
109278
|
+
}
|
|
109207
109279
|
providerOptions.openrouter = {
|
|
109208
109280
|
reasoning: {
|
|
109209
109281
|
max_tokens: thinkingBudgetTokens
|
|
@@ -110522,6 +110594,89 @@ var prCommand = new Command("pr").description("Create a GitHub pull request").ar
|
|
|
110522
110594
|
// src/commands/review.ts
|
|
110523
110595
|
import { execSync as execSync3 } from "node:child_process";
|
|
110524
110596
|
var import_lodash9 = __toESM(require_lodash(), 1);
|
|
110597
|
+
function parseGitStatus(statusOutput) {
|
|
110598
|
+
const statusLines = statusOutput.split(`
|
|
110599
|
+
`).filter((line) => line);
|
|
110600
|
+
const files = [];
|
|
110601
|
+
for (const line of statusLines) {
|
|
110602
|
+
const indexStatus = line[0];
|
|
110603
|
+
const workingTreeStatus = line[1];
|
|
110604
|
+
const filepath = line.slice(3);
|
|
110605
|
+
const statuses = [];
|
|
110606
|
+
if (indexStatus !== " " && indexStatus !== "?") {
|
|
110607
|
+
switch (indexStatus) {
|
|
110608
|
+
case "A":
|
|
110609
|
+
statuses.push("Added (staged)");
|
|
110610
|
+
break;
|
|
110611
|
+
case "M":
|
|
110612
|
+
statuses.push("Modified (staged)");
|
|
110613
|
+
break;
|
|
110614
|
+
case "D":
|
|
110615
|
+
statuses.push("Deleted (staged)");
|
|
110616
|
+
break;
|
|
110617
|
+
case "R":
|
|
110618
|
+
statuses.push("Renamed (staged)");
|
|
110619
|
+
break;
|
|
110620
|
+
case "C":
|
|
110621
|
+
statuses.push("Copied (staged)");
|
|
110622
|
+
break;
|
|
110623
|
+
default:
|
|
110624
|
+
statuses.push("Changed (staged)");
|
|
110625
|
+
}
|
|
110626
|
+
}
|
|
110627
|
+
if (workingTreeStatus !== " ") {
|
|
110628
|
+
switch (workingTreeStatus) {
|
|
110629
|
+
case "M":
|
|
110630
|
+
statuses.push("Modified (unstaged)");
|
|
110631
|
+
break;
|
|
110632
|
+
case "D":
|
|
110633
|
+
statuses.push("Deleted (unstaged)");
|
|
110634
|
+
break;
|
|
110635
|
+
case "?":
|
|
110636
|
+
statuses.push("Untracked");
|
|
110637
|
+
break;
|
|
110638
|
+
default:
|
|
110639
|
+
statuses.push("Changed (unstaged)");
|
|
110640
|
+
}
|
|
110641
|
+
}
|
|
110642
|
+
if (statuses.length > 0) {
|
|
110643
|
+
files.push({ path: filepath, status: statuses.join(", ") });
|
|
110644
|
+
}
|
|
110645
|
+
}
|
|
110646
|
+
return files;
|
|
110647
|
+
}
|
|
110648
|
+
function parseGitDiffNameStatus(diffOutput) {
|
|
110649
|
+
const lines = diffOutput.split(`
|
|
110650
|
+
`).filter((line) => line.trim());
|
|
110651
|
+
return lines.map((line) => {
|
|
110652
|
+
const [status, ...pathParts] = line.split("\t");
|
|
110653
|
+
const path = pathParts.join("\t");
|
|
110654
|
+
let statusDescription;
|
|
110655
|
+
switch (status[0]) {
|
|
110656
|
+
case "A":
|
|
110657
|
+
statusDescription = "Added";
|
|
110658
|
+
break;
|
|
110659
|
+
case "M":
|
|
110660
|
+
statusDescription = "Modified";
|
|
110661
|
+
break;
|
|
110662
|
+
case "D":
|
|
110663
|
+
statusDescription = "Deleted";
|
|
110664
|
+
break;
|
|
110665
|
+
case "R":
|
|
110666
|
+
statusDescription = "Renamed";
|
|
110667
|
+
break;
|
|
110668
|
+
case "C":
|
|
110669
|
+
statusDescription = "Copied";
|
|
110670
|
+
break;
|
|
110671
|
+
case "T":
|
|
110672
|
+
statusDescription = "Type changed";
|
|
110673
|
+
break;
|
|
110674
|
+
default:
|
|
110675
|
+
statusDescription = "Unknown";
|
|
110676
|
+
}
|
|
110677
|
+
return { path, status: statusDescription };
|
|
110678
|
+
});
|
|
110679
|
+
}
|
|
110525
110680
|
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
110681
|
const parentOptions = command.parent?.opts() ?? {};
|
|
110527
110682
|
const { providerConfig, config: config6 } = parseOptions(parentOptions);
|
|
@@ -110604,12 +110759,21 @@ async function reviewPR(prIdentifier, spinner, sharedAiOptions, isJsonOutput) {
|
|
|
110604
110759
|
const commitMessages = prDetails.commits.map((c) => c.messageBody).join(`
|
|
110605
110760
|
---
|
|
110606
110761
|
`);
|
|
110762
|
+
spinner.text = "Getting file changes...";
|
|
110763
|
+
let changedFiles = [];
|
|
110764
|
+
try {
|
|
110765
|
+
const diffNameStatus = execSync3(`git diff --name-status --no-color ${defaultBranch}...HEAD`, { encoding: "utf-8" });
|
|
110766
|
+
changedFiles = parseGitDiffNameStatus(diffNameStatus);
|
|
110767
|
+
} catch (_error) {
|
|
110768
|
+
console.warn("Warning: Could not retrieve file changes list");
|
|
110769
|
+
}
|
|
110607
110770
|
spinner.text = "Generating review...";
|
|
110608
110771
|
const result = await reviewDiff(sharedAiOptions, {
|
|
110609
110772
|
commitRange: `${defaultBranch}...HEAD`,
|
|
110610
110773
|
pullRequestTitle: prDetails.title,
|
|
110611
110774
|
pullRequestDescription: prDetails.body,
|
|
110612
|
-
commitMessages
|
|
110775
|
+
commitMessages,
|
|
110776
|
+
changedFiles
|
|
110613
110777
|
});
|
|
110614
110778
|
spinner.succeed("Review generated successfully");
|
|
110615
110779
|
if (isJsonOutput) {
|
|
@@ -110619,10 +110783,19 @@ async function reviewPR(prIdentifier, spinner, sharedAiOptions, isJsonOutput) {
|
|
|
110619
110783
|
}
|
|
110620
110784
|
}
|
|
110621
110785
|
async function reviewLocal(spinner, sharedAiOptions, isJsonOutput) {
|
|
110622
|
-
const
|
|
110786
|
+
const gitStatus = execSync3("git status --porcelain=v1", { encoding: "utf-8" }).trim();
|
|
110787
|
+
const statusLines = gitStatus.split(`
|
|
110788
|
+
`).filter((line) => line);
|
|
110789
|
+
const hasStagedChanges = statusLines.some((line) => "MARC".includes(line[0]));
|
|
110790
|
+
const hasUnstagedChanges = statusLines.some((line) => "MARCDU".includes(line[1]));
|
|
110791
|
+
const changedFiles = parseGitStatus(gitStatus);
|
|
110623
110792
|
if (hasStagedChanges) {
|
|
110624
110793
|
spinner.text = "Generating review for staged changes...";
|
|
110625
|
-
const
|
|
110794
|
+
const stagedFiles = changedFiles.filter((file4) => file4.status.includes("staged"));
|
|
110795
|
+
const result2 = await reviewDiff(sharedAiOptions, {
|
|
110796
|
+
staged: true,
|
|
110797
|
+
changedFiles: stagedFiles
|
|
110798
|
+
});
|
|
110626
110799
|
spinner.succeed("Review generated successfully");
|
|
110627
110800
|
if (isJsonOutput) {
|
|
110628
110801
|
console.log(JSON.stringify(result2, null, 2));
|
|
@@ -110631,10 +110804,13 @@ async function reviewLocal(spinner, sharedAiOptions, isJsonOutput) {
|
|
|
110631
110804
|
}
|
|
110632
110805
|
return;
|
|
110633
110806
|
}
|
|
110634
|
-
const hasUnstagedChanges = execSync3('git diff --quiet || echo "unstaged"', { encoding: "utf-8" }).trim() === "unstaged";
|
|
110635
110807
|
if (hasUnstagedChanges) {
|
|
110636
110808
|
spinner.text = "Generating review for unstaged changes...";
|
|
110637
|
-
const
|
|
110809
|
+
const unstagedFiles = changedFiles.filter((file4) => file4.status.includes("unstaged") || file4.status.includes("Untracked"));
|
|
110810
|
+
const result2 = await reviewDiff(sharedAiOptions, {
|
|
110811
|
+
staged: false,
|
|
110812
|
+
changedFiles: unstagedFiles
|
|
110813
|
+
});
|
|
110638
110814
|
spinner.succeed("Review generated successfully");
|
|
110639
110815
|
if (isJsonOutput) {
|
|
110640
110816
|
console.log(JSON.stringify(result2, null, 2));
|
|
@@ -110659,9 +110835,18 @@ async function reviewLocal(spinner, sharedAiOptions, isJsonOutput) {
|
|
|
110659
110835
|
spinner.succeed(`No changes to review. You are on the default branch ('${defaultBranch}').`);
|
|
110660
110836
|
process.exit(0);
|
|
110661
110837
|
}
|
|
110838
|
+
spinner.text = "Getting file changes...";
|
|
110839
|
+
let branchChangedFiles = [];
|
|
110840
|
+
try {
|
|
110841
|
+
const diffNameStatus = execSync3(`git diff --name-status --no-color ${defaultBranch}...${currentBranch}`, { encoding: "utf-8" });
|
|
110842
|
+
branchChangedFiles = parseGitDiffNameStatus(diffNameStatus);
|
|
110843
|
+
} catch (_error) {
|
|
110844
|
+
console.warn("Warning: Could not retrieve file changes list");
|
|
110845
|
+
}
|
|
110662
110846
|
spinner.text = `Generating review for changes between '${defaultBranch}' and '${currentBranch}'...`;
|
|
110663
110847
|
const result = await reviewDiff(sharedAiOptions, {
|
|
110664
|
-
commitRange: `${defaultBranch}...${currentBranch}
|
|
110848
|
+
commitRange: `${defaultBranch}...${currentBranch}`,
|
|
110849
|
+
changedFiles: branchChangedFiles
|
|
110665
110850
|
});
|
|
110666
110851
|
spinner.succeed("Review generated successfully");
|
|
110667
110852
|
if (isJsonOutput) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polka-codes/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.5",
|
|
4
4
|
"license": "AGPL-3.0",
|
|
5
5
|
"author": "github@polka.codes",
|
|
6
6
|
"type": "module",
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"@ai-sdk/provider": "2.0.0-beta.1",
|
|
25
25
|
"@ai-sdk/provider-utils": "3.0.0-beta.5",
|
|
26
26
|
"@inquirer/prompts": "^7.2.3",
|
|
27
|
-
"@openrouter/ai-sdk-provider": "^1.0.0-beta.
|
|
28
|
-
"@polka-codes/cli-shared": "0.9.
|
|
29
|
-
"@polka-codes/core": "0.9.
|
|
27
|
+
"@openrouter/ai-sdk-provider": "^1.0.0-beta.6",
|
|
28
|
+
"@polka-codes/cli-shared": "0.9.4",
|
|
29
|
+
"@polka-codes/core": "0.9.4",
|
|
30
30
|
"ai": "5.0.0-beta.24",
|
|
31
31
|
"commander": "^13.0.0",
|
|
32
32
|
"dotenv": "^16.4.7",
|