zelari-code 2.11.2 → 2.12.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 +16 -5
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +17 -4
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/kraken/completionProof.js +176 -0
- package/dist/cli/kraken/completionProof.js.map +1 -0
- package/dist/cli/kraken/nativeVerification.js +12 -5
- package/dist/cli/kraken/nativeVerification.js.map +1 -1
- package/dist/cli/kraken/verificationBridge.js +5 -1
- package/dist/cli/kraken/verificationBridge.js.map +1 -1
- package/dist/cli/kraken/verifierLifecycle.js +72 -8
- package/dist/cli/kraken/verifierLifecycle.js.map +1 -1
- package/dist/cli/main.bundled.js +949 -396
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/orchestration/policy.js +88 -0
- package/dist/cli/orchestration/policy.js.map +1 -0
- package/dist/cli/runHeadless.js +49 -0
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/safety/policyEngine.js +280 -0
- package/dist/cli/safety/policyEngine.js.map +1 -0
- package/dist/cli/safety/toolPermissions.js +38 -0
- package/dist/cli/safety/toolPermissions.js.map +1 -1
- package/dist/cli/toolRegistry.js +40 -9
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/krakenModel.js +75 -0
- package/dist/cli/tools/krakenModel.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -3288,10 +3288,10 @@ function mergeDefs(...defs) {
|
|
|
3288
3288
|
function cloneDef(schema) {
|
|
3289
3289
|
return mergeDefs(schema._zod.def);
|
|
3290
3290
|
}
|
|
3291
|
-
function getElementAtPath(obj,
|
|
3292
|
-
if (!
|
|
3291
|
+
function getElementAtPath(obj, path74) {
|
|
3292
|
+
if (!path74)
|
|
3293
3293
|
return obj;
|
|
3294
|
-
return
|
|
3294
|
+
return path74.reduce((acc, key) => acc?.[key], obj);
|
|
3295
3295
|
}
|
|
3296
3296
|
function promiseAllObject(promisesObj) {
|
|
3297
3297
|
const keys = Object.keys(promisesObj);
|
|
@@ -3619,11 +3619,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
3619
3619
|
}
|
|
3620
3620
|
return false;
|
|
3621
3621
|
}
|
|
3622
|
-
function prefixIssues(
|
|
3622
|
+
function prefixIssues(path74, issues) {
|
|
3623
3623
|
return issues.map((iss) => {
|
|
3624
3624
|
var _a3;
|
|
3625
3625
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
3626
|
-
iss.path.unshift(
|
|
3626
|
+
iss.path.unshift(path74);
|
|
3627
3627
|
return iss;
|
|
3628
3628
|
});
|
|
3629
3629
|
}
|
|
@@ -3841,16 +3841,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3841
3841
|
}
|
|
3842
3842
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
3843
3843
|
const fieldErrors = { _errors: [] };
|
|
3844
|
-
const processError = (error52,
|
|
3844
|
+
const processError = (error52, path74 = []) => {
|
|
3845
3845
|
for (const issue2 of error52.issues) {
|
|
3846
3846
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3847
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
3847
|
+
issue2.errors.map((issues) => processError({ issues }, [...path74, ...issue2.path]));
|
|
3848
3848
|
} else if (issue2.code === "invalid_key") {
|
|
3849
|
-
processError({ issues: issue2.issues }, [...
|
|
3849
|
+
processError({ issues: issue2.issues }, [...path74, ...issue2.path]);
|
|
3850
3850
|
} else if (issue2.code === "invalid_element") {
|
|
3851
|
-
processError({ issues: issue2.issues }, [...
|
|
3851
|
+
processError({ issues: issue2.issues }, [...path74, ...issue2.path]);
|
|
3852
3852
|
} else {
|
|
3853
|
-
const fullpath = [...
|
|
3853
|
+
const fullpath = [...path74, ...issue2.path];
|
|
3854
3854
|
if (fullpath.length === 0) {
|
|
3855
3855
|
fieldErrors._errors.push(mapper(issue2));
|
|
3856
3856
|
} else {
|
|
@@ -3877,17 +3877,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3877
3877
|
}
|
|
3878
3878
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
3879
3879
|
const result = { errors: [] };
|
|
3880
|
-
const processError = (error52,
|
|
3880
|
+
const processError = (error52, path74 = []) => {
|
|
3881
3881
|
var _a3, _b;
|
|
3882
3882
|
for (const issue2 of error52.issues) {
|
|
3883
3883
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3884
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
3884
|
+
issue2.errors.map((issues) => processError({ issues }, [...path74, ...issue2.path]));
|
|
3885
3885
|
} else if (issue2.code === "invalid_key") {
|
|
3886
|
-
processError({ issues: issue2.issues }, [...
|
|
3886
|
+
processError({ issues: issue2.issues }, [...path74, ...issue2.path]);
|
|
3887
3887
|
} else if (issue2.code === "invalid_element") {
|
|
3888
|
-
processError({ issues: issue2.issues }, [...
|
|
3888
|
+
processError({ issues: issue2.issues }, [...path74, ...issue2.path]);
|
|
3889
3889
|
} else {
|
|
3890
|
-
const fullpath = [...
|
|
3890
|
+
const fullpath = [...path74, ...issue2.path];
|
|
3891
3891
|
if (fullpath.length === 0) {
|
|
3892
3892
|
result.errors.push(mapper(issue2));
|
|
3893
3893
|
continue;
|
|
@@ -3919,8 +3919,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3919
3919
|
}
|
|
3920
3920
|
function toDotPath(_path) {
|
|
3921
3921
|
const segs = [];
|
|
3922
|
-
const
|
|
3923
|
-
for (const seg of
|
|
3922
|
+
const path74 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
3923
|
+
for (const seg of path74) {
|
|
3924
3924
|
if (typeof seg === "number")
|
|
3925
3925
|
segs.push(`[${seg}]`);
|
|
3926
3926
|
else if (typeof seg === "symbol")
|
|
@@ -17423,13 +17423,13 @@ function resolveRef(ref, ctx) {
|
|
|
17423
17423
|
if (!ref.startsWith("#")) {
|
|
17424
17424
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
17425
17425
|
}
|
|
17426
|
-
const
|
|
17427
|
-
if (
|
|
17426
|
+
const path74 = ref.slice(1).split("/").filter(Boolean);
|
|
17427
|
+
if (path74.length === 0) {
|
|
17428
17428
|
return ctx.rootSchema;
|
|
17429
17429
|
}
|
|
17430
17430
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
17431
|
-
if (
|
|
17432
|
-
const key =
|
|
17431
|
+
if (path74[0] === defsKey) {
|
|
17432
|
+
const key = path74[1];
|
|
17433
17433
|
if (!key || !ctx.defs[key]) {
|
|
17434
17434
|
throw new Error(`Reference not found: ${ref}`);
|
|
17435
17435
|
}
|
|
@@ -19765,11 +19765,11 @@ var init_tools = __esm({
|
|
|
19765
19765
|
if (!ctx.addDocument)
|
|
19766
19766
|
return "Knowledge vault tool not available.";
|
|
19767
19767
|
const title = args["title"] || "New Document";
|
|
19768
|
-
const
|
|
19768
|
+
const path74 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
19769
19769
|
const content = args["content"] || "";
|
|
19770
19770
|
const tags = args["tags"] || [];
|
|
19771
19771
|
ctx.addDocument({
|
|
19772
|
-
path:
|
|
19772
|
+
path: path74,
|
|
19773
19773
|
title,
|
|
19774
19774
|
content,
|
|
19775
19775
|
format: "markdown",
|
|
@@ -19778,7 +19778,7 @@ var init_tools = __esm({
|
|
|
19778
19778
|
workspaceId: ctx.workspaceId
|
|
19779
19779
|
});
|
|
19780
19780
|
ctx.addActivity("vault", "created document", title);
|
|
19781
|
-
return `Document "${title}" created at "${
|
|
19781
|
+
return `Document "${title}" created at "${path74}".`;
|
|
19782
19782
|
}
|
|
19783
19783
|
}
|
|
19784
19784
|
];
|
|
@@ -25734,11 +25734,11 @@ var init_synthesisAudit = __esm({
|
|
|
25734
25734
|
import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "node:fs";
|
|
25735
25735
|
import { join as join4 } from "node:path";
|
|
25736
25736
|
function loadNfrSpec(zelariRoot) {
|
|
25737
|
-
const
|
|
25738
|
-
if (!existsSync7(
|
|
25737
|
+
const path74 = join4(zelariRoot, "nfr-spec.json");
|
|
25738
|
+
if (!existsSync7(path74))
|
|
25739
25739
|
return null;
|
|
25740
25740
|
try {
|
|
25741
|
-
const raw = JSON.parse(readFileSync7(
|
|
25741
|
+
const raw = JSON.parse(readFileSync7(path74, "utf8"));
|
|
25742
25742
|
if (raw.version !== 1 || !Array.isArray(raw.targets))
|
|
25743
25743
|
return null;
|
|
25744
25744
|
return raw;
|
|
@@ -28044,9 +28044,9 @@ var init_types5 = __esm({
|
|
|
28044
28044
|
import { readFileSync as readFileSync12 } from "node:fs";
|
|
28045
28045
|
import { join as join10 } from "node:path";
|
|
28046
28046
|
function readLessonsDeduped(zelariRoot) {
|
|
28047
|
-
const
|
|
28047
|
+
const path74 = join10(zelariRoot, LESSONS_FILE);
|
|
28048
28048
|
try {
|
|
28049
|
-
const raw = readFileSync12(
|
|
28049
|
+
const raw = readFileSync12(path74, "utf8");
|
|
28050
28050
|
const byId = /* @__PURE__ */ new Map();
|
|
28051
28051
|
for (const line of raw.split(/\r?\n/)) {
|
|
28052
28052
|
if (!line.trim())
|
|
@@ -28147,8 +28147,8 @@ function keywordsFrom(check2, signature) {
|
|
|
28147
28147
|
return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
|
|
28148
28148
|
}
|
|
28149
28149
|
function writeLesson(zelariRoot, lesson) {
|
|
28150
|
-
const
|
|
28151
|
-
appendFileSync(
|
|
28150
|
+
const path74 = join11(zelariRoot, LESSONS_FILE);
|
|
28151
|
+
appendFileSync(path74, `${JSON.stringify(lesson)}
|
|
28152
28152
|
`, "utf8");
|
|
28153
28153
|
}
|
|
28154
28154
|
function findSimilar(lessons, signature) {
|
|
@@ -30111,9 +30111,9 @@ function findCycle(nodes) {
|
|
|
30111
30111
|
if (color.get(start) !== WHITE)
|
|
30112
30112
|
continue;
|
|
30113
30113
|
const stack = [[start, 0]];
|
|
30114
|
-
const
|
|
30114
|
+
const path74 = [];
|
|
30115
30115
|
color.set(start, GRAY);
|
|
30116
|
-
|
|
30116
|
+
path74.push(start);
|
|
30117
30117
|
while (stack.length > 0) {
|
|
30118
30118
|
const top = stack[stack.length - 1];
|
|
30119
30119
|
const [id3, idx] = top;
|
|
@@ -30126,17 +30126,17 @@ function findCycle(nodes) {
|
|
|
30126
30126
|
continue;
|
|
30127
30127
|
const c = color.get(dep);
|
|
30128
30128
|
if (c === GRAY) {
|
|
30129
|
-
const at =
|
|
30130
|
-
return [...
|
|
30129
|
+
const at = path74.indexOf(dep);
|
|
30130
|
+
return [...path74.slice(at), dep];
|
|
30131
30131
|
}
|
|
30132
30132
|
if (c === WHITE) {
|
|
30133
30133
|
color.set(dep, GRAY);
|
|
30134
|
-
|
|
30134
|
+
path74.push(dep);
|
|
30135
30135
|
stack.push([dep, 0]);
|
|
30136
30136
|
}
|
|
30137
30137
|
} else {
|
|
30138
30138
|
color.set(id3, BLACK);
|
|
30139
|
-
|
|
30139
|
+
path74.pop();
|
|
30140
30140
|
stack.pop();
|
|
30141
30141
|
}
|
|
30142
30142
|
}
|
|
@@ -31056,8 +31056,8 @@ var init_runner = __esm({
|
|
|
31056
31056
|
failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
|
|
31057
31057
|
pending: []
|
|
31058
31058
|
};
|
|
31059
|
-
const
|
|
31060
|
-
this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${
|
|
31059
|
+
const path74 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
|
|
31060
|
+
this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path74}`);
|
|
31061
31061
|
return snapshot;
|
|
31062
31062
|
}
|
|
31063
31063
|
callLog(msg, data) {
|
|
@@ -33499,16 +33499,16 @@ function runRetentionFromEnv() {
|
|
|
33499
33499
|
maxTotalBytes: Number.isFinite(parseMb) && parseMb > 0 ? Math.round(parseMb * 1024 * 1024) : DEFAULT_RUN_RETENTION_MAX_MB * 1024 * 1024
|
|
33500
33500
|
};
|
|
33501
33501
|
}
|
|
33502
|
-
async function dirSize(
|
|
33502
|
+
async function dirSize(path74) {
|
|
33503
33503
|
let total = 0;
|
|
33504
33504
|
let entries;
|
|
33505
33505
|
try {
|
|
33506
|
-
entries = await readdir(
|
|
33506
|
+
entries = await readdir(path74, { withFileTypes: true });
|
|
33507
33507
|
} catch {
|
|
33508
33508
|
return 0;
|
|
33509
33509
|
}
|
|
33510
33510
|
for (const entry of entries) {
|
|
33511
|
-
const child = join13(
|
|
33511
|
+
const child = join13(path74, entry.name);
|
|
33512
33512
|
if (entry.isDirectory())
|
|
33513
33513
|
total += await dirSize(child);
|
|
33514
33514
|
else {
|
|
@@ -33535,19 +33535,19 @@ async function enforceRunRetention(runsDir, options = {}) {
|
|
|
33535
33535
|
for (const entry of entries) {
|
|
33536
33536
|
if (!entry.isDirectory())
|
|
33537
33537
|
continue;
|
|
33538
|
-
const
|
|
33538
|
+
const path74 = join13(runsDir, entry.name);
|
|
33539
33539
|
let startedAt = 0;
|
|
33540
33540
|
let endedAt;
|
|
33541
33541
|
let completed = false;
|
|
33542
33542
|
try {
|
|
33543
|
-
const manifest = JSON.parse(await readFile(join13(
|
|
33543
|
+
const manifest = JSON.parse(await readFile(join13(path74, "manifest.json"), "utf8"));
|
|
33544
33544
|
startedAt = manifest.startedAt ?? 0;
|
|
33545
33545
|
endedAt = manifest.endedAt;
|
|
33546
33546
|
completed = Boolean(endedAt) && manifest.status !== "running";
|
|
33547
33547
|
} catch {
|
|
33548
33548
|
completed = false;
|
|
33549
33549
|
}
|
|
33550
|
-
infos.push({ name: entry.name, path:
|
|
33550
|
+
infos.push({ name: entry.name, path: path74, startedAt, endedAt, completed, bytes: await dirSize(path74) });
|
|
33551
33551
|
}
|
|
33552
33552
|
const remove = async (info) => {
|
|
33553
33553
|
await rm(info.path, { recursive: true, force: true });
|
|
@@ -34319,12 +34319,12 @@ var init_engine = __esm({
|
|
|
34319
34319
|
* content digest) and the returned ref carries the event seq when the
|
|
34320
34320
|
* emitter resolved one.
|
|
34321
34321
|
*/
|
|
34322
|
-
async fsEvidence(observation,
|
|
34322
|
+
async fsEvidence(observation, path74, sha256, content, extra = {}) {
|
|
34323
34323
|
const digest = sha256 && content !== void 0 ? sha256(content) : void 0;
|
|
34324
|
-
const seq = await this.emitEvidence({ observation, path:
|
|
34324
|
+
const seq = await this.emitEvidence({ observation, path: path74, ...extra, ...digest ? { digest } : {} });
|
|
34325
34325
|
return {
|
|
34326
34326
|
tier: "fs-observation",
|
|
34327
|
-
ref:
|
|
34327
|
+
ref: path74,
|
|
34328
34328
|
capturedAt: Date.now(),
|
|
34329
34329
|
...digest ? { digest } : {},
|
|
34330
34330
|
...seq !== void 0 ? { seq } : {}
|
|
@@ -34706,7 +34706,8 @@ var init_verifier = __esm({
|
|
|
34706
34706
|
});
|
|
34707
34707
|
VERIFIER_SYSTEM_PROMPT = [
|
|
34708
34708
|
"You are an independent completion verifier.",
|
|
34709
|
-
"You receive a
|
|
34709
|
+
"You receive the original task, a git diff summary, a test output excerpt,",
|
|
34710
|
+
"and deterministic verification results \u2014 never the builder narration.",
|
|
34710
34711
|
"Answer with a single JSON object and nothing else:",
|
|
34711
34712
|
'{"verdict":"confirmed|rejected|unknown","score":0..1,"rationale":"..."}',
|
|
34712
34713
|
"Rules: never confirm when a required deterministic check failed or is unknown;",
|
|
@@ -34741,8 +34742,14 @@ var init_verifier = __esm({
|
|
|
34741
34742
|
try {
|
|
34742
34743
|
response = await this.deps.callModel({
|
|
34743
34744
|
system: VERIFIER_SYSTEM_PROMPT,
|
|
34745
|
+
// Blind review payload: evidence only (task, diff summary, test output
|
|
34746
|
+
// excerpt, deterministic results). Builder narration/reasoning is
|
|
34747
|
+
// structurally excluded — undefined keys are omitted.
|
|
34744
34748
|
user: JSON.stringify({
|
|
34749
|
+
...request.task === void 0 ? {} : { task: request.task },
|
|
34745
34750
|
summary: request.summary,
|
|
34751
|
+
...request.diffSummary === void 0 ? {} : { diffSummary: request.diffSummary },
|
|
34752
|
+
...request.testOutputExcerpt === void 0 ? {} : { testOutputExcerpt: request.testOutputExcerpt },
|
|
34746
34753
|
deterministicResults: request.results.map((r) => ({
|
|
34747
34754
|
criterionId: r.criterionId,
|
|
34748
34755
|
status: r.status,
|
|
@@ -37457,9 +37464,9 @@ function spillToolOutput(fullText, meta3) {
|
|
|
37457
37464
|
const rnd = randomBytes3(3).toString("hex");
|
|
37458
37465
|
const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
|
|
37459
37466
|
const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
|
|
37460
|
-
const
|
|
37461
|
-
writeFileSync11(
|
|
37462
|
-
return
|
|
37467
|
+
const path74 = join14(dir, file2);
|
|
37468
|
+
writeFileSync11(path74, fullText, "utf8");
|
|
37469
|
+
return path74;
|
|
37463
37470
|
} catch {
|
|
37464
37471
|
return null;
|
|
37465
37472
|
}
|
|
@@ -37505,10 +37512,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
|
|
|
37505
37512
|
${tail2}`;
|
|
37506
37513
|
}
|
|
37507
37514
|
if (doSpill) {
|
|
37508
|
-
const
|
|
37509
|
-
if (
|
|
37515
|
+
const path74 = spillToolOutput(text, { toolName: opts.toolName });
|
|
37516
|
+
if (path74) {
|
|
37510
37517
|
const spillNote = `
|
|
37511
|
-
\u2026 [full output spilled to: ${
|
|
37518
|
+
\u2026 [full output spilled to: ${path74} \u2014 re-read with read_file if you need the complete text] \u2026`;
|
|
37512
37519
|
if (preview.includes("] \u2026\n")) {
|
|
37513
37520
|
preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
|
|
37514
37521
|
`);
|
|
@@ -40340,28 +40347,28 @@ var init_storage = __esm({
|
|
|
40340
40347
|
VALID_SCALARS = /^(true|false|null|~)$/i;
|
|
40341
40348
|
Storage = class {
|
|
40342
40349
|
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
40343
|
-
read(
|
|
40344
|
-
if (!existsSync19(
|
|
40345
|
-
throw new Error(`File not found: ${
|
|
40350
|
+
read(path74) {
|
|
40351
|
+
if (!existsSync19(path74)) {
|
|
40352
|
+
throw new Error(`File not found: ${path74}`);
|
|
40346
40353
|
}
|
|
40347
|
-
const md = readFileSync16(
|
|
40354
|
+
const md = readFileSync16(path74, "utf8");
|
|
40348
40355
|
return parseFrontmatter(md);
|
|
40349
40356
|
}
|
|
40350
40357
|
/** Read a Markdown file; returns null if not found. */
|
|
40351
|
-
readIfExists(
|
|
40352
|
-
if (!existsSync19(
|
|
40353
|
-
return this.read(
|
|
40358
|
+
readIfExists(path74) {
|
|
40359
|
+
if (!existsSync19(path74)) return null;
|
|
40360
|
+
return this.read(path74);
|
|
40354
40361
|
}
|
|
40355
40362
|
/**
|
|
40356
40363
|
* Write a Markdown file atomically (tmp + rename). Creates parent dirs.
|
|
40357
40364
|
* The meta object is serialized as YAML frontmatter; body as Markdown.
|
|
40358
40365
|
*/
|
|
40359
|
-
write(
|
|
40360
|
-
mkdirSync10(dirname2(
|
|
40361
|
-
const tmp =
|
|
40366
|
+
write(path74, meta3, body) {
|
|
40367
|
+
mkdirSync10(dirname2(path74), { recursive: true });
|
|
40368
|
+
const tmp = path74 + ".tmp-" + process.pid;
|
|
40362
40369
|
const md = serializeFrontmatter(meta3, body);
|
|
40363
40370
|
writeFileSync13(tmp, md, "utf8");
|
|
40364
|
-
renameSync(tmp,
|
|
40371
|
+
renameSync(tmp, path74);
|
|
40365
40372
|
}
|
|
40366
40373
|
/** List all .md files in a directory (non-recursive). */
|
|
40367
40374
|
listMarkdown(dir) {
|
|
@@ -40423,8 +40430,8 @@ function nextPlanTaskId(store6) {
|
|
|
40423
40430
|
return `t${store6.counter}`;
|
|
40424
40431
|
}
|
|
40425
40432
|
function writePlanTaskArtifact(rootDir, task) {
|
|
40426
|
-
const
|
|
40427
|
-
mkdirSync11(dirname3(
|
|
40433
|
+
const path74 = join18(rootDir, "plan-tasks", `${task.id}.md`);
|
|
40434
|
+
mkdirSync11(dirname3(path74), { recursive: true });
|
|
40428
40435
|
const meta3 = {
|
|
40429
40436
|
kind: "task",
|
|
40430
40437
|
id: task.id,
|
|
@@ -40445,7 +40452,7 @@ function writePlanTaskArtifact(rootDir, task) {
|
|
|
40445
40452
|
task.notes?.trim() ? task.notes.trim() : "_(no notes)_",
|
|
40446
40453
|
""
|
|
40447
40454
|
].filter((l) => l !== null).join("\n");
|
|
40448
|
-
new Storage().write(
|
|
40455
|
+
new Storage().write(path74, meta3, body);
|
|
40449
40456
|
}
|
|
40450
40457
|
function loadHandle(rootDir) {
|
|
40451
40458
|
const jsonPath = join18(rootDir, "plan.json");
|
|
@@ -43733,21 +43740,21 @@ function normalizeAuth(auth) {
|
|
|
43733
43740
|
return "agent";
|
|
43734
43741
|
}
|
|
43735
43742
|
function readSecrets() {
|
|
43736
|
-
const
|
|
43737
|
-
if (!existsSync23(
|
|
43743
|
+
const path74 = getSshSecretsPath();
|
|
43744
|
+
if (!existsSync23(path74)) return {};
|
|
43738
43745
|
try {
|
|
43739
|
-
return JSON.parse(readFileSync20(
|
|
43746
|
+
return JSON.parse(readFileSync20(path74, "utf8"));
|
|
43740
43747
|
} catch {
|
|
43741
43748
|
return {};
|
|
43742
43749
|
}
|
|
43743
43750
|
}
|
|
43744
43751
|
function writeSecrets(data) {
|
|
43745
|
-
const
|
|
43746
|
-
mkdirSync12(dirname4(
|
|
43747
|
-
writeFileSync15(
|
|
43752
|
+
const path74 = getSshSecretsPath();
|
|
43753
|
+
mkdirSync12(dirname4(path74), { recursive: true });
|
|
43754
|
+
writeFileSync15(path74, `${JSON.stringify(data, null, 2)}
|
|
43748
43755
|
`, "utf8");
|
|
43749
43756
|
try {
|
|
43750
|
-
chmodSync(
|
|
43757
|
+
chmodSync(path74, 384);
|
|
43751
43758
|
} catch {
|
|
43752
43759
|
}
|
|
43753
43760
|
}
|
|
@@ -43776,10 +43783,10 @@ function deleteSshPassword(id3) {
|
|
|
43776
43783
|
writeSecrets({ passwords });
|
|
43777
43784
|
}
|
|
43778
43785
|
function readStore2() {
|
|
43779
|
-
const
|
|
43780
|
-
if (!existsSync23(
|
|
43786
|
+
const path74 = getSshTargetsPath();
|
|
43787
|
+
if (!existsSync23(path74)) return [];
|
|
43781
43788
|
try {
|
|
43782
|
-
const parsed = JSON.parse(readFileSync20(
|
|
43789
|
+
const parsed = JSON.parse(readFileSync20(path74, "utf8"));
|
|
43783
43790
|
const list = Array.isArray(parsed.targets) ? parsed.targets : [];
|
|
43784
43791
|
return list.filter(
|
|
43785
43792
|
(t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
|
|
@@ -43794,11 +43801,11 @@ function readStore2() {
|
|
|
43794
43801
|
}
|
|
43795
43802
|
}
|
|
43796
43803
|
function writeStore2(targets) {
|
|
43797
|
-
const
|
|
43798
|
-
mkdirSync12(dirname4(
|
|
43804
|
+
const path74 = getSshTargetsPath();
|
|
43805
|
+
mkdirSync12(dirname4(path74), { recursive: true });
|
|
43799
43806
|
const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
|
|
43800
43807
|
writeFileSync15(
|
|
43801
|
-
|
|
43808
|
+
path74,
|
|
43802
43809
|
`${JSON.stringify({ targets: clean }, null, 2)}
|
|
43803
43810
|
`,
|
|
43804
43811
|
"utf8"
|
|
@@ -44044,11 +44051,11 @@ function formatSshTargetsForPrompt() {
|
|
|
44044
44051
|
];
|
|
44045
44052
|
for (const t of targets) {
|
|
44046
44053
|
const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
|
|
44047
|
-
const
|
|
44054
|
+
const path74 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
|
|
44048
44055
|
const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
|
|
44049
44056
|
const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
|
|
44050
44057
|
lines.push(
|
|
44051
|
-
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${
|
|
44058
|
+
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path74}${tags}${allow}`
|
|
44052
44059
|
);
|
|
44053
44060
|
}
|
|
44054
44061
|
return lines.join("\n");
|
|
@@ -45048,6 +45055,19 @@ function defaultPermissionPolicy(overrides) {
|
|
|
45048
45055
|
...overrides
|
|
45049
45056
|
};
|
|
45050
45057
|
}
|
|
45058
|
+
function moreRestrictive(a, b) {
|
|
45059
|
+
return ACTION_RANK2[a] >= ACTION_RANK2[b] ? a : b;
|
|
45060
|
+
}
|
|
45061
|
+
function intersectPermissionPolicy(parent, child) {
|
|
45062
|
+
return {
|
|
45063
|
+
read: moreRestrictive(parent.read, child.read),
|
|
45064
|
+
write: moreRestrictive(parent.write, child.write),
|
|
45065
|
+
execute: moreRestrictive(parent.execute, child.execute),
|
|
45066
|
+
network: moreRestrictive(parent.network, child.network),
|
|
45067
|
+
ui: moreRestrictive(parent.ui, child.ui),
|
|
45068
|
+
auto: parent.auto && child.auto
|
|
45069
|
+
};
|
|
45070
|
+
}
|
|
45051
45071
|
function resolveToolPermission(toolName, required2, policy) {
|
|
45052
45072
|
if (!required2.length) {
|
|
45053
45073
|
return { action: "allow", reason: "", categories: [] };
|
|
@@ -45083,12 +45103,13 @@ function resolveToolPermission(toolName, required2, policy) {
|
|
|
45083
45103
|
categories: hit
|
|
45084
45104
|
};
|
|
45085
45105
|
}
|
|
45086
|
-
var sessionToolGrants, sessionCategoryGrants;
|
|
45106
|
+
var sessionToolGrants, sessionCategoryGrants, ACTION_RANK2;
|
|
45087
45107
|
var init_toolPermissions = __esm({
|
|
45088
45108
|
"src/cli/safety/toolPermissions.ts"() {
|
|
45089
45109
|
"use strict";
|
|
45090
45110
|
sessionToolGrants = /* @__PURE__ */ new Set();
|
|
45091
45111
|
sessionCategoryGrants = /* @__PURE__ */ new Set();
|
|
45112
|
+
ACTION_RANK2 = { allow: 0, ask: 1, deny: 2 };
|
|
45092
45113
|
}
|
|
45093
45114
|
});
|
|
45094
45115
|
|
|
@@ -45265,10 +45286,194 @@ var init_lifecycleHooks = __esm({
|
|
|
45265
45286
|
}
|
|
45266
45287
|
});
|
|
45267
45288
|
|
|
45289
|
+
// src/cli/safety/policyEngine.ts
|
|
45290
|
+
import { readFileSync as readFileSync22 } from "node:fs";
|
|
45291
|
+
import { homedir as homedir10 } from "node:os";
|
|
45292
|
+
import path40 from "node:path";
|
|
45293
|
+
function emptyPolicySet() {
|
|
45294
|
+
return { agents: /* @__PURE__ */ new Map(), warnings: [] };
|
|
45295
|
+
}
|
|
45296
|
+
function agentRulesFor(set2, agent) {
|
|
45297
|
+
return set2.agents.get(agent) ?? EMPTY_POLICY_RULE_SET;
|
|
45298
|
+
}
|
|
45299
|
+
function globToRegExp(pattern) {
|
|
45300
|
+
let src = "^";
|
|
45301
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
45302
|
+
const ch = pattern[i];
|
|
45303
|
+
if (ch === "*") {
|
|
45304
|
+
while (pattern[i + 1] === "*") i++;
|
|
45305
|
+
src += ".*";
|
|
45306
|
+
} else if ("\\^$.|?+()[]{}".includes(ch)) {
|
|
45307
|
+
src += "\\" + ch;
|
|
45308
|
+
} else {
|
|
45309
|
+
src += ch;
|
|
45310
|
+
}
|
|
45311
|
+
}
|
|
45312
|
+
return new RegExp(src + "$");
|
|
45313
|
+
}
|
|
45314
|
+
function normalizeForMatch(value) {
|
|
45315
|
+
return value.replace(/\\/g, "/");
|
|
45316
|
+
}
|
|
45317
|
+
function resolvePolicyRule(rules, value) {
|
|
45318
|
+
const v = normalizeForMatch(value);
|
|
45319
|
+
for (const rule of rules) {
|
|
45320
|
+
if (globToRegExp(normalizeForMatch(rule.match)).test(v)) return rule;
|
|
45321
|
+
}
|
|
45322
|
+
return null;
|
|
45323
|
+
}
|
|
45324
|
+
function mergeRuleEffect(base2, rule) {
|
|
45325
|
+
if (!rule) return base2;
|
|
45326
|
+
return EFFECT_RANK[rule.effect] > EFFECT_RANK[base2] ? rule.effect : base2;
|
|
45327
|
+
}
|
|
45328
|
+
function pathCandidates(value, root) {
|
|
45329
|
+
const norm = normalizeForMatch(value);
|
|
45330
|
+
if (!root) return [norm];
|
|
45331
|
+
const prefix = normalizeForMatch(root).replace(/\/+$/, "") + "/";
|
|
45332
|
+
const stripped = norm.toLowerCase().startsWith(prefix.toLowerCase()) ? norm.slice(prefix.length) : null;
|
|
45333
|
+
return stripped !== null ? [stripped, norm] : [norm];
|
|
45334
|
+
}
|
|
45335
|
+
function matchAgentPolicyRule(rules, required2, args, root) {
|
|
45336
|
+
if (!rules) return null;
|
|
45337
|
+
const a = args !== null && typeof args === "object" ? args : {};
|
|
45338
|
+
if (required2.includes("execute")) {
|
|
45339
|
+
const cmd = a["command"];
|
|
45340
|
+
if (typeof cmd === "string" && cmd !== "") {
|
|
45341
|
+
const hit = resolvePolicyRule(rules.shell, cmd);
|
|
45342
|
+
if (hit) return hit;
|
|
45343
|
+
}
|
|
45344
|
+
}
|
|
45345
|
+
if (required2.includes("write")) {
|
|
45346
|
+
const p3 = typeof a["path"] === "string" ? a["path"] : typeof a["file_path"] === "string" ? a["file_path"] : "";
|
|
45347
|
+
if (p3 !== "") {
|
|
45348
|
+
for (const candidate of pathCandidates(p3, root)) {
|
|
45349
|
+
const hit = resolvePolicyRule(rules.edit, candidate);
|
|
45350
|
+
if (hit) return hit;
|
|
45351
|
+
}
|
|
45352
|
+
}
|
|
45353
|
+
}
|
|
45354
|
+
return null;
|
|
45355
|
+
}
|
|
45356
|
+
function isPolicyEngineDisabled() {
|
|
45357
|
+
const v = process.env.ZELARI_POLICY?.trim().toLowerCase();
|
|
45358
|
+
return v === "0" || v === "false" || v === "no" || v === "off";
|
|
45359
|
+
}
|
|
45360
|
+
function isPlainObject2(v) {
|
|
45361
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
45362
|
+
}
|
|
45363
|
+
function parseRuleList(raw, origin, warnings) {
|
|
45364
|
+
if (raw === void 0) return [];
|
|
45365
|
+
if (!Array.isArray(raw)) {
|
|
45366
|
+
warnings.push(`${origin}: expected an array of rules, got ${typeof raw} \u2014 section ignored.`);
|
|
45367
|
+
return [];
|
|
45368
|
+
}
|
|
45369
|
+
const out = [];
|
|
45370
|
+
raw.forEach((item, i) => {
|
|
45371
|
+
const where = `${origin}[${i}]`;
|
|
45372
|
+
if (!isPlainObject2(item)) {
|
|
45373
|
+
warnings.push(`${where}: rule is not an object \u2014 skipped.`);
|
|
45374
|
+
return;
|
|
45375
|
+
}
|
|
45376
|
+
const match = item["match"];
|
|
45377
|
+
const effect = item["effect"];
|
|
45378
|
+
const reason = item["reason"];
|
|
45379
|
+
if (typeof match !== "string" || match.trim() === "") {
|
|
45380
|
+
warnings.push(`${where}: missing or empty "match" \u2014 skipped.`);
|
|
45381
|
+
return;
|
|
45382
|
+
}
|
|
45383
|
+
if (effect !== "allow" && effect !== "ask" && effect !== "deny") {
|
|
45384
|
+
warnings.push(`${where} ("${match}"): "effect" must be allow|ask|deny \u2014 skipped.`);
|
|
45385
|
+
return;
|
|
45386
|
+
}
|
|
45387
|
+
out.push(
|
|
45388
|
+
typeof reason === "string" && reason.trim() !== "" ? { match, effect, reason } : { match, effect }
|
|
45389
|
+
);
|
|
45390
|
+
});
|
|
45391
|
+
return out;
|
|
45392
|
+
}
|
|
45393
|
+
function parsePolicyFile(raw, origin, warnings) {
|
|
45394
|
+
if (!isPlainObject2(raw)) {
|
|
45395
|
+
warnings.push(`${origin}: policy file is not a JSON object \u2014 file ignored.`);
|
|
45396
|
+
return null;
|
|
45397
|
+
}
|
|
45398
|
+
const version2 = raw["version"];
|
|
45399
|
+
if (version2 !== void 0 && version2 !== 1) {
|
|
45400
|
+
warnings.push(`${origin}: unsupported "version" ${JSON.stringify(version2)} (expected 1) \u2014 file ignored.`);
|
|
45401
|
+
return null;
|
|
45402
|
+
}
|
|
45403
|
+
const agentsRaw = raw["agents"];
|
|
45404
|
+
if (agentsRaw === void 0) {
|
|
45405
|
+
warnings.push(`${origin}: no "agents" key \u2014 file ignored.`);
|
|
45406
|
+
return null;
|
|
45407
|
+
}
|
|
45408
|
+
if (!isPlainObject2(agentsRaw)) {
|
|
45409
|
+
warnings.push(`${origin}: "agents" is not an object \u2014 file ignored.`);
|
|
45410
|
+
return null;
|
|
45411
|
+
}
|
|
45412
|
+
const out = /* @__PURE__ */ new Map();
|
|
45413
|
+
for (const [key, val] of Object.entries(agentsRaw)) {
|
|
45414
|
+
const agent = key.trim().toLowerCase();
|
|
45415
|
+
if (!KNOWN_AGENTS.has(agent)) {
|
|
45416
|
+
warnings.push(`${origin}: unknown agent "${key}" (known: ${POLICY_AGENTS.join(" | ")}) \u2014 ignored.`);
|
|
45417
|
+
continue;
|
|
45418
|
+
}
|
|
45419
|
+
if (!isPlainObject2(val)) {
|
|
45420
|
+
warnings.push(`${origin}: agents.${key} is not an object \u2014 ignored.`);
|
|
45421
|
+
continue;
|
|
45422
|
+
}
|
|
45423
|
+
const shell = parseRuleList(val["shell"], `${origin} agents.${key}.shell`, warnings);
|
|
45424
|
+
const edit = parseRuleList(val["edit"], `${origin} agents.${key}.edit`, warnings);
|
|
45425
|
+
out.set(agent, { shell, edit });
|
|
45426
|
+
}
|
|
45427
|
+
return out;
|
|
45428
|
+
}
|
|
45429
|
+
function readPolicyFile(file2, warnings) {
|
|
45430
|
+
let text;
|
|
45431
|
+
try {
|
|
45432
|
+
text = readFileSync22(file2, "utf8");
|
|
45433
|
+
} catch {
|
|
45434
|
+
return /* @__PURE__ */ new Map();
|
|
45435
|
+
}
|
|
45436
|
+
let parsed;
|
|
45437
|
+
try {
|
|
45438
|
+
parsed = JSON.parse(text);
|
|
45439
|
+
} catch (err) {
|
|
45440
|
+
warnings.push(
|
|
45441
|
+
`${file2}: invalid JSON (${err instanceof Error ? err.message : String(err)}) \u2014 file ignored.`
|
|
45442
|
+
);
|
|
45443
|
+
return /* @__PURE__ */ new Map();
|
|
45444
|
+
}
|
|
45445
|
+
return parsePolicyFile(parsed, file2, warnings) ?? /* @__PURE__ */ new Map();
|
|
45446
|
+
}
|
|
45447
|
+
function loadPolicySet(root, opts = {}) {
|
|
45448
|
+
if (isPolicyEngineDisabled()) return emptyPolicySet();
|
|
45449
|
+
const warnings = [];
|
|
45450
|
+
const project = readPolicyFile(path40.join(root, ".zelari", "policy.json"), warnings);
|
|
45451
|
+
const global = readPolicyFile(path40.join(opts.homeDir ?? homedir10(), ".zelari", "policy.json"), warnings);
|
|
45452
|
+
const agents = /* @__PURE__ */ new Map();
|
|
45453
|
+
for (const [agent, g] of global) {
|
|
45454
|
+
agents.set(agent, { shell: [...g.shell], edit: [...g.edit] });
|
|
45455
|
+
}
|
|
45456
|
+
for (const [agent, p3] of project) {
|
|
45457
|
+
const g = agents.get(agent) ?? EMPTY_POLICY_RULE_SET;
|
|
45458
|
+
agents.set(agent, { shell: [...p3.shell, ...g.shell], edit: [...p3.edit, ...g.edit] });
|
|
45459
|
+
}
|
|
45460
|
+
return { agents, warnings };
|
|
45461
|
+
}
|
|
45462
|
+
var POLICY_AGENTS, KNOWN_AGENTS, EMPTY_POLICY_RULE_SET, EFFECT_RANK;
|
|
45463
|
+
var init_policyEngine = __esm({
|
|
45464
|
+
"src/cli/safety/policyEngine.ts"() {
|
|
45465
|
+
"use strict";
|
|
45466
|
+
POLICY_AGENTS = ["lead", "explore", "general", "verify"];
|
|
45467
|
+
KNOWN_AGENTS = new Set(POLICY_AGENTS);
|
|
45468
|
+
EMPTY_POLICY_RULE_SET = { shell: [], edit: [] };
|
|
45469
|
+
EFFECT_RANK = { allow: 0, ask: 1, deny: 2 };
|
|
45470
|
+
}
|
|
45471
|
+
});
|
|
45472
|
+
|
|
45268
45473
|
// src/cli/toolResultCache.ts
|
|
45269
45474
|
import { createHash as createHash13 } from "node:crypto";
|
|
45270
45475
|
import { promises as fs19 } from "node:fs";
|
|
45271
|
-
import
|
|
45476
|
+
import path41 from "node:path";
|
|
45272
45477
|
function isToolCacheEnabled() {
|
|
45273
45478
|
const raw = process.env.ZELARI_TOOL_CACHE;
|
|
45274
45479
|
return raw !== "0" && raw !== "false" && raw !== "off";
|
|
@@ -45353,7 +45558,7 @@ async function statKey(toolName, input, ctx) {
|
|
|
45353
45558
|
if (!input || typeof input !== "object") return null;
|
|
45354
45559
|
const rawPath = input.path;
|
|
45355
45560
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
45356
|
-
const abs =
|
|
45561
|
+
const abs = path41.isAbsolute(rawPath) ? rawPath : path41.join(ctx.cwd, rawPath);
|
|
45357
45562
|
try {
|
|
45358
45563
|
const st = await fs19.stat(abs);
|
|
45359
45564
|
return hashKey({
|
|
@@ -45402,10 +45607,13 @@ var init_toolResultCache = __esm({
|
|
|
45402
45607
|
// src/cli/tools/krakenModel.ts
|
|
45403
45608
|
var krakenModel_exports = {};
|
|
45404
45609
|
__export(krakenModel_exports, {
|
|
45610
|
+
inferModelFamily: () => inferModelFamily,
|
|
45405
45611
|
isCheapModelId: () => isCheapModelId,
|
|
45406
45612
|
isKrakenAutoModelEnabled: () => isKrakenAutoModelEnabled,
|
|
45407
45613
|
parseQualifiedModelRef: () => parseQualifiedModelRef,
|
|
45408
45614
|
pickCheapModel: () => pickCheapModel,
|
|
45615
|
+
pickDifferentFamily: () => pickDifferentFamily,
|
|
45616
|
+
resolveCrossModelVerifier: () => resolveCrossModelVerifier,
|
|
45409
45617
|
resolveKrakenPlannerModel: () => resolveKrakenPlannerModel,
|
|
45410
45618
|
resolveKrakenSubModel: () => resolveKrakenSubModel,
|
|
45411
45619
|
resolveKrakenSubModelAsync: () => resolveKrakenSubModelAsync,
|
|
@@ -45450,6 +45658,44 @@ function parseQualifiedModelRef(ref) {
|
|
|
45450
45658
|
if (!provider || !model) return null;
|
|
45451
45659
|
return { provider, model };
|
|
45452
45660
|
}
|
|
45661
|
+
function inferModelFamily(provider, model) {
|
|
45662
|
+
const p3 = (provider ?? "").trim().toLowerCase();
|
|
45663
|
+
const m = (model ?? "").trim().toLowerCase();
|
|
45664
|
+
const hay = `${p3} ${m}`.trim();
|
|
45665
|
+
if (!hay) return "other";
|
|
45666
|
+
if (/\b(zhipu|glm)\b/.test(hay)) return "zhipu";
|
|
45667
|
+
if (/\b(google|gemini)\b/.test(hay)) return "google";
|
|
45668
|
+
if (/\b(xai|grok)\b/.test(hay)) return "xai";
|
|
45669
|
+
if (/\b(anthropic|claude)\b/.test(hay)) return "anthropic";
|
|
45670
|
+
if (/\b(openai|chatgpt|codex)\b/.test(hay) || /\bgpt\b/.test(hay) || /(^|\s)o[134]($|[-_.])/.test(hay)) {
|
|
45671
|
+
return "openai";
|
|
45672
|
+
}
|
|
45673
|
+
return p3 || "other";
|
|
45674
|
+
}
|
|
45675
|
+
function pickDifferentFamily(builder, candidates) {
|
|
45676
|
+
const builderFamily = inferModelFamily(builder.provider, builder.model);
|
|
45677
|
+
for (const c of candidates) {
|
|
45678
|
+
const provider = c.provider?.trim() ?? "";
|
|
45679
|
+
const model = c.model?.trim() ?? "";
|
|
45680
|
+
if (!provider || !model) continue;
|
|
45681
|
+
if (inferModelFamily(provider, model) !== builderFamily) {
|
|
45682
|
+
return { provider, model };
|
|
45683
|
+
}
|
|
45684
|
+
}
|
|
45685
|
+
return null;
|
|
45686
|
+
}
|
|
45687
|
+
function resolveCrossModelVerifier(builder, candidates, env = process.env) {
|
|
45688
|
+
const cross = (env.ZELARI_KRAKEN_CROSS_MODEL ?? "").trim().toLowerCase();
|
|
45689
|
+
if (cross === "0" || cross === "false" || cross === "off") return null;
|
|
45690
|
+
const specific = env.ZELARI_KRAKEN_VERIFY_MODEL?.trim();
|
|
45691
|
+
if (specific) {
|
|
45692
|
+
const qualified = parseQualifiedModelRef(specific);
|
|
45693
|
+
if (qualified) return qualified;
|
|
45694
|
+
const provider = builder.provider?.trim();
|
|
45695
|
+
return provider ? { provider, model: specific } : null;
|
|
45696
|
+
}
|
|
45697
|
+
return pickDifferentFamily(builder, candidates);
|
|
45698
|
+
}
|
|
45453
45699
|
function resolveKrakenSubModel(agent, parentModel, env = process.env, opts = {}) {
|
|
45454
45700
|
const kindKey = agent === "explore" ? "ZELARI_KRAKEN_EXPLORE_MODEL" : agent === "verify" ? "ZELARI_KRAKEN_VERIFY_MODEL" : "ZELARI_KRAKEN_GENERAL_MODEL";
|
|
45455
45701
|
const specific = env[kindKey]?.trim();
|
|
@@ -45462,6 +45708,13 @@ function resolveKrakenSubModel(agent, parentModel, env = process.env, opts = {})
|
|
|
45462
45708
|
}
|
|
45463
45709
|
return shared2;
|
|
45464
45710
|
}
|
|
45711
|
+
if (agent === "verify" && opts.familyCandidates && opts.familyCandidates.length > 0) {
|
|
45712
|
+
const picked = pickDifferentFamily(
|
|
45713
|
+
{ provider: opts.provider ?? "", model: parentModel },
|
|
45714
|
+
opts.familyCandidates
|
|
45715
|
+
);
|
|
45716
|
+
if (picked) return `${picked.provider}/${picked.model}`;
|
|
45717
|
+
}
|
|
45465
45718
|
if ((agent === "explore" || agent === "verify") && isKrakenAutoModelEnabled(env) && opts.candidates && opts.candidates.length > 0) {
|
|
45466
45719
|
const picked = pickCheapModel(parentModel, opts.candidates);
|
|
45467
45720
|
if (picked) return picked;
|
|
@@ -45557,7 +45810,11 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
45557
45810
|
const allowMutators = !readOnly && !verifyMode && !gauntletParent;
|
|
45558
45811
|
const allowBash = (allowMutators || verifyMode) && !gauntletParent;
|
|
45559
45812
|
const permPolicy = options.permissionPolicy ?? defaultPermissionPolicy();
|
|
45560
|
-
const
|
|
45813
|
+
const agentPolicyRules = agentRulesFor(
|
|
45814
|
+
loadPolicySet(root),
|
|
45815
|
+
options.policyAgent ?? "lead"
|
|
45816
|
+
);
|
|
45817
|
+
const withPerm = (t) => wrapWithPermissions(t, permPolicy, options.onPermissionAsk, agentPolicyRules, root);
|
|
45561
45818
|
registry4.register(withPerm(safeReadFile));
|
|
45562
45819
|
registry4.register(withPerm(safeGrepContent));
|
|
45563
45820
|
registry4.register(withPerm(safeListFiles));
|
|
@@ -45691,6 +45948,10 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
45691
45948
|
root,
|
|
45692
45949
|
audit,
|
|
45693
45950
|
sessionId: sessionId2,
|
|
45951
|
+
// P0.4 capability inheritance: tentacles intersect THIS
|
|
45952
|
+
// registry's own policy (permPolicy above) — they can never
|
|
45953
|
+
// exceed it.
|
|
45954
|
+
parentPolicy: permPolicy,
|
|
45694
45955
|
...options.subAgentProvider ? { provider: options.subAgentProvider } : {},
|
|
45695
45956
|
...options.subAgentModel ? { model: options.subAgentModel } : {}
|
|
45696
45957
|
}),
|
|
@@ -45768,7 +46029,7 @@ function taskAgentToProfile(agent) {
|
|
|
45768
46029
|
return "explore";
|
|
45769
46030
|
}
|
|
45770
46031
|
function createKrakenSubAgentContextFactory(opts) {
|
|
45771
|
-
const { root, audit, sessionId: sessionId2, provider: providerOverride, model: modelOverride } = opts;
|
|
46032
|
+
const { root, audit, sessionId: sessionId2, provider: providerOverride, model: modelOverride, parentPolicy } = opts;
|
|
45772
46033
|
return async ({ agent, cwd: subCwd }) => {
|
|
45773
46034
|
const cfg = providerOverride ? await providerConfigFor(providerOverride) : await providerFromEnv();
|
|
45774
46035
|
if (!cfg) return null;
|
|
@@ -45787,6 +46048,11 @@ function createKrakenSubAgentContextFactory(opts) {
|
|
|
45787
46048
|
const subCfg = { ...effCfg, model };
|
|
45788
46049
|
const subProfile = taskAgentToProfile(agent);
|
|
45789
46050
|
const subRoot = subCwd || root;
|
|
46051
|
+
const agentPolicyForSubProfile = defaultPermissionPolicy({ auto: true });
|
|
46052
|
+
const effectiveSubPolicy = intersectPermissionPolicy(
|
|
46053
|
+
parentPolicy ?? agentPolicyForSubProfile,
|
|
46054
|
+
agentPolicyForSubProfile
|
|
46055
|
+
);
|
|
45790
46056
|
const { registry: subRegistry } = createBuiltinToolRegistry({
|
|
45791
46057
|
root: subRoot,
|
|
45792
46058
|
audit,
|
|
@@ -45796,7 +46062,9 @@ function createKrakenSubAgentContextFactory(opts) {
|
|
|
45796
46062
|
enableSkill: agent === "general",
|
|
45797
46063
|
diagnostics: false,
|
|
45798
46064
|
lspProvider: null,
|
|
45799
|
-
permissionPolicy:
|
|
46065
|
+
permissionPolicy: effectiveSubPolicy,
|
|
46066
|
+
// P0.5: the tentacle's agent identity drives per-agent policy rules.
|
|
46067
|
+
policyAgent: agent
|
|
45800
46068
|
});
|
|
45801
46069
|
return {
|
|
45802
46070
|
providerStream: buildProviderStream(subCfg),
|
|
@@ -45813,7 +46081,7 @@ function createKrakenSubAgentContextFactory(opts) {
|
|
|
45813
46081
|
};
|
|
45814
46082
|
};
|
|
45815
46083
|
}
|
|
45816
|
-
function wrapWithPermissions(original, policy, onAsk) {
|
|
46084
|
+
function wrapWithPermissions(original, policy, onAsk, agentRules, root) {
|
|
45817
46085
|
const required2 = original.permissions ?? [];
|
|
45818
46086
|
const decisionProbe = resolveToolPermission(original.name, required2, policy);
|
|
45819
46087
|
if (decisionProbe.action === "allow" && !required2.includes("write") && !required2.includes("execute")) {
|
|
@@ -45822,13 +46090,21 @@ function wrapWithPermissions(original, policy, onAsk) {
|
|
|
45822
46090
|
...original,
|
|
45823
46091
|
execute: async (input, ctx) => {
|
|
45824
46092
|
const decision = resolveToolPermission(original.name, required2, policy);
|
|
45825
|
-
|
|
45826
|
-
|
|
45827
|
-
|
|
45828
|
-
|
|
46093
|
+
const rule = agentRules ? matchAgentPolicyRule(
|
|
46094
|
+
agentRules,
|
|
46095
|
+
required2,
|
|
46096
|
+
input ?? {},
|
|
46097
|
+
root ?? process.cwd()
|
|
46098
|
+
) : null;
|
|
46099
|
+
const action = mergeRuleEffect(decision.action, rule);
|
|
46100
|
+
const rulePrefix = rule ? `[policy] rule '${rule.match}'${rule.reason ? ` \u2014 ${rule.reason}` : ""}` : "";
|
|
46101
|
+
if (action === "deny") {
|
|
46102
|
+
return typedErr(`[permission] ${rulePrefix || decision.reason}`);
|
|
46103
|
+
}
|
|
46104
|
+
if (action === "ask") {
|
|
45829
46105
|
if (!onAsk) {
|
|
45830
46106
|
return typedErr(
|
|
45831
|
-
`[permission] ${decision.reason} No interactive approval available (set ZELARI_AUTO=1 to auto-allow, or configure onPermissionAsk).`
|
|
46107
|
+
`[permission] ${rulePrefix ? `${rulePrefix} ` : ""}${decision.reason} No interactive approval available (set ZELARI_AUTO=1 to auto-allow, or configure onPermissionAsk).`
|
|
45832
46108
|
);
|
|
45833
46109
|
}
|
|
45834
46110
|
try {
|
|
@@ -46044,6 +46320,7 @@ var init_toolRegistry = __esm({
|
|
|
46044
46320
|
init_providerConfig();
|
|
46045
46321
|
init_toolPermissions();
|
|
46046
46322
|
init_lifecycleHooks();
|
|
46323
|
+
init_policyEngine();
|
|
46047
46324
|
init_toolResultCache();
|
|
46048
46325
|
init_toolTypes();
|
|
46049
46326
|
init_skills2();
|
|
@@ -46064,7 +46341,7 @@ var init_toolRegistry = __esm({
|
|
|
46064
46341
|
|
|
46065
46342
|
// src/cli/metrics.ts
|
|
46066
46343
|
import { promises as fs20, existsSync as existsSync25, statSync as statSync4, renameSync as renameSync3, appendFileSync as appendFileSync3, mkdirSync as mkdirSync14 } from "node:fs";
|
|
46067
|
-
import
|
|
46344
|
+
import path42 from "node:path";
|
|
46068
46345
|
import os9 from "node:os";
|
|
46069
46346
|
async function readMetrics(file2) {
|
|
46070
46347
|
let raw = "";
|
|
@@ -46113,8 +46390,8 @@ var init_metrics3 = __esm({
|
|
|
46113
46390
|
file;
|
|
46114
46391
|
writeQueue = Promise.resolve();
|
|
46115
46392
|
constructor(file2) {
|
|
46116
|
-
this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ??
|
|
46117
|
-
mkdirSync14(
|
|
46393
|
+
this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ?? path42.join(os9.homedir(), ".tmp", "zelari-code", "metrics.jsonl");
|
|
46394
|
+
mkdirSync14(path42.dirname(this.file), { recursive: true });
|
|
46118
46395
|
}
|
|
46119
46396
|
/** Metrics file path — doctor/summary readers use this. */
|
|
46120
46397
|
get filePath() {
|
|
@@ -46246,12 +46523,12 @@ Current policy: **lead only**.
|
|
|
46246
46523
|
// src/cli/state/fileStateStore.ts
|
|
46247
46524
|
import { createHash as createHash15, randomUUID as randomUUID3 } from "node:crypto";
|
|
46248
46525
|
import { promises as fs21 } from "node:fs";
|
|
46249
|
-
import * as
|
|
46526
|
+
import * as path45 from "node:path";
|
|
46250
46527
|
function shortId() {
|
|
46251
46528
|
return randomUUID3().replace(/-/g, "").slice(0, 12);
|
|
46252
46529
|
}
|
|
46253
46530
|
async function writeJsonAtomic(filePath, data) {
|
|
46254
|
-
await fs21.mkdir(
|
|
46531
|
+
await fs21.mkdir(path45.dirname(filePath), { recursive: true });
|
|
46255
46532
|
const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
46256
46533
|
await fs21.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
46257
46534
|
await fs21.rename(tmp, filePath);
|
|
@@ -46312,11 +46589,11 @@ var init_fileStateStore = __esm({
|
|
|
46312
46589
|
indexPath = "";
|
|
46313
46590
|
async init(projectRoot) {
|
|
46314
46591
|
this.root = projectRoot;
|
|
46315
|
-
this.stateDir =
|
|
46316
|
-
this.commitsDir =
|
|
46317
|
-
this.artifactsDir =
|
|
46318
|
-
this.headPath =
|
|
46319
|
-
this.indexPath =
|
|
46592
|
+
this.stateDir = path45.join(projectRoot, ".zelari", "state");
|
|
46593
|
+
this.commitsDir = path45.join(this.stateDir, "commits");
|
|
46594
|
+
this.artifactsDir = path45.join(this.stateDir, "artifacts");
|
|
46595
|
+
this.headPath = path45.join(this.stateDir, "HEAD.json");
|
|
46596
|
+
this.indexPath = path45.join(this.stateDir, "index.jsonl");
|
|
46320
46597
|
await fs21.mkdir(this.commitsDir, { recursive: true });
|
|
46321
46598
|
await fs21.mkdir(this.artifactsDir, { recursive: true });
|
|
46322
46599
|
}
|
|
@@ -46329,13 +46606,13 @@ var init_fileStateStore = __esm({
|
|
|
46329
46606
|
const discoveries = input.discoveries ?? [];
|
|
46330
46607
|
const parent = await this.head();
|
|
46331
46608
|
const id3 = shortId();
|
|
46332
|
-
const artifactRel =
|
|
46333
|
-
const artifactAbs =
|
|
46609
|
+
const artifactRel = path45.join("artifacts", id3);
|
|
46610
|
+
const artifactAbs = path45.join(this.artifactsDir, id3);
|
|
46334
46611
|
await fs21.mkdir(artifactAbs, { recursive: true });
|
|
46335
46612
|
const summary = defaultSummary(input, discoveries);
|
|
46336
|
-
await fs21.writeFile(
|
|
46337
|
-
await writeJsonAtomic(
|
|
46338
|
-
await writeJsonAtomic(
|
|
46613
|
+
await fs21.writeFile(path45.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
|
|
46614
|
+
await writeJsonAtomic(path45.join(artifactAbs, "discoveries.json"), discoveries);
|
|
46615
|
+
await writeJsonAtomic(path45.join(artifactAbs, "verification.json"), input.verification);
|
|
46339
46616
|
const meta3 = {
|
|
46340
46617
|
id: id3,
|
|
46341
46618
|
parentId: parent?.id ?? null,
|
|
@@ -46347,14 +46624,14 @@ var init_fileStateStore = __esm({
|
|
|
46347
46624
|
workspaceCheckpointId: input.workspaceCheckpointId,
|
|
46348
46625
|
verification: {
|
|
46349
46626
|
...input.verification,
|
|
46350
|
-
reportPath: input.verification.reportPath ??
|
|
46627
|
+
reportPath: input.verification.reportPath ?? path45.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
|
|
46351
46628
|
},
|
|
46352
46629
|
changedPaths: input.changedPaths ?? [],
|
|
46353
46630
|
stablePromptHash: input.stablePromptHash,
|
|
46354
46631
|
discoveryCount: discoveries.length,
|
|
46355
46632
|
artifactDir: artifactRel.replace(/\\/g, "/")
|
|
46356
46633
|
};
|
|
46357
|
-
await writeJsonAtomic(
|
|
46634
|
+
await writeJsonAtomic(path45.join(this.commitsDir, `${id3}.json`), meta3);
|
|
46358
46635
|
await writeJsonAtomic(this.headPath, { id: id3, updatedAt: meta3.createdAt });
|
|
46359
46636
|
await fs21.appendFile(this.indexPath, JSON.stringify({ id: id3, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
|
|
46360
46637
|
return stripStored(meta3);
|
|
@@ -46365,7 +46642,7 @@ var init_fileStateStore = __esm({
|
|
|
46365
46642
|
return this.get(head.id);
|
|
46366
46643
|
}
|
|
46367
46644
|
async get(id3) {
|
|
46368
|
-
const stored = await readJsonFile(
|
|
46645
|
+
const stored = await readJsonFile(path45.join(this.commitsDir, `${id3}.json`));
|
|
46369
46646
|
return stored ? stripStored(stored) : null;
|
|
46370
46647
|
}
|
|
46371
46648
|
async list(limit = 20) {
|
|
@@ -46404,9 +46681,9 @@ var init_fileStateStore = __esm({
|
|
|
46404
46681
|
async loadDiscoveries(id3) {
|
|
46405
46682
|
const meta3 = id3 ? await this.get(id3) : await this.head();
|
|
46406
46683
|
if (!meta3) return [];
|
|
46407
|
-
const stored = await readJsonFile(
|
|
46684
|
+
const stored = await readJsonFile(path45.join(this.commitsDir, `${meta3.id}.json`));
|
|
46408
46685
|
if (!stored?.artifactDir) return [];
|
|
46409
|
-
const discPath =
|
|
46686
|
+
const discPath = path45.join(this.stateDir, stored.artifactDir, "discoveries.json");
|
|
46410
46687
|
return await readJsonFile(discPath) ?? [];
|
|
46411
46688
|
}
|
|
46412
46689
|
async materializeContext(id3, maxChars = DEFAULT_MATERIALIZE_CHARS) {
|
|
@@ -47357,7 +47634,7 @@ var init_mode = __esm({
|
|
|
47357
47634
|
});
|
|
47358
47635
|
|
|
47359
47636
|
// src/cli/headless.ts
|
|
47360
|
-
import { readFileSync as
|
|
47637
|
+
import { readFileSync as readFileSync23 } from "node:fs";
|
|
47361
47638
|
function defaultProfileForMode(mode) {
|
|
47362
47639
|
switch (mode) {
|
|
47363
47640
|
case "council":
|
|
@@ -47378,6 +47655,7 @@ function parseHeadlessFlags(argv) {
|
|
|
47378
47655
|
let phase2 = "build";
|
|
47379
47656
|
let modeExplicit = false;
|
|
47380
47657
|
let councilFlag = false;
|
|
47658
|
+
let sawModeAuto = false;
|
|
47381
47659
|
let provider;
|
|
47382
47660
|
let model;
|
|
47383
47661
|
let history2;
|
|
@@ -47412,7 +47690,7 @@ function parseHeadlessFlags(argv) {
|
|
|
47412
47690
|
const next = argv[i + 1];
|
|
47413
47691
|
if (next) {
|
|
47414
47692
|
try {
|
|
47415
|
-
const fromFile =
|
|
47693
|
+
const fromFile = readFileSync23(next, "utf-8");
|
|
47416
47694
|
if (fromFile.trim()) task = fromFile;
|
|
47417
47695
|
} catch {
|
|
47418
47696
|
}
|
|
@@ -47422,11 +47700,17 @@ function parseHeadlessFlags(argv) {
|
|
|
47422
47700
|
councilFlag = true;
|
|
47423
47701
|
} else if (arg === "--mode") {
|
|
47424
47702
|
const next = argv[i + 1];
|
|
47703
|
+
if (next !== void 0 && next.trim().toLowerCase() === "auto") {
|
|
47704
|
+
sawModeAuto = true;
|
|
47705
|
+
modeExplicit = true;
|
|
47706
|
+
i++;
|
|
47707
|
+
continue;
|
|
47708
|
+
}
|
|
47425
47709
|
const parsed = next ? parseMode(next) : null;
|
|
47426
47710
|
if (!parsed) {
|
|
47427
47711
|
return {
|
|
47428
47712
|
options: null,
|
|
47429
|
-
error: `--mode requires 'kraken', 'council', or '
|
|
47713
|
+
error: `--mode requires 'kraken', 'council', 'zelari', or 'auto' (agent=alias), got '${next ?? "(missing)"}'`
|
|
47430
47714
|
};
|
|
47431
47715
|
}
|
|
47432
47716
|
mode = parsed;
|
|
@@ -47455,7 +47739,7 @@ function parseHeadlessFlags(argv) {
|
|
|
47455
47739
|
let raw = null;
|
|
47456
47740
|
if (arg === "--history-file") {
|
|
47457
47741
|
try {
|
|
47458
|
-
raw =
|
|
47742
|
+
raw = readFileSync23(next, "utf-8");
|
|
47459
47743
|
} catch {
|
|
47460
47744
|
raw = null;
|
|
47461
47745
|
}
|
|
@@ -47550,7 +47834,7 @@ function parseHeadlessFlags(argv) {
|
|
|
47550
47834
|
const next = argv[i + 1];
|
|
47551
47835
|
if (next) {
|
|
47552
47836
|
try {
|
|
47553
|
-
const fromFile =
|
|
47837
|
+
const fromFile = readFileSync23(next, "utf-8");
|
|
47554
47838
|
if (fromFile.trim()) krakenGraph = fromFile;
|
|
47555
47839
|
} catch {
|
|
47556
47840
|
}
|
|
@@ -47588,6 +47872,7 @@ function parseHeadlessFlags(argv) {
|
|
|
47588
47872
|
mode,
|
|
47589
47873
|
phase: phase2,
|
|
47590
47874
|
useCouncil: mode === "council",
|
|
47875
|
+
...sawModeAuto ? { orchestrationAuto: true } : {},
|
|
47591
47876
|
provider,
|
|
47592
47877
|
model,
|
|
47593
47878
|
...history2 && history2.length > 0 ? { history: history2 } : {},
|
|
@@ -48115,7 +48400,7 @@ var init_claudeProvider = __esm({
|
|
|
48115
48400
|
// src/cli/memory/legacyImport.ts
|
|
48116
48401
|
import { createHash as createHash16 } from "node:crypto";
|
|
48117
48402
|
import { promises as fs22 } from "node:fs";
|
|
48118
|
-
import * as
|
|
48403
|
+
import * as path46 from "node:path";
|
|
48119
48404
|
function sourceId(fact, line) {
|
|
48120
48405
|
return `jsonl:${fact.id ?? createHash16("sha256").update(line).digest("hex")}`;
|
|
48121
48406
|
}
|
|
@@ -48133,7 +48418,7 @@ function timestamp(value) {
|
|
|
48133
48418
|
}
|
|
48134
48419
|
async function importLegacyMemoryLog(backend, service) {
|
|
48135
48420
|
const result = { found: 0, imported: 0, skipped: 0, corrupt: 0 };
|
|
48136
|
-
const logPath =
|
|
48421
|
+
const logPath = path46.join(path46.dirname(backend.databasePath), "log.jsonl");
|
|
48137
48422
|
let raw;
|
|
48138
48423
|
try {
|
|
48139
48424
|
raw = await fs22.readFile(logPath, "utf8");
|
|
@@ -48316,7 +48601,7 @@ var init_sqliteCodec = __esm({
|
|
|
48316
48601
|
// src/cli/memory/sqliteRpc.ts
|
|
48317
48602
|
import { existsSync as existsSync27 } from "node:fs";
|
|
48318
48603
|
import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
48319
|
-
import * as
|
|
48604
|
+
import * as path47 from "node:path";
|
|
48320
48605
|
import { Worker } from "node:worker_threads";
|
|
48321
48606
|
function isBusy(error51) {
|
|
48322
48607
|
const candidate = error51;
|
|
@@ -48325,10 +48610,10 @@ function isBusy(error51) {
|
|
|
48325
48610
|
);
|
|
48326
48611
|
}
|
|
48327
48612
|
function resolveWorkerUrl() {
|
|
48328
|
-
const here =
|
|
48329
|
-
const direct =
|
|
48613
|
+
const here = path47.dirname(fileURLToPath2(import.meta.url));
|
|
48614
|
+
const direct = path47.join(here, "sqliteWorker.mjs");
|
|
48330
48615
|
if (existsSync27(direct)) return pathToFileURL2(direct);
|
|
48331
|
-
return pathToFileURL2(
|
|
48616
|
+
return pathToFileURL2(path47.join(here, "memory", "sqliteWorker.mjs"));
|
|
48332
48617
|
}
|
|
48333
48618
|
var SqliteWorkerRpc;
|
|
48334
48619
|
var init_sqliteRpc = __esm({
|
|
@@ -48617,7 +48902,7 @@ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.node_id = n.id);
|
|
|
48617
48902
|
// src/cli/memory/sqliteBackend.ts
|
|
48618
48903
|
import { createHash as createHash17, randomUUID as randomUUID4 } from "node:crypto";
|
|
48619
48904
|
import { promises as fs23 } from "node:fs";
|
|
48620
|
-
import * as
|
|
48905
|
+
import * as path48 from "node:path";
|
|
48621
48906
|
function boundedLimit(value, fallback = 50) {
|
|
48622
48907
|
return Math.max(1, Math.min(Math.floor(value ?? fallback), 1e5));
|
|
48623
48908
|
}
|
|
@@ -48679,16 +48964,16 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
|
|
|
48679
48964
|
try {
|
|
48680
48965
|
resolved = await fs23.realpath(projectRoot);
|
|
48681
48966
|
} catch {
|
|
48682
|
-
resolved =
|
|
48967
|
+
resolved = path48.resolve(projectRoot);
|
|
48683
48968
|
}
|
|
48684
48969
|
if (this.initialized && resolved === this.projectRoot) return;
|
|
48685
48970
|
if (this.initialized) await this.close();
|
|
48686
48971
|
const filename = this.options.filename ?? "memory.db";
|
|
48687
|
-
if (
|
|
48972
|
+
if (path48.basename(filename) !== filename || filename === "." || filename === "..") {
|
|
48688
48973
|
throw new Error("SQLite memory filename must not contain a path.");
|
|
48689
48974
|
}
|
|
48690
|
-
const zelariDirectory =
|
|
48691
|
-
const directory =
|
|
48975
|
+
const zelariDirectory = path48.join(resolved, ".zelari");
|
|
48976
|
+
const directory = path48.join(zelariDirectory, "memory");
|
|
48692
48977
|
for (const candidate of [zelariDirectory, directory]) {
|
|
48693
48978
|
let stat2;
|
|
48694
48979
|
try {
|
|
@@ -48707,12 +48992,12 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
|
|
|
48707
48992
|
}
|
|
48708
48993
|
}
|
|
48709
48994
|
const canonicalDirectory = await fs23.realpath(directory);
|
|
48710
|
-
const relativeDirectory =
|
|
48711
|
-
if (relativeDirectory.startsWith("..") ||
|
|
48995
|
+
const relativeDirectory = path48.relative(resolved, canonicalDirectory);
|
|
48996
|
+
if (relativeDirectory.startsWith("..") || path48.isAbsolute(relativeDirectory)) {
|
|
48712
48997
|
throw new Error("SQLite memory directory resolves outside the active project.");
|
|
48713
48998
|
}
|
|
48714
48999
|
this.projectRoot = resolved;
|
|
48715
|
-
this.databasePath =
|
|
49000
|
+
this.databasePath = path48.join(canonicalDirectory, filename);
|
|
48716
49001
|
const opened = await this.rpc.open({
|
|
48717
49002
|
dbPath: this.databasePath,
|
|
48718
49003
|
schemaSql: SQLITE_MEMORY_BASE_SCHEMA,
|
|
@@ -49245,7 +49530,7 @@ __export(serviceFactory_exports, {
|
|
|
49245
49530
|
});
|
|
49246
49531
|
import { createHash as createHash18 } from "node:crypto";
|
|
49247
49532
|
import { promises as fs24 } from "node:fs";
|
|
49248
|
-
import * as
|
|
49533
|
+
import * as path49 from "node:path";
|
|
49249
49534
|
function isMemoryV2Enabled(env = process.env) {
|
|
49250
49535
|
if (env.ZELARI_MEMORY === "0") return false;
|
|
49251
49536
|
if (env.ZELARI_MEMORY_BACKEND === "file" || env.ZELARI_MEMORY_BACKEND === "jsonl") return false;
|
|
@@ -49266,7 +49551,7 @@ async function canonicalProjectId(projectRoot) {
|
|
|
49266
49551
|
try {
|
|
49267
49552
|
canonical = await fs24.realpath(projectRoot);
|
|
49268
49553
|
} catch {
|
|
49269
|
-
canonical =
|
|
49554
|
+
canonical = path49.resolve(projectRoot);
|
|
49270
49555
|
}
|
|
49271
49556
|
canonical = canonical.replace(/\\/g, "/").replace(/\/$/, "");
|
|
49272
49557
|
if (process.platform === "win32") canonical = canonical.toLocaleLowerCase("en-US");
|
|
@@ -49334,14 +49619,14 @@ var init_serviceFactory = __esm({
|
|
|
49334
49619
|
});
|
|
49335
49620
|
|
|
49336
49621
|
// src/cli/workspace/projectInstructions.ts
|
|
49337
|
-
import { existsSync as existsSync28, readFileSync as
|
|
49622
|
+
import { existsSync as existsSync28, readFileSync as readFileSync24 } from "node:fs";
|
|
49338
49623
|
import { join as join26 } from "node:path";
|
|
49339
49624
|
function loadProjectInstructions(projectRoot = process.cwd(), maxChars = MAX_CHARS) {
|
|
49340
49625
|
for (const name of CANDIDATES) {
|
|
49341
49626
|
const full = join26(projectRoot, name);
|
|
49342
49627
|
if (!existsSync28(full)) continue;
|
|
49343
49628
|
try {
|
|
49344
|
-
let raw =
|
|
49629
|
+
let raw = readFileSync24(full, "utf8");
|
|
49345
49630
|
raw = raw.replace(/\r\n/g, "\n").trim();
|
|
49346
49631
|
if (!raw) continue;
|
|
49347
49632
|
if (raw.length <= maxChars) {
|
|
@@ -49385,7 +49670,7 @@ __export(workspaceSummary_exports, {
|
|
|
49385
49670
|
buildWorkspaceSummary: () => buildWorkspaceSummary,
|
|
49386
49671
|
buildZelariReadHint: () => buildZelariReadHint
|
|
49387
49672
|
});
|
|
49388
|
-
import { existsSync as existsSync29, readFileSync as
|
|
49673
|
+
import { existsSync as existsSync29, readFileSync as readFileSync25, readdirSync as readdirSync6, statSync as statSync5 } from "node:fs";
|
|
49389
49674
|
import { join as join27, relative as relative2 } from "node:path";
|
|
49390
49675
|
function buildWorkspaceSummary(projectRoot = process.cwd(), options = {}) {
|
|
49391
49676
|
const { maxEntries = 30, maxChars = 3500, maxDeps = 24, maxScripts = 16 } = options;
|
|
@@ -49423,7 +49708,7 @@ function buildPlanSummary(projectRoot = process.cwd(), options) {
|
|
|
49423
49708
|
if (!existsSync29(planPath)) return null;
|
|
49424
49709
|
let plan;
|
|
49425
49710
|
try {
|
|
49426
|
-
plan = JSON.parse(
|
|
49711
|
+
plan = JSON.parse(readFileSync25(planPath, "utf8"));
|
|
49427
49712
|
} catch {
|
|
49428
49713
|
return null;
|
|
49429
49714
|
}
|
|
@@ -49581,7 +49866,7 @@ function readPackageJson(projectRoot) {
|
|
|
49581
49866
|
const p3 = join27(projectRoot, "package.json");
|
|
49582
49867
|
if (!existsSync29(p3)) return null;
|
|
49583
49868
|
try {
|
|
49584
|
-
return JSON.parse(
|
|
49869
|
+
return JSON.parse(readFileSync25(p3, "utf8"));
|
|
49585
49870
|
} catch {
|
|
49586
49871
|
return null;
|
|
49587
49872
|
}
|
|
@@ -49709,7 +49994,7 @@ var composeContext_exports = {};
|
|
|
49709
49994
|
__export(composeContext_exports, {
|
|
49710
49995
|
composeProjectContext: () => composeProjectContext
|
|
49711
49996
|
});
|
|
49712
|
-
import { existsSync as existsSync31, readdirSync as readdirSync7, readFileSync as
|
|
49997
|
+
import { existsSync as existsSync31, readdirSync as readdirSync7, readFileSync as readFileSync26 } from "node:fs";
|
|
49713
49998
|
import { join as join29 } from "node:path";
|
|
49714
49999
|
function cap2(text, max, label) {
|
|
49715
50000
|
if (!text || text.length <= max) return { text: text || "", truncated: false };
|
|
@@ -49850,15 +50135,15 @@ function readDurableHeadSync(projectRoot) {
|
|
|
49850
50135
|
try {
|
|
49851
50136
|
const headPath = join29(projectRoot, ".zelari", "state", "HEAD.json");
|
|
49852
50137
|
if (!existsSync31(headPath)) return "";
|
|
49853
|
-
const head = JSON.parse(
|
|
50138
|
+
const head = JSON.parse(readFileSync26(headPath, "utf8"));
|
|
49854
50139
|
if (!head?.id) return "";
|
|
49855
50140
|
const metaPath = join29(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
|
|
49856
50141
|
if (!existsSync31(metaPath)) return "";
|
|
49857
|
-
const meta3 = JSON.parse(
|
|
50142
|
+
const meta3 = JSON.parse(readFileSync26(metaPath, "utf8"));
|
|
49858
50143
|
const discPath = meta3.artifactDir ? join29(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join29(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
|
|
49859
50144
|
let discoveries = [];
|
|
49860
50145
|
if (existsSync31(discPath)) {
|
|
49861
|
-
discoveries = JSON.parse(
|
|
50146
|
+
discoveries = JSON.parse(readFileSync26(discPath, "utf8"));
|
|
49862
50147
|
}
|
|
49863
50148
|
const reusable = discoveries.filter((d) => d.reusable !== false);
|
|
49864
50149
|
const lines = [
|
|
@@ -49891,13 +50176,13 @@ var planDetect_exports = {};
|
|
|
49891
50176
|
__export(planDetect_exports, {
|
|
49892
50177
|
hasWorkspacePlan: () => hasWorkspacePlan
|
|
49893
50178
|
});
|
|
49894
|
-
import { existsSync as existsSync32, readFileSync as
|
|
50179
|
+
import { existsSync as existsSync32, readFileSync as readFileSync27 } from "node:fs";
|
|
49895
50180
|
import { join as join30 } from "node:path";
|
|
49896
50181
|
function hasWorkspacePlan(projectRoot = process.cwd()) {
|
|
49897
50182
|
const planPath = join30(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
49898
50183
|
if (!existsSync32(planPath)) return false;
|
|
49899
50184
|
try {
|
|
49900
|
-
const parsed = JSON.parse(
|
|
50185
|
+
const parsed = JSON.parse(readFileSync27(planPath, "utf8"));
|
|
49901
50186
|
return Array.isArray(parsed.phases) && parsed.phases.length > 0;
|
|
49902
50187
|
} catch {
|
|
49903
50188
|
return false;
|
|
@@ -49959,7 +50244,7 @@ import {
|
|
|
49959
50244
|
existsSync as existsSync33,
|
|
49960
50245
|
readdirSync as readdirSync8,
|
|
49961
50246
|
writeFileSync as writeFileSync17,
|
|
49962
|
-
readFileSync as
|
|
50247
|
+
readFileSync as readFileSync28,
|
|
49963
50248
|
mkdirSync as mkdirSync15,
|
|
49964
50249
|
renameSync as renameSync4
|
|
49965
50250
|
} from "node:fs";
|
|
@@ -49980,7 +50265,7 @@ function readPlan(ctx) {
|
|
|
49980
50265
|
if (existsSync33(jsonPath)) {
|
|
49981
50266
|
try {
|
|
49982
50267
|
const parsed = JSON.parse(
|
|
49983
|
-
|
|
50268
|
+
readFileSync28(jsonPath, "utf8")
|
|
49984
50269
|
);
|
|
49985
50270
|
const { phases, tasks, milestones, ...root } = parsed;
|
|
49986
50271
|
return {
|
|
@@ -49992,8 +50277,8 @@ function readPlan(ctx) {
|
|
|
49992
50277
|
} catch {
|
|
49993
50278
|
}
|
|
49994
50279
|
}
|
|
49995
|
-
const
|
|
49996
|
-
const doc = ctx.storage.readIfExists(
|
|
50280
|
+
const path74 = workspaceFile(ctx.rootDir, "plan");
|
|
50281
|
+
const doc = ctx.storage.readIfExists(path74);
|
|
49997
50282
|
if (!doc) return { phases: [], tasks: [], milestones: [] };
|
|
49998
50283
|
const meta3 = doc.meta;
|
|
49999
50284
|
return {
|
|
@@ -50171,7 +50456,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
50171
50456
|
dueDate: input.dueDate,
|
|
50172
50457
|
targetVersion: version2
|
|
50173
50458
|
});
|
|
50174
|
-
const
|
|
50459
|
+
const path74 = join31(ctx.rootDir, "milestones", `${id3}.md`);
|
|
50175
50460
|
const meta3 = {
|
|
50176
50461
|
kind: "milestone",
|
|
50177
50462
|
id: id3,
|
|
@@ -50188,7 +50473,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
50188
50473
|
`Target version: ${version2}`,
|
|
50189
50474
|
""
|
|
50190
50475
|
].join("\n");
|
|
50191
|
-
ctx.storage.write(
|
|
50476
|
+
ctx.storage.write(path74, meta3, body);
|
|
50192
50477
|
return { id: id3, created: true };
|
|
50193
50478
|
}
|
|
50194
50479
|
function readPlanSummary(ctx) {
|
|
@@ -50392,7 +50677,7 @@ function addIdeaStub(ctx) {
|
|
|
50392
50677
|
const tags = args["tags"] ?? [];
|
|
50393
50678
|
const category = args["category"] ?? "General";
|
|
50394
50679
|
const id3 = `${nextAdrId(ctx)}-${slugify3(title)}`;
|
|
50395
|
-
const
|
|
50680
|
+
const path74 = workspaceArtifact(ctx.rootDir, "decisions", id3);
|
|
50396
50681
|
const meta3 = {
|
|
50397
50682
|
kind: "adr",
|
|
50398
50683
|
status: "proposed",
|
|
@@ -50418,7 +50703,7 @@ function addIdeaStub(ctx) {
|
|
|
50418
50703
|
...consequences.map((c) => `- ${c}`),
|
|
50419
50704
|
""
|
|
50420
50705
|
].join("\n");
|
|
50421
|
-
ctx.storage.write(
|
|
50706
|
+
ctx.storage.write(path74, meta3, body);
|
|
50422
50707
|
return `ADR ${id3} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
|
|
50423
50708
|
});
|
|
50424
50709
|
}
|
|
@@ -50500,14 +50785,14 @@ function createDocumentStub(ctx) {
|
|
|
50500
50785
|
ctx.storage.write(risksPath, riskMeta, content);
|
|
50501
50786
|
return `Document "${title}" created at risks.md (workspace root).`;
|
|
50502
50787
|
}
|
|
50503
|
-
const
|
|
50788
|
+
const path74 = workspaceArtifact(ctx.rootDir, "docs", slug);
|
|
50504
50789
|
const meta3 = {
|
|
50505
50790
|
kind: "doc",
|
|
50506
50791
|
id: slug,
|
|
50507
50792
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
50508
50793
|
tags
|
|
50509
50794
|
};
|
|
50510
|
-
ctx.storage.write(
|
|
50795
|
+
ctx.storage.write(path74, meta3, content);
|
|
50511
50796
|
return `Document "${title}" created at docs/${slug}.md.`;
|
|
50512
50797
|
});
|
|
50513
50798
|
}
|
|
@@ -50544,7 +50829,7 @@ function searchDocumentsStub(ctx) {
|
|
|
50544
50829
|
const results = [];
|
|
50545
50830
|
for (const file2 of files) {
|
|
50546
50831
|
if (!existsSync33(file2)) continue;
|
|
50547
|
-
const raw =
|
|
50832
|
+
const raw = readFileSync28(file2, "utf8");
|
|
50548
50833
|
const content = raw.toLowerCase();
|
|
50549
50834
|
let idx = -1;
|
|
50550
50835
|
let matchLen = 0;
|
|
@@ -50883,21 +51168,21 @@ var init_mcpClient = __esm({
|
|
|
50883
51168
|
import {
|
|
50884
51169
|
existsSync as existsSync34,
|
|
50885
51170
|
mkdirSync as mkdirSync16,
|
|
50886
|
-
readFileSync as
|
|
51171
|
+
readFileSync as readFileSync29,
|
|
50887
51172
|
writeFileSync as writeFileSync18
|
|
50888
51173
|
} from "node:fs";
|
|
50889
51174
|
import { dirname as dirname9, join as join32 } from "node:path";
|
|
50890
|
-
import { homedir as
|
|
51175
|
+
import { homedir as homedir11 } from "node:os";
|
|
50891
51176
|
function getUserMcpPath() {
|
|
50892
|
-
return join32(
|
|
51177
|
+
return join32(homedir11(), ".zelari-code", "mcp.json");
|
|
50893
51178
|
}
|
|
50894
51179
|
function getProjectMcpPath(projectRoot) {
|
|
50895
51180
|
return join32(projectRoot, ".zelari", "mcp.json");
|
|
50896
51181
|
}
|
|
50897
|
-
function readFile4(
|
|
50898
|
-
if (!existsSync34(
|
|
51182
|
+
function readFile4(path74) {
|
|
51183
|
+
if (!existsSync34(path74)) return {};
|
|
50899
51184
|
try {
|
|
50900
|
-
const parsed = JSON.parse(
|
|
51185
|
+
const parsed = JSON.parse(readFileSync29(path74, "utf8"));
|
|
50901
51186
|
const out = {};
|
|
50902
51187
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
50903
51188
|
if (!cfg || typeof cfg.command !== "string" || !cfg.command.trim()) continue;
|
|
@@ -50913,10 +51198,10 @@ function readFile4(path72) {
|
|
|
50913
51198
|
return {};
|
|
50914
51199
|
}
|
|
50915
51200
|
}
|
|
50916
|
-
function
|
|
50917
|
-
mkdirSync16(dirname9(
|
|
51201
|
+
function writeFile3(path74, servers) {
|
|
51202
|
+
mkdirSync16(dirname9(path74), { recursive: true });
|
|
50918
51203
|
const body = { mcpServers: servers };
|
|
50919
|
-
writeFileSync18(
|
|
51204
|
+
writeFileSync18(path74, `${JSON.stringify(body, null, 2)}
|
|
50920
51205
|
`, "utf8");
|
|
50921
51206
|
}
|
|
50922
51207
|
function listMcpServers(projectRoot) {
|
|
@@ -50949,9 +51234,9 @@ function upsertMcpServer(opts) {
|
|
|
50949
51234
|
if (!opts.config.command?.trim()) {
|
|
50950
51235
|
return { ok: false, error: "command is required" };
|
|
50951
51236
|
}
|
|
50952
|
-
let
|
|
51237
|
+
let path74;
|
|
50953
51238
|
if (opts.scope === "user") {
|
|
50954
|
-
|
|
51239
|
+
path74 = getUserMcpPath();
|
|
50955
51240
|
} else {
|
|
50956
51241
|
const root = opts.projectRoot?.trim();
|
|
50957
51242
|
if (!root) {
|
|
@@ -50960,30 +51245,30 @@ function upsertMcpServer(opts) {
|
|
|
50960
51245
|
error: "projectRoot required for project scope (Open Folder first)"
|
|
50961
51246
|
};
|
|
50962
51247
|
}
|
|
50963
|
-
|
|
51248
|
+
path74 = getProjectMcpPath(root);
|
|
50964
51249
|
}
|
|
50965
|
-
const current = readFile4(
|
|
51250
|
+
const current = readFile4(path74);
|
|
50966
51251
|
current[name] = {
|
|
50967
51252
|
command: opts.config.command.trim(),
|
|
50968
51253
|
args: opts.config.args,
|
|
50969
51254
|
env: opts.config.env,
|
|
50970
51255
|
enabled: opts.config.enabled !== false
|
|
50971
51256
|
};
|
|
50972
|
-
|
|
50973
|
-
return { ok: true, path:
|
|
51257
|
+
writeFile3(path74, current);
|
|
51258
|
+
return { ok: true, path: path74 };
|
|
50974
51259
|
}
|
|
50975
51260
|
function removeMcpServer(opts) {
|
|
50976
|
-
const
|
|
50977
|
-
if (!
|
|
51261
|
+
const path74 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
|
|
51262
|
+
if (!path74) {
|
|
50978
51263
|
return { ok: false, error: "projectRoot required for project scope" };
|
|
50979
51264
|
}
|
|
50980
|
-
const current = readFile4(
|
|
51265
|
+
const current = readFile4(path74);
|
|
50981
51266
|
if (!(opts.name in current)) {
|
|
50982
|
-
return { ok: false, error: `Server "${opts.name}" not found in ${
|
|
51267
|
+
return { ok: false, error: `Server "${opts.name}" not found in ${path74}` };
|
|
50983
51268
|
}
|
|
50984
51269
|
delete current[opts.name];
|
|
50985
|
-
|
|
50986
|
-
return { ok: true, path:
|
|
51270
|
+
writeFile3(path74, current);
|
|
51271
|
+
return { ok: true, path: path74 };
|
|
50987
51272
|
}
|
|
50988
51273
|
var init_mcpConfigIo = __esm({
|
|
50989
51274
|
"src/cli/mcp/mcpConfigIo.ts"() {
|
|
@@ -51125,14 +51410,14 @@ __export(mcpManager_exports, {
|
|
|
51125
51410
|
readMcpConfig: () => readMcpConfig,
|
|
51126
51411
|
registerMcpTools: () => registerMcpTools
|
|
51127
51412
|
});
|
|
51128
|
-
import { existsSync as existsSync35, readFileSync as
|
|
51413
|
+
import { existsSync as existsSync35, readFileSync as readFileSync30 } from "node:fs";
|
|
51129
51414
|
import { join as join33 } from "node:path";
|
|
51130
|
-
import { homedir as
|
|
51415
|
+
import { homedir as homedir12 } from "node:os";
|
|
51131
51416
|
function readMcpConfig(projectRoot = process.cwd(), opts) {
|
|
51132
51417
|
const merged = {};
|
|
51133
51418
|
const paths = [];
|
|
51134
51419
|
if (process.env["ZELARI_MCP_USER"] !== "0") {
|
|
51135
|
-
paths.push(join33(
|
|
51420
|
+
paths.push(join33(homedir12(), ".zelari-code", "mcp.json"));
|
|
51136
51421
|
}
|
|
51137
51422
|
if (!opts?.skipProjectMcp) {
|
|
51138
51423
|
paths.push(join33(projectRoot, ".zelari", "mcp.json"));
|
|
@@ -51140,7 +51425,7 @@ function readMcpConfig(projectRoot = process.cwd(), opts) {
|
|
|
51140
51425
|
for (const p3 of paths) {
|
|
51141
51426
|
if (!existsSync35(p3)) continue;
|
|
51142
51427
|
try {
|
|
51143
|
-
const parsed = JSON.parse(
|
|
51428
|
+
const parsed = JSON.parse(readFileSync30(p3, "utf8"));
|
|
51144
51429
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
51145
51430
|
if (!cfg || typeof cfg.command !== "string" || cfg.command.length === 0) continue;
|
|
51146
51431
|
merged[name] = cfg;
|
|
@@ -51379,15 +51664,15 @@ __export(agentsMd_exports, {
|
|
|
51379
51664
|
serializeAgentsMd: () => serializeAgentsMd,
|
|
51380
51665
|
updateAgentsMd: () => updateAgentsMd
|
|
51381
51666
|
});
|
|
51382
|
-
import { existsSync as existsSync36, readFileSync as
|
|
51667
|
+
import { existsSync as existsSync36, readFileSync as readFileSync31, writeFileSync as writeFileSync19 } from "node:fs";
|
|
51383
51668
|
import { createHash as createHash19 } from "node:crypto";
|
|
51384
51669
|
import { join as join34 } from "node:path";
|
|
51385
51670
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
51386
51671
|
async function readPackageJson2(projectRoot) {
|
|
51387
|
-
const
|
|
51388
|
-
if (!existsSync36(
|
|
51672
|
+
const path74 = join34(projectRoot, "package.json");
|
|
51673
|
+
if (!existsSync36(path74)) return null;
|
|
51389
51674
|
try {
|
|
51390
|
-
return JSON.parse(await readFile5(
|
|
51675
|
+
return JSON.parse(await readFile5(path74, "utf8"));
|
|
51391
51676
|
} catch {
|
|
51392
51677
|
return null;
|
|
51393
51678
|
}
|
|
@@ -51437,7 +51722,7 @@ async function genConventions(ctx) {
|
|
|
51437
51722
|
const lines = [];
|
|
51438
51723
|
const claudeMd = join34(ctx.projectRoot, "CLAUDE.MD");
|
|
51439
51724
|
if (existsSync36(claudeMd)) {
|
|
51440
|
-
const content =
|
|
51725
|
+
const content = readFileSync31(claudeMd, "utf8");
|
|
51441
51726
|
const match = content.match(/## Architecture rules[\s\S]+?(?=\n## |\n*$)/);
|
|
51442
51727
|
if (match) {
|
|
51443
51728
|
lines.push('<!-- Extracted from CLAUDE.MD "Architecture rules" -->');
|
|
@@ -51469,9 +51754,9 @@ async function genBuild(ctx) {
|
|
|
51469
51754
|
].join("\n");
|
|
51470
51755
|
}
|
|
51471
51756
|
async function genOpenQuestions(ctx) {
|
|
51472
|
-
const
|
|
51473
|
-
if (!existsSync36(
|
|
51474
|
-
const content =
|
|
51757
|
+
const path74 = join34(ctx.rootDir, "risks.md");
|
|
51758
|
+
if (!existsSync36(path74)) return "_No open questions._";
|
|
51759
|
+
const content = readFileSync31(path74, "utf8");
|
|
51475
51760
|
const lines = content.split("\n");
|
|
51476
51761
|
const questions = [];
|
|
51477
51762
|
let currentTitle = "";
|
|
@@ -51547,7 +51832,7 @@ function titleCase(id3) {
|
|
|
51547
51832
|
async function updateAgentsMd(ctx, projectRoot) {
|
|
51548
51833
|
const agentsPath = join34(projectRoot, "AGENTS.MD");
|
|
51549
51834
|
if (existsSync36(agentsPath)) {
|
|
51550
|
-
const content =
|
|
51835
|
+
const content = readFileSync31(agentsPath, "utf8");
|
|
51551
51836
|
const hasAnyMarker = AUTO_SECTIONS.some((id3) => content.includes(MARKER_OPEN(id3)));
|
|
51552
51837
|
if (!hasAnyMarker) {
|
|
51553
51838
|
return {
|
|
@@ -51563,7 +51848,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
51563
51848
|
}
|
|
51564
51849
|
let manualContent = "";
|
|
51565
51850
|
if (existsSync36(agentsPath)) {
|
|
51566
|
-
const { manualBlocks } = parseAgentsMd(
|
|
51851
|
+
const { manualBlocks } = parseAgentsMd(readFileSync31(agentsPath, "utf8"));
|
|
51567
51852
|
manualContent = manualBlocks.after;
|
|
51568
51853
|
} else {
|
|
51569
51854
|
const projectName2 = projectName(projectRoot);
|
|
@@ -51579,7 +51864,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
51579
51864
|
""
|
|
51580
51865
|
].join("\n");
|
|
51581
51866
|
}
|
|
51582
|
-
const oldContent = existsSync36(agentsPath) ?
|
|
51867
|
+
const oldContent = existsSync36(agentsPath) ? readFileSync31(agentsPath, "utf8") : "";
|
|
51583
51868
|
const { sections: oldSections } = parseAgentsMd(oldContent);
|
|
51584
51869
|
const changedSections = [];
|
|
51585
51870
|
for (const id3 of AUTO_SECTIONS) {
|
|
@@ -51716,7 +52001,7 @@ var init_completeDesign = __esm({
|
|
|
51716
52001
|
});
|
|
51717
52002
|
|
|
51718
52003
|
// src/cli/workspace/planDriftCheck.ts
|
|
51719
|
-
import { existsSync as existsSync37, readFileSync as
|
|
52004
|
+
import { existsSync as existsSync37, readFileSync as readFileSync32, readdirSync as readdirSync9, statSync as statSync6, writeFileSync as writeFileSync20 } from "node:fs";
|
|
51720
52005
|
import { join as join35 } from "node:path";
|
|
51721
52006
|
function findCanonicalDoc(rootDir) {
|
|
51722
52007
|
const docsDir = join35(rootDir, "docs");
|
|
@@ -51745,9 +52030,9 @@ function versionKey(value) {
|
|
|
51745
52030
|
function firstString2(v) {
|
|
51746
52031
|
return typeof v === "string" && v.trim().length > 0 ? v : null;
|
|
51747
52032
|
}
|
|
51748
|
-
function readFileSyncSafe(
|
|
52033
|
+
function readFileSyncSafe(path74) {
|
|
51749
52034
|
try {
|
|
51750
|
-
return
|
|
52035
|
+
return readFileSync32(path74, "utf8");
|
|
51751
52036
|
} catch {
|
|
51752
52037
|
return null;
|
|
51753
52038
|
}
|
|
@@ -51762,7 +52047,7 @@ async function runPlanDriftCheck(rootDir) {
|
|
|
51762
52047
|
}
|
|
51763
52048
|
let plan;
|
|
51764
52049
|
try {
|
|
51765
|
-
plan = JSON.parse(
|
|
52050
|
+
plan = JSON.parse(readFileSync32(planPath, "utf8"));
|
|
51766
52051
|
} catch {
|
|
51767
52052
|
return { ran: false, reason: ".zelari/plan.json corrupt" };
|
|
51768
52053
|
}
|
|
@@ -51888,7 +52173,7 @@ var init_planDriftCheck = __esm({
|
|
|
51888
52173
|
|
|
51889
52174
|
// src/cli/workspace/projectSmoke.ts
|
|
51890
52175
|
import { spawn as spawn14 } from "node:child_process";
|
|
51891
|
-
import { existsSync as existsSync38, readFileSync as
|
|
52176
|
+
import { existsSync as existsSync38, readFileSync as readFileSync33 } from "node:fs";
|
|
51892
52177
|
import { join as join36 } from "node:path";
|
|
51893
52178
|
function pickSmokeScript(scripts) {
|
|
51894
52179
|
if (!scripts) return null;
|
|
@@ -51907,7 +52192,7 @@ async function runProjectSmoke(projectRoot, timeoutMs2 = DEFAULT_TIMEOUT_MS3) {
|
|
|
51907
52192
|
}
|
|
51908
52193
|
let scripts = {};
|
|
51909
52194
|
try {
|
|
51910
|
-
const pkg = JSON.parse(
|
|
52195
|
+
const pkg = JSON.parse(readFileSync33(pkgPath, "utf8"));
|
|
51911
52196
|
scripts = pkg.scripts ?? {};
|
|
51912
52197
|
} catch {
|
|
51913
52198
|
return { ran: false, reason: "package.json unreadable (skipped)" };
|
|
@@ -51995,7 +52280,7 @@ __export(postCouncilHook_exports, {
|
|
|
51995
52280
|
runPostCouncilHook: () => runPostCouncilHook
|
|
51996
52281
|
});
|
|
51997
52282
|
import { spawn as spawn15 } from "node:child_process";
|
|
51998
|
-
import { existsSync as existsSync39, readFileSync as
|
|
52283
|
+
import { existsSync as existsSync39, readFileSync as readFileSync34 } from "node:fs";
|
|
51999
52284
|
import { join as join37 } from "node:path";
|
|
52000
52285
|
async function runCompleteDesignPostProcessor(ctx, options) {
|
|
52001
52286
|
if (options?.runMode === "implementation") {
|
|
@@ -52017,7 +52302,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
52017
52302
|
}
|
|
52018
52303
|
let phaseCount = 0;
|
|
52019
52304
|
try {
|
|
52020
|
-
const parsed = JSON.parse(
|
|
52305
|
+
const parsed = JSON.parse(readFileSync34(planJsonPath2, "utf8"));
|
|
52021
52306
|
phaseCount = Array.isArray(parsed.phases) ? parsed.phases.length : 0;
|
|
52022
52307
|
} catch {
|
|
52023
52308
|
return { ran: false, reason: ".zelari/plan.json corrupt" };
|
|
@@ -52210,8 +52495,8 @@ async function runPostCouncilHook(ctx, options) {
|
|
|
52210
52495
|
sources: scope.sources
|
|
52211
52496
|
} : void 0
|
|
52212
52497
|
});
|
|
52213
|
-
const
|
|
52214
|
-
completionHook = { ran: true, path:
|
|
52498
|
+
const path74 = writeCouncilCompletion(ctx.rootDir, completion);
|
|
52499
|
+
completionHook = { ran: true, path: path74, completion };
|
|
52215
52500
|
} catch (err) {
|
|
52216
52501
|
completionHook = {
|
|
52217
52502
|
ran: true,
|
|
@@ -52252,11 +52537,11 @@ __export(councilFeedback_exports, {
|
|
|
52252
52537
|
import {
|
|
52253
52538
|
promises as fs25,
|
|
52254
52539
|
existsSync as existsSync40,
|
|
52255
|
-
readFileSync as
|
|
52540
|
+
readFileSync as readFileSync35,
|
|
52256
52541
|
writeFileSync as writeFileSync21,
|
|
52257
52542
|
mkdirSync as mkdirSync17
|
|
52258
52543
|
} from "node:fs";
|
|
52259
|
-
import
|
|
52544
|
+
import path50 from "node:path";
|
|
52260
52545
|
import os10 from "node:os";
|
|
52261
52546
|
var FeedbackStore;
|
|
52262
52547
|
var init_councilFeedback = __esm({
|
|
@@ -52267,7 +52552,7 @@ var init_councilFeedback = __esm({
|
|
|
52267
52552
|
now;
|
|
52268
52553
|
entries = [];
|
|
52269
52554
|
constructor(options = {}) {
|
|
52270
|
-
this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ??
|
|
52555
|
+
this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ?? path50.join(os10.homedir(), ".tmp", "zelari-code", "council-feedback.json"));
|
|
52271
52556
|
this.now = options.now ?? Date.now;
|
|
52272
52557
|
this.load();
|
|
52273
52558
|
}
|
|
@@ -52362,7 +52647,7 @@ var init_councilFeedback = __esm({
|
|
|
52362
52647
|
load() {
|
|
52363
52648
|
if (!existsSync40(this.file)) return;
|
|
52364
52649
|
try {
|
|
52365
|
-
const raw =
|
|
52650
|
+
const raw = readFileSync35(this.file, "utf-8");
|
|
52366
52651
|
const parsed = JSON.parse(raw);
|
|
52367
52652
|
if (parsed && Array.isArray(parsed.entries)) {
|
|
52368
52653
|
this.entries = parsed.entries.filter(
|
|
@@ -52373,7 +52658,7 @@ var init_councilFeedback = __esm({
|
|
|
52373
52658
|
}
|
|
52374
52659
|
}
|
|
52375
52660
|
save() {
|
|
52376
|
-
mkdirSync17(
|
|
52661
|
+
mkdirSync17(path50.dirname(this.file), { recursive: true });
|
|
52377
52662
|
writeFileSync21(
|
|
52378
52663
|
this.file,
|
|
52379
52664
|
JSON.stringify({ entries: this.entries }, null, 2),
|
|
@@ -52441,7 +52726,7 @@ import { execFile as execFile3 } from "node:child_process";
|
|
|
52441
52726
|
import { promisify as promisify2 } from "node:util";
|
|
52442
52727
|
import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
|
|
52443
52728
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
52444
|
-
import
|
|
52729
|
+
import path51 from "node:path";
|
|
52445
52730
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
52446
52731
|
async function git3(cwd, args, env) {
|
|
52447
52732
|
const { stdout } = await execFileAsync2("git", ["-C", cwd, ...args], {
|
|
@@ -52461,8 +52746,8 @@ async function isGitRepo(cwd) {
|
|
|
52461
52746
|
return await gitSafe(cwd, ["rev-parse", "--is-inside-work-tree"]) === "true";
|
|
52462
52747
|
}
|
|
52463
52748
|
async function withTempIndex(fn) {
|
|
52464
|
-
const dir = mkdtempSync(
|
|
52465
|
-
const indexFile =
|
|
52749
|
+
const dir = mkdtempSync(path51.join(tmpdir2(), "zelari-ckpt-"));
|
|
52750
|
+
const indexFile = path51.join(dir, "index");
|
|
52466
52751
|
try {
|
|
52467
52752
|
return await fn(indexFile);
|
|
52468
52753
|
} finally {
|
|
@@ -52553,7 +52838,7 @@ async function restoreCheckpoint(cwd, id3) {
|
|
|
52553
52838
|
const deleted = [];
|
|
52554
52839
|
for (const rel2 of added) {
|
|
52555
52840
|
try {
|
|
52556
|
-
rmSync2(
|
|
52841
|
+
rmSync2(path51.join(cwd, rel2), { force: true });
|
|
52557
52842
|
deleted.push(rel2);
|
|
52558
52843
|
} catch {
|
|
52559
52844
|
}
|
|
@@ -52654,7 +52939,7 @@ __export(fileBackend_exports, {
|
|
|
52654
52939
|
});
|
|
52655
52940
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
52656
52941
|
import { promises as fs26 } from "node:fs";
|
|
52657
|
-
import * as
|
|
52942
|
+
import * as path52 from "node:path";
|
|
52658
52943
|
function tokenize(text) {
|
|
52659
52944
|
return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
|
|
52660
52945
|
}
|
|
@@ -52705,8 +52990,8 @@ var init_fileBackend = __esm({
|
|
|
52705
52990
|
logPath = "";
|
|
52706
52991
|
memoryDir = "";
|
|
52707
52992
|
async init(projectRoot) {
|
|
52708
|
-
this.memoryDir =
|
|
52709
|
-
this.logPath =
|
|
52993
|
+
this.memoryDir = path52.join(projectRoot, ".zelari", "memory");
|
|
52994
|
+
this.logPath = path52.join(this.memoryDir, "log.jsonl");
|
|
52710
52995
|
await fs26.mkdir(this.memoryDir, { recursive: true });
|
|
52711
52996
|
}
|
|
52712
52997
|
async add(content, metadata2 = {}, graph) {
|
|
@@ -52779,12 +53064,12 @@ var init_fileBackend = __esm({
|
|
|
52779
53064
|
|
|
52780
53065
|
// src/cli/traceStore.ts
|
|
52781
53066
|
import { promises as fs27 } from "node:fs";
|
|
52782
|
-
import * as
|
|
53067
|
+
import * as path53 from "node:path";
|
|
52783
53068
|
function traceDir(projectRoot) {
|
|
52784
|
-
return
|
|
53069
|
+
return path53.join(projectRoot, ".zelari", "trace");
|
|
52785
53070
|
}
|
|
52786
53071
|
function tracePath(projectRoot, missionId) {
|
|
52787
|
-
return
|
|
53072
|
+
return path53.join(traceDir(projectRoot), `${missionId}.json`);
|
|
52788
53073
|
}
|
|
52789
53074
|
async function saveTrace(projectRoot, missionId, entries) {
|
|
52790
53075
|
const dir = traceDir(projectRoot);
|
|
@@ -52821,7 +53106,7 @@ __export(zelariMission_exports, {
|
|
|
52821
53106
|
});
|
|
52822
53107
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
52823
53108
|
import { promises as fs28 } from "node:fs";
|
|
52824
|
-
import * as
|
|
53109
|
+
import * as path54 from "node:path";
|
|
52825
53110
|
function resolveMaxIterations(env = process.env) {
|
|
52826
53111
|
const raw = env.ZELARI_MISSION_MAX_ITER;
|
|
52827
53112
|
const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
|
|
@@ -52864,10 +53149,10 @@ function isMissionAutoStart(env = process.env) {
|
|
|
52864
53149
|
return env.ZELARI_MISSION_AUTO === "1";
|
|
52865
53150
|
}
|
|
52866
53151
|
async function writeMissionState(projectRoot, state3) {
|
|
52867
|
-
const dir =
|
|
53152
|
+
const dir = path54.join(projectRoot, ".zelari");
|
|
52868
53153
|
await fs28.mkdir(dir, { recursive: true });
|
|
52869
53154
|
await fs28.writeFile(
|
|
52870
|
-
|
|
53155
|
+
path54.join(dir, "mission-state.json"),
|
|
52871
53156
|
JSON.stringify(state3, null, 2) + "\n",
|
|
52872
53157
|
"utf8"
|
|
52873
53158
|
);
|
|
@@ -53542,7 +53827,7 @@ function safeSocketPath(socketPath) {
|
|
|
53542
53827
|
return socketPath.trim();
|
|
53543
53828
|
}
|
|
53544
53829
|
function startPermissionBroker(socketPath, handlers, opts) {
|
|
53545
|
-
const
|
|
53830
|
+
const path74 = safeSocketPath(socketPath);
|
|
53546
53831
|
const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
|
|
53547
53832
|
const sockets = /* @__PURE__ */ new Set();
|
|
53548
53833
|
const server = createServer2((socket) => {
|
|
@@ -53642,10 +53927,10 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
53642
53927
|
return new Promise((resolve7, reject) => {
|
|
53643
53928
|
const onError = (err) => reject(err);
|
|
53644
53929
|
server.once("error", onError);
|
|
53645
|
-
server.listen(
|
|
53930
|
+
server.listen(path74, () => {
|
|
53646
53931
|
server.removeListener("error", onError);
|
|
53647
53932
|
resolve7({
|
|
53648
|
-
socketPath:
|
|
53933
|
+
socketPath: path74,
|
|
53649
53934
|
stop: () => new Promise((res) => {
|
|
53650
53935
|
for (const s of sockets) s.destroy();
|
|
53651
53936
|
sockets.clear();
|
|
@@ -53656,7 +53941,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
53656
53941
|
if (done) return;
|
|
53657
53942
|
done = true;
|
|
53658
53943
|
if (process.platform !== "win32") {
|
|
53659
|
-
unlink(
|
|
53944
|
+
unlink(path74, () => res());
|
|
53660
53945
|
} else {
|
|
53661
53946
|
res();
|
|
53662
53947
|
}
|
|
@@ -53669,11 +53954,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
53669
53954
|
});
|
|
53670
53955
|
}
|
|
53671
53956
|
function requestBrokerAsk(socketPath, ask, opts) {
|
|
53672
|
-
const
|
|
53957
|
+
const path74 = safeSocketPath(socketPath);
|
|
53673
53958
|
const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
|
|
53674
53959
|
const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
|
|
53675
53960
|
return new Promise((resolve7, reject) => {
|
|
53676
|
-
const socket = connect(
|
|
53961
|
+
const socket = connect(path74);
|
|
53677
53962
|
let buffer = "";
|
|
53678
53963
|
let settled = false;
|
|
53679
53964
|
const settle = (fn) => {
|
|
@@ -53688,7 +53973,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
|
|
|
53688
53973
|
settle(
|
|
53689
53974
|
() => reject(
|
|
53690
53975
|
new Error(
|
|
53691
|
-
`permission broker unavailable at "${
|
|
53976
|
+
`permission broker unavailable at "${path74}" (connect timed out after ${connectTimeoutMs}ms)`
|
|
53692
53977
|
)
|
|
53693
53978
|
)
|
|
53694
53979
|
);
|
|
@@ -54431,9 +54716,9 @@ __export(graphMemory_exports, {
|
|
|
54431
54716
|
toGraphSnapshot: () => toGraphSnapshot
|
|
54432
54717
|
});
|
|
54433
54718
|
import { promises as fs31 } from "node:fs";
|
|
54434
|
-
import
|
|
54719
|
+
import path58 from "node:path";
|
|
54435
54720
|
function snapshotPath(cwd) {
|
|
54436
|
-
return
|
|
54721
|
+
return path58.join(cwd, SNAPSHOT_DIR, SNAPSHOT_FILE);
|
|
54437
54722
|
}
|
|
54438
54723
|
function toGraphSnapshot(graph, opts) {
|
|
54439
54724
|
const unresolved = (opts.unresolvedFindings ?? []).map((u) => ({
|
|
@@ -54460,7 +54745,7 @@ async function saveGraphSnapshot(cwd, snapshot) {
|
|
|
54460
54745
|
try {
|
|
54461
54746
|
await fs31.access(cwd);
|
|
54462
54747
|
const file2 = snapshotPath(cwd);
|
|
54463
|
-
await fs31.mkdir(
|
|
54748
|
+
await fs31.mkdir(path58.dirname(file2), { recursive: true });
|
|
54464
54749
|
await fs31.writeFile(file2, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
54465
54750
|
} catch {
|
|
54466
54751
|
}
|
|
@@ -54527,7 +54812,7 @@ var SNAPSHOT_DIR, SNAPSHOT_FILE, MAX_SNAPSHOT_FINDINGS_CHARS;
|
|
|
54527
54812
|
var init_graphMemory = __esm({
|
|
54528
54813
|
"src/cli/kraken/graphMemory.ts"() {
|
|
54529
54814
|
"use strict";
|
|
54530
|
-
SNAPSHOT_DIR =
|
|
54815
|
+
SNAPSHOT_DIR = path58.join(".zelari", "kraken");
|
|
54531
54816
|
SNAPSHOT_FILE = "last-graph.json";
|
|
54532
54817
|
MAX_SNAPSHOT_FINDINGS_CHARS = 400;
|
|
54533
54818
|
}
|
|
@@ -54543,14 +54828,14 @@ var init_tentacle = __esm({
|
|
|
54543
54828
|
|
|
54544
54829
|
// src/cli/kraken/workbench.ts
|
|
54545
54830
|
import { promises as fs32 } from "node:fs";
|
|
54546
|
-
import
|
|
54831
|
+
import path59 from "node:path";
|
|
54547
54832
|
function isWorkbenchEnabled(env = process.env) {
|
|
54548
54833
|
const v = (env.ZELARI_KRAKEN_WORKBENCH ?? "1").trim().toLowerCase();
|
|
54549
54834
|
if (v === "0" || v === "false" || v === "no" || v === "off") return false;
|
|
54550
54835
|
return true;
|
|
54551
54836
|
}
|
|
54552
54837
|
function workbenchPath(cwd, graphId) {
|
|
54553
|
-
return
|
|
54838
|
+
return path59.join(cwd, ".zelari", "radio", `workbench-${graphId}.md`);
|
|
54554
54839
|
}
|
|
54555
54840
|
function countByStatus2(nodes) {
|
|
54556
54841
|
const out = { pending: 0, running: 0, done: 0, error: 0, skipped: 0 };
|
|
@@ -54713,7 +54998,7 @@ var init_workbench = __esm({
|
|
|
54713
54998
|
if (!this.enabled) return null;
|
|
54714
54999
|
if (!this.dirty && this.lastWrite) return this.lastWrite;
|
|
54715
55000
|
const out = workbenchPath(this.cwd, this.graphId);
|
|
54716
|
-
await fs32.mkdir(
|
|
55001
|
+
await fs32.mkdir(path59.dirname(out), { recursive: true });
|
|
54717
55002
|
const body = this.render();
|
|
54718
55003
|
const tmp = `${out}.${process.pid}.${Date.now()}.tmp`;
|
|
54719
55004
|
await fs32.writeFile(tmp, body, "utf8");
|
|
@@ -54910,7 +55195,7 @@ __export(executor_exports, {
|
|
|
54910
55195
|
thoroughnessForKind: () => thoroughnessForKind
|
|
54911
55196
|
});
|
|
54912
55197
|
import { existsSync as existsSync41 } from "node:fs";
|
|
54913
|
-
import
|
|
55198
|
+
import path60 from "node:path";
|
|
54914
55199
|
function resolveMaxParallel(env = process.env) {
|
|
54915
55200
|
const raw = env.ZELARI_KRAKEN_MAX_PARALLEL;
|
|
54916
55201
|
if (raw === void 0 || raw === "") return DEFAULT_MAX_PARALLEL;
|
|
@@ -54968,7 +55253,7 @@ function isWorldModelGateEnabled(cwd, env = process.env, checksExists = defaultC
|
|
|
54968
55253
|
}
|
|
54969
55254
|
function defaultChecksExists(cwd) {
|
|
54970
55255
|
try {
|
|
54971
|
-
return existsSync41(
|
|
55256
|
+
return existsSync41(path60.join(cwd, ".zelari", "world", "checks.json"));
|
|
54972
55257
|
} catch {
|
|
54973
55258
|
return false;
|
|
54974
55259
|
}
|
|
@@ -56364,17 +56649,17 @@ var init_prereqChecks = __esm({
|
|
|
56364
56649
|
});
|
|
56365
56650
|
|
|
56366
56651
|
// src/cli/plugins/prefs.ts
|
|
56367
|
-
import { existsSync as existsSync43, readFileSync as
|
|
56368
|
-
import
|
|
56652
|
+
import { existsSync as existsSync43, readFileSync as readFileSync36, writeFileSync as writeFileSync22, mkdirSync as mkdirSync18 } from "node:fs";
|
|
56653
|
+
import path63 from "node:path";
|
|
56369
56654
|
import os11 from "node:os";
|
|
56370
56655
|
function getPluginPrefsPath() {
|
|
56371
|
-
return process.env.ZELARI_PLUGINS_PREFS_FILE ??
|
|
56656
|
+
return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path63.join(os11.homedir(), ".tmp", "zelari-code", "plugins.json");
|
|
56372
56657
|
}
|
|
56373
56658
|
function getPluginPrefs() {
|
|
56374
56659
|
const file2 = getPluginPrefsPath();
|
|
56375
56660
|
try {
|
|
56376
56661
|
if (!existsSync43(file2)) return { ...DEFAULTS2, dontAskAgain: {} };
|
|
56377
|
-
const raw =
|
|
56662
|
+
const raw = readFileSync36(file2, "utf-8");
|
|
56378
56663
|
const parsed = JSON.parse(raw);
|
|
56379
56664
|
if (parsed && typeof parsed === "object" && parsed.dontAskAgain && typeof parsed.dontAskAgain === "object") {
|
|
56380
56665
|
const clean = {};
|
|
@@ -56389,7 +56674,7 @@ function getPluginPrefs() {
|
|
|
56389
56674
|
}
|
|
56390
56675
|
function writePluginPrefs(prefs) {
|
|
56391
56676
|
const file2 = getPluginPrefsPath();
|
|
56392
|
-
mkdirSync18(
|
|
56677
|
+
mkdirSync18(path63.dirname(file2), { recursive: true });
|
|
56393
56678
|
writeFileSync22(file2, JSON.stringify(prefs, null, 2), {
|
|
56394
56679
|
encoding: "utf-8",
|
|
56395
56680
|
mode: 384
|
|
@@ -56426,7 +56711,7 @@ __export(registry_exports, {
|
|
|
56426
56711
|
isBinaryOnPath: () => isBinaryOnPath
|
|
56427
56712
|
});
|
|
56428
56713
|
import { existsSync as existsSync44 } from "node:fs";
|
|
56429
|
-
import
|
|
56714
|
+
import path64 from "node:path";
|
|
56430
56715
|
function detectLocalBin(bin) {
|
|
56431
56716
|
return (cwd) => {
|
|
56432
56717
|
try {
|
|
@@ -56444,7 +56729,7 @@ function isBinaryOnPath(bin, opts = {}) {
|
|
|
56444
56729
|
const platform = opts.platform ?? process.platform;
|
|
56445
56730
|
const exists = opts.exists ?? existsSync44;
|
|
56446
56731
|
const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
|
|
56447
|
-
const pathMod = platform === "win32" ?
|
|
56732
|
+
const pathMod = platform === "win32" ? path64.win32 : path64.posix;
|
|
56448
56733
|
const sep4 = platform === "win32" ? ";" : ":";
|
|
56449
56734
|
const dirs = pathEnv.split(sep4).filter((d) => d.length > 0);
|
|
56450
56735
|
const candidates = [bin];
|
|
@@ -57176,7 +57461,7 @@ __export(atMentions_exports, {
|
|
|
57176
57461
|
extractAtMentions: () => extractAtMentions,
|
|
57177
57462
|
hasAtMentions: () => hasAtMentions
|
|
57178
57463
|
});
|
|
57179
|
-
import { existsSync as existsSync47, readFileSync as
|
|
57464
|
+
import { existsSync as existsSync47, readFileSync as readFileSync38, statSync as statSync9 } from "node:fs";
|
|
57180
57465
|
import { basename as basename4, isAbsolute as isAbsolute4, relative as relative5, resolve as resolve5, sep as sep2 } from "node:path";
|
|
57181
57466
|
function isImagePath(abs) {
|
|
57182
57467
|
const ext = abs.split(".").pop()?.toLowerCase() ?? "";
|
|
@@ -57282,7 +57567,7 @@ function resolveMention(token, cwd) {
|
|
|
57282
57567
|
note: `image too large (${Math.round(st.size / 1024)} KB) \u2014 path only`
|
|
57283
57568
|
};
|
|
57284
57569
|
}
|
|
57285
|
-
const dataBase64 =
|
|
57570
|
+
const dataBase64 = readFileSync38(abs).toString("base64");
|
|
57286
57571
|
return {
|
|
57287
57572
|
raw: token,
|
|
57288
57573
|
path: rel2,
|
|
@@ -57293,7 +57578,7 @@ function resolveMention(token, cwd) {
|
|
|
57293
57578
|
};
|
|
57294
57579
|
}
|
|
57295
57580
|
try {
|
|
57296
|
-
const buf =
|
|
57581
|
+
const buf = readFileSync38(abs);
|
|
57297
57582
|
const head = buf.subarray(0, 800).toString("utf8");
|
|
57298
57583
|
if (!isProbablyText(abs, head)) {
|
|
57299
57584
|
return {
|
|
@@ -58278,9 +58563,9 @@ __export(triggerLock_exports, {
|
|
|
58278
58563
|
releaseLock: () => releaseLock
|
|
58279
58564
|
});
|
|
58280
58565
|
import { promises as fs40 } from "node:fs";
|
|
58281
|
-
import * as
|
|
58566
|
+
import * as path69 from "node:path";
|
|
58282
58567
|
function lockPath(projectRoot) {
|
|
58283
|
-
return
|
|
58568
|
+
return path69.join(projectRoot, ".zelari", "trigger.lock");
|
|
58284
58569
|
}
|
|
58285
58570
|
function isPidAlive(pid) {
|
|
58286
58571
|
try {
|
|
@@ -58293,7 +58578,7 @@ function isPidAlive(pid) {
|
|
|
58293
58578
|
}
|
|
58294
58579
|
async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
|
|
58295
58580
|
const lp = lockPath(projectRoot);
|
|
58296
|
-
const dir =
|
|
58581
|
+
const dir = path69.dirname(lp);
|
|
58297
58582
|
await fs40.mkdir(dir, { recursive: true });
|
|
58298
58583
|
try {
|
|
58299
58584
|
const raw = await fs40.readFile(lp, "utf8");
|
|
@@ -58721,12 +59006,12 @@ import {
|
|
|
58721
59006
|
existsSync as existsSync49,
|
|
58722
59007
|
mkdirSync as mkdirSync21,
|
|
58723
59008
|
readdirSync as readdirSync10,
|
|
58724
|
-
readFileSync as
|
|
59009
|
+
readFileSync as readFileSync39,
|
|
58725
59010
|
rmSync as rmSync4,
|
|
58726
59011
|
writeFileSync as writeFileSync24
|
|
58727
59012
|
} from "node:fs";
|
|
58728
59013
|
import { dirname as dirname13, join as join45 } from "node:path";
|
|
58729
|
-
import { homedir as
|
|
59014
|
+
import { homedir as homedir13 } from "node:os";
|
|
58730
59015
|
function ensureBuiltinSkillsLoadedSync() {
|
|
58731
59016
|
if (builtinsLoaded) return;
|
|
58732
59017
|
for (const spec of BUILTIN_SKILL_MODULES) {
|
|
@@ -58737,7 +59022,7 @@ function ensureBuiltinSkillsLoadedSync() {
|
|
|
58737
59022
|
}
|
|
58738
59023
|
}
|
|
58739
59024
|
function getUserSkillsDir() {
|
|
58740
|
-
return join45(
|
|
59025
|
+
return join45(homedir13(), ".zelari-code", "skills");
|
|
58741
59026
|
}
|
|
58742
59027
|
function getProjectSkillsDir(projectRoot) {
|
|
58743
59028
|
return join45(projectRoot, ".zelari", "skills");
|
|
@@ -58803,7 +59088,7 @@ function scanSkillsDir(dir, projectRoot, seen, out) {
|
|
|
58803
59088
|
const skillPath = skillFilePath(dir, entry);
|
|
58804
59089
|
if (!existsSync49(skillPath)) continue;
|
|
58805
59090
|
try {
|
|
58806
|
-
const parsed = parseSkillMd(
|
|
59091
|
+
const parsed = parseSkillMd(readFileSync39(skillPath, "utf8"), skillPath);
|
|
58807
59092
|
if (!parsed) continue;
|
|
58808
59093
|
if (seen.has(parsed.name)) continue;
|
|
58809
59094
|
seen.add(parsed.name);
|
|
@@ -58887,7 +59172,7 @@ function upsertSkill(opts) {
|
|
|
58887
59172
|
}
|
|
58888
59173
|
dir = getProjectSkillsDir(root);
|
|
58889
59174
|
}
|
|
58890
|
-
const
|
|
59175
|
+
const path74 = skillFilePath(dir, name);
|
|
58891
59176
|
const content = serializeSkillMd({
|
|
58892
59177
|
name,
|
|
58893
59178
|
description,
|
|
@@ -58896,13 +59181,13 @@ function upsertSkill(opts) {
|
|
|
58896
59181
|
tools: opts.tools,
|
|
58897
59182
|
cost: opts.cost
|
|
58898
59183
|
});
|
|
58899
|
-
const parsed = parseSkillMd(content,
|
|
59184
|
+
const parsed = parseSkillMd(content, path74);
|
|
58900
59185
|
if (!parsed) {
|
|
58901
59186
|
return { ok: false, error: "Generated SKILL.md failed validation" };
|
|
58902
59187
|
}
|
|
58903
|
-
mkdirSync21(dirname13(
|
|
58904
|
-
writeFileSync24(
|
|
58905
|
-
return { ok: true, path:
|
|
59188
|
+
mkdirSync21(dirname13(path74), { recursive: true });
|
|
59189
|
+
writeFileSync24(path74, content, "utf8");
|
|
59190
|
+
return { ok: true, path: path74 };
|
|
58906
59191
|
}
|
|
58907
59192
|
function removeSkill(opts) {
|
|
58908
59193
|
const name = opts.name.trim().toLowerCase();
|
|
@@ -58920,8 +59205,8 @@ function removeSkill(opts) {
|
|
|
58920
59205
|
dir = getProjectSkillsDir(root);
|
|
58921
59206
|
}
|
|
58922
59207
|
const skillDir = join45(dir, name);
|
|
58923
|
-
const
|
|
58924
|
-
if (!existsSync49(
|
|
59208
|
+
const path74 = skillFilePath(dir, name);
|
|
59209
|
+
if (!existsSync49(path74) && !existsSync49(skillDir)) {
|
|
58925
59210
|
return { ok: false, error: `Skill "${name}" not found in ${dir}` };
|
|
58926
59211
|
}
|
|
58927
59212
|
try {
|
|
@@ -58932,7 +59217,7 @@ function removeSkill(opts) {
|
|
|
58932
59217
|
error: err instanceof Error ? err.message : String(err)
|
|
58933
59218
|
};
|
|
58934
59219
|
}
|
|
58935
|
-
return { ok: true, path:
|
|
59220
|
+
return { ok: true, path: path74 };
|
|
58936
59221
|
}
|
|
58937
59222
|
var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
|
|
58938
59223
|
var init_skillConfigIo = __esm({
|
|
@@ -59051,7 +59336,7 @@ var init_jsonApi = __esm({
|
|
|
59051
59336
|
});
|
|
59052
59337
|
|
|
59053
59338
|
// src/cli/memory/mcpAdapter.ts
|
|
59054
|
-
import * as
|
|
59339
|
+
import * as path71 from "node:path";
|
|
59055
59340
|
var id2, projectId, source, SearchSchema, AddSchema, LinkSchema, RetractSchema, MEMORY_MCP_TOOLS, MemoryMcpAdapter;
|
|
59056
59341
|
var init_mcpAdapter = __esm({
|
|
59057
59342
|
"src/cli/memory/mcpAdapter.ts"() {
|
|
@@ -59221,8 +59506,8 @@ var init_mcpAdapter = __esm({
|
|
|
59221
59506
|
this.takeWrite();
|
|
59222
59507
|
const externalFile = args.source?.file;
|
|
59223
59508
|
if (externalFile) {
|
|
59224
|
-
const normalized =
|
|
59225
|
-
if (
|
|
59509
|
+
const normalized = path71.normalize(externalFile);
|
|
59510
|
+
if (path71.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path71.sep}`)) {
|
|
59226
59511
|
throw new Error("source.file must be project-relative and cannot escape the project");
|
|
59227
59512
|
}
|
|
59228
59513
|
}
|
|
@@ -59728,14 +60013,14 @@ var init_permissionCli = __esm({
|
|
|
59728
60013
|
import {
|
|
59729
60014
|
existsSync as existsSync50,
|
|
59730
60015
|
mkdirSync as mkdirSync22,
|
|
59731
|
-
readFileSync as
|
|
60016
|
+
readFileSync as readFileSync40,
|
|
59732
60017
|
writeFileSync as writeFileSync25
|
|
59733
60018
|
} from "node:fs";
|
|
59734
60019
|
import { join as join46 } from "node:path";
|
|
59735
|
-
import { homedir as
|
|
60020
|
+
import { homedir as homedir14 } from "node:os";
|
|
59736
60021
|
import { createHash as createHash20, randomBytes as randomBytes6, timingSafeEqual } from "node:crypto";
|
|
59737
60022
|
function getZelariHome() {
|
|
59738
|
-
return join46(
|
|
60023
|
+
return join46(homedir14(), ".zelari-code");
|
|
59739
60024
|
}
|
|
59740
60025
|
function getCompanionConfigPath() {
|
|
59741
60026
|
return join46(getZelariHome(), "companion.json");
|
|
@@ -59750,12 +60035,12 @@ function ensureHome() {
|
|
|
59750
60035
|
}
|
|
59751
60036
|
}
|
|
59752
60037
|
function loadCompanionConfig() {
|
|
59753
|
-
const
|
|
59754
|
-
if (!existsSync50(
|
|
60038
|
+
const path74 = getCompanionConfigPath();
|
|
60039
|
+
if (!existsSync50(path74)) {
|
|
59755
60040
|
return { projects: [] };
|
|
59756
60041
|
}
|
|
59757
60042
|
try {
|
|
59758
|
-
const raw = JSON.parse(
|
|
60043
|
+
const raw = JSON.parse(readFileSync40(path74, "utf8"));
|
|
59759
60044
|
const projects = Array.isArray(raw.projects) ? raw.projects.filter(
|
|
59760
60045
|
(p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
|
|
59761
60046
|
).map((p3) => ({
|
|
@@ -59793,16 +60078,16 @@ function loadOrCreateToken(explicit) {
|
|
|
59793
60078
|
return { token: explicit.trim(), created: false };
|
|
59794
60079
|
}
|
|
59795
60080
|
ensureHome();
|
|
59796
|
-
const
|
|
59797
|
-
if (existsSync50(
|
|
59798
|
-
const t =
|
|
60081
|
+
const path74 = getCompanionTokenPath();
|
|
60082
|
+
if (existsSync50(path74)) {
|
|
60083
|
+
const t = readFileSync40(path74, "utf8").trim();
|
|
59799
60084
|
if (t) return { token: t, created: false };
|
|
59800
60085
|
}
|
|
59801
60086
|
const token = randomBytes6(24).toString("base64url");
|
|
59802
|
-
writeFileSync25(
|
|
60087
|
+
writeFileSync25(path74, token + "\n", "utf8");
|
|
59803
60088
|
try {
|
|
59804
60089
|
const fs42 = __require("node:fs");
|
|
59805
|
-
fs42.chmodSync?.(
|
|
60090
|
+
fs42.chmodSync?.(path74, 384);
|
|
59806
60091
|
} catch {
|
|
59807
60092
|
}
|
|
59808
60093
|
return { token, created: true };
|
|
@@ -59827,17 +60112,17 @@ function mergeProjects(cfg, extraPaths) {
|
|
|
59827
60112
|
byId.set(p3.id, p3);
|
|
59828
60113
|
}
|
|
59829
60114
|
for (const raw of extraPaths) {
|
|
59830
|
-
const
|
|
59831
|
-
if (!
|
|
59832
|
-
let id3 = slugFromPath(
|
|
60115
|
+
const path74 = raw.trim();
|
|
60116
|
+
if (!path74) continue;
|
|
60117
|
+
let id3 = slugFromPath(path74);
|
|
59833
60118
|
let n = 2;
|
|
59834
|
-
while (byId.has(id3) && byId.get(id3).path !==
|
|
59835
|
-
id3 = `${slugFromPath(
|
|
60119
|
+
while (byId.has(id3) && byId.get(id3).path !== path74) {
|
|
60120
|
+
id3 = `${slugFromPath(path74)}-${n++}`;
|
|
59836
60121
|
}
|
|
59837
60122
|
byId.set(id3, {
|
|
59838
60123
|
id: id3,
|
|
59839
|
-
name: slugFromPath(
|
|
59840
|
-
path:
|
|
60124
|
+
name: slugFromPath(path74),
|
|
60125
|
+
path: path74
|
|
59841
60126
|
});
|
|
59842
60127
|
}
|
|
59843
60128
|
return [...byId.values()];
|
|
@@ -60214,9 +60499,9 @@ async function runCompanionServe(opts = {}) {
|
|
|
60214
60499
|
return;
|
|
60215
60500
|
}
|
|
60216
60501
|
const url2 = parseUrl(req);
|
|
60217
|
-
const
|
|
60502
|
+
const path74 = url2.pathname.replace(/\/+$/, "") || "/";
|
|
60218
60503
|
try {
|
|
60219
|
-
if (req.method === "GET" && (
|
|
60504
|
+
if (req.method === "GET" && (path74 === "/health" || path74 === "/v1/health")) {
|
|
60220
60505
|
sendJson2(res, 200, {
|
|
60221
60506
|
ok: true,
|
|
60222
60507
|
service: "zelari-companion",
|
|
@@ -60228,18 +60513,18 @@ async function runCompanionServe(opts = {}) {
|
|
|
60228
60513
|
});
|
|
60229
60514
|
return;
|
|
60230
60515
|
}
|
|
60231
|
-
if (
|
|
60516
|
+
if (path74.startsWith("/v1")) {
|
|
60232
60517
|
if (!tokenMatches(token, getBearer(req))) {
|
|
60233
60518
|
sendJson2(res, 401, { ok: false, error: "unauthorized" });
|
|
60234
60519
|
return;
|
|
60235
60520
|
}
|
|
60236
60521
|
}
|
|
60237
|
-
if (req.method === "GET" &&
|
|
60522
|
+
if (req.method === "GET" && path74 === "/v1/config") {
|
|
60238
60523
|
const snap = buildDesktopConfigSnapshot();
|
|
60239
60524
|
sendJson2(res, 200, { ok: true, ...snap });
|
|
60240
60525
|
return;
|
|
60241
60526
|
}
|
|
60242
|
-
if (req.method === "GET" &&
|
|
60527
|
+
if (req.method === "GET" && path74 === "/v1/projects") {
|
|
60243
60528
|
sendJson2(res, 200, {
|
|
60244
60529
|
ok: true,
|
|
60245
60530
|
projects: projects.map((p3) => ({
|
|
@@ -60250,7 +60535,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
60250
60535
|
});
|
|
60251
60536
|
return;
|
|
60252
60537
|
}
|
|
60253
|
-
if (req.method === "GET" &&
|
|
60538
|
+
if (req.method === "GET" && path74 === "/v1/runs") {
|
|
60254
60539
|
sendJson2(res, 200, {
|
|
60255
60540
|
ok: true,
|
|
60256
60541
|
active: runs.getActive(),
|
|
@@ -60268,7 +60553,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
60268
60553
|
});
|
|
60269
60554
|
return;
|
|
60270
60555
|
}
|
|
60271
|
-
if (req.method === "POST" &&
|
|
60556
|
+
if (req.method === "POST" && path74 === "/v1/runs") {
|
|
60272
60557
|
const raw = await readBody(req);
|
|
60273
60558
|
let body = {};
|
|
60274
60559
|
try {
|
|
@@ -60315,7 +60600,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
60315
60600
|
});
|
|
60316
60601
|
return;
|
|
60317
60602
|
}
|
|
60318
|
-
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(
|
|
60603
|
+
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path74);
|
|
60319
60604
|
if (req.method === "GET" && eventsMatch) {
|
|
60320
60605
|
const runId = eventsMatch[1];
|
|
60321
60606
|
const run = runs.getRun(runId);
|
|
@@ -60380,7 +60665,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
60380
60665
|
}, 500);
|
|
60381
60666
|
return;
|
|
60382
60667
|
}
|
|
60383
|
-
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(
|
|
60668
|
+
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path74);
|
|
60384
60669
|
if (req.method === "POST" && cancelMatch) {
|
|
60385
60670
|
const runId = cancelMatch[1];
|
|
60386
60671
|
const result = runs.cancel(runId);
|
|
@@ -60530,26 +60815,26 @@ __export(doctor_exports, {
|
|
|
60530
60815
|
runDoctor: () => runDoctor
|
|
60531
60816
|
});
|
|
60532
60817
|
import { execSync as execSync2 } from "node:child_process";
|
|
60533
|
-
import { existsSync as existsSync52, readFileSync as
|
|
60818
|
+
import { existsSync as existsSync52, readFileSync as readFileSync41, readlinkSync, statSync as statSync10 } from "node:fs";
|
|
60534
60819
|
import { createRequire as createRequire3 } from "node:module";
|
|
60535
60820
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
60536
|
-
import
|
|
60821
|
+
import path72 from "node:path";
|
|
60537
60822
|
function findPackageRoot(start) {
|
|
60538
60823
|
let dir = start;
|
|
60539
60824
|
for (let i = 0; i < 6; i += 1) {
|
|
60540
|
-
const candidate =
|
|
60825
|
+
const candidate = path72.join(dir, "package.json");
|
|
60541
60826
|
if (existsSync52(candidate)) {
|
|
60542
60827
|
try {
|
|
60543
|
-
const pkg = JSON.parse(
|
|
60828
|
+
const pkg = JSON.parse(readFileSync41(candidate, "utf8"));
|
|
60544
60829
|
if (pkg.name === "zelari-code") return dir;
|
|
60545
60830
|
} catch {
|
|
60546
60831
|
}
|
|
60547
60832
|
}
|
|
60548
|
-
const parent =
|
|
60833
|
+
const parent = path72.dirname(dir);
|
|
60549
60834
|
if (parent === dir) break;
|
|
60550
60835
|
dir = parent;
|
|
60551
60836
|
}
|
|
60552
|
-
return
|
|
60837
|
+
return path72.resolve(__dirname3, "..", "..", "..");
|
|
60553
60838
|
}
|
|
60554
60839
|
function tryExec(cmd) {
|
|
60555
60840
|
try {
|
|
@@ -60563,8 +60848,8 @@ function tryExec(cmd) {
|
|
|
60563
60848
|
}
|
|
60564
60849
|
function readPackageJson3() {
|
|
60565
60850
|
try {
|
|
60566
|
-
const pkgPath =
|
|
60567
|
-
return JSON.parse(
|
|
60851
|
+
const pkgPath = path72.join(packageRoot, "package.json");
|
|
60852
|
+
return JSON.parse(readFileSync41(pkgPath, "utf8"));
|
|
60568
60853
|
} catch {
|
|
60569
60854
|
return null;
|
|
60570
60855
|
}
|
|
@@ -60579,7 +60864,7 @@ function checkShim(pkgName) {
|
|
|
60579
60864
|
}
|
|
60580
60865
|
const isWin = process.platform === "win32";
|
|
60581
60866
|
const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
|
|
60582
|
-
const shimPath =
|
|
60867
|
+
const shimPath = path72.join(prefix, shimName);
|
|
60583
60868
|
if (!existsSync52(shimPath)) {
|
|
60584
60869
|
return FAIL(
|
|
60585
60870
|
`shim not found at ${shimPath}
|
|
@@ -60589,7 +60874,7 @@ function checkShim(pkgName) {
|
|
|
60589
60874
|
try {
|
|
60590
60875
|
const st = statSync10(shimPath);
|
|
60591
60876
|
if (isWin) {
|
|
60592
|
-
const content =
|
|
60877
|
+
const content = readFileSync41(shimPath, "utf8");
|
|
60593
60878
|
if (content.includes(`${pkgName}\\bin\\`) || content.includes(`${pkgName}/bin/`)) {
|
|
60594
60879
|
return OK(`shim OK at ${shimPath} (${st.size} bytes)`);
|
|
60595
60880
|
}
|
|
@@ -60607,8 +60892,8 @@ function checkShim(pkgName) {
|
|
|
60607
60892
|
fix: npm install -g ${pkgName}@latest --force`
|
|
60608
60893
|
);
|
|
60609
60894
|
}
|
|
60610
|
-
const resolved =
|
|
60611
|
-
const expected =
|
|
60895
|
+
const resolved = path72.resolve(path72.dirname(shimPath), target);
|
|
60896
|
+
const expected = path72.join(
|
|
60612
60897
|
prefix,
|
|
60613
60898
|
"node_modules",
|
|
60614
60899
|
pkgName,
|
|
@@ -60647,7 +60932,7 @@ function checkNode(pkg) {
|
|
|
60647
60932
|
return OK(`node ${raw}`);
|
|
60648
60933
|
}
|
|
60649
60934
|
function checkBundle() {
|
|
60650
|
-
const bundle =
|
|
60935
|
+
const bundle = path72.join(packageRoot, "dist", "cli", "main.bundled.js");
|
|
60651
60936
|
if (!existsSync52(bundle)) {
|
|
60652
60937
|
return FAIL(
|
|
60653
60938
|
`dist/cli/main.bundled.js missing at ${bundle}
|
|
@@ -60668,7 +60953,7 @@ function checkRuntimeDeps() {
|
|
|
60668
60953
|
const missing = [];
|
|
60669
60954
|
for (const dep of required2) {
|
|
60670
60955
|
try {
|
|
60671
|
-
const localReq = createRequire3(
|
|
60956
|
+
const localReq = createRequire3(path72.join(packageRoot, "package.json"));
|
|
60672
60957
|
localReq.resolve(dep);
|
|
60673
60958
|
} catch {
|
|
60674
60959
|
missing.push(dep);
|
|
@@ -60868,7 +61153,7 @@ var init_doctor = __esm({
|
|
|
60868
61153
|
init_metrics3();
|
|
60869
61154
|
init_contextGrowthSummary();
|
|
60870
61155
|
require3 = createRequire3(import.meta.url);
|
|
60871
|
-
__dirname3 =
|
|
61156
|
+
__dirname3 = path72.dirname(fileURLToPath3(import.meta.url));
|
|
60872
61157
|
packageRoot = findPackageRoot(__dirname3);
|
|
60873
61158
|
OK = (message) => ({
|
|
60874
61159
|
ok: true,
|
|
@@ -61052,15 +61337,15 @@ __export(inspect_exports, {
|
|
|
61052
61337
|
collectInspectReport: () => collectInspectReport,
|
|
61053
61338
|
runInspect: () => runInspect
|
|
61054
61339
|
});
|
|
61055
|
-
import
|
|
61056
|
-
import { existsSync as existsSync53, readFileSync as
|
|
61057
|
-
import { homedir as
|
|
61340
|
+
import path73 from "node:path";
|
|
61341
|
+
import { existsSync as existsSync53, readFileSync as readFileSync42, readdirSync as readdirSync11 } from "node:fs";
|
|
61342
|
+
import { homedir as homedir15 } from "node:os";
|
|
61058
61343
|
async function collectInspectReport(cwd = process.cwd()) {
|
|
61059
61344
|
ensureBuiltinSkillsLoadedSync();
|
|
61060
61345
|
const snap = listSkillsSnapshot(cwd);
|
|
61061
61346
|
const mcp = listMcpServers(cwd);
|
|
61062
|
-
const userMcpPath =
|
|
61063
|
-
const projectMcpPath =
|
|
61347
|
+
const userMcpPath = path73.join(homedir15(), ".zelari-code", "mcp.json");
|
|
61348
|
+
const projectMcpPath = path73.join(cwd, ".zelari", "mcp.json");
|
|
61064
61349
|
const globalHooks = globalHooksDir();
|
|
61065
61350
|
const projectHooks = projectHooksDir(cwd);
|
|
61066
61351
|
const projectTrusted = isFolderTrusted(cwd);
|
|
@@ -61088,9 +61373,9 @@ async function collectInspectReport(cwd = process.cwd()) {
|
|
|
61088
61373
|
configSources: [
|
|
61089
61374
|
{ path: userMcpPath, exists: existsSync53(userMcpPath) },
|
|
61090
61375
|
{ path: projectMcpPath, exists: existsSync53(projectMcpPath) },
|
|
61091
|
-
{ path:
|
|
61092
|
-
{ path:
|
|
61093
|
-
{ path:
|
|
61376
|
+
{ path: path73.join(homedir15(), ".zelari-code", "provider.json"), exists: existsSync53(path73.join(homedir15(), ".zelari-code", "provider.json")) },
|
|
61377
|
+
{ path: path73.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync53(path73.join(cwd, ".zelari", "AGENTS.md")) },
|
|
61378
|
+
{ path: path73.join(cwd, "AGENTS.md"), exists: existsSync53(path73.join(cwd, "AGENTS.md")) }
|
|
61094
61379
|
],
|
|
61095
61380
|
skills: {
|
|
61096
61381
|
total: snap.skills.length,
|
|
@@ -61130,14 +61415,14 @@ function listJsonFiles(dir) {
|
|
|
61130
61415
|
}
|
|
61131
61416
|
function findAgentsMd(cwd) {
|
|
61132
61417
|
const candidates = [
|
|
61133
|
-
|
|
61134
|
-
|
|
61418
|
+
path73.join(cwd, "AGENTS.md"),
|
|
61419
|
+
path73.join(cwd, ".zelari", "AGENTS.md")
|
|
61135
61420
|
];
|
|
61136
61421
|
const found = [];
|
|
61137
61422
|
for (const c of candidates) {
|
|
61138
61423
|
if (existsSync53(c)) {
|
|
61139
61424
|
try {
|
|
61140
|
-
const text =
|
|
61425
|
+
const text = readFileSync42(c, "utf8");
|
|
61141
61426
|
found.push(`${c} (${text.length} bytes)`);
|
|
61142
61427
|
} catch {
|
|
61143
61428
|
found.push(`${c} (unreadable)`);
|
|
@@ -64431,10 +64716,11 @@ import { createHash as createHash14 } from "node:crypto";
|
|
|
64431
64716
|
init_runtime2();
|
|
64432
64717
|
init_verification2();
|
|
64433
64718
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
64434
|
-
import
|
|
64719
|
+
import path43 from "node:path";
|
|
64435
64720
|
function nativePackEnabled(env = process.env) {
|
|
64436
64721
|
const v = env.ZELARI_VERIFY_PACK?.toLowerCase();
|
|
64437
|
-
|
|
64722
|
+
if (v === "0" || v === "off" || v === "false") return false;
|
|
64723
|
+
return true;
|
|
64438
64724
|
}
|
|
64439
64725
|
function resolvePackCommands(env, scripts) {
|
|
64440
64726
|
const pick2 = (override, scriptName) => {
|
|
@@ -64458,7 +64744,7 @@ function packTimeoutMs(env = process.env) {
|
|
|
64458
64744
|
}
|
|
64459
64745
|
async function readPackageScripts(cwd = process.cwd()) {
|
|
64460
64746
|
try {
|
|
64461
|
-
const raw = await readFile3(
|
|
64747
|
+
const raw = await readFile3(path43.join(cwd, "package.json"), "utf-8");
|
|
64462
64748
|
const parsed = JSON.parse(raw);
|
|
64463
64749
|
if (parsed && typeof parsed === "object" && typeof parsed.scripts === "object") {
|
|
64464
64750
|
return parsed.scripts;
|
|
@@ -64497,7 +64783,8 @@ function strictDoneEnabled(surface = "kraken") {
|
|
|
64497
64783
|
return true;
|
|
64498
64784
|
}
|
|
64499
64785
|
const v = process.env.ZELARI_STRICT_DONE;
|
|
64500
|
-
|
|
64786
|
+
if (v === "0" || v === "false") return false;
|
|
64787
|
+
return true;
|
|
64501
64788
|
}
|
|
64502
64789
|
function criterionId(check2, index) {
|
|
64503
64790
|
const slug = check2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
@@ -64734,6 +65021,145 @@ function strictGateEventPayload(evaluation) {
|
|
|
64734
65021
|
};
|
|
64735
65022
|
}
|
|
64736
65023
|
|
|
65024
|
+
// src/cli/kraken/completionProof.ts
|
|
65025
|
+
import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
|
|
65026
|
+
import path44 from "node:path";
|
|
65027
|
+
function verdictOf(evaluation) {
|
|
65028
|
+
return evaluation.evaluation?.verdict ?? (evaluation.blocked ? "BLOCKED" : "PASS");
|
|
65029
|
+
}
|
|
65030
|
+
function cell(text, max = 200) {
|
|
65031
|
+
const flat = text.replace(/\r?\n/g, " ").replace(/\|/g, "\\|").trim();
|
|
65032
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
|
|
65033
|
+
}
|
|
65034
|
+
function evidenceCell(result) {
|
|
65035
|
+
if (!result || result.evidence.length === 0) return "\u2014";
|
|
65036
|
+
return result.evidence.map((e) => {
|
|
65037
|
+
const parts = [e.tier];
|
|
65038
|
+
if (e.seq !== void 0) parts.push(`seq ${e.seq}`);
|
|
65039
|
+
if (e.digest) parts.push(`digest ${e.digest.slice(0, 8)}\u2026`);
|
|
65040
|
+
return parts.join(" \xB7 ");
|
|
65041
|
+
}).join("; ");
|
|
65042
|
+
}
|
|
65043
|
+
function proofRows(evaluation) {
|
|
65044
|
+
const nativeById = new Map(
|
|
65045
|
+
(evaluation.native?.criteria ?? []).map((c) => [c.id, c])
|
|
65046
|
+
);
|
|
65047
|
+
const rows = /* @__PURE__ */ new Map();
|
|
65048
|
+
for (const result of evaluation.results ?? []) {
|
|
65049
|
+
const criterion = nativeById.get(result.criterionId);
|
|
65050
|
+
rows.set(result.criterionId, {
|
|
65051
|
+
id: result.criterionId,
|
|
65052
|
+
text: criterion?.text ?? null,
|
|
65053
|
+
required: criterion ? criterion.required : true,
|
|
65054
|
+
status: result.status,
|
|
65055
|
+
result
|
|
65056
|
+
});
|
|
65057
|
+
}
|
|
65058
|
+
for (const unsatisfied of evaluation.evaluation?.unsatisfied ?? []) {
|
|
65059
|
+
if (rows.has(unsatisfied.id)) continue;
|
|
65060
|
+
const criterion = nativeById.get(unsatisfied.id);
|
|
65061
|
+
rows.set(unsatisfied.id, {
|
|
65062
|
+
id: unsatisfied.id,
|
|
65063
|
+
text: criterion?.text ?? null,
|
|
65064
|
+
required: true,
|
|
65065
|
+
// satisfied/unsatisfied lists cover required criteria only
|
|
65066
|
+
status: unsatisfied.status,
|
|
65067
|
+
result: null
|
|
65068
|
+
});
|
|
65069
|
+
}
|
|
65070
|
+
return [...rows.values()];
|
|
65071
|
+
}
|
|
65072
|
+
function renderMarkdown(evaluation, meta3) {
|
|
65073
|
+
const lines = [
|
|
65074
|
+
"# Completion Proof",
|
|
65075
|
+
"",
|
|
65076
|
+
"Strict build-gate proof-of-work (ADR-0023). The machine-readable twin of",
|
|
65077
|
+
"this document \u2014 `completion-proof.json` \u2014 is the exact `verification.run`",
|
|
65078
|
+
"payload sent to the session spine.",
|
|
65079
|
+
"",
|
|
65080
|
+
`- **Verdict**: **${verdictOf(evaluation)}**`,
|
|
65081
|
+
`- **Strict gate**: ${evaluation.strict ? "on" : "off"}`,
|
|
65082
|
+
`- **Turn blocked**: ${evaluation.blocked ? "yes" : "no"}`,
|
|
65083
|
+
`- **Summary**: ${cell(evaluation.summary, 400)}`,
|
|
65084
|
+
`- **Legacy selection gate**: ${evaluation.gate.passed}/${evaluation.gate.total} passed` + (evaluation.gate.failedChecks.length > 0 ? `; failed: ${evaluation.gate.failedChecks.length}` : "") + (evaluation.gate.unknownChecks.length > 0 ? `; unknown: ${evaluation.gate.unknownChecks.length}` : "")
|
|
65085
|
+
];
|
|
65086
|
+
if (meta3.surface) lines.push(`- **Surface**: ${meta3.surface}`);
|
|
65087
|
+
if (meta3.sessionId) lines.push(`- **Session**: ${meta3.sessionId} (session spine)`);
|
|
65088
|
+
if (meta3.generatedAt !== void 0) {
|
|
65089
|
+
lines.push(`- **Generated**: ${new Date(meta3.generatedAt).toISOString()}`);
|
|
65090
|
+
}
|
|
65091
|
+
const rows = proofRows(evaluation);
|
|
65092
|
+
lines.push("", "## Criteria", "", "| Criterion | Required | Status | Evidence |", "| --- | --- | --- | --- |");
|
|
65093
|
+
if (rows.length === 0) {
|
|
65094
|
+
lines.push("| _none \u2014 no criteria joined this evaluation_ | \u2014 | \u2014 | \u2014 |");
|
|
65095
|
+
}
|
|
65096
|
+
for (const row of rows) {
|
|
65097
|
+
const label = row.text ? `\`${row.id}\` \u2014 ${cell(row.text)}` : `\`${row.id}\``;
|
|
65098
|
+
lines.push(`| ${label} | ${row.required ? "yes" : "no"} | ${row.status} | ${evidenceCell(row.result)} |`);
|
|
65099
|
+
}
|
|
65100
|
+
const unsatisfied = evaluation.evaluation?.unsatisfied ?? [];
|
|
65101
|
+
if (unsatisfied.length > 0) {
|
|
65102
|
+
lines.push("", "### Unsatisfied", "");
|
|
65103
|
+
for (const u of unsatisfied) lines.push(`- \`${u.id}\`: **${u.status}** \u2014 ${cell(u.reason, 300)}`);
|
|
65104
|
+
}
|
|
65105
|
+
const native = evaluation.native;
|
|
65106
|
+
if (native) {
|
|
65107
|
+
lines.push(
|
|
65108
|
+
"",
|
|
65109
|
+
`## Native criteria pack \u2014 ${native.packId}`,
|
|
65110
|
+
"",
|
|
65111
|
+
"| Criterion | Command | Status | Detail |",
|
|
65112
|
+
"| --- | --- | --- | --- |"
|
|
65113
|
+
);
|
|
65114
|
+
for (const result of native.results) {
|
|
65115
|
+
const criterion = native.criteria.find((c) => c.id === result.criterionId);
|
|
65116
|
+
const check2 = criterion?.check;
|
|
65117
|
+
const command = check2?.kind === "command" ? check2.command : "\u2014";
|
|
65118
|
+
const label = criterion?.text ? `\`${result.criterionId}\` \u2014 ${cell(criterion.text, 120)}` : `\`${result.criterionId}\``;
|
|
65119
|
+
lines.push(`| ${label} | \`${cell(command, 120)}\` | ${result.status} | ${cell(result.detail ?? "\u2014")} |`);
|
|
65120
|
+
}
|
|
65121
|
+
}
|
|
65122
|
+
const review = evaluation.review;
|
|
65123
|
+
if (review) {
|
|
65124
|
+
lines.push(
|
|
65125
|
+
"",
|
|
65126
|
+
"## Advisory verifier review",
|
|
65127
|
+
"",
|
|
65128
|
+
"_Advisory only \u2014 this review cannot change the gate verdict above._",
|
|
65129
|
+
"",
|
|
65130
|
+
`- **Verdict**: ${review.verdict}`
|
|
65131
|
+
);
|
|
65132
|
+
if (review.score !== void 0) lines.push(`- **Score**: ${review.score}`);
|
|
65133
|
+
const model = review.effectiveModel.model ?? review.effectiveModel.provider ?? review.effectiveModel.mode;
|
|
65134
|
+
lines.push(`- **Model**: ${model}${review.usedLogprobs ? " (logprobs)" : ""}`);
|
|
65135
|
+
if (review.fallback) lines.push(`- **Fallback**: ${review.fallback}`);
|
|
65136
|
+
if (review.rationale) lines.push(`- **Rationale**: ${cell(review.rationale, 400)}`);
|
|
65137
|
+
}
|
|
65138
|
+
lines.push("", "---", "", "Machine record: `completion-proof.json` (same directory).");
|
|
65139
|
+
return `${lines.join("\n")}
|
|
65140
|
+
`;
|
|
65141
|
+
}
|
|
65142
|
+
function renderCompletionProof(evaluation, meta3 = {}) {
|
|
65143
|
+
return {
|
|
65144
|
+
markdown: renderMarkdown(evaluation, meta3),
|
|
65145
|
+
json: JSON.stringify(strictGateEventPayload(evaluation), null, 2)
|
|
65146
|
+
};
|
|
65147
|
+
}
|
|
65148
|
+
async function writeCompletionProof(evaluation, options = {}) {
|
|
65149
|
+
try {
|
|
65150
|
+
const dir = path44.join(options.baseDir ?? process.cwd(), ".zelari");
|
|
65151
|
+
await mkdir2(dir, { recursive: true });
|
|
65152
|
+
const { markdown, json: json3 } = renderCompletionProof(evaluation, options.meta);
|
|
65153
|
+
const markdownPath = path44.join(dir, "completion-proof.md");
|
|
65154
|
+
const jsonPath = path44.join(dir, "completion-proof.json");
|
|
65155
|
+
await writeFile2(markdownPath, markdown, "utf8");
|
|
65156
|
+
await writeFile2(jsonPath, json3, "utf8");
|
|
65157
|
+
return { markdownPath, jsonPath };
|
|
65158
|
+
} catch {
|
|
65159
|
+
return null;
|
|
65160
|
+
}
|
|
65161
|
+
}
|
|
65162
|
+
|
|
64737
65163
|
// src/cli/hooks/permissionPicker.ts
|
|
64738
65164
|
init_toolPermissions();
|
|
64739
65165
|
|
|
@@ -65774,10 +66200,15 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
65774
66200
|
if (event.type === "agent_end") {
|
|
65775
66201
|
let krakenSuppressFinish = false;
|
|
65776
66202
|
const krakenSpineEmit = (input) => writerRef.current?.spine?.appendEvent(input) ?? Promise.resolve(null);
|
|
66203
|
+
const writeProofSafe2 = (gate) => writeCompletionProof(gate, { meta: { surface: "kraken", sessionId: sessionId2 } }).then(
|
|
66204
|
+
() => void 0,
|
|
66205
|
+
() => void 0
|
|
66206
|
+
);
|
|
65777
66207
|
if (event.reason === "completed" && !krakenRepairEnqueued && (isKrakenSelectionEnabled() || nativePackEnabled()) && workPhase === "build") {
|
|
65778
66208
|
const strictGate = await evaluateStrictBuildGate("build", { emit: krakenSpineEmit });
|
|
65779
66209
|
const krakenGate = strictGate.gate;
|
|
65780
66210
|
writerRef.current?.spine?.verificationRun(strictGateEventPayload(strictGate));
|
|
66211
|
+
await writeProofSafe2(strictGate);
|
|
65781
66212
|
if (krakenGate.blocked) {
|
|
65782
66213
|
krakenRepairEnqueued = true;
|
|
65783
66214
|
markRepairTriggered();
|
|
@@ -65791,10 +66222,13 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
65791
66222
|
krakenSuppressFinish = true;
|
|
65792
66223
|
}
|
|
65793
66224
|
}
|
|
65794
|
-
|
|
66225
|
+
const repairCheck = event.reason === "completed" && krakenRepairEnqueued ? await evaluateStrictBuildGate("build", { emit: krakenSpineEmit }) : null;
|
|
66226
|
+
if (repairCheck) await writeProofSafe2(repairCheck);
|
|
66227
|
+
if (repairCheck && !repairCheck.blocked) {
|
|
65795
66228
|
markRepairSucceeded();
|
|
65796
66229
|
} else if (event.reason === "completed" && krakenRepairEnqueued) {
|
|
65797
66230
|
const still = await evaluateStrictBuildGate("build", { emit: krakenSpineEmit });
|
|
66231
|
+
await writeProofSafe2(still);
|
|
65798
66232
|
if (still.blocked) {
|
|
65799
66233
|
appendSystem(
|
|
65800
66234
|
setMessages,
|
|
@@ -67910,7 +68344,7 @@ init_sessionManager();
|
|
|
67910
68344
|
// src/cli/gitOps.ts
|
|
67911
68345
|
import { execFile as execFile4 } from "node:child_process";
|
|
67912
68346
|
import { promisify as promisify3 } from "node:util";
|
|
67913
|
-
import
|
|
68347
|
+
import path55 from "node:path";
|
|
67914
68348
|
var execFileAsync3 = promisify3(execFile4);
|
|
67915
68349
|
async function git4(cwd, args) {
|
|
67916
68350
|
try {
|
|
@@ -67956,7 +68390,7 @@ async function undoWorkingChanges(opts = {}) {
|
|
|
67956
68390
|
};
|
|
67957
68391
|
}
|
|
67958
68392
|
function defaultProjectRoot() {
|
|
67959
|
-
return
|
|
68393
|
+
return path55.resolve(__dirname, "..", "..", "..");
|
|
67960
68394
|
}
|
|
67961
68395
|
|
|
67962
68396
|
// src/cli/slashHandlers/git.ts
|
|
@@ -68243,11 +68677,11 @@ function handleCacheStats(ctx) {
|
|
|
68243
68677
|
init_messageHelpers();
|
|
68244
68678
|
init_serviceFactory();
|
|
68245
68679
|
import { promises as fs30 } from "node:fs";
|
|
68246
|
-
import * as
|
|
68680
|
+
import * as path57 from "node:path";
|
|
68247
68681
|
|
|
68248
68682
|
// src/cli/memory/promotion.ts
|
|
68249
68683
|
import { promises as fs29 } from "node:fs";
|
|
68250
|
-
import * as
|
|
68684
|
+
import * as path56 from "node:path";
|
|
68251
68685
|
var START = "<!-- zelari:memory-promotions:start -->";
|
|
68252
68686
|
var END = "<!-- zelari:memory-promotions:end -->";
|
|
68253
68687
|
var DURABLE_KINDS = /* @__PURE__ */ new Set(["fact", "decision", "constraint", "preference", "procedure"]);
|
|
@@ -68258,13 +68692,13 @@ function lineFor(node) {
|
|
|
68258
68692
|
}
|
|
68259
68693
|
async function promoteMemoryToAgentsMd(projectRoot, node) {
|
|
68260
68694
|
if (node.status !== "active") {
|
|
68261
|
-
return { added: false, path:
|
|
68695
|
+
return { added: false, path: path56.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
|
|
68262
68696
|
}
|
|
68263
68697
|
if (!DURABLE_KINDS.has(node.kind)) {
|
|
68264
|
-
return { added: false, path:
|
|
68698
|
+
return { added: false, path: path56.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
|
|
68265
68699
|
}
|
|
68266
|
-
const root = await fs29.realpath(projectRoot).catch(() =>
|
|
68267
|
-
const target =
|
|
68700
|
+
const root = await fs29.realpath(projectRoot).catch(() => path56.resolve(projectRoot));
|
|
68701
|
+
const target = path56.join(root, "AGENTS.md");
|
|
68268
68702
|
try {
|
|
68269
68703
|
const stat2 = await fs29.lstat(target);
|
|
68270
68704
|
if (stat2.isSymbolicLink() || !stat2.isFile()) throw new Error("AGENTS.md must be a regular project file.");
|
|
@@ -68329,22 +68763,22 @@ function sourceLine(source2) {
|
|
|
68329
68763
|
return entries.length ? entries.map(([key, value]) => `${key}=${value}`).join(" \xB7 ") : "unknown";
|
|
68330
68764
|
}
|
|
68331
68765
|
function isInside(root, target) {
|
|
68332
|
-
const relative6 =
|
|
68333
|
-
return relative6 === "" || !relative6.startsWith("..") && !
|
|
68766
|
+
const relative6 = path57.relative(root, target);
|
|
68767
|
+
return relative6 === "" || !relative6.startsWith("..") && !path57.isAbsolute(relative6);
|
|
68334
68768
|
}
|
|
68335
68769
|
async function safeExportPath(cwd, requested) {
|
|
68336
|
-
const lexicalRoot =
|
|
68770
|
+
const lexicalRoot = path57.resolve(cwd);
|
|
68337
68771
|
const root = await fs30.realpath(lexicalRoot).catch(() => lexicalRoot);
|
|
68338
|
-
const fallback =
|
|
68339
|
-
const target = requested?.trim() ?
|
|
68772
|
+
const fallback = path57.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
|
|
68773
|
+
const target = requested?.trim() ? path57.resolve(root, requested.trim()) : fallback;
|
|
68340
68774
|
if (!isInside(root, target)) {
|
|
68341
68775
|
throw new Error("Export path must stay inside the active project.");
|
|
68342
68776
|
}
|
|
68343
|
-
const parent =
|
|
68344
|
-
const relativeParent =
|
|
68777
|
+
const parent = path57.dirname(target);
|
|
68778
|
+
const relativeParent = path57.relative(root, parent);
|
|
68345
68779
|
let cursor = root;
|
|
68346
|
-
for (const segment of relativeParent.split(
|
|
68347
|
-
cursor =
|
|
68780
|
+
for (const segment of relativeParent.split(path57.sep).filter(Boolean)) {
|
|
68781
|
+
cursor = path57.join(cursor, segment);
|
|
68348
68782
|
try {
|
|
68349
68783
|
const stat2 = await fs30.lstat(cursor);
|
|
68350
68784
|
if (stat2.isSymbolicLink()) {
|
|
@@ -68516,9 +68950,9 @@ ${message}` : message
|
|
|
68516
68950
|
}
|
|
68517
68951
|
case "export": {
|
|
68518
68952
|
const target = await safeExportPath(ctx.cwd, args.join(" ").trim() || void 0);
|
|
68519
|
-
await fs30.mkdir(
|
|
68520
|
-
const root = await fs30.realpath(ctx.cwd).catch(() =>
|
|
68521
|
-
const realParent = await fs30.realpath(
|
|
68953
|
+
await fs30.mkdir(path57.dirname(target), { recursive: true });
|
|
68954
|
+
const root = await fs30.realpath(ctx.cwd).catch(() => path57.resolve(ctx.cwd));
|
|
68955
|
+
const realParent = await fs30.realpath(path57.dirname(target));
|
|
68522
68956
|
if (!isInside(root, realParent)) {
|
|
68523
68957
|
throw new Error("Export path resolves outside the active project.");
|
|
68524
68958
|
}
|
|
@@ -68714,7 +69148,7 @@ import { promises as fs34 } from "node:fs";
|
|
|
68714
69148
|
init_zod();
|
|
68715
69149
|
init_taskTool();
|
|
68716
69150
|
import { promises as fs33 } from "node:fs";
|
|
68717
|
-
import
|
|
69151
|
+
import path61 from "node:path";
|
|
68718
69152
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
68719
69153
|
var CsvFanoutArgsSchema = external_exports.object({
|
|
68720
69154
|
csv_path: external_exports.string().min(1),
|
|
@@ -68808,8 +69242,8 @@ function resolveMaxConcurrency(env = process.env) {
|
|
|
68808
69242
|
}
|
|
68809
69243
|
async function runCsvFanout(args, deps, opts) {
|
|
68810
69244
|
const start = Date.now();
|
|
68811
|
-
const absCsv =
|
|
68812
|
-
const absOut =
|
|
69245
|
+
const absCsv = path61.isAbsolute(args.csv_path) ? args.csv_path : path61.join(opts.parentCwd, args.csv_path);
|
|
69246
|
+
const absOut = path61.isAbsolute(args.output_csv_path) ? args.output_csv_path : path61.join(opts.parentCwd, args.output_csv_path);
|
|
68813
69247
|
const { headers: headers2, rows } = await readCsv(absCsv);
|
|
68814
69248
|
if (headers2.length === 0) {
|
|
68815
69249
|
throw new Error(`kraken_csv_fanout: ${absCsv} is empty`);
|
|
@@ -68865,7 +69299,7 @@ async function runCsvFanout(args, deps, opts) {
|
|
|
68865
69299
|
errored += 1;
|
|
68866
69300
|
errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
|
|
68867
69301
|
}
|
|
68868
|
-
await fs33.mkdir(
|
|
69302
|
+
await fs33.mkdir(path61.dirname(absOut), { recursive: true });
|
|
68869
69303
|
await queueWrite(serializeCsv(outHeaders, outputRecords));
|
|
68870
69304
|
}
|
|
68871
69305
|
}
|
|
@@ -69060,7 +69494,7 @@ function splitArgs(s) {
|
|
|
69060
69494
|
// src/cli/slashHandlers/krakenWorkbench.ts
|
|
69061
69495
|
init_messageHelpers();
|
|
69062
69496
|
import { promises as fs35 } from "node:fs";
|
|
69063
|
-
import
|
|
69497
|
+
import path62 from "node:path";
|
|
69064
69498
|
|
|
69065
69499
|
// src/cli/kraken/workbenchView.ts
|
|
69066
69500
|
var EMPTY = {
|
|
@@ -69177,14 +69611,14 @@ function formatWorkbenchForTerminal(p3) {
|
|
|
69177
69611
|
|
|
69178
69612
|
// src/cli/slashHandlers/krakenWorkbench.ts
|
|
69179
69613
|
async function handleKrakenWorkbench(ctx) {
|
|
69180
|
-
const dir =
|
|
69614
|
+
const dir = path62.join(ctx.cwd, ".zelari", "radio");
|
|
69181
69615
|
let latest = null;
|
|
69182
69616
|
let latestMtime = 0;
|
|
69183
69617
|
try {
|
|
69184
69618
|
const files = await fs35.readdir(dir);
|
|
69185
69619
|
for (const f of files) {
|
|
69186
69620
|
if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
|
|
69187
|
-
const full =
|
|
69621
|
+
const full = path62.join(dir, f);
|
|
69188
69622
|
const stat2 = await fs35.stat(full);
|
|
69189
69623
|
if (stat2.mtimeMs > latestMtime) {
|
|
69190
69624
|
latestMtime = stat2.mtimeMs;
|
|
@@ -69201,10 +69635,10 @@ async function handleKrakenWorkbench(ctx) {
|
|
|
69201
69635
|
const parsed = parseWorkbench(content);
|
|
69202
69636
|
const rendered = formatWorkbenchForTerminal(parsed);
|
|
69203
69637
|
if (!rendered.trim()) {
|
|
69204
|
-
appendSystem(ctx.setMessages, `[kraken workbench] ${
|
|
69638
|
+
appendSystem(ctx.setMessages, `[kraken workbench] ${path62.basename(latest)}: (no nodes / no events yet)`);
|
|
69205
69639
|
return;
|
|
69206
69640
|
}
|
|
69207
|
-
appendSystem(ctx.setMessages, `[kraken workbench] ${
|
|
69641
|
+
appendSystem(ctx.setMessages, `[kraken workbench] ${path62.basename(latest)}:
|
|
69208
69642
|
${rendered}`);
|
|
69209
69643
|
}
|
|
69210
69644
|
|
|
@@ -69511,15 +69945,15 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
|
|
|
69511
69945
|
// src/cli/slashHandlers/promoteMember.ts
|
|
69512
69946
|
init_messageHelpers();
|
|
69513
69947
|
import { promises as fs36 } from "node:fs";
|
|
69514
|
-
import
|
|
69948
|
+
import path65 from "node:path";
|
|
69515
69949
|
import os12 from "node:os";
|
|
69516
69950
|
async function handlePromoteMember(ctx, memberId) {
|
|
69517
69951
|
try {
|
|
69518
69952
|
const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
69519
69953
|
const { skill, markdown } = promoteMember2(memberId);
|
|
69520
|
-
const skillDir = process.env.ANATHEMA_SKILL_DIR ??
|
|
69954
|
+
const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path65.join(os12.homedir(), ".tmp", "zelari-code", "skills");
|
|
69521
69955
|
await fs36.mkdir(skillDir, { recursive: true });
|
|
69522
|
-
const filePath =
|
|
69956
|
+
const filePath = path65.join(skillDir, `${skill.id}.md`);
|
|
69523
69957
|
await fs36.writeFile(filePath, markdown, "utf8");
|
|
69524
69958
|
appendSystem(
|
|
69525
69959
|
ctx.setMessages,
|
|
@@ -69536,25 +69970,25 @@ async function handlePromoteMember(ctx, memberId) {
|
|
|
69536
69970
|
}
|
|
69537
69971
|
|
|
69538
69972
|
// src/cli/branchManager.ts
|
|
69539
|
-
import { promises as fs37, existsSync as existsSync45, readFileSync as
|
|
69540
|
-
import
|
|
69973
|
+
import { promises as fs37, existsSync as existsSync45, readFileSync as readFileSync37, writeFileSync as writeFileSync23, mkdirSync as mkdirSync19, statSync as statSync7, rmSync as rmSync3 } from "node:fs";
|
|
69974
|
+
import path66 from "node:path";
|
|
69541
69975
|
import os13 from "node:os";
|
|
69542
69976
|
var META_FILENAME = "meta.json";
|
|
69543
69977
|
var SESSIONS_SUBDIR = "sessions";
|
|
69544
69978
|
function getBranchesBaseDir() {
|
|
69545
|
-
return process.env.ANATHEMA_BRANCHES_DIR ??
|
|
69979
|
+
return process.env.ANATHEMA_BRANCHES_DIR ?? path66.join(os13.homedir(), ".tmp", "zelari-code", "branches");
|
|
69546
69980
|
}
|
|
69547
69981
|
function getSessionsBaseDir() {
|
|
69548
|
-
return process.env.ANATHEMA_SESSIONS_DIR ??
|
|
69982
|
+
return process.env.ANATHEMA_SESSIONS_DIR ?? path66.join(os13.homedir(), ".tmp", "zelari-code", "sessions");
|
|
69549
69983
|
}
|
|
69550
69984
|
function branchPathFor(name, baseDir) {
|
|
69551
|
-
return
|
|
69985
|
+
return path66.join(baseDir, name);
|
|
69552
69986
|
}
|
|
69553
69987
|
function metaPathFor(name, baseDir) {
|
|
69554
|
-
return
|
|
69988
|
+
return path66.join(baseDir, name, META_FILENAME);
|
|
69555
69989
|
}
|
|
69556
69990
|
function sessionsPathFor(name, baseDir) {
|
|
69557
|
-
return
|
|
69991
|
+
return path66.join(baseDir, name, SESSIONS_SUBDIR);
|
|
69558
69992
|
}
|
|
69559
69993
|
function readBranchMeta(name, baseDir) {
|
|
69560
69994
|
const metaPath = metaPathFor(name, baseDir);
|
|
@@ -69562,7 +69996,7 @@ function readBranchMeta(name, baseDir) {
|
|
|
69562
69996
|
throw new BranchNotFoundError(`Branch "${name}" not found`);
|
|
69563
69997
|
}
|
|
69564
69998
|
try {
|
|
69565
|
-
const raw =
|
|
69999
|
+
const raw = readFileSync37(metaPath, "utf-8");
|
|
69566
70000
|
const parsed = JSON.parse(raw);
|
|
69567
70001
|
if (!parsed || typeof parsed !== "object" || typeof parsed.name !== "string" || typeof parsed.createdAt !== "number" || typeof parsed.fromSessionId !== "string") {
|
|
69568
70002
|
throw new BranchCorruptError(`Branch "${name}" meta.json is malformed`);
|
|
@@ -69579,7 +70013,7 @@ function readBranchMeta(name, baseDir) {
|
|
|
69579
70013
|
}
|
|
69580
70014
|
function writeBranchMeta(name, baseDir, meta3) {
|
|
69581
70015
|
const metaPath = metaPathFor(name, baseDir);
|
|
69582
|
-
mkdirSync19(
|
|
70016
|
+
mkdirSync19(path66.dirname(metaPath), { recursive: true });
|
|
69583
70017
|
writeFileSync23(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
|
|
69584
70018
|
}
|
|
69585
70019
|
async function countSessions(name, baseDir) {
|
|
@@ -69630,14 +70064,14 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
69630
70064
|
if (branchExists(name, baseDir)) {
|
|
69631
70065
|
throw new BranchAlreadyExistsError(name);
|
|
69632
70066
|
}
|
|
69633
|
-
const sourcePath =
|
|
70067
|
+
const sourcePath = path66.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
|
|
69634
70068
|
if (!existsSync45(sourcePath)) {
|
|
69635
70069
|
throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
|
|
69636
70070
|
}
|
|
69637
70071
|
const branchPath = branchPathFor(name, baseDir);
|
|
69638
70072
|
const branchSessionsPath = sessionsPathFor(name, baseDir);
|
|
69639
70073
|
mkdirSync19(branchSessionsPath, { recursive: true });
|
|
69640
|
-
const destPath =
|
|
70074
|
+
const destPath = path66.join(branchSessionsPath, `${fromSessionId}.jsonl`);
|
|
69641
70075
|
await fs37.copyFile(sourcePath, destPath);
|
|
69642
70076
|
const meta3 = {
|
|
69643
70077
|
name,
|
|
@@ -69741,14 +70175,14 @@ async function handleBranchCheckout(ctx, branchName) {
|
|
|
69741
70175
|
// src/cli/slashHandlers/workspace.ts
|
|
69742
70176
|
init_messageHelpers();
|
|
69743
70177
|
import { promises as fs38 } from "node:fs";
|
|
69744
|
-
import
|
|
70178
|
+
import path67 from "node:path";
|
|
69745
70179
|
async function handleWorkspaceShow(ctx, what) {
|
|
69746
70180
|
try {
|
|
69747
|
-
const zelari =
|
|
70181
|
+
const zelari = path67.join(process.cwd(), ".zelari");
|
|
69748
70182
|
let content;
|
|
69749
70183
|
switch (what) {
|
|
69750
70184
|
case "plan": {
|
|
69751
|
-
const planPath =
|
|
70185
|
+
const planPath = path67.join(zelari, "plan.md");
|
|
69752
70186
|
try {
|
|
69753
70187
|
content = await fs38.readFile(planPath, "utf-8");
|
|
69754
70188
|
} catch {
|
|
@@ -69757,7 +70191,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
69757
70191
|
break;
|
|
69758
70192
|
}
|
|
69759
70193
|
case "decisions": {
|
|
69760
|
-
const decisionsDir =
|
|
70194
|
+
const decisionsDir = path67.join(zelari, "decisions");
|
|
69761
70195
|
try {
|
|
69762
70196
|
const files = (await fs38.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
69763
70197
|
if (files.length === 0) {
|
|
@@ -69767,7 +70201,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
69767
70201
|
`];
|
|
69768
70202
|
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
|
|
69769
70203
|
for (const f of files) {
|
|
69770
|
-
const raw = await fs38.readFile(
|
|
70204
|
+
const raw = await fs38.readFile(path67.join(decisionsDir, f), "utf-8");
|
|
69771
70205
|
const { meta: meta3, body } = parseFrontmatter2(raw);
|
|
69772
70206
|
const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
|
|
69773
70207
|
lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
|
|
@@ -69780,7 +70214,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
69780
70214
|
break;
|
|
69781
70215
|
}
|
|
69782
70216
|
case "risks": {
|
|
69783
|
-
const risksPath =
|
|
70217
|
+
const risksPath = path67.join(zelari, "risks.md");
|
|
69784
70218
|
try {
|
|
69785
70219
|
content = await fs38.readFile(risksPath, "utf-8");
|
|
69786
70220
|
} catch {
|
|
@@ -69789,7 +70223,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
69789
70223
|
break;
|
|
69790
70224
|
}
|
|
69791
70225
|
case "agents": {
|
|
69792
|
-
const agentsPath =
|
|
70226
|
+
const agentsPath = path67.join(process.cwd(), "AGENTS.MD");
|
|
69793
70227
|
try {
|
|
69794
70228
|
content = await fs38.readFile(agentsPath, "utf-8");
|
|
69795
70229
|
} catch {
|
|
@@ -69798,7 +70232,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
69798
70232
|
break;
|
|
69799
70233
|
}
|
|
69800
70234
|
case "docs": {
|
|
69801
|
-
const docsDir =
|
|
70235
|
+
const docsDir = path67.join(zelari, "docs");
|
|
69802
70236
|
try {
|
|
69803
70237
|
const files = (await fs38.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
69804
70238
|
content = files.length ? `# Docs (${files.length})
|
|
@@ -69840,7 +70274,7 @@ async function handleWorkspaceReset(ctx, force) {
|
|
|
69840
70274
|
return;
|
|
69841
70275
|
}
|
|
69842
70276
|
try {
|
|
69843
|
-
const target =
|
|
70277
|
+
const target = path67.join(process.cwd(), ".zelari");
|
|
69844
70278
|
await fs38.rm(target, { recursive: true, force: true });
|
|
69845
70279
|
appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
|
|
69846
70280
|
} catch (err) {
|
|
@@ -69852,7 +70286,7 @@ async function handleWorkspaceReset(ctx, force) {
|
|
|
69852
70286
|
init_provider2();
|
|
69853
70287
|
|
|
69854
70288
|
// src/cli/slashHandlers/skills.ts
|
|
69855
|
-
import
|
|
70289
|
+
import path68 from "node:path";
|
|
69856
70290
|
import os14 from "node:os";
|
|
69857
70291
|
|
|
69858
70292
|
// src/cli/skillHistory.ts
|
|
@@ -69981,7 +70415,7 @@ function handleSkillPicker(ctx, skills, openPicker, fallbackMessage) {
|
|
|
69981
70415
|
});
|
|
69982
70416
|
}
|
|
69983
70417
|
async function handleSkillStats(ctx, skillId) {
|
|
69984
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
70418
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path68.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
69985
70419
|
try {
|
|
69986
70420
|
const records = await readSkillHistory(historyFile);
|
|
69987
70421
|
const stats = getSkillStats(records, skillId);
|
|
@@ -69997,7 +70431,7 @@ async function handleSkillCompare(ctx, ids, fallbackMessage) {
|
|
|
69997
70431
|
appendSystem(ctx.setMessages, fallbackMessage ?? "[skill-compare] missing args");
|
|
69998
70432
|
return;
|
|
69999
70433
|
}
|
|
70000
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
70434
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path68.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
70001
70435
|
try {
|
|
70002
70436
|
const formatted = await compareSkillsFromFile(ids[0], ids[1], historyFile);
|
|
70003
70437
|
appendSystem(ctx.setMessages, formatted);
|
|
@@ -71512,6 +71946,54 @@ init_candidateRegistry();
|
|
|
71512
71946
|
init_metrics2();
|
|
71513
71947
|
init_completionGate();
|
|
71514
71948
|
init_delegationPolicy();
|
|
71949
|
+
|
|
71950
|
+
// src/cli/orchestration/policy.ts
|
|
71951
|
+
var DEFAULT_MAX_SOLO_CHARS = 300;
|
|
71952
|
+
var KRAKEN_SIGNALS = [
|
|
71953
|
+
{ re: /\bimplement(?:s|ed|ing)?\b/i, reason: "implementation signal" },
|
|
71954
|
+
{ re: /\brefactor(?:ing|ed)?\b/i, reason: "refactor signal" },
|
|
71955
|
+
{ re: /\bmigrat(?:e|es|ed|ion|ing)\b/i, reason: "migration signal" },
|
|
71956
|
+
{
|
|
71957
|
+
re: /\b(?:add|build|create|introduce)\b[^.?!]{0,48}\b(?:feature|endpoint|module|service|command|api|registry|runtime)\b/i,
|
|
71958
|
+
reason: "new-capability signal"
|
|
71959
|
+
},
|
|
71960
|
+
{
|
|
71961
|
+
re: /\b(?:unit|integration|e2e|end-to-end)\s+(?:tests?|testing|specs?)\b|\bwrite\s+(?:the\s+|some\s+)?tests?\b/i,
|
|
71962
|
+
reason: "test-writing signal"
|
|
71963
|
+
},
|
|
71964
|
+
{
|
|
71965
|
+
re: /\b\d+\s*-?\s*(?:files?|modules?|packages?|components?|services?|endpoints?|worktrees?)\b/i,
|
|
71966
|
+
reason: "multi-artifact count"
|
|
71967
|
+
},
|
|
71968
|
+
{
|
|
71969
|
+
re: /\b(?:across|spanning|between|touching)\s+(?:all\s+|the\s+)?(?:\w+\s+){0,2}(?:files|modules|packages|layers|surfaces)\b/i,
|
|
71970
|
+
reason: "cross-cutting scope"
|
|
71971
|
+
}
|
|
71972
|
+
];
|
|
71973
|
+
var QUESTION_RE = /\?\s*$|^(?:who|what|why|when|where|which|how|is|are|was|were|does|do|did|can|could|should|would|will)\b/i;
|
|
71974
|
+
var EXPLAIN_RE = /\b(?:explain|describe|summarize|summarise|clarify|walk\W*me\W*through)\b/i;
|
|
71975
|
+
var READONLY_RE = /\b(?:find|show|list|grep|search|locate|inspect|read|check|review|where\W+is)\b/i;
|
|
71976
|
+
function chooseOrchestration(task, opts = {}) {
|
|
71977
|
+
const text = String(task ?? "").trim();
|
|
71978
|
+
const failClosed = () => ({
|
|
71979
|
+
surface: "solo",
|
|
71980
|
+
reason: "fail-closed default"
|
|
71981
|
+
});
|
|
71982
|
+
if (!text) return failClosed();
|
|
71983
|
+
for (const { re, reason } of KRAKEN_SIGNALS) {
|
|
71984
|
+
if (re.test(text)) return { surface: "kraken", reason };
|
|
71985
|
+
}
|
|
71986
|
+
if (QUESTION_RE.test(text)) return { surface: "solo", reason: "question-shaped task" };
|
|
71987
|
+
if (EXPLAIN_RE.test(text)) return { surface: "solo", reason: "explanation request" };
|
|
71988
|
+
if (READONLY_RE.test(text)) return { surface: "solo", reason: "read-only request" };
|
|
71989
|
+
const budget = opts.maxSoloChars ?? DEFAULT_MAX_SOLO_CHARS;
|
|
71990
|
+
if (text.length <= budget) {
|
|
71991
|
+
return { surface: "solo", reason: "small task, no heavy signals" };
|
|
71992
|
+
}
|
|
71993
|
+
return failClosed();
|
|
71994
|
+
}
|
|
71995
|
+
|
|
71996
|
+
// src/cli/runHeadless.ts
|
|
71515
71997
|
init_headless();
|
|
71516
71998
|
init_claudeProvider();
|
|
71517
71999
|
init_skills2();
|
|
@@ -71550,12 +72032,13 @@ function createStreamScrubber2() {
|
|
|
71550
72032
|
init_taskTool();
|
|
71551
72033
|
init_sessionTodos();
|
|
71552
72034
|
import { promises as fs41 } from "node:fs";
|
|
71553
|
-
import
|
|
72035
|
+
import path70 from "node:path";
|
|
71554
72036
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
71555
72037
|
|
|
71556
72038
|
// src/cli/kraken/verifierLifecycle.ts
|
|
71557
72039
|
init_verification2();
|
|
71558
72040
|
init_krakenSelectTool();
|
|
72041
|
+
init_krakenModel();
|
|
71559
72042
|
|
|
71560
72043
|
// src/cli/kraken/verifierResolution.ts
|
|
71561
72044
|
init_providerConfig();
|
|
@@ -71599,18 +72082,61 @@ function makeVerifierCallModel(loadStream, identity, timeoutMs2 = 12e4) {
|
|
|
71599
72082
|
return { text, provider: identity.provider, model: identity.model };
|
|
71600
72083
|
};
|
|
71601
72084
|
}
|
|
71602
|
-
function resolveIdentity(selection, session) {
|
|
72085
|
+
function resolveIdentity(selection, session, familyCandidates, env = process.env) {
|
|
71603
72086
|
if (selection.mode === "fixed") {
|
|
71604
72087
|
return { provider: selection.provider, model: selection.model };
|
|
71605
72088
|
}
|
|
71606
|
-
|
|
72089
|
+
if (!session || !session.provider || !session.model) return null;
|
|
72090
|
+
if (familyCandidates && familyCandidates.length > 0) {
|
|
72091
|
+
const cross = resolveCrossModelVerifier(session, familyCandidates, env);
|
|
72092
|
+
if (cross) return { provider: cross.provider, model: cross.model };
|
|
72093
|
+
}
|
|
72094
|
+
return session;
|
|
72095
|
+
}
|
|
72096
|
+
function isTestEvidenceCriterion(criterionId2) {
|
|
72097
|
+
const id3 = criterionId2.toLowerCase();
|
|
72098
|
+
return ["test", "typecheck", "build", "lint"].some((k) => id3.includes(k));
|
|
72099
|
+
}
|
|
72100
|
+
function extractTestOutputExcerpt(results, maxChars = 4e3) {
|
|
72101
|
+
const lines = [];
|
|
72102
|
+
for (const r of results) {
|
|
72103
|
+
if (!isTestEvidenceCriterion(r.criterionId)) continue;
|
|
72104
|
+
lines.push([r.criterionId, r.status, r.detail].filter(Boolean).join(" \u2014 "));
|
|
72105
|
+
}
|
|
72106
|
+
if (lines.length === 0) return "";
|
|
72107
|
+
return lines.join("\n").slice(0, maxChars);
|
|
72108
|
+
}
|
|
72109
|
+
async function buildBlindReviewInput(evaluation, deps) {
|
|
72110
|
+
const results = evaluation.results ?? [];
|
|
72111
|
+
const passed = results.filter((r) => r.status === "pass").length;
|
|
72112
|
+
const verdict = evaluation.evaluation?.verdict ?? "UNKNOWN";
|
|
72113
|
+
const summary = `Kraken BUILD turn \u2014 deterministic evidence: ${passed}/${results.length} criteria pass, completion verdict ${verdict}.`;
|
|
72114
|
+
const task = deps.task?.trim();
|
|
72115
|
+
const testOutputExcerpt = extractTestOutputExcerpt(results);
|
|
72116
|
+
let diffSummary;
|
|
72117
|
+
try {
|
|
72118
|
+
const res = await (deps.getDiff ?? getWorkingDiff)({
|
|
72119
|
+
cwd: deps.cwd ?? process.cwd(),
|
|
72120
|
+
maxChars: 8e3,
|
|
72121
|
+
staged: true
|
|
72122
|
+
});
|
|
72123
|
+
if (res && !res.empty && res.diff) diffSummary = res.diff;
|
|
72124
|
+
} catch {
|
|
72125
|
+
}
|
|
72126
|
+
return {
|
|
72127
|
+
...task ? { task } : {},
|
|
72128
|
+
summary,
|
|
72129
|
+
...diffSummary !== void 0 ? { diffSummary } : {},
|
|
72130
|
+
...testOutputExcerpt ? { testOutputExcerpt } : {},
|
|
72131
|
+
results
|
|
72132
|
+
};
|
|
71607
72133
|
}
|
|
71608
72134
|
async function runAdvisoryVerifierReview(evaluation, deps = {}) {
|
|
71609
72135
|
if (!evaluation.evaluation || !evaluation.results) return null;
|
|
71610
72136
|
const env = deps.env ?? process.env;
|
|
71611
72137
|
const selection = deps.selection ?? loadVerifierModelSelection();
|
|
71612
72138
|
if (!verifierReviewEnabled(selection, env)) return null;
|
|
71613
|
-
const identity = resolveIdentity(selection, deps.session);
|
|
72139
|
+
const identity = resolveIdentity(selection, deps.session, deps.familyCandidates, env);
|
|
71614
72140
|
let callModel = deps.callModel;
|
|
71615
72141
|
if (!callModel) {
|
|
71616
72142
|
if (!identity || !deps.loadStream) return null;
|
|
@@ -71627,11 +72153,9 @@ async function runAdvisoryVerifierReview(evaluation, deps = {}) {
|
|
|
71627
72153
|
emit: deps.emit,
|
|
71628
72154
|
env
|
|
71629
72155
|
});
|
|
71630
|
-
const
|
|
71631
|
-
const summary = `Kraken BUILD turn \u2014 deterministic evidence: ${passed}/${evaluation.results.length} criteria pass, completion verdict ${evaluation.evaluation.verdict}.`;
|
|
72156
|
+
const blind = await buildBlindReviewInput(evaluation, deps);
|
|
71632
72157
|
const review = await service.reviewCompletion({
|
|
71633
|
-
|
|
71634
|
-
results: evaluation.results,
|
|
72158
|
+
...blind,
|
|
71635
72159
|
session: deps.session
|
|
71636
72160
|
});
|
|
71637
72161
|
evaluation.review = review;
|
|
@@ -71945,6 +72469,13 @@ ${err.stack}` : "";
|
|
|
71945
72469
|
model
|
|
71946
72470
|
});
|
|
71947
72471
|
}
|
|
72472
|
+
if (opts.orchestrationAuto) {
|
|
72473
|
+
const verdict = chooseOrchestration(opts.task ?? "");
|
|
72474
|
+
const line = `[orchestration] --mode auto -> surface=${verdict.surface} (${verdict.reason})`;
|
|
72475
|
+
if (opts.output === "json") emitEvent({ type: "log", message: line });
|
|
72476
|
+
else process.stderr.write(`[zelari-code --headless] ${line}
|
|
72477
|
+
`);
|
|
72478
|
+
}
|
|
71948
72479
|
const mode = opts.mode ?? (opts.useCouncil ? "council" : "kraken");
|
|
71949
72480
|
const profileId = resolveHeadlessProfileId(mode, opts.profile);
|
|
71950
72481
|
if (opts.output === "json") {
|
|
@@ -72018,7 +72549,7 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
72018
72549
|
try {
|
|
72019
72550
|
let preflightGraph;
|
|
72020
72551
|
if (opts.runPlan && opts.runPlan.trim() !== "") {
|
|
72021
|
-
const planPath =
|
|
72552
|
+
const planPath = path70.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
|
|
72022
72553
|
log(`loading pre-flight plan: ${planPath}`);
|
|
72023
72554
|
let raw;
|
|
72024
72555
|
try {
|
|
@@ -72058,8 +72589,8 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
72058
72589
|
log(formatKrakenGraphAscii2(graph));
|
|
72059
72590
|
if (opts.planOnly) {
|
|
72060
72591
|
const planId = randomUUID8();
|
|
72061
|
-
const planDir =
|
|
72062
|
-
const planPath =
|
|
72592
|
+
const planDir = path70.join(cwd, ".zelari", "radio");
|
|
72593
|
+
const planPath = path70.join(planDir, `plan-${planId}.json`);
|
|
72063
72594
|
await fs41.mkdir(planDir, { recursive: true });
|
|
72064
72595
|
await fs41.writeFile(
|
|
72065
72596
|
planPath,
|
|
@@ -72087,6 +72618,18 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
72087
72618
|
root: cwd,
|
|
72088
72619
|
audit,
|
|
72089
72620
|
sessionId: sessionId2,
|
|
72621
|
+
// P0.4 capability inheritance: tentacles intersect the headless
|
|
72622
|
+
// parent policy. Headless runs are auto-allow (the same literal
|
|
72623
|
+
// the main headless registry below uses), so this is a no-op
|
|
72624
|
+
// today — wired for correctness if that default ever tightens.
|
|
72625
|
+
parentPolicy: {
|
|
72626
|
+
read: "allow",
|
|
72627
|
+
write: "allow",
|
|
72628
|
+
execute: "allow",
|
|
72629
|
+
network: "allow",
|
|
72630
|
+
ui: "allow",
|
|
72631
|
+
auto: true
|
|
72632
|
+
},
|
|
72090
72633
|
// Anchor every tentacle to the SAME provider/model this run
|
|
72091
72634
|
// resolved (Desktop's selector, or --provider/--model), instead
|
|
72092
72635
|
// of the persisted provider.json default the factory falls back
|
|
@@ -72179,6 +72722,12 @@ async function registerHeadlessMcp(toolRegistry, opts) {
|
|
|
72179
72722
|
}
|
|
72180
72723
|
}
|
|
72181
72724
|
}
|
|
72725
|
+
function writeProofSafe(gate, meta3, baseDir = process.cwd()) {
|
|
72726
|
+
return writeCompletionProof(gate, { baseDir, meta: meta3 }).then(
|
|
72727
|
+
() => void 0,
|
|
72728
|
+
() => void 0
|
|
72729
|
+
);
|
|
72730
|
+
}
|
|
72182
72731
|
async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
72183
72732
|
const sessionId2 = crypto.randomUUID();
|
|
72184
72733
|
const memoryFactory = await Promise.resolve().then(() => (init_serviceFactory(), serviceFactory_exports));
|
|
@@ -72517,6 +73066,7 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
72517
73066
|
let strictExit = 0;
|
|
72518
73067
|
const verifierReviewDeps = {
|
|
72519
73068
|
session: { provider, model },
|
|
73069
|
+
task: effectiveTask,
|
|
72520
73070
|
loadStream: async (providerId, modelId) => {
|
|
72521
73071
|
if (providerId === provider) return providerStream;
|
|
72522
73072
|
try {
|
|
@@ -72544,6 +73094,7 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
72544
73094
|
if (opts.output === "json") {
|
|
72545
73095
|
emitEvent({ type: "verification_run", ...verificationPayload });
|
|
72546
73096
|
}
|
|
73097
|
+
await writeProofSafe(strictGate, { surface: "kraken", sessionId: spine.sessionId });
|
|
72547
73098
|
if (strictGate.blocked) {
|
|
72548
73099
|
const repairPrompt = buildKrakenRepairPrompt(gate);
|
|
72549
73100
|
if (opts.output === "json") {
|
|
@@ -72577,6 +73128,7 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
72577
73128
|
if (opts.output === "json") {
|
|
72578
73129
|
emitEvent({ type: "verification_run", ...afterPayload });
|
|
72579
73130
|
}
|
|
73131
|
+
await writeProofSafe(after, { surface: "kraken", sessionId: spine.sessionId });
|
|
72580
73132
|
if (!after.blocked) markRepairSucceeded();
|
|
72581
73133
|
else {
|
|
72582
73134
|
strictExit = strictGateExitCode(after);
|
|
@@ -72610,7 +73162,7 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
72610
73162
|
if (json3) {
|
|
72611
73163
|
if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
|
|
72612
73164
|
else {
|
|
72613
|
-
await fs41.mkdir(
|
|
73165
|
+
await fs41.mkdir(path70.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
|
|
72614
73166
|
await fs41.writeFile(opts.exportSessionPath, json3, "utf8");
|
|
72615
73167
|
}
|
|
72616
73168
|
}
|
|
@@ -72839,7 +73391,7 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
72839
73391
|
if (json3) {
|
|
72840
73392
|
if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
|
|
72841
73393
|
else {
|
|
72842
|
-
await fs41.mkdir(
|
|
73394
|
+
await fs41.mkdir(path70.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
|
|
72843
73395
|
await fs41.writeFile(opts.exportSessionPath, json3, "utf8");
|
|
72844
73396
|
}
|
|
72845
73397
|
}
|
|
@@ -73219,6 +73771,7 @@ ${ragContext}` : slicePrompt;
|
|
|
73219
73771
|
if (opts.output === "json") {
|
|
73220
73772
|
emitEvent({ type: "verification_run", ...missionVerificationPayload });
|
|
73221
73773
|
}
|
|
73774
|
+
await writeProofSafe(missionGate, { surface: "mission", sessionId: spine.sessionId }, projectRoot);
|
|
73222
73775
|
if (missionGate.blocked) {
|
|
73223
73776
|
exitCode = strictGateExitCode(missionGate);
|
|
73224
73777
|
spine.missionPhase("verification", "mission-strict-blocked");
|
|
@@ -73253,7 +73806,7 @@ ${ragContext}` : slicePrompt;
|
|
|
73253
73806
|
if (json3) {
|
|
73254
73807
|
if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
|
|
73255
73808
|
else {
|
|
73256
|
-
await fs41.mkdir(
|
|
73809
|
+
await fs41.mkdir(path70.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
|
|
73257
73810
|
await fs41.writeFile(opts.exportSessionPath, json3, "utf8");
|
|
73258
73811
|
}
|
|
73259
73812
|
}
|
|
@@ -73455,8 +74008,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
|
|
|
73455
74008
|
let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
73456
74009
|
if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
|
|
73457
74010
|
try {
|
|
73458
|
-
const
|
|
73459
|
-
name =
|
|
74011
|
+
const path74 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
74012
|
+
name = path74 && /^[a-z0-9]/.test(path74) ? path74 : "imported-skill";
|
|
73460
74013
|
} catch {
|
|
73461
74014
|
name = "imported-skill";
|
|
73462
74015
|
}
|