zelari-code 1.10.0 → 1.11.0
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/cli/headless.js +41 -0
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/main.bundled.js +202 -34
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/provider/openai-compatible.js +46 -3
- package/dist/cli/provider/openai-compatible.js.map +1 -1
- package/dist/cli/runHeadless.js +169 -30
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/utils/streamScrub.js +55 -0
- package/dist/cli/utils/streamScrub.js.map +1 -0
- package/package.json +2 -2
package/dist/cli/headless.js
CHANGED
|
@@ -19,6 +19,7 @@ import { getActiveProvider, getModelForProvider } from './providerConfig.js';
|
|
|
19
19
|
import { openaiCompatibleProvider } from './provider/openai-compatible.js';
|
|
20
20
|
import { parsePhase } from './phase.js';
|
|
21
21
|
import { parseMode } from './mode.js';
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
22
23
|
const HELP_TEXT = `zelari-code --headless --task <prompt> [options]
|
|
23
24
|
|
|
24
25
|
Non-interactive mode. Streams BrainEvents as NDJSON to stdout (one JSON
|
|
@@ -32,6 +33,8 @@ Options:
|
|
|
32
33
|
--phase plan|build Work phase (default: build)
|
|
33
34
|
--provider <id> Provider override (default: active)
|
|
34
35
|
--model <name> Model override (default: provider default)
|
|
36
|
+
--history <json> Prior turns (JSON AgentMessage[]) for multi-turn context
|
|
37
|
+
--history-file <path> Same as --history but read from a file (avoids Windows argv cap)
|
|
35
38
|
|
|
36
39
|
Exit codes:
|
|
37
40
|
0 completed
|
|
@@ -55,6 +58,7 @@ export function parseHeadlessFlags(argv) {
|
|
|
55
58
|
let councilFlag = false;
|
|
56
59
|
let provider;
|
|
57
60
|
let model;
|
|
61
|
+
let history;
|
|
58
62
|
for (let i = 0; i < argv.length; i++) {
|
|
59
63
|
const arg = argv[i];
|
|
60
64
|
if (arg === '--headless')
|
|
@@ -112,6 +116,42 @@ export function parseHeadlessFlags(argv) {
|
|
|
112
116
|
model = argv[i + 1];
|
|
113
117
|
i++;
|
|
114
118
|
}
|
|
119
|
+
else if (arg === '--history' || arg === '--history-file') {
|
|
120
|
+
// Multi-turn context from the desktop. `--history` takes the JSON inline
|
|
121
|
+
// (kept for backward compat / scripting); `--history-file` reads it from
|
|
122
|
+
// a tempfile. The file path is PREFERRED on Windows because CreateProcess
|
|
123
|
+
// caps the command line at ~32KB (os error 206) and a long chat history
|
|
124
|
+
// overflows it. Invalid/missing JSON is ignored: the run degrades to
|
|
125
|
+
// stateless (pre-v1.10.0 behavior) rather than erroring out.
|
|
126
|
+
const next = argv[i + 1];
|
|
127
|
+
if (next) {
|
|
128
|
+
let raw = null;
|
|
129
|
+
if (arg === '--history-file') {
|
|
130
|
+
try {
|
|
131
|
+
raw = readFileSync(next, 'utf-8');
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
raw = null; // File gone/unreadable — run stateless.
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
raw = next;
|
|
139
|
+
}
|
|
140
|
+
if (raw) {
|
|
141
|
+
try {
|
|
142
|
+
const parsedHist = JSON.parse(raw);
|
|
143
|
+
if (Array.isArray(parsedHist)) {
|
|
144
|
+
history = parsedHist.filter((m) => m && typeof m === 'object' && typeof m.role === 'string' &&
|
|
145
|
+
typeof m.content === 'string');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// Swallow: stale/incompatible history.
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
i++;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
115
155
|
}
|
|
116
156
|
// --council is an alias for --mode council when --mode was not set.
|
|
117
157
|
if (councilFlag && !modeExplicit) {
|
|
@@ -135,6 +175,7 @@ export function parseHeadlessFlags(argv) {
|
|
|
135
175
|
useCouncil: mode === 'council',
|
|
136
176
|
provider,
|
|
137
177
|
model,
|
|
178
|
+
...(history && history.length > 0 ? { history } : {}),
|
|
138
179
|
},
|
|
139
180
|
};
|
|
140
181
|
}
|
package/dist/cli/headless.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headless.js","sourceRoot":"","sources":["../../src/cli/headless.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"headless.js","sourceRoot":"","sources":["../../src/cli/headless.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/main.bundled.js
CHANGED
|
@@ -19774,6 +19774,16 @@ ${cached2}`
|
|
|
19774
19774
|
finishRef.value = "tool_calls";
|
|
19775
19775
|
}
|
|
19776
19776
|
}
|
|
19777
|
+
if (finishRef.value === "tool_calls" && turnToolCalls.length === 0 && turnToolResults.length === 0) {
|
|
19778
|
+
const truncErr = createBrainEvent("error", this.sessionId, {
|
|
19779
|
+
severity: "recoverable",
|
|
19780
|
+
message: "Tool call was truncated (finish_reason=tool_calls but no complete tool_call received). The provider cut the response mid-arguments. Retry with a shorter payload or split the work.",
|
|
19781
|
+
code: "tool_call_truncated"
|
|
19782
|
+
});
|
|
19783
|
+
this.emit(truncErr);
|
|
19784
|
+
yield truncErr;
|
|
19785
|
+
finishRef.value = "stop";
|
|
19786
|
+
}
|
|
19777
19787
|
if (turnToolCalls.length > 0 || turnText.length > 0) {
|
|
19778
19788
|
this.config.messages.push({
|
|
19779
19789
|
role: "assistant",
|
|
@@ -20170,6 +20180,8 @@ function openaiCompatibleProvider(config2) {
|
|
|
20170
20180
|
return;
|
|
20171
20181
|
}
|
|
20172
20182
|
try {
|
|
20183
|
+
const timeoutSignal = AbortSignal.timeout(PROVIDER_TIMEOUT_MS);
|
|
20184
|
+
const fetchSignal = params.signal ? AbortSignal.any([params.signal, timeoutSignal]) : timeoutSignal;
|
|
20173
20185
|
response = await fetch(`${config2.baseUrl}/chat/completions`, {
|
|
20174
20186
|
method: "POST",
|
|
20175
20187
|
headers: {
|
|
@@ -20181,11 +20193,17 @@ function openaiCompatibleProvider(config2) {
|
|
|
20181
20193
|
// controller) so `.cancel()` actually aborts the HTTP request.
|
|
20182
20194
|
// `config.signal` is the factory-level signal, typically undefined.
|
|
20183
20195
|
// v0.6.0 audit HIGH-2.
|
|
20184
|
-
|
|
20196
|
+
// v1.10.0: also apply PROVIDER_TIMEOUT_MS so a stalled connection
|
|
20197
|
+
// can't hang the harness forever.
|
|
20198
|
+
signal: fetchSignal
|
|
20185
20199
|
});
|
|
20186
20200
|
} catch (err) {
|
|
20187
20201
|
lastStatus = 0;
|
|
20188
20202
|
lastErrText = err instanceof Error ? err.message : String(err);
|
|
20203
|
+
if (params.signal?.aborted) {
|
|
20204
|
+
yield { kind: "error", message: "aborted" };
|
|
20205
|
+
return;
|
|
20206
|
+
}
|
|
20189
20207
|
if (attempt < MAX_RETRIES) {
|
|
20190
20208
|
await abortableSleep(backoffDelay(attempt, null), params.signal);
|
|
20191
20209
|
continue;
|
|
@@ -20246,6 +20264,10 @@ function openaiCompatibleProvider(config2) {
|
|
|
20246
20264
|
if (typeof delta?.content === "string" && delta.content.length > 0) {
|
|
20247
20265
|
yield { kind: "text", delta: delta.content };
|
|
20248
20266
|
}
|
|
20267
|
+
const reasoning = delta?.reasoning_content ?? delta?.reasoning;
|
|
20268
|
+
if (typeof reasoning === "string" && reasoning.length > 0) {
|
|
20269
|
+
yield { kind: "thinking", delta: reasoning };
|
|
20270
|
+
}
|
|
20249
20271
|
if (Array.isArray(delta?.tool_calls)) {
|
|
20250
20272
|
for (const tc of delta.tool_calls) {
|
|
20251
20273
|
const idx = tc.index ?? 0;
|
|
@@ -20306,7 +20328,7 @@ async function providerConfigFor(providerId) {
|
|
|
20306
20328
|
providerId
|
|
20307
20329
|
};
|
|
20308
20330
|
}
|
|
20309
|
-
var RETRYABLE_STATUSES, MAX_RETRIES, BACKOFF_BASE_MS, BACKOFF_CAP_MS, PROVIDER_ENDPOINTS;
|
|
20331
|
+
var RETRYABLE_STATUSES, MAX_RETRIES, BACKOFF_BASE_MS, BACKOFF_CAP_MS, PROVIDER_TIMEOUT_MS, PROVIDER_ENDPOINTS;
|
|
20310
20332
|
var init_openai_compatible = __esm({
|
|
20311
20333
|
"src/cli/provider/openai-compatible.ts"() {
|
|
20312
20334
|
"use strict";
|
|
@@ -20320,6 +20342,11 @@ var init_openai_compatible = __esm({
|
|
|
20320
20342
|
})();
|
|
20321
20343
|
BACKOFF_BASE_MS = 500;
|
|
20322
20344
|
BACKOFF_CAP_MS = 8e3;
|
|
20345
|
+
PROVIDER_TIMEOUT_MS = (() => {
|
|
20346
|
+
const raw = process.env.ZELARI_PROVIDER_TIMEOUT_MS;
|
|
20347
|
+
const n = raw ? Number.parseInt(raw, 10) : 3e5;
|
|
20348
|
+
return Number.isFinite(n) && n >= 1e4 ? n : 3e5;
|
|
20349
|
+
})();
|
|
20323
20350
|
PROVIDER_ENDPOINTS = {
|
|
20324
20351
|
"openai-compatible": "https://api.x.ai/v1",
|
|
20325
20352
|
"minimax": "https://api.minimax.io/v1",
|
|
@@ -30392,7 +30419,7 @@ __export(doctor_exports, {
|
|
|
30392
30419
|
runDoctor: () => runDoctor
|
|
30393
30420
|
});
|
|
30394
30421
|
import { execSync as execSync2 } from "node:child_process";
|
|
30395
|
-
import { existsSync as existsSync32, readFileSync as
|
|
30422
|
+
import { existsSync as existsSync32, readFileSync as readFileSync27, readlinkSync, statSync as statSync6 } from "node:fs";
|
|
30396
30423
|
import { createRequire as createRequire3 } from "node:module";
|
|
30397
30424
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
30398
30425
|
import path35 from "node:path";
|
|
@@ -30402,7 +30429,7 @@ function findPackageRoot(start) {
|
|
|
30402
30429
|
const candidate = path35.join(dir, "package.json");
|
|
30403
30430
|
if (existsSync32(candidate)) {
|
|
30404
30431
|
try {
|
|
30405
|
-
const pkg = JSON.parse(
|
|
30432
|
+
const pkg = JSON.parse(readFileSync27(candidate, "utf8"));
|
|
30406
30433
|
if (pkg.name === "zelari-code") return dir;
|
|
30407
30434
|
} catch {
|
|
30408
30435
|
}
|
|
@@ -30426,7 +30453,7 @@ function tryExec(cmd) {
|
|
|
30426
30453
|
function readPackageJson3() {
|
|
30427
30454
|
try {
|
|
30428
30455
|
const pkgPath = path35.join(packageRoot, "package.json");
|
|
30429
|
-
return JSON.parse(
|
|
30456
|
+
return JSON.parse(readFileSync27(pkgPath, "utf8"));
|
|
30430
30457
|
} catch {
|
|
30431
30458
|
return null;
|
|
30432
30459
|
}
|
|
@@ -30451,7 +30478,7 @@ function checkShim(pkgName) {
|
|
|
30451
30478
|
try {
|
|
30452
30479
|
const st = statSync6(shimPath);
|
|
30453
30480
|
if (isWin) {
|
|
30454
|
-
const content =
|
|
30481
|
+
const content = readFileSync27(shimPath, "utf8");
|
|
30455
30482
|
if (content.includes(`${pkgName}\\bin\\`) || content.includes(`${pkgName}/bin/`)) {
|
|
30456
30483
|
return OK(`shim OK at ${shimPath} (${st.size} bytes)`);
|
|
30457
30484
|
}
|
|
@@ -38696,6 +38723,7 @@ init_keyStore();
|
|
|
38696
38723
|
init_providerConfig();
|
|
38697
38724
|
init_openai_compatible();
|
|
38698
38725
|
init_phase();
|
|
38726
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
38699
38727
|
function parseHeadlessFlags(argv) {
|
|
38700
38728
|
if (!argv.includes("--headless")) {
|
|
38701
38729
|
return { options: null };
|
|
@@ -38708,6 +38736,7 @@ function parseHeadlessFlags(argv) {
|
|
|
38708
38736
|
let councilFlag = false;
|
|
38709
38737
|
let provider;
|
|
38710
38738
|
let model;
|
|
38739
|
+
let history2;
|
|
38711
38740
|
for (let i = 0; i < argv.length; i++) {
|
|
38712
38741
|
const arg = argv[i];
|
|
38713
38742
|
if (arg === "--headless") continue;
|
|
@@ -38756,6 +38785,32 @@ function parseHeadlessFlags(argv) {
|
|
|
38756
38785
|
} else if (arg === "--model") {
|
|
38757
38786
|
model = argv[i + 1];
|
|
38758
38787
|
i++;
|
|
38788
|
+
} else if (arg === "--history" || arg === "--history-file") {
|
|
38789
|
+
const next = argv[i + 1];
|
|
38790
|
+
if (next) {
|
|
38791
|
+
let raw = null;
|
|
38792
|
+
if (arg === "--history-file") {
|
|
38793
|
+
try {
|
|
38794
|
+
raw = readFileSync25(next, "utf-8");
|
|
38795
|
+
} catch {
|
|
38796
|
+
raw = null;
|
|
38797
|
+
}
|
|
38798
|
+
} else {
|
|
38799
|
+
raw = next;
|
|
38800
|
+
}
|
|
38801
|
+
if (raw) {
|
|
38802
|
+
try {
|
|
38803
|
+
const parsedHist = JSON.parse(raw);
|
|
38804
|
+
if (Array.isArray(parsedHist)) {
|
|
38805
|
+
history2 = parsedHist.filter(
|
|
38806
|
+
(m) => m && typeof m === "object" && typeof m.role === "string" && typeof m.content === "string"
|
|
38807
|
+
);
|
|
38808
|
+
}
|
|
38809
|
+
} catch {
|
|
38810
|
+
}
|
|
38811
|
+
}
|
|
38812
|
+
i++;
|
|
38813
|
+
}
|
|
38759
38814
|
}
|
|
38760
38815
|
}
|
|
38761
38816
|
if (councilFlag && !modeExplicit) {
|
|
@@ -38777,7 +38832,8 @@ function parseHeadlessFlags(argv) {
|
|
|
38777
38832
|
phase: phase2,
|
|
38778
38833
|
useCouncil: mode === "council",
|
|
38779
38834
|
provider,
|
|
38780
|
-
model
|
|
38835
|
+
model,
|
|
38836
|
+
...history2 && history2.length > 0 ? { history: history2 } : {}
|
|
38781
38837
|
}
|
|
38782
38838
|
};
|
|
38783
38839
|
}
|
|
@@ -38810,12 +38866,66 @@ function emitEvent(event) {
|
|
|
38810
38866
|
|
|
38811
38867
|
// src/cli/runHeadless.ts
|
|
38812
38868
|
init_harness();
|
|
38869
|
+
init_conversationContext();
|
|
38813
38870
|
init_toolRegistry();
|
|
38814
38871
|
init_skills2();
|
|
38815
38872
|
init_envNumber();
|
|
38816
38873
|
init_phaseState();
|
|
38817
38874
|
init_phase();
|
|
38875
|
+
|
|
38876
|
+
// src/cli/utils/streamScrub.ts
|
|
38877
|
+
function createStreamScrubber() {
|
|
38878
|
+
let rawBuf = "";
|
|
38879
|
+
let emittedLen = 0;
|
|
38880
|
+
const snapshot = () => {
|
|
38881
|
+
const cleaned = cleanAgentContent(rawBuf);
|
|
38882
|
+
if (cleaned.length <= emittedLen) return "";
|
|
38883
|
+
const delta = cleaned.slice(emittedLen);
|
|
38884
|
+
emittedLen = cleaned.length;
|
|
38885
|
+
return delta;
|
|
38886
|
+
};
|
|
38887
|
+
return {
|
|
38888
|
+
push(rawDelta) {
|
|
38889
|
+
rawBuf += rawDelta;
|
|
38890
|
+
return snapshot();
|
|
38891
|
+
},
|
|
38892
|
+
flush() {
|
|
38893
|
+
return snapshot();
|
|
38894
|
+
},
|
|
38895
|
+
reset() {
|
|
38896
|
+
rawBuf = "";
|
|
38897
|
+
emittedLen = 0;
|
|
38898
|
+
}
|
|
38899
|
+
};
|
|
38900
|
+
}
|
|
38901
|
+
|
|
38902
|
+
// src/cli/runHeadless.ts
|
|
38818
38903
|
async function runHeadless(opts) {
|
|
38904
|
+
let crashed = false;
|
|
38905
|
+
const handleFatal = (label, err) => {
|
|
38906
|
+
if (crashed) return;
|
|
38907
|
+
crashed = true;
|
|
38908
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
38909
|
+
const stack = err instanceof Error && err.stack ? `
|
|
38910
|
+
${err.stack}` : "";
|
|
38911
|
+
const line = `[zelari-code --headless] FATAL ${label}: ${msg}${stack}`;
|
|
38912
|
+
try {
|
|
38913
|
+
emitEvent({
|
|
38914
|
+
type: "error",
|
|
38915
|
+
severity: "fatal",
|
|
38916
|
+
message: `${label}: ${msg}`,
|
|
38917
|
+
code: "uncaught"
|
|
38918
|
+
});
|
|
38919
|
+
} catch {
|
|
38920
|
+
}
|
|
38921
|
+
try {
|
|
38922
|
+
process.stderr.write(line + "\n");
|
|
38923
|
+
} catch {
|
|
38924
|
+
}
|
|
38925
|
+
process.exit(2);
|
|
38926
|
+
};
|
|
38927
|
+
process.on("uncaughtException", (err) => handleFatal("uncaughtException", err));
|
|
38928
|
+
process.on("unhandledRejection", (err) => handleFatal("unhandledRejection", err));
|
|
38819
38929
|
setPhase(opts.phase ?? "build");
|
|
38820
38930
|
const { provider, model } = resolveHeadlessProvider(opts);
|
|
38821
38931
|
const key = await resolveHeadlessKey(provider);
|
|
@@ -38917,13 +39027,19 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
38917
39027
|
languageDirectiveContent
|
|
38918
39028
|
].join("\n");
|
|
38919
39029
|
}
|
|
39030
|
+
const historySeed = (opts.history ?? []).map(
|
|
39031
|
+
(m) => m.role === "assistant" && m.content ? { ...m, content: cleanAgentContent(m.content, { stripQuestion: false }) } : m
|
|
39032
|
+
);
|
|
39033
|
+
const effectiveTask = maybeAnchorShortAnswer(opts.task) ?? opts.task;
|
|
39034
|
+
const historySeedLen = historySeed.length;
|
|
38920
39035
|
const harness = new AgentHarness({
|
|
38921
39036
|
model,
|
|
38922
39037
|
provider,
|
|
38923
39038
|
sessionId,
|
|
38924
39039
|
messages: [
|
|
38925
39040
|
{ role: "system", content: systemPrompt },
|
|
38926
|
-
|
|
39041
|
+
...historySeed,
|
|
39042
|
+
{ role: "user", content: effectiveTask }
|
|
38927
39043
|
],
|
|
38928
39044
|
tools,
|
|
38929
39045
|
toolRegistry,
|
|
@@ -38936,23 +39052,39 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
38936
39052
|
let finalReason = "completed";
|
|
38937
39053
|
let exitCode = 0;
|
|
38938
39054
|
const textBuffer = [];
|
|
39055
|
+
const scrub = createStreamScrubber();
|
|
38939
39056
|
try {
|
|
38940
39057
|
for await (const event of harness.run()) {
|
|
38941
|
-
if (
|
|
38942
|
-
|
|
39058
|
+
if (event.type === "message_start") {
|
|
39059
|
+
scrub.reset();
|
|
38943
39060
|
}
|
|
38944
|
-
if (event.type === "message_delta") {
|
|
38945
|
-
|
|
38946
|
-
|
|
39061
|
+
if (event.type === "message_delta" && typeof event.delta === "string") {
|
|
39062
|
+
const cleanDelta = scrub.push(event.delta);
|
|
39063
|
+
if (opts.output === "json") {
|
|
39064
|
+
if (cleanDelta.length > 0) {
|
|
39065
|
+
emitEvent({ ...event, delta: cleanDelta });
|
|
39066
|
+
}
|
|
39067
|
+
} else if (opts.output === "plain") {
|
|
39068
|
+
if (cleanDelta.length > 0) process.stdout.write(cleanDelta);
|
|
38947
39069
|
} else {
|
|
38948
|
-
textBuffer.push(
|
|
39070
|
+
if (cleanDelta.length > 0) textBuffer.push(cleanDelta);
|
|
38949
39071
|
}
|
|
38950
|
-
} else
|
|
38951
|
-
|
|
38952
|
-
|
|
38953
|
-
|
|
38954
|
-
if (event.
|
|
38955
|
-
|
|
39072
|
+
} else {
|
|
39073
|
+
if (opts.output === "json") {
|
|
39074
|
+
emitEvent(event);
|
|
39075
|
+
}
|
|
39076
|
+
if (event.type === "agent_end") {
|
|
39077
|
+
const tail = scrub.flush();
|
|
39078
|
+
if (tail.length > 0) {
|
|
39079
|
+
if (opts.output === "plain") process.stdout.write(tail);
|
|
39080
|
+
else textBuffer.push(tail);
|
|
39081
|
+
}
|
|
39082
|
+
finalReason = event.reason;
|
|
39083
|
+
if (event.reason === "error") exitCode = 3;
|
|
39084
|
+
} else if (event.type === "error") {
|
|
39085
|
+
if (event.severity === "fatal") {
|
|
39086
|
+
exitCode = 2;
|
|
39087
|
+
}
|
|
38956
39088
|
}
|
|
38957
39089
|
}
|
|
38958
39090
|
}
|
|
@@ -38967,6 +39099,21 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
38967
39099
|
process.stdout.write(textBuffer.join(""));
|
|
38968
39100
|
}
|
|
38969
39101
|
process.stdout.write("");
|
|
39102
|
+
if (finalReason !== "error" && opts.output === "json") {
|
|
39103
|
+
try {
|
|
39104
|
+
const all = harness.getMessages();
|
|
39105
|
+
const seedLen = 1 + historySeedLen + 1;
|
|
39106
|
+
if (all.length > seedLen) {
|
|
39107
|
+
const tail = all.slice(seedLen).map(
|
|
39108
|
+
(m) => m.role === "assistant" && m.content ? { ...m, content: cleanAgentContent(m.content, { stripQuestion: false }) } : m
|
|
39109
|
+
);
|
|
39110
|
+
if (tail.length > 0) {
|
|
39111
|
+
emitEvent({ type: "history_snapshot", messages: tail });
|
|
39112
|
+
}
|
|
39113
|
+
}
|
|
39114
|
+
} catch {
|
|
39115
|
+
}
|
|
39116
|
+
}
|
|
38970
39117
|
if (finalReason === "error") return 3;
|
|
38971
39118
|
return exitCode;
|
|
38972
39119
|
}
|
|
@@ -38991,6 +39138,7 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
38991
39138
|
const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
|
|
38992
39139
|
const feedbackStore = new FeedbackStore2();
|
|
38993
39140
|
let exitCode = 0;
|
|
39141
|
+
const scrub = createStreamScrubber();
|
|
38994
39142
|
try {
|
|
38995
39143
|
for await (const event of dispatchCouncil2(opts.task, {
|
|
38996
39144
|
apiKey: "REDACTED",
|
|
@@ -39002,14 +39150,25 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
39002
39150
|
feedbackStore,
|
|
39003
39151
|
runMode: planModeFromOpts(opts) ? "design-phase" : "implementation"
|
|
39004
39152
|
})) {
|
|
39005
|
-
if (
|
|
39006
|
-
|
|
39007
|
-
}
|
|
39008
|
-
|
|
39009
|
-
|
|
39010
|
-
|
|
39011
|
-
|
|
39012
|
-
|
|
39153
|
+
if (event.type === "message_start") {
|
|
39154
|
+
scrub.reset();
|
|
39155
|
+
}
|
|
39156
|
+
if (event.type === "message_delta" && typeof event.delta === "string") {
|
|
39157
|
+
const cleanDelta = scrub.push(event.delta);
|
|
39158
|
+
if (opts.output === "json") {
|
|
39159
|
+
if (cleanDelta.length > 0) emitEvent({ ...event, delta: cleanDelta });
|
|
39160
|
+
} else if (opts.output === "plain" && cleanDelta.length > 0) {
|
|
39161
|
+
process.stdout.write(cleanDelta);
|
|
39162
|
+
}
|
|
39163
|
+
} else {
|
|
39164
|
+
if (opts.output === "json") emitEvent(event);
|
|
39165
|
+
if (event.type === "agent_end") {
|
|
39166
|
+
const tail = scrub.flush();
|
|
39167
|
+
if (opts.output === "plain" && tail.length > 0) process.stdout.write(tail);
|
|
39168
|
+
if (event.reason === "error") exitCode = 3;
|
|
39169
|
+
} else if (event.type === "error" && event.severity === "fatal") {
|
|
39170
|
+
exitCode = 2;
|
|
39171
|
+
}
|
|
39013
39172
|
}
|
|
39014
39173
|
}
|
|
39015
39174
|
} catch (err) {
|
|
@@ -39066,6 +39225,7 @@ ${ragContext}` : slicePrompt;
|
|
|
39066
39225
|
let writeCount = 0;
|
|
39067
39226
|
let chairmanErrored = false;
|
|
39068
39227
|
let membersCompleted = 0;
|
|
39228
|
+
const scrub = createStreamScrubber();
|
|
39069
39229
|
for await (const event of dispatchCouncil2(fullPrompt, {
|
|
39070
39230
|
apiKey: "REDACTED",
|
|
39071
39231
|
model,
|
|
@@ -39077,13 +39237,21 @@ ${ragContext}` : slicePrompt;
|
|
|
39077
39237
|
runMode: planModeFromOpts(opts) ? "design-phase" : runMode,
|
|
39078
39238
|
maxToolCallsChairman: chairmanBudget
|
|
39079
39239
|
})) {
|
|
39080
|
-
if (
|
|
39081
|
-
|
|
39082
|
-
} else if (event.type === "message_delta") {
|
|
39083
|
-
process.stdout.write(event.delta);
|
|
39240
|
+
if (event.type === "message_start") {
|
|
39241
|
+
scrub.reset();
|
|
39084
39242
|
}
|
|
39085
39243
|
if (event.type === "message_delta" && typeof event.delta === "string") {
|
|
39086
39244
|
synthesisText += event.delta;
|
|
39245
|
+
const cleanDelta = scrub.push(event.delta);
|
|
39246
|
+
if (opts.output === "json") {
|
|
39247
|
+
if (cleanDelta.length > 0) emitEvent({ ...event, delta: cleanDelta });
|
|
39248
|
+
} else if (opts.output === "plain" && cleanDelta.length > 0) {
|
|
39249
|
+
process.stdout.write(cleanDelta);
|
|
39250
|
+
}
|
|
39251
|
+
} else {
|
|
39252
|
+
if (opts.output === "json") {
|
|
39253
|
+
emitEvent(event);
|
|
39254
|
+
}
|
|
39087
39255
|
}
|
|
39088
39256
|
if (event.type === "tool_execution_end") {
|
|
39089
39257
|
const name = event.toolName ?? event.name ?? "";
|
|
@@ -39396,7 +39564,7 @@ async function runDiscoverModels(providerArg) {
|
|
|
39396
39564
|
|
|
39397
39565
|
// src/cli/skillsMd.ts
|
|
39398
39566
|
init_skills2();
|
|
39399
|
-
import { existsSync as existsSync31, readdirSync as readdirSync4, readFileSync as
|
|
39567
|
+
import { existsSync as existsSync31, readdirSync as readdirSync4, readFileSync as readFileSync26 } from "node:fs";
|
|
39400
39568
|
import { join as join23 } from "node:path";
|
|
39401
39569
|
import { homedir as homedir6 } from "node:os";
|
|
39402
39570
|
var CODING_CATEGORIES = /* @__PURE__ */ new Set([
|
|
@@ -39485,7 +39653,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
39485
39653
|
const skillPath = join23(dir, entry, "SKILL.md");
|
|
39486
39654
|
if (!existsSync31(skillPath)) continue;
|
|
39487
39655
|
try {
|
|
39488
|
-
const parsed = parseSkillMd(
|
|
39656
|
+
const parsed = parseSkillMd(readFileSync26(skillPath, "utf8"), skillPath);
|
|
39489
39657
|
if (!parsed) {
|
|
39490
39658
|
summary.skipped.push({ path: skillPath, reason: "missing/invalid frontmatter (name, description) or empty body" });
|
|
39491
39659
|
continue;
|