jinzd-ai-cli 0.4.23 → 0.4.25
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/chunk-4BKXL7SM.js +98 -0
- package/dist/{chunk-PDVX5QJA.js → chunk-5GZQLJAY.js} +1068 -201
- package/dist/{chunk-UA4BVWKV.js → chunk-AHH5I2U6.js} +1 -1
- package/dist/{chunk-XMTMCMAP.js → chunk-ETMUP3CY.js} +1 -1
- package/dist/chunk-SKET65WZ.js +96 -0
- package/dist/{chunk-GBMVHLPA.js → chunk-SS7BQZ5R.js} +2 -198
- package/dist/{hub-YN245LMP.js → hub-JOYPSPR2.js} +1 -1
- package/dist/index.js +170 -500
- package/dist/{run-tests-2S6SYL2M.js → run-tests-25BZE3KQ.js} +1 -1
- package/dist/{run-tests-7ZBI4ZTU.js → run-tests-L3JNRB6X.js} +1 -1
- package/dist/{server-SD5ICBFP.js → server-V3IZSAMO.js} +126 -7
- package/dist/{task-orchestrator-C472QXTJ.js → task-orchestrator-4N5UUA6L.js} +3 -2
- package/dist/web/client/app.js +16 -3
- package/package.json +1 -1
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
SessionManager,
|
|
8
8
|
SkillManager,
|
|
9
9
|
TOOL_CALL_REMINDER,
|
|
10
|
-
checkPermission,
|
|
11
10
|
detectsHallucinatedFileOp,
|
|
12
11
|
formatGitContextForPrompt,
|
|
13
12
|
getContentText,
|
|
@@ -15,24 +14,27 @@ import {
|
|
|
15
14
|
getGitRoot,
|
|
16
15
|
hadPreviousWriteToolCalls,
|
|
17
16
|
loadDevState,
|
|
18
|
-
renderDiff,
|
|
19
|
-
runHook,
|
|
20
17
|
setupProxy
|
|
21
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-SS7BQZ5R.js";
|
|
22
19
|
import {
|
|
23
20
|
AuthManager
|
|
24
21
|
} from "./chunk-BYNY5JPB.js";
|
|
25
22
|
import {
|
|
23
|
+
ToolExecutor,
|
|
26
24
|
ToolRegistry,
|
|
27
25
|
askUserContext,
|
|
26
|
+
checkPermission,
|
|
28
27
|
getDangerLevel,
|
|
29
28
|
googleSearchContext,
|
|
30
29
|
isFileWriteTool,
|
|
30
|
+
renderDiff,
|
|
31
|
+
runHook,
|
|
31
32
|
setContextWindow,
|
|
32
33
|
spawnAgentContext,
|
|
33
34
|
truncateOutput,
|
|
34
35
|
undoStack
|
|
35
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-5GZQLJAY.js";
|
|
37
|
+
import "./chunk-4BKXL7SM.js";
|
|
36
38
|
import {
|
|
37
39
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
38
40
|
AUTHOR,
|
|
@@ -50,7 +52,7 @@ import {
|
|
|
50
52
|
SKILLS_DIR_NAME,
|
|
51
53
|
VERSION,
|
|
52
54
|
buildUserIdentityPrompt
|
|
53
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-AHH5I2U6.js";
|
|
54
56
|
|
|
55
57
|
// src/web/server.ts
|
|
56
58
|
import express from "express";
|
|
@@ -815,6 +817,7 @@ You have a maximum of ${MAX_TOOL_ROUNDS} tool call rounds for this task. Plan ef
|
|
|
815
817
|
spawnAgentContext.systemPrompt = systemPrompt;
|
|
816
818
|
spawnAgentContext.modelParams = modelParams;
|
|
817
819
|
spawnAgentContext.configManager = this.config;
|
|
820
|
+
ToolExecutor.currentMessageIndex = this.sessions.current?.messages.length ?? 0;
|
|
818
821
|
const toolResults = await this.toolExecutor.executeAll(result.toolCalls);
|
|
819
822
|
const reasoningContent = result.reasoningContent;
|
|
820
823
|
const newMsgs = provider.buildToolResultMessages(result.toolCalls, toolResults, reasoningContent);
|
|
@@ -1512,11 +1515,96 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
1512
1515
|
}
|
|
1513
1516
|
break;
|
|
1514
1517
|
}
|
|
1518
|
+
// ── /security-review ──────────────────────────────────────────────
|
|
1519
|
+
case "security-review": {
|
|
1520
|
+
const gitCtx = getGitContext();
|
|
1521
|
+
if (!gitCtx) {
|
|
1522
|
+
this.send({ type: "error", message: "Not a git repository." });
|
|
1523
|
+
break;
|
|
1524
|
+
}
|
|
1525
|
+
const secStaged = args.includes("--staged");
|
|
1526
|
+
let secDiff;
|
|
1527
|
+
try {
|
|
1528
|
+
const cmd = secStaged ? "git diff --staged" : "git diff";
|
|
1529
|
+
secDiff = execSync(cmd, { encoding: "utf-8", timeout: 1e4 }).trim();
|
|
1530
|
+
} catch {
|
|
1531
|
+
this.send({ type: "error", message: "Failed to run git diff." });
|
|
1532
|
+
break;
|
|
1533
|
+
}
|
|
1534
|
+
if (!secDiff) {
|
|
1535
|
+
this.send({ type: "info", message: "No changes to review." + (secStaged ? "" : " Try --staged for staged changes.") });
|
|
1536
|
+
break;
|
|
1537
|
+
}
|
|
1538
|
+
const SEC_MAX_DIFF = 8e3;
|
|
1539
|
+
let secTruncated = false;
|
|
1540
|
+
if (secDiff.length > SEC_MAX_DIFF) {
|
|
1541
|
+
const head = secDiff.slice(0, Math.floor(SEC_MAX_DIFF * 0.7));
|
|
1542
|
+
const tail = secDiff.slice(secDiff.length - Math.floor(SEC_MAX_DIFF * 0.2));
|
|
1543
|
+
secDiff = head + "\n\n... [diff truncated, " + secDiff.length + " chars total] ...\n\n" + tail;
|
|
1544
|
+
secTruncated = true;
|
|
1545
|
+
}
|
|
1546
|
+
const secPrompt = this.buildSecurityReviewPrompt(secDiff, formatGitContextForPrompt(gitCtx));
|
|
1547
|
+
this.send({ type: "info", message: "\u{1F512} Scanning for security vulnerabilities..." });
|
|
1548
|
+
try {
|
|
1549
|
+
const secReview = await this.chatOnce(secPrompt, { temperature: 0.2, maxTokens: 8192 });
|
|
1550
|
+
const secMsg = secTruncated ? secReview + "\n\n\u26A0 Diff was truncated. Consider reviewing smaller changesets." : secReview;
|
|
1551
|
+
this.send({ type: "info", message: secMsg });
|
|
1552
|
+
} catch (err) {
|
|
1553
|
+
this.send({ type: "error", message: `Security review failed: ${err.message}` });
|
|
1554
|
+
}
|
|
1555
|
+
break;
|
|
1556
|
+
}
|
|
1557
|
+
// ── /rewind ────────────────────────────────────────────────────────
|
|
1558
|
+
case "rewind": {
|
|
1559
|
+
const session = this.sessions.current;
|
|
1560
|
+
if (!session || session.messages.length === 0) {
|
|
1561
|
+
this.send({ type: "info", message: "No messages to rewind." });
|
|
1562
|
+
break;
|
|
1563
|
+
}
|
|
1564
|
+
const rewindSub = args[0];
|
|
1565
|
+
if (rewindSub === "list" || !rewindSub) {
|
|
1566
|
+
const lines = [`Conversation messages (${session.messages.length} total):
|
|
1567
|
+
`];
|
|
1568
|
+
const cpIndices = (await import("./file-checkpoint-NKBHGC7L.js")).fileCheckpoints.getMessageIndices();
|
|
1569
|
+
for (let i = 0; i < session.messages.length; i++) {
|
|
1570
|
+
const m = session.messages[i];
|
|
1571
|
+
const text = getContentText(m.content).replace(/\n/g, " ").slice(0, 60);
|
|
1572
|
+
const pin = cpIndices.includes(i) ? " \u{1F4CC}" : "";
|
|
1573
|
+
lines.push(` [${i + 1}] ${m.role.padEnd(10)} ${text}${pin}`);
|
|
1574
|
+
}
|
|
1575
|
+
lines.push("", "Usage: /rewind <n> \u2014 rewind to message N", "\u{1F4CC} = file checkpoint");
|
|
1576
|
+
this.send({ type: "info", message: lines.join("\n") });
|
|
1577
|
+
break;
|
|
1578
|
+
}
|
|
1579
|
+
const rewindN = parseInt(rewindSub, 10);
|
|
1580
|
+
if (isNaN(rewindN) || rewindN < 1 || rewindN > session.messages.length) {
|
|
1581
|
+
this.send({ type: "error", message: `Invalid message number: ${rewindSub}. Range: 1-${session.messages.length}` });
|
|
1582
|
+
break;
|
|
1583
|
+
}
|
|
1584
|
+
const { fileCheckpoints: fc } = await import("./file-checkpoint-NKBHGC7L.js");
|
|
1585
|
+
const rewindRemoved = session.messages.length - rewindN;
|
|
1586
|
+
const rewindResult = fc.restoreToMessageIndex(rewindN);
|
|
1587
|
+
session.messages = session.messages.slice(0, rewindN);
|
|
1588
|
+
session.checkpoints = session.checkpoints.filter((c) => c.messageIndex <= rewindN);
|
|
1589
|
+
session.updated = /* @__PURE__ */ new Date();
|
|
1590
|
+
this.sessions.save();
|
|
1591
|
+
const rewindLines = [`\u2713 Rewound to message ${rewindN}`, ` Messages removed: ${rewindRemoved}`];
|
|
1592
|
+
if (rewindResult.restored > 0 || rewindResult.deleted > 0) {
|
|
1593
|
+
rewindLines.push(` Files restored: ${rewindResult.restored}, deleted: ${rewindResult.deleted}`);
|
|
1594
|
+
for (const f of rewindResult.files) rewindLines.push(` ${f}`);
|
|
1595
|
+
} else {
|
|
1596
|
+
rewindLines.push(" No file changes to revert.");
|
|
1597
|
+
}
|
|
1598
|
+
this.send({ type: "info", message: rewindLines.join("\n") });
|
|
1599
|
+
this.sendSessionMessages();
|
|
1600
|
+
this.sendStatus();
|
|
1601
|
+
break;
|
|
1602
|
+
}
|
|
1515
1603
|
// ── /test ───────────────────────────────────────────────────────
|
|
1516
1604
|
case "test": {
|
|
1517
1605
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
1518
1606
|
try {
|
|
1519
|
-
const { executeTests } = await import("./run-tests-
|
|
1607
|
+
const { executeTests } = await import("./run-tests-L3JNRB6X.js");
|
|
1520
1608
|
const argStr = args.join(" ").trim();
|
|
1521
1609
|
let testArgs = {};
|
|
1522
1610
|
if (argStr) {
|
|
@@ -2320,6 +2408,37 @@ ${diff}
|
|
|
2320
2408
|
4. **Highlights** (if any)
|
|
2321
2409
|
|
|
2322
2410
|
Severity: \u{1F534} Critical / \u{1F7E1} Warning / \u{1F535} Info`;
|
|
2411
|
+
}
|
|
2412
|
+
buildSecurityReviewPrompt(diff, gitContextStr) {
|
|
2413
|
+
return `# Security Vulnerability Review
|
|
2414
|
+
|
|
2415
|
+
Analyze the following code changes **exclusively for security vulnerabilities**.
|
|
2416
|
+
|
|
2417
|
+
## Categories
|
|
2418
|
+
1. Injection (SQL, command, path traversal, XSS)
|
|
2419
|
+
2. Auth & Authorization (hardcoded creds, missing checks)
|
|
2420
|
+
3. Secrets & Sensitive Data (API keys, tokens in code)
|
|
2421
|
+
4. Input Validation (missing validation, unsafe deserialization)
|
|
2422
|
+
5. Cryptography (weak algorithms, hardcoded IVs)
|
|
2423
|
+
6. File System (path traversal, symlink attacks)
|
|
2424
|
+
7. Network (SSRF, insecure protocols)
|
|
2425
|
+
|
|
2426
|
+
## Git Status
|
|
2427
|
+
${gitContextStr}
|
|
2428
|
+
|
|
2429
|
+
## Code Changes
|
|
2430
|
+
\`\`\`diff
|
|
2431
|
+
${diff}
|
|
2432
|
+
\`\`\`
|
|
2433
|
+
|
|
2434
|
+
## Output Format
|
|
2435
|
+
For each finding:
|
|
2436
|
+
- **Severity**: \u{1F534} CRITICAL / \u{1F7E0} HIGH / \u{1F7E1} MEDIUM / \u{1F535} LOW
|
|
2437
|
+
- **Category** + **File:line**
|
|
2438
|
+
- **Description** + exploitation scenario
|
|
2439
|
+
- **Recommended fix**
|
|
2440
|
+
|
|
2441
|
+
If none found: "\u2705 No security vulnerabilities detected"`;
|
|
2323
2442
|
}
|
|
2324
2443
|
loadContextFiles() {
|
|
2325
2444
|
const parts = [];
|
|
@@ -4,10 +4,11 @@ import {
|
|
|
4
4
|
getDangerLevel,
|
|
5
5
|
googleSearchContext,
|
|
6
6
|
truncateOutput
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5GZQLJAY.js";
|
|
8
|
+
import "./chunk-4BKXL7SM.js";
|
|
8
9
|
import {
|
|
9
10
|
SUBAGENT_ALLOWED_TOOLS
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-AHH5I2U6.js";
|
|
11
12
|
|
|
12
13
|
// src/hub/task-orchestrator.ts
|
|
13
14
|
import { createInterface } from "readline";
|
package/dist/web/client/app.js
CHANGED
|
@@ -782,27 +782,40 @@ function renderFilteredSessions(filter) {
|
|
|
782
782
|
</div>`;
|
|
783
783
|
}).join('');
|
|
784
784
|
|
|
785
|
-
// Click to load session
|
|
785
|
+
// Click to load session / double-click title to rename
|
|
786
786
|
sessionListEl.querySelectorAll('.session-item').forEach(el => {
|
|
787
|
+
let clickTimer = null;
|
|
788
|
+
|
|
787
789
|
el.addEventListener('click', (e) => {
|
|
788
790
|
if (e.target.closest('.session-delete-btn') || e.target.closest('.session-batch-cb') || e.target.closest('.session-rename-input')) return;
|
|
789
791
|
if (batchSelectMode) {
|
|
790
|
-
// In batch mode, clicking the row toggles the checkbox
|
|
791
792
|
const cb = el.querySelector('.session-batch-cb');
|
|
792
793
|
if (cb) { cb.checked = !cb.checked; cb.dispatchEvent(new Event('change')); }
|
|
793
794
|
return;
|
|
794
795
|
}
|
|
796
|
+
// If clicking on the title text, delay to allow dblclick detection
|
|
797
|
+
if (!batchSelectMode && e.target.closest('.session-title')) {
|
|
798
|
+
if (clickTimer) return; // Already waiting
|
|
799
|
+
clickTimer = setTimeout(() => {
|
|
800
|
+
clickTimer = null;
|
|
801
|
+
const id = el.dataset.sessionId;
|
|
802
|
+
if (id) send({ type: 'command', name: 'session', args: ['load', id] });
|
|
803
|
+
}, 300);
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
// Clicking elsewhere on the item — load immediately
|
|
795
807
|
const id = el.dataset.sessionId;
|
|
796
808
|
if (!id) return;
|
|
797
809
|
send({ type: 'command', name: 'session', args: ['load', id] });
|
|
798
810
|
});
|
|
799
811
|
|
|
800
|
-
// Double-click session title to rename
|
|
801
812
|
if (!batchSelectMode) {
|
|
802
813
|
const titleEl = el.querySelector('.session-title');
|
|
803
814
|
if (titleEl) {
|
|
804
815
|
titleEl.addEventListener('dblclick', (e) => {
|
|
805
816
|
e.stopPropagation();
|
|
817
|
+
e.preventDefault();
|
|
818
|
+
if (clickTimer) { clearTimeout(clickTimer); clickTimer = null; }
|
|
806
819
|
startSessionRename(el, titleEl);
|
|
807
820
|
});
|
|
808
821
|
}
|