jinzd-ai-cli 0.4.215 → 0.4.217
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 +5 -2
- package/dist/{batch-74H5SA7P.js → batch-YCOVKTXD.js} +2 -2
- package/dist/{chat-index-R2E27VXN.js → chat-index-PS274XM7.js} +1 -1
- package/dist/{chunk-ZOF5NFKW.js → chunk-524WZOKS.js} +1 -1
- package/dist/{ci-3ALK2XJN.js → chunk-KOPUCJXM.js} +40 -46
- package/dist/{chunk-6C3JYNM6.js → chunk-MGBMNCHG.js} +279 -54
- package/dist/{chunk-KL7UBVSQ.js → chunk-OUAZOE5U.js} +2 -2
- package/dist/{chunk-RS4WBI73.js → chunk-QAYOI57M.js} +3 -1
- package/dist/{chunk-X6OXS7KU.js → chunk-SNJAOXFT.js} +1 -1
- package/dist/{chunk-OQGVGPEK.js → chunk-VHY6NVMQ.js} +2 -0
- package/dist/{chunk-3TSHNZKI.js → chunk-VTH7BLXK.js} +1 -1
- package/dist/{chunk-2224JGA6.js → chunk-WKOQ5CYC.js} +1 -1
- package/dist/chunk-WZ3VKLF3.js +105 -0
- package/dist/{chunk-7JES2NWR.js → chunk-XJGEQIYS.js} +3 -1
- package/dist/ci-52RZIYWB.js +19 -0
- package/dist/ci-format-73UXKE65.js +18 -0
- package/dist/{constants-IN2HXJK7.js → constants-DIXAD35W.js} +3 -1
- package/dist/{doctor-cli-7XL4TCVT.js → doctor-cli-7GOQPULZ.js} +4 -4
- package/dist/electron-server.js +562 -318
- package/dist/{hub-VAOG5EY6.js → hub-GIGBITZN.js} +1 -1
- package/dist/index.js +169 -73
- package/dist/pr-KPQ5RPKB.js +267 -0
- package/dist/{run-tests-J2JQ57R3.js → run-tests-K7QR5QN4.js} +1 -1
- package/dist/{run-tests-QJD43AML.js → run-tests-ZDSA3QES.js} +2 -2
- package/dist/{server-WDLV3W4F.js → server-22YF3U34.js} +5 -4
- package/dist/{server-VGPZOISQ.js → server-QT3SC2KI.js} +129 -86
- package/dist/{task-orchestrator-QFOCO3N7.js → task-orchestrator-BHQQCVTY.js} +5 -4
- package/dist/{usage-IEB476NE.js → usage-WZZFSFLM.js} +2 -2
- package/dist/web/client/app.js +53 -2
- package/dist/web/client/index.html +11 -1
- package/package.json +1 -1
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
countSeverity,
|
|
4
|
+
runCi
|
|
5
|
+
} from "./chunk-KOPUCJXM.js";
|
|
6
|
+
import "./chunk-WZ3VKLF3.js";
|
|
7
|
+
import {
|
|
8
|
+
buildReviewPrompt,
|
|
9
|
+
buildSecurityReviewPrompt,
|
|
10
|
+
truncateDiff
|
|
11
|
+
} from "./chunk-HLWUDRBO.js";
|
|
12
|
+
import {
|
|
13
|
+
ProviderRegistry
|
|
14
|
+
} from "./chunk-QMXC327F.js";
|
|
15
|
+
import "./chunk-XPBEJB27.js";
|
|
16
|
+
import {
|
|
17
|
+
ConfigManager
|
|
18
|
+
} from "./chunk-WKOQ5CYC.js";
|
|
19
|
+
import "./chunk-TZQHYZKT.js";
|
|
20
|
+
import {
|
|
21
|
+
VERSION
|
|
22
|
+
} from "./chunk-XJGEQIYS.js";
|
|
23
|
+
import "./chunk-IW3Q7AE5.js";
|
|
24
|
+
|
|
25
|
+
// src/cli/pr.ts
|
|
26
|
+
import { execFileSync } from "child_process";
|
|
27
|
+
var ALLOWED_AGENTS = /* @__PURE__ */ new Set(["security", "bugs", "tests", "maintainability"]);
|
|
28
|
+
function parsePrTarget(input) {
|
|
29
|
+
if (!input) return {};
|
|
30
|
+
const s = input.trim();
|
|
31
|
+
if (/^https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/\d+(?:[/?#].*)?$/.test(s)) return { pr: s };
|
|
32
|
+
if (/^#?\d+$/.test(s)) return { pr: parseInt(s.replace(/^#/, ""), 10) };
|
|
33
|
+
const range = s.match(/^([^\s.][^\s]*?)\.\.\.([^\s]+)$/);
|
|
34
|
+
if (range) return { base: range[1], head: range[2] };
|
|
35
|
+
return { base: s, head: "HEAD" };
|
|
36
|
+
}
|
|
37
|
+
function parseAgentList(input) {
|
|
38
|
+
if (!input) return [];
|
|
39
|
+
const agents = input.split(",").map((s) => s.trim()).filter(Boolean);
|
|
40
|
+
const invalid = agents.filter((a) => !ALLOWED_AGENTS.has(a));
|
|
41
|
+
if (invalid.length) throw new Error(`unknown PR review agent(s): ${invalid.join(", ")}. Allowed: ${Array.from(ALLOWED_AGENTS).join(", ")}`);
|
|
42
|
+
return [...new Set(agents)];
|
|
43
|
+
}
|
|
44
|
+
function validateGitRef(ref) {
|
|
45
|
+
if (!/^[A-Za-z0-9._/\-]+$/.test(ref)) throw new Error(`unsafe ref: ${ref}`);
|
|
46
|
+
}
|
|
47
|
+
function hasGitHubToken() {
|
|
48
|
+
return !!(process.env.GH_TOKEN || process.env.GITHUB_TOKEN);
|
|
49
|
+
}
|
|
50
|
+
function fetchPrMetadata(pr) {
|
|
51
|
+
if (!hasGitHubToken()) return null;
|
|
52
|
+
try {
|
|
53
|
+
const out = execFileSync("gh", ["pr", "view", String(pr), "--json", "number,url,title,author,state,baseRefName,headRefName"], {
|
|
54
|
+
encoding: "utf-8",
|
|
55
|
+
maxBuffer: 5 * 1024 * 1024,
|
|
56
|
+
timeout: 3e4
|
|
57
|
+
});
|
|
58
|
+
const parsed = JSON.parse(out);
|
|
59
|
+
return {
|
|
60
|
+
number: parsed.number,
|
|
61
|
+
url: parsed.url,
|
|
62
|
+
title: parsed.title,
|
|
63
|
+
state: parsed.state,
|
|
64
|
+
baseRefName: parsed.baseRefName,
|
|
65
|
+
headRefName: parsed.headRefName,
|
|
66
|
+
author: parsed.author?.login
|
|
67
|
+
};
|
|
68
|
+
} catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function fetchDiffSource(opts) {
|
|
73
|
+
const target = parsePrTarget(opts.target);
|
|
74
|
+
if (opts.diffOverride != null) {
|
|
75
|
+
const isPr = target.pr != null;
|
|
76
|
+
return {
|
|
77
|
+
kind: isPr ? "github-pr" : "git",
|
|
78
|
+
label: isPr ? `PR ${String(target.pr)}` : opts.base ? `${opts.base}...${opts.head || "HEAD"}` : "injected diff",
|
|
79
|
+
diff: opts.diffOverride,
|
|
80
|
+
metadata: opts.metadataOverride ?? null
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const pr = target.pr;
|
|
84
|
+
const base = opts.base ?? target.base ?? "main";
|
|
85
|
+
const head = opts.head ?? target.head ?? "HEAD";
|
|
86
|
+
if (pr != null) {
|
|
87
|
+
try {
|
|
88
|
+
const diff = execFileSync("gh", ["pr", "diff", String(pr)], {
|
|
89
|
+
encoding: "utf-8",
|
|
90
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
91
|
+
timeout: 6e4
|
|
92
|
+
});
|
|
93
|
+
return { kind: "github-pr", label: `PR ${String(pr)}`, diff, metadata: fetchPrMetadata(pr) };
|
|
94
|
+
} catch (err) {
|
|
95
|
+
const msg = err.stderr?.toString() ?? err.message;
|
|
96
|
+
throw new Error(`gh pr diff ${String(pr)} failed: ${msg.trim() || "unknown error"}. For local review without GitHub auth, use --base/--head instead.`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
validateGitRef(base);
|
|
100
|
+
validateGitRef(head);
|
|
101
|
+
try {
|
|
102
|
+
const diff = execFileSync("git", ["diff", `${base}...${head}`], {
|
|
103
|
+
encoding: "utf-8",
|
|
104
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
105
|
+
timeout: 3e4
|
|
106
|
+
});
|
|
107
|
+
return { kind: "git", label: `${base}...${head}`, diff, metadata: null };
|
|
108
|
+
} catch (err) {
|
|
109
|
+
throw new Error(`git diff ${base}...${head} failed: ${err.message}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function metadataMarkdown(meta) {
|
|
113
|
+
if (!meta) return "";
|
|
114
|
+
const parts = [
|
|
115
|
+
meta.number != null ? `#${meta.number}` : void 0,
|
|
116
|
+
meta.title,
|
|
117
|
+
meta.state,
|
|
118
|
+
meta.author ? `by @${meta.author}` : void 0,
|
|
119
|
+
meta.baseRefName && meta.headRefName ? `${meta.baseRefName} \u2190 ${meta.headRefName}` : void 0,
|
|
120
|
+
meta.url
|
|
121
|
+
].filter(Boolean);
|
|
122
|
+
return parts.length ? `
|
|
123
|
+
PR metadata: ${parts.join(" \xB7 ")}` : "";
|
|
124
|
+
}
|
|
125
|
+
function buildGitContext(src) {
|
|
126
|
+
const parts = [`Source: ${src.label}`, `Reviewer: aicli v${VERSION}`];
|
|
127
|
+
if (src.metadata?.number != null) parts.push(`PR: #${src.metadata.number}`);
|
|
128
|
+
if (src.metadata?.title) parts.push(`Title: ${src.metadata.title}`);
|
|
129
|
+
if (src.metadata?.baseRefName && src.metadata?.headRefName) parts.push(`Base/Head: ${src.metadata.baseRefName}...${src.metadata.headRefName}`);
|
|
130
|
+
return parts.join(" | ");
|
|
131
|
+
}
|
|
132
|
+
function buildSummaryPrompt(diff, gitContext) {
|
|
133
|
+
return `# Pull Request Summary Request
|
|
134
|
+
|
|
135
|
+
Summarize this pull request for maintainers. Focus on what changed, why it matters, risk areas, tests implied by the diff, and release-note worthy behavior.
|
|
136
|
+
|
|
137
|
+
## Git Context
|
|
138
|
+
${gitContext}
|
|
139
|
+
|
|
140
|
+
## Code Changes (diff)
|
|
141
|
+
\`\`\`diff
|
|
142
|
+
${diff}
|
|
143
|
+
\`\`\`
|
|
144
|
+
|
|
145
|
+
## Output Format
|
|
146
|
+
1. **Summary**: 2-4 bullets
|
|
147
|
+
2. **Key Files**: important files and why they changed
|
|
148
|
+
3. **Risk / Review Focus**: areas reviewers should inspect
|
|
149
|
+
4. **Testing Notes**: tests present or missing
|
|
150
|
+
5. **Suggested PR Description**: concise markdown description`;
|
|
151
|
+
}
|
|
152
|
+
function buildAgentPrompt(agent, diff, gitContext) {
|
|
153
|
+
const focus = {
|
|
154
|
+
security: "security vulnerabilities, secret handling, authz/authn, injection, unsafe network/file behavior",
|
|
155
|
+
bugs: "logic bugs, edge cases, race conditions, incorrect assumptions, regressions",
|
|
156
|
+
tests: "missing tests, weak assertions, CI breakage risk, testability gaps",
|
|
157
|
+
maintainability: "complexity, naming, duplication, API shape, future maintenance risk"
|
|
158
|
+
};
|
|
159
|
+
return `# PR Review Agent: ${agent}
|
|
160
|
+
|
|
161
|
+
Review the diff only from this lens: ${focus[agent]}. Be concise and cite file paths/lines when possible.
|
|
162
|
+
|
|
163
|
+
## Git Context
|
|
164
|
+
${gitContext}
|
|
165
|
+
|
|
166
|
+
## Diff
|
|
167
|
+
\`\`\`diff
|
|
168
|
+
${diff}
|
|
169
|
+
\`\`\`
|
|
170
|
+
|
|
171
|
+
## Output Format
|
|
172
|
+
- Findings first, ordered by severity
|
|
173
|
+
- If no material findings, say so clearly
|
|
174
|
+
- Keep recommendations actionable`;
|
|
175
|
+
}
|
|
176
|
+
async function getProvider(opts) {
|
|
177
|
+
const config = new ConfigManager();
|
|
178
|
+
const registry = new ProviderRegistry();
|
|
179
|
+
await registry.initialize(
|
|
180
|
+
(id) => config.getApiKey(id),
|
|
181
|
+
(id) => ({ baseUrl: config.get("customBaseUrls")[id], timeout: config.get("timeouts")[id], proxy: config.get("proxy") }),
|
|
182
|
+
config.get("customProviders")
|
|
183
|
+
);
|
|
184
|
+
const providerId = opts.provider ?? config.getDefaultProvider();
|
|
185
|
+
if (!registry.has(providerId)) throw new Error(`Provider '${providerId}' is not configured. Set the right AICLI_API_KEY_* env var or pass --provider.`);
|
|
186
|
+
const info = registry.get(providerId).info;
|
|
187
|
+
return { registry, providerId, modelId: opts.model ?? config.get("defaultModels")[providerId] ?? info.defaultModel };
|
|
188
|
+
}
|
|
189
|
+
async function runPrompt(registry, providerId, modelId, prompt) {
|
|
190
|
+
const provider = registry.get(providerId);
|
|
191
|
+
const resp = await provider.chat({
|
|
192
|
+
messages: [{ role: "user", content: prompt, timestamp: /* @__PURE__ */ new Date() }],
|
|
193
|
+
model: modelId,
|
|
194
|
+
stream: false,
|
|
195
|
+
temperature: 0.3,
|
|
196
|
+
maxTokens: 8192
|
|
197
|
+
});
|
|
198
|
+
return resp.content?.trim() ?? "";
|
|
199
|
+
}
|
|
200
|
+
async function runPrCli(opts) {
|
|
201
|
+
let source;
|
|
202
|
+
try {
|
|
203
|
+
source = fetchDiffSource(opts);
|
|
204
|
+
} catch (err) {
|
|
205
|
+
return { exitCode: 2, markdown: `\u274C ${err.message}`, posted: false, severity: { critical: 0, high: 0, warning: 0, info: 0 } };
|
|
206
|
+
}
|
|
207
|
+
const diff = source.diff.trim();
|
|
208
|
+
if (!diff) return { exitCode: 0, markdown: `\u2705 No changes to review (${source.label}).`, posted: false, severity: { critical: 0, high: 0, warning: 0, info: 0 } };
|
|
209
|
+
const parsedTarget = parsePrTarget(opts.target);
|
|
210
|
+
const requestedAgents = parseAgentList(opts.agents);
|
|
211
|
+
if (opts.post && source.kind !== "github-pr") {
|
|
212
|
+
return { exitCode: 2, markdown: "\u274C --post requires a GitHub PR number or URL target.", posted: false, severity: { critical: 0, high: 0, warning: 0, info: 0 } };
|
|
213
|
+
}
|
|
214
|
+
if (opts.post && opts.action === "summarize") {
|
|
215
|
+
return { exitCode: 2, markdown: "\u274C --post is currently supported for pr review and pr security-review only.", posted: false, severity: { critical: 0, high: 0, warning: 0, info: 0 } };
|
|
216
|
+
}
|
|
217
|
+
if (opts.post && requestedAgents.length > 0) {
|
|
218
|
+
return { exitCode: 2, markdown: "\u274C --post is currently not supported together with --agents; run without --agents or post the Markdown manually.", posted: false, severity: { critical: 0, high: 0, warning: 0, info: 0 } };
|
|
219
|
+
}
|
|
220
|
+
if ((opts.action === "review" || opts.action === "security-review") && requestedAgents.length === 0) {
|
|
221
|
+
const ci = await runCi({
|
|
222
|
+
pr: source.kind === "github-pr" ? parsedTarget.pr : void 0,
|
|
223
|
+
diffOverride: diff,
|
|
224
|
+
base: source.kind === "git" ? source.label.split("...")[0] : void 0,
|
|
225
|
+
post: !!opts.post,
|
|
226
|
+
update: opts.update !== false,
|
|
227
|
+
skipCode: opts.action === "security-review",
|
|
228
|
+
skipSecurity: opts.action === "review",
|
|
229
|
+
detailed: !!opts.detailed,
|
|
230
|
+
maxDiffChars: opts.maxDiffChars,
|
|
231
|
+
provider: opts.provider,
|
|
232
|
+
model: opts.model,
|
|
233
|
+
dryRun: !!opts.dryRun
|
|
234
|
+
});
|
|
235
|
+
return { exitCode: ci.exitCode, markdown: ci.markdown + metadataMarkdown(source.metadata), posted: ci.posted, severity: ci.severity };
|
|
236
|
+
}
|
|
237
|
+
const maxDiff = opts.maxDiffChars ?? 3e4;
|
|
238
|
+
const { diff: trimmedDiff, truncated } = truncateDiff(diff, maxDiff);
|
|
239
|
+
const gitContext = buildGitContext(source);
|
|
240
|
+
let providerBundle;
|
|
241
|
+
try {
|
|
242
|
+
providerBundle = await getProvider(opts);
|
|
243
|
+
} catch (err) {
|
|
244
|
+
return { exitCode: 2, markdown: `\u274C ${err.message}`, posted: false, severity: { critical: 0, high: 0, warning: 0, info: 0 } };
|
|
245
|
+
}
|
|
246
|
+
const sections = [`## \u{1F916} aicli pr ${opts.action}`, `*Provider: \`${providerBundle.providerId}\` \xB7 Model: \`${providerBundle.modelId}\` \xB7 Source: \`${source.label}\` \xB7 aicli v${VERSION}*`, ""];
|
|
247
|
+
if (source.metadata) sections.push(`> ${metadataMarkdown(source.metadata).trim()}`, "");
|
|
248
|
+
try {
|
|
249
|
+
const prompt = opts.action === "security-review" ? buildSecurityReviewPrompt(trimmedDiff, gitContext) : opts.action === "summarize" ? buildSummaryPrompt(trimmedDiff, gitContext) : buildReviewPrompt(trimmedDiff, gitContext, !!opts.detailed);
|
|
250
|
+
sections.push(await runPrompt(providerBundle.registry, providerBundle.providerId, providerBundle.modelId, prompt), "");
|
|
251
|
+
if (requestedAgents.length) {
|
|
252
|
+
const outputs = await Promise.all(requestedAgents.map(async (agent) => ({ agent, output: await runPrompt(providerBundle.registry, providerBundle.providerId, providerBundle.modelId, buildAgentPrompt(agent, trimmedDiff, gitContext)) })));
|
|
253
|
+
sections.push("### Agent Lenses", "");
|
|
254
|
+
for (const item of outputs) sections.push(`#### ${item.agent}`, item.output, "");
|
|
255
|
+
}
|
|
256
|
+
} catch (err) {
|
|
257
|
+
return { exitCode: 2, markdown: `\u274C PR review call failed: ${err.message}`, posted: false, severity: { critical: 0, high: 0, warning: 0, info: 0 } };
|
|
258
|
+
}
|
|
259
|
+
if (truncated) sections.push(`> \u26A0 Diff was truncated to ${maxDiff} chars (original: ${diff.length}). Consider splitting large PRs.`);
|
|
260
|
+
const markdown = sections.join("\n");
|
|
261
|
+
return { exitCode: 0, markdown, posted: false, severity: countSeverity(markdown) };
|
|
262
|
+
}
|
|
263
|
+
export {
|
|
264
|
+
parseAgentList,
|
|
265
|
+
parsePrTarget,
|
|
266
|
+
runPrCli
|
|
267
|
+
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ToolRegistry
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MGBMNCHG.js";
|
|
5
5
|
import "./chunk-T2NL5ZIA.js";
|
|
6
6
|
import "./chunk-BXP6YZ2P.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-VTH7BLXK.js";
|
|
8
8
|
import {
|
|
9
9
|
runTool
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-SNJAOXFT.js";
|
|
11
11
|
import {
|
|
12
12
|
getDangerLevel,
|
|
13
13
|
schemaToJsonSchema
|
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
import "./chunk-TZQHYZKT.js";
|
|
16
16
|
import {
|
|
17
17
|
VERSION
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-XJGEQIYS.js";
|
|
19
|
+
import "./chunk-HOSJZMQS.js";
|
|
19
20
|
import "./chunk-4BKXL7SM.js";
|
|
20
21
|
import "./chunk-TB4W4Y4T.js";
|
|
21
22
|
import "./chunk-KHYD3WXE.js";
|