zelari-code 1.23.0 → 1.24.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 +6 -0
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/main.bundled.js +427 -241
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/missionSlice.js +19 -0
- package/dist/cli/missionSlice.js.map +1 -1
- package/dist/cli/runHeadless.js +18 -0
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/traceStore.js +84 -0
- package/dist/cli/traceStore.js.map +1 -0
- package/dist/cli/triggerLock.js +79 -0
- package/dist/cli/triggerLock.js.map +1 -0
- package/dist/cli/zelariMission.js +77 -0
- package/dist/cli/zelariMission.js.map +1 -1
- package/dist/cli/zelariMission.test.js +44 -0
- package/dist/cli/zelariMission.test.js.map +1 -0
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -21,6 +21,87 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
21
21
|
};
|
|
22
22
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
23
23
|
|
|
24
|
+
// src/cli/modelPricing.ts
|
|
25
|
+
function envOverride(model) {
|
|
26
|
+
const key = `ANATHEMA_PRICE_${model.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
|
|
27
|
+
const raw = process.env[key] ?? process.env.ANATHEMA_PRICE_DEFAULT;
|
|
28
|
+
return parseRateOverride(raw);
|
|
29
|
+
}
|
|
30
|
+
function parseRateOverride(raw) {
|
|
31
|
+
if (!raw) return null;
|
|
32
|
+
const [inStr, outStr] = raw.split("/");
|
|
33
|
+
const input = Number.parseFloat(inStr);
|
|
34
|
+
const output = outStr !== void 0 ? Number.parseFloat(outStr) : input;
|
|
35
|
+
if (!Number.isFinite(input) || !Number.isFinite(output)) return null;
|
|
36
|
+
return { input, output };
|
|
37
|
+
}
|
|
38
|
+
function getModelRate(model) {
|
|
39
|
+
if (!model) return DEFAULT_RATE;
|
|
40
|
+
return envOverride(model) ?? PRICES_PER_MILLION[model] ?? DEFAULT_RATE;
|
|
41
|
+
}
|
|
42
|
+
function calculateCost(model, promptTokens, completionTokens, cachedPromptTokens = 0) {
|
|
43
|
+
if (!Number.isFinite(promptTokens) || promptTokens < 0) return 0;
|
|
44
|
+
if (!Number.isFinite(completionTokens) || completionTokens < 0) return 0;
|
|
45
|
+
const rate = getModelRate(model);
|
|
46
|
+
const cached2 = Number.isFinite(cachedPromptTokens) && cachedPromptTokens > 0 ? Math.min(cachedPromptTokens, promptTokens) : 0;
|
|
47
|
+
const uncachedPrompt = promptTokens - cached2;
|
|
48
|
+
const cachedRate = rate.cachedInput ?? rate.input * DEFAULT_CACHE_DISCOUNT;
|
|
49
|
+
const inputCost = uncachedPrompt / 1e6 * rate.input + cached2 / 1e6 * cachedRate;
|
|
50
|
+
const outputCost = completionTokens / 1e6 * rate.output;
|
|
51
|
+
return Number((inputCost + outputCost).toFixed(6));
|
|
52
|
+
}
|
|
53
|
+
function formatCost(usd) {
|
|
54
|
+
if (!Number.isFinite(usd) || usd < 0) return "$0.0000";
|
|
55
|
+
if (usd === 0) return "$0.0000";
|
|
56
|
+
if (usd < 1e-4) return "<$0.0001";
|
|
57
|
+
return `$${usd.toFixed(4)}`;
|
|
58
|
+
}
|
|
59
|
+
function formatTokens(tokens) {
|
|
60
|
+
if (!Number.isFinite(tokens) || tokens < 0) return "0";
|
|
61
|
+
if (tokens < 1e3) return `${tokens}`;
|
|
62
|
+
if (tokens < 1e6) return `${(tokens / 1e3).toFixed(1)}k`;
|
|
63
|
+
if (tokens < 1e9) return `${(tokens / 1e6).toFixed(2)}M`;
|
|
64
|
+
return `${(tokens / 1e9).toFixed(2)}B`;
|
|
65
|
+
}
|
|
66
|
+
var PRICES_PER_MILLION, DEFAULT_RATE, DEFAULT_CACHE_DISCOUNT;
|
|
67
|
+
var init_modelPricing = __esm({
|
|
68
|
+
"src/cli/modelPricing.ts"() {
|
|
69
|
+
"use strict";
|
|
70
|
+
PRICES_PER_MILLION = {
|
|
71
|
+
// xAI Grok (list prices; grok-4.5 default reasoning_effort is "high")
|
|
72
|
+
"grok-4.5": { input: 2, output: 6, cachedInput: 0.5 },
|
|
73
|
+
"grok-4.3": { input: 1.25, output: 2.5, cachedInput: 0.2 },
|
|
74
|
+
"grok-4": { input: 3, output: 15 },
|
|
75
|
+
"grok-4-fast": { input: 0.2, output: 0.5 },
|
|
76
|
+
"grok-3": { input: 3, output: 15 },
|
|
77
|
+
"grok-3-mini": { input: 0.3, output: 0.5 },
|
|
78
|
+
"grok-2-vision": { input: 2, output: 10 },
|
|
79
|
+
// GLM / Z.AI
|
|
80
|
+
"glm-4.6": { input: 0.6, output: 2.2 },
|
|
81
|
+
"glm-4.5": { input: 0.5, output: 2 },
|
|
82
|
+
"glm-4.5-air": { input: 0.1, output: 0.6 },
|
|
83
|
+
"glm-z1": { input: 0.5, output: 2 },
|
|
84
|
+
// MiniMax
|
|
85
|
+
"MiniMax-M2.5": { input: 0.2, output: 1.1 },
|
|
86
|
+
"MiniMax-M2": { input: 0.2, output: 1.1 },
|
|
87
|
+
"MiniMax-M2-her": { input: 0.3, output: 1.2 },
|
|
88
|
+
// DeepSeek (global platform) — estimated list prices; override via
|
|
89
|
+
// ANATHEMA_PRICE_DEEPSEEK_V4_FLASH / ANATHEMA_PRICE_DEEPSEEK_V4_PRO.
|
|
90
|
+
// DeepSeek prompt-cache hits are ~10× cheaper than a cache miss.
|
|
91
|
+
"deepseek-v4-flash": { input: 0.14, output: 0.28, cachedInput: 0.014 },
|
|
92
|
+
"deepseek-v4-pro": { input: 0.55, output: 2.19, cachedInput: 0.055 },
|
|
93
|
+
// OpenAI (for openai-compatible fallback)
|
|
94
|
+
"gpt-4o": { input: 2.5, output: 10 },
|
|
95
|
+
"gpt-4o-mini": { input: 0.15, output: 0.6 },
|
|
96
|
+
"gpt-4-turbo": { input: 10, output: 30 },
|
|
97
|
+
"o1-preview": { input: 15, output: 60 },
|
|
98
|
+
"o1-mini": { input: 3, output: 12 }
|
|
99
|
+
};
|
|
100
|
+
DEFAULT_RATE = { input: 1, output: 3 };
|
|
101
|
+
DEFAULT_CACHE_DISCOUNT = 0.25;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
24
105
|
// src/cli/grokOAuth.ts
|
|
25
106
|
var grokOAuth_exports = {};
|
|
26
107
|
__export(grokOAuth_exports, {
|
|
@@ -1543,10 +1624,10 @@ function mergeDefs(...defs) {
|
|
|
1543
1624
|
function cloneDef(schema) {
|
|
1544
1625
|
return mergeDefs(schema._zod.def);
|
|
1545
1626
|
}
|
|
1546
|
-
function getElementAtPath(obj,
|
|
1547
|
-
if (!
|
|
1627
|
+
function getElementAtPath(obj, path40) {
|
|
1628
|
+
if (!path40)
|
|
1548
1629
|
return obj;
|
|
1549
|
-
return
|
|
1630
|
+
return path40.reduce((acc, key) => acc?.[key], obj);
|
|
1550
1631
|
}
|
|
1551
1632
|
function promiseAllObject(promisesObj) {
|
|
1552
1633
|
const keys = Object.keys(promisesObj);
|
|
@@ -1874,11 +1955,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
1874
1955
|
}
|
|
1875
1956
|
return false;
|
|
1876
1957
|
}
|
|
1877
|
-
function prefixIssues(
|
|
1958
|
+
function prefixIssues(path40, issues) {
|
|
1878
1959
|
return issues.map((iss) => {
|
|
1879
1960
|
var _a3;
|
|
1880
1961
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
1881
|
-
iss.path.unshift(
|
|
1962
|
+
iss.path.unshift(path40);
|
|
1882
1963
|
return iss;
|
|
1883
1964
|
});
|
|
1884
1965
|
}
|
|
@@ -2096,16 +2177,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2096
2177
|
}
|
|
2097
2178
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
2098
2179
|
const fieldErrors = { _errors: [] };
|
|
2099
|
-
const processError = (error52,
|
|
2180
|
+
const processError = (error52, path40 = []) => {
|
|
2100
2181
|
for (const issue2 of error52.issues) {
|
|
2101
2182
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2102
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2183
|
+
issue2.errors.map((issues) => processError({ issues }, [...path40, ...issue2.path]));
|
|
2103
2184
|
} else if (issue2.code === "invalid_key") {
|
|
2104
|
-
processError({ issues: issue2.issues }, [...
|
|
2185
|
+
processError({ issues: issue2.issues }, [...path40, ...issue2.path]);
|
|
2105
2186
|
} else if (issue2.code === "invalid_element") {
|
|
2106
|
-
processError({ issues: issue2.issues }, [...
|
|
2187
|
+
processError({ issues: issue2.issues }, [...path40, ...issue2.path]);
|
|
2107
2188
|
} else {
|
|
2108
|
-
const fullpath = [...
|
|
2189
|
+
const fullpath = [...path40, ...issue2.path];
|
|
2109
2190
|
if (fullpath.length === 0) {
|
|
2110
2191
|
fieldErrors._errors.push(mapper(issue2));
|
|
2111
2192
|
} else {
|
|
@@ -2132,17 +2213,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2132
2213
|
}
|
|
2133
2214
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
2134
2215
|
const result = { errors: [] };
|
|
2135
|
-
const processError = (error52,
|
|
2216
|
+
const processError = (error52, path40 = []) => {
|
|
2136
2217
|
var _a3, _b;
|
|
2137
2218
|
for (const issue2 of error52.issues) {
|
|
2138
2219
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2139
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2220
|
+
issue2.errors.map((issues) => processError({ issues }, [...path40, ...issue2.path]));
|
|
2140
2221
|
} else if (issue2.code === "invalid_key") {
|
|
2141
|
-
processError({ issues: issue2.issues }, [...
|
|
2222
|
+
processError({ issues: issue2.issues }, [...path40, ...issue2.path]);
|
|
2142
2223
|
} else if (issue2.code === "invalid_element") {
|
|
2143
|
-
processError({ issues: issue2.issues }, [...
|
|
2224
|
+
processError({ issues: issue2.issues }, [...path40, ...issue2.path]);
|
|
2144
2225
|
} else {
|
|
2145
|
-
const fullpath = [...
|
|
2226
|
+
const fullpath = [...path40, ...issue2.path];
|
|
2146
2227
|
if (fullpath.length === 0) {
|
|
2147
2228
|
result.errors.push(mapper(issue2));
|
|
2148
2229
|
continue;
|
|
@@ -2174,8 +2255,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2174
2255
|
}
|
|
2175
2256
|
function toDotPath(_path) {
|
|
2176
2257
|
const segs = [];
|
|
2177
|
-
const
|
|
2178
|
-
for (const seg of
|
|
2258
|
+
const path40 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
2259
|
+
for (const seg of path40) {
|
|
2179
2260
|
if (typeof seg === "number")
|
|
2180
2261
|
segs.push(`[${seg}]`);
|
|
2181
2262
|
else if (typeof seg === "symbol")
|
|
@@ -15678,13 +15759,13 @@ function resolveRef(ref, ctx) {
|
|
|
15678
15759
|
if (!ref.startsWith("#")) {
|
|
15679
15760
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
15680
15761
|
}
|
|
15681
|
-
const
|
|
15682
|
-
if (
|
|
15762
|
+
const path40 = ref.slice(1).split("/").filter(Boolean);
|
|
15763
|
+
if (path40.length === 0) {
|
|
15683
15764
|
return ctx.rootSchema;
|
|
15684
15765
|
}
|
|
15685
15766
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
15686
|
-
if (
|
|
15687
|
-
const key =
|
|
15767
|
+
if (path40[0] === defsKey) {
|
|
15768
|
+
const key = path40[1];
|
|
15688
15769
|
if (!key || !ctx.defs[key]) {
|
|
15689
15770
|
throw new Error(`Reference not found: ${ref}`);
|
|
15690
15771
|
}
|
|
@@ -17848,11 +17929,11 @@ var init_tools = __esm({
|
|
|
17848
17929
|
if (!ctx.addDocument)
|
|
17849
17930
|
return "Knowledge vault tool not available.";
|
|
17850
17931
|
const title = args["title"] || "New Document";
|
|
17851
|
-
const
|
|
17932
|
+
const path40 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
17852
17933
|
const content = args["content"] || "";
|
|
17853
17934
|
const tags = args["tags"] || [];
|
|
17854
17935
|
ctx.addDocument({
|
|
17855
|
-
path:
|
|
17936
|
+
path: path40,
|
|
17856
17937
|
title,
|
|
17857
17938
|
content,
|
|
17858
17939
|
format: "markdown",
|
|
@@ -17861,7 +17942,7 @@ var init_tools = __esm({
|
|
|
17861
17942
|
workspaceId: ctx.workspaceId
|
|
17862
17943
|
});
|
|
17863
17944
|
ctx.addActivity("vault", "created document", title);
|
|
17864
|
-
return `Document "${title}" created at "${
|
|
17945
|
+
return `Document "${title}" created at "${path40}".`;
|
|
17865
17946
|
}
|
|
17866
17947
|
}
|
|
17867
17948
|
];
|
|
@@ -21059,9 +21140,9 @@ function spillToolOutput(fullText, meta3) {
|
|
|
21059
21140
|
const rnd = randomBytes(3).toString("hex");
|
|
21060
21141
|
const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
|
|
21061
21142
|
const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
|
|
21062
|
-
const
|
|
21063
|
-
writeFileSync5(
|
|
21064
|
-
return
|
|
21143
|
+
const path40 = join(dir, file2);
|
|
21144
|
+
writeFileSync5(path40, fullText, "utf8");
|
|
21145
|
+
return path40;
|
|
21065
21146
|
} catch {
|
|
21066
21147
|
return null;
|
|
21067
21148
|
}
|
|
@@ -21107,10 +21188,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
|
|
|
21107
21188
|
${tail}`;
|
|
21108
21189
|
}
|
|
21109
21190
|
if (doSpill) {
|
|
21110
|
-
const
|
|
21111
|
-
if (
|
|
21191
|
+
const path40 = spillToolOutput(text, { toolName: opts.toolName });
|
|
21192
|
+
if (path40) {
|
|
21112
21193
|
const spillNote = `
|
|
21113
|
-
\u2026 [full output spilled to: ${
|
|
21194
|
+
\u2026 [full output spilled to: ${path40} \u2014 re-read with read_file if you need the complete text] \u2026`;
|
|
21114
21195
|
if (preview.includes("] \u2026\n")) {
|
|
21115
21196
|
preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
|
|
21116
21197
|
`);
|
|
@@ -23542,21 +23623,21 @@ function normalizeAuth(auth) {
|
|
|
23542
23623
|
return "agent";
|
|
23543
23624
|
}
|
|
23544
23625
|
function readSecrets() {
|
|
23545
|
-
const
|
|
23546
|
-
if (!existsSync11(
|
|
23626
|
+
const path40 = getSshSecretsPath();
|
|
23627
|
+
if (!existsSync11(path40)) return {};
|
|
23547
23628
|
try {
|
|
23548
|
-
return JSON.parse(readFileSync8(
|
|
23629
|
+
return JSON.parse(readFileSync8(path40, "utf8"));
|
|
23549
23630
|
} catch {
|
|
23550
23631
|
return {};
|
|
23551
23632
|
}
|
|
23552
23633
|
}
|
|
23553
23634
|
function writeSecrets(data) {
|
|
23554
|
-
const
|
|
23555
|
-
mkdirSync7(dirname2(
|
|
23556
|
-
writeFileSync6(
|
|
23635
|
+
const path40 = getSshSecretsPath();
|
|
23636
|
+
mkdirSync7(dirname2(path40), { recursive: true });
|
|
23637
|
+
writeFileSync6(path40, `${JSON.stringify(data, null, 2)}
|
|
23557
23638
|
`, "utf8");
|
|
23558
23639
|
try {
|
|
23559
|
-
chmodSync(
|
|
23640
|
+
chmodSync(path40, 384);
|
|
23560
23641
|
} catch {
|
|
23561
23642
|
}
|
|
23562
23643
|
}
|
|
@@ -23585,10 +23666,10 @@ function deleteSshPassword(id) {
|
|
|
23585
23666
|
writeSecrets({ passwords });
|
|
23586
23667
|
}
|
|
23587
23668
|
function readStore2() {
|
|
23588
|
-
const
|
|
23589
|
-
if (!existsSync11(
|
|
23669
|
+
const path40 = getSshTargetsPath();
|
|
23670
|
+
if (!existsSync11(path40)) return [];
|
|
23590
23671
|
try {
|
|
23591
|
-
const parsed = JSON.parse(readFileSync8(
|
|
23672
|
+
const parsed = JSON.parse(readFileSync8(path40, "utf8"));
|
|
23592
23673
|
const list = Array.isArray(parsed.targets) ? parsed.targets : [];
|
|
23593
23674
|
return list.filter(
|
|
23594
23675
|
(t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
|
|
@@ -23603,11 +23684,11 @@ function readStore2() {
|
|
|
23603
23684
|
}
|
|
23604
23685
|
}
|
|
23605
23686
|
function writeStore2(targets) {
|
|
23606
|
-
const
|
|
23607
|
-
mkdirSync7(dirname2(
|
|
23687
|
+
const path40 = getSshTargetsPath();
|
|
23688
|
+
mkdirSync7(dirname2(path40), { recursive: true });
|
|
23608
23689
|
const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
|
|
23609
23690
|
writeFileSync6(
|
|
23610
|
-
|
|
23691
|
+
path40,
|
|
23611
23692
|
`${JSON.stringify({ targets: clean }, null, 2)}
|
|
23612
23693
|
`,
|
|
23613
23694
|
"utf8"
|
|
@@ -23853,11 +23934,11 @@ function formatSshTargetsForPrompt() {
|
|
|
23853
23934
|
];
|
|
23854
23935
|
for (const t of targets) {
|
|
23855
23936
|
const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
|
|
23856
|
-
const
|
|
23937
|
+
const path40 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
|
|
23857
23938
|
const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
|
|
23858
23939
|
const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
|
|
23859
23940
|
lines.push(
|
|
23860
|
-
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${
|
|
23941
|
+
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path40}${tags}${allow}`
|
|
23861
23942
|
);
|
|
23862
23943
|
}
|
|
23863
23944
|
return lines.join("\n");
|
|
@@ -25857,11 +25938,11 @@ var init_synthesisAudit = __esm({
|
|
|
25857
25938
|
import { existsSync as existsSync13, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "node:fs";
|
|
25858
25939
|
import { join as join6 } from "node:path";
|
|
25859
25940
|
function loadNfrSpec(zelariRoot) {
|
|
25860
|
-
const
|
|
25861
|
-
if (!existsSync13(
|
|
25941
|
+
const path40 = join6(zelariRoot, "nfr-spec.json");
|
|
25942
|
+
if (!existsSync13(path40))
|
|
25862
25943
|
return null;
|
|
25863
25944
|
try {
|
|
25864
|
-
const raw = JSON.parse(readFileSync10(
|
|
25945
|
+
const raw = JSON.parse(readFileSync10(path40, "utf8"));
|
|
25865
25946
|
if (raw.version !== 1 || !Array.isArray(raw.targets))
|
|
25866
25947
|
return null;
|
|
25867
25948
|
return raw;
|
|
@@ -28167,9 +28248,9 @@ var init_types3 = __esm({
|
|
|
28167
28248
|
import { readFileSync as readFileSync15 } from "node:fs";
|
|
28168
28249
|
import { join as join12 } from "node:path";
|
|
28169
28250
|
function readLessonsDeduped(zelariRoot) {
|
|
28170
|
-
const
|
|
28251
|
+
const path40 = join12(zelariRoot, LESSONS_FILE);
|
|
28171
28252
|
try {
|
|
28172
|
-
const raw = readFileSync15(
|
|
28253
|
+
const raw = readFileSync15(path40, "utf8");
|
|
28173
28254
|
const byId = /* @__PURE__ */ new Map();
|
|
28174
28255
|
for (const line of raw.split(/\r?\n/)) {
|
|
28175
28256
|
if (!line.trim())
|
|
@@ -28270,8 +28351,8 @@ function keywordsFrom(check2, signature) {
|
|
|
28270
28351
|
return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
|
|
28271
28352
|
}
|
|
28272
28353
|
function writeLesson(zelariRoot, lesson) {
|
|
28273
|
-
const
|
|
28274
|
-
appendFileSync2(
|
|
28354
|
+
const path40 = join13(zelariRoot, LESSONS_FILE);
|
|
28355
|
+
appendFileSync2(path40, `${JSON.stringify(lesson)}
|
|
28275
28356
|
`, "utf8");
|
|
28276
28357
|
}
|
|
28277
28358
|
function findSimilar(lessons, signature) {
|
|
@@ -30428,28 +30509,28 @@ var init_storage = __esm({
|
|
|
30428
30509
|
VALID_SCALARS = /^(true|false|null|~)$/i;
|
|
30429
30510
|
Storage = class {
|
|
30430
30511
|
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
30431
|
-
read(
|
|
30432
|
-
if (!existsSync23(
|
|
30433
|
-
throw new Error(`File not found: ${
|
|
30512
|
+
read(path40) {
|
|
30513
|
+
if (!existsSync23(path40)) {
|
|
30514
|
+
throw new Error(`File not found: ${path40}`);
|
|
30434
30515
|
}
|
|
30435
|
-
const md = readFileSync20(
|
|
30516
|
+
const md = readFileSync20(path40, "utf8");
|
|
30436
30517
|
return parseFrontmatter(md);
|
|
30437
30518
|
}
|
|
30438
30519
|
/** Read a Markdown file; returns null if not found. */
|
|
30439
|
-
readIfExists(
|
|
30440
|
-
if (!existsSync23(
|
|
30441
|
-
return this.read(
|
|
30520
|
+
readIfExists(path40) {
|
|
30521
|
+
if (!existsSync23(path40)) return null;
|
|
30522
|
+
return this.read(path40);
|
|
30442
30523
|
}
|
|
30443
30524
|
/**
|
|
30444
30525
|
* Write a Markdown file atomically (tmp + rename). Creates parent dirs.
|
|
30445
30526
|
* The meta object is serialized as YAML frontmatter; body as Markdown.
|
|
30446
30527
|
*/
|
|
30447
|
-
write(
|
|
30448
|
-
mkdirSync9(dirname4(
|
|
30449
|
-
const tmp =
|
|
30528
|
+
write(path40, meta3, body) {
|
|
30529
|
+
mkdirSync9(dirname4(path40), { recursive: true });
|
|
30530
|
+
const tmp = path40 + ".tmp-" + process.pid;
|
|
30450
30531
|
const md = serializeFrontmatter(meta3, body);
|
|
30451
30532
|
writeFileSync13(tmp, md, "utf8");
|
|
30452
|
-
renameSync2(tmp,
|
|
30533
|
+
renameSync2(tmp, path40);
|
|
30453
30534
|
}
|
|
30454
30535
|
/** List all .md files in a directory (non-recursive). */
|
|
30455
30536
|
listMarkdown(dir) {
|
|
@@ -30527,8 +30608,8 @@ function readPlan(ctx) {
|
|
|
30527
30608
|
} catch {
|
|
30528
30609
|
}
|
|
30529
30610
|
}
|
|
30530
|
-
const
|
|
30531
|
-
const doc = ctx.storage.readIfExists(
|
|
30611
|
+
const path40 = workspaceFile(ctx.rootDir, "plan");
|
|
30612
|
+
const doc = ctx.storage.readIfExists(path40);
|
|
30532
30613
|
if (!doc) return { phases: [], tasks: [], milestones: [] };
|
|
30533
30614
|
const meta3 = doc.meta;
|
|
30534
30615
|
return {
|
|
@@ -30693,7 +30774,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
30693
30774
|
dueDate: input.dueDate,
|
|
30694
30775
|
targetVersion: version2
|
|
30695
30776
|
});
|
|
30696
|
-
const
|
|
30777
|
+
const path40 = join23(ctx.rootDir, "milestones", `${id}.md`);
|
|
30697
30778
|
const meta3 = {
|
|
30698
30779
|
kind: "milestone",
|
|
30699
30780
|
id,
|
|
@@ -30710,7 +30791,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
30710
30791
|
`Target version: ${version2}`,
|
|
30711
30792
|
""
|
|
30712
30793
|
].join("\n");
|
|
30713
|
-
ctx.storage.write(
|
|
30794
|
+
ctx.storage.write(path40, meta3, body);
|
|
30714
30795
|
return { id, created: true };
|
|
30715
30796
|
}
|
|
30716
30797
|
function readPlanSummary(ctx) {
|
|
@@ -30914,7 +30995,7 @@ function addIdeaStub(ctx) {
|
|
|
30914
30995
|
const tags = args["tags"] ?? [];
|
|
30915
30996
|
const category = args["category"] ?? "General";
|
|
30916
30997
|
const id = `${nextAdrId(ctx)}-${slugify3(title)}`;
|
|
30917
|
-
const
|
|
30998
|
+
const path40 = workspaceArtifact(ctx.rootDir, "decisions", id);
|
|
30918
30999
|
const meta3 = {
|
|
30919
31000
|
kind: "adr",
|
|
30920
31001
|
status: "proposed",
|
|
@@ -30940,7 +31021,7 @@ function addIdeaStub(ctx) {
|
|
|
30940
31021
|
...consequences.map((c) => `- ${c}`),
|
|
30941
31022
|
""
|
|
30942
31023
|
].join("\n");
|
|
30943
|
-
ctx.storage.write(
|
|
31024
|
+
ctx.storage.write(path40, meta3, body);
|
|
30944
31025
|
return `ADR ${id} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
|
|
30945
31026
|
});
|
|
30946
31027
|
}
|
|
@@ -31022,14 +31103,14 @@ function createDocumentStub(ctx) {
|
|
|
31022
31103
|
ctx.storage.write(risksPath, riskMeta, content);
|
|
31023
31104
|
return `Document "${title}" created at risks.md (workspace root).`;
|
|
31024
31105
|
}
|
|
31025
|
-
const
|
|
31106
|
+
const path40 = workspaceArtifact(ctx.rootDir, "docs", slug);
|
|
31026
31107
|
const meta3 = {
|
|
31027
31108
|
kind: "doc",
|
|
31028
31109
|
id: slug,
|
|
31029
31110
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
31030
31111
|
tags
|
|
31031
31112
|
};
|
|
31032
|
-
ctx.storage.write(
|
|
31113
|
+
ctx.storage.write(path40, meta3, content);
|
|
31033
31114
|
return `Document "${title}" created at docs/${slug}.md.`;
|
|
31034
31115
|
});
|
|
31035
31116
|
}
|
|
@@ -31573,10 +31654,10 @@ function getUserMcpPath() {
|
|
|
31573
31654
|
function getProjectMcpPath(projectRoot) {
|
|
31574
31655
|
return join24(projectRoot, ".zelari", "mcp.json");
|
|
31575
31656
|
}
|
|
31576
|
-
function readFile2(
|
|
31577
|
-
if (!existsSync26(
|
|
31657
|
+
function readFile2(path40) {
|
|
31658
|
+
if (!existsSync26(path40)) return {};
|
|
31578
31659
|
try {
|
|
31579
|
-
const parsed = JSON.parse(readFileSync22(
|
|
31660
|
+
const parsed = JSON.parse(readFileSync22(path40, "utf8"));
|
|
31580
31661
|
const out = {};
|
|
31581
31662
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
31582
31663
|
if (!cfg || typeof cfg.command !== "string" || !cfg.command.trim()) continue;
|
|
@@ -31592,10 +31673,10 @@ function readFile2(path38) {
|
|
|
31592
31673
|
return {};
|
|
31593
31674
|
}
|
|
31594
31675
|
}
|
|
31595
|
-
function writeFile(
|
|
31596
|
-
mkdirSync11(dirname6(
|
|
31676
|
+
function writeFile(path40, servers) {
|
|
31677
|
+
mkdirSync11(dirname6(path40), { recursive: true });
|
|
31597
31678
|
const body = { mcpServers: servers };
|
|
31598
|
-
writeFileSync15(
|
|
31679
|
+
writeFileSync15(path40, `${JSON.stringify(body, null, 2)}
|
|
31599
31680
|
`, "utf8");
|
|
31600
31681
|
}
|
|
31601
31682
|
function listMcpServers(projectRoot) {
|
|
@@ -31628,9 +31709,9 @@ function upsertMcpServer(opts) {
|
|
|
31628
31709
|
if (!opts.config.command?.trim()) {
|
|
31629
31710
|
return { ok: false, error: "command is required" };
|
|
31630
31711
|
}
|
|
31631
|
-
let
|
|
31712
|
+
let path40;
|
|
31632
31713
|
if (opts.scope === "user") {
|
|
31633
|
-
|
|
31714
|
+
path40 = getUserMcpPath();
|
|
31634
31715
|
} else {
|
|
31635
31716
|
const root = opts.projectRoot?.trim();
|
|
31636
31717
|
if (!root) {
|
|
@@ -31639,30 +31720,30 @@ function upsertMcpServer(opts) {
|
|
|
31639
31720
|
error: "projectRoot required for project scope (Open Folder first)"
|
|
31640
31721
|
};
|
|
31641
31722
|
}
|
|
31642
|
-
|
|
31723
|
+
path40 = getProjectMcpPath(root);
|
|
31643
31724
|
}
|
|
31644
|
-
const current = readFile2(
|
|
31725
|
+
const current = readFile2(path40);
|
|
31645
31726
|
current[name] = {
|
|
31646
31727
|
command: opts.config.command.trim(),
|
|
31647
31728
|
args: opts.config.args,
|
|
31648
31729
|
env: opts.config.env,
|
|
31649
31730
|
enabled: opts.config.enabled !== false
|
|
31650
31731
|
};
|
|
31651
|
-
writeFile(
|
|
31652
|
-
return { ok: true, path:
|
|
31732
|
+
writeFile(path40, current);
|
|
31733
|
+
return { ok: true, path: path40 };
|
|
31653
31734
|
}
|
|
31654
31735
|
function removeMcpServer(opts) {
|
|
31655
|
-
const
|
|
31656
|
-
if (!
|
|
31736
|
+
const path40 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
|
|
31737
|
+
if (!path40) {
|
|
31657
31738
|
return { ok: false, error: "projectRoot required for project scope" };
|
|
31658
31739
|
}
|
|
31659
|
-
const current = readFile2(
|
|
31740
|
+
const current = readFile2(path40);
|
|
31660
31741
|
if (!(opts.name in current)) {
|
|
31661
|
-
return { ok: false, error: `Server "${opts.name}" not found in ${
|
|
31742
|
+
return { ok: false, error: `Server "${opts.name}" not found in ${path40}` };
|
|
31662
31743
|
}
|
|
31663
31744
|
delete current[opts.name];
|
|
31664
|
-
writeFile(
|
|
31665
|
-
return { ok: true, path:
|
|
31745
|
+
writeFile(path40, current);
|
|
31746
|
+
return { ok: true, path: path40 };
|
|
31666
31747
|
}
|
|
31667
31748
|
var init_mcpConfigIo = __esm({
|
|
31668
31749
|
"src/cli/mcp/mcpConfigIo.ts"() {
|
|
@@ -31999,10 +32080,10 @@ import { createHash as createHash5 } from "node:crypto";
|
|
|
31999
32080
|
import { join as join26 } from "node:path";
|
|
32000
32081
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
32001
32082
|
async function readPackageJson2(projectRoot) {
|
|
32002
|
-
const
|
|
32003
|
-
if (!existsSync28(
|
|
32083
|
+
const path40 = join26(projectRoot, "package.json");
|
|
32084
|
+
if (!existsSync28(path40)) return null;
|
|
32004
32085
|
try {
|
|
32005
|
-
return JSON.parse(await readFile3(
|
|
32086
|
+
return JSON.parse(await readFile3(path40, "utf8"));
|
|
32006
32087
|
} catch {
|
|
32007
32088
|
return null;
|
|
32008
32089
|
}
|
|
@@ -32084,9 +32165,9 @@ async function genBuild(ctx) {
|
|
|
32084
32165
|
].join("\n");
|
|
32085
32166
|
}
|
|
32086
32167
|
async function genOpenQuestions(ctx) {
|
|
32087
|
-
const
|
|
32088
|
-
if (!existsSync28(
|
|
32089
|
-
const content = readFileSync24(
|
|
32168
|
+
const path40 = join26(ctx.rootDir, "risks.md");
|
|
32169
|
+
if (!existsSync28(path40)) return "_No open questions._";
|
|
32170
|
+
const content = readFileSync24(path40, "utf8");
|
|
32090
32171
|
const lines = content.split("\n");
|
|
32091
32172
|
const questions = [];
|
|
32092
32173
|
let currentTitle = "";
|
|
@@ -32653,8 +32734,8 @@ async function runPostCouncilHook(ctx, options) {
|
|
|
32653
32734
|
sources: scope.sources
|
|
32654
32735
|
} : void 0
|
|
32655
32736
|
});
|
|
32656
|
-
const
|
|
32657
|
-
completionHook = { ran: true, path:
|
|
32737
|
+
const path40 = writeCouncilCompletion(ctx.rootDir, completion);
|
|
32738
|
+
completionHook = { ran: true, path: path40, completion };
|
|
32658
32739
|
} catch (err) {
|
|
32659
32740
|
completionHook = {
|
|
32660
32741
|
ran: true,
|
|
@@ -33211,18 +33292,49 @@ var init_fileBackend = __esm({
|
|
|
33211
33292
|
}
|
|
33212
33293
|
});
|
|
33213
33294
|
|
|
33295
|
+
// src/cli/traceStore.ts
|
|
33296
|
+
import { promises as fs17 } from "node:fs";
|
|
33297
|
+
import * as path29 from "node:path";
|
|
33298
|
+
function traceDir(projectRoot) {
|
|
33299
|
+
return path29.join(projectRoot, ".zelari", "trace");
|
|
33300
|
+
}
|
|
33301
|
+
function tracePath(projectRoot, missionId) {
|
|
33302
|
+
return path29.join(traceDir(projectRoot), `${missionId}.json`);
|
|
33303
|
+
}
|
|
33304
|
+
async function saveTrace(projectRoot, missionId, entries) {
|
|
33305
|
+
const dir = traceDir(projectRoot);
|
|
33306
|
+
await fs17.mkdir(dir, { recursive: true });
|
|
33307
|
+
const payload = {
|
|
33308
|
+
missionId,
|
|
33309
|
+
ts: Date.now(),
|
|
33310
|
+
entries
|
|
33311
|
+
};
|
|
33312
|
+
await fs17.writeFile(
|
|
33313
|
+
tracePath(projectRoot, missionId),
|
|
33314
|
+
JSON.stringify(payload, null, 2) + "\n",
|
|
33315
|
+
"utf8"
|
|
33316
|
+
);
|
|
33317
|
+
}
|
|
33318
|
+
var init_traceStore = __esm({
|
|
33319
|
+
"src/cli/traceStore.ts"() {
|
|
33320
|
+
"use strict";
|
|
33321
|
+
}
|
|
33322
|
+
});
|
|
33323
|
+
|
|
33214
33324
|
// src/cli/zelariMission.ts
|
|
33215
33325
|
var zelariMission_exports = {};
|
|
33216
33326
|
__export(zelariMission_exports, {
|
|
33217
33327
|
formatBriefForChat: () => formatBriefForChat,
|
|
33218
33328
|
isMissionAutoStart: () => isMissionAutoStart,
|
|
33329
|
+
resolveMaxCost: () => resolveMaxCost,
|
|
33219
33330
|
resolveMaxIterations: () => resolveMaxIterations,
|
|
33220
33331
|
resolveMaxStall: () => resolveMaxStall,
|
|
33332
|
+
resolveMaxTokens: () => resolveMaxTokens,
|
|
33221
33333
|
runZelariMission: () => runZelariMission
|
|
33222
33334
|
});
|
|
33223
33335
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
33224
|
-
import { promises as
|
|
33225
|
-
import * as
|
|
33336
|
+
import { promises as fs18 } from "node:fs";
|
|
33337
|
+
import * as path30 from "node:path";
|
|
33226
33338
|
function resolveMaxIterations(env = process.env) {
|
|
33227
33339
|
const raw = env.ZELARI_MISSION_MAX_ITER;
|
|
33228
33340
|
const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
|
|
@@ -33234,17 +33346,35 @@ function resolveMaxStall(env = process.env) {
|
|
|
33234
33346
|
const n = Number.parseInt(raw, 10);
|
|
33235
33347
|
return Number.isFinite(n) && n >= 0 ? n : DEFAULT_MAX_STALL;
|
|
33236
33348
|
}
|
|
33349
|
+
function resolveMaxCost(env = process.env) {
|
|
33350
|
+
const raw = env.ZELARI_MISSION_MAX_COST;
|
|
33351
|
+
if (!raw) return void 0;
|
|
33352
|
+
const n = Number.parseFloat(raw);
|
|
33353
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
33354
|
+
}
|
|
33355
|
+
function resolveMaxTokens(env = process.env) {
|
|
33356
|
+
const raw = env.ZELARI_MISSION_MAX_TOKENS;
|
|
33357
|
+
if (!raw) return void 0;
|
|
33358
|
+
const n = Number.parseInt(raw, 10);
|
|
33359
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
33360
|
+
}
|
|
33237
33361
|
function isMissionAutoStart(env = process.env) {
|
|
33238
33362
|
return env.ZELARI_MISSION_AUTO === "1";
|
|
33239
33363
|
}
|
|
33240
33364
|
async function writeMissionState(projectRoot, state2) {
|
|
33241
|
-
const dir =
|
|
33242
|
-
await
|
|
33243
|
-
await
|
|
33244
|
-
|
|
33365
|
+
const dir = path30.join(projectRoot, ".zelari");
|
|
33366
|
+
await fs18.mkdir(dir, { recursive: true });
|
|
33367
|
+
await fs18.writeFile(
|
|
33368
|
+
path30.join(dir, "mission-state.json"),
|
|
33245
33369
|
JSON.stringify(state2, null, 2) + "\n",
|
|
33246
33370
|
"utf8"
|
|
33247
33371
|
);
|
|
33372
|
+
if (state2.trace?.length) {
|
|
33373
|
+
try {
|
|
33374
|
+
await saveTrace(projectRoot, state2.missionId, state2.trace);
|
|
33375
|
+
} catch {
|
|
33376
|
+
}
|
|
33377
|
+
}
|
|
33248
33378
|
}
|
|
33249
33379
|
function buildSlicePrompt(brief, userMessage, runMode, iteration) {
|
|
33250
33380
|
if (runMode === "design-phase") {
|
|
@@ -33282,6 +33412,8 @@ async function runZelariMission(userMessage, brief, deps) {
|
|
|
33282
33412
|
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
33283
33413
|
const maxIter = deps.maxIterations ?? resolveMaxIterations(deps.env);
|
|
33284
33414
|
const maxStall = resolveMaxStall(deps.env);
|
|
33415
|
+
const maxCost = resolveMaxCost(deps.env);
|
|
33416
|
+
const maxTokens = resolveMaxTokens(deps.env);
|
|
33285
33417
|
const missionId = deps.missionId ?? `m_${randomUUID5().slice(0, 8)}`;
|
|
33286
33418
|
const startedAt = now().toISOString();
|
|
33287
33419
|
const state2 = {
|
|
@@ -33317,6 +33449,8 @@ async function runZelariMission(userMessage, brief, deps) {
|
|
|
33317
33449
|
let step = 0;
|
|
33318
33450
|
let implStep = 0;
|
|
33319
33451
|
let pendingDesign = designFirst;
|
|
33452
|
+
let cumulativeCostUsd = 0;
|
|
33453
|
+
let cumulativeTokens = 0;
|
|
33320
33454
|
while (true) {
|
|
33321
33455
|
const runMode = pendingDesign ? "design-phase" : "implementation";
|
|
33322
33456
|
if (runMode === "implementation") {
|
|
@@ -33333,6 +33467,8 @@ async function runZelariMission(userMessage, brief, deps) {
|
|
|
33333
33467
|
const promptIter = runMode === "implementation" ? implStep : 1;
|
|
33334
33468
|
const slicePrompt = buildSlicePrompt(brief, userMessage, runMode, promptIter);
|
|
33335
33469
|
const implementerRetry = runMode === "implementation" && implStep > 1;
|
|
33470
|
+
const sliceStartedAt = now().toISOString();
|
|
33471
|
+
const sliceStartMs = now().getTime();
|
|
33336
33472
|
if (runMode === "design-phase") {
|
|
33337
33473
|
deps.emit(
|
|
33338
33474
|
`[zelari] design-phase (fuori budget) \xB7 step ${step} \xB7 slice ${brief.sliceMvp.id}`
|
|
@@ -33369,6 +33505,8 @@ async function runZelariMission(userMessage, brief, deps) {
|
|
|
33369
33505
|
);
|
|
33370
33506
|
return state2;
|
|
33371
33507
|
}
|
|
33508
|
+
if (typeof result.costUsd === "number") cumulativeCostUsd += result.costUsd;
|
|
33509
|
+
if (typeof result.costTokens === "number") cumulativeTokens += result.costTokens;
|
|
33372
33510
|
await deps.memory.add(
|
|
33373
33511
|
JSON.stringify({
|
|
33374
33512
|
iteration: step,
|
|
@@ -33394,6 +33532,20 @@ async function runZelariMission(userMessage, brief, deps) {
|
|
|
33394
33532
|
}
|
|
33395
33533
|
state2.lastCompletionOk = completionOk;
|
|
33396
33534
|
state2.updatedAt = now().toISOString();
|
|
33535
|
+
state2.cumulativeCostUsd = cumulativeCostUsd;
|
|
33536
|
+
state2.cumulativeTokens = cumulativeTokens;
|
|
33537
|
+
if (!state2.trace) state2.trace = [];
|
|
33538
|
+
state2.trace.push({
|
|
33539
|
+
sliceId: brief.sliceMvp.id,
|
|
33540
|
+
iteration: step,
|
|
33541
|
+
runMode,
|
|
33542
|
+
completionOk,
|
|
33543
|
+
degraded: result.degraded,
|
|
33544
|
+
costTokens: typeof result.costTokens === "number" ? result.costTokens : void 0,
|
|
33545
|
+
costUsd: typeof result.costUsd === "number" ? result.costUsd : void 0,
|
|
33546
|
+
startedAt: sliceStartedAt,
|
|
33547
|
+
durationMs: now().getTime() - sliceStartMs
|
|
33548
|
+
});
|
|
33397
33549
|
if (runMode === "design-phase") {
|
|
33398
33550
|
pendingDesign = false;
|
|
33399
33551
|
await writeMissionState(deps.projectRoot, state2);
|
|
@@ -33457,6 +33609,16 @@ async function runZelariMission(userMessage, brief, deps) {
|
|
|
33457
33609
|
return state2;
|
|
33458
33610
|
}
|
|
33459
33611
|
}
|
|
33612
|
+
if (maxCost !== void 0 && cumulativeCostUsd >= maxCost || maxTokens !== void 0 && cumulativeTokens >= maxTokens) {
|
|
33613
|
+
state2.status = "stopped";
|
|
33614
|
+
state2.updatedAt = now().toISOString();
|
|
33615
|
+
await writeMissionState(deps.projectRoot, state2);
|
|
33616
|
+
const reason = maxCost !== void 0 && cumulativeCostUsd >= maxCost ? `budget USD ${formatCost(cumulativeCostUsd)} \u2265 ${formatCost(maxCost)}` : `token ${formatTokens(cumulativeTokens)} \u2265 ${formatTokens(maxTokens)}`;
|
|
33617
|
+
deps.emit(
|
|
33618
|
+
`[zelari] fermata: ${reason}. Imposta ZELARI_MISSION_MAX_COST / ZELARI_MISSION_MAX_TOKENS pi\xF9 alto, o usa un modello pi\xF9 economico. Stato salvato in .zelari/mission-state.json`
|
|
33619
|
+
);
|
|
33620
|
+
return state2;
|
|
33621
|
+
}
|
|
33460
33622
|
await writeMissionState(deps.projectRoot, state2);
|
|
33461
33623
|
}
|
|
33462
33624
|
state2.status = "stopped";
|
|
@@ -33475,6 +33637,8 @@ var init_zelariMission = __esm({
|
|
|
33475
33637
|
init_checkpointManager();
|
|
33476
33638
|
init_fileStateStore();
|
|
33477
33639
|
init_commitHelpers();
|
|
33640
|
+
init_modelPricing();
|
|
33641
|
+
init_traceStore();
|
|
33478
33642
|
DEFAULT_MAX_ITER = 6;
|
|
33479
33643
|
DEFAULT_MAX_STALL = 2;
|
|
33480
33644
|
}
|
|
@@ -33632,6 +33796,8 @@ async function runAgentMissionSlice(deps) {
|
|
|
33632
33796
|
});
|
|
33633
33797
|
let text = "";
|
|
33634
33798
|
let errored2 = false;
|
|
33799
|
+
let promptTokens = 0;
|
|
33800
|
+
let completionTokens = 0;
|
|
33635
33801
|
try {
|
|
33636
33802
|
for await (const event of harness.run()) {
|
|
33637
33803
|
counter.onEvent(event);
|
|
@@ -33642,6 +33808,11 @@ async function runAgentMissionSlice(deps) {
|
|
|
33642
33808
|
if (event.type === "agent_end" && event.reason === "error") {
|
|
33643
33809
|
errored2 = true;
|
|
33644
33810
|
}
|
|
33811
|
+
if (event.type === "message_end" && event.usage) {
|
|
33812
|
+
const u = event.usage;
|
|
33813
|
+
promptTokens += u.promptTokens ?? 0;
|
|
33814
|
+
completionTokens += u.completionTokens ?? 0;
|
|
33815
|
+
}
|
|
33645
33816
|
if (event.type === "error" && event.severity === "fatal") {
|
|
33646
33817
|
errored2 = true;
|
|
33647
33818
|
}
|
|
@@ -33664,7 +33835,9 @@ async function runAgentMissionSlice(deps) {
|
|
|
33664
33835
|
successfulWrites: counter.state.successfulWrites,
|
|
33665
33836
|
emittedWrites: counter.state.emittedWrites,
|
|
33666
33837
|
errored: errored2,
|
|
33667
|
-
messages: harness.getMessages()
|
|
33838
|
+
messages: harness.getMessages(),
|
|
33839
|
+
promptTokens,
|
|
33840
|
+
completionTokens
|
|
33668
33841
|
};
|
|
33669
33842
|
}
|
|
33670
33843
|
const initial = [
|
|
@@ -33676,6 +33849,8 @@ async function runAgentMissionSlice(deps) {
|
|
|
33676
33849
|
let totalEmitted = pass.emittedWrites;
|
|
33677
33850
|
let synthesisText = pass.text;
|
|
33678
33851
|
let errored = pass.errored;
|
|
33852
|
+
let totalPromptTokens = pass.promptTokens;
|
|
33853
|
+
let totalCompletionTokens = pass.completionTokens;
|
|
33679
33854
|
if (writeRetry && totalWrites === 0 && !errored) {
|
|
33680
33855
|
deps.emit?.(
|
|
33681
33856
|
"[zelari] build@agent: 0 write \u2014 forcing implementation retry"
|
|
@@ -33695,6 +33870,8 @@ async function runAgentMissionSlice(deps) {
|
|
|
33695
33870
|
${retry.text}` : retry.text;
|
|
33696
33871
|
}
|
|
33697
33872
|
errored = errored || retry.errored;
|
|
33873
|
+
totalPromptTokens += retry.promptTokens;
|
|
33874
|
+
totalCompletionTokens += retry.completionTokens;
|
|
33698
33875
|
}
|
|
33699
33876
|
const cleaned = cleanAgentContent(synthesisText, {
|
|
33700
33877
|
stripQuestion: false,
|
|
@@ -33741,12 +33918,16 @@ ${retry.text}` : retry.text;
|
|
|
33741
33918
|
else degraded = true;
|
|
33742
33919
|
}
|
|
33743
33920
|
void totalEmitted;
|
|
33921
|
+
const costTokens = totalPromptTokens + totalCompletionTokens;
|
|
33922
|
+
const costUsd = calculateCost(deps.model, totalPromptTokens, totalCompletionTokens);
|
|
33744
33923
|
return {
|
|
33745
33924
|
completionOk,
|
|
33746
33925
|
ran: true,
|
|
33747
33926
|
synthesisText: cleaned || void 0,
|
|
33748
33927
|
writeCount: totalWrites,
|
|
33749
|
-
degraded
|
|
33928
|
+
degraded,
|
|
33929
|
+
costTokens,
|
|
33930
|
+
costUsd
|
|
33750
33931
|
};
|
|
33751
33932
|
}
|
|
33752
33933
|
var MUTATING, AGENT_MISSION_IMPLEMENTER_PREAMBLE;
|
|
@@ -33759,6 +33940,7 @@ var init_missionSlice = __esm({
|
|
|
33759
33940
|
init_dist();
|
|
33760
33941
|
init_buildPolicy();
|
|
33761
33942
|
init_envNumber();
|
|
33943
|
+
init_modelPricing();
|
|
33762
33944
|
MUTATING = /* @__PURE__ */ new Set(["write_file", "edit_file", "apply_diff"]);
|
|
33763
33945
|
AGENT_MISSION_IMPLEMENTER_PREAMBLE = "You are the sole implementer for this Zelari mission slice. A multi-agent council may already have produced a plan under `.zelari/` \u2014 treat it as a SPEC to apply on disk. You MUST create or modify real project files with write_file / edit_file. Prose without successful writes is a failed slice.";
|
|
33764
33946
|
}
|
|
@@ -34148,10 +34330,10 @@ var init_prereqChecks = __esm({
|
|
|
34148
34330
|
|
|
34149
34331
|
// src/cli/plugins/prefs.ts
|
|
34150
34332
|
import { existsSync as existsSync33, readFileSync as readFileSync28, writeFileSync as writeFileSync18, mkdirSync as mkdirSync13 } from "node:fs";
|
|
34151
|
-
import
|
|
34333
|
+
import path32 from "node:path";
|
|
34152
34334
|
import os9 from "node:os";
|
|
34153
34335
|
function getPluginPrefsPath() {
|
|
34154
|
-
return process.env.ZELARI_PLUGINS_PREFS_FILE ??
|
|
34336
|
+
return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path32.join(os9.homedir(), ".tmp", "zelari-code", "plugins.json");
|
|
34155
34337
|
}
|
|
34156
34338
|
function getPluginPrefs() {
|
|
34157
34339
|
const file2 = getPluginPrefsPath();
|
|
@@ -34172,7 +34354,7 @@ function getPluginPrefs() {
|
|
|
34172
34354
|
}
|
|
34173
34355
|
function writePluginPrefs(prefs) {
|
|
34174
34356
|
const file2 = getPluginPrefsPath();
|
|
34175
|
-
mkdirSync13(
|
|
34357
|
+
mkdirSync13(path32.dirname(file2), { recursive: true });
|
|
34176
34358
|
writeFileSync18(file2, JSON.stringify(prefs, null, 2), {
|
|
34177
34359
|
encoding: "utf-8",
|
|
34178
34360
|
mode: 384
|
|
@@ -34209,7 +34391,7 @@ __export(registry_exports, {
|
|
|
34209
34391
|
isBinaryOnPath: () => isBinaryOnPath
|
|
34210
34392
|
});
|
|
34211
34393
|
import { existsSync as existsSync34 } from "node:fs";
|
|
34212
|
-
import
|
|
34394
|
+
import path33 from "node:path";
|
|
34213
34395
|
function detectLocalBin(bin) {
|
|
34214
34396
|
return (cwd) => {
|
|
34215
34397
|
try {
|
|
@@ -34227,7 +34409,7 @@ function isBinaryOnPath(bin, opts = {}) {
|
|
|
34227
34409
|
const platform = opts.platform ?? process.platform;
|
|
34228
34410
|
const exists = opts.exists ?? existsSync34;
|
|
34229
34411
|
const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
|
|
34230
|
-
const pathMod = platform === "win32" ?
|
|
34412
|
+
const pathMod = platform === "win32" ? path33.win32 : path33.posix;
|
|
34231
34413
|
const sep = platform === "win32" ? ";" : ":";
|
|
34232
34414
|
const dirs = pathEnv.split(sep).filter((d) => d.length > 0);
|
|
34233
34415
|
const candidates = [bin];
|
|
@@ -34357,6 +34539,59 @@ var init_registry2 = __esm({
|
|
|
34357
34539
|
}
|
|
34358
34540
|
});
|
|
34359
34541
|
|
|
34542
|
+
// src/cli/triggerLock.ts
|
|
34543
|
+
var triggerLock_exports = {};
|
|
34544
|
+
__export(triggerLock_exports, {
|
|
34545
|
+
acquireLock: () => acquireLock,
|
|
34546
|
+
lockPath: () => lockPath,
|
|
34547
|
+
releaseLock: () => releaseLock
|
|
34548
|
+
});
|
|
34549
|
+
import { promises as fs23 } from "node:fs";
|
|
34550
|
+
import * as path38 from "node:path";
|
|
34551
|
+
function lockPath(projectRoot) {
|
|
34552
|
+
return path38.join(projectRoot, ".zelari", "trigger.lock");
|
|
34553
|
+
}
|
|
34554
|
+
function isPidAlive(pid) {
|
|
34555
|
+
try {
|
|
34556
|
+
process.kill(pid, 0);
|
|
34557
|
+
return true;
|
|
34558
|
+
} catch (err) {
|
|
34559
|
+
const code = err.code;
|
|
34560
|
+
return code === "EPERM";
|
|
34561
|
+
}
|
|
34562
|
+
}
|
|
34563
|
+
async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
|
|
34564
|
+
const lp = lockPath(projectRoot);
|
|
34565
|
+
const dir = path38.dirname(lp);
|
|
34566
|
+
await fs23.mkdir(dir, { recursive: true });
|
|
34567
|
+
try {
|
|
34568
|
+
const raw = await fs23.readFile(lp, "utf8");
|
|
34569
|
+
const existing = JSON.parse(raw);
|
|
34570
|
+
if (existing.pid && isPidAlive(existing.pid)) {
|
|
34571
|
+
return { acquired: false, heldBy: existing.pid, lockPath: lp };
|
|
34572
|
+
}
|
|
34573
|
+
} catch {
|
|
34574
|
+
}
|
|
34575
|
+
const payload = {
|
|
34576
|
+
pid: process.pid,
|
|
34577
|
+
acquiredAt: now().toISOString()
|
|
34578
|
+
};
|
|
34579
|
+
await fs23.writeFile(lp, JSON.stringify(payload, null, 2) + "\n", "utf8");
|
|
34580
|
+
return { acquired: true, lockPath: lp };
|
|
34581
|
+
}
|
|
34582
|
+
async function releaseLock(projectRoot) {
|
|
34583
|
+
const lp = lockPath(projectRoot);
|
|
34584
|
+
try {
|
|
34585
|
+
await fs23.unlink(lp);
|
|
34586
|
+
} catch {
|
|
34587
|
+
}
|
|
34588
|
+
}
|
|
34589
|
+
var init_triggerLock = __esm({
|
|
34590
|
+
"src/cli/triggerLock.ts"() {
|
|
34591
|
+
"use strict";
|
|
34592
|
+
}
|
|
34593
|
+
});
|
|
34594
|
+
|
|
34360
34595
|
// src/cli/utils/doctor.ts
|
|
34361
34596
|
var doctor_exports = {};
|
|
34362
34597
|
__export(doctor_exports, {
|
|
@@ -34366,11 +34601,11 @@ import { execSync as execSync2 } from "node:child_process";
|
|
|
34366
34601
|
import { existsSync as existsSync38, readFileSync as readFileSync31, readlinkSync, statSync as statSync6 } from "node:fs";
|
|
34367
34602
|
import { createRequire as createRequire3 } from "node:module";
|
|
34368
34603
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
34369
|
-
import
|
|
34604
|
+
import path39 from "node:path";
|
|
34370
34605
|
function findPackageRoot(start) {
|
|
34371
34606
|
let dir = start;
|
|
34372
34607
|
for (let i = 0; i < 6; i += 1) {
|
|
34373
|
-
const candidate =
|
|
34608
|
+
const candidate = path39.join(dir, "package.json");
|
|
34374
34609
|
if (existsSync38(candidate)) {
|
|
34375
34610
|
try {
|
|
34376
34611
|
const pkg = JSON.parse(readFileSync31(candidate, "utf8"));
|
|
@@ -34378,11 +34613,11 @@ function findPackageRoot(start) {
|
|
|
34378
34613
|
} catch {
|
|
34379
34614
|
}
|
|
34380
34615
|
}
|
|
34381
|
-
const parent =
|
|
34616
|
+
const parent = path39.dirname(dir);
|
|
34382
34617
|
if (parent === dir) break;
|
|
34383
34618
|
dir = parent;
|
|
34384
34619
|
}
|
|
34385
|
-
return
|
|
34620
|
+
return path39.resolve(__dirname3, "..", "..", "..");
|
|
34386
34621
|
}
|
|
34387
34622
|
function tryExec(cmd) {
|
|
34388
34623
|
try {
|
|
@@ -34396,7 +34631,7 @@ function tryExec(cmd) {
|
|
|
34396
34631
|
}
|
|
34397
34632
|
function readPackageJson3() {
|
|
34398
34633
|
try {
|
|
34399
|
-
const pkgPath =
|
|
34634
|
+
const pkgPath = path39.join(packageRoot, "package.json");
|
|
34400
34635
|
return JSON.parse(readFileSync31(pkgPath, "utf8"));
|
|
34401
34636
|
} catch {
|
|
34402
34637
|
return null;
|
|
@@ -34412,7 +34647,7 @@ function checkShim(pkgName) {
|
|
|
34412
34647
|
}
|
|
34413
34648
|
const isWin = process.platform === "win32";
|
|
34414
34649
|
const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
|
|
34415
|
-
const shimPath =
|
|
34650
|
+
const shimPath = path39.join(prefix, shimName);
|
|
34416
34651
|
if (!existsSync38(shimPath)) {
|
|
34417
34652
|
return FAIL(
|
|
34418
34653
|
`shim not found at ${shimPath}
|
|
@@ -34440,8 +34675,8 @@ function checkShim(pkgName) {
|
|
|
34440
34675
|
fix: npm install -g ${pkgName}@latest --force`
|
|
34441
34676
|
);
|
|
34442
34677
|
}
|
|
34443
|
-
const resolved =
|
|
34444
|
-
const expected =
|
|
34678
|
+
const resolved = path39.resolve(path39.dirname(shimPath), target);
|
|
34679
|
+
const expected = path39.join(
|
|
34445
34680
|
prefix,
|
|
34446
34681
|
"node_modules",
|
|
34447
34682
|
pkgName,
|
|
@@ -34480,7 +34715,7 @@ function checkNode(pkg) {
|
|
|
34480
34715
|
return OK(`node ${raw}`);
|
|
34481
34716
|
}
|
|
34482
34717
|
function checkBundle() {
|
|
34483
|
-
const bundle =
|
|
34718
|
+
const bundle = path39.join(packageRoot, "dist", "cli", "main.bundled.js");
|
|
34484
34719
|
if (!existsSync38(bundle)) {
|
|
34485
34720
|
return FAIL(
|
|
34486
34721
|
`dist/cli/main.bundled.js missing at ${bundle}
|
|
@@ -34501,7 +34736,7 @@ function checkRuntimeDeps() {
|
|
|
34501
34736
|
const missing = [];
|
|
34502
34737
|
for (const dep of required2) {
|
|
34503
34738
|
try {
|
|
34504
|
-
const localReq = createRequire3(
|
|
34739
|
+
const localReq = createRequire3(path39.join(packageRoot, "package.json"));
|
|
34505
34740
|
localReq.resolve(dep);
|
|
34506
34741
|
} catch {
|
|
34507
34742
|
missing.push(dep);
|
|
@@ -34677,7 +34912,7 @@ var init_doctor = __esm({
|
|
|
34677
34912
|
"use strict";
|
|
34678
34913
|
init_prereqChecks();
|
|
34679
34914
|
require3 = createRequire3(import.meta.url);
|
|
34680
|
-
__dirname3 =
|
|
34915
|
+
__dirname3 = path39.dirname(fileURLToPath2(import.meta.url));
|
|
34681
34916
|
packageRoot = findPackageRoot(__dirname3);
|
|
34682
34917
|
OK = (message) => ({
|
|
34683
34918
|
ok: true,
|
|
@@ -35285,83 +35520,7 @@ function StreamingTail(m) {
|
|
|
35285
35520
|
// src/cli/components/StatusBar.tsx
|
|
35286
35521
|
import React6 from "react";
|
|
35287
35522
|
import { Box as Box5, Text as Text6 } from "ink";
|
|
35288
|
-
|
|
35289
|
-
// src/cli/modelPricing.ts
|
|
35290
|
-
var PRICES_PER_MILLION = {
|
|
35291
|
-
// xAI Grok (list prices; grok-4.5 default reasoning_effort is "high")
|
|
35292
|
-
"grok-4.5": { input: 2, output: 6, cachedInput: 0.5 },
|
|
35293
|
-
"grok-4.3": { input: 1.25, output: 2.5, cachedInput: 0.2 },
|
|
35294
|
-
"grok-4": { input: 3, output: 15 },
|
|
35295
|
-
"grok-4-fast": { input: 0.2, output: 0.5 },
|
|
35296
|
-
"grok-3": { input: 3, output: 15 },
|
|
35297
|
-
"grok-3-mini": { input: 0.3, output: 0.5 },
|
|
35298
|
-
"grok-2-vision": { input: 2, output: 10 },
|
|
35299
|
-
// GLM / Z.AI
|
|
35300
|
-
"glm-4.6": { input: 0.6, output: 2.2 },
|
|
35301
|
-
"glm-4.5": { input: 0.5, output: 2 },
|
|
35302
|
-
"glm-4.5-air": { input: 0.1, output: 0.6 },
|
|
35303
|
-
"glm-z1": { input: 0.5, output: 2 },
|
|
35304
|
-
// MiniMax
|
|
35305
|
-
"MiniMax-M2.5": { input: 0.2, output: 1.1 },
|
|
35306
|
-
"MiniMax-M2": { input: 0.2, output: 1.1 },
|
|
35307
|
-
"MiniMax-M2-her": { input: 0.3, output: 1.2 },
|
|
35308
|
-
// DeepSeek (global platform) — estimated list prices; override via
|
|
35309
|
-
// ANATHEMA_PRICE_DEEPSEEK_V4_FLASH / ANATHEMA_PRICE_DEEPSEEK_V4_PRO.
|
|
35310
|
-
// DeepSeek prompt-cache hits are ~10× cheaper than a cache miss.
|
|
35311
|
-
"deepseek-v4-flash": { input: 0.14, output: 0.28, cachedInput: 0.014 },
|
|
35312
|
-
"deepseek-v4-pro": { input: 0.55, output: 2.19, cachedInput: 0.055 },
|
|
35313
|
-
// OpenAI (for openai-compatible fallback)
|
|
35314
|
-
"gpt-4o": { input: 2.5, output: 10 },
|
|
35315
|
-
"gpt-4o-mini": { input: 0.15, output: 0.6 },
|
|
35316
|
-
"gpt-4-turbo": { input: 10, output: 30 },
|
|
35317
|
-
"o1-preview": { input: 15, output: 60 },
|
|
35318
|
-
"o1-mini": { input: 3, output: 12 }
|
|
35319
|
-
};
|
|
35320
|
-
var DEFAULT_RATE = { input: 1, output: 3 };
|
|
35321
|
-
var DEFAULT_CACHE_DISCOUNT = 0.25;
|
|
35322
|
-
function envOverride(model) {
|
|
35323
|
-
const key = `ANATHEMA_PRICE_${model.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
|
|
35324
|
-
const raw = process.env[key] ?? process.env.ANATHEMA_PRICE_DEFAULT;
|
|
35325
|
-
return parseRateOverride(raw);
|
|
35326
|
-
}
|
|
35327
|
-
function parseRateOverride(raw) {
|
|
35328
|
-
if (!raw) return null;
|
|
35329
|
-
const [inStr, outStr] = raw.split("/");
|
|
35330
|
-
const input = Number.parseFloat(inStr);
|
|
35331
|
-
const output = outStr !== void 0 ? Number.parseFloat(outStr) : input;
|
|
35332
|
-
if (!Number.isFinite(input) || !Number.isFinite(output)) return null;
|
|
35333
|
-
return { input, output };
|
|
35334
|
-
}
|
|
35335
|
-
function getModelRate(model) {
|
|
35336
|
-
if (!model) return DEFAULT_RATE;
|
|
35337
|
-
return envOverride(model) ?? PRICES_PER_MILLION[model] ?? DEFAULT_RATE;
|
|
35338
|
-
}
|
|
35339
|
-
function calculateCost(model, promptTokens, completionTokens, cachedPromptTokens = 0) {
|
|
35340
|
-
if (!Number.isFinite(promptTokens) || promptTokens < 0) return 0;
|
|
35341
|
-
if (!Number.isFinite(completionTokens) || completionTokens < 0) return 0;
|
|
35342
|
-
const rate = getModelRate(model);
|
|
35343
|
-
const cached2 = Number.isFinite(cachedPromptTokens) && cachedPromptTokens > 0 ? Math.min(cachedPromptTokens, promptTokens) : 0;
|
|
35344
|
-
const uncachedPrompt = promptTokens - cached2;
|
|
35345
|
-
const cachedRate = rate.cachedInput ?? rate.input * DEFAULT_CACHE_DISCOUNT;
|
|
35346
|
-
const inputCost = uncachedPrompt / 1e6 * rate.input + cached2 / 1e6 * cachedRate;
|
|
35347
|
-
const outputCost = completionTokens / 1e6 * rate.output;
|
|
35348
|
-
return Number((inputCost + outputCost).toFixed(6));
|
|
35349
|
-
}
|
|
35350
|
-
function formatCost(usd) {
|
|
35351
|
-
if (!Number.isFinite(usd) || usd < 0) return "$0.0000";
|
|
35352
|
-
if (usd === 0) return "$0.0000";
|
|
35353
|
-
if (usd < 1e-4) return "<$0.0001";
|
|
35354
|
-
return `$${usd.toFixed(4)}`;
|
|
35355
|
-
}
|
|
35356
|
-
function formatTokens(tokens) {
|
|
35357
|
-
if (!Number.isFinite(tokens) || tokens < 0) return "0";
|
|
35358
|
-
if (tokens < 1e3) return `${tokens}`;
|
|
35359
|
-
if (tokens < 1e6) return `${(tokens / 1e3).toFixed(1)}k`;
|
|
35360
|
-
if (tokens < 1e9) return `${(tokens / 1e6).toFixed(2)}M`;
|
|
35361
|
-
return `${(tokens / 1e9).toFixed(2)}B`;
|
|
35362
|
-
}
|
|
35363
|
-
|
|
35364
|
-
// src/cli/components/StatusBar.tsx
|
|
35523
|
+
init_modelPricing();
|
|
35365
35524
|
function StatusBar({
|
|
35366
35525
|
model,
|
|
35367
35526
|
provider,
|
|
@@ -38705,6 +38864,9 @@ function finalizeStreamingAssistant(setMessages) {
|
|
|
38705
38864
|
// src/cli/hooks/useChatTurn.ts
|
|
38706
38865
|
init_conversationContext();
|
|
38707
38866
|
|
|
38867
|
+
// src/cli/hooks/chatStats.ts
|
|
38868
|
+
init_modelPricing();
|
|
38869
|
+
|
|
38708
38870
|
// src/cli/state/promptCacheStats.ts
|
|
38709
38871
|
function emptyPromptCacheStats() {
|
|
38710
38872
|
return {
|
|
@@ -40904,7 +41066,7 @@ ${formatSkillList(availableSkills)}`
|
|
|
40904
41066
|
// src/cli/gitOps.ts
|
|
40905
41067
|
import { execFile as execFile3 } from "node:child_process";
|
|
40906
41068
|
import { promisify as promisify2 } from "node:util";
|
|
40907
|
-
import
|
|
41069
|
+
import path31 from "node:path";
|
|
40908
41070
|
var execFileAsync2 = promisify2(execFile3);
|
|
40909
41071
|
async function git2(cwd, args) {
|
|
40910
41072
|
try {
|
|
@@ -40950,7 +41112,7 @@ async function undoWorkingChanges(opts = {}) {
|
|
|
40950
41112
|
};
|
|
40951
41113
|
}
|
|
40952
41114
|
function defaultProjectRoot() {
|
|
40953
|
-
return
|
|
41115
|
+
return path31.resolve(__dirname, "..", "..", "..");
|
|
40954
41116
|
}
|
|
40955
41117
|
|
|
40956
41118
|
// src/cli/slashHandlers/git.ts
|
|
@@ -41590,17 +41752,17 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
|
|
|
41590
41752
|
}
|
|
41591
41753
|
|
|
41592
41754
|
// src/cli/slashHandlers/promoteMember.ts
|
|
41593
|
-
import { promises as
|
|
41594
|
-
import
|
|
41755
|
+
import { promises as fs19 } from "node:fs";
|
|
41756
|
+
import path34 from "node:path";
|
|
41595
41757
|
import os10 from "node:os";
|
|
41596
41758
|
async function handlePromoteMember(ctx, memberId) {
|
|
41597
41759
|
try {
|
|
41598
41760
|
const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
41599
41761
|
const { skill, markdown } = promoteMember2(memberId);
|
|
41600
|
-
const skillDir = process.env.ANATHEMA_SKILL_DIR ??
|
|
41601
|
-
await
|
|
41602
|
-
const filePath =
|
|
41603
|
-
await
|
|
41762
|
+
const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path34.join(os10.homedir(), ".tmp", "zelari-code", "skills");
|
|
41763
|
+
await fs19.mkdir(skillDir, { recursive: true });
|
|
41764
|
+
const filePath = path34.join(skillDir, `${skill.id}.md`);
|
|
41765
|
+
await fs19.writeFile(filePath, markdown, "utf8");
|
|
41604
41766
|
appendSystem(
|
|
41605
41767
|
ctx.setMessages,
|
|
41606
41768
|
`[promote-member] ${skill.name} (${memberId}) \u2192 ${filePath}
|
|
@@ -41616,25 +41778,25 @@ async function handlePromoteMember(ctx, memberId) {
|
|
|
41616
41778
|
}
|
|
41617
41779
|
|
|
41618
41780
|
// src/cli/branchManager.ts
|
|
41619
|
-
import { promises as
|
|
41620
|
-
import
|
|
41781
|
+
import { promises as fs20, existsSync as existsSync35, readFileSync as readFileSync29, writeFileSync as writeFileSync19, mkdirSync as mkdirSync14, statSync as statSync4, rmSync as rmSync2 } from "node:fs";
|
|
41782
|
+
import path35 from "node:path";
|
|
41621
41783
|
import os11 from "node:os";
|
|
41622
41784
|
var META_FILENAME = "meta.json";
|
|
41623
41785
|
var SESSIONS_SUBDIR = "sessions";
|
|
41624
41786
|
function getBranchesBaseDir() {
|
|
41625
|
-
return process.env.ANATHEMA_BRANCHES_DIR ??
|
|
41787
|
+
return process.env.ANATHEMA_BRANCHES_DIR ?? path35.join(os11.homedir(), ".tmp", "zelari-code", "branches");
|
|
41626
41788
|
}
|
|
41627
41789
|
function getSessionsBaseDir() {
|
|
41628
|
-
return process.env.ANATHEMA_SESSIONS_DIR ??
|
|
41790
|
+
return process.env.ANATHEMA_SESSIONS_DIR ?? path35.join(os11.homedir(), ".tmp", "zelari-code", "sessions");
|
|
41629
41791
|
}
|
|
41630
41792
|
function branchPathFor(name, baseDir) {
|
|
41631
|
-
return
|
|
41793
|
+
return path35.join(baseDir, name);
|
|
41632
41794
|
}
|
|
41633
41795
|
function metaPathFor(name, baseDir) {
|
|
41634
|
-
return
|
|
41796
|
+
return path35.join(baseDir, name, META_FILENAME);
|
|
41635
41797
|
}
|
|
41636
41798
|
function sessionsPathFor(name, baseDir) {
|
|
41637
|
-
return
|
|
41799
|
+
return path35.join(baseDir, name, SESSIONS_SUBDIR);
|
|
41638
41800
|
}
|
|
41639
41801
|
function readBranchMeta(name, baseDir) {
|
|
41640
41802
|
const metaPath = metaPathFor(name, baseDir);
|
|
@@ -41659,13 +41821,13 @@ function readBranchMeta(name, baseDir) {
|
|
|
41659
41821
|
}
|
|
41660
41822
|
function writeBranchMeta(name, baseDir, meta3) {
|
|
41661
41823
|
const metaPath = metaPathFor(name, baseDir);
|
|
41662
|
-
mkdirSync14(
|
|
41824
|
+
mkdirSync14(path35.dirname(metaPath), { recursive: true });
|
|
41663
41825
|
writeFileSync19(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
|
|
41664
41826
|
}
|
|
41665
41827
|
async function countSessions(name, baseDir) {
|
|
41666
41828
|
const sessionsPath = sessionsPathFor(name, baseDir);
|
|
41667
41829
|
try {
|
|
41668
|
-
const entries = await
|
|
41830
|
+
const entries = await fs20.readdir(sessionsPath);
|
|
41669
41831
|
return entries.filter((e) => e.endsWith(".jsonl")).length;
|
|
41670
41832
|
} catch (err) {
|
|
41671
41833
|
if (err.code === "ENOENT") return 0;
|
|
@@ -41710,15 +41872,15 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
41710
41872
|
if (branchExists(name, baseDir)) {
|
|
41711
41873
|
throw new BranchAlreadyExistsError(name);
|
|
41712
41874
|
}
|
|
41713
|
-
const sourcePath =
|
|
41875
|
+
const sourcePath = path35.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
|
|
41714
41876
|
if (!existsSync35(sourcePath)) {
|
|
41715
41877
|
throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
|
|
41716
41878
|
}
|
|
41717
41879
|
const branchPath = branchPathFor(name, baseDir);
|
|
41718
41880
|
const branchSessionsPath = sessionsPathFor(name, baseDir);
|
|
41719
41881
|
mkdirSync14(branchSessionsPath, { recursive: true });
|
|
41720
|
-
const destPath =
|
|
41721
|
-
await
|
|
41882
|
+
const destPath = path35.join(branchSessionsPath, `${fromSessionId}.jsonl`);
|
|
41883
|
+
await fs20.copyFile(sourcePath, destPath);
|
|
41722
41884
|
const meta3 = {
|
|
41723
41885
|
name,
|
|
41724
41886
|
createdAt: Date.now(),
|
|
@@ -41736,7 +41898,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
41736
41898
|
async function listBranches(baseDir = getBranchesBaseDir()) {
|
|
41737
41899
|
let entries;
|
|
41738
41900
|
try {
|
|
41739
|
-
entries = await
|
|
41901
|
+
entries = await fs20.readdir(baseDir);
|
|
41740
41902
|
} catch (err) {
|
|
41741
41903
|
if (err.code === "ENOENT") return [];
|
|
41742
41904
|
throw err;
|
|
@@ -41817,26 +41979,26 @@ async function handleBranchCheckout(ctx, branchName) {
|
|
|
41817
41979
|
}
|
|
41818
41980
|
|
|
41819
41981
|
// src/cli/slashHandlers/workspace.ts
|
|
41820
|
-
import { promises as
|
|
41821
|
-
import
|
|
41982
|
+
import { promises as fs21 } from "node:fs";
|
|
41983
|
+
import path36 from "node:path";
|
|
41822
41984
|
async function handleWorkspaceShow(ctx, what) {
|
|
41823
41985
|
try {
|
|
41824
|
-
const zelari =
|
|
41986
|
+
const zelari = path36.join(process.cwd(), ".zelari");
|
|
41825
41987
|
let content;
|
|
41826
41988
|
switch (what) {
|
|
41827
41989
|
case "plan": {
|
|
41828
|
-
const planPath =
|
|
41990
|
+
const planPath = path36.join(zelari, "plan.md");
|
|
41829
41991
|
try {
|
|
41830
|
-
content = await
|
|
41992
|
+
content = await fs21.readFile(planPath, "utf-8");
|
|
41831
41993
|
} catch {
|
|
41832
41994
|
content = "(no plan.md yet \u2014 run a council session first)";
|
|
41833
41995
|
}
|
|
41834
41996
|
break;
|
|
41835
41997
|
}
|
|
41836
41998
|
case "decisions": {
|
|
41837
|
-
const decisionsDir =
|
|
41999
|
+
const decisionsDir = path36.join(zelari, "decisions");
|
|
41838
42000
|
try {
|
|
41839
|
-
const files = (await
|
|
42001
|
+
const files = (await fs21.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
41840
42002
|
if (files.length === 0) {
|
|
41841
42003
|
content = "(no ADRs yet \u2014 invoke /council to generate some)";
|
|
41842
42004
|
} else {
|
|
@@ -41844,7 +42006,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
41844
42006
|
`];
|
|
41845
42007
|
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
|
|
41846
42008
|
for (const f of files) {
|
|
41847
|
-
const raw = await
|
|
42009
|
+
const raw = await fs21.readFile(path36.join(decisionsDir, f), "utf-8");
|
|
41848
42010
|
const { meta: meta3, body } = parseFrontmatter2(raw);
|
|
41849
42011
|
const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
|
|
41850
42012
|
lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
|
|
@@ -41857,27 +42019,27 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
41857
42019
|
break;
|
|
41858
42020
|
}
|
|
41859
42021
|
case "risks": {
|
|
41860
|
-
const risksPath =
|
|
42022
|
+
const risksPath = path36.join(zelari, "risks.md");
|
|
41861
42023
|
try {
|
|
41862
|
-
content = await
|
|
42024
|
+
content = await fs21.readFile(risksPath, "utf-8");
|
|
41863
42025
|
} catch {
|
|
41864
42026
|
content = "(no risks.md yet)";
|
|
41865
42027
|
}
|
|
41866
42028
|
break;
|
|
41867
42029
|
}
|
|
41868
42030
|
case "agents": {
|
|
41869
|
-
const agentsPath =
|
|
42031
|
+
const agentsPath = path36.join(process.cwd(), "AGENTS.MD");
|
|
41870
42032
|
try {
|
|
41871
|
-
content = await
|
|
42033
|
+
content = await fs21.readFile(agentsPath, "utf-8");
|
|
41872
42034
|
} catch {
|
|
41873
42035
|
content = "(no AGENTS.MD yet at project root \u2014 run `/workspace sync` after a council session)";
|
|
41874
42036
|
}
|
|
41875
42037
|
break;
|
|
41876
42038
|
}
|
|
41877
42039
|
case "docs": {
|
|
41878
|
-
const docsDir =
|
|
42040
|
+
const docsDir = path36.join(zelari, "docs");
|
|
41879
42041
|
try {
|
|
41880
|
-
const files = (await
|
|
42042
|
+
const files = (await fs21.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
41881
42043
|
content = files.length ? `# Docs (${files.length})
|
|
41882
42044
|
|
|
41883
42045
|
` + files.map((f) => `- ${f}`).join("\n") : "(no docs drafts yet)";
|
|
@@ -41917,8 +42079,8 @@ async function handleWorkspaceReset(ctx, force) {
|
|
|
41917
42079
|
return;
|
|
41918
42080
|
}
|
|
41919
42081
|
try {
|
|
41920
|
-
const target =
|
|
41921
|
-
await
|
|
42082
|
+
const target = path36.join(process.cwd(), ".zelari");
|
|
42083
|
+
await fs21.rm(target, { recursive: true, force: true });
|
|
41922
42084
|
appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
|
|
41923
42085
|
} catch (err) {
|
|
41924
42086
|
appendSystem(ctx.setMessages, `[workspace reset error] ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -42276,16 +42438,16 @@ function handleModelsRefresh(ctx) {
|
|
|
42276
42438
|
}
|
|
42277
42439
|
|
|
42278
42440
|
// src/cli/slashHandlers/skills.ts
|
|
42279
|
-
import
|
|
42441
|
+
import path37 from "node:path";
|
|
42280
42442
|
import os12 from "node:os";
|
|
42281
42443
|
|
|
42282
42444
|
// src/cli/skillHistory.ts
|
|
42283
|
-
import { promises as
|
|
42445
|
+
import { promises as fs22, existsSync as existsSync36, statSync as statSync5, renameSync as renameSync4, appendFileSync as appendFileSync3, mkdirSync as mkdirSync15 } from "node:fs";
|
|
42284
42446
|
var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
42285
42447
|
async function readSkillHistory(file2) {
|
|
42286
42448
|
let raw = "";
|
|
42287
42449
|
try {
|
|
42288
|
-
raw = await
|
|
42450
|
+
raw = await fs22.readFile(file2, "utf-8");
|
|
42289
42451
|
} catch {
|
|
42290
42452
|
return [];
|
|
42291
42453
|
}
|
|
@@ -42378,7 +42540,7 @@ async function applySteerInterrupt(options) {
|
|
|
42378
42540
|
|
|
42379
42541
|
// src/cli/slashHandlers/skills.ts
|
|
42380
42542
|
async function handleSkillStats(ctx, skillId) {
|
|
42381
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
42543
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path37.join(os12.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
42382
42544
|
try {
|
|
42383
42545
|
const records = await readSkillHistory(historyFile);
|
|
42384
42546
|
const stats = getSkillStats(records, skillId);
|
|
@@ -42394,7 +42556,7 @@ async function handleSkillCompare(ctx, ids, fallbackMessage) {
|
|
|
42394
42556
|
appendSystem(ctx.setMessages, fallbackMessage ?? "[skill-compare] missing args");
|
|
42395
42557
|
return;
|
|
42396
42558
|
}
|
|
42397
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
42559
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path37.join(os12.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
42398
42560
|
try {
|
|
42399
42561
|
const formatted = await compareSkillsFromFile(ids[0], ids[1], historyFile);
|
|
42400
42562
|
appendSystem(ctx.setMessages, formatted);
|
|
@@ -43808,6 +43970,7 @@ function parseHeadlessFlags(argv) {
|
|
|
43808
43970
|
let provider;
|
|
43809
43971
|
let model;
|
|
43810
43972
|
let history2;
|
|
43973
|
+
let once = false;
|
|
43811
43974
|
for (let i = 0; i < argv.length; i++) {
|
|
43812
43975
|
const arg = argv[i];
|
|
43813
43976
|
if (arg === "--headless") continue;
|
|
@@ -43896,6 +44059,8 @@ function parseHeadlessFlags(argv) {
|
|
|
43896
44059
|
}
|
|
43897
44060
|
i++;
|
|
43898
44061
|
}
|
|
44062
|
+
} else if (arg === "--once") {
|
|
44063
|
+
once = true;
|
|
43899
44064
|
}
|
|
43900
44065
|
}
|
|
43901
44066
|
if (councilFlag && !modeExplicit) {
|
|
@@ -43918,7 +44083,8 @@ function parseHeadlessFlags(argv) {
|
|
|
43918
44083
|
useCouncil: mode === "council",
|
|
43919
44084
|
provider,
|
|
43920
44085
|
model,
|
|
43921
|
-
...history2 && history2.length > 0 ? { history: history2 } : {}
|
|
44086
|
+
...history2 && history2.length > 0 ? { history: history2 } : {},
|
|
44087
|
+
...once ? { once: true } : {}
|
|
43922
44088
|
}
|
|
43923
44089
|
};
|
|
43924
44090
|
}
|
|
@@ -44601,6 +44767,22 @@ ${JSON.stringify({ deliverable: brief.deliverableThisMission, mvp: brief.sliceMv
|
|
|
44601
44767
|
}
|
|
44602
44768
|
let exitCode = 0;
|
|
44603
44769
|
let lastMissionAssistant = "";
|
|
44770
|
+
let lockAcquired = false;
|
|
44771
|
+
if (opts.once) {
|
|
44772
|
+
const { acquireLock: acquireLock2 } = await Promise.resolve().then(() => (init_triggerLock(), triggerLock_exports));
|
|
44773
|
+
const lockRes = await acquireLock2(projectRoot);
|
|
44774
|
+
if (!lockRes.acquired) {
|
|
44775
|
+
process.stderr.write(
|
|
44776
|
+
`[zelari-code --once] skip: another mission is running (pid ${lockRes.heldBy}).
|
|
44777
|
+
`
|
|
44778
|
+
);
|
|
44779
|
+
return 0;
|
|
44780
|
+
}
|
|
44781
|
+
lockAcquired = true;
|
|
44782
|
+
if (!process.env.ZELARI_MISSION_MAX_ITER) {
|
|
44783
|
+
process.env.ZELARI_MISSION_MAX_ITER = "1";
|
|
44784
|
+
}
|
|
44785
|
+
}
|
|
44604
44786
|
try {
|
|
44605
44787
|
const state2 = await runZelariMission2(missionTask, brief, {
|
|
44606
44788
|
projectRoot,
|
|
@@ -44819,6 +45001,10 @@ ${ragContext}` : slicePrompt;
|
|
|
44819
45001
|
);
|
|
44820
45002
|
return 2;
|
|
44821
45003
|
} finally {
|
|
45004
|
+
if (lockAcquired) {
|
|
45005
|
+
const { releaseLock: releaseLock2 } = await Promise.resolve().then(() => (init_triggerLock(), triggerLock_exports));
|
|
45006
|
+
await releaseLock2(projectRoot);
|
|
45007
|
+
}
|
|
44822
45008
|
await memory.close().catch(() => void 0);
|
|
44823
45009
|
}
|
|
44824
45010
|
if (opts.output === "json") {
|