jinzd-ai-cli 0.4.259 → 0.4.261
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/{batch-74P2FQWX.js → batch-YUPAC4CK.js} +2 -2
- package/dist/{chunk-4TDVLTX2.js → chunk-323S2X5I.js} +1 -1
- package/dist/{chunk-PSH5O44I.js → chunk-GC4KA5LF.js} +1 -1
- package/dist/{chunk-G65I4DXP.js → chunk-H6FND2UG.js} +1 -1
- package/dist/{chunk-FGONEVTP.js → chunk-HGTDI5ME.js} +1 -1
- package/dist/{chunk-4RPJQJBI.js → chunk-HU3IYBU5.js} +11 -9
- package/dist/{chunk-V5FB72RK.js → chunk-KFNQESEG.js} +1 -1
- package/dist/{chunk-BWJYDG3C.js → chunk-KQQHMGK7.js} +1 -1
- package/dist/{chunk-ZZ5WTHKY.js → chunk-NOB2OPQI.js} +4 -4
- package/dist/{chunk-GDJII6TK.js → chunk-OIOTHBDB.js} +23 -5
- package/dist/{chunk-DLOOIAAD.js → chunk-R6DXWVVN.js} +1 -1
- package/dist/{chunk-KXAVUZKH.js → chunk-T7R7ILYT.js} +1 -1
- package/dist/{chunk-3KYUE2MD.js → chunk-W5XUZYQE.js} +1 -1
- package/dist/{chunk-XPNKMDBH.js → chunk-XZNRZGG2.js} +63 -26
- package/dist/{chunk-7DVIAK6J.js → chunk-YXMBP567.js} +2 -2
- package/dist/{chunk-3EWST6SE.js → chunk-Z5TCAE4L.js} +4 -4
- package/dist/{ci-6BANR65W.js → ci-FX26BNT2.js} +6 -6
- package/dist/{ci-format-2OVEQK6O.js → ci-format-GEWIAIZD.js} +2 -2
- package/dist/{constants-DKZEF3CE.js → constants-YN4B6C7B.js} +1 -1
- package/dist/{doctor-cli-6MHA7Q7M.js → doctor-cli-PXGXZYQB.js} +6 -6
- package/dist/electron-server.js +96 -40
- package/dist/{hub-L7RSDS4J.js → hub-RCANK6SK.js} +1 -1
- package/dist/index.js +145 -65
- package/dist/{persistent-memory-I4JV3CME.js → persistent-memory-P3COUZZM.js} +2 -2
- package/dist/{persistent-memory-WBR2DALU.js → persistent-memory-UARSSYAA.js} +2 -2
- package/dist/{pr-UNCWDVN3.js → pr-7LQTAUFK.js} +6 -6
- package/dist/{run-tests-HFT5RUXF.js → run-tests-7RYU4BK5.js} +2 -2
- package/dist/{run-tests-XBODGDFO.js → run-tests-YNHESHYY.js} +2 -2
- package/dist/{server-ILKG2672.js → server-SSAWGNT7.js} +13 -13
- package/dist/{server-RNBKZ6TP.js → server-YZ37TL46.js} +6 -6
- package/dist/{task-orchestrator-GXP5HNBZ.js → task-orchestrator-ZFL4E6NZ.js} +6 -6
- package/dist/{usage-KCPH75KI.js → usage-PDKM7J75.js} +2 -2
- package/package.json +1 -1
package/dist/electron-server.js
CHANGED
|
@@ -34,14 +34,14 @@ import {
|
|
|
34
34
|
touchMemoryReferences,
|
|
35
35
|
updateMemoryApproval,
|
|
36
36
|
updateMemoryEntry
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-T7R7ILYT.js";
|
|
38
38
|
import {
|
|
39
39
|
redactJson,
|
|
40
40
|
scanString
|
|
41
41
|
} from "./chunk-YVTASHS5.js";
|
|
42
42
|
import {
|
|
43
43
|
runTestsTool
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-KFNQESEG.js";
|
|
45
45
|
import {
|
|
46
46
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
47
47
|
APP_NAME,
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
SUBAGENT_MAX_ROUNDS_LIMIT,
|
|
74
74
|
VERSION,
|
|
75
75
|
buildUserIdentityPrompt
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-R6DXWVVN.js";
|
|
77
77
|
import {
|
|
78
78
|
hasSemanticIndex,
|
|
79
79
|
semanticSearch
|
|
@@ -987,7 +987,8 @@ var ClaudeProvider = class extends BaseProvider {
|
|
|
987
987
|
max_tokens: request.maxTokens ?? 8192,
|
|
988
988
|
temperature,
|
|
989
989
|
thinking
|
|
990
|
-
|
|
990
|
+
// 非流式路径必须收 signal,否则 Ctrl+C 期间请求不可中断(同 openai-compatible 的同类遗漏)
|
|
991
|
+
}, { signal: request.signal });
|
|
991
992
|
const content = this.extractContent(response.content);
|
|
992
993
|
return {
|
|
993
994
|
content,
|
|
@@ -1066,7 +1067,8 @@ var ClaudeProvider = class extends BaseProvider {
|
|
|
1066
1067
|
max_tokens: request.maxTokens ?? 8192,
|
|
1067
1068
|
temperature,
|
|
1068
1069
|
thinking
|
|
1069
|
-
|
|
1070
|
+
// 轮次耗尽的总结轮对所有 provider 都走这条非流式路径——漏 signal 则 Ctrl+C 无效
|
|
1071
|
+
}, { signal: request.signal });
|
|
1070
1072
|
const usage = this.extractUsage(response.usage);
|
|
1071
1073
|
const toolUseBlocks = response.content.filter(
|
|
1072
1074
|
(b) => b.type === "tool_use"
|
|
@@ -1811,6 +1813,52 @@ CRITICAL \u2014 Batch file generation rules:
|
|
|
1811
1813
|
4. Only produce a text summary AFTER all write_file calls have been made and returned success.
|
|
1812
1814
|
5. The system compares every "file saved" claim against actual tool calls. Phantom claims trigger an automatic retry \u2014 do not waste rounds.`;
|
|
1813
1815
|
var HALLUCINATION_CORRECTION_MESSAGE = "You did NOT actually call the write_file tool \u2014 the file was NOT created! Please immediately use the write_file tool via the function calling API to perform the actual file write. Do NOT describe file content in text \u2014 you MUST invoke write_file through the tool_calls mechanism.";
|
|
1816
|
+
var ACTION_WORD_RE = /(?:已[生保写创]|saved|written|created|完成.*(?:写入|保存|创建|生成)|输出|file\s+(?:saved|written|created))/i;
|
|
1817
|
+
var CLAUSE_BOUNDARY_RE = /[。.!?!?;;,,]/;
|
|
1818
|
+
var LIST_LINE_RE = /^\s*(?:[-*+]|\d+[.)]|\|)/;
|
|
1819
|
+
function hasWriteIntentNear(content, pathStart, pathEnd) {
|
|
1820
|
+
const lineStart = content.lastIndexOf("\n", pathStart - 1) + 1;
|
|
1821
|
+
const lineEndRaw = content.indexOf("\n", pathEnd);
|
|
1822
|
+
const lineEnd = lineEndRaw === -1 ? content.length : lineEndRaw;
|
|
1823
|
+
const currentLine = content.slice(lineStart, lineEnd);
|
|
1824
|
+
const prevLineStart = lineStart === 0 ? 0 : content.lastIndexOf("\n", lineStart - 2) + 1;
|
|
1825
|
+
const prevLine = lineStart === 0 ? "" : content.slice(prevLineStart, lineStart - 1);
|
|
1826
|
+
const introColon = /[::]\s*$/.test(prevLine);
|
|
1827
|
+
if (LIST_LINE_RE.test(currentLine) || introColon) {
|
|
1828
|
+
let pos = pathStart;
|
|
1829
|
+
let linesBack = 0;
|
|
1830
|
+
while (linesBack < 9 && pos > 0) {
|
|
1831
|
+
pos--;
|
|
1832
|
+
if (content[pos] === "\n") linesBack++;
|
|
1833
|
+
}
|
|
1834
|
+
const windowStart = pos === 0 ? 0 : pos + 1;
|
|
1835
|
+
return ACTION_WORD_RE.test(content.slice(windowStart, lineEnd));
|
|
1836
|
+
}
|
|
1837
|
+
const boundaryBefore = (from) => {
|
|
1838
|
+
for (let i = from - 1; i >= lineStart; i--) {
|
|
1839
|
+
if (CLAUSE_BOUNDARY_RE.test(content[i] ?? "")) return i + 1;
|
|
1840
|
+
}
|
|
1841
|
+
return lineStart;
|
|
1842
|
+
};
|
|
1843
|
+
let clauseEnd = lineEnd;
|
|
1844
|
+
for (let i = pathEnd; i < lineEnd; i++) {
|
|
1845
|
+
if (CLAUSE_BOUNDARY_RE.test(content[i] ?? "")) {
|
|
1846
|
+
clauseEnd = i + 1;
|
|
1847
|
+
break;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
const isBareClause = (text2) => text2.replace(/`[^`\n]*`/g, "").replace(content.slice(pathStart, pathEnd), "").replace(/[\s'"“”‘’()()、,,。;;::+\-和与及]/g, "").length <= 2;
|
|
1851
|
+
let start = boundaryBefore(pathStart);
|
|
1852
|
+
let text = content.slice(start, clauseEnd);
|
|
1853
|
+
if (ACTION_WORD_RE.test(text)) return true;
|
|
1854
|
+
for (let step = 0; step < 6 && start > lineStart && isBareClause(text); step++) {
|
|
1855
|
+
const prevEnd = start - 1;
|
|
1856
|
+
start = boundaryBefore(prevEnd);
|
|
1857
|
+
text = content.slice(start, prevEnd);
|
|
1858
|
+
if (ACTION_WORD_RE.test(text)) return true;
|
|
1859
|
+
}
|
|
1860
|
+
return false;
|
|
1861
|
+
}
|
|
1814
1862
|
function extractClaimedFilePaths(content) {
|
|
1815
1863
|
const paths = /* @__PURE__ */ new Set();
|
|
1816
1864
|
const add = (p) => {
|
|
@@ -1818,36 +1866,19 @@ function extractClaimedFilePaths(content) {
|
|
|
1818
1866
|
if (trimmed && /\.\w{1,6}$/.test(trimmed)) paths.add(trimmed);
|
|
1819
1867
|
};
|
|
1820
1868
|
let m;
|
|
1821
|
-
const actionLineRe = /(?:已[生保写创]|saved|written|created|完成.*(?:写入|保存|创建|生成)|输出|file\s+(?:saved|written|created))/i;
|
|
1822
1869
|
const backtickRe = /`([^`\n]+?\.\w{1,6})`/g;
|
|
1823
1870
|
while ((m = backtickRe.exec(content)) !== null) {
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
while (linesBack < 9 && pos > 0) {
|
|
1827
|
-
pos--;
|
|
1828
|
-
if (content[pos] === "\n") linesBack++;
|
|
1829
|
-
}
|
|
1830
|
-
const windowStart = pos === 0 ? 0 : pos + 1;
|
|
1831
|
-
const lineEndIdx = content.indexOf("\n", m.index + m[0].length);
|
|
1832
|
-
const window = content.slice(windowStart, lineEndIdx === -1 ? void 0 : lineEndIdx);
|
|
1833
|
-
if (actionLineRe.test(window)) add(m[1]);
|
|
1871
|
+
const pathStart = m.index + m[0].indexOf(m[1]);
|
|
1872
|
+
if (hasWriteIntentNear(content, pathStart, pathStart + m[1].length)) add(m[1]);
|
|
1834
1873
|
}
|
|
1835
|
-
const zhRe = /(?:已保存(?:到)?|已写入(?:到)?|已创建|已生成|文件路径[::]|保存为|写入到)\s*[`'”””]?([^\s`'”””,,。\n]
|
|
1874
|
+
const zhRe = /(?:已保存(?:到)?|已写入(?:到)?|已创建|已生成|文件路径[::]|保存为|写入到)\s*[`'”””]?([^\s`'”””,,。\n]+\.\w{1,6})/g;
|
|
1836
1875
|
while ((m = zhRe.exec(content)) !== null) add(m[1]);
|
|
1837
|
-
const enRe = /(?:saved|written|created)\s+(?:to|as|at)\s+[`'”]?([^\s`'”\n,]
|
|
1876
|
+
const enRe = /(?:saved|written|created)\s+(?:to|as|at)\s+[`'”]?([^\s`'”\n,]+\.\w{1,6})/gi;
|
|
1838
1877
|
while ((m = enRe.exec(content)) !== null) add(m[1]);
|
|
1839
1878
|
const checkRe = /✅[^\n`]*?[`'”]?([^\s`'”\n,,。]+?\.\w{1,6})/g;
|
|
1840
1879
|
while ((m = checkRe.exec(content)) !== null) {
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
while (linesBack < 9 && pos > 0) {
|
|
1844
|
-
pos--;
|
|
1845
|
-
if (content[pos] === "\n") linesBack++;
|
|
1846
|
-
}
|
|
1847
|
-
const windowStart = pos === 0 ? 0 : pos + 1;
|
|
1848
|
-
const lineEndIdx = content.indexOf("\n", m.index + m[0].length);
|
|
1849
|
-
const window = content.slice(windowStart, lineEndIdx === -1 ? void 0 : lineEndIdx);
|
|
1850
|
-
if (actionLineRe.test(window)) add(m[1]);
|
|
1880
|
+
const pathStart = m.index + m[0].lastIndexOf(m[1]);
|
|
1881
|
+
if (hasWriteIntentNear(content, pathStart, pathStart + m[1].length)) add(m[1]);
|
|
1851
1882
|
}
|
|
1852
1883
|
return Array.from(paths);
|
|
1853
1884
|
}
|
|
@@ -1960,7 +1991,7 @@ function findPhantomClaims(content, extraMessages) {
|
|
|
1960
1991
|
}
|
|
1961
1992
|
function buildPhantomCorrectionMessage(phantoms) {
|
|
1962
1993
|
const list = phantoms.map((p) => ` - ${p}`).join("\n");
|
|
1963
|
-
return
|
|
1994
|
+
return 'Your reply mentions the following file(s) alongside a "written / saved / created" claim, but no matching write_file or edit_file tool call was made in this turn:\n' + list + "\n\nIf you did intend to create or modify them, invoke write_file / edit_file NOW \u2014 they do not exist on disk yet, and you must not report the task as done until the tool calls return.\n\nIf you were only REFERENCING them (files you merely read, cited as examples, or named as prior art), then this was a false alarm: do NOT create them, do NOT overwrite anything. Simply restate your answer and say explicitly which of the listed paths you only read or cited. Creating a file that the user never asked for is worse than the false alarm.";
|
|
1964
1995
|
}
|
|
1965
1996
|
var DSML_PIPE_CLASS = "[|\\uFF5C\\u2502\\u2503\\u01C0]";
|
|
1966
1997
|
var PSEUDO_TOOL_CALL_PATTERNS = [
|
|
@@ -2393,7 +2424,7 @@ async function consumeToolCallStream(stream, hooks = {}) {
|
|
|
2393
2424
|
}
|
|
2394
2425
|
}
|
|
2395
2426
|
} catch (err) {
|
|
2396
|
-
if (
|
|
2427
|
+
if (isAbortError(err)) {
|
|
2397
2428
|
aborted = true;
|
|
2398
2429
|
} else {
|
|
2399
2430
|
throw err;
|
|
@@ -2487,6 +2518,10 @@ var BudgetWarner = class {
|
|
|
2487
2518
|
return null;
|
|
2488
2519
|
}
|
|
2489
2520
|
};
|
|
2521
|
+
function isAbortError(err) {
|
|
2522
|
+
if (!(err instanceof Error)) return false;
|
|
2523
|
+
return err.name === "AbortError" || err.name === "APIUserAbortError" || err.message.includes("aborted");
|
|
2524
|
+
}
|
|
2490
2525
|
var EMPTY_RESPONSE_NUDGE = "Your previous response was empty \u2014 no text and no tool calls. This usually means the context window is nearly full. Please either: (1) continue the task by calling the next tool you need, or (2) give a concise final text summary of what has been accomplished so far and what remains. Do NOT repeat earlier long outputs.";
|
|
2491
2526
|
var LENGTH_LIMIT_NUDGE = "Your previous attempt hit the model output token limit (finish_reason=length) before producing ANY answer text or tool call \u2014 the entire output budget was consumed by extended reasoning. Retrying the same way will fail identically. Do NOT reason at length again: start producing output immediately. If the deliverable is long, do NOT try to emit it in one response \u2014 write it to disk in several smaller write_file calls (part 1, part 2, ...), each well under the output limit, and keep any thinking short.";
|
|
2492
2527
|
function describeFinishReason(fr) {
|
|
@@ -2591,6 +2626,8 @@ async function runAgentLoop(host) {
|
|
|
2591
2626
|
const freeRounds = new FreeRoundTracker();
|
|
2592
2627
|
const roundToolHistory = [];
|
|
2593
2628
|
const hasWriteTools = host.toolDefs.some((t) => t.name === "write_file" || t.name === "edit_file");
|
|
2629
|
+
let hallucinationRetries = 0;
|
|
2630
|
+
const MAX_HALLUCINATION_RETRIES = 2;
|
|
2594
2631
|
for (let round = 0; round < maxToolRounds; round++) {
|
|
2595
2632
|
if (host.signal?.aborted) return { reason: "aborted", usage };
|
|
2596
2633
|
host.onRoundStart?.(round, maxToolRounds);
|
|
@@ -2628,7 +2665,8 @@ async function runAgentLoop(host) {
|
|
|
2628
2665
|
const phantomPaths = (coarseHallucination || alreadyWrote) && !host.planMode && hasWriteTools && content ? findPhantomClaims(content, extraMessages) : [];
|
|
2629
2666
|
const bashRanThisTurn = extractBashCommands(extraMessages).length > 0;
|
|
2630
2667
|
const coarseShouldFire = coarseHallucination && !bashRanThisTurn;
|
|
2631
|
-
if ((phantomPaths.length > 0 || coarseShouldFire) && round < maxToolRounds - 1) {
|
|
2668
|
+
if ((phantomPaths.length > 0 || coarseShouldFire) && round < maxToolRounds - 1 && hallucinationRetries < MAX_HALLUCINATION_RETRIES) {
|
|
2669
|
+
hallucinationRetries++;
|
|
2632
2670
|
host.onHallucinationRetry?.({ phantomPaths, round, alreadyRendered });
|
|
2633
2671
|
const correctionMsg = phantomPaths.length > 0 ? buildPhantomCorrectionMessage(phantomPaths) : HALLUCINATION_CORRECTION_MESSAGE;
|
|
2634
2672
|
const reasoningField = outcome.reasoningContent ? { reasoning_content: outcome.reasoningContent } : host.providerId === "deepseek" ? { reasoning_content: "" } : {};
|
|
@@ -2916,6 +2954,17 @@ var OpenAICompatibleProvider = class extends BaseProvider {
|
|
|
2916
2954
|
}
|
|
2917
2955
|
return msgs;
|
|
2918
2956
|
}
|
|
2957
|
+
/**
|
|
2958
|
+
* 非流式请求必须把 `request.signal` 交给 SDK —— 否则 Ctrl+C 完全无效。
|
|
2959
|
+
*
|
|
2960
|
+
* 实战(v0.4.260):东叔按建议把 `timeouts.deepseek` 提到 900000 后出卷,第 3 轮等了
|
|
2961
|
+
* 11 分钟,**按 Ctrl+C 退不出去**。DeepSeek/Kimi 的 `enableStreamingToolCalls=false`
|
|
2962
|
+
* 让整个 agentic 循环都走 `chatWithTools()` 这条阻塞路径,而这里此前只传了 `timeout`、
|
|
2963
|
+
* 没传 `signal`:REPL 的 AbortController 一路传到 `request.signal` 就断在这一跳,
|
|
2964
|
+
* 请求无法取消;`consumeToolCallStream()` 又只在**事件之间**检查 aborted,而回退路径
|
|
2965
|
+
* 要等这个 await 返回后才会吐第一个事件 —— 于是中断只能等满超时(被我调高到 15 分钟)。
|
|
2966
|
+
* 两个流式方法本来就传了 signal,唯独两个非流式方法漏了,属同一处遗漏的两半。
|
|
2967
|
+
*/
|
|
2919
2968
|
async chat(request) {
|
|
2920
2969
|
try {
|
|
2921
2970
|
const response = await this.client.chat.completions.create({
|
|
@@ -2926,7 +2975,8 @@ var OpenAICompatibleProvider = class extends BaseProvider {
|
|
|
2926
2975
|
stream: false,
|
|
2927
2976
|
...request.thinking ? { thinking: { type: "enabled" } } : {}
|
|
2928
2977
|
}, {
|
|
2929
|
-
timeout: request.timeout ?? this.defaultTimeout
|
|
2978
|
+
timeout: request.timeout ?? this.defaultTimeout,
|
|
2979
|
+
signal: request.signal
|
|
2930
2980
|
});
|
|
2931
2981
|
const firstChoice = response.choices?.[0];
|
|
2932
2982
|
if (!firstChoice) {
|
|
@@ -3032,7 +3082,9 @@ var OpenAICompatibleProvider = class extends BaseProvider {
|
|
|
3032
3082
|
stream: false,
|
|
3033
3083
|
...request.thinking ? { thinking: { type: "enabled" } } : {}
|
|
3034
3084
|
}, {
|
|
3035
|
-
timeout: request.timeout ?? this.defaultTimeout
|
|
3085
|
+
timeout: request.timeout ?? this.defaultTimeout,
|
|
3086
|
+
// 非流式路径同样必须收 signal,否则 Ctrl+C 期间整个请求不可中断(见 chat() 上方注释)
|
|
3087
|
+
signal: request.signal
|
|
3036
3088
|
});
|
|
3037
3089
|
const firstChoice = response.choices?.[0];
|
|
3038
3090
|
if (!firstChoice) {
|
|
@@ -3288,6 +3340,8 @@ var OpenAICompatibleProvider = class extends BaseProvider {
|
|
|
3288
3340
|
}
|
|
3289
3341
|
}
|
|
3290
3342
|
wrapError(err) {
|
|
3343
|
+
if (err instanceof OpenAI.APIUserAbortError) return err;
|
|
3344
|
+
if (err instanceof Error && err.name === "AbortError") return err;
|
|
3291
3345
|
if (err instanceof OpenAI.AuthenticationError) {
|
|
3292
3346
|
return new AuthError(this.info.id);
|
|
3293
3347
|
}
|
|
@@ -5059,9 +5113,9 @@ function buildWrappedCommand(command, id, isWindows) {
|
|
|
5059
5113
|
if (!isWindows) {
|
|
5060
5114
|
return `echo "${markerStart}"; ${command}; echo "${markerEnd}:$?"`;
|
|
5061
5115
|
}
|
|
5062
|
-
const
|
|
5063
|
-
const
|
|
5064
|
-
return
|
|
5116
|
+
const b64 = Buffer.from(command, "utf-8").toString("base64");
|
|
5117
|
+
const decoded = `[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${b64}'))`;
|
|
5118
|
+
return `${WIN_UTF8_PREAMBLE} Write-Output "${markerStart}"; $global:LASTEXITCODE = 0; Invoke-Expression (${decoded}); $__ok = $?; $__ec = $LASTEXITCODE; $__code = if ($null -ne $__ec -and $__ec -ne 0) { $__ec } elseif ($__ok) { 0 } else { 1 }; Write-Output "${markerEnd}:$__code"`;
|
|
5065
5119
|
}
|
|
5066
5120
|
async function execInPool(sessionKey, command, timeout, cwd, abortSignal) {
|
|
5067
5121
|
let entry = pool.get(sessionKey);
|
|
@@ -8424,7 +8478,9 @@ Note: Path can be absolute or relative to cwd.`,
|
|
|
8424
8478
|
}
|
|
8425
8479
|
const lines = [];
|
|
8426
8480
|
if (anyFailed && stopOnError) {
|
|
8427
|
-
|
|
8481
|
+
const failedIdx = reports.find((r) => !r.ok)?.index;
|
|
8482
|
+
const failedLabel = failedIdx != null ? `#${failedIdx + 1}` : "an edit";
|
|
8483
|
+
lines.push(`ERROR: Batch edit aborted \u2014 ${appliedCount}/${edits.length} applied, then edit ${failedLabel} failed. No changes written (stop_on_error=true).`);
|
|
8428
8484
|
} else if (anyFailed) {
|
|
8429
8485
|
lines.push(`Partial success: ${appliedCount}/${edits.length} edits applied to ${filePath} (stop_on_error=false).`);
|
|
8430
8486
|
} else {
|
|
@@ -15313,7 +15369,7 @@ Cache: write=${cacheCreate} read=${cacheRead}` : "";
|
|
|
15313
15369
|
Cost: ${formatCost(cost)}` : "";
|
|
15314
15370
|
let memoryLine = "";
|
|
15315
15371
|
try {
|
|
15316
|
-
const { countPendingMemories } = await import("./persistent-memory-
|
|
15372
|
+
const { countPendingMemories } = await import("./persistent-memory-P3COUZZM.js");
|
|
15317
15373
|
const pending = countPendingMemories(ctx.config.getConfigDir());
|
|
15318
15374
|
if (pending > 0) memoryLine = `
|
|
15319
15375
|
Memory: \u26A0 ${pending} pending approval \u2014 see the Memory panel or /memory`;
|
|
@@ -16122,7 +16178,7 @@ async function handleSecurityReview(args, ctx) {
|
|
|
16122
16178
|
async function handleTest(args, ctx) {
|
|
16123
16179
|
ctx.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
16124
16180
|
try {
|
|
16125
|
-
const { executeTests } = await import("./run-tests-
|
|
16181
|
+
const { executeTests } = await import("./run-tests-7RYU4BK5.js");
|
|
16126
16182
|
const argStr = args.join(" ").trim();
|
|
16127
16183
|
let testArgs = {};
|
|
16128
16184
|
if (argStr) {
|
|
@@ -16386,7 +16442,7 @@ async function handleMemory(args, ctx) {
|
|
|
16386
16442
|
ctx.handleMemoryManage(sub, args[1], sub === "expire" ? args[2] : void 0);
|
|
16387
16443
|
} else if (sub === "export") {
|
|
16388
16444
|
if (args[1] === "md") {
|
|
16389
|
-
const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-
|
|
16445
|
+
const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-P3COUZZM.js");
|
|
16390
16446
|
ctx.send({
|
|
16391
16447
|
type: "export_data",
|
|
16392
16448
|
format: "md",
|
|
@@ -154,7 +154,7 @@ ${content}`);
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
157
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
157
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-ZFL4E6NZ.js");
|
|
158
158
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
159
159
|
let interrupted = false;
|
|
160
160
|
const onSigint = () => {
|