zelari-code 1.27.2 → 1.28.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/kraken/executor.js +89 -12
- package/dist/cli/kraken/executor.js.map +1 -1
- package/dist/cli/kraken/graphMemory.js +111 -0
- package/dist/cli/kraken/graphMemory.js.map +1 -0
- package/dist/cli/kraken/planner.js +124 -15
- package/dist/cli/kraken/planner.js.map +1 -1
- package/dist/cli/main.bundled.js +496 -237
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/runHeadless.js +15 -1
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/slashHandlers/krakenGraph.js +12 -1
- package/dist/cli/slashHandlers/krakenGraph.js.map +1 -1
- package/dist/cli/tools/taskTool.js +47 -2
- package/dist/cli/tools/taskTool.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -1829,10 +1829,10 @@ function mergeDefs(...defs) {
|
|
|
1829
1829
|
function cloneDef(schema) {
|
|
1830
1830
|
return mergeDefs(schema._zod.def);
|
|
1831
1831
|
}
|
|
1832
|
-
function getElementAtPath(obj,
|
|
1833
|
-
if (!
|
|
1832
|
+
function getElementAtPath(obj, path44) {
|
|
1833
|
+
if (!path44)
|
|
1834
1834
|
return obj;
|
|
1835
|
-
return
|
|
1835
|
+
return path44.reduce((acc, key) => acc?.[key], obj);
|
|
1836
1836
|
}
|
|
1837
1837
|
function promiseAllObject(promisesObj) {
|
|
1838
1838
|
const keys = Object.keys(promisesObj);
|
|
@@ -2160,11 +2160,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
2160
2160
|
}
|
|
2161
2161
|
return false;
|
|
2162
2162
|
}
|
|
2163
|
-
function prefixIssues(
|
|
2163
|
+
function prefixIssues(path44, issues) {
|
|
2164
2164
|
return issues.map((iss) => {
|
|
2165
2165
|
var _a3;
|
|
2166
2166
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
2167
|
-
iss.path.unshift(
|
|
2167
|
+
iss.path.unshift(path44);
|
|
2168
2168
|
return iss;
|
|
2169
2169
|
});
|
|
2170
2170
|
}
|
|
@@ -2382,16 +2382,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2382
2382
|
}
|
|
2383
2383
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
2384
2384
|
const fieldErrors = { _errors: [] };
|
|
2385
|
-
const processError = (error52,
|
|
2385
|
+
const processError = (error52, path44 = []) => {
|
|
2386
2386
|
for (const issue2 of error52.issues) {
|
|
2387
2387
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2388
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2388
|
+
issue2.errors.map((issues) => processError({ issues }, [...path44, ...issue2.path]));
|
|
2389
2389
|
} else if (issue2.code === "invalid_key") {
|
|
2390
|
-
processError({ issues: issue2.issues }, [...
|
|
2390
|
+
processError({ issues: issue2.issues }, [...path44, ...issue2.path]);
|
|
2391
2391
|
} else if (issue2.code === "invalid_element") {
|
|
2392
|
-
processError({ issues: issue2.issues }, [...
|
|
2392
|
+
processError({ issues: issue2.issues }, [...path44, ...issue2.path]);
|
|
2393
2393
|
} else {
|
|
2394
|
-
const fullpath = [...
|
|
2394
|
+
const fullpath = [...path44, ...issue2.path];
|
|
2395
2395
|
if (fullpath.length === 0) {
|
|
2396
2396
|
fieldErrors._errors.push(mapper(issue2));
|
|
2397
2397
|
} else {
|
|
@@ -2418,17 +2418,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2418
2418
|
}
|
|
2419
2419
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
2420
2420
|
const result = { errors: [] };
|
|
2421
|
-
const processError = (error52,
|
|
2421
|
+
const processError = (error52, path44 = []) => {
|
|
2422
2422
|
var _a3, _b;
|
|
2423
2423
|
for (const issue2 of error52.issues) {
|
|
2424
2424
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2425
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2425
|
+
issue2.errors.map((issues) => processError({ issues }, [...path44, ...issue2.path]));
|
|
2426
2426
|
} else if (issue2.code === "invalid_key") {
|
|
2427
|
-
processError({ issues: issue2.issues }, [...
|
|
2427
|
+
processError({ issues: issue2.issues }, [...path44, ...issue2.path]);
|
|
2428
2428
|
} else if (issue2.code === "invalid_element") {
|
|
2429
|
-
processError({ issues: issue2.issues }, [...
|
|
2429
|
+
processError({ issues: issue2.issues }, [...path44, ...issue2.path]);
|
|
2430
2430
|
} else {
|
|
2431
|
-
const fullpath = [...
|
|
2431
|
+
const fullpath = [...path44, ...issue2.path];
|
|
2432
2432
|
if (fullpath.length === 0) {
|
|
2433
2433
|
result.errors.push(mapper(issue2));
|
|
2434
2434
|
continue;
|
|
@@ -2460,8 +2460,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2460
2460
|
}
|
|
2461
2461
|
function toDotPath(_path) {
|
|
2462
2462
|
const segs = [];
|
|
2463
|
-
const
|
|
2464
|
-
for (const seg of
|
|
2463
|
+
const path44 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
2464
|
+
for (const seg of path44) {
|
|
2465
2465
|
if (typeof seg === "number")
|
|
2466
2466
|
segs.push(`[${seg}]`);
|
|
2467
2467
|
else if (typeof seg === "symbol")
|
|
@@ -15964,13 +15964,13 @@ function resolveRef(ref, ctx) {
|
|
|
15964
15964
|
if (!ref.startsWith("#")) {
|
|
15965
15965
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
15966
15966
|
}
|
|
15967
|
-
const
|
|
15968
|
-
if (
|
|
15967
|
+
const path44 = ref.slice(1).split("/").filter(Boolean);
|
|
15968
|
+
if (path44.length === 0) {
|
|
15969
15969
|
return ctx.rootSchema;
|
|
15970
15970
|
}
|
|
15971
15971
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
15972
|
-
if (
|
|
15973
|
-
const key =
|
|
15972
|
+
if (path44[0] === defsKey) {
|
|
15973
|
+
const key = path44[1];
|
|
15974
15974
|
if (!key || !ctx.defs[key]) {
|
|
15975
15975
|
throw new Error(`Reference not found: ${ref}`);
|
|
15976
15976
|
}
|
|
@@ -18134,11 +18134,11 @@ var init_tools = __esm({
|
|
|
18134
18134
|
if (!ctx.addDocument)
|
|
18135
18135
|
return "Knowledge vault tool not available.";
|
|
18136
18136
|
const title = args["title"] || "New Document";
|
|
18137
|
-
const
|
|
18137
|
+
const path44 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
18138
18138
|
const content = args["content"] || "";
|
|
18139
18139
|
const tags = args["tags"] || [];
|
|
18140
18140
|
ctx.addDocument({
|
|
18141
|
-
path:
|
|
18141
|
+
path: path44,
|
|
18142
18142
|
title,
|
|
18143
18143
|
content,
|
|
18144
18144
|
format: "markdown",
|
|
@@ -18147,7 +18147,7 @@ var init_tools = __esm({
|
|
|
18147
18147
|
workspaceId: ctx.workspaceId
|
|
18148
18148
|
});
|
|
18149
18149
|
ctx.addActivity("vault", "created document", title);
|
|
18150
|
-
return `Document "${title}" created at "${
|
|
18150
|
+
return `Document "${title}" created at "${path44}".`;
|
|
18151
18151
|
}
|
|
18152
18152
|
}
|
|
18153
18153
|
];
|
|
@@ -21839,11 +21839,11 @@ var init_synthesisAudit = __esm({
|
|
|
21839
21839
|
import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
21840
21840
|
import { join as join2 } from "node:path";
|
|
21841
21841
|
function loadNfrSpec(zelariRoot) {
|
|
21842
|
-
const
|
|
21843
|
-
if (!existsSync6(
|
|
21842
|
+
const path44 = join2(zelariRoot, "nfr-spec.json");
|
|
21843
|
+
if (!existsSync6(path44))
|
|
21844
21844
|
return null;
|
|
21845
21845
|
try {
|
|
21846
|
-
const raw = JSON.parse(readFileSync5(
|
|
21846
|
+
const raw = JSON.parse(readFileSync5(path44, "utf8"));
|
|
21847
21847
|
if (raw.version !== 1 || !Array.isArray(raw.targets))
|
|
21848
21848
|
return null;
|
|
21849
21849
|
return raw;
|
|
@@ -24149,9 +24149,9 @@ var init_types3 = __esm({
|
|
|
24149
24149
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
24150
24150
|
import { join as join8 } from "node:path";
|
|
24151
24151
|
function readLessonsDeduped(zelariRoot) {
|
|
24152
|
-
const
|
|
24152
|
+
const path44 = join8(zelariRoot, LESSONS_FILE);
|
|
24153
24153
|
try {
|
|
24154
|
-
const raw = readFileSync10(
|
|
24154
|
+
const raw = readFileSync10(path44, "utf8");
|
|
24155
24155
|
const byId = /* @__PURE__ */ new Map();
|
|
24156
24156
|
for (const line of raw.split(/\r?\n/)) {
|
|
24157
24157
|
if (!line.trim())
|
|
@@ -24252,8 +24252,8 @@ function keywordsFrom(check2, signature) {
|
|
|
24252
24252
|
return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
|
|
24253
24253
|
}
|
|
24254
24254
|
function writeLesson(zelariRoot, lesson) {
|
|
24255
|
-
const
|
|
24256
|
-
appendFileSync(
|
|
24255
|
+
const path44 = join9(zelariRoot, LESSONS_FILE);
|
|
24256
|
+
appendFileSync(path44, `${JSON.stringify(lesson)}
|
|
24257
24257
|
`, "utf8");
|
|
24258
24258
|
}
|
|
24259
24259
|
function findSimilar(lessons, signature) {
|
|
@@ -24866,9 +24866,9 @@ function findCycle(nodes) {
|
|
|
24866
24866
|
if (color.get(start) !== WHITE)
|
|
24867
24867
|
continue;
|
|
24868
24868
|
const stack = [[start, 0]];
|
|
24869
|
-
const
|
|
24869
|
+
const path44 = [];
|
|
24870
24870
|
color.set(start, GRAY);
|
|
24871
|
-
|
|
24871
|
+
path44.push(start);
|
|
24872
24872
|
while (stack.length > 0) {
|
|
24873
24873
|
const top = stack[stack.length - 1];
|
|
24874
24874
|
const [id, idx] = top;
|
|
@@ -24881,17 +24881,17 @@ function findCycle(nodes) {
|
|
|
24881
24881
|
continue;
|
|
24882
24882
|
const c = color.get(dep);
|
|
24883
24883
|
if (c === GRAY) {
|
|
24884
|
-
const at =
|
|
24885
|
-
return [...
|
|
24884
|
+
const at = path44.indexOf(dep);
|
|
24885
|
+
return [...path44.slice(at), dep];
|
|
24886
24886
|
}
|
|
24887
24887
|
if (c === WHITE) {
|
|
24888
24888
|
color.set(dep, GRAY);
|
|
24889
|
-
|
|
24889
|
+
path44.push(dep);
|
|
24890
24890
|
stack.push([dep, 0]);
|
|
24891
24891
|
}
|
|
24892
24892
|
} else {
|
|
24893
24893
|
color.set(id, BLACK);
|
|
24894
|
-
|
|
24894
|
+
path44.pop();
|
|
24895
24895
|
stack.pop();
|
|
24896
24896
|
}
|
|
24897
24897
|
}
|
|
@@ -25700,9 +25700,9 @@ function spillToolOutput(fullText, meta3) {
|
|
|
25700
25700
|
const rnd = randomBytes(3).toString("hex");
|
|
25701
25701
|
const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
|
|
25702
25702
|
const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
|
|
25703
|
-
const
|
|
25704
|
-
writeFileSync10(
|
|
25705
|
-
return
|
|
25703
|
+
const path44 = join11(dir, file2);
|
|
25704
|
+
writeFileSync10(path44, fullText, "utf8");
|
|
25705
|
+
return path44;
|
|
25706
25706
|
} catch {
|
|
25707
25707
|
return null;
|
|
25708
25708
|
}
|
|
@@ -25748,10 +25748,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
|
|
|
25748
25748
|
${tail}`;
|
|
25749
25749
|
}
|
|
25750
25750
|
if (doSpill) {
|
|
25751
|
-
const
|
|
25752
|
-
if (
|
|
25751
|
+
const path44 = spillToolOutput(text, { toolName: opts.toolName });
|
|
25752
|
+
if (path44) {
|
|
25753
25753
|
const spillNote = `
|
|
25754
|
-
\u2026 [full output spilled to: ${
|
|
25754
|
+
\u2026 [full output spilled to: ${path44} \u2014 re-read with read_file if you need the complete text] \u2026`;
|
|
25755
25755
|
if (preview.includes("] \u2026\n")) {
|
|
25756
25756
|
preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
|
|
25757
25757
|
`);
|
|
@@ -26581,11 +26581,20 @@ function maxToolCallsForThoroughness(thoroughness, agent) {
|
|
|
26581
26581
|
if (thoroughness === "deep") return 12;
|
|
26582
26582
|
return 6;
|
|
26583
26583
|
}
|
|
26584
|
-
async function runSubAgent(harness) {
|
|
26584
|
+
async function runSubAgent(harness, opts = {}) {
|
|
26585
|
+
const { signal } = opts;
|
|
26585
26586
|
let current = "";
|
|
26586
26587
|
let lastCompleted = "";
|
|
26587
26588
|
let error51;
|
|
26589
|
+
if (signal?.aborted) return { result: "", aborted: true };
|
|
26588
26590
|
for await (const ev of harness.run()) {
|
|
26591
|
+
if (signal?.aborted) {
|
|
26592
|
+
return {
|
|
26593
|
+
result: (lastCompleted || current).trim(),
|
|
26594
|
+
...error51 ? { error: error51 } : {},
|
|
26595
|
+
aborted: true
|
|
26596
|
+
};
|
|
26597
|
+
}
|
|
26589
26598
|
switch (ev.type) {
|
|
26590
26599
|
case "message_start":
|
|
26591
26600
|
current = "";
|
|
@@ -26715,8 +26724,31 @@ async function runTentacle(opts) {
|
|
|
26715
26724
|
error: `task: failed to start sub-agent \u2014 ${err instanceof Error ? err.message : String(err)}`
|
|
26716
26725
|
};
|
|
26717
26726
|
}
|
|
26718
|
-
const { result, error: error51 } = await runSubAgent(harness
|
|
26727
|
+
const { result, error: error51, aborted: aborted2 } = await runSubAgent(harness, {
|
|
26728
|
+
...opts.signal ? { signal: opts.signal } : {}
|
|
26729
|
+
});
|
|
26719
26730
|
const durationMs = Date.now() - started;
|
|
26731
|
+
if (aborted2) {
|
|
26732
|
+
if (worktree && !shouldKeepWorktree()) await cleanupKrakenWorktree(worktree);
|
|
26733
|
+
appendKrakenRadio(parentCwd, sessionId, {
|
|
26734
|
+
kind: "error",
|
|
26735
|
+
agent,
|
|
26736
|
+
thoroughness,
|
|
26737
|
+
description: args.description,
|
|
26738
|
+
detail: "cancelled: node timeout",
|
|
26739
|
+
model: sub.model,
|
|
26740
|
+
worktree: worktree?.path ?? null,
|
|
26741
|
+
durationMs,
|
|
26742
|
+
ok: false
|
|
26743
|
+
});
|
|
26744
|
+
krakenTentacleEnd(liveId, {
|
|
26745
|
+
ok: false,
|
|
26746
|
+
model: sub.model,
|
|
26747
|
+
detail: "cancelled",
|
|
26748
|
+
durationMs
|
|
26749
|
+
});
|
|
26750
|
+
return { ok: false, agent, error: "task: sub-agent cancelled (node timeout)", cancelled: true };
|
|
26751
|
+
}
|
|
26720
26752
|
if (!result) {
|
|
26721
26753
|
if (worktree) await cleanupKrakenWorktree(worktree);
|
|
26722
26754
|
appendKrakenRadio(parentCwd, sessionId, {
|
|
@@ -28660,21 +28692,21 @@ function normalizeAuth(auth) {
|
|
|
28660
28692
|
return "agent";
|
|
28661
28693
|
}
|
|
28662
28694
|
function readSecrets() {
|
|
28663
|
-
const
|
|
28664
|
-
if (!existsSync17(
|
|
28695
|
+
const path44 = getSshSecretsPath();
|
|
28696
|
+
if (!existsSync17(path44)) return {};
|
|
28665
28697
|
try {
|
|
28666
|
-
return JSON.parse(readFileSync16(
|
|
28698
|
+
return JSON.parse(readFileSync16(path44, "utf8"));
|
|
28667
28699
|
} catch {
|
|
28668
28700
|
return {};
|
|
28669
28701
|
}
|
|
28670
28702
|
}
|
|
28671
28703
|
function writeSecrets(data) {
|
|
28672
|
-
const
|
|
28673
|
-
mkdirSync9(dirname2(
|
|
28674
|
-
writeFileSync11(
|
|
28704
|
+
const path44 = getSshSecretsPath();
|
|
28705
|
+
mkdirSync9(dirname2(path44), { recursive: true });
|
|
28706
|
+
writeFileSync11(path44, `${JSON.stringify(data, null, 2)}
|
|
28675
28707
|
`, "utf8");
|
|
28676
28708
|
try {
|
|
28677
|
-
chmodSync(
|
|
28709
|
+
chmodSync(path44, 384);
|
|
28678
28710
|
} catch {
|
|
28679
28711
|
}
|
|
28680
28712
|
}
|
|
@@ -28703,10 +28735,10 @@ function deleteSshPassword(id) {
|
|
|
28703
28735
|
writeSecrets({ passwords });
|
|
28704
28736
|
}
|
|
28705
28737
|
function readStore2() {
|
|
28706
|
-
const
|
|
28707
|
-
if (!existsSync17(
|
|
28738
|
+
const path44 = getSshTargetsPath();
|
|
28739
|
+
if (!existsSync17(path44)) return [];
|
|
28708
28740
|
try {
|
|
28709
|
-
const parsed = JSON.parse(readFileSync16(
|
|
28741
|
+
const parsed = JSON.parse(readFileSync16(path44, "utf8"));
|
|
28710
28742
|
const list = Array.isArray(parsed.targets) ? parsed.targets : [];
|
|
28711
28743
|
return list.filter(
|
|
28712
28744
|
(t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
|
|
@@ -28721,11 +28753,11 @@ function readStore2() {
|
|
|
28721
28753
|
}
|
|
28722
28754
|
}
|
|
28723
28755
|
function writeStore2(targets) {
|
|
28724
|
-
const
|
|
28725
|
-
mkdirSync9(dirname2(
|
|
28756
|
+
const path44 = getSshTargetsPath();
|
|
28757
|
+
mkdirSync9(dirname2(path44), { recursive: true });
|
|
28726
28758
|
const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
|
|
28727
28759
|
writeFileSync11(
|
|
28728
|
-
|
|
28760
|
+
path44,
|
|
28729
28761
|
`${JSON.stringify({ targets: clean }, null, 2)}
|
|
28730
28762
|
`,
|
|
28731
28763
|
"utf8"
|
|
@@ -28971,11 +29003,11 @@ function formatSshTargetsForPrompt() {
|
|
|
28971
29003
|
];
|
|
28972
29004
|
for (const t of targets) {
|
|
28973
29005
|
const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
|
|
28974
|
-
const
|
|
29006
|
+
const path44 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
|
|
28975
29007
|
const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
|
|
28976
29008
|
const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
|
|
28977
29009
|
lines.push(
|
|
28978
|
-
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${
|
|
29010
|
+
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path44}${tags}${allow}`
|
|
28979
29011
|
);
|
|
28980
29012
|
}
|
|
28981
29013
|
return lines.join("\n");
|
|
@@ -31827,28 +31859,28 @@ var init_storage = __esm({
|
|
|
31827
31859
|
VALID_SCALARS = /^(true|false|null|~)$/i;
|
|
31828
31860
|
Storage = class {
|
|
31829
31861
|
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
31830
|
-
read(
|
|
31831
|
-
if (!existsSync25(
|
|
31832
|
-
throw new Error(`File not found: ${
|
|
31862
|
+
read(path44) {
|
|
31863
|
+
if (!existsSync25(path44)) {
|
|
31864
|
+
throw new Error(`File not found: ${path44}`);
|
|
31833
31865
|
}
|
|
31834
|
-
const md = readFileSync21(
|
|
31866
|
+
const md = readFileSync21(path44, "utf8");
|
|
31835
31867
|
return parseFrontmatter(md);
|
|
31836
31868
|
}
|
|
31837
31869
|
/** Read a Markdown file; returns null if not found. */
|
|
31838
|
-
readIfExists(
|
|
31839
|
-
if (!existsSync25(
|
|
31840
|
-
return this.read(
|
|
31870
|
+
readIfExists(path44) {
|
|
31871
|
+
if (!existsSync25(path44)) return null;
|
|
31872
|
+
return this.read(path44);
|
|
31841
31873
|
}
|
|
31842
31874
|
/**
|
|
31843
31875
|
* Write a Markdown file atomically (tmp + rename). Creates parent dirs.
|
|
31844
31876
|
* The meta object is serialized as YAML frontmatter; body as Markdown.
|
|
31845
31877
|
*/
|
|
31846
|
-
write(
|
|
31847
|
-
mkdirSync11(dirname4(
|
|
31848
|
-
const tmp =
|
|
31878
|
+
write(path44, meta3, body) {
|
|
31879
|
+
mkdirSync11(dirname4(path44), { recursive: true });
|
|
31880
|
+
const tmp = path44 + ".tmp-" + process.pid;
|
|
31849
31881
|
const md = serializeFrontmatter(meta3, body);
|
|
31850
31882
|
writeFileSync13(tmp, md, "utf8");
|
|
31851
|
-
renameSync2(tmp,
|
|
31883
|
+
renameSync2(tmp, path44);
|
|
31852
31884
|
}
|
|
31853
31885
|
/** List all .md files in a directory (non-recursive). */
|
|
31854
31886
|
listMarkdown(dir) {
|
|
@@ -31926,8 +31958,8 @@ function readPlan(ctx) {
|
|
|
31926
31958
|
} catch {
|
|
31927
31959
|
}
|
|
31928
31960
|
}
|
|
31929
|
-
const
|
|
31930
|
-
const doc = ctx.storage.readIfExists(
|
|
31961
|
+
const path44 = workspaceFile(ctx.rootDir, "plan");
|
|
31962
|
+
const doc = ctx.storage.readIfExists(path44);
|
|
31931
31963
|
if (!doc) return { phases: [], tasks: [], milestones: [] };
|
|
31932
31964
|
const meta3 = doc.meta;
|
|
31933
31965
|
return {
|
|
@@ -32092,7 +32124,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
32092
32124
|
dueDate: input.dueDate,
|
|
32093
32125
|
targetVersion: version2
|
|
32094
32126
|
});
|
|
32095
|
-
const
|
|
32127
|
+
const path44 = join23(ctx.rootDir, "milestones", `${id}.md`);
|
|
32096
32128
|
const meta3 = {
|
|
32097
32129
|
kind: "milestone",
|
|
32098
32130
|
id,
|
|
@@ -32109,7 +32141,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
32109
32141
|
`Target version: ${version2}`,
|
|
32110
32142
|
""
|
|
32111
32143
|
].join("\n");
|
|
32112
|
-
ctx.storage.write(
|
|
32144
|
+
ctx.storage.write(path44, meta3, body);
|
|
32113
32145
|
return { id, created: true };
|
|
32114
32146
|
}
|
|
32115
32147
|
function readPlanSummary(ctx) {
|
|
@@ -32313,7 +32345,7 @@ function addIdeaStub(ctx) {
|
|
|
32313
32345
|
const tags = args["tags"] ?? [];
|
|
32314
32346
|
const category = args["category"] ?? "General";
|
|
32315
32347
|
const id = `${nextAdrId(ctx)}-${slugify3(title)}`;
|
|
32316
|
-
const
|
|
32348
|
+
const path44 = workspaceArtifact(ctx.rootDir, "decisions", id);
|
|
32317
32349
|
const meta3 = {
|
|
32318
32350
|
kind: "adr",
|
|
32319
32351
|
status: "proposed",
|
|
@@ -32339,7 +32371,7 @@ function addIdeaStub(ctx) {
|
|
|
32339
32371
|
...consequences.map((c) => `- ${c}`),
|
|
32340
32372
|
""
|
|
32341
32373
|
].join("\n");
|
|
32342
|
-
ctx.storage.write(
|
|
32374
|
+
ctx.storage.write(path44, meta3, body);
|
|
32343
32375
|
return `ADR ${id} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
|
|
32344
32376
|
});
|
|
32345
32377
|
}
|
|
@@ -32421,14 +32453,14 @@ function createDocumentStub(ctx) {
|
|
|
32421
32453
|
ctx.storage.write(risksPath, riskMeta, content);
|
|
32422
32454
|
return `Document "${title}" created at risks.md (workspace root).`;
|
|
32423
32455
|
}
|
|
32424
|
-
const
|
|
32456
|
+
const path44 = workspaceArtifact(ctx.rootDir, "docs", slug);
|
|
32425
32457
|
const meta3 = {
|
|
32426
32458
|
kind: "doc",
|
|
32427
32459
|
id: slug,
|
|
32428
32460
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
32429
32461
|
tags
|
|
32430
32462
|
};
|
|
32431
|
-
ctx.storage.write(
|
|
32463
|
+
ctx.storage.write(path44, meta3, content);
|
|
32432
32464
|
return `Document "${title}" created at docs/${slug}.md.`;
|
|
32433
32465
|
});
|
|
32434
32466
|
}
|
|
@@ -32972,10 +33004,10 @@ function getUserMcpPath() {
|
|
|
32972
33004
|
function getProjectMcpPath(projectRoot) {
|
|
32973
33005
|
return join24(projectRoot, ".zelari", "mcp.json");
|
|
32974
33006
|
}
|
|
32975
|
-
function readFile2(
|
|
32976
|
-
if (!existsSync28(
|
|
33007
|
+
function readFile2(path44) {
|
|
33008
|
+
if (!existsSync28(path44)) return {};
|
|
32977
33009
|
try {
|
|
32978
|
-
const parsed = JSON.parse(readFileSync23(
|
|
33010
|
+
const parsed = JSON.parse(readFileSync23(path44, "utf8"));
|
|
32979
33011
|
const out = {};
|
|
32980
33012
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
32981
33013
|
if (!cfg || typeof cfg.command !== "string" || !cfg.command.trim()) continue;
|
|
@@ -32991,10 +33023,10 @@ function readFile2(path43) {
|
|
|
32991
33023
|
return {};
|
|
32992
33024
|
}
|
|
32993
33025
|
}
|
|
32994
|
-
function writeFile(
|
|
32995
|
-
mkdirSync13(dirname6(
|
|
33026
|
+
function writeFile(path44, servers) {
|
|
33027
|
+
mkdirSync13(dirname6(path44), { recursive: true });
|
|
32996
33028
|
const body = { mcpServers: servers };
|
|
32997
|
-
writeFileSync15(
|
|
33029
|
+
writeFileSync15(path44, `${JSON.stringify(body, null, 2)}
|
|
32998
33030
|
`, "utf8");
|
|
32999
33031
|
}
|
|
33000
33032
|
function listMcpServers(projectRoot) {
|
|
@@ -33027,9 +33059,9 @@ function upsertMcpServer(opts) {
|
|
|
33027
33059
|
if (!opts.config.command?.trim()) {
|
|
33028
33060
|
return { ok: false, error: "command is required" };
|
|
33029
33061
|
}
|
|
33030
|
-
let
|
|
33062
|
+
let path44;
|
|
33031
33063
|
if (opts.scope === "user") {
|
|
33032
|
-
|
|
33064
|
+
path44 = getUserMcpPath();
|
|
33033
33065
|
} else {
|
|
33034
33066
|
const root = opts.projectRoot?.trim();
|
|
33035
33067
|
if (!root) {
|
|
@@ -33038,30 +33070,30 @@ function upsertMcpServer(opts) {
|
|
|
33038
33070
|
error: "projectRoot required for project scope (Open Folder first)"
|
|
33039
33071
|
};
|
|
33040
33072
|
}
|
|
33041
|
-
|
|
33073
|
+
path44 = getProjectMcpPath(root);
|
|
33042
33074
|
}
|
|
33043
|
-
const current = readFile2(
|
|
33075
|
+
const current = readFile2(path44);
|
|
33044
33076
|
current[name] = {
|
|
33045
33077
|
command: opts.config.command.trim(),
|
|
33046
33078
|
args: opts.config.args,
|
|
33047
33079
|
env: opts.config.env,
|
|
33048
33080
|
enabled: opts.config.enabled !== false
|
|
33049
33081
|
};
|
|
33050
|
-
writeFile(
|
|
33051
|
-
return { ok: true, path:
|
|
33082
|
+
writeFile(path44, current);
|
|
33083
|
+
return { ok: true, path: path44 };
|
|
33052
33084
|
}
|
|
33053
33085
|
function removeMcpServer(opts) {
|
|
33054
|
-
const
|
|
33055
|
-
if (!
|
|
33086
|
+
const path44 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
|
|
33087
|
+
if (!path44) {
|
|
33056
33088
|
return { ok: false, error: "projectRoot required for project scope" };
|
|
33057
33089
|
}
|
|
33058
|
-
const current = readFile2(
|
|
33090
|
+
const current = readFile2(path44);
|
|
33059
33091
|
if (!(opts.name in current)) {
|
|
33060
|
-
return { ok: false, error: `Server "${opts.name}" not found in ${
|
|
33092
|
+
return { ok: false, error: `Server "${opts.name}" not found in ${path44}` };
|
|
33061
33093
|
}
|
|
33062
33094
|
delete current[opts.name];
|
|
33063
|
-
writeFile(
|
|
33064
|
-
return { ok: true, path:
|
|
33095
|
+
writeFile(path44, current);
|
|
33096
|
+
return { ok: true, path: path44 };
|
|
33065
33097
|
}
|
|
33066
33098
|
var init_mcpConfigIo = __esm({
|
|
33067
33099
|
"src/cli/mcp/mcpConfigIo.ts"() {
|
|
@@ -33398,10 +33430,10 @@ import { createHash as createHash5 } from "node:crypto";
|
|
|
33398
33430
|
import { join as join26 } from "node:path";
|
|
33399
33431
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
33400
33432
|
async function readPackageJson2(projectRoot) {
|
|
33401
|
-
const
|
|
33402
|
-
if (!existsSync30(
|
|
33433
|
+
const path44 = join26(projectRoot, "package.json");
|
|
33434
|
+
if (!existsSync30(path44)) return null;
|
|
33403
33435
|
try {
|
|
33404
|
-
return JSON.parse(await readFile3(
|
|
33436
|
+
return JSON.parse(await readFile3(path44, "utf8"));
|
|
33405
33437
|
} catch {
|
|
33406
33438
|
return null;
|
|
33407
33439
|
}
|
|
@@ -33483,9 +33515,9 @@ async function genBuild(ctx) {
|
|
|
33483
33515
|
].join("\n");
|
|
33484
33516
|
}
|
|
33485
33517
|
async function genOpenQuestions(ctx) {
|
|
33486
|
-
const
|
|
33487
|
-
if (!existsSync30(
|
|
33488
|
-
const content = readFileSync25(
|
|
33518
|
+
const path44 = join26(ctx.rootDir, "risks.md");
|
|
33519
|
+
if (!existsSync30(path44)) return "_No open questions._";
|
|
33520
|
+
const content = readFileSync25(path44, "utf8");
|
|
33489
33521
|
const lines = content.split("\n");
|
|
33490
33522
|
const questions = [];
|
|
33491
33523
|
let currentTitle = "";
|
|
@@ -34052,8 +34084,8 @@ async function runPostCouncilHook(ctx, options) {
|
|
|
34052
34084
|
sources: scope.sources
|
|
34053
34085
|
} : void 0
|
|
34054
34086
|
});
|
|
34055
|
-
const
|
|
34056
|
-
completionHook = { ran: true, path:
|
|
34087
|
+
const path44 = writeCouncilCompletion(ctx.rootDir, completion);
|
|
34088
|
+
completionHook = { ran: true, path: path44, completion };
|
|
34057
34089
|
} catch (err) {
|
|
34058
34090
|
completionHook = {
|
|
34059
34091
|
ran: true,
|
|
@@ -35272,7 +35304,8 @@ __export(planner_exports, {
|
|
|
35272
35304
|
PlannerTransportError: () => PlannerTransportError,
|
|
35273
35305
|
buildGraphFromPlan: () => buildGraphFromPlan,
|
|
35274
35306
|
extractJsonObject: () => extractJsonObject,
|
|
35275
|
-
planTaskGraph: () => planTaskGraph
|
|
35307
|
+
planTaskGraph: () => planTaskGraph,
|
|
35308
|
+
stripReasoningBlocks: () => stripReasoningBlocks
|
|
35276
35309
|
});
|
|
35277
35310
|
function resolvePlannerTimeoutMs(env = process.env) {
|
|
35278
35311
|
const raw = env.ZELARI_KRAKEN_PLANNER_TIMEOUT_MS;
|
|
@@ -35286,22 +35319,77 @@ function resolvePlannerMaxTokens(env = process.env) {
|
|
|
35286
35319
|
const n = Number.parseInt(raw, 10);
|
|
35287
35320
|
return Number.isFinite(n) && n > 0 ? n : DEFAULT_LLM_MAX_TOKENS;
|
|
35288
35321
|
}
|
|
35289
|
-
function extractJsonObject(text) {
|
|
35290
|
-
const
|
|
35291
|
-
const
|
|
35292
|
-
|
|
35293
|
-
const
|
|
35294
|
-
|
|
35322
|
+
function extractJsonObject(text, opts = {}) {
|
|
35323
|
+
const stripped = stripReasoningBlocks(text);
|
|
35324
|
+
const usable = findJsonIn(stripped, opts);
|
|
35325
|
+
if (usable) return usable.value;
|
|
35326
|
+
const raw = findJsonIn(text, opts);
|
|
35327
|
+
if (raw) return raw.value;
|
|
35328
|
+
const body = bodyOf(stripped) || bodyOf(text);
|
|
35295
35329
|
try {
|
|
35296
|
-
return JSON.parse(
|
|
35330
|
+
return JSON.parse(body);
|
|
35297
35331
|
} catch (err) {
|
|
35298
35332
|
try {
|
|
35299
|
-
return JSON.parse(repairLooseJson(
|
|
35333
|
+
return JSON.parse(repairLooseJson(body));
|
|
35300
35334
|
} catch {
|
|
35301
35335
|
throw err instanceof Error ? err : new Error(String(err));
|
|
35302
35336
|
}
|
|
35303
35337
|
}
|
|
35304
35338
|
}
|
|
35339
|
+
function bodyOf(text) {
|
|
35340
|
+
const trimmed = text.trim();
|
|
35341
|
+
const fenced = /^```(?:json)?\s*([\s\S]*?)```$/i.exec(trimmed);
|
|
35342
|
+
return fenced ? fenced[1].trim() : trimmed;
|
|
35343
|
+
}
|
|
35344
|
+
function findJsonIn(text, opts) {
|
|
35345
|
+
let firstParsed = null;
|
|
35346
|
+
for (const candidate of balancedJsonObjects(bodyOf(text))) {
|
|
35347
|
+
let value;
|
|
35348
|
+
try {
|
|
35349
|
+
value = JSON.parse(candidate);
|
|
35350
|
+
} catch {
|
|
35351
|
+
try {
|
|
35352
|
+
value = JSON.parse(repairLooseJson(candidate));
|
|
35353
|
+
} catch {
|
|
35354
|
+
continue;
|
|
35355
|
+
}
|
|
35356
|
+
}
|
|
35357
|
+
if (!opts.requireKey) return { value };
|
|
35358
|
+
if (value && typeof value === "object" && opts.requireKey in value) {
|
|
35359
|
+
return { value };
|
|
35360
|
+
}
|
|
35361
|
+
const unwrapped = unwrapKey(value, opts.requireKey);
|
|
35362
|
+
if (unwrapped) return { value: unwrapped };
|
|
35363
|
+
if (!firstParsed) firstParsed = { value };
|
|
35364
|
+
}
|
|
35365
|
+
return firstParsed;
|
|
35366
|
+
}
|
|
35367
|
+
function unwrapKey(value, key) {
|
|
35368
|
+
if (!value || typeof value !== "object") return null;
|
|
35369
|
+
for (const child of Object.values(value)) {
|
|
35370
|
+
if (child && typeof child === "object" && key in child) {
|
|
35371
|
+
return child;
|
|
35372
|
+
}
|
|
35373
|
+
}
|
|
35374
|
+
return null;
|
|
35375
|
+
}
|
|
35376
|
+
function stripReasoningBlocks(text) {
|
|
35377
|
+
let out = text.replace(/<(think|thinking|reasoning)>[\s\S]*?<\/\1>/gi, "");
|
|
35378
|
+
const openIdx = out.search(/<(think|thinking|reasoning)>/i);
|
|
35379
|
+
if (openIdx >= 0) out = out.slice(0, openIdx);
|
|
35380
|
+
return out;
|
|
35381
|
+
}
|
|
35382
|
+
function* balancedJsonObjects(s) {
|
|
35383
|
+
let from = 0;
|
|
35384
|
+
while (from < s.length) {
|
|
35385
|
+
const next = extractBalancedJsonObject2(s.slice(from));
|
|
35386
|
+
if (!next) return;
|
|
35387
|
+
yield next;
|
|
35388
|
+
const idx = s.indexOf(next, from);
|
|
35389
|
+
if (idx < 0) return;
|
|
35390
|
+
from = idx + next.length;
|
|
35391
|
+
}
|
|
35392
|
+
}
|
|
35305
35393
|
function extractBalancedJsonObject2(s) {
|
|
35306
35394
|
const start = s.indexOf("{");
|
|
35307
35395
|
if (start < 0) return null;
|
|
@@ -35527,10 +35615,13 @@ async function createDefaultLlmClient(opts) {
|
|
|
35527
35615
|
}
|
|
35528
35616
|
};
|
|
35529
35617
|
}
|
|
35530
|
-
function buildPlannerUserPrompt(prompt) {
|
|
35618
|
+
function buildPlannerUserPrompt(prompt, previousAttempt) {
|
|
35619
|
+
const prev2 = previousAttempt?.trim() ? `
|
|
35620
|
+
${previousAttempt.trim()}
|
|
35621
|
+
` : "";
|
|
35531
35622
|
return `Goal:
|
|
35532
35623
|
${prompt.trim()}
|
|
35533
|
-
|
|
35624
|
+
${prev2}
|
|
35534
35625
|
Return ONLY the JSON object described in the system prompt.`;
|
|
35535
35626
|
}
|
|
35536
35627
|
function uniqueId(base, existing) {
|
|
@@ -35597,14 +35688,19 @@ async function planTaskGraph(opts) {
|
|
|
35597
35688
|
const client = opts.llmClient ?? await createDefaultLlmClient({ provider: opts.provider, model: opts.model });
|
|
35598
35689
|
const maxNodes = opts.maxNodes ?? DEFAULT_MAX_NODES;
|
|
35599
35690
|
const graphId = opts.graphId ?? `kraken-${Date.now().toString(36)}`;
|
|
35600
|
-
const userBase = buildPlannerUserPrompt(opts.prompt);
|
|
35691
|
+
const userBase = buildPlannerUserPrompt(opts.prompt, opts.previousAttempt);
|
|
35601
35692
|
let lastError;
|
|
35602
35693
|
let userMessage = userBase;
|
|
35603
35694
|
for (let attempt = 1; attempt <= MAX_PLAN_ATTEMPTS; attempt++) {
|
|
35604
35695
|
try {
|
|
35605
35696
|
const text = await client.complete({ system: KRAKEN_PLANNER_SYSTEM_PROMPT, user: userMessage });
|
|
35606
|
-
const parsedJson = extractJsonObject(text);
|
|
35697
|
+
const parsedJson = extractJsonObject(text, { requireKey: "nodes" });
|
|
35607
35698
|
const validated = PlannedGraphSchema.parse(parsedJson);
|
|
35699
|
+
if (!validated.nodes.some((n) => n.kind === "general")) {
|
|
35700
|
+
throw new Error(
|
|
35701
|
+
'the plan contains no "general" node, so it cannot change anything \u2014 every node is read-only "explore". Include at least one "general" node that performs the actual work.'
|
|
35702
|
+
);
|
|
35703
|
+
}
|
|
35608
35704
|
const graph = buildGraphFromPlan(graphId, validated.nodes);
|
|
35609
35705
|
const check2 = validateGraph(graph, { maxNodes });
|
|
35610
35706
|
if (!check2.ok) {
|
|
@@ -35682,6 +35778,93 @@ var init_planner = __esm({
|
|
|
35682
35778
|
}
|
|
35683
35779
|
});
|
|
35684
35780
|
|
|
35781
|
+
// src/cli/kraken/graphMemory.ts
|
|
35782
|
+
var graphMemory_exports = {};
|
|
35783
|
+
__export(graphMemory_exports, {
|
|
35784
|
+
formatSnapshotForPlanner: () => formatSnapshotForPlanner,
|
|
35785
|
+
loadGraphSnapshot: () => loadGraphSnapshot,
|
|
35786
|
+
saveGraphSnapshot: () => saveGraphSnapshot,
|
|
35787
|
+
toGraphSnapshot: () => toGraphSnapshot
|
|
35788
|
+
});
|
|
35789
|
+
import { promises as fs19 } from "node:fs";
|
|
35790
|
+
import path34 from "node:path";
|
|
35791
|
+
function snapshotPath(cwd) {
|
|
35792
|
+
return path34.join(cwd, SNAPSHOT_DIR, SNAPSHOT_FILE);
|
|
35793
|
+
}
|
|
35794
|
+
function toGraphSnapshot(graph, opts) {
|
|
35795
|
+
return {
|
|
35796
|
+
graphId: graph.id,
|
|
35797
|
+
goal: opts.goal,
|
|
35798
|
+
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
35799
|
+
converged: opts.converged,
|
|
35800
|
+
nodes: [...graph.nodes.values()].map((n) => ({
|
|
35801
|
+
id: n.id,
|
|
35802
|
+
kind: n.kind,
|
|
35803
|
+
label: n.label,
|
|
35804
|
+
status: n.status,
|
|
35805
|
+
...n.scope && n.scope.length > 0 ? { scope: n.scope } : {},
|
|
35806
|
+
...n.error ? { error: n.error.slice(0, 300) } : {}
|
|
35807
|
+
}))
|
|
35808
|
+
};
|
|
35809
|
+
}
|
|
35810
|
+
async function saveGraphSnapshot(cwd, snapshot) {
|
|
35811
|
+
try {
|
|
35812
|
+
await fs19.access(cwd);
|
|
35813
|
+
const file2 = snapshotPath(cwd);
|
|
35814
|
+
await fs19.mkdir(path34.dirname(file2), { recursive: true });
|
|
35815
|
+
await fs19.writeFile(file2, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
35816
|
+
} catch {
|
|
35817
|
+
}
|
|
35818
|
+
}
|
|
35819
|
+
async function loadGraphSnapshot(cwd) {
|
|
35820
|
+
try {
|
|
35821
|
+
const raw = await fs19.readFile(snapshotPath(cwd), "utf8");
|
|
35822
|
+
const parsed = JSON.parse(raw);
|
|
35823
|
+
if (!parsed || !Array.isArray(parsed.nodes)) return null;
|
|
35824
|
+
return parsed;
|
|
35825
|
+
} catch {
|
|
35826
|
+
return null;
|
|
35827
|
+
}
|
|
35828
|
+
}
|
|
35829
|
+
function formatSnapshotForPlanner(snapshot) {
|
|
35830
|
+
if (!snapshot) return "";
|
|
35831
|
+
const done = snapshot.nodes.filter((n) => n.status === "done");
|
|
35832
|
+
const failed = snapshot.nodes.filter((n) => n.status === "error");
|
|
35833
|
+
const skipped = snapshot.nodes.filter((n) => n.status === "skipped");
|
|
35834
|
+
if (failed.length === 0 && skipped.length === 0) return "";
|
|
35835
|
+
const line = (n) => `- ${n.label}${n.scope ? ` [${n.scope.join(", ")}]` : ""}${n.error ? ` \u2014 ${n.error}` : ""}`;
|
|
35836
|
+
const parts = [
|
|
35837
|
+
"",
|
|
35838
|
+
"## Previous unfinished task graph in this project",
|
|
35839
|
+
`Goal it was working on: "${snapshot.goal}"`,
|
|
35840
|
+
`It did NOT finish (${done.length} done, ${failed.length} failed, ${skipped.length} never ran).`,
|
|
35841
|
+
"",
|
|
35842
|
+
"If that goal is unrelated to the one above, ignore this section entirely.",
|
|
35843
|
+
""
|
|
35844
|
+
];
|
|
35845
|
+
if (done.length > 0) {
|
|
35846
|
+
parts.push("Already completed \u2014 do NOT redo this work:", ...done.map(line), "");
|
|
35847
|
+
}
|
|
35848
|
+
if (failed.length > 0) {
|
|
35849
|
+
parts.push("Failed \u2014 needs to be finished or repaired:", ...failed.map(line), "");
|
|
35850
|
+
}
|
|
35851
|
+
if (skipped.length > 0) {
|
|
35852
|
+
parts.push("Never ran (blocked by the failures above):", ...skipped.map(line), "");
|
|
35853
|
+
}
|
|
35854
|
+
parts.push(
|
|
35855
|
+
"Plan only the remaining work. Inspect what is already on disk before rewriting it, and prefer wiring/finishing existing modules over recreating them."
|
|
35856
|
+
);
|
|
35857
|
+
return parts.join("\n");
|
|
35858
|
+
}
|
|
35859
|
+
var SNAPSHOT_DIR, SNAPSHOT_FILE;
|
|
35860
|
+
var init_graphMemory = __esm({
|
|
35861
|
+
"src/cli/kraken/graphMemory.ts"() {
|
|
35862
|
+
"use strict";
|
|
35863
|
+
SNAPSHOT_DIR = path34.join(".zelari", "kraken");
|
|
35864
|
+
SNAPSHOT_FILE = "last-graph.json";
|
|
35865
|
+
}
|
|
35866
|
+
});
|
|
35867
|
+
|
|
35685
35868
|
// src/cli/kraken/tentacle.ts
|
|
35686
35869
|
var init_tentacle = __esm({
|
|
35687
35870
|
"src/cli/kraken/tentacle.ts"() {
|
|
@@ -35693,6 +35876,7 @@ var init_tentacle = __esm({
|
|
|
35693
35876
|
// src/cli/kraken/executor.ts
|
|
35694
35877
|
var executor_exports = {};
|
|
35695
35878
|
__export(executor_exports, {
|
|
35879
|
+
DEFAULT_CANCEL_GRACE_MS: () => DEFAULT_CANCEL_GRACE_MS,
|
|
35696
35880
|
DEFAULT_FIX_BUDGET: () => DEFAULT_FIX_BUDGET,
|
|
35697
35881
|
DEFAULT_MAX_PARALLEL: () => DEFAULT_MAX_PARALLEL,
|
|
35698
35882
|
DEFAULT_NODE_TIMEOUT_MS: () => DEFAULT_NODE_TIMEOUT_MS,
|
|
@@ -35700,12 +35884,13 @@ __export(executor_exports, {
|
|
|
35700
35884
|
KrakenGraphExecutor: () => KrakenGraphExecutor,
|
|
35701
35885
|
isKrakenGraphEnabled: () => isKrakenGraphEnabled,
|
|
35702
35886
|
isWorldModelGateEnabled: () => isWorldModelGateEnabled,
|
|
35887
|
+
resolveCancelGraceMs: () => resolveCancelGraceMs,
|
|
35703
35888
|
resolveFixBudget: () => resolveFixBudget,
|
|
35704
35889
|
resolveMaxParallel: () => resolveMaxParallel,
|
|
35705
35890
|
resolveNodeTimeoutMs: () => resolveNodeTimeoutMs
|
|
35706
35891
|
});
|
|
35707
35892
|
import { existsSync as existsSync34 } from "node:fs";
|
|
35708
|
-
import
|
|
35893
|
+
import path35 from "node:path";
|
|
35709
35894
|
function resolveMaxParallel(env = process.env) {
|
|
35710
35895
|
const raw = env.ZELARI_KRAKEN_MAX_PARALLEL;
|
|
35711
35896
|
if (raw === void 0 || raw === "") return DEFAULT_MAX_PARALLEL;
|
|
@@ -35718,6 +35903,12 @@ function resolveFixBudget(env = process.env) {
|
|
|
35718
35903
|
const n = Number.parseInt(raw, 10);
|
|
35719
35904
|
return Number.isFinite(n) && n >= 0 ? n : DEFAULT_FIX_BUDGET;
|
|
35720
35905
|
}
|
|
35906
|
+
function resolveCancelGraceMs(env = process.env) {
|
|
35907
|
+
const raw = env.ZELARI_KRAKEN_CANCEL_GRACE_MS;
|
|
35908
|
+
if (raw === void 0 || raw === "") return DEFAULT_CANCEL_GRACE_MS;
|
|
35909
|
+
const n = Number.parseInt(raw, 10);
|
|
35910
|
+
return Number.isFinite(n) && n >= 0 ? n : DEFAULT_CANCEL_GRACE_MS;
|
|
35911
|
+
}
|
|
35721
35912
|
function resolveNodeTimeoutMs(env = process.env, agent) {
|
|
35722
35913
|
const raw = env.ZELARI_KRAKEN_NODE_TIMEOUT_MS;
|
|
35723
35914
|
if (raw !== void 0 && raw !== "") {
|
|
@@ -35743,12 +35934,12 @@ function isWorldModelGateEnabled(cwd, env = process.env, checksExists = defaultC
|
|
|
35743
35934
|
}
|
|
35744
35935
|
function defaultChecksExists(cwd) {
|
|
35745
35936
|
try {
|
|
35746
|
-
return existsSync34(
|
|
35937
|
+
return existsSync34(path35.join(cwd, ".zelari", "world", "checks.json"));
|
|
35747
35938
|
} catch {
|
|
35748
35939
|
return false;
|
|
35749
35940
|
}
|
|
35750
35941
|
}
|
|
35751
|
-
var DEFAULT_MAX_PARALLEL, DEFAULT_FIX_BUDGET, DEFAULT_NODE_TIMEOUT_MS, DEFAULT_WRITER_NODE_TIMEOUT_MS, KrakenGraphExecutor;
|
|
35942
|
+
var DEFAULT_MAX_PARALLEL, DEFAULT_FIX_BUDGET, DEFAULT_NODE_TIMEOUT_MS, DEFAULT_WRITER_NODE_TIMEOUT_MS, DEFAULT_CANCEL_GRACE_MS, KrakenGraphExecutor;
|
|
35752
35943
|
var init_executor = __esm({
|
|
35753
35944
|
"src/cli/kraken/executor.ts"() {
|
|
35754
35945
|
"use strict";
|
|
@@ -35758,17 +35949,21 @@ var init_executor = __esm({
|
|
|
35758
35949
|
init_krakenRadio();
|
|
35759
35950
|
init_worldModel();
|
|
35760
35951
|
init_graphStatus();
|
|
35952
|
+
init_graphMemory();
|
|
35761
35953
|
DEFAULT_MAX_PARALLEL = 12;
|
|
35762
35954
|
DEFAULT_FIX_BUDGET = 3;
|
|
35763
35955
|
DEFAULT_NODE_TIMEOUT_MS = 3e5;
|
|
35764
35956
|
DEFAULT_WRITER_NODE_TIMEOUT_MS = 9e5;
|
|
35957
|
+
DEFAULT_CANCEL_GRACE_MS = 3e4;
|
|
35765
35958
|
KrakenGraphExecutor = class {
|
|
35766
35959
|
deps;
|
|
35767
35960
|
parentCwd;
|
|
35768
35961
|
sessionId;
|
|
35962
|
+
goal;
|
|
35769
35963
|
maxParallel;
|
|
35770
35964
|
/** Explicit all-kinds override; when undefined the budget is per-kind. */
|
|
35771
35965
|
nodeTimeoutMs;
|
|
35966
|
+
cancelGraceMs;
|
|
35772
35967
|
fixBudgetRemaining;
|
|
35773
35968
|
worldModelGateOverride;
|
|
35774
35969
|
runTentacleFn;
|
|
@@ -35780,8 +35975,10 @@ var init_executor = __esm({
|
|
|
35780
35975
|
this.deps = opts.taskToolDeps;
|
|
35781
35976
|
this.parentCwd = opts.parentCwd;
|
|
35782
35977
|
this.sessionId = opts.sessionId;
|
|
35978
|
+
this.goal = opts.goal;
|
|
35783
35979
|
this.maxParallel = opts.maxParallel ?? resolveMaxParallel();
|
|
35784
35980
|
this.nodeTimeoutMs = opts.nodeTimeoutMs;
|
|
35981
|
+
this.cancelGraceMs = opts.cancelGraceMs;
|
|
35785
35982
|
this.fixBudgetRemaining = opts.fixBudget ?? resolveFixBudget();
|
|
35786
35983
|
this.worldModelGateOverride = opts.worldModelGate;
|
|
35787
35984
|
this.runTentacleFn = opts.runTentacleFn ?? runTentacle;
|
|
@@ -35839,6 +36036,10 @@ var init_executor = __esm({
|
|
|
35839
36036
|
});
|
|
35840
36037
|
}
|
|
35841
36038
|
endKrakenGraphLive(graph, converged);
|
|
36039
|
+
await saveGraphSnapshot(
|
|
36040
|
+
this.parentCwd,
|
|
36041
|
+
toGraphSnapshot(graph, { goal: this.goal ?? graph.id, converged })
|
|
36042
|
+
);
|
|
35842
36043
|
return {
|
|
35843
36044
|
graph,
|
|
35844
36045
|
converged,
|
|
@@ -35855,6 +36056,7 @@ var init_executor = __esm({
|
|
|
35855
36056
|
}
|
|
35856
36057
|
const usesWorktree = node.kind === "general" || node.kind === "fix";
|
|
35857
36058
|
const agent = node.kind === "fix" ? "general" : node.kind;
|
|
36059
|
+
const controller = new AbortController();
|
|
35858
36060
|
const res = await this.withNodeTimeout(
|
|
35859
36061
|
this.runTentacleFn({
|
|
35860
36062
|
deps: this.deps,
|
|
@@ -35872,9 +36074,11 @@ var init_executor = __esm({
|
|
|
35872
36074
|
// (Correction 4); explore/verify never create a worktree.
|
|
35873
36075
|
deferMerge: usesWorktree,
|
|
35874
36076
|
graphId: graph.id,
|
|
35875
|
-
nodeId: node.id
|
|
36077
|
+
nodeId: node.id,
|
|
36078
|
+
signal: controller.signal
|
|
35876
36079
|
}),
|
|
35877
|
-
agent
|
|
36080
|
+
agent,
|
|
36081
|
+
controller
|
|
35878
36082
|
);
|
|
35879
36083
|
if (res.ok && usesWorktree) {
|
|
35880
36084
|
this.nodeRunState.set(node.id, { worktreeHandle: res.worktreeHandle });
|
|
@@ -35883,25 +36087,49 @@ var init_executor = __esm({
|
|
|
35883
36087
|
}
|
|
35884
36088
|
/**
|
|
35885
36089
|
* Bound a tentacle run to its wall-clock budget (explicit `nodeTimeoutMs`
|
|
35886
|
-
* option, else per-kind — writers get more than readers). On timeout
|
|
35887
|
-
*
|
|
35888
|
-
*
|
|
35889
|
-
*
|
|
35890
|
-
*
|
|
35891
|
-
*
|
|
36090
|
+
* option, else per-kind — writers get more than readers). On timeout the
|
|
36091
|
+
* run is CANCELLED via its AbortSignal, then given `cancelGraceMs` to
|
|
36092
|
+
* unwind. Cancellation lands at the sub-agent's next event boundary (an
|
|
36093
|
+
* async generator only observes `.return()` when it next yields), so a run
|
|
36094
|
+
* blocked on a slow provider call can outlive the grace period — that case
|
|
36095
|
+
* resolves with `cancelled: false` and `applyResult` refuses to re-spawn
|
|
36096
|
+
* the node, since a tentacle that may still be writing must not be joined
|
|
36097
|
+
* by a second one on the same scope.
|
|
36098
|
+
*
|
|
36099
|
+
* Either way `execute()` always settles, so the caller's process can exit
|
|
36100
|
+
* instead of hanging forever on one stuck node.
|
|
35892
36101
|
*/
|
|
35893
|
-
withNodeTimeout(promise2, agent) {
|
|
36102
|
+
async withNodeTimeout(promise2, agent, controller) {
|
|
35894
36103
|
const ms = this.nodeTimeoutMs ?? resolveNodeTimeoutMs(process.env, agent);
|
|
35895
36104
|
if (ms <= 0) return promise2;
|
|
35896
36105
|
let timer;
|
|
36106
|
+
const TIMED_OUT = Symbol("timeout");
|
|
35897
36107
|
const timeout = new Promise((resolve3) => {
|
|
35898
|
-
timer = setTimeout(() =>
|
|
35899
|
-
resolve3({ ok: false, agent, error: `tentacle timed out after ${ms}ms` });
|
|
35900
|
-
}, ms);
|
|
36108
|
+
timer = setTimeout(() => resolve3(TIMED_OUT), ms);
|
|
35901
36109
|
});
|
|
35902
|
-
|
|
36110
|
+
const raced = await Promise.race([promise2, timeout]).finally(() => {
|
|
35903
36111
|
if (timer) clearTimeout(timer);
|
|
35904
36112
|
});
|
|
36113
|
+
if (raced !== TIMED_OUT) return raced;
|
|
36114
|
+
controller?.abort();
|
|
36115
|
+
const graceMs = this.cancelGraceMs ?? resolveCancelGraceMs();
|
|
36116
|
+
let graceTimer;
|
|
36117
|
+
const grace = new Promise((resolve3) => {
|
|
36118
|
+
graceTimer = setTimeout(() => resolve3(TIMED_OUT), graceMs);
|
|
36119
|
+
});
|
|
36120
|
+
const settled = await Promise.race([promise2, grace]).finally(() => {
|
|
36121
|
+
if (graceTimer) clearTimeout(graceTimer);
|
|
36122
|
+
});
|
|
36123
|
+
if (settled !== TIMED_OUT) {
|
|
36124
|
+
if (settled.ok) return settled;
|
|
36125
|
+
return { ...settled, cancelled: true };
|
|
36126
|
+
}
|
|
36127
|
+
return {
|
|
36128
|
+
ok: false,
|
|
36129
|
+
agent,
|
|
36130
|
+
error: `tentacle timed out after ${ms}ms and did not stop within ${graceMs}ms of being cancelled; not retrying to avoid two tentacles writing the same scope`,
|
|
36131
|
+
cancelled: false
|
|
36132
|
+
};
|
|
35905
36133
|
}
|
|
35906
36134
|
/**
|
|
35907
36135
|
* Sequentially merge every dep node's deferred worktree (in dep order) into
|
|
@@ -35965,6 +36193,16 @@ var init_executor = __esm({
|
|
|
35965
36193
|
return;
|
|
35966
36194
|
}
|
|
35967
36195
|
node.error = res.error;
|
|
36196
|
+
if (res.cancelled === false) {
|
|
36197
|
+
node.status = "error";
|
|
36198
|
+
this.radio("node_end", {
|
|
36199
|
+
description: node.label,
|
|
36200
|
+
agent: node.kind,
|
|
36201
|
+
detail: res.error,
|
|
36202
|
+
ok: false
|
|
36203
|
+
});
|
|
36204
|
+
return;
|
|
36205
|
+
}
|
|
35968
36206
|
if (node.retryCount < node.maxRetries) {
|
|
35969
36207
|
node.retryCount += 1;
|
|
35970
36208
|
node.status = "pending";
|
|
@@ -36453,10 +36691,10 @@ var init_prereqChecks = __esm({
|
|
|
36453
36691
|
|
|
36454
36692
|
// src/cli/plugins/prefs.ts
|
|
36455
36693
|
import { existsSync as existsSync36, readFileSync as readFileSync29, writeFileSync as writeFileSync18, mkdirSync as mkdirSync15 } from "node:fs";
|
|
36456
|
-
import
|
|
36694
|
+
import path36 from "node:path";
|
|
36457
36695
|
import os9 from "node:os";
|
|
36458
36696
|
function getPluginPrefsPath() {
|
|
36459
|
-
return process.env.ZELARI_PLUGINS_PREFS_FILE ??
|
|
36697
|
+
return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path36.join(os9.homedir(), ".tmp", "zelari-code", "plugins.json");
|
|
36460
36698
|
}
|
|
36461
36699
|
function getPluginPrefs() {
|
|
36462
36700
|
const file2 = getPluginPrefsPath();
|
|
@@ -36477,7 +36715,7 @@ function getPluginPrefs() {
|
|
|
36477
36715
|
}
|
|
36478
36716
|
function writePluginPrefs(prefs) {
|
|
36479
36717
|
const file2 = getPluginPrefsPath();
|
|
36480
|
-
mkdirSync15(
|
|
36718
|
+
mkdirSync15(path36.dirname(file2), { recursive: true });
|
|
36481
36719
|
writeFileSync18(file2, JSON.stringify(prefs, null, 2), {
|
|
36482
36720
|
encoding: "utf-8",
|
|
36483
36721
|
mode: 384
|
|
@@ -36514,7 +36752,7 @@ __export(registry_exports, {
|
|
|
36514
36752
|
isBinaryOnPath: () => isBinaryOnPath
|
|
36515
36753
|
});
|
|
36516
36754
|
import { existsSync as existsSync37 } from "node:fs";
|
|
36517
|
-
import
|
|
36755
|
+
import path37 from "node:path";
|
|
36518
36756
|
function detectLocalBin(bin) {
|
|
36519
36757
|
return (cwd) => {
|
|
36520
36758
|
try {
|
|
@@ -36532,7 +36770,7 @@ function isBinaryOnPath(bin, opts = {}) {
|
|
|
36532
36770
|
const platform = opts.platform ?? process.platform;
|
|
36533
36771
|
const exists = opts.exists ?? existsSync37;
|
|
36534
36772
|
const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
|
|
36535
|
-
const pathMod = platform === "win32" ?
|
|
36773
|
+
const pathMod = platform === "win32" ? path37.win32 : path37.posix;
|
|
36536
36774
|
const sep2 = platform === "win32" ? ";" : ":";
|
|
36537
36775
|
const dirs = pathEnv.split(sep2).filter((d) => d.length > 0);
|
|
36538
36776
|
const candidates = [bin];
|
|
@@ -36841,10 +37079,10 @@ __export(triggerLock_exports, {
|
|
|
36841
37079
|
lockPath: () => lockPath,
|
|
36842
37080
|
releaseLock: () => releaseLock
|
|
36843
37081
|
});
|
|
36844
|
-
import { promises as
|
|
36845
|
-
import * as
|
|
37082
|
+
import { promises as fs24 } from "node:fs";
|
|
37083
|
+
import * as path42 from "node:path";
|
|
36846
37084
|
function lockPath(projectRoot) {
|
|
36847
|
-
return
|
|
37085
|
+
return path42.join(projectRoot, ".zelari", "trigger.lock");
|
|
36848
37086
|
}
|
|
36849
37087
|
function isPidAlive(pid) {
|
|
36850
37088
|
try {
|
|
@@ -36857,10 +37095,10 @@ function isPidAlive(pid) {
|
|
|
36857
37095
|
}
|
|
36858
37096
|
async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
|
|
36859
37097
|
const lp = lockPath(projectRoot);
|
|
36860
|
-
const dir =
|
|
36861
|
-
await
|
|
37098
|
+
const dir = path42.dirname(lp);
|
|
37099
|
+
await fs24.mkdir(dir, { recursive: true });
|
|
36862
37100
|
try {
|
|
36863
|
-
const raw = await
|
|
37101
|
+
const raw = await fs24.readFile(lp, "utf8");
|
|
36864
37102
|
const existing = JSON.parse(raw);
|
|
36865
37103
|
if (existing.pid && isPidAlive(existing.pid)) {
|
|
36866
37104
|
return { acquired: false, heldBy: existing.pid, lockPath: lp };
|
|
@@ -36871,13 +37109,13 @@ async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date())
|
|
|
36871
37109
|
pid: process.pid,
|
|
36872
37110
|
acquiredAt: now().toISOString()
|
|
36873
37111
|
};
|
|
36874
|
-
await
|
|
37112
|
+
await fs24.writeFile(lp, JSON.stringify(payload, null, 2) + "\n", "utf8");
|
|
36875
37113
|
return { acquired: true, lockPath: lp };
|
|
36876
37114
|
}
|
|
36877
37115
|
async function releaseLock(projectRoot) {
|
|
36878
37116
|
const lp = lockPath(projectRoot);
|
|
36879
37117
|
try {
|
|
36880
|
-
await
|
|
37118
|
+
await fs24.unlink(lp);
|
|
36881
37119
|
} catch {
|
|
36882
37120
|
}
|
|
36883
37121
|
}
|
|
@@ -37165,12 +37403,12 @@ function ensureHome() {
|
|
|
37165
37403
|
}
|
|
37166
37404
|
}
|
|
37167
37405
|
function loadCompanionConfig() {
|
|
37168
|
-
const
|
|
37169
|
-
if (!existsSync43(
|
|
37406
|
+
const path44 = getCompanionConfigPath();
|
|
37407
|
+
if (!existsSync43(path44)) {
|
|
37170
37408
|
return { projects: [] };
|
|
37171
37409
|
}
|
|
37172
37410
|
try {
|
|
37173
|
-
const raw = JSON.parse(readFileSync34(
|
|
37411
|
+
const raw = JSON.parse(readFileSync34(path44, "utf8"));
|
|
37174
37412
|
const projects = Array.isArray(raw.projects) ? raw.projects.filter(
|
|
37175
37413
|
(p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
|
|
37176
37414
|
).map((p3) => ({
|
|
@@ -37208,16 +37446,16 @@ function loadOrCreateToken(explicit) {
|
|
|
37208
37446
|
return { token: explicit.trim(), created: false };
|
|
37209
37447
|
}
|
|
37210
37448
|
ensureHome();
|
|
37211
|
-
const
|
|
37212
|
-
if (existsSync43(
|
|
37213
|
-
const t = readFileSync34(
|
|
37449
|
+
const path44 = getCompanionTokenPath();
|
|
37450
|
+
if (existsSync43(path44)) {
|
|
37451
|
+
const t = readFileSync34(path44, "utf8").trim();
|
|
37214
37452
|
if (t) return { token: t, created: false };
|
|
37215
37453
|
}
|
|
37216
37454
|
const token = randomBytes3(24).toString("base64url");
|
|
37217
|
-
writeFileSync21(
|
|
37455
|
+
writeFileSync21(path44, token + "\n", "utf8");
|
|
37218
37456
|
try {
|
|
37219
|
-
const
|
|
37220
|
-
|
|
37457
|
+
const fs25 = __require("node:fs");
|
|
37458
|
+
fs25.chmodSync?.(path44, 384);
|
|
37221
37459
|
} catch {
|
|
37222
37460
|
}
|
|
37223
37461
|
return { token, created: true };
|
|
@@ -37242,17 +37480,17 @@ function mergeProjects(cfg, extraPaths) {
|
|
|
37242
37480
|
byId.set(p3.id, p3);
|
|
37243
37481
|
}
|
|
37244
37482
|
for (const raw of extraPaths) {
|
|
37245
|
-
const
|
|
37246
|
-
if (!
|
|
37247
|
-
let id = slugFromPath(
|
|
37483
|
+
const path44 = raw.trim();
|
|
37484
|
+
if (!path44) continue;
|
|
37485
|
+
let id = slugFromPath(path44);
|
|
37248
37486
|
let n = 2;
|
|
37249
|
-
while (byId.has(id) && byId.get(id).path !==
|
|
37250
|
-
id = `${slugFromPath(
|
|
37487
|
+
while (byId.has(id) && byId.get(id).path !== path44) {
|
|
37488
|
+
id = `${slugFromPath(path44)}-${n++}`;
|
|
37251
37489
|
}
|
|
37252
37490
|
byId.set(id, {
|
|
37253
37491
|
id,
|
|
37254
|
-
name: slugFromPath(
|
|
37255
|
-
path:
|
|
37492
|
+
name: slugFromPath(path44),
|
|
37493
|
+
path: path44
|
|
37256
37494
|
});
|
|
37257
37495
|
}
|
|
37258
37496
|
return [...byId.values()];
|
|
@@ -37629,9 +37867,9 @@ async function runCompanionServe(opts = {}) {
|
|
|
37629
37867
|
return;
|
|
37630
37868
|
}
|
|
37631
37869
|
const url2 = parseUrl(req);
|
|
37632
|
-
const
|
|
37870
|
+
const path44 = url2.pathname.replace(/\/+$/, "") || "/";
|
|
37633
37871
|
try {
|
|
37634
|
-
if (req.method === "GET" && (
|
|
37872
|
+
if (req.method === "GET" && (path44 === "/health" || path44 === "/v1/health")) {
|
|
37635
37873
|
sendJson(res, 200, {
|
|
37636
37874
|
ok: true,
|
|
37637
37875
|
service: "zelari-companion",
|
|
@@ -37643,18 +37881,18 @@ async function runCompanionServe(opts = {}) {
|
|
|
37643
37881
|
});
|
|
37644
37882
|
return;
|
|
37645
37883
|
}
|
|
37646
|
-
if (
|
|
37884
|
+
if (path44.startsWith("/v1")) {
|
|
37647
37885
|
if (!tokenMatches(token, getBearer(req))) {
|
|
37648
37886
|
sendJson(res, 401, { ok: false, error: "unauthorized" });
|
|
37649
37887
|
return;
|
|
37650
37888
|
}
|
|
37651
37889
|
}
|
|
37652
|
-
if (req.method === "GET" &&
|
|
37890
|
+
if (req.method === "GET" && path44 === "/v1/config") {
|
|
37653
37891
|
const snap = buildDesktopConfigSnapshot();
|
|
37654
37892
|
sendJson(res, 200, { ok: true, ...snap });
|
|
37655
37893
|
return;
|
|
37656
37894
|
}
|
|
37657
|
-
if (req.method === "GET" &&
|
|
37895
|
+
if (req.method === "GET" && path44 === "/v1/projects") {
|
|
37658
37896
|
sendJson(res, 200, {
|
|
37659
37897
|
ok: true,
|
|
37660
37898
|
projects: projects.map((p3) => ({
|
|
@@ -37665,7 +37903,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
37665
37903
|
});
|
|
37666
37904
|
return;
|
|
37667
37905
|
}
|
|
37668
|
-
if (req.method === "GET" &&
|
|
37906
|
+
if (req.method === "GET" && path44 === "/v1/runs") {
|
|
37669
37907
|
sendJson(res, 200, {
|
|
37670
37908
|
ok: true,
|
|
37671
37909
|
active: runs.getActive(),
|
|
@@ -37683,7 +37921,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
37683
37921
|
});
|
|
37684
37922
|
return;
|
|
37685
37923
|
}
|
|
37686
|
-
if (req.method === "POST" &&
|
|
37924
|
+
if (req.method === "POST" && path44 === "/v1/runs") {
|
|
37687
37925
|
const raw = await readBody(req);
|
|
37688
37926
|
let body = {};
|
|
37689
37927
|
try {
|
|
@@ -37730,7 +37968,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
37730
37968
|
});
|
|
37731
37969
|
return;
|
|
37732
37970
|
}
|
|
37733
|
-
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(
|
|
37971
|
+
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path44);
|
|
37734
37972
|
if (req.method === "GET" && eventsMatch) {
|
|
37735
37973
|
const runId = eventsMatch[1];
|
|
37736
37974
|
const run = runs.getRun(runId);
|
|
@@ -37795,7 +38033,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
37795
38033
|
}, 500);
|
|
37796
38034
|
return;
|
|
37797
38035
|
}
|
|
37798
|
-
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(
|
|
38036
|
+
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path44);
|
|
37799
38037
|
if (req.method === "POST" && cancelMatch) {
|
|
37800
38038
|
const runId = cancelMatch[1];
|
|
37801
38039
|
const result = runs.cancel(runId);
|
|
@@ -37907,11 +38145,11 @@ import { execSync as execSync2 } from "node:child_process";
|
|
|
37907
38145
|
import { existsSync as existsSync45, readFileSync as readFileSync35, readlinkSync, statSync as statSync7 } from "node:fs";
|
|
37908
38146
|
import { createRequire as createRequire3 } from "node:module";
|
|
37909
38147
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
37910
|
-
import
|
|
38148
|
+
import path43 from "node:path";
|
|
37911
38149
|
function findPackageRoot(start) {
|
|
37912
38150
|
let dir = start;
|
|
37913
38151
|
for (let i = 0; i < 6; i += 1) {
|
|
37914
|
-
const candidate =
|
|
38152
|
+
const candidate = path43.join(dir, "package.json");
|
|
37915
38153
|
if (existsSync45(candidate)) {
|
|
37916
38154
|
try {
|
|
37917
38155
|
const pkg = JSON.parse(readFileSync35(candidate, "utf8"));
|
|
@@ -37919,11 +38157,11 @@ function findPackageRoot(start) {
|
|
|
37919
38157
|
} catch {
|
|
37920
38158
|
}
|
|
37921
38159
|
}
|
|
37922
|
-
const parent =
|
|
38160
|
+
const parent = path43.dirname(dir);
|
|
37923
38161
|
if (parent === dir) break;
|
|
37924
38162
|
dir = parent;
|
|
37925
38163
|
}
|
|
37926
|
-
return
|
|
38164
|
+
return path43.resolve(__dirname3, "..", "..", "..");
|
|
37927
38165
|
}
|
|
37928
38166
|
function tryExec(cmd) {
|
|
37929
38167
|
try {
|
|
@@ -37937,7 +38175,7 @@ function tryExec(cmd) {
|
|
|
37937
38175
|
}
|
|
37938
38176
|
function readPackageJson3() {
|
|
37939
38177
|
try {
|
|
37940
|
-
const pkgPath =
|
|
38178
|
+
const pkgPath = path43.join(packageRoot, "package.json");
|
|
37941
38179
|
return JSON.parse(readFileSync35(pkgPath, "utf8"));
|
|
37942
38180
|
} catch {
|
|
37943
38181
|
return null;
|
|
@@ -37953,7 +38191,7 @@ function checkShim(pkgName) {
|
|
|
37953
38191
|
}
|
|
37954
38192
|
const isWin = process.platform === "win32";
|
|
37955
38193
|
const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
|
|
37956
|
-
const shimPath =
|
|
38194
|
+
const shimPath = path43.join(prefix, shimName);
|
|
37957
38195
|
if (!existsSync45(shimPath)) {
|
|
37958
38196
|
return FAIL(
|
|
37959
38197
|
`shim not found at ${shimPath}
|
|
@@ -37981,8 +38219,8 @@ function checkShim(pkgName) {
|
|
|
37981
38219
|
fix: npm install -g ${pkgName}@latest --force`
|
|
37982
38220
|
);
|
|
37983
38221
|
}
|
|
37984
|
-
const resolved =
|
|
37985
|
-
const expected =
|
|
38222
|
+
const resolved = path43.resolve(path43.dirname(shimPath), target);
|
|
38223
|
+
const expected = path43.join(
|
|
37986
38224
|
prefix,
|
|
37987
38225
|
"node_modules",
|
|
37988
38226
|
pkgName,
|
|
@@ -38021,7 +38259,7 @@ function checkNode(pkg) {
|
|
|
38021
38259
|
return OK(`node ${raw}`);
|
|
38022
38260
|
}
|
|
38023
38261
|
function checkBundle() {
|
|
38024
|
-
const bundle =
|
|
38262
|
+
const bundle = path43.join(packageRoot, "dist", "cli", "main.bundled.js");
|
|
38025
38263
|
if (!existsSync45(bundle)) {
|
|
38026
38264
|
return FAIL(
|
|
38027
38265
|
`dist/cli/main.bundled.js missing at ${bundle}
|
|
@@ -38042,7 +38280,7 @@ function checkRuntimeDeps() {
|
|
|
38042
38280
|
const missing = [];
|
|
38043
38281
|
for (const dep of required2) {
|
|
38044
38282
|
try {
|
|
38045
|
-
const localReq = createRequire3(
|
|
38283
|
+
const localReq = createRequire3(path43.join(packageRoot, "package.json"));
|
|
38046
38284
|
localReq.resolve(dep);
|
|
38047
38285
|
} catch {
|
|
38048
38286
|
missing.push(dep);
|
|
@@ -38218,7 +38456,7 @@ var init_doctor = __esm({
|
|
|
38218
38456
|
"use strict";
|
|
38219
38457
|
init_prereqChecks();
|
|
38220
38458
|
require3 = createRequire3(import.meta.url);
|
|
38221
|
-
__dirname3 =
|
|
38459
|
+
__dirname3 = path43.dirname(fileURLToPath2(import.meta.url));
|
|
38222
38460
|
packageRoot = findPackageRoot(__dirname3);
|
|
38223
38461
|
OK = (message) => ({
|
|
38224
38462
|
ok: true,
|
|
@@ -44633,6 +44871,7 @@ init_krakenRadio();
|
|
|
44633
44871
|
init_auditLogger();
|
|
44634
44872
|
init_toolRegistry();
|
|
44635
44873
|
init_planner();
|
|
44874
|
+
init_graphMemory();
|
|
44636
44875
|
init_executor();
|
|
44637
44876
|
init_graphStatus();
|
|
44638
44877
|
async function handleKrakenGraph(ctx, prompt) {
|
|
@@ -44657,12 +44896,22 @@ async function handleKrakenGraph(ctx, prompt) {
|
|
|
44657
44896
|
})
|
|
44658
44897
|
};
|
|
44659
44898
|
try {
|
|
44660
|
-
const
|
|
44899
|
+
const previous = await loadGraphSnapshot(ctx.cwd);
|
|
44900
|
+
const previousAttempt = formatSnapshotForPlanner(previous);
|
|
44901
|
+
if (previousAttempt) {
|
|
44902
|
+
appendSystem(ctx.setMessages, "[kraken] resuming from the previous unfinished graph");
|
|
44903
|
+
}
|
|
44904
|
+
const graph = await planTaskGraph({
|
|
44905
|
+
prompt,
|
|
44906
|
+
graphId: `kraken-${Date.now().toString(36)}`,
|
|
44907
|
+
...previousAttempt ? { previousAttempt } : {}
|
|
44908
|
+
});
|
|
44661
44909
|
appendSystem(ctx.setMessages, formatKrakenGraphAscii(graph));
|
|
44662
44910
|
const executor = new KrakenGraphExecutor({
|
|
44663
44911
|
taskToolDeps,
|
|
44664
44912
|
parentCwd: ctx.cwd,
|
|
44665
|
-
sessionId: ctx.sessionId
|
|
44913
|
+
sessionId: ctx.sessionId,
|
|
44914
|
+
goal: prompt
|
|
44666
44915
|
});
|
|
44667
44916
|
const summary = await executor.execute(graph);
|
|
44668
44917
|
appendSystem(
|
|
@@ -44976,17 +45225,17 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
|
|
|
44976
45225
|
}
|
|
44977
45226
|
|
|
44978
45227
|
// src/cli/slashHandlers/promoteMember.ts
|
|
44979
|
-
import { promises as
|
|
44980
|
-
import
|
|
45228
|
+
import { promises as fs20 } from "node:fs";
|
|
45229
|
+
import path38 from "node:path";
|
|
44981
45230
|
import os10 from "node:os";
|
|
44982
45231
|
async function handlePromoteMember(ctx, memberId) {
|
|
44983
45232
|
try {
|
|
44984
45233
|
const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
44985
45234
|
const { skill, markdown } = promoteMember2(memberId);
|
|
44986
|
-
const skillDir = process.env.ANATHEMA_SKILL_DIR ??
|
|
44987
|
-
await
|
|
44988
|
-
const filePath =
|
|
44989
|
-
await
|
|
45235
|
+
const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path38.join(os10.homedir(), ".tmp", "zelari-code", "skills");
|
|
45236
|
+
await fs20.mkdir(skillDir, { recursive: true });
|
|
45237
|
+
const filePath = path38.join(skillDir, `${skill.id}.md`);
|
|
45238
|
+
await fs20.writeFile(filePath, markdown, "utf8");
|
|
44990
45239
|
appendSystem(
|
|
44991
45240
|
ctx.setMessages,
|
|
44992
45241
|
`[promote-member] ${skill.name} (${memberId}) \u2192 ${filePath}
|
|
@@ -45002,25 +45251,25 @@ async function handlePromoteMember(ctx, memberId) {
|
|
|
45002
45251
|
}
|
|
45003
45252
|
|
|
45004
45253
|
// src/cli/branchManager.ts
|
|
45005
|
-
import { promises as
|
|
45006
|
-
import
|
|
45254
|
+
import { promises as fs21, existsSync as existsSync38, readFileSync as readFileSync30, writeFileSync as writeFileSync19, mkdirSync as mkdirSync16, statSync as statSync4, rmSync as rmSync3 } from "node:fs";
|
|
45255
|
+
import path39 from "node:path";
|
|
45007
45256
|
import os11 from "node:os";
|
|
45008
45257
|
var META_FILENAME = "meta.json";
|
|
45009
45258
|
var SESSIONS_SUBDIR = "sessions";
|
|
45010
45259
|
function getBranchesBaseDir() {
|
|
45011
|
-
return process.env.ANATHEMA_BRANCHES_DIR ??
|
|
45260
|
+
return process.env.ANATHEMA_BRANCHES_DIR ?? path39.join(os11.homedir(), ".tmp", "zelari-code", "branches");
|
|
45012
45261
|
}
|
|
45013
45262
|
function getSessionsBaseDir() {
|
|
45014
|
-
return process.env.ANATHEMA_SESSIONS_DIR ??
|
|
45263
|
+
return process.env.ANATHEMA_SESSIONS_DIR ?? path39.join(os11.homedir(), ".tmp", "zelari-code", "sessions");
|
|
45015
45264
|
}
|
|
45016
45265
|
function branchPathFor(name, baseDir) {
|
|
45017
|
-
return
|
|
45266
|
+
return path39.join(baseDir, name);
|
|
45018
45267
|
}
|
|
45019
45268
|
function metaPathFor(name, baseDir) {
|
|
45020
|
-
return
|
|
45269
|
+
return path39.join(baseDir, name, META_FILENAME);
|
|
45021
45270
|
}
|
|
45022
45271
|
function sessionsPathFor(name, baseDir) {
|
|
45023
|
-
return
|
|
45272
|
+
return path39.join(baseDir, name, SESSIONS_SUBDIR);
|
|
45024
45273
|
}
|
|
45025
45274
|
function readBranchMeta(name, baseDir) {
|
|
45026
45275
|
const metaPath = metaPathFor(name, baseDir);
|
|
@@ -45045,13 +45294,13 @@ function readBranchMeta(name, baseDir) {
|
|
|
45045
45294
|
}
|
|
45046
45295
|
function writeBranchMeta(name, baseDir, meta3) {
|
|
45047
45296
|
const metaPath = metaPathFor(name, baseDir);
|
|
45048
|
-
mkdirSync16(
|
|
45297
|
+
mkdirSync16(path39.dirname(metaPath), { recursive: true });
|
|
45049
45298
|
writeFileSync19(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
|
|
45050
45299
|
}
|
|
45051
45300
|
async function countSessions(name, baseDir) {
|
|
45052
45301
|
const sessionsPath = sessionsPathFor(name, baseDir);
|
|
45053
45302
|
try {
|
|
45054
|
-
const entries = await
|
|
45303
|
+
const entries = await fs21.readdir(sessionsPath);
|
|
45055
45304
|
return entries.filter((e) => e.endsWith(".jsonl")).length;
|
|
45056
45305
|
} catch (err) {
|
|
45057
45306
|
if (err.code === "ENOENT") return 0;
|
|
@@ -45096,15 +45345,15 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
45096
45345
|
if (branchExists(name, baseDir)) {
|
|
45097
45346
|
throw new BranchAlreadyExistsError(name);
|
|
45098
45347
|
}
|
|
45099
|
-
const sourcePath =
|
|
45348
|
+
const sourcePath = path39.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
|
|
45100
45349
|
if (!existsSync38(sourcePath)) {
|
|
45101
45350
|
throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
|
|
45102
45351
|
}
|
|
45103
45352
|
const branchPath = branchPathFor(name, baseDir);
|
|
45104
45353
|
const branchSessionsPath = sessionsPathFor(name, baseDir);
|
|
45105
45354
|
mkdirSync16(branchSessionsPath, { recursive: true });
|
|
45106
|
-
const destPath =
|
|
45107
|
-
await
|
|
45355
|
+
const destPath = path39.join(branchSessionsPath, `${fromSessionId}.jsonl`);
|
|
45356
|
+
await fs21.copyFile(sourcePath, destPath);
|
|
45108
45357
|
const meta3 = {
|
|
45109
45358
|
name,
|
|
45110
45359
|
createdAt: Date.now(),
|
|
@@ -45122,7 +45371,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
45122
45371
|
async function listBranches(baseDir = getBranchesBaseDir()) {
|
|
45123
45372
|
let entries;
|
|
45124
45373
|
try {
|
|
45125
|
-
entries = await
|
|
45374
|
+
entries = await fs21.readdir(baseDir);
|
|
45126
45375
|
} catch (err) {
|
|
45127
45376
|
if (err.code === "ENOENT") return [];
|
|
45128
45377
|
throw err;
|
|
@@ -45203,26 +45452,26 @@ async function handleBranchCheckout(ctx, branchName) {
|
|
|
45203
45452
|
}
|
|
45204
45453
|
|
|
45205
45454
|
// src/cli/slashHandlers/workspace.ts
|
|
45206
|
-
import { promises as
|
|
45207
|
-
import
|
|
45455
|
+
import { promises as fs22 } from "node:fs";
|
|
45456
|
+
import path40 from "node:path";
|
|
45208
45457
|
async function handleWorkspaceShow(ctx, what) {
|
|
45209
45458
|
try {
|
|
45210
|
-
const zelari =
|
|
45459
|
+
const zelari = path40.join(process.cwd(), ".zelari");
|
|
45211
45460
|
let content;
|
|
45212
45461
|
switch (what) {
|
|
45213
45462
|
case "plan": {
|
|
45214
|
-
const planPath =
|
|
45463
|
+
const planPath = path40.join(zelari, "plan.md");
|
|
45215
45464
|
try {
|
|
45216
|
-
content = await
|
|
45465
|
+
content = await fs22.readFile(planPath, "utf-8");
|
|
45217
45466
|
} catch {
|
|
45218
45467
|
content = "(no plan.md yet \u2014 run a council session first)";
|
|
45219
45468
|
}
|
|
45220
45469
|
break;
|
|
45221
45470
|
}
|
|
45222
45471
|
case "decisions": {
|
|
45223
|
-
const decisionsDir =
|
|
45472
|
+
const decisionsDir = path40.join(zelari, "decisions");
|
|
45224
45473
|
try {
|
|
45225
|
-
const files = (await
|
|
45474
|
+
const files = (await fs22.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
45226
45475
|
if (files.length === 0) {
|
|
45227
45476
|
content = "(no ADRs yet \u2014 invoke /council to generate some)";
|
|
45228
45477
|
} else {
|
|
@@ -45230,7 +45479,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
45230
45479
|
`];
|
|
45231
45480
|
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
|
|
45232
45481
|
for (const f of files) {
|
|
45233
|
-
const raw = await
|
|
45482
|
+
const raw = await fs22.readFile(path40.join(decisionsDir, f), "utf-8");
|
|
45234
45483
|
const { meta: meta3, body } = parseFrontmatter2(raw);
|
|
45235
45484
|
const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
|
|
45236
45485
|
lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
|
|
@@ -45243,27 +45492,27 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
45243
45492
|
break;
|
|
45244
45493
|
}
|
|
45245
45494
|
case "risks": {
|
|
45246
|
-
const risksPath =
|
|
45495
|
+
const risksPath = path40.join(zelari, "risks.md");
|
|
45247
45496
|
try {
|
|
45248
|
-
content = await
|
|
45497
|
+
content = await fs22.readFile(risksPath, "utf-8");
|
|
45249
45498
|
} catch {
|
|
45250
45499
|
content = "(no risks.md yet)";
|
|
45251
45500
|
}
|
|
45252
45501
|
break;
|
|
45253
45502
|
}
|
|
45254
45503
|
case "agents": {
|
|
45255
|
-
const agentsPath =
|
|
45504
|
+
const agentsPath = path40.join(process.cwd(), "AGENTS.MD");
|
|
45256
45505
|
try {
|
|
45257
|
-
content = await
|
|
45506
|
+
content = await fs22.readFile(agentsPath, "utf-8");
|
|
45258
45507
|
} catch {
|
|
45259
45508
|
content = "(no AGENTS.MD yet at project root \u2014 run `/workspace sync` after a council session)";
|
|
45260
45509
|
}
|
|
45261
45510
|
break;
|
|
45262
45511
|
}
|
|
45263
45512
|
case "docs": {
|
|
45264
|
-
const docsDir =
|
|
45513
|
+
const docsDir = path40.join(zelari, "docs");
|
|
45265
45514
|
try {
|
|
45266
|
-
const files = (await
|
|
45515
|
+
const files = (await fs22.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
45267
45516
|
content = files.length ? `# Docs (${files.length})
|
|
45268
45517
|
|
|
45269
45518
|
` + files.map((f) => `- ${f}`).join("\n") : "(no docs drafts yet)";
|
|
@@ -45303,8 +45552,8 @@ async function handleWorkspaceReset(ctx, force) {
|
|
|
45303
45552
|
return;
|
|
45304
45553
|
}
|
|
45305
45554
|
try {
|
|
45306
|
-
const target =
|
|
45307
|
-
await
|
|
45555
|
+
const target = path40.join(process.cwd(), ".zelari");
|
|
45556
|
+
await fs22.rm(target, { recursive: true, force: true });
|
|
45308
45557
|
appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
|
|
45309
45558
|
} catch (err) {
|
|
45310
45559
|
appendSystem(ctx.setMessages, `[workspace reset error] ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -45663,16 +45912,16 @@ function handleModelsRefresh(ctx) {
|
|
|
45663
45912
|
}
|
|
45664
45913
|
|
|
45665
45914
|
// src/cli/slashHandlers/skills.ts
|
|
45666
|
-
import
|
|
45915
|
+
import path41 from "node:path";
|
|
45667
45916
|
import os12 from "node:os";
|
|
45668
45917
|
|
|
45669
45918
|
// src/cli/skillHistory.ts
|
|
45670
|
-
import { promises as
|
|
45919
|
+
import { promises as fs23, existsSync as existsSync39, statSync as statSync5, renameSync as renameSync4, appendFileSync as appendFileSync4, mkdirSync as mkdirSync17 } from "node:fs";
|
|
45671
45920
|
var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
45672
45921
|
async function readSkillHistory(file2) {
|
|
45673
45922
|
let raw = "";
|
|
45674
45923
|
try {
|
|
45675
|
-
raw = await
|
|
45924
|
+
raw = await fs23.readFile(file2, "utf-8");
|
|
45676
45925
|
} catch {
|
|
45677
45926
|
return [];
|
|
45678
45927
|
}
|
|
@@ -45789,7 +46038,7 @@ function handleSkillPicker(ctx, skills, openPicker, fallbackMessage) {
|
|
|
45789
46038
|
});
|
|
45790
46039
|
}
|
|
45791
46040
|
async function handleSkillStats(ctx, skillId) {
|
|
45792
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
46041
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path41.join(os12.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
45793
46042
|
try {
|
|
45794
46043
|
const records = await readSkillHistory(historyFile);
|
|
45795
46044
|
const stats = getSkillStats(records, skillId);
|
|
@@ -45805,7 +46054,7 @@ async function handleSkillCompare(ctx, ids, fallbackMessage) {
|
|
|
45805
46054
|
appendSystem(ctx.setMessages, fallbackMessage ?? "[skill-compare] missing args");
|
|
45806
46055
|
return;
|
|
45807
46056
|
}
|
|
45808
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
46057
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path41.join(os12.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
45809
46058
|
try {
|
|
45810
46059
|
const formatted = await compareSkillsFromFile(ids[0], ids[1], historyFile);
|
|
45811
46060
|
appendSystem(ctx.setMessages, formatted);
|
|
@@ -47530,6 +47779,7 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
47530
47779
|
return 1;
|
|
47531
47780
|
}
|
|
47532
47781
|
const { planTaskGraph: planTaskGraph2 } = await Promise.resolve().then(() => (init_planner(), planner_exports));
|
|
47782
|
+
const { loadGraphSnapshot: loadGraphSnapshot2, formatSnapshotForPlanner: formatSnapshotForPlanner2 } = await Promise.resolve().then(() => (init_graphMemory(), graphMemory_exports));
|
|
47533
47783
|
const { formatKrakenGraphAscii: formatKrakenGraphAscii2 } = await Promise.resolve().then(() => (init_graphStatus(), graphStatus_exports));
|
|
47534
47784
|
const { AuditLogger: AuditLogger2 } = await Promise.resolve().then(() => (init_auditLogger(), auditLogger_exports));
|
|
47535
47785
|
const { createKrakenSubAgentContextFactory: createKrakenSubAgentContextFactory2 } = await Promise.resolve().then(() => (init_toolRegistry(), toolRegistry_exports));
|
|
@@ -47545,7 +47795,15 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
47545
47795
|
};
|
|
47546
47796
|
try {
|
|
47547
47797
|
log(`planning kraken graph: ${prompt}`);
|
|
47548
|
-
const
|
|
47798
|
+
const previous = await loadGraphSnapshot2(cwd);
|
|
47799
|
+
const previousAttempt = formatSnapshotForPlanner2(previous);
|
|
47800
|
+
if (previousAttempt) log("resuming from the previous unfinished graph");
|
|
47801
|
+
const graph = await planTaskGraph2({
|
|
47802
|
+
prompt,
|
|
47803
|
+
provider,
|
|
47804
|
+
model,
|
|
47805
|
+
...previousAttempt ? { previousAttempt } : {}
|
|
47806
|
+
});
|
|
47549
47807
|
log(formatKrakenGraphAscii2(graph));
|
|
47550
47808
|
const audit = new AuditLogger2();
|
|
47551
47809
|
const executor = new KrakenGraphExecutor2({
|
|
@@ -47564,7 +47822,8 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
47564
47822
|
})
|
|
47565
47823
|
},
|
|
47566
47824
|
parentCwd: cwd,
|
|
47567
|
-
sessionId
|
|
47825
|
+
sessionId,
|
|
47826
|
+
goal: prompt
|
|
47568
47827
|
});
|
|
47569
47828
|
const summary = await executor.execute(graph);
|
|
47570
47829
|
const finalAscii = formatKrakenGraphAscii2(summary.graph);
|
|
@@ -48709,7 +48968,7 @@ function upsertSkill(opts) {
|
|
|
48709
48968
|
}
|
|
48710
48969
|
dir = getProjectSkillsDir(root);
|
|
48711
48970
|
}
|
|
48712
|
-
const
|
|
48971
|
+
const path44 = skillFilePath(dir, name);
|
|
48713
48972
|
const content = serializeSkillMd({
|
|
48714
48973
|
name,
|
|
48715
48974
|
description,
|
|
@@ -48718,13 +48977,13 @@ function upsertSkill(opts) {
|
|
|
48718
48977
|
tools: opts.tools,
|
|
48719
48978
|
cost: opts.cost
|
|
48720
48979
|
});
|
|
48721
|
-
const parsed = parseSkillMd(content,
|
|
48980
|
+
const parsed = parseSkillMd(content, path44);
|
|
48722
48981
|
if (!parsed) {
|
|
48723
48982
|
return { ok: false, error: "Generated SKILL.md failed validation" };
|
|
48724
48983
|
}
|
|
48725
|
-
mkdirSync18(dirname9(
|
|
48726
|
-
writeFileSync20(
|
|
48727
|
-
return { ok: true, path:
|
|
48984
|
+
mkdirSync18(dirname9(path44), { recursive: true });
|
|
48985
|
+
writeFileSync20(path44, content, "utf8");
|
|
48986
|
+
return { ok: true, path: path44 };
|
|
48728
48987
|
}
|
|
48729
48988
|
function removeSkill(opts) {
|
|
48730
48989
|
const name = opts.name.trim().toLowerCase();
|
|
@@ -48742,8 +49001,8 @@ function removeSkill(opts) {
|
|
|
48742
49001
|
dir = getProjectSkillsDir(root);
|
|
48743
49002
|
}
|
|
48744
49003
|
const skillDir = join34(dir, name);
|
|
48745
|
-
const
|
|
48746
|
-
if (!existsSync42(
|
|
49004
|
+
const path44 = skillFilePath(dir, name);
|
|
49005
|
+
if (!existsSync42(path44) && !existsSync42(skillDir)) {
|
|
48747
49006
|
return { ok: false, error: `Skill "${name}" not found in ${dir}` };
|
|
48748
49007
|
}
|
|
48749
49008
|
try {
|
|
@@ -48754,7 +49013,7 @@ function removeSkill(opts) {
|
|
|
48754
49013
|
error: err instanceof Error ? err.message : String(err)
|
|
48755
49014
|
};
|
|
48756
49015
|
}
|
|
48757
|
-
return { ok: true, path:
|
|
49016
|
+
return { ok: true, path: path44 };
|
|
48758
49017
|
}
|
|
48759
49018
|
|
|
48760
49019
|
// src/cli/generateSkillFromUrl.ts
|
|
@@ -48844,8 +49103,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
|
|
|
48844
49103
|
let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
48845
49104
|
if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
|
|
48846
49105
|
try {
|
|
48847
|
-
const
|
|
48848
|
-
name =
|
|
49106
|
+
const path44 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
49107
|
+
name = path44 && /^[a-z0-9]/.test(path44) ? path44 : "imported-skill";
|
|
48849
49108
|
} catch {
|
|
48850
49109
|
name = "imported-skill";
|
|
48851
49110
|
}
|