zelari-code 1.8.2 → 1.9.2
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 +13 -0
- package/dist/cli/app.js +17 -34
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/components/Sidebar.js +49 -31
- package/dist/cli/components/Sidebar.js.map +1 -1
- package/dist/cli/components/StartupBanner.js +28 -0
- package/dist/cli/components/StartupBanner.js.map +1 -0
- package/dist/cli/components/StatusBar.js +1 -7
- package/dist/cli/components/StatusBar.js.map +1 -1
- package/dist/cli/desktopConfig.js +281 -0
- package/dist/cli/desktopConfig.js.map +1 -0
- package/dist/cli/headless.js +62 -5
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/hooks/chatStats.js +7 -0
- package/dist/cli/hooks/chatStats.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +14 -3
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/main.bundled.js +880 -229
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +132 -5
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/runHeadless.js +184 -44
- package/dist/cli/runHeadless.js.map +1 -1
- package/package.json +5 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -18971,35 +18971,111 @@ function normalizeTextToolArgs(name, args) {
|
|
|
18971
18971
|
}
|
|
18972
18972
|
function parseTextToolCalls(text) {
|
|
18973
18973
|
const m = /---TOOLS---\s*([\s\S]*?)---END---/.exec(text);
|
|
18974
|
-
if (
|
|
18975
|
-
|
|
18976
|
-
|
|
18977
|
-
|
|
18978
|
-
const candidates = [body];
|
|
18979
|
-
if (/\]\s*\[/.test(body)) {
|
|
18980
|
-
candidates.push(body.replace(/\]\s*\[/g, ","));
|
|
18981
|
-
}
|
|
18982
|
-
if (body.includes('\\"')) {
|
|
18983
|
-
candidates.push(body.replace(/\\"/g, '"'));
|
|
18974
|
+
if (m?.[1]) {
|
|
18975
|
+
let body = m[1].trim();
|
|
18976
|
+
body = body.replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/i, "").trim();
|
|
18977
|
+
const candidates = [body];
|
|
18984
18978
|
if (/\]\s*\[/.test(body)) {
|
|
18985
|
-
candidates.push(body.replace(
|
|
18979
|
+
candidates.push(body.replace(/\]\s*\[/g, ","));
|
|
18980
|
+
}
|
|
18981
|
+
if (body.includes('\\"')) {
|
|
18982
|
+
candidates.push(body.replace(/\\"/g, '"'));
|
|
18983
|
+
if (/\]\s*\[/.test(body)) {
|
|
18984
|
+
candidates.push(body.replace(/\\"/g, '"').replace(/\]\s*\[/g, ","));
|
|
18985
|
+
}
|
|
18986
|
+
}
|
|
18987
|
+
for (const cand of candidates) {
|
|
18988
|
+
const items = tryParseToolArray(cand);
|
|
18989
|
+
if (items.length > 0)
|
|
18990
|
+
return items;
|
|
18991
|
+
}
|
|
18992
|
+
const arrays = extractJsonArrays(body);
|
|
18993
|
+
if (arrays.length > 1) {
|
|
18994
|
+
const merged = [];
|
|
18995
|
+
for (const a of arrays) {
|
|
18996
|
+
merged.push(...tryParseToolArray(a));
|
|
18997
|
+
}
|
|
18998
|
+
if (merged.length > 0)
|
|
18999
|
+
return merged;
|
|
19000
|
+
}
|
|
19001
|
+
const objs = extractToolObjects(body);
|
|
19002
|
+
if (objs.length > 0)
|
|
19003
|
+
return objs;
|
|
19004
|
+
}
|
|
19005
|
+
const mini = parseMinimaxStyleToolCalls(text);
|
|
19006
|
+
if (mini.length > 0)
|
|
19007
|
+
return mini;
|
|
19008
|
+
return [];
|
|
19009
|
+
}
|
|
19010
|
+
function parseMinimaxStyleToolCalls(text) {
|
|
19011
|
+
const out = [];
|
|
19012
|
+
const normalized = text.replace(/\]\s*<\s*\]\s*minimax\s*\[\s*>\s*\[</gi, "<minimax:").replace(/\]\s*<\s*\]\s*minimax\s*\[\s*>/gi, "<minimax:").replace(/minimax\s*\[\s*>\s*\[</gi, "minimax:").replace(/\]\s*</g, "<");
|
|
19013
|
+
const blockRe = /<(?:minimax:)?tool_call[^>]*>([\s\S]*?)<\/(?:minimax:)?tool_call>|<invoke\s+name=["']([^"']+)["'][^>]*>([\s\S]*?)(?:<\/invoke>|(?=<invoke\s+name=)|$)/gi;
|
|
19014
|
+
let match;
|
|
19015
|
+
while ((match = blockRe.exec(normalized)) !== null) {
|
|
19016
|
+
if (match[2]) {
|
|
19017
|
+
out.push({ name: match[2], args: parseLooseArgs(match[3] ?? "") });
|
|
19018
|
+
} else if (match[1]) {
|
|
19019
|
+
const inner = match[1];
|
|
19020
|
+
const inv = /invoke\s+name=["']([^"']+)["']/i.exec(inner);
|
|
19021
|
+
if (inv) {
|
|
19022
|
+
out.push({ name: inv[1], args: parseLooseArgs(inner) });
|
|
19023
|
+
} else {
|
|
19024
|
+
const jsonish = tryParseToolArray(inner.trim());
|
|
19025
|
+
if (jsonish.length)
|
|
19026
|
+
out.push(...jsonish);
|
|
19027
|
+
else {
|
|
19028
|
+
const objs = extractToolObjects(inner);
|
|
19029
|
+
if (objs.length)
|
|
19030
|
+
out.push(...objs);
|
|
19031
|
+
}
|
|
19032
|
+
}
|
|
19033
|
+
}
|
|
19034
|
+
}
|
|
19035
|
+
if (out.length === 0) {
|
|
19036
|
+
const loose = /invoke\s+name=["']([^"']+)["']([\s\S]*?)(?=invoke\s+name=|$)/gi;
|
|
19037
|
+
let lm;
|
|
19038
|
+
while ((lm = loose.exec(normalized)) !== null) {
|
|
19039
|
+
const name = lm[1];
|
|
19040
|
+
const args = parseLooseArgs(lm[2] ?? "");
|
|
19041
|
+
if (name)
|
|
19042
|
+
out.push({ name, args });
|
|
18986
19043
|
}
|
|
18987
19044
|
}
|
|
18988
|
-
|
|
18989
|
-
|
|
18990
|
-
|
|
18991
|
-
|
|
19045
|
+
return out;
|
|
19046
|
+
}
|
|
19047
|
+
function parseLooseArgs(body) {
|
|
19048
|
+
const args = {};
|
|
19049
|
+
const paramTag = /(?:parameter\s+name=|<\s*)["']?([a-zA-Z_][\w]*)["']?\s*(?:>|=\s*["']?)([^<\]\n]+)/gi;
|
|
19050
|
+
let m;
|
|
19051
|
+
while ((m = paramTag.exec(body)) !== null) {
|
|
19052
|
+
const key = m[1];
|
|
19053
|
+
if (key === "invoke" || key === "minimax" || key === "tool_call")
|
|
19054
|
+
continue;
|
|
19055
|
+
args[key] = m[2].replace(/^["']|["']$/g, "").trim();
|
|
19056
|
+
}
|
|
19057
|
+
const lineRe = /(?:^|[\s\[>])([a-zA-Z_][\w]*)\s*[>:=]\s*([^\n<\]]+)/g;
|
|
19058
|
+
while ((m = lineRe.exec(body)) !== null) {
|
|
19059
|
+
const key = m[1];
|
|
19060
|
+
if (args[key] !== void 0)
|
|
19061
|
+
continue;
|
|
19062
|
+
if (["invoke", "name", "minimax", "tool_call", "parameter"].includes(key))
|
|
19063
|
+
continue;
|
|
19064
|
+
args[key] = m[2].replace(/^["']|["']$/g, "").trim();
|
|
18992
19065
|
}
|
|
18993
|
-
|
|
18994
|
-
|
|
18995
|
-
|
|
18996
|
-
|
|
18997
|
-
|
|
19066
|
+
if (Object.keys(args).length === 0) {
|
|
19067
|
+
const brace = body.indexOf("{");
|
|
19068
|
+
if (brace >= 0) {
|
|
19069
|
+
try {
|
|
19070
|
+
const parsed = JSON.parse(body.slice(brace));
|
|
19071
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
19072
|
+
return parsed;
|
|
19073
|
+
}
|
|
19074
|
+
} catch {
|
|
19075
|
+
}
|
|
18998
19076
|
}
|
|
18999
|
-
if (merged.length > 0)
|
|
19000
|
-
return merged;
|
|
19001
19077
|
}
|
|
19002
|
-
return
|
|
19078
|
+
return args;
|
|
19003
19079
|
}
|
|
19004
19080
|
function tryParseToolArray(raw) {
|
|
19005
19081
|
let parsed;
|
|
@@ -19105,6 +19181,7 @@ var init_AgentHarness = __esm({
|
|
|
19105
19181
|
sessionId;
|
|
19106
19182
|
maxQueuedIterations;
|
|
19107
19183
|
maxToolLoopIterations;
|
|
19184
|
+
maxToolLoopHardCap;
|
|
19108
19185
|
cancelled = false;
|
|
19109
19186
|
activeController = null;
|
|
19110
19187
|
queue = [];
|
|
@@ -19130,6 +19207,9 @@ var init_AgentHarness = __esm({
|
|
|
19130
19207
|
this.sessionId = config2.sessionId ?? crypto.randomUUID();
|
|
19131
19208
|
this.maxQueuedIterations = config2.maxQueuedIterations ?? 3;
|
|
19132
19209
|
this.maxToolLoopIterations = config2.maxToolLoopIterations ?? 30;
|
|
19210
|
+
const soft = this.maxToolLoopIterations;
|
|
19211
|
+
const hardCfg = config2.maxToolLoopHardCap;
|
|
19212
|
+
this.maxToolLoopHardCap = typeof hardCfg === "number" && hardCfg > 0 ? Math.max(soft, hardCfg) : Math.max(soft * 3, soft + 60);
|
|
19133
19213
|
}
|
|
19134
19214
|
/**
|
|
19135
19215
|
* Snapshot of the live transcript (`this.config.messages`) as mutated
|
|
@@ -19406,7 +19486,11 @@ ${shared2.content}`,
|
|
|
19406
19486
|
this.emit(initialMsgEnd);
|
|
19407
19487
|
yield initialMsgEnd;
|
|
19408
19488
|
let toolLoopTurns = 0;
|
|
19409
|
-
|
|
19489
|
+
let softCap = this.maxToolLoopIterations;
|
|
19490
|
+
const hardCap = this.maxToolLoopHardCap;
|
|
19491
|
+
let extensions = 0;
|
|
19492
|
+
const maxExtensions = 8;
|
|
19493
|
+
while (!this.cancelled && !hadError && toolLoopTurns < softCap && initialFinishRef.value === "tool_calls") {
|
|
19410
19494
|
toolLoopTurns++;
|
|
19411
19495
|
const turnMessageId = crypto.randomUUID();
|
|
19412
19496
|
const msgStart = createBrainEvent("message_start", this.sessionId, { messageId: turnMessageId, role: "assistant", ...this.memberFields() });
|
|
@@ -19437,9 +19521,25 @@ ${shared2.content}`,
|
|
|
19437
19521
|
initialFinishRef.value = turnFinishRef.value;
|
|
19438
19522
|
if (hadError || this.cancelled)
|
|
19439
19523
|
break;
|
|
19524
|
+
if (initialFinishRef.value === "tool_calls" && toolLoopTurns >= softCap && toolLoopTurns < hardCap && extensions < maxExtensions) {
|
|
19525
|
+
extensions++;
|
|
19526
|
+
const chunk = this.maxToolLoopIterations;
|
|
19527
|
+
softCap = Math.min(hardCap, softCap + chunk);
|
|
19528
|
+
this.config.messages.push({
|
|
19529
|
+
role: "user",
|
|
19530
|
+
content: `[system] Soft tool budget reached (${toolLoopTurns}/${hardCap} hard). Work may be incomplete \u2014 CONTINUE with tools as needed to finish remaining steps. Prefer concrete progress over summarizing. Do not apologize for budgets.`
|
|
19531
|
+
});
|
|
19532
|
+
const note = createBrainEvent("error", this.sessionId, {
|
|
19533
|
+
severity: "recoverable",
|
|
19534
|
+
message: `Tool budget extended (${toolLoopTurns}\u2192${softCap}, hard ${hardCap}) to allow completion.`,
|
|
19535
|
+
code: "tool_budget_extended"
|
|
19536
|
+
});
|
|
19537
|
+
this.emit(note);
|
|
19538
|
+
yield note;
|
|
19539
|
+
}
|
|
19440
19540
|
}
|
|
19441
|
-
const
|
|
19442
|
-
if (!this.cancelled && !hadError && initialFinishRef.value === "tool_calls" &&
|
|
19541
|
+
const hitHardCap = toolLoopTurns >= hardCap || toolLoopTurns >= softCap && softCap >= hardCap;
|
|
19542
|
+
if (!this.cancelled && !hadError && initialFinishRef.value === "tool_calls" && hitHardCap) {
|
|
19443
19543
|
yield* this.runFinalAnswerTurn();
|
|
19444
19544
|
}
|
|
19445
19545
|
let turns = 0;
|
|
@@ -19603,13 +19703,14 @@ ${cached2}`
|
|
|
19603
19703
|
pendingNativeTools.length = 0;
|
|
19604
19704
|
}
|
|
19605
19705
|
const textTools = parseTextToolCalls(turnText);
|
|
19606
|
-
const
|
|
19607
|
-
|
|
19608
|
-
|
|
19609
|
-
|
|
19706
|
+
const toolsToRun = textTools.filter((tt) => {
|
|
19707
|
+
const key = hashToolCall(tt.name, tt.args);
|
|
19708
|
+
return !turnToolCalls.some((n) => hashToolCall(n.name, n.args) === key);
|
|
19709
|
+
});
|
|
19710
|
+
if ((/---TOOLS---/.test(turnText) || /minimax|invoke\s+name=/i.test(turnText)) && textTools.length === 0) {
|
|
19610
19711
|
const parseErr = createBrainEvent("error", this.sessionId, {
|
|
19611
19712
|
severity: "recoverable",
|
|
19612
|
-
message: "Found
|
|
19713
|
+
message: "Found text-format tool block but parse failed; tool calls were not executed. Prefer native tool_call, or ---TOOLS--- with ONE valid JSON array.",
|
|
19613
19714
|
code: "text_tools_parse_failed"
|
|
19614
19715
|
});
|
|
19615
19716
|
this.emit(parseErr);
|
|
@@ -19741,7 +19842,7 @@ ${cached2}`
|
|
|
19741
19842
|
yield msgStart;
|
|
19742
19843
|
this.config.messages.push({
|
|
19743
19844
|
role: "user",
|
|
19744
|
-
content: "[system]
|
|
19845
|
+
content: "[system] Hard tool-iteration ceiling reached. Stop calling tools and give a clear status: what is DONE, what remains, and the exact next steps. Use what you already gathered. Do not apologize for the tools."
|
|
19745
19846
|
});
|
|
19746
19847
|
let totalLength = 0;
|
|
19747
19848
|
const finishRef = { value: "stop" };
|
|
@@ -19940,6 +20041,7 @@ __export(harness_exports, {
|
|
|
19940
20041
|
SessionJsonlWriter: () => SessionJsonlWriter,
|
|
19941
20042
|
hashToolCall: () => hashToolCall,
|
|
19942
20043
|
normalizeTextToolArgs: () => normalizeTextToolArgs,
|
|
20044
|
+
parseMinimaxStyleToolCalls: () => parseMinimaxStyleToolCalls,
|
|
19943
20045
|
parseTextToolCalls: () => parseTextToolCalls,
|
|
19944
20046
|
readSession: () => readSession,
|
|
19945
20047
|
wrapLegacyStream: () => wrapLegacyStream
|
|
@@ -30652,12 +30754,12 @@ var init_fixPath = __esm({
|
|
|
30652
30754
|
});
|
|
30653
30755
|
|
|
30654
30756
|
// src/cli/main.ts
|
|
30655
|
-
import
|
|
30757
|
+
import React15 from "react";
|
|
30656
30758
|
import { render } from "ink";
|
|
30657
30759
|
|
|
30658
30760
|
// src/cli/app.tsx
|
|
30659
|
-
import
|
|
30660
|
-
import { Box as
|
|
30761
|
+
import React10, { useState as useState8, useMemo, useCallback as useCallback5, useEffect as useEffect7 } from "react";
|
|
30762
|
+
import { Box as Box9, Static, useInput as useInput2, useStdin as useStdin2 } from "ink";
|
|
30661
30763
|
|
|
30662
30764
|
// src/cli/components/InputBar.tsx
|
|
30663
30765
|
import React from "react";
|
|
@@ -31171,8 +31273,7 @@ function StatusBar({
|
|
|
31171
31273
|
costUsd = 0,
|
|
31172
31274
|
cachedTokens = 0,
|
|
31173
31275
|
contextUsed = 0,
|
|
31174
|
-
contextLimit = 0
|
|
31175
|
-
brandVersion
|
|
31276
|
+
contextLimit = 0
|
|
31176
31277
|
}) {
|
|
31177
31278
|
const ctxLabel = contextLimit > 0 ? `${formatTokens(contextUsed)}/${formatTokens(contextLimit)}` : contextUsed > 0 ? formatTokens(contextUsed) : null;
|
|
31178
31279
|
return /* @__PURE__ */ React6.createElement(Box5, { paddingX: 1, width: "100%", justifyContent: "space-between", gap: 2 }, /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 2 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, /* @__PURE__ */ React6.createElement(Text6, { color: sessionActive ? "green" : "gray" }, sessionActive ? "\u25CF" : "\u25CB"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: phase2 === "plan" ? "yellow" : "green" }, phase2 === "plan" ? "\u25C7 plan" : "\u25C6 build"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(
|
|
@@ -31182,7 +31283,7 @@ function StatusBar({
|
|
|
31182
31283
|
color: mode === "council" ? "magenta" : mode === "zelari" ? "green" : "cyan"
|
|
31183
31284
|
},
|
|
31184
31285
|
mode === "council" ? "council" : mode === "zelari" ? "zelari" : "agent"
|
|
31185
|
-
), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, provider), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, null, model), cwd ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, cwd)) : null)), /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 1 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, busy && elapsedMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Spinner, { color: "yellow" }), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, " ", formatDuration(elapsedMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : lastMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "last ", formatDuration(lastMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, queueCount > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, "queue ", queueCount), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, ctxLabel ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan" }, ctxLabel), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, costUsd > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, formatCost(costUsd)), cachedTokens > 0 ? /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (", formatTokens(cachedTokens), " cached)") : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null,
|
|
31286
|
+
), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, provider), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, null, model), cwd ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, cwd)) : null)), /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 1 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, busy && elapsedMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Spinner, { color: "yellow" }), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, " ", formatDuration(elapsedMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : lastMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "last ", formatDuration(lastMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, queueCount > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, "queue ", queueCount), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, ctxLabel ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan" }, ctxLabel), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, costUsd > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, formatCost(costUsd)), cachedTokens > 0 ? /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (", formatTokens(cachedTokens), " cached)") : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "session ", sessionId))));
|
|
31186
31287
|
}
|
|
31187
31288
|
|
|
31188
31289
|
// src/cli/components/SelectList.tsx
|
|
@@ -31230,14 +31331,47 @@ function SelectList({
|
|
|
31230
31331
|
// src/cli/components/Sidebar.tsx
|
|
31231
31332
|
import React8 from "react";
|
|
31232
31333
|
import { Box as Box7, Text as Text8 } from "ink";
|
|
31334
|
+
|
|
31335
|
+
// src/cli/components/brandArt.ts
|
|
31336
|
+
var BRAND_LOGO_ASCII = [
|
|
31337
|
+
" -#%=",
|
|
31338
|
+
" +%%%%#.",
|
|
31339
|
+
" :#%%%%%%%-",
|
|
31340
|
+
":%%@@@@@@@@=",
|
|
31341
|
+
"-%@@@@@@@@@@@+",
|
|
31342
|
+
":%@@@@@@%@@@@@@=",
|
|
31343
|
+
"-%%@@@@@.+%@@%@+",
|
|
31344
|
+
" -@@@@@@:%++%@=",
|
|
31345
|
+
"=*%@@@@@@:@@%=*@#+.",
|
|
31346
|
+
"%%%%%@@@@:+++-*%@@*",
|
|
31347
|
+
".%%%%%@@@@@+%+=:%@@@@:",
|
|
31348
|
+
"*@@@@@@@@@@@@@%@@@@@@*"
|
|
31349
|
+
].join("\n");
|
|
31350
|
+
var BRAND_LOGO_COMPACT = [
|
|
31351
|
+
" -#%=",
|
|
31352
|
+
" +%%%%#.",
|
|
31353
|
+
":%%@@@@=",
|
|
31354
|
+
"*@@@@@@*"
|
|
31355
|
+
].join("\n");
|
|
31356
|
+
|
|
31357
|
+
// src/cli/components/Sidebar.tsx
|
|
31358
|
+
var EMBLEM_BRAILLE = `\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2880\u28F4\u28FF\u28F7\u28C6\u2840
|
|
31359
|
+
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2880\u28F6\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28E6\u2840
|
|
31360
|
+
\u2800\u2800\u2800\u2800\u2800\u2800\u28F0\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28E6
|
|
31361
|
+
\u2800\u2800\u2800\u2800\u28A0\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28F7\u2844
|
|
31362
|
+
\u2800\u2800\u2800\u2800\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u2819\u283B\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u2806
|
|
31363
|
+
\u2800\u2800\u2800\u2800\u28C8\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u2800\u28F7\u28EC\u285B\u28BF\u28FF\u28DF\u28C1
|
|
31364
|
+
\u2800\u2880\u28F4\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u2800\u287F\u28BF\u287F\u2883\u28C8\u28FB\u28FF\u28FF\u28F6
|
|
31365
|
+
\u2800\u28FC\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28E0\u28F4\u28C6\u283B\u280E\u28BF\u28FF\u28FF\u28FF\u28FF\u28E7
|
|
31366
|
+
\u28F0\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u2847`;
|
|
31233
31367
|
var SIDEBAR_WIDTH = 28;
|
|
31234
31368
|
var SIDEBAR_MIN_COLUMNS = 96;
|
|
31235
31369
|
var SIDEBAR_HIDE_COLUMNS = 88;
|
|
31236
31370
|
var SIDEBAR_MIN_ROWS = 16;
|
|
31237
31371
|
var SIDEBAR_HIDE_ROWS = 14;
|
|
31238
|
-
var
|
|
31239
|
-
var
|
|
31240
|
-
var
|
|
31372
|
+
var BRAILLE_MIN_ROWS = 28;
|
|
31373
|
+
var MAX_FILES_SHORT = 6;
|
|
31374
|
+
var MAX_FILES_TALL = 10;
|
|
31241
31375
|
function shouldShowSidebar(columns, rows) {
|
|
31242
31376
|
return columns >= SIDEBAR_MIN_COLUMNS && rows >= SIDEBAR_MIN_ROWS;
|
|
31243
31377
|
}
|
|
@@ -31247,18 +31381,19 @@ function sidebarVisibility(columns, rows, currentlyVisible) {
|
|
|
31247
31381
|
}
|
|
31248
31382
|
return shouldShowSidebar(columns, rows);
|
|
31249
31383
|
}
|
|
31250
|
-
function maxSidebarFiles(rows) {
|
|
31251
|
-
const budget = Math.max(2, rows - 14 - SIDEBAR_CHROME_LINES);
|
|
31252
|
-
const cap = rows >= 28 ? MAX_FILES_TALL : MAX_FILES_SHORT;
|
|
31253
|
-
return Math.min(cap, budget);
|
|
31254
|
-
}
|
|
31255
31384
|
function truncatePath(p3, max) {
|
|
31256
31385
|
if (p3.length <= max) return p3;
|
|
31257
31386
|
return `\u2026${p3.slice(-(max - 1))}`;
|
|
31258
31387
|
}
|
|
31388
|
+
function preferAsciiLogo() {
|
|
31389
|
+
if (process.env.ZELARI_ASCII_LOGO === "1") return true;
|
|
31390
|
+
if (process.env.ZELARI_ASCII_LOGO === "0") return false;
|
|
31391
|
+
return process.platform === "win32";
|
|
31392
|
+
}
|
|
31259
31393
|
function Sidebar({ version: version2, changes, rows }) {
|
|
31260
|
-
|
|
31261
|
-
const
|
|
31394
|
+
const useBraille = !preferAsciiLogo() && rows >= BRAILLE_MIN_ROWS;
|
|
31395
|
+
const logoLines = useBraille ? EMBLEM_BRAILLE.split("\n") : BRAND_LOGO_COMPACT.split("\n");
|
|
31396
|
+
const maxFiles = rows >= BRAILLE_MIN_ROWS + 8 ? MAX_FILES_TALL : MAX_FILES_SHORT;
|
|
31262
31397
|
const visible = changes.files.slice(0, maxFiles);
|
|
31263
31398
|
const hidden = changes.files.length - visible.length;
|
|
31264
31399
|
const innerWidth = SIDEBAR_WIDTH - 4;
|
|
@@ -31270,65 +31405,42 @@ function Sidebar({ version: version2, changes, rows }) {
|
|
|
31270
31405
|
borderStyle: "single",
|
|
31271
31406
|
borderColor: "gray",
|
|
31272
31407
|
paddingX: 1,
|
|
31273
|
-
flexShrink: 0
|
|
31274
|
-
height: Math.min(rows - 8, SIDEBAR_CHROME_LINES + maxFiles + 2),
|
|
31275
|
-
overflow: "hidden"
|
|
31408
|
+
flexShrink: 0
|
|
31276
31409
|
},
|
|
31277
|
-
/* @__PURE__ */ React8.createElement(Box7, {
|
|
31410
|
+
/* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", alignItems: "center" }, logoLines.map((line, i) => /* @__PURE__ */ React8.createElement(Text8, { key: i, color: "cyan" }, line))),
|
|
31411
|
+
/* @__PURE__ */ React8.createElement(Box7, { justifyContent: "center" }, /* @__PURE__ */ React8.createElement(Text8, { bold: true, color: "white" }, "ZELARI CODE")),
|
|
31412
|
+
/* @__PURE__ */ React8.createElement(Box7, { justifyContent: "center" }, /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "v", version2, changes.branch ? ` \xB7 ${truncatePath(changes.branch, 12)}` : "")),
|
|
31278
31413
|
/* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "\u2500".repeat(innerWidth)),
|
|
31279
31414
|
!changes.isRepo ? /* @__PURE__ */ React8.createElement(Text8, { dimColor: true, italic: true }, "not a git repo") : changes.files.length === 0 ? /* @__PURE__ */ React8.createElement(Text8, { dimColor: true, italic: true }, "no changes") : /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "changes (", changes.files.length, ")"), visible.map((f) => /* @__PURE__ */ React8.createElement(FileRow, { key: f.path, file: f, pathWidth: innerWidth - 10 })), hidden > 0 && /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, " +", hidden, " more\u2026"))
|
|
31280
31415
|
);
|
|
31281
31416
|
}
|
|
31282
|
-
function FileRow({
|
|
31417
|
+
function FileRow({
|
|
31418
|
+
file: file2,
|
|
31419
|
+
pathWidth
|
|
31420
|
+
}) {
|
|
31283
31421
|
const name = truncatePath(file2.path, Math.max(6, pathWidth));
|
|
31284
31422
|
return /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text8, { wrap: "truncate" }, /* @__PURE__ */ React8.createElement(Text8, { color: file2.untracked ? "yellow" : "white" }, name), file2.untracked ? /* @__PURE__ */ React8.createElement(Text8, { color: "yellow" }, " new") : /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text8, { color: "green" }, " +", file2.added ?? "\xB7"), /* @__PURE__ */ React8.createElement(Text8, { color: "red" }, " -", file2.removed ?? "\xB7"))));
|
|
31285
31423
|
}
|
|
31286
31424
|
|
|
31287
|
-
// src/cli/components/
|
|
31288
|
-
|
|
31289
|
-
|
|
31290
|
-
|
|
31291
|
-
|
|
31292
|
-
|
|
31293
|
-
|
|
31294
|
-
|
|
31295
|
-
|
|
31296
|
-
|
|
31297
|
-
|
|
31298
|
-
|
|
31299
|
-
"
|
|
31300
|
-
|
|
31301
|
-
|
|
31302
|
-
|
|
31303
|
-
|
|
31304
|
-
|
|
31305
|
-
"
|
|
31306
|
-
"*@@@@@@*"
|
|
31307
|
-
].join("\n");
|
|
31308
|
-
function formatBannerWithLogoRight(opts) {
|
|
31309
|
-
const logoSrc = opts.compact ? BRAND_LOGO_COMPACT : BRAND_LOGO_ASCII;
|
|
31310
|
-
const logoLines = logoSrc.split("\n");
|
|
31311
|
-
const logoWidth = Math.max(...logoLines.map((l) => l.length));
|
|
31312
|
-
const cols = Math.max(logoWidth + 20, Math.min(opts.columns, 120));
|
|
31313
|
-
const left = [...opts.leftLines];
|
|
31314
|
-
const wordmark = `ZELARI CODE v${opts.version}`;
|
|
31315
|
-
const rightExtra = [wordmark];
|
|
31316
|
-
const rightBlock = [...logoLines, ...rightExtra];
|
|
31317
|
-
const rows = Math.max(left.length, rightBlock.length);
|
|
31318
|
-
const out = [];
|
|
31319
|
-
for (let i = 0; i < rows; i++) {
|
|
31320
|
-
const L = left[i] ?? "";
|
|
31321
|
-
const R = rightBlock[i] ?? "";
|
|
31322
|
-
if (!R) {
|
|
31323
|
-
out.push(L);
|
|
31324
|
-
continue;
|
|
31325
|
-
}
|
|
31326
|
-
const maxLeft = Math.max(0, cols - R.length - 2);
|
|
31327
|
-
const leftClipped = L.length > maxLeft ? L.slice(0, Math.max(0, maxLeft - 1)) + "\u2026" : L;
|
|
31328
|
-
const pad = Math.max(2, cols - leftClipped.length - R.length);
|
|
31329
|
-
out.push(leftClipped + " ".repeat(pad) + R);
|
|
31330
|
-
}
|
|
31331
|
-
return out.join("\n");
|
|
31425
|
+
// src/cli/components/StartupBanner.tsx
|
|
31426
|
+
import React9 from "react";
|
|
31427
|
+
import { Box as Box8, Text as Text9 } from "ink";
|
|
31428
|
+
function StartupBanner({
|
|
31429
|
+
version: version2,
|
|
31430
|
+
providerId,
|
|
31431
|
+
model,
|
|
31432
|
+
cwd,
|
|
31433
|
+
columns,
|
|
31434
|
+
rows
|
|
31435
|
+
}) {
|
|
31436
|
+
const compact = columns < 72 || rows < 20;
|
|
31437
|
+
const logo = (compact ? BRAND_LOGO_COMPACT : BRAND_LOGO_ASCII).split("\n");
|
|
31438
|
+
const leftLines = [
|
|
31439
|
+
`zelari-code v${version2} \u2014 ${providerId}/${model}`,
|
|
31440
|
+
`cwd: ${cwd}`,
|
|
31441
|
+
`/help \xB7 /plan \xB7 /build \xB7 /view-plan \xB7 shift+tab mode`
|
|
31442
|
+
];
|
|
31443
|
+
return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "row", justifyContent: "space-between", marginBottom: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", flexGrow: 1, marginRight: 2 }, leftLines.map((line, i) => /* @__PURE__ */ React9.createElement(Text9, { key: i, color: i === 0 ? "cyan" : void 0, dimColor: i > 0 }, line))), /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", flexShrink: 0, alignItems: "flex-end" }, logo.map((line, i) => /* @__PURE__ */ React9.createElement(Text9, { key: i, color: "cyan" }, line)), /* @__PURE__ */ React9.createElement(Text9, { bold: true, color: "white" }, "ZELARI CODE"), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "v", version2)));
|
|
31332
31444
|
}
|
|
31333
31445
|
|
|
31334
31446
|
// src/cli/modelDiscovery.ts
|
|
@@ -34315,10 +34427,12 @@ function computeSessionStatsDelta(realUsage, userText, assistantContent, model,
|
|
|
34315
34427
|
const completionTokens = realUsage ? realUsage.completionTokens : Math.ceil(assistantContent.length / 4);
|
|
34316
34428
|
const cachedPromptTokens = realUsage?.cachedPromptTokens ?? 0;
|
|
34317
34429
|
const turnCost = calculateCost(model, promptTokens, completionTokens, cachedPromptTokens);
|
|
34430
|
+
const contextTokens = realUsage ? realUsage.totalTokens || promptTokens + completionTokens : promptTokens + completionTokens;
|
|
34318
34431
|
return {
|
|
34319
34432
|
totalTokens: prev2.totalTokens + promptTokens + completionTokens,
|
|
34320
34433
|
totalCostUsd: prev2.totalCostUsd + turnCost,
|
|
34321
|
-
cachedTokens: (prev2.cachedTokens ?? 0) + cachedPromptTokens
|
|
34434
|
+
cachedTokens: (prev2.cachedTokens ?? 0) + cachedPromptTokens,
|
|
34435
|
+
contextTokens
|
|
34322
34436
|
};
|
|
34323
34437
|
}
|
|
34324
34438
|
|
|
@@ -34604,6 +34718,11 @@ function useChatTurn(params) {
|
|
|
34604
34718
|
min: 1
|
|
34605
34719
|
});
|
|
34606
34720
|
const maxToolLoopIterations = budget.maxToolLoopIterations;
|
|
34721
|
+
const maxToolLoopHardCap = envNumber(process.env.ZELARI_MAX_TOOL_LOOP_HARD, {
|
|
34722
|
+
default: 0,
|
|
34723
|
+
// 0 → harness default (soft×3, min soft+60)
|
|
34724
|
+
min: 0
|
|
34725
|
+
});
|
|
34607
34726
|
const harness2 = new AgentHarness({
|
|
34608
34727
|
model: envConfig.model,
|
|
34609
34728
|
provider: "openai-compatible",
|
|
@@ -34624,7 +34743,8 @@ function useChatTurn(params) {
|
|
|
34624
34743
|
providerStream,
|
|
34625
34744
|
cwd,
|
|
34626
34745
|
maxToolCallsPerTurn,
|
|
34627
|
-
maxToolLoopIterations
|
|
34746
|
+
maxToolLoopIterations,
|
|
34747
|
+
...maxToolLoopHardCap > 0 ? { maxToolLoopHardCap } : {}
|
|
34628
34748
|
});
|
|
34629
34749
|
harnessRef.current = harness2;
|
|
34630
34750
|
setQueueCount(harness2.queueLength);
|
|
@@ -34699,7 +34819,15 @@ function useChatTurn(params) {
|
|
|
34699
34819
|
}
|
|
34700
34820
|
} else if (event.type === "error") {
|
|
34701
34821
|
flushStreaming();
|
|
34702
|
-
|
|
34822
|
+
if (event.code === "tool_budget_extended") {
|
|
34823
|
+
appendSystem(
|
|
34824
|
+
setMessages,
|
|
34825
|
+
`[budget] ${event.message}`,
|
|
34826
|
+
Date.now()
|
|
34827
|
+
);
|
|
34828
|
+
} else {
|
|
34829
|
+
appendSystem(setMessages, `[error] ${event.message}`, Date.now());
|
|
34830
|
+
}
|
|
34703
34831
|
} else if (event.type === "tool_execution_start") {
|
|
34704
34832
|
toolNameById.set(event.toolCallId, event.toolName);
|
|
34705
34833
|
flushStreaming();
|
|
@@ -36193,6 +36321,10 @@ function nextMode(current) {
|
|
|
36193
36321
|
const i = MODES.indexOf(current);
|
|
36194
36322
|
return MODES[(i + 1) % MODES.length] ?? "agent";
|
|
36195
36323
|
}
|
|
36324
|
+
function parseMode(input) {
|
|
36325
|
+
const v = input.trim().toLowerCase();
|
|
36326
|
+
return MODES.includes(v) ? v : null;
|
|
36327
|
+
}
|
|
36196
36328
|
function describeMode(mode) {
|
|
36197
36329
|
switch (mode) {
|
|
36198
36330
|
case "council":
|
|
@@ -37841,7 +37973,12 @@ function App() {
|
|
|
37841
37973
|
const [input, setInput] = useState8("");
|
|
37842
37974
|
const [busy, setBusy] = useState8(false);
|
|
37843
37975
|
const [providerConfig, setProviderConfig] = useState8(() => getProviderConfig());
|
|
37844
|
-
const [sessionStats, setSessionStats] = useState8({
|
|
37976
|
+
const [sessionStats, setSessionStats] = useState8({
|
|
37977
|
+
totalTokens: 0,
|
|
37978
|
+
totalCostUsd: 0,
|
|
37979
|
+
cachedTokens: 0,
|
|
37980
|
+
contextTokens: 0
|
|
37981
|
+
});
|
|
37845
37982
|
const [clearEpoch, setClearEpoch] = useState8(0);
|
|
37846
37983
|
const [mode, setMode] = useState8("agent");
|
|
37847
37984
|
const [phase2, setPhaseUi] = useState8("build");
|
|
@@ -37942,89 +38079,73 @@ function App() {
|
|
|
37942
38079
|
}
|
|
37943
38080
|
setPicker(null);
|
|
37944
38081
|
}, [picker]);
|
|
37945
|
-
const bannerColsRef = useRef6(null);
|
|
37946
|
-
if (bannerColsRef.current === null) {
|
|
37947
|
-
bannerColsRef.current = size.columns > 0 ? size.columns : 80;
|
|
37948
|
-
}
|
|
37949
38082
|
const banner = useMemo(() => {
|
|
37950
|
-
const cols = bannerColsRef.current ?? 80;
|
|
37951
|
-
const content = formatBannerWithLogoRight({
|
|
37952
|
-
leftLines: [
|
|
37953
|
-
`zelari-code \xB7 ${activeProviderSpec.id}/${activeModel}`,
|
|
37954
|
-
`cwd: ${cwd}`,
|
|
37955
|
-
`/help \xB7 /plan \xB7 /build \xB7 /view-plan \xB7 shift+tab mode`
|
|
37956
|
-
],
|
|
37957
|
-
version: VERSION,
|
|
37958
|
-
columns: cols,
|
|
37959
|
-
compact: cols < 72
|
|
37960
|
-
});
|
|
37961
38083
|
return {
|
|
37962
38084
|
id: "banner-once",
|
|
37963
38085
|
role: "system",
|
|
37964
38086
|
ts: 0,
|
|
37965
|
-
content
|
|
38087
|
+
content: ""
|
|
37966
38088
|
};
|
|
37967
|
-
}, [
|
|
38089
|
+
}, []);
|
|
37968
38090
|
const [sidebarOpen, setSidebarOpen] = useState8(false);
|
|
37969
38091
|
useEffect7(() => {
|
|
37970
38092
|
setSidebarOpen((prev2) => sidebarVisibility(size.columns, size.rows, prev2));
|
|
37971
38093
|
}, [size.columns, size.rows]);
|
|
37972
38094
|
const staticKey = `${session.sessionId || "pre-bootstrap"}-${clearEpoch}`;
|
|
37973
38095
|
const staticItems = session.sessionId ? [banner, ...session.messages] : [];
|
|
37974
|
-
|
|
37975
|
-
|
|
37976
|
-
Box8,
|
|
38096
|
+
return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(Static, { key: staticKey, items: staticItems }, (item) => item.id === "banner-once" ? /* @__PURE__ */ React10.createElement(
|
|
38097
|
+
StartupBanner,
|
|
37977
38098
|
{
|
|
37978
|
-
|
|
37979
|
-
|
|
37980
|
-
|
|
37981
|
-
|
|
37982
|
-
|
|
37983
|
-
|
|
37984
|
-
|
|
37985
|
-
|
|
37986
|
-
|
|
37987
|
-
|
|
37988
|
-
|
|
37989
|
-
|
|
37990
|
-
|
|
37991
|
-
|
|
37992
|
-
|
|
37993
|
-
|
|
37994
|
-
|
|
37995
|
-
|
|
37996
|
-
|
|
37997
|
-
|
|
37998
|
-
|
|
37999
|
-
|
|
38000
|
-
|
|
38001
|
-
|
|
38002
|
-
|
|
38003
|
-
|
|
38004
|
-
|
|
38005
|
-
|
|
38006
|
-
|
|
38007
|
-
|
|
38008
|
-
|
|
38009
|
-
|
|
38010
|
-
|
|
38011
|
-
|
|
38012
|
-
|
|
38013
|
-
|
|
38014
|
-
|
|
38015
|
-
|
|
38016
|
-
|
|
38017
|
-
|
|
38018
|
-
|
|
38019
|
-
|
|
38020
|
-
|
|
38021
|
-
|
|
38022
|
-
));
|
|
38099
|
+
key: item.id,
|
|
38100
|
+
version: VERSION,
|
|
38101
|
+
providerId: activeProviderSpec.id,
|
|
38102
|
+
model: activeModel,
|
|
38103
|
+
cwd,
|
|
38104
|
+
columns: size.columns || 80,
|
|
38105
|
+
rows: size.rows || 24
|
|
38106
|
+
}
|
|
38107
|
+
) : renderMessage(item)), /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "row" }, /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", flexGrow: 1, paddingX: 1 }, /* @__PURE__ */ React10.createElement(LiveRegion, { live: session.live, busy, elapsedMs: timer.elapsedMs }), picker ? /* @__PURE__ */ React10.createElement(
|
|
38108
|
+
SelectList,
|
|
38109
|
+
{
|
|
38110
|
+
title: picker.title,
|
|
38111
|
+
items: picker.items,
|
|
38112
|
+
onSelect: onPickerSelect,
|
|
38113
|
+
onCancel: onPickerCancel,
|
|
38114
|
+
maxVisible: Math.max(4, Math.min(10, size.rows - 10))
|
|
38115
|
+
}
|
|
38116
|
+
) : /* @__PURE__ */ React10.createElement(
|
|
38117
|
+
InputBar,
|
|
38118
|
+
{
|
|
38119
|
+
value: input,
|
|
38120
|
+
onChange: setInput,
|
|
38121
|
+
onSubmit: handleSubmit,
|
|
38122
|
+
disabled: busy
|
|
38123
|
+
}
|
|
38124
|
+
), /* @__PURE__ */ React10.createElement(
|
|
38125
|
+
StatusBar,
|
|
38126
|
+
{
|
|
38127
|
+
model: activeModel,
|
|
38128
|
+
provider: activeProviderSpec.id,
|
|
38129
|
+
sessionId: session.sessionId ? session.sessionId.slice(0, 8) : "...",
|
|
38130
|
+
sessionActive: session.sessionActive,
|
|
38131
|
+
queueCount: chatTurn.queueCount,
|
|
38132
|
+
busy,
|
|
38133
|
+
mode,
|
|
38134
|
+
phase: phase2,
|
|
38135
|
+
cwd,
|
|
38136
|
+
elapsedMs: timer.elapsedMs,
|
|
38137
|
+
lastMs: timer.lastMs,
|
|
38138
|
+
costUsd: sessionStats.totalCostUsd,
|
|
38139
|
+
cachedTokens: sessionStats.cachedTokens,
|
|
38140
|
+
contextUsed: sessionStats.contextTokens || 0,
|
|
38141
|
+
contextLimit: Number(process.env.ZELARI_CONTEXT_LIMIT) || 2e5
|
|
38142
|
+
}
|
|
38143
|
+
)), sidebarOpen && /* @__PURE__ */ React10.createElement(Sidebar, { version: VERSION, changes: gitChanges, rows: size.rows })));
|
|
38023
38144
|
}
|
|
38024
38145
|
|
|
38025
38146
|
// src/cli/components/SplashScreen.tsx
|
|
38026
|
-
import
|
|
38027
|
-
import { Box as
|
|
38147
|
+
import React11, { useEffect as useEffect8, useState as useState9 } from "react";
|
|
38148
|
+
import { Box as Box10, Text as Text11, useInput as useInput3, useStdin as useStdin3 } from "ink";
|
|
38028
38149
|
var SPLASH_DURATION_MS = 2e3;
|
|
38029
38150
|
var EMBLEM_LARGE = ` =%@*-
|
|
38030
38151
|
=%@@@@@#:
|
|
@@ -38160,8 +38281,8 @@ function Splash({ onDone, version: version2 }) {
|
|
|
38160
38281
|
{ isActive: isRawModeSupported === true }
|
|
38161
38282
|
);
|
|
38162
38283
|
if (!picked) return null;
|
|
38163
|
-
return /* @__PURE__ */
|
|
38164
|
-
|
|
38284
|
+
return /* @__PURE__ */ React11.createElement(
|
|
38285
|
+
Box10,
|
|
38165
38286
|
{
|
|
38166
38287
|
flexDirection: "column",
|
|
38167
38288
|
alignItems: "center",
|
|
@@ -38169,10 +38290,10 @@ function Splash({ onDone, version: version2 }) {
|
|
|
38169
38290
|
width: columns,
|
|
38170
38291
|
height: rows - 1
|
|
38171
38292
|
},
|
|
38172
|
-
/* @__PURE__ */
|
|
38173
|
-
/* @__PURE__ */
|
|
38174
|
-
!picked.compact && /* @__PURE__ */
|
|
38175
|
-
!picked.compact && /* @__PURE__ */
|
|
38293
|
+
/* @__PURE__ */ React11.createElement(Text11, { color: "cyan" }, picked.art),
|
|
38294
|
+
/* @__PURE__ */ React11.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text11, { bold: true, color: "white" }, "Z E L A R I C O D E")),
|
|
38295
|
+
!picked.compact && /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, `${version2 ? `v${version2} \u2014 ` : ""}N-THEM Studio`),
|
|
38296
|
+
!picked.compact && /* @__PURE__ */ React11.createElement(Text11, { dimColor: true, italic: true }, "press any key to skip")
|
|
38176
38297
|
);
|
|
38177
38298
|
}
|
|
38178
38299
|
function SplashGate({
|
|
@@ -38188,14 +38309,14 @@ function SplashGate({
|
|
|
38188
38309
|
})
|
|
38189
38310
|
);
|
|
38190
38311
|
if (show) {
|
|
38191
|
-
return /* @__PURE__ */
|
|
38312
|
+
return /* @__PURE__ */ React11.createElement(Splash, { onDone: () => setShow(false), version: version2 });
|
|
38192
38313
|
}
|
|
38193
|
-
return /* @__PURE__ */
|
|
38314
|
+
return /* @__PURE__ */ React11.createElement(React11.Fragment, null, children);
|
|
38194
38315
|
}
|
|
38195
38316
|
|
|
38196
38317
|
// src/cli/components/PluginGate.tsx
|
|
38197
|
-
import
|
|
38198
|
-
import { Box as
|
|
38318
|
+
import React12, { useEffect as useEffect9, useState as useState10, useCallback as useCallback6 } from "react";
|
|
38319
|
+
import { Box as Box11, Text as Text12, useStdin as useStdin4 } from "ink";
|
|
38199
38320
|
init_registry2();
|
|
38200
38321
|
init_prefs();
|
|
38201
38322
|
var CHOICE_INSTALL = "__install__";
|
|
@@ -38284,20 +38405,20 @@ function PluginGate({ cwd, children }) {
|
|
|
38284
38405
|
[current, cwd, advance]
|
|
38285
38406
|
);
|
|
38286
38407
|
if (phase2 === "done") {
|
|
38287
|
-
return /* @__PURE__ */
|
|
38408
|
+
return /* @__PURE__ */ React12.createElement(React12.Fragment, null, children);
|
|
38288
38409
|
}
|
|
38289
38410
|
if (phase2 === "detecting") {
|
|
38290
|
-
return /* @__PURE__ */
|
|
38411
|
+
return /* @__PURE__ */ React12.createElement(Box11, { paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text12, { dimColor: true }, "Checking for optional tool plugins\u2026"));
|
|
38291
38412
|
}
|
|
38292
38413
|
if (!current) {
|
|
38293
|
-
return /* @__PURE__ */
|
|
38414
|
+
return /* @__PURE__ */ React12.createElement(React12.Fragment, null, children);
|
|
38294
38415
|
}
|
|
38295
38416
|
if (phase2 === "installing") {
|
|
38296
|
-
return /* @__PURE__ */
|
|
38417
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, "\u23F3 Installing ", current.label, "\u2026"), /* @__PURE__ */ React12.createElement(Text12, { dimColor: true }, "npm install ", current.installScope === "global" ? "-g" : "-D", " ", current.npmPackage));
|
|
38297
38418
|
}
|
|
38298
38419
|
if (phase2 === "result") {
|
|
38299
38420
|
const ok = result?.ok === true;
|
|
38300
|
-
return /* @__PURE__ */
|
|
38421
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text12, { color: ok ? "green" : "red" }, ok ? "\u2713" : "\u2717", " ", ok ? "Installed" : "Install failed", ": ", current.label), !ok && result?.error ? /* @__PURE__ */ React12.createElement(Text12, { dimColor: true }, result.error) : null, ok && current.postInstallHint ? /* @__PURE__ */ React12.createElement(Text12, { color: "yellow" }, " \u2192 ", current.postInstallHint) : null, /* @__PURE__ */ React12.createElement(Text12, { dimColor: true }, "Press any key to continue\u2026"), /* @__PURE__ */ React12.createElement(ContinueKey, { onContinue: advance }));
|
|
38301
38422
|
}
|
|
38302
38423
|
const items = [
|
|
38303
38424
|
{
|
|
@@ -38308,7 +38429,7 @@ function PluginGate({ cwd, children }) {
|
|
|
38308
38429
|
{ value: CHOICE_LATER, label: "Maybe later" },
|
|
38309
38430
|
{ value: CHOICE_NEVER, label: "Don't ask again" }
|
|
38310
38431
|
];
|
|
38311
|
-
return /* @__PURE__ */
|
|
38432
|
+
return /* @__PURE__ */ React12.createElement(
|
|
38312
38433
|
SelectList,
|
|
38313
38434
|
{
|
|
38314
38435
|
title: `Optional plugin missing: ${current.label}`,
|
|
@@ -38370,15 +38491,15 @@ function parseWizardFlags(argv) {
|
|
|
38370
38491
|
}
|
|
38371
38492
|
|
|
38372
38493
|
// src/cli/wizard/runWizard.tsx
|
|
38373
|
-
import
|
|
38374
|
-
import { Box as
|
|
38494
|
+
import React14, { useEffect as useEffect10, useState as useState11 } from "react";
|
|
38495
|
+
import { Box as Box13, Text as Text14 } from "ink";
|
|
38375
38496
|
import { useInput as useInput4 } from "ink";
|
|
38376
38497
|
init_keyStore();
|
|
38377
38498
|
init_providerConfig();
|
|
38378
38499
|
|
|
38379
38500
|
// src/cli/wizard/index.tsx
|
|
38380
|
-
import
|
|
38381
|
-
import { Box as
|
|
38501
|
+
import React13 from "react";
|
|
38502
|
+
import { Box as Box12, Text as Text13 } from "ink";
|
|
38382
38503
|
|
|
38383
38504
|
// src/cli/wizard/useWizardState.ts
|
|
38384
38505
|
init_providerConfig();
|
|
@@ -38494,16 +38615,16 @@ var API_KEY_OPTIONS = ["env", "keystore", "skip"];
|
|
|
38494
38615
|
|
|
38495
38616
|
// src/cli/wizard/index.tsx
|
|
38496
38617
|
function Frame({ children }) {
|
|
38497
|
-
return /* @__PURE__ */
|
|
38618
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 }, children);
|
|
38498
38619
|
}
|
|
38499
38620
|
function Step(props) {
|
|
38500
|
-
return /* @__PURE__ */
|
|
38621
|
+
return /* @__PURE__ */ React13.createElement(Box12, null, /* @__PURE__ */ React13.createElement(Text13, { color: props.active ? "cyan" : "gray", inverse: props.active }, " ", props.index, "/", props.total, " ", props.name, " "));
|
|
38501
38622
|
}
|
|
38502
38623
|
function renderProviderList(providers, cursor) {
|
|
38503
|
-
return /* @__PURE__ */
|
|
38624
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column" }, providers.map((p3, i) => {
|
|
38504
38625
|
const arrow = i === cursor ? "\u279C " : " ";
|
|
38505
38626
|
const color = i === cursor ? "cyan" : void 0;
|
|
38506
|
-
return /* @__PURE__ */
|
|
38627
|
+
return /* @__PURE__ */ React13.createElement(Text13, { key: p3.id, color }, arrow, p3.displayName, " ", /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "(", p3.id, ", uses env ", p3.envVar, ")"));
|
|
38507
38628
|
}));
|
|
38508
38629
|
}
|
|
38509
38630
|
function renderApiKeyOptions(cursor) {
|
|
@@ -38512,18 +38633,18 @@ function renderApiKeyOptions(cursor) {
|
|
|
38512
38633
|
keystore: "Save to local keyStore (encrypted)",
|
|
38513
38634
|
skip: "Skip for now (chat will fail until key is set)"
|
|
38514
38635
|
};
|
|
38515
|
-
return /* @__PURE__ */
|
|
38636
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column" }, API_KEY_OPTIONS.map((choice, i) => {
|
|
38516
38637
|
const arrow = i === cursor ? "\u279C " : " ";
|
|
38517
38638
|
const color = i === cursor ? "cyan" : void 0;
|
|
38518
|
-
return /* @__PURE__ */
|
|
38639
|
+
return /* @__PURE__ */ React13.createElement(Text13, { key: choice, color }, arrow, labels[choice]);
|
|
38519
38640
|
}));
|
|
38520
38641
|
}
|
|
38521
38642
|
function Wizard({ state: state2, providers }) {
|
|
38522
38643
|
const s = state2.state;
|
|
38523
38644
|
if (s.committed) {
|
|
38524
|
-
return /* @__PURE__ */
|
|
38645
|
+
return /* @__PURE__ */ React13.createElement(Frame, null, /* @__PURE__ */ React13.createElement(Text13, { color: "green" }, "\u2713 Setup complete!"), /* @__PURE__ */ React13.createElement(Text13, null, "Provider: ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.providerId), " | ", "Model: ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.model), " | ", "API key: ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.apiKeyChoice ?? "n/a")), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "Launching zelari-code\u2026 (press any key)")));
|
|
38525
38646
|
}
|
|
38526
|
-
return /* @__PURE__ */
|
|
38647
|
+
return /* @__PURE__ */ React13.createElement(Frame, null, /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", bold: true }, "zelari-code v", VERSION, " \u2014 first-time setup"), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1, marginBottom: 1, flexDirection: "row" }, /* @__PURE__ */ React13.createElement(Step, { index: 1, total: 5, name: "welcome", active: s.step === "welcome" }), /* @__PURE__ */ React13.createElement(Step, { index: 2, total: 5, name: "provider", active: s.step === "provider" }), /* @__PURE__ */ React13.createElement(Step, { index: 3, total: 5, name: "model", active: s.step === "model" }), /* @__PURE__ */ React13.createElement(Step, { index: 4, total: 5, name: "apikey", active: s.step === "apikey" }), /* @__PURE__ */ React13.createElement(Step, { index: 5, total: 5, name: "confirm", active: s.step === "confirm" })), s.step === "welcome" && /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Text13, null, "Welcome! Let's get you coding in under two minutes."), /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "We'll pick a provider, default model, and how to handle your API key."), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, null, "Press "), /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", inverse: true }, " Enter "), /* @__PURE__ */ React13.createElement(Text13, null, " to continue, or "), /* @__PURE__ */ React13.createElement(Text13, { color: "red", inverse: true }, " Q "), /* @__PURE__ */ React13.createElement(Text13, null, " to quit (re-run with "), /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "--no-wizard"), /* @__PURE__ */ React13.createElement(Text13, null, " to skip later)."))), s.step === "provider" && /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Text13, null, "Choose your LLM provider:"), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, renderProviderList(providers, s.providerCursor)), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "\u2191/\u2193 to move, Enter to confirm"))), s.step === "model" && /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Text13, null, "Model for ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.providerId), ":"), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1, borderStyle: "single", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React13.createElement(Text13, null, s.model ?? "(empty)")), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, null, "Press ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", inverse: true }, " Enter "), "to accept, or type a new name. ", /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "(default kept on empty input)")))), s.step === "apikey" && /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Text13, null, "How should we handle the API key?"), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, renderApiKeyOptions(s.apiKeyCursor)), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "\u2191/\u2193 to move, Enter to confirm"))), s.step === "confirm" && /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Text13, null, "Confirm your setup:"), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Text13, null, "Provider: ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.providerId)), /* @__PURE__ */ React13.createElement(Text13, null, "Model: ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.model)), /* @__PURE__ */ React13.createElement(Text13, null, "API key: ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.apiKeyChoice ?? "(unset)"))), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, null, "Press ", /* @__PURE__ */ React13.createElement(Text13, { color: "green", inverse: true }, " Enter "), "to save and launch, or ", /* @__PURE__ */ React13.createElement(Text13, { color: "yellow", inverse: true }, " B "), "to go back."))));
|
|
38527
38648
|
}
|
|
38528
38649
|
|
|
38529
38650
|
// src/cli/wizard/runWizard.tsx
|
|
@@ -38599,9 +38720,9 @@ function RunWizard(_props) {
|
|
|
38599
38720
|
}
|
|
38600
38721
|
});
|
|
38601
38722
|
if (wiz.state.committed) {
|
|
38602
|
-
return /* @__PURE__ */
|
|
38723
|
+
return /* @__PURE__ */ React14.createElement(PostCommitBridge, null);
|
|
38603
38724
|
}
|
|
38604
|
-
return /* @__PURE__ */
|
|
38725
|
+
return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React14.createElement(Wizard, { state: wiz, providers: PROVIDERS }));
|
|
38605
38726
|
}
|
|
38606
38727
|
function PostCommitBridge() {
|
|
38607
38728
|
const [showApp, setShowApp] = useState11(false);
|
|
@@ -38610,22 +38731,26 @@ function PostCommitBridge() {
|
|
|
38610
38731
|
return () => clearTimeout(t);
|
|
38611
38732
|
}, []);
|
|
38612
38733
|
if (showApp) {
|
|
38613
|
-
return /* @__PURE__ */
|
|
38734
|
+
return /* @__PURE__ */ React14.createElement(App, null);
|
|
38614
38735
|
}
|
|
38615
|
-
return /* @__PURE__ */
|
|
38736
|
+
return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React14.createElement(Box13, { borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Text14, { color: "green", bold: true }, "\u2713 Setup complete! Launching zelari-code\u2026"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, "Press Ctrl+C any time to exit.")));
|
|
38616
38737
|
}
|
|
38617
38738
|
|
|
38618
38739
|
// src/cli/headless.ts
|
|
38619
38740
|
init_keyStore();
|
|
38620
38741
|
init_providerConfig();
|
|
38621
38742
|
init_openai_compatible();
|
|
38743
|
+
init_phase();
|
|
38622
38744
|
function parseHeadlessFlags(argv) {
|
|
38623
38745
|
if (!argv.includes("--headless")) {
|
|
38624
38746
|
return { options: null };
|
|
38625
38747
|
}
|
|
38626
38748
|
let task;
|
|
38627
38749
|
let output = "json";
|
|
38628
|
-
let
|
|
38750
|
+
let mode = "agent";
|
|
38751
|
+
let phase2 = "build";
|
|
38752
|
+
let modeExplicit = false;
|
|
38753
|
+
let councilFlag = false;
|
|
38629
38754
|
let provider;
|
|
38630
38755
|
let model;
|
|
38631
38756
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -38646,7 +38771,30 @@ function parseHeadlessFlags(argv) {
|
|
|
38646
38771
|
task = argv[i + 1];
|
|
38647
38772
|
i++;
|
|
38648
38773
|
} else if (arg === "--council") {
|
|
38649
|
-
|
|
38774
|
+
councilFlag = true;
|
|
38775
|
+
} else if (arg === "--mode") {
|
|
38776
|
+
const next = argv[i + 1];
|
|
38777
|
+
const parsed = next ? parseMode(next) : null;
|
|
38778
|
+
if (!parsed) {
|
|
38779
|
+
return {
|
|
38780
|
+
options: null,
|
|
38781
|
+
error: `--mode requires 'agent', 'council', or 'zelari', got '${next ?? "(missing)"}'`
|
|
38782
|
+
};
|
|
38783
|
+
}
|
|
38784
|
+
mode = parsed;
|
|
38785
|
+
modeExplicit = true;
|
|
38786
|
+
i++;
|
|
38787
|
+
} else if (arg === "--phase") {
|
|
38788
|
+
const next = argv[i + 1];
|
|
38789
|
+
const parsed = next ? parsePhase(next) : null;
|
|
38790
|
+
if (!parsed) {
|
|
38791
|
+
return {
|
|
38792
|
+
options: null,
|
|
38793
|
+
error: `--phase requires 'plan' or 'build', got '${next ?? "(missing)"}'`
|
|
38794
|
+
};
|
|
38795
|
+
}
|
|
38796
|
+
phase2 = parsed;
|
|
38797
|
+
i++;
|
|
38650
38798
|
} else if (arg === "--provider") {
|
|
38651
38799
|
provider = argv[i + 1];
|
|
38652
38800
|
i++;
|
|
@@ -38655,11 +38803,27 @@ function parseHeadlessFlags(argv) {
|
|
|
38655
38803
|
i++;
|
|
38656
38804
|
}
|
|
38657
38805
|
}
|
|
38806
|
+
if (councilFlag && !modeExplicit) {
|
|
38807
|
+
mode = "council";
|
|
38808
|
+
} else if (councilFlag && modeExplicit && mode !== "council") {
|
|
38809
|
+
return {
|
|
38810
|
+
options: null,
|
|
38811
|
+
error: `--council conflicts with --mode ${mode}`
|
|
38812
|
+
};
|
|
38813
|
+
}
|
|
38658
38814
|
if (!task || task.trim().length === 0) {
|
|
38659
38815
|
return { options: null, error: "--headless requires --task <prompt>" };
|
|
38660
38816
|
}
|
|
38661
38817
|
return {
|
|
38662
|
-
options: {
|
|
38818
|
+
options: {
|
|
38819
|
+
task,
|
|
38820
|
+
output,
|
|
38821
|
+
mode,
|
|
38822
|
+
phase: phase2,
|
|
38823
|
+
useCouncil: mode === "council",
|
|
38824
|
+
provider,
|
|
38825
|
+
model
|
|
38826
|
+
}
|
|
38663
38827
|
};
|
|
38664
38828
|
}
|
|
38665
38829
|
async function resolveHeadlessKey(providerId) {
|
|
@@ -38694,7 +38858,10 @@ init_harness();
|
|
|
38694
38858
|
init_toolRegistry();
|
|
38695
38859
|
init_skills2();
|
|
38696
38860
|
init_envNumber();
|
|
38861
|
+
init_phaseState();
|
|
38862
|
+
init_phase();
|
|
38697
38863
|
async function runHeadless(opts) {
|
|
38864
|
+
setPhase(opts.phase ?? "build");
|
|
38698
38865
|
const { provider, model } = resolveHeadlessProvider(opts);
|
|
38699
38866
|
const key = await resolveHeadlessKey(provider);
|
|
38700
38867
|
if ("error" in key) {
|
|
@@ -38708,14 +38875,34 @@ async function runHeadless(opts) {
|
|
|
38708
38875
|
baseUrl: key.baseUrl,
|
|
38709
38876
|
model
|
|
38710
38877
|
});
|
|
38711
|
-
|
|
38878
|
+
const mode = opts.mode ?? (opts.useCouncil ? "council" : "agent");
|
|
38879
|
+
if (opts.output === "json") {
|
|
38880
|
+
emitEvent({
|
|
38881
|
+
type: "log",
|
|
38882
|
+
message: `[headless] mode=${mode} phase=${opts.phase ?? "build"} provider=${provider} model=${model}`
|
|
38883
|
+
});
|
|
38884
|
+
} else {
|
|
38885
|
+
process.stderr.write(
|
|
38886
|
+
`[zelari-code --headless] mode=${mode} phase=${describePhase(opts.phase ?? "build")}
|
|
38887
|
+
`
|
|
38888
|
+
);
|
|
38889
|
+
}
|
|
38890
|
+
if (mode === "zelari") {
|
|
38891
|
+
return runHeadlessZelari(opts, provider, model, providerStream);
|
|
38892
|
+
}
|
|
38893
|
+
if (mode === "council" || opts.useCouncil) {
|
|
38712
38894
|
return runHeadlessCouncil(opts, provider, model, providerStream);
|
|
38713
38895
|
}
|
|
38714
38896
|
return runHeadlessSingle(opts, provider, model, providerStream);
|
|
38715
38897
|
}
|
|
38898
|
+
function planModeFromOpts(opts) {
|
|
38899
|
+
return (opts.phase ?? "build") === "plan";
|
|
38900
|
+
}
|
|
38716
38901
|
async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
38717
38902
|
const sessionId = crypto.randomUUID();
|
|
38718
|
-
const { registry: toolRegistry } = createBuiltinToolRegistry(
|
|
38903
|
+
const { registry: toolRegistry } = createBuiltinToolRegistry({
|
|
38904
|
+
planMode: planModeFromOpts(opts)
|
|
38905
|
+
});
|
|
38719
38906
|
const tools = toolRegistry.toOpenAITools().map((t) => ({
|
|
38720
38907
|
name: t.function.name,
|
|
38721
38908
|
description: t.function.description,
|
|
@@ -38738,10 +38925,6 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
38738
38925
|
color: "#00d9a3",
|
|
38739
38926
|
avatar: "\u25C6",
|
|
38740
38927
|
tools: toolNames,
|
|
38741
|
-
// v1.7.0 fix (agy audit): include platform/shell context in the role
|
|
38742
|
-
// prompt so the agent knows its cwd and shell — previously this was
|
|
38743
|
-
// empty (systemPrompt: '') and the agent lacked the platform block
|
|
38744
|
-
// the TUI single-agent path gets.
|
|
38745
38928
|
systemPrompt: [
|
|
38746
38929
|
"# Platform",
|
|
38747
38930
|
`platform: ${process.platform}`,
|
|
@@ -38750,7 +38933,10 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
38750
38933
|
"# Working Directory",
|
|
38751
38934
|
`You are running in: ${process.cwd()}`,
|
|
38752
38935
|
"All relative file paths are resolved against this directory.",
|
|
38753
|
-
"The shell is NON-INTERACTIVE (stdin closed): pass non-interactive flags (--yes, --force, --template)."
|
|
38936
|
+
"The shell is NON-INTERACTIVE (stdin closed): pass non-interactive flags (--yes, --force, --template).",
|
|
38937
|
+
"",
|
|
38938
|
+
`# Work phase: ${opts.phase ?? "build"}`,
|
|
38939
|
+
(opts.phase ?? "build") === "plan" ? "PLAN phase: explore and design only. Do not write project source files (write_file/edit_file/bash blocked). Plan artifacts under .zelari are allowed." : "BUILD phase: full tools; implement changes."
|
|
38754
38940
|
].join("\n")
|
|
38755
38941
|
};
|
|
38756
38942
|
systemPrompt = buildSystemPrompt(headlessRole, {
|
|
@@ -38829,18 +39015,11 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
38829
39015
|
if (finalReason === "error") return 3;
|
|
38830
39016
|
return exitCode;
|
|
38831
39017
|
}
|
|
38832
|
-
async function
|
|
38833
|
-
const {
|
|
38834
|
-
const sessionId = crypto.randomUUID();
|
|
38835
|
-
const { registry: toolRegistry } = createBuiltinToolRegistry();
|
|
38836
|
-
const workspaceCtx = {
|
|
38837
|
-
projectRoot: process.cwd(),
|
|
38838
|
-
getActiveBranch: () => null
|
|
38839
|
-
};
|
|
39018
|
+
async function buildCouncilToolRegistry(planMode) {
|
|
39019
|
+
const { registry: toolRegistry } = createBuiltinToolRegistry({ planMode });
|
|
38840
39020
|
const { createWorkspaceContext: createWorkspaceContext2, createWorkspaceStubs: createWorkspaceStubs2 } = await Promise.resolve().then(() => (init_stubs(), stubs_exports));
|
|
38841
39021
|
const { createWorkspaceToolRegistry: createWorkspaceToolRegistry2 } = await Promise.resolve().then(() => (init_toolRegistry2(), toolRegistry_exports2));
|
|
38842
39022
|
const { setWorkspaceStubs: setWorkspaceStubs2 } = await Promise.resolve().then(() => (init_skills2(), skills_exports));
|
|
38843
|
-
const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
|
|
38844
39023
|
const realCtx = createWorkspaceContext2();
|
|
38845
39024
|
const realReg = createWorkspaceToolRegistry2(realCtx);
|
|
38846
39025
|
for (const name of realReg.list()) {
|
|
@@ -38848,6 +39027,13 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
38848
39027
|
if (td) toolRegistry.register(td);
|
|
38849
39028
|
}
|
|
38850
39029
|
setWorkspaceStubs2(createWorkspaceStubs2(realCtx));
|
|
39030
|
+
return { toolRegistry, workspaceCtx: realCtx };
|
|
39031
|
+
}
|
|
39032
|
+
async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
39033
|
+
const { dispatchCouncil: dispatchCouncil2 } = await Promise.resolve().then(() => (init_councilDispatcher(), councilDispatcher_exports));
|
|
39034
|
+
const sessionId = crypto.randomUUID();
|
|
39035
|
+
const { toolRegistry } = await buildCouncilToolRegistry(planModeFromOpts(opts));
|
|
39036
|
+
const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
|
|
38851
39037
|
const feedbackStore = new FeedbackStore2();
|
|
38852
39038
|
let exitCode = 0;
|
|
38853
39039
|
try {
|
|
@@ -38858,7 +39044,8 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
38858
39044
|
providerStream,
|
|
38859
39045
|
sessionId,
|
|
38860
39046
|
tools: toolRegistry,
|
|
38861
|
-
feedbackStore
|
|
39047
|
+
feedbackStore,
|
|
39048
|
+
runMode: planModeFromOpts(opts) ? "design-phase" : "implementation"
|
|
38862
39049
|
})) {
|
|
38863
39050
|
if (opts.output === "json") {
|
|
38864
39051
|
emitEvent(event);
|
|
@@ -38879,6 +39066,378 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
38879
39066
|
}
|
|
38880
39067
|
return exitCode;
|
|
38881
39068
|
}
|
|
39069
|
+
async function runHeadlessZelari(opts, provider, model, providerStream) {
|
|
39070
|
+
const projectRoot = process.cwd();
|
|
39071
|
+
const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
39072
|
+
const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
|
|
39073
|
+
const { getMemoryBackend: getMemoryBackend2 } = await Promise.resolve().then(() => (init_fileBackend(), fileBackend_exports));
|
|
39074
|
+
const { runZelariMission: runZelariMission2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
|
|
39075
|
+
const { dispatchCouncil: dispatchCouncil2 } = await Promise.resolve().then(() => (init_councilDispatcher(), councilDispatcher_exports));
|
|
39076
|
+
const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
|
|
39077
|
+
const { runPostCouncilHook: runPostCouncilHook2 } = await Promise.resolve().then(() => (init_postCouncilHook(), postCouncilHook_exports));
|
|
39078
|
+
const brief = buildMissionBrief2({
|
|
39079
|
+
userMessage: opts.task,
|
|
39080
|
+
hasPlan: hasWorkspacePlan2(projectRoot)
|
|
39081
|
+
});
|
|
39082
|
+
const memory = await getMemoryBackend2(projectRoot);
|
|
39083
|
+
const { toolRegistry, workspaceCtx } = await buildCouncilToolRegistry(planModeFromOpts(opts));
|
|
39084
|
+
const feedbackStore = new FeedbackStore2();
|
|
39085
|
+
const chairmanBudget = envNumber(process.env.ZELARI_MODE_MAX_TOOLS_LUCIFER, {
|
|
39086
|
+
default: 30,
|
|
39087
|
+
min: 1
|
|
39088
|
+
});
|
|
39089
|
+
const emit = (message) => {
|
|
39090
|
+
if (opts.output === "json") {
|
|
39091
|
+
emitEvent({ type: "log", message });
|
|
39092
|
+
} else {
|
|
39093
|
+
process.stderr.write(message + "\n");
|
|
39094
|
+
}
|
|
39095
|
+
};
|
|
39096
|
+
emit(`[zelari] mission brief
|
|
39097
|
+
${JSON.stringify({ deliverable: brief.deliverableThisMission, mvp: brief.sliceMvp?.title }, null, 0)}`);
|
|
39098
|
+
let exitCode = 0;
|
|
39099
|
+
try {
|
|
39100
|
+
const state2 = await runZelariMission2(opts.task, brief, {
|
|
39101
|
+
projectRoot,
|
|
39102
|
+
memory,
|
|
39103
|
+
emit,
|
|
39104
|
+
runSlice: async ({ userMessage: slicePrompt, runMode, ragContext }) => {
|
|
39105
|
+
const sessionId = crypto.randomUUID();
|
|
39106
|
+
const fullPrompt = ragContext ? `${slicePrompt}
|
|
39107
|
+
|
|
39108
|
+
## Memory context
|
|
39109
|
+
${ragContext}` : slicePrompt;
|
|
39110
|
+
let synthesisText = "";
|
|
39111
|
+
let writeCount = 0;
|
|
39112
|
+
let chairmanErrored = false;
|
|
39113
|
+
let membersCompleted = 0;
|
|
39114
|
+
for await (const event of dispatchCouncil2(fullPrompt, {
|
|
39115
|
+
apiKey: "REDACTED",
|
|
39116
|
+
model,
|
|
39117
|
+
provider: "openai-compatible",
|
|
39118
|
+
providerStream,
|
|
39119
|
+
sessionId,
|
|
39120
|
+
tools: toolRegistry,
|
|
39121
|
+
feedbackStore,
|
|
39122
|
+
runMode: planModeFromOpts(opts) ? "design-phase" : runMode,
|
|
39123
|
+
maxToolCallsChairman: chairmanBudget
|
|
39124
|
+
})) {
|
|
39125
|
+
if (opts.output === "json") {
|
|
39126
|
+
emitEvent(event);
|
|
39127
|
+
} else if (event.type === "message_delta") {
|
|
39128
|
+
process.stdout.write(event.delta);
|
|
39129
|
+
}
|
|
39130
|
+
if (event.type === "message_delta" && typeof event.delta === "string") {
|
|
39131
|
+
synthesisText += event.delta;
|
|
39132
|
+
}
|
|
39133
|
+
if (event.type === "tool_execution_end") {
|
|
39134
|
+
const name = event.toolName ?? event.name ?? "";
|
|
39135
|
+
if (name === "write_file" || name === "edit_file" || name === "apply_diff") {
|
|
39136
|
+
writeCount += 1;
|
|
39137
|
+
}
|
|
39138
|
+
}
|
|
39139
|
+
if (event.type === "agent_end") {
|
|
39140
|
+
membersCompleted += 1;
|
|
39141
|
+
if (event.reason === "error") chairmanErrored = true;
|
|
39142
|
+
}
|
|
39143
|
+
if (event.type === "error" && event.severity === "fatal") {
|
|
39144
|
+
chairmanErrored = true;
|
|
39145
|
+
exitCode = 2;
|
|
39146
|
+
}
|
|
39147
|
+
}
|
|
39148
|
+
let completionOk = false;
|
|
39149
|
+
let degraded = false;
|
|
39150
|
+
try {
|
|
39151
|
+
const { detectDegradedRun: detectDegradedRun2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
39152
|
+
const d = detectDegradedRun2({
|
|
39153
|
+
chairmanErrored,
|
|
39154
|
+
councilAborted: false,
|
|
39155
|
+
luciferWriteCount: writeCount,
|
|
39156
|
+
synthesisText,
|
|
39157
|
+
runMode
|
|
39158
|
+
});
|
|
39159
|
+
degraded = d.degraded;
|
|
39160
|
+
const hook = await runPostCouncilHook2(workspaceCtx, {
|
|
39161
|
+
runMode,
|
|
39162
|
+
userMessage: opts.task,
|
|
39163
|
+
synthesisText: synthesisText || void 0,
|
|
39164
|
+
degradedRun: d.degraded,
|
|
39165
|
+
degradedReasons: d.reasons
|
|
39166
|
+
});
|
|
39167
|
+
completionOk = hook.completion?.completion?.ok ?? false;
|
|
39168
|
+
if (completionOk) {
|
|
39169
|
+
emit(`[zelari] slice completion ok`);
|
|
39170
|
+
}
|
|
39171
|
+
} catch {
|
|
39172
|
+
}
|
|
39173
|
+
return {
|
|
39174
|
+
completionOk,
|
|
39175
|
+
ran: membersCompleted > 0 || synthesisText.length > 0,
|
|
39176
|
+
synthesisText: synthesisText || void 0,
|
|
39177
|
+
writeCount,
|
|
39178
|
+
degraded
|
|
39179
|
+
};
|
|
39180
|
+
}
|
|
39181
|
+
});
|
|
39182
|
+
if (state2.status === "error") exitCode = exitCode || 3;
|
|
39183
|
+
else if (state2.status === "success") exitCode = 0;
|
|
39184
|
+
else if (state2.status === "stalled" || state2.status === "stopped") exitCode = exitCode || 0;
|
|
39185
|
+
} catch (err) {
|
|
39186
|
+
process.stderr.write(
|
|
39187
|
+
`[zelari-code --headless] zelari error: ${err instanceof Error ? err.message : String(err)}
|
|
39188
|
+
`
|
|
39189
|
+
);
|
|
39190
|
+
return 2;
|
|
39191
|
+
} finally {
|
|
39192
|
+
await memory.close().catch(() => void 0);
|
|
39193
|
+
}
|
|
39194
|
+
return exitCode;
|
|
39195
|
+
}
|
|
39196
|
+
|
|
39197
|
+
// src/cli/desktopConfig.ts
|
|
39198
|
+
init_keyStore();
|
|
39199
|
+
init_providerConfig();
|
|
39200
|
+
init_updater();
|
|
39201
|
+
function wantsPrintConfig(argv) {
|
|
39202
|
+
return argv.includes("--print-config");
|
|
39203
|
+
}
|
|
39204
|
+
function wantsSetKey(argv) {
|
|
39205
|
+
return argv.includes("--set-key");
|
|
39206
|
+
}
|
|
39207
|
+
function wantsDiscoverModels(argv) {
|
|
39208
|
+
return argv.includes("--discover-models");
|
|
39209
|
+
}
|
|
39210
|
+
function parseSetConfigFlags(argv) {
|
|
39211
|
+
if (!argv.includes("--set-config")) {
|
|
39212
|
+
return { request: null };
|
|
39213
|
+
}
|
|
39214
|
+
let provider;
|
|
39215
|
+
let model;
|
|
39216
|
+
let endpoint;
|
|
39217
|
+
let endpointClear = false;
|
|
39218
|
+
for (let i = 0; i < argv.length; i++) {
|
|
39219
|
+
const arg = argv[i];
|
|
39220
|
+
if (arg === "--provider") {
|
|
39221
|
+
provider = argv[i + 1];
|
|
39222
|
+
i++;
|
|
39223
|
+
} else if (arg === "--model") {
|
|
39224
|
+
model = argv[i + 1];
|
|
39225
|
+
i++;
|
|
39226
|
+
} else if (arg === "--endpoint") {
|
|
39227
|
+
endpoint = argv[i + 1];
|
|
39228
|
+
i++;
|
|
39229
|
+
} else if (arg === "--endpoint-clear") {
|
|
39230
|
+
endpointClear = true;
|
|
39231
|
+
}
|
|
39232
|
+
}
|
|
39233
|
+
if (!provider && !model && !endpoint && !endpointClear) {
|
|
39234
|
+
return {
|
|
39235
|
+
request: null,
|
|
39236
|
+
error: "--set-config requires --provider, --model, --endpoint, and/or --endpoint-clear"
|
|
39237
|
+
};
|
|
39238
|
+
}
|
|
39239
|
+
if (provider !== void 0 && provider.trim().length === 0) {
|
|
39240
|
+
return { request: null, error: "--provider cannot be empty" };
|
|
39241
|
+
}
|
|
39242
|
+
if (model !== void 0 && model.trim().length === 0) {
|
|
39243
|
+
return { request: null, error: "--model cannot be empty" };
|
|
39244
|
+
}
|
|
39245
|
+
if (endpoint !== void 0 && endpoint.trim().length === 0) {
|
|
39246
|
+
return { request: null, error: "--endpoint cannot be empty" };
|
|
39247
|
+
}
|
|
39248
|
+
if (endpoint && endpointClear) {
|
|
39249
|
+
return { request: null, error: "--endpoint and --endpoint-clear conflict" };
|
|
39250
|
+
}
|
|
39251
|
+
return {
|
|
39252
|
+
request: {
|
|
39253
|
+
provider: provider?.trim(),
|
|
39254
|
+
model: model?.trim(),
|
|
39255
|
+
endpoint: endpoint?.trim(),
|
|
39256
|
+
endpointClear: endpointClear || void 0
|
|
39257
|
+
}
|
|
39258
|
+
};
|
|
39259
|
+
}
|
|
39260
|
+
function parseSetKeyFlags(argv) {
|
|
39261
|
+
if (!argv.includes("--set-key")) {
|
|
39262
|
+
return { request: null };
|
|
39263
|
+
}
|
|
39264
|
+
let provider;
|
|
39265
|
+
let key;
|
|
39266
|
+
for (let i = 0; i < argv.length; i++) {
|
|
39267
|
+
const arg = argv[i];
|
|
39268
|
+
if (arg === "--provider") {
|
|
39269
|
+
provider = argv[i + 1];
|
|
39270
|
+
i++;
|
|
39271
|
+
} else if (arg === "--key") {
|
|
39272
|
+
key = argv[i + 1];
|
|
39273
|
+
i++;
|
|
39274
|
+
}
|
|
39275
|
+
}
|
|
39276
|
+
if (!provider || provider.trim().length === 0) {
|
|
39277
|
+
return { request: null, error: "--set-key requires --provider <id>" };
|
|
39278
|
+
}
|
|
39279
|
+
if (!key || key.trim().length === 0) {
|
|
39280
|
+
return { request: null, error: "--set-key requires --key <secret>" };
|
|
39281
|
+
}
|
|
39282
|
+
return {
|
|
39283
|
+
request: {
|
|
39284
|
+
provider: provider.trim(),
|
|
39285
|
+
key: key.trim()
|
|
39286
|
+
}
|
|
39287
|
+
};
|
|
39288
|
+
}
|
|
39289
|
+
function parseDiscoverModelsFlags(argv) {
|
|
39290
|
+
if (!argv.includes("--discover-models")) {
|
|
39291
|
+
return { provider: null, present: false };
|
|
39292
|
+
}
|
|
39293
|
+
let provider;
|
|
39294
|
+
for (let i = 0; i < argv.length; i++) {
|
|
39295
|
+
if (argv[i] === "--provider") {
|
|
39296
|
+
provider = argv[i + 1];
|
|
39297
|
+
i++;
|
|
39298
|
+
}
|
|
39299
|
+
}
|
|
39300
|
+
return {
|
|
39301
|
+
present: true,
|
|
39302
|
+
provider: provider?.trim() || null
|
|
39303
|
+
};
|
|
39304
|
+
}
|
|
39305
|
+
function buildDesktopConfigSnapshot() {
|
|
39306
|
+
const config2 = getProviderConfig();
|
|
39307
|
+
const providers = PROVIDERS.map((p3) => {
|
|
39308
|
+
const cached2 = getCachedModels(p3.id);
|
|
39309
|
+
const models = cached2?.models.map((m) => m.id) ?? [];
|
|
39310
|
+
const defaultModel = config2.modelByProvider[p3.id] ?? "";
|
|
39311
|
+
if (defaultModel && !models.includes(defaultModel)) {
|
|
39312
|
+
models.unshift(defaultModel);
|
|
39313
|
+
}
|
|
39314
|
+
const custom2 = getCustomEndpoint(p3.id);
|
|
39315
|
+
const builtin = p3.baseUrl ?? null;
|
|
39316
|
+
return {
|
|
39317
|
+
id: p3.id,
|
|
39318
|
+
displayName: p3.displayName,
|
|
39319
|
+
hasKey: !!resolveApiKey(p3.id),
|
|
39320
|
+
envVar: p3.envVar,
|
|
39321
|
+
models,
|
|
39322
|
+
defaultModel,
|
|
39323
|
+
endpoint: custom2 ?? null,
|
|
39324
|
+
baseUrl: custom2 ?? builtin
|
|
39325
|
+
};
|
|
39326
|
+
});
|
|
39327
|
+
return {
|
|
39328
|
+
activeProviderId: config2.activeProviderId,
|
|
39329
|
+
modelByProvider: { ...config2.modelByProvider },
|
|
39330
|
+
providers,
|
|
39331
|
+
cliVersion: getCurrentVersion(),
|
|
39332
|
+
configPaths: {
|
|
39333
|
+
provider: getProviderConfigPath(),
|
|
39334
|
+
keys: getKeyStorePath()
|
|
39335
|
+
}
|
|
39336
|
+
};
|
|
39337
|
+
}
|
|
39338
|
+
function printDesktopConfig() {
|
|
39339
|
+
const snap = buildDesktopConfigSnapshot();
|
|
39340
|
+
process.stdout.write(JSON.stringify(snap, null, 2) + "\n");
|
|
39341
|
+
}
|
|
39342
|
+
function applySetConfig(req) {
|
|
39343
|
+
try {
|
|
39344
|
+
const config2 = getProviderConfig();
|
|
39345
|
+
let targetProvider = req.provider ?? config2.activeProviderId;
|
|
39346
|
+
if (req.provider) {
|
|
39347
|
+
const exists = PROVIDERS.some((p3) => p3.id === req.provider);
|
|
39348
|
+
if (!exists) {
|
|
39349
|
+
return {
|
|
39350
|
+
ok: false,
|
|
39351
|
+
error: `unknown provider '${req.provider}'. Available: ${PROVIDERS.map((p3) => p3.id).join(", ")}`
|
|
39352
|
+
};
|
|
39353
|
+
}
|
|
39354
|
+
setActiveProviderId(req.provider);
|
|
39355
|
+
targetProvider = req.provider;
|
|
39356
|
+
}
|
|
39357
|
+
if (req.endpointClear) {
|
|
39358
|
+
clearCustomEndpoint(targetProvider);
|
|
39359
|
+
}
|
|
39360
|
+
if (req.endpoint) {
|
|
39361
|
+
setCustomEndpoint(targetProvider, req.endpoint);
|
|
39362
|
+
}
|
|
39363
|
+
if (req.model) {
|
|
39364
|
+
setModelForProvider(targetProvider, req.model);
|
|
39365
|
+
}
|
|
39366
|
+
const after = getProviderConfig();
|
|
39367
|
+
const ep = getCustomEndpoint(after.activeProviderId);
|
|
39368
|
+
return {
|
|
39369
|
+
ok: true,
|
|
39370
|
+
message: `activeProvider=${after.activeProviderId} model=${after.modelByProvider[after.activeProviderId]}` + (ep ? ` endpoint=${ep}` : "")
|
|
39371
|
+
};
|
|
39372
|
+
} catch (err) {
|
|
39373
|
+
return {
|
|
39374
|
+
ok: false,
|
|
39375
|
+
error: err instanceof Error ? err.message : String(err)
|
|
39376
|
+
};
|
|
39377
|
+
}
|
|
39378
|
+
}
|
|
39379
|
+
function applySetKey(req) {
|
|
39380
|
+
try {
|
|
39381
|
+
const exists = PROVIDERS.some((p3) => p3.id === req.provider);
|
|
39382
|
+
if (!exists) {
|
|
39383
|
+
return {
|
|
39384
|
+
ok: false,
|
|
39385
|
+
error: `unknown provider '${req.provider}'. Available: ${PROVIDERS.map((p3) => p3.id).join(", ")}`
|
|
39386
|
+
};
|
|
39387
|
+
}
|
|
39388
|
+
setApiKey(req.provider, req.key);
|
|
39389
|
+
setActiveProviderId(req.provider);
|
|
39390
|
+
return {
|
|
39391
|
+
ok: true,
|
|
39392
|
+
provider: req.provider,
|
|
39393
|
+
masked: maskKey(req.key)
|
|
39394
|
+
};
|
|
39395
|
+
} catch (err) {
|
|
39396
|
+
return {
|
|
39397
|
+
ok: false,
|
|
39398
|
+
error: err instanceof Error ? err.message : String(err)
|
|
39399
|
+
};
|
|
39400
|
+
}
|
|
39401
|
+
}
|
|
39402
|
+
var DISCOVERABLE = [
|
|
39403
|
+
"grok",
|
|
39404
|
+
"glm",
|
|
39405
|
+
"minimax",
|
|
39406
|
+
"deepseek",
|
|
39407
|
+
"openai-compatible"
|
|
39408
|
+
];
|
|
39409
|
+
async function runDiscoverModels(providerArg) {
|
|
39410
|
+
const config2 = getProviderConfig();
|
|
39411
|
+
const providerId = (providerArg ?? config2.activeProviderId).trim();
|
|
39412
|
+
if (!DISCOVERABLE.includes(providerId)) {
|
|
39413
|
+
if (providerId === "custom") {
|
|
39414
|
+
} else {
|
|
39415
|
+
return {
|
|
39416
|
+
ok: false,
|
|
39417
|
+
error: `provider '${providerId}' is not discoverable. Use: ${DISCOVERABLE.join(", ")}`
|
|
39418
|
+
};
|
|
39419
|
+
}
|
|
39420
|
+
}
|
|
39421
|
+
const discoveryId = providerId === "custom" ? "openai-compatible" : providerId;
|
|
39422
|
+
try {
|
|
39423
|
+
const entry = await discoverModelsForProvider(discoveryId);
|
|
39424
|
+
return {
|
|
39425
|
+
ok: true,
|
|
39426
|
+
payload: {
|
|
39427
|
+
ok: true,
|
|
39428
|
+
provider: providerId,
|
|
39429
|
+
models: entry.models.map((m) => m.id),
|
|
39430
|
+
fetchedAt: entry.fetchedAt,
|
|
39431
|
+
baseUrl: entry.baseUrl
|
|
39432
|
+
}
|
|
39433
|
+
};
|
|
39434
|
+
} catch (err) {
|
|
39435
|
+
return {
|
|
39436
|
+
ok: false,
|
|
39437
|
+
error: err instanceof Error ? err.message : String(err)
|
|
39438
|
+
};
|
|
39439
|
+
}
|
|
39440
|
+
}
|
|
38882
39441
|
|
|
38883
39442
|
// src/cli/skillsMd.ts
|
|
38884
39443
|
init_skills2();
|
|
@@ -39088,10 +39647,85 @@ function pickRootComponent() {
|
|
|
39088
39647
|
}
|
|
39089
39648
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
39090
39649
|
console.log(
|
|
39091
|
-
"zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --council
|
|
39650
|
+
"zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --mode agent|council|zelari Dispatch mode (default: agent)\n --council Alias for --mode council\n --phase plan|build Work phase (default: build)\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n --print-config Print provider/model config as JSON (no secrets)\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
|
|
39092
39651
|
);
|
|
39093
39652
|
process.exit(0);
|
|
39094
39653
|
}
|
|
39654
|
+
if (wantsPrintConfig(argv)) {
|
|
39655
|
+
try {
|
|
39656
|
+
printDesktopConfig();
|
|
39657
|
+
process.exit(0);
|
|
39658
|
+
} catch (err) {
|
|
39659
|
+
console.error(
|
|
39660
|
+
`[zelari-code --print-config] ${err instanceof Error ? err.message : String(err)}`
|
|
39661
|
+
);
|
|
39662
|
+
process.exit(1);
|
|
39663
|
+
}
|
|
39664
|
+
}
|
|
39665
|
+
const setConfigParse = parseSetConfigFlags(argv);
|
|
39666
|
+
if (setConfigParse.error) {
|
|
39667
|
+
console.error(`[zelari-code --set-config] ${setConfigParse.error}`);
|
|
39668
|
+
process.exit(1);
|
|
39669
|
+
}
|
|
39670
|
+
if (setConfigParse.request) {
|
|
39671
|
+
const result = applySetConfig(setConfigParse.request);
|
|
39672
|
+
if (!result.ok) {
|
|
39673
|
+
console.error(`[zelari-code --set-config] ${result.error}`);
|
|
39674
|
+
process.exit(1);
|
|
39675
|
+
}
|
|
39676
|
+
console.log(JSON.stringify({ ok: true, message: result.message }));
|
|
39677
|
+
process.exit(0);
|
|
39678
|
+
}
|
|
39679
|
+
if (wantsSetKey(argv)) {
|
|
39680
|
+
const keyParse = parseSetKeyFlags(argv);
|
|
39681
|
+
if (keyParse.error || !keyParse.request) {
|
|
39682
|
+
console.error(
|
|
39683
|
+
`[zelari-code --set-key] ${keyParse.error ?? "invalid arguments"}`
|
|
39684
|
+
);
|
|
39685
|
+
process.exit(1);
|
|
39686
|
+
}
|
|
39687
|
+
const result = applySetKey(keyParse.request);
|
|
39688
|
+
if (!result.ok) {
|
|
39689
|
+
console.error(`[zelari-code --set-key] ${result.error}`);
|
|
39690
|
+
process.exit(1);
|
|
39691
|
+
}
|
|
39692
|
+
console.log(
|
|
39693
|
+
JSON.stringify({
|
|
39694
|
+
ok: true,
|
|
39695
|
+
provider: result.provider,
|
|
39696
|
+
masked: result.masked
|
|
39697
|
+
})
|
|
39698
|
+
);
|
|
39699
|
+
process.exit(0);
|
|
39700
|
+
}
|
|
39701
|
+
if (wantsDiscoverModels(argv)) {
|
|
39702
|
+
const disc = parseDiscoverModelsFlags(argv);
|
|
39703
|
+
void runDiscoverModels(disc.provider).then(async (result) => {
|
|
39704
|
+
if (!result.ok) {
|
|
39705
|
+
console.error(JSON.stringify({ ok: false, error: result.error }));
|
|
39706
|
+
await new Promise((r) => setImmediate(r));
|
|
39707
|
+
process.exit(1);
|
|
39708
|
+
return;
|
|
39709
|
+
}
|
|
39710
|
+
console.log(JSON.stringify(result.payload));
|
|
39711
|
+
try {
|
|
39712
|
+
await getMetricsLogger().flush();
|
|
39713
|
+
} catch {
|
|
39714
|
+
}
|
|
39715
|
+
await new Promise((r) => setImmediate(r));
|
|
39716
|
+
process.exit(0);
|
|
39717
|
+
}).catch(async (err) => {
|
|
39718
|
+
console.error(
|
|
39719
|
+
JSON.stringify({
|
|
39720
|
+
ok: false,
|
|
39721
|
+
error: err instanceof Error ? err.message : String(err)
|
|
39722
|
+
})
|
|
39723
|
+
);
|
|
39724
|
+
await new Promise((r) => setImmediate(r));
|
|
39725
|
+
process.exit(1);
|
|
39726
|
+
});
|
|
39727
|
+
return { kind: "done" };
|
|
39728
|
+
}
|
|
39095
39729
|
const headlessParse = parseHeadlessFlags(argv);
|
|
39096
39730
|
if (headlessParse.options !== null) {
|
|
39097
39731
|
return { kind: "headless", headlessOpts: headlessParse.options };
|
|
@@ -39109,16 +39743,16 @@ function pickRootComponent() {
|
|
|
39109
39743
|
});
|
|
39110
39744
|
if (decision.shouldRun) {
|
|
39111
39745
|
console.error(`[zelari-code] starting wizard: ${decision.reason}`);
|
|
39112
|
-
return { kind: "wizard", element:
|
|
39746
|
+
return { kind: "wizard", element: React15.createElement(RunWizard) };
|
|
39113
39747
|
}
|
|
39114
39748
|
return {
|
|
39115
39749
|
kind: "app",
|
|
39116
|
-
element:
|
|
39750
|
+
element: React15.createElement(
|
|
39117
39751
|
SplashGate,
|
|
39118
39752
|
{ version: VERSION },
|
|
39119
|
-
|
|
39753
|
+
React15.createElement(PluginGate, {
|
|
39120
39754
|
cwd: process.cwd(),
|
|
39121
|
-
children:
|
|
39755
|
+
children: React15.createElement(App)
|
|
39122
39756
|
})
|
|
39123
39757
|
)
|
|
39124
39758
|
};
|
|
@@ -39144,10 +39778,27 @@ function main() {
|
|
|
39144
39778
|
runPreflight();
|
|
39145
39779
|
loadUserSkills();
|
|
39146
39780
|
if (picked.kind === "headless") {
|
|
39147
|
-
void runHeadless(picked.headlessOpts).then((code) => {
|
|
39148
|
-
|
|
39149
|
-
|
|
39781
|
+
void runHeadless(picked.headlessOpts).then(async (code) => {
|
|
39782
|
+
try {
|
|
39783
|
+
await getMetricsLogger().flush();
|
|
39784
|
+
} catch {
|
|
39785
|
+
}
|
|
39786
|
+
try {
|
|
39787
|
+
const { closeMcpClients: closeMcpClients2 } = await Promise.resolve().then(() => (init_mcpManager(), mcpManager_exports));
|
|
39788
|
+
closeMcpClients2();
|
|
39789
|
+
} catch {
|
|
39790
|
+
}
|
|
39791
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
39150
39792
|
process.exit(code);
|
|
39793
|
+
}).catch(async (err) => {
|
|
39794
|
+
console.error(
|
|
39795
|
+
`[zelari-code --headless] fatal: ${err instanceof Error ? err.message : String(err)}`
|
|
39796
|
+
);
|
|
39797
|
+
try {
|
|
39798
|
+
await getMetricsLogger().flush();
|
|
39799
|
+
} catch {
|
|
39800
|
+
}
|
|
39801
|
+
process.exit(2);
|
|
39151
39802
|
});
|
|
39152
39803
|
return;
|
|
39153
39804
|
}
|