zelari-code 2.30.0 → 2.32.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/README.md +6 -4
- package/dist/cli/app.js +22 -1
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/budget/historySummary.js +41 -0
- package/dist/cli/budget/historySummary.js.map +1 -1
- package/dist/cli/budget/tokenBudget.js +6 -2
- package/dist/cli/budget/tokenBudget.js.map +1 -1
- package/dist/cli/components/StatusBar.js +4 -1
- package/dist/cli/components/StatusBar.js.map +1 -1
- package/dist/cli/costBudget.js +16 -0
- package/dist/cli/costBudget.js.map +1 -1
- package/dist/cli/headless/runOneTurn.js +9 -11
- package/dist/cli/headless/runOneTurn.js.map +1 -1
- package/dist/cli/hooks/historyCompaction.js +59 -18
- package/dist/cli/hooks/historyCompaction.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +24 -0
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/hooks/useSlashDispatch.js +16 -0
- package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
- package/dist/cli/kraken/verifyStatus.js +6 -0
- package/dist/cli/kraken/verifyStatus.js.map +1 -1
- package/dist/cli/main.bundled.js +1117 -819
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +82 -14
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/runHeadless.js +18 -27
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/safety/destructiveCommands.js +72 -0
- package/dist/cli/safety/destructiveCommands.js.map +1 -0
- package/dist/cli/safety/osJail.js +7 -1
- package/dist/cli/safety/osJail.js.map +1 -1
- package/dist/cli/slashCommands.js +6 -1
- package/dist/cli/slashCommands.js.map +1 -1
- package/dist/cli/toolRegistry.js +21 -1
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/utils/doctor.js +29 -4
- package/dist/cli/utils/doctor.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -27111,6 +27111,19 @@ var init_contractCompiler = __esm({
|
|
|
27111
27111
|
});
|
|
27112
27112
|
|
|
27113
27113
|
// src/cli/kraken/verificationBridge.ts
|
|
27114
|
+
var verificationBridge_exports = {};
|
|
27115
|
+
__export(verificationBridge_exports, {
|
|
27116
|
+
STRICT_DONE_EXIT_CODE: () => STRICT_DONE_EXIT_CODE,
|
|
27117
|
+
anchorSelectionEvidence: () => anchorSelectionEvidence,
|
|
27118
|
+
evaluateStrictBuildGate: () => evaluateStrictBuildGate,
|
|
27119
|
+
evaluateStrictBuildGateFromSession: () => evaluateStrictBuildGateFromSession,
|
|
27120
|
+
krakenResultsToContract: () => krakenResultsToContract,
|
|
27121
|
+
matchNoteToToolTrace: () => matchNoteToToolTrace,
|
|
27122
|
+
strictDoneEnabled: () => strictDoneEnabled,
|
|
27123
|
+
strictEnvOverlay: () => strictEnvOverlay,
|
|
27124
|
+
strictGateEventPayload: () => strictGateEventPayload,
|
|
27125
|
+
strictGateExitCode: () => strictGateExitCode
|
|
27126
|
+
});
|
|
27114
27127
|
import { createHash as createHash9 } from "node:crypto";
|
|
27115
27128
|
function strictDoneEnabled(surface = "kraken", env = process.env) {
|
|
27116
27129
|
if (surface === "mission") {
|
|
@@ -27392,6 +27405,20 @@ function strictGateEventPayload(evaluation) {
|
|
|
27392
27405
|
summary: evaluation.summary
|
|
27393
27406
|
};
|
|
27394
27407
|
}
|
|
27408
|
+
function evaluateStrictBuildGateFromSession(mode, snapshot) {
|
|
27409
|
+
const gate = evaluateKrakenCompletionGate(mode);
|
|
27410
|
+
const evaluation = snapshot ? snapshotToCompletionEvaluation(snapshot) : null;
|
|
27411
|
+
const blocked = evaluation ? evaluation.verdict !== "PASS" : false;
|
|
27412
|
+
return {
|
|
27413
|
+
gate,
|
|
27414
|
+
strict: evaluation !== null,
|
|
27415
|
+
evaluation,
|
|
27416
|
+
native: null,
|
|
27417
|
+
// session replay carries the payload, not in-process results
|
|
27418
|
+
blocked,
|
|
27419
|
+
summary: evaluation ? blocked ? `blocked (strict ${evaluation.verdict} from session log seq=${snapshot?.seq}): ${evaluation.summary}` : `open (strict PASS from session log seq=${snapshot?.seq}): ${evaluation.summary}` : "open (no strict verification record in session log)"
|
|
27420
|
+
};
|
|
27421
|
+
}
|
|
27395
27422
|
var STRICT_DONE_EXIT_CODE;
|
|
27396
27423
|
var init_verificationBridge = __esm({
|
|
27397
27424
|
"src/cli/kraken/verificationBridge.ts"() {
|
|
@@ -27405,6 +27432,461 @@ var init_verificationBridge = __esm({
|
|
|
27405
27432
|
}
|
|
27406
27433
|
});
|
|
27407
27434
|
|
|
27435
|
+
// src/cli/kraken/verifyStatus.ts
|
|
27436
|
+
var verifyStatus_exports = {};
|
|
27437
|
+
__export(verifyStatus_exports, {
|
|
27438
|
+
formatStrictBlockExplanation: () => formatStrictBlockExplanation,
|
|
27439
|
+
formatVerifyChip: () => formatVerifyChip,
|
|
27440
|
+
getVerifyChip: () => getVerifyChip,
|
|
27441
|
+
permissionsChip: () => permissionsChip,
|
|
27442
|
+
recordStrictGateEvaluation: () => recordStrictGateEvaluation,
|
|
27443
|
+
verifyStateFromGate: () => verifyStateFromGate
|
|
27444
|
+
});
|
|
27445
|
+
function verifyStateFromGate(evaluation) {
|
|
27446
|
+
if (!evaluation.blocked) return "pass";
|
|
27447
|
+
const verdict = evaluation.evaluation?.verdict;
|
|
27448
|
+
if (verdict === "BLOCKED") return "blocked";
|
|
27449
|
+
return "repair";
|
|
27450
|
+
}
|
|
27451
|
+
function formatVerifyChip(state3) {
|
|
27452
|
+
if (state3 === "pass") return { label: "prova: PASS", tone: "green" };
|
|
27453
|
+
if (state3 === "blocked") return { label: "prova: BLOCCATO", tone: "red" };
|
|
27454
|
+
return { label: "prova: RIPARA", tone: "yellow" };
|
|
27455
|
+
}
|
|
27456
|
+
function permissionsChip(phase2, strictOn = strictDoneEnabled()) {
|
|
27457
|
+
if (phase2 === "plan") return { label: "scrive: no (piano)", tone: "yellow" };
|
|
27458
|
+
return strictOn ? { label: "scrive: s\xEC \xB7 prova obbligatoria", tone: "green" } : { label: "scrive: s\xEC \xB7 senza prova (dichiarato)", tone: "yellow" };
|
|
27459
|
+
}
|
|
27460
|
+
function formatStrictBlockExplanation(evaluation) {
|
|
27461
|
+
const state3 = verifyStateFromGate(evaluation);
|
|
27462
|
+
const gate = evaluation.gate;
|
|
27463
|
+
if (state3 === "pass") {
|
|
27464
|
+
return `[verifica] PASS \u2014 ${gate.passed}/${gate.total} prove superate.`;
|
|
27465
|
+
}
|
|
27466
|
+
const word = state3 === "blocked" ? "BLOCCATO" : "RIPARA";
|
|
27467
|
+
const lines = [
|
|
27468
|
+
`[verifica] ${word} \u2014 ${gate.passed}/${gate.total} prove superate; il turno non pu\xF2 dichiararsi finito senza prova.`
|
|
27469
|
+
];
|
|
27470
|
+
const evalr = evaluation.evaluation ?? null;
|
|
27471
|
+
if (evalr) {
|
|
27472
|
+
const byId = /* @__PURE__ */ new Map();
|
|
27473
|
+
for (const c of evalr.criteria ?? []) byId.set(c.id, c.text);
|
|
27474
|
+
const unsatisfied = (evalr.results ?? []).filter((r) => r.status !== "pass");
|
|
27475
|
+
if (unsatisfied.length > 0) {
|
|
27476
|
+
lines.push("Mancano:");
|
|
27477
|
+
for (const r of unsatisfied.slice(0, 8)) {
|
|
27478
|
+
lines.push(` \u2022 ${byId.get(r.criterionId) ?? r.criterionId} [${r.status}]`);
|
|
27479
|
+
}
|
|
27480
|
+
if (unsatisfied.length > 8) {
|
|
27481
|
+
lines.push(` \u2022 \u2026 e altri ${unsatisfied.length - 8}`);
|
|
27482
|
+
}
|
|
27483
|
+
const first = byId.get(unsatisfied[0].criterionId) ?? unsatisfied[0].criterionId;
|
|
27484
|
+
lines.push(
|
|
27485
|
+
state3 === "blocked" ? `Prossimo comando: /verify \u2014 poi porta evidenza per \xAB${first}\xBB e riprova.` : `Prossimo comando: ripara \xAB${first}\xBB, poi /verify per ricontrollare.`
|
|
27486
|
+
);
|
|
27487
|
+
}
|
|
27488
|
+
}
|
|
27489
|
+
lines.push(
|
|
27490
|
+
"La prova \xE8 obbligatoria: chiudo il turno solo quando ogni criterio richiesto ha evidenza."
|
|
27491
|
+
);
|
|
27492
|
+
return lines.join("\n");
|
|
27493
|
+
}
|
|
27494
|
+
function recordStrictGateEvaluation(evaluation) {
|
|
27495
|
+
const g = globalThis;
|
|
27496
|
+
g.__zelariVerifyState = {
|
|
27497
|
+
state: verifyStateFromGate(evaluation),
|
|
27498
|
+
at: Date.now(),
|
|
27499
|
+
passed: evaluation.gate.passed,
|
|
27500
|
+
total: evaluation.gate.total
|
|
27501
|
+
};
|
|
27502
|
+
}
|
|
27503
|
+
function getVerifyChip() {
|
|
27504
|
+
const g = globalThis;
|
|
27505
|
+
const s = g.__zelariVerifyState;
|
|
27506
|
+
if (!s) return null;
|
|
27507
|
+
return formatVerifyChip(s.state);
|
|
27508
|
+
}
|
|
27509
|
+
var init_verifyStatus = __esm({
|
|
27510
|
+
"src/cli/kraken/verifyStatus.ts"() {
|
|
27511
|
+
"use strict";
|
|
27512
|
+
init_verificationBridge();
|
|
27513
|
+
}
|
|
27514
|
+
});
|
|
27515
|
+
|
|
27516
|
+
// src/cli/safety/policyLoadMode.ts
|
|
27517
|
+
var policyLoadMode_exports = {};
|
|
27518
|
+
__export(policyLoadMode_exports, {
|
|
27519
|
+
POLICY_LOAD_BLOCK_REASON: () => POLICY_LOAD_BLOCK_REASON,
|
|
27520
|
+
POLICY_LOAD_EXIT_CODE: () => POLICY_LOAD_EXIT_CODE,
|
|
27521
|
+
POLICY_LOAD_MODE_ENV: () => POLICY_LOAD_MODE_ENV,
|
|
27522
|
+
activePolicyLoadMode: () => activePolicyLoadMode,
|
|
27523
|
+
activePolicyLoadSurface: () => activePolicyLoadSurface,
|
|
27524
|
+
resolvePolicyLoadMode: () => resolvePolicyLoadMode,
|
|
27525
|
+
setActivePolicyLoadSurface: () => setActivePolicyLoadSurface
|
|
27526
|
+
});
|
|
27527
|
+
function isTruthyFlag(v) {
|
|
27528
|
+
const n = v?.trim().toLowerCase();
|
|
27529
|
+
return n === "1" || n === "true" || n === "yes" || n === "on";
|
|
27530
|
+
}
|
|
27531
|
+
function resolvePolicyLoadMode(input) {
|
|
27532
|
+
const v = input.override?.trim().toLowerCase();
|
|
27533
|
+
if (v === "strict") return "strict";
|
|
27534
|
+
if (v === "permissive") return "permissive";
|
|
27535
|
+
if (input.surface === "headless" || input.surface === "mission") return "strict";
|
|
27536
|
+
if (isTruthyFlag(input.ci)) return "strict";
|
|
27537
|
+
return "permissive";
|
|
27538
|
+
}
|
|
27539
|
+
function setActivePolicyLoadSurface(surface) {
|
|
27540
|
+
activeSurface = surface;
|
|
27541
|
+
}
|
|
27542
|
+
function activePolicyLoadSurface() {
|
|
27543
|
+
return activeSurface;
|
|
27544
|
+
}
|
|
27545
|
+
function activePolicyLoadMode(env = process.env) {
|
|
27546
|
+
return resolvePolicyLoadMode({
|
|
27547
|
+
surface: activeSurface,
|
|
27548
|
+
override: env[POLICY_LOAD_MODE_ENV],
|
|
27549
|
+
ci: typeof env.CI === "string" ? env.CI : void 0
|
|
27550
|
+
});
|
|
27551
|
+
}
|
|
27552
|
+
var POLICY_LOAD_MODE_ENV, POLICY_LOAD_BLOCK_REASON, POLICY_LOAD_EXIT_CODE, activeSurface;
|
|
27553
|
+
var init_policyLoadMode = __esm({
|
|
27554
|
+
"src/cli/safety/policyLoadMode.ts"() {
|
|
27555
|
+
"use strict";
|
|
27556
|
+
POLICY_LOAD_MODE_ENV = "ZELARI_POLICY_LOAD_MODE";
|
|
27557
|
+
POLICY_LOAD_BLOCK_REASON = "policy-load-failed";
|
|
27558
|
+
POLICY_LOAD_EXIT_CODE = 2;
|
|
27559
|
+
activeSurface = "tui";
|
|
27560
|
+
}
|
|
27561
|
+
});
|
|
27562
|
+
|
|
27563
|
+
// src/cli/safety/jails/darwin.ts
|
|
27564
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
27565
|
+
function sbplQuote(p3) {
|
|
27566
|
+
return `"${p3.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
27567
|
+
}
|
|
27568
|
+
function buildSeatbeltProfile(spec) {
|
|
27569
|
+
const lines = [
|
|
27570
|
+
"(version 1)",
|
|
27571
|
+
`; zelari osJail (t28) \u2014 generated from JailSpec root=${spec.root}`,
|
|
27572
|
+
"(allow default)",
|
|
27573
|
+
"(deny file-write*)",
|
|
27574
|
+
"(allow file-write*"
|
|
27575
|
+
];
|
|
27576
|
+
for (const dir of spec.writable) {
|
|
27577
|
+
lines.push(` (subpath ${sbplQuote(dir)})`);
|
|
27578
|
+
}
|
|
27579
|
+
lines.push(")");
|
|
27580
|
+
switch (spec.network.mode) {
|
|
27581
|
+
case "deny":
|
|
27582
|
+
lines.push("(deny network*)");
|
|
27583
|
+
break;
|
|
27584
|
+
case "allow":
|
|
27585
|
+
lines.push("(allow network*)");
|
|
27586
|
+
break;
|
|
27587
|
+
case "allow-list":
|
|
27588
|
+
lines.push(
|
|
27589
|
+
`; allow-list hosts (${spec.network.hosts.join(", ")}) NOT kernel-filtered \u2014 degraded to allow`,
|
|
27590
|
+
"(allow network*)"
|
|
27591
|
+
);
|
|
27592
|
+
break;
|
|
27593
|
+
}
|
|
27594
|
+
return lines.join("\n");
|
|
27595
|
+
}
|
|
27596
|
+
function darwinProbe(platform, exists) {
|
|
27597
|
+
if (platform !== "darwin") {
|
|
27598
|
+
return {
|
|
27599
|
+
backend: "seatbelt",
|
|
27600
|
+
available: false,
|
|
27601
|
+
reason: `platform ${platform} is not darwin`
|
|
27602
|
+
};
|
|
27603
|
+
}
|
|
27604
|
+
if (!exists(SANDBOX_EXEC_PATH)) {
|
|
27605
|
+
return {
|
|
27606
|
+
backend: "seatbelt",
|
|
27607
|
+
available: false,
|
|
27608
|
+
reason: `${SANDBOX_EXEC_PATH} not found`
|
|
27609
|
+
};
|
|
27610
|
+
}
|
|
27611
|
+
return {
|
|
27612
|
+
backend: "seatbelt",
|
|
27613
|
+
available: true,
|
|
27614
|
+
reason: `sandbox-exec available at ${SANDBOX_EXEC_PATH}`
|
|
27615
|
+
};
|
|
27616
|
+
}
|
|
27617
|
+
var SANDBOX_EXEC_PATH, darwinBackend;
|
|
27618
|
+
var init_darwin = __esm({
|
|
27619
|
+
"src/cli/safety/jails/darwin.ts"() {
|
|
27620
|
+
"use strict";
|
|
27621
|
+
SANDBOX_EXEC_PATH = "/usr/bin/sandbox-exec";
|
|
27622
|
+
darwinBackend = {
|
|
27623
|
+
id: "seatbelt",
|
|
27624
|
+
probe: () => darwinProbe(process.platform, (p3) => existsSync7(p3)),
|
|
27625
|
+
wrap: (spec, program, argv) => ({
|
|
27626
|
+
program: SANDBOX_EXEC_PATH,
|
|
27627
|
+
argv: ["-p", buildSeatbeltProfile(spec), program, ...argv]
|
|
27628
|
+
})
|
|
27629
|
+
};
|
|
27630
|
+
}
|
|
27631
|
+
});
|
|
27632
|
+
|
|
27633
|
+
// src/cli/safety/jails/linux.ts
|
|
27634
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
27635
|
+
function findBinaryOnPath(bin, pathValue, exists) {
|
|
27636
|
+
for (const dir of pathValue.split(/[:;]/)) {
|
|
27637
|
+
if (!dir) continue;
|
|
27638
|
+
const full = `${dir}/${bin}`;
|
|
27639
|
+
if (exists(full)) return full;
|
|
27640
|
+
}
|
|
27641
|
+
return null;
|
|
27642
|
+
}
|
|
27643
|
+
function linuxProbe(platform, pathValue, exists) {
|
|
27644
|
+
if (platform !== "linux") {
|
|
27645
|
+
return { backend: "bwrap", available: false, reason: `platform ${platform} is not linux` };
|
|
27646
|
+
}
|
|
27647
|
+
const found = findBinaryOnPath(BWRAP_BIN, pathValue, exists);
|
|
27648
|
+
if (!found) {
|
|
27649
|
+
return {
|
|
27650
|
+
backend: "bwrap",
|
|
27651
|
+
available: false,
|
|
27652
|
+
reason: `${BWRAP_BIN} not found on PATH (landlock needs native syscalls Node does not expose)`
|
|
27653
|
+
};
|
|
27654
|
+
}
|
|
27655
|
+
return { backend: "bwrap", available: true, reason: `${BWRAP_BIN} found at ${found}` };
|
|
27656
|
+
}
|
|
27657
|
+
function buildBwrapArgs(spec, program, argv) {
|
|
27658
|
+
const args = ["--ro-bind", "/", "/", "--dev", "/dev", "--proc", "/proc"];
|
|
27659
|
+
for (const dir of spec.writable) {
|
|
27660
|
+
args.push("--bind-try", dir, dir);
|
|
27661
|
+
}
|
|
27662
|
+
if (spec.network.mode === "deny") {
|
|
27663
|
+
args.push("--unshare-net");
|
|
27664
|
+
}
|
|
27665
|
+
args.push("--", program, ...argv);
|
|
27666
|
+
return args;
|
|
27667
|
+
}
|
|
27668
|
+
var BWRAP_BIN, linuxBackend;
|
|
27669
|
+
var init_linux = __esm({
|
|
27670
|
+
"src/cli/safety/jails/linux.ts"() {
|
|
27671
|
+
"use strict";
|
|
27672
|
+
BWRAP_BIN = "bwrap";
|
|
27673
|
+
linuxBackend = {
|
|
27674
|
+
id: "bwrap",
|
|
27675
|
+
probe: () => linuxProbe(process.platform, process.env.PATH ?? "", (p3) => existsSync8(p3)),
|
|
27676
|
+
wrap: (spec, program, argv) => ({
|
|
27677
|
+
program: BWRAP_BIN,
|
|
27678
|
+
argv: buildBwrapArgs(spec, program, argv)
|
|
27679
|
+
})
|
|
27680
|
+
};
|
|
27681
|
+
}
|
|
27682
|
+
});
|
|
27683
|
+
|
|
27684
|
+
// src/cli/safety/jails/win32.ts
|
|
27685
|
+
function win32Probe(platform) {
|
|
27686
|
+
if (platform !== "win32") {
|
|
27687
|
+
return { backend: "win32-restricted-token", available: false, reason: `platform ${platform} is not win32` };
|
|
27688
|
+
}
|
|
27689
|
+
return { backend: "win32-restricted-token", available: false, reason: WIN32_UNAVAILABLE_REASON };
|
|
27690
|
+
}
|
|
27691
|
+
var WIN32_UNAVAILABLE_REASON, win32Backend;
|
|
27692
|
+
var init_win32 = __esm({
|
|
27693
|
+
"src/cli/safety/jails/win32.ts"() {
|
|
27694
|
+
"use strict";
|
|
27695
|
+
WIN32_UNAVAILABLE_REASON = "restricted-token + Job Object require native Windows APIs that pure Node does not expose (no native npm deps allowed, P5) \u2014 honest unavailable; see src/cli/safety/jails/win32.ts";
|
|
27696
|
+
win32Backend = {
|
|
27697
|
+
id: "win32-restricted-token",
|
|
27698
|
+
probe: () => win32Probe(process.platform),
|
|
27699
|
+
wrap: () => {
|
|
27700
|
+
throw new Error(`win32 jail backend unavailable: ${WIN32_UNAVAILABLE_REASON}`);
|
|
27701
|
+
}
|
|
27702
|
+
};
|
|
27703
|
+
}
|
|
27704
|
+
});
|
|
27705
|
+
|
|
27706
|
+
// src/cli/safety/osJail.ts
|
|
27707
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
27708
|
+
import { homedir as homedir4, tmpdir } from "node:os";
|
|
27709
|
+
import path27 from "node:path";
|
|
27710
|
+
function resolveJailMode(override, env = process.env) {
|
|
27711
|
+
const v = override?.trim().toLowerCase();
|
|
27712
|
+
if (v === "off") return "off";
|
|
27713
|
+
if (v === "advisory") return "advisory";
|
|
27714
|
+
if (v === "required") return "required";
|
|
27715
|
+
const strictIntent = activePolicyLoadMode(env) === "strict" || (env.ZELARI_PERMISSION_PRESET ?? "").trim().toLowerCase() === "strict";
|
|
27716
|
+
if (!strictIntent) return "advisory";
|
|
27717
|
+
return probeJailBackend().available ? "required" : "advisory";
|
|
27718
|
+
}
|
|
27719
|
+
function activeJailMode(env = process.env) {
|
|
27720
|
+
return resolveJailMode(env[OS_JAIL_ENV], env);
|
|
27721
|
+
}
|
|
27722
|
+
function platformBackend(platform = process.platform) {
|
|
27723
|
+
switch (platform) {
|
|
27724
|
+
case "darwin":
|
|
27725
|
+
return darwinBackend;
|
|
27726
|
+
case "linux":
|
|
27727
|
+
return linuxBackend;
|
|
27728
|
+
default:
|
|
27729
|
+
return win32Backend;
|
|
27730
|
+
}
|
|
27731
|
+
}
|
|
27732
|
+
function currentBackend(platform = process.platform) {
|
|
27733
|
+
return testBackend ?? platformBackend(platform);
|
|
27734
|
+
}
|
|
27735
|
+
function probeJailBackend(platform = process.platform) {
|
|
27736
|
+
if (testBackend) return testBackend.probe();
|
|
27737
|
+
if (!probeCache || probeCache.platform !== platform) {
|
|
27738
|
+
probeCache = { platform, result: platformBackend(platform).probe() };
|
|
27739
|
+
}
|
|
27740
|
+
return probeCache.result;
|
|
27741
|
+
}
|
|
27742
|
+
function defaultEnvAllowlist(platform = process.platform) {
|
|
27743
|
+
return platform === "win32" ? [...BASE_ENV_ALLOWLIST, ...WIN32_ENV_ALLOWLIST] : BASE_ENV_ALLOWLIST;
|
|
27744
|
+
}
|
|
27745
|
+
function defaultWritable(root, home = homedir4(), tmp = tmpdir(), platform = process.platform) {
|
|
27746
|
+
const raw = [path27.resolve(root), path27.resolve(tmp), path27.join(home, ".zelari-code")];
|
|
27747
|
+
const out = [];
|
|
27748
|
+
for (const p3 of raw) {
|
|
27749
|
+
const key = platform === "win32" ? p3.toLowerCase() : p3;
|
|
27750
|
+
if (!out.some((q) => (platform === "win32" ? q.toLowerCase() : q) === key)) out.push(p3);
|
|
27751
|
+
}
|
|
27752
|
+
return out;
|
|
27753
|
+
}
|
|
27754
|
+
function buildJailSpec(opts) {
|
|
27755
|
+
return {
|
|
27756
|
+
root: path27.resolve(opts.root),
|
|
27757
|
+
network: opts.network ?? { mode: "deny" },
|
|
27758
|
+
envAllowlist: opts.envAllowlist ?? defaultEnvAllowlist(),
|
|
27759
|
+
writable: opts.writable ?? defaultWritable(opts.root)
|
|
27760
|
+
};
|
|
27761
|
+
}
|
|
27762
|
+
function networkSpecFromClaimHosts(allowedHosts) {
|
|
27763
|
+
if (!allowedHosts || allowedHosts.length === 0) return { mode: "deny" };
|
|
27764
|
+
return { mode: "allow-list", hosts: [...new Set(allowedHosts)] };
|
|
27765
|
+
}
|
|
27766
|
+
function sanitizeEnv(env, allowlist, platform = process.platform) {
|
|
27767
|
+
const wanted = new Set(allowlist.map((k) => platform === "win32" ? k.toLowerCase() : k));
|
|
27768
|
+
const out = {};
|
|
27769
|
+
for (const [k, v] of Object.entries(env)) {
|
|
27770
|
+
if (v === void 0) continue;
|
|
27771
|
+
const key = platform === "win32" ? k.toLowerCase() : k;
|
|
27772
|
+
if (wanted.has(key)) out[k] = v;
|
|
27773
|
+
}
|
|
27774
|
+
return out;
|
|
27775
|
+
}
|
|
27776
|
+
function jailDenyReason(probe, mode) {
|
|
27777
|
+
return `OS jail backend unavailable (${probe.backend}: ${probe.reason}) with ZELARI_OS_JAIL=${mode} \u2014 execution is DENIED instead of running unjailed (t28 golden rule: missing backend + required \u21D2 deny, never warn/skip). Set ZELARI_OS_JAIL=advisory (visible fail-open) or =off to explicitly allow unjailed execution.`;
|
|
27778
|
+
}
|
|
27779
|
+
function jailAdvisoryNotice(probe) {
|
|
27780
|
+
return `advisory: OS jail backend unavailable (${probe.backend}: ${probe.reason}) \u2014 this process will run UNJAILED (visible fail-open). Set ZELARI_OS_JAIL=required to deny instead.`;
|
|
27781
|
+
}
|
|
27782
|
+
function decideJailSpawn(spec, input) {
|
|
27783
|
+
const mode = input.mode ?? activeJailMode();
|
|
27784
|
+
const merged = { ...input.env ?? process.env, ...input.envExtras ?? {} };
|
|
27785
|
+
if (mode === "off") return { action: "spawn-plain", env: merged };
|
|
27786
|
+
const probe = probeJailBackend();
|
|
27787
|
+
if (!probe.available) {
|
|
27788
|
+
if (mode === "required") return { action: "deny", reason: jailDenyReason(probe, mode) };
|
|
27789
|
+
return { action: "spawn-plain", env: sanitizeEnv(merged, spec.envAllowlist), notice: jailAdvisoryNotice(probe) };
|
|
27790
|
+
}
|
|
27791
|
+
const wrapped = currentBackend().wrap(spec, input.program, input.argv);
|
|
27792
|
+
return {
|
|
27793
|
+
action: "spawn-jailed",
|
|
27794
|
+
probe,
|
|
27795
|
+
program: wrapped.program,
|
|
27796
|
+
argv: wrapped.argv,
|
|
27797
|
+
env: sanitizeEnv(merged, spec.envAllowlist)
|
|
27798
|
+
};
|
|
27799
|
+
}
|
|
27800
|
+
function spawnJailed(spec, req) {
|
|
27801
|
+
const decision = decideJailSpawn(spec, {
|
|
27802
|
+
program: req.program,
|
|
27803
|
+
argv: req.argv,
|
|
27804
|
+
env: req.env,
|
|
27805
|
+
envExtras: req.envExtras
|
|
27806
|
+
});
|
|
27807
|
+
if (decision.action === "deny") {
|
|
27808
|
+
return { outcome: "denied", reason: `[jail] ${decision.reason}` };
|
|
27809
|
+
}
|
|
27810
|
+
const notice = decision.action === "spawn-plain" ? decision.notice : void 0;
|
|
27811
|
+
if (notice) {
|
|
27812
|
+
console.error(`[os-jail] ${notice}`);
|
|
27813
|
+
req.onNotice?.(notice);
|
|
27814
|
+
}
|
|
27815
|
+
const jailed = decision.action === "spawn-jailed";
|
|
27816
|
+
const program = jailed ? decision.program : req.program;
|
|
27817
|
+
const argv = jailed ? decision.argv : [...req.argv];
|
|
27818
|
+
try {
|
|
27819
|
+
const child = spawn4(program, argv, {
|
|
27820
|
+
cwd: req.cwd,
|
|
27821
|
+
signal: req.signal,
|
|
27822
|
+
shell: false,
|
|
27823
|
+
env: decision.env,
|
|
27824
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
27825
|
+
// non-interactive by construction
|
|
27826
|
+
});
|
|
27827
|
+
return {
|
|
27828
|
+
outcome: "spawned",
|
|
27829
|
+
child,
|
|
27830
|
+
backend: jailed ? decision.probe.backend : "none",
|
|
27831
|
+
jailed,
|
|
27832
|
+
...notice ? { notice } : {}
|
|
27833
|
+
};
|
|
27834
|
+
} catch (err) {
|
|
27835
|
+
return { outcome: "failed", reason: err instanceof Error ? err.message : String(err) };
|
|
27836
|
+
}
|
|
27837
|
+
}
|
|
27838
|
+
function jailAvailability(env = process.env) {
|
|
27839
|
+
const mode = activeJailMode(env);
|
|
27840
|
+
const probe = mode === "off" ? { backend: "none", available: false, reason: "jail disabled (ZELARI_OS_JAIL=off)" } : probeJailBackend();
|
|
27841
|
+
return { mode, probe };
|
|
27842
|
+
}
|
|
27843
|
+
var OS_JAIL_ENV, testBackend, probeCache, BASE_ENV_ALLOWLIST, WIN32_ENV_ALLOWLIST;
|
|
27844
|
+
var init_osJail = __esm({
|
|
27845
|
+
"src/cli/safety/osJail.ts"() {
|
|
27846
|
+
"use strict";
|
|
27847
|
+
init_policyLoadMode();
|
|
27848
|
+
init_darwin();
|
|
27849
|
+
init_linux();
|
|
27850
|
+
init_win32();
|
|
27851
|
+
OS_JAIL_ENV = "ZELARI_OS_JAIL";
|
|
27852
|
+
testBackend = null;
|
|
27853
|
+
probeCache = null;
|
|
27854
|
+
BASE_ENV_ALLOWLIST = [
|
|
27855
|
+
"PATH",
|
|
27856
|
+
"HOME",
|
|
27857
|
+
"USER",
|
|
27858
|
+
"LANG",
|
|
27859
|
+
"CI",
|
|
27860
|
+
"TERM",
|
|
27861
|
+
"NO_COLOR"
|
|
27862
|
+
];
|
|
27863
|
+
WIN32_ENV_ALLOWLIST = [
|
|
27864
|
+
"PATH",
|
|
27865
|
+
"Path",
|
|
27866
|
+
"HOMEDRIVE",
|
|
27867
|
+
"HOMEPATH",
|
|
27868
|
+
"SystemRoot",
|
|
27869
|
+
"SystemDrive",
|
|
27870
|
+
"ComSpec",
|
|
27871
|
+
"PATHEXT",
|
|
27872
|
+
"TEMP",
|
|
27873
|
+
"TMP",
|
|
27874
|
+
"APPDATA",
|
|
27875
|
+
"LOCALAPPDATA",
|
|
27876
|
+
"USERPROFILE",
|
|
27877
|
+
"USERNAME",
|
|
27878
|
+
"MSYSTEM",
|
|
27879
|
+
"PROGRAMFILES",
|
|
27880
|
+
"ProgramFiles",
|
|
27881
|
+
"ProgramData",
|
|
27882
|
+
"OS",
|
|
27883
|
+
"NUMBER_OF_PROCESSORS",
|
|
27884
|
+
"PROCESSOR_ARCHITECTURE",
|
|
27885
|
+
"WINDIR"
|
|
27886
|
+
];
|
|
27887
|
+
}
|
|
27888
|
+
});
|
|
27889
|
+
|
|
27408
27890
|
// packages/core/dist/shared/events.js
|
|
27409
27891
|
function isBrainAgentStartEvent(e) {
|
|
27410
27892
|
return e.type === "agent_start";
|
|
@@ -29461,7 +29943,7 @@ var init_providerStream = __esm({
|
|
|
29461
29943
|
|
|
29462
29944
|
// packages/core/dist/core/sessionJsonl.js
|
|
29463
29945
|
import { promises as fs13 } from "node:fs";
|
|
29464
|
-
import
|
|
29946
|
+
import path28 from "node:path";
|
|
29465
29947
|
import os from "node:os";
|
|
29466
29948
|
async function readSession(filePath) {
|
|
29467
29949
|
try {
|
|
@@ -29487,7 +29969,7 @@ async function readSession(filePath) {
|
|
|
29487
29969
|
}
|
|
29488
29970
|
}
|
|
29489
29971
|
function defaultBaseDir() {
|
|
29490
|
-
return
|
|
29972
|
+
return path28.join(os.tmpdir(), "zelari-code", "sessions");
|
|
29491
29973
|
}
|
|
29492
29974
|
var MAX_PENDING_EVENTS, MAX_PENDING_BYTES, DEFAULT_FLUSH_INTERVAL_MS, SessionJsonlWriter;
|
|
29493
29975
|
var init_sessionJsonl = __esm({
|
|
@@ -29513,7 +29995,7 @@ var init_sessionJsonl = __esm({
|
|
|
29513
29995
|
idleWaiters = [];
|
|
29514
29996
|
constructor(sessionId2, options = {}) {
|
|
29515
29997
|
const baseDir = options.baseDir ?? defaultBaseDir();
|
|
29516
|
-
this.filePath =
|
|
29998
|
+
this.filePath = path28.join(baseDir, `${sessionId2}.jsonl`);
|
|
29517
29999
|
this.onError = options.onError ?? console.error;
|
|
29518
30000
|
this.flushIntervalMs = options.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
|
|
29519
30001
|
}
|
|
@@ -29524,7 +30006,7 @@ var init_sessionJsonl = __esm({
|
|
|
29524
30006
|
/** Ensure the parent directory exists — once per writer lifetime. */
|
|
29525
30007
|
ensureDir() {
|
|
29526
30008
|
if (!this.dirEnsured) {
|
|
29527
|
-
this.dirEnsured = fs13.mkdir(
|
|
30009
|
+
this.dirEnsured = fs13.mkdir(path28.dirname(this.filePath), { recursive: true }).then(() => void 0).catch((err) => {
|
|
29528
30010
|
this.dirEnsured = null;
|
|
29529
30011
|
throw err;
|
|
29530
30012
|
});
|
|
@@ -29686,9 +30168,9 @@ var init_types6 = __esm({
|
|
|
29686
30168
|
});
|
|
29687
30169
|
|
|
29688
30170
|
// packages/core/dist/core/hooks/lifecycleHookRunner.js
|
|
29689
|
-
import { spawn as
|
|
30171
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
29690
30172
|
import { readdirSync as readdirSync2, readFileSync as readFileSync7 } from "node:fs";
|
|
29691
|
-
import
|
|
30173
|
+
import path29 from "node:path";
|
|
29692
30174
|
function parseJson(text) {
|
|
29693
30175
|
try {
|
|
29694
30176
|
return JSON.parse(text);
|
|
@@ -29768,14 +30250,14 @@ var init_lifecycleHookRunner = __esm({
|
|
|
29768
30250
|
}
|
|
29769
30251
|
let loaded = 0;
|
|
29770
30252
|
for (const f of files) {
|
|
29771
|
-
const full =
|
|
30253
|
+
const full = path29.join(dir, f);
|
|
29772
30254
|
try {
|
|
29773
30255
|
const parsed = parseJson(readFileSync7(full, "utf8"));
|
|
29774
30256
|
if (!parsed || !parsed.name || !parsed.match) {
|
|
29775
30257
|
this.logger(`skipping invalid hook file ${full}`);
|
|
29776
30258
|
continue;
|
|
29777
30259
|
}
|
|
29778
|
-
parsed.name = parsed.name ||
|
|
30260
|
+
parsed.name = parsed.name || path29.basename(f, ".json");
|
|
29779
30261
|
this.hooks.push(parsed);
|
|
29780
30262
|
loaded += 1;
|
|
29781
30263
|
} catch (err) {
|
|
@@ -29897,7 +30379,7 @@ var init_lifecycleHookRunner = __esm({
|
|
|
29897
30379
|
reject(new Error("empty hook command"));
|
|
29898
30380
|
return;
|
|
29899
30381
|
}
|
|
29900
|
-
const child =
|
|
30382
|
+
const child = spawn5(argv[0], argv.slice(1), {
|
|
29901
30383
|
shell: false,
|
|
29902
30384
|
cwd,
|
|
29903
30385
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -30726,7 +31208,7 @@ var init_parseCssMotion = __esm({
|
|
|
30726
31208
|
});
|
|
30727
31209
|
|
|
30728
31210
|
// packages/core/dist/council/verification/citeVerify.js
|
|
30729
|
-
import { existsSync as
|
|
31211
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8 } from "node:fs";
|
|
30730
31212
|
import { join as join4 } from "node:path";
|
|
30731
31213
|
function extractCitations(text) {
|
|
30732
31214
|
const out = [];
|
|
@@ -30750,7 +31232,7 @@ function verifyCitations(projectRoot, synthesisText) {
|
|
|
30750
31232
|
const results = [];
|
|
30751
31233
|
for (const cite of extractCitations(synthesisText)) {
|
|
30752
31234
|
const abs = join4(projectRoot, cite.file);
|
|
30753
|
-
if (!
|
|
31235
|
+
if (!existsSync9(abs)) {
|
|
30754
31236
|
results.push({
|
|
30755
31237
|
id: "synthesis.cite-invalid",
|
|
30756
31238
|
severity: "error",
|
|
@@ -31069,11 +31551,11 @@ var init_synthesisAudit = __esm({
|
|
|
31069
31551
|
});
|
|
31070
31552
|
|
|
31071
31553
|
// packages/core/dist/council/verification/runChecks.js
|
|
31072
|
-
import { existsSync as
|
|
31554
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
|
|
31073
31555
|
import { join as join5 } from "node:path";
|
|
31074
31556
|
function loadNfrSpec(zelariRoot) {
|
|
31075
31557
|
const path99 = join5(zelariRoot, "nfr-spec.json");
|
|
31076
|
-
if (!
|
|
31558
|
+
if (!existsSync10(path99))
|
|
31077
31559
|
return null;
|
|
31078
31560
|
try {
|
|
31079
31561
|
const raw = JSON.parse(readFileSync9(path99, "utf8"));
|
|
@@ -31087,11 +31569,11 @@ function loadNfrSpec(zelariRoot) {
|
|
|
31087
31569
|
function resolveTargets(projectRoot, spec) {
|
|
31088
31570
|
const found = [];
|
|
31089
31571
|
for (const rel2 of spec.targets) {
|
|
31090
|
-
if (
|
|
31572
|
+
if (existsSync10(join5(projectRoot, rel2))) {
|
|
31091
31573
|
found.push(rel2);
|
|
31092
31574
|
}
|
|
31093
31575
|
}
|
|
31094
|
-
if (found.length === 0 &&
|
|
31576
|
+
if (found.length === 0 && existsSync10(join5(projectRoot, "index.html"))) {
|
|
31095
31577
|
return ["index.html"];
|
|
31096
31578
|
}
|
|
31097
31579
|
return found;
|
|
@@ -31147,7 +31629,7 @@ function checkDeadCssHooks(html, relFile) {
|
|
|
31147
31629
|
}
|
|
31148
31630
|
function checkPlanReality(projectRoot, zelariRoot, targets, keywords) {
|
|
31149
31631
|
const planPath = join5(zelariRoot, "plan.json");
|
|
31150
|
-
if (!
|
|
31632
|
+
if (!existsSync10(planPath) || keywords.length === 0)
|
|
31151
31633
|
return [];
|
|
31152
31634
|
let plan;
|
|
31153
31635
|
try {
|
|
@@ -31187,11 +31669,11 @@ function checkPlanReality(projectRoot, zelariRoot, targets, keywords) {
|
|
|
31187
31669
|
}
|
|
31188
31670
|
function checkReadmeStale(projectRoot, targets) {
|
|
31189
31671
|
const readmePath = join5(projectRoot, "README.md");
|
|
31190
|
-
if (!
|
|
31672
|
+
if (!existsSync10(readmePath) || targets.length === 0)
|
|
31191
31673
|
return [];
|
|
31192
31674
|
const readme = readFileSync9(readmePath, "utf8");
|
|
31193
31675
|
const htmlPath = join5(projectRoot, targets[0]);
|
|
31194
|
-
if (!
|
|
31676
|
+
if (!existsSync10(htmlPath))
|
|
31195
31677
|
return [];
|
|
31196
31678
|
const html = readFileSync9(htmlPath, "utf8");
|
|
31197
31679
|
const sectionCount = (html.match(/<section\s+id=/gi) ?? []).length;
|
|
@@ -31317,7 +31799,7 @@ var init_runChecks = __esm({
|
|
|
31317
31799
|
});
|
|
31318
31800
|
|
|
31319
31801
|
// packages/core/dist/council/verification/microGate.js
|
|
31320
|
-
import { existsSync as
|
|
31802
|
+
import { existsSync as existsSync11, readFileSync as readFileSync10 } from "node:fs";
|
|
31321
31803
|
import { join as join6 } from "node:path";
|
|
31322
31804
|
function checkDeadHooksInHtml(html) {
|
|
31323
31805
|
const warnings = [];
|
|
@@ -31347,7 +31829,7 @@ function checkDeadHooksInHtml(html) {
|
|
|
31347
31829
|
}
|
|
31348
31830
|
function runMicroVerificationOnFile(projectRoot, relPath, zelariRoot) {
|
|
31349
31831
|
const abs = join6(projectRoot, relPath);
|
|
31350
|
-
if (!
|
|
31832
|
+
if (!existsSync11(abs) || !/\.html?$/i.test(relPath))
|
|
31351
31833
|
return [];
|
|
31352
31834
|
const spec = (zelariRoot ? loadNfrSpec(zelariRoot) : null) ?? DEFAULT_NFR_SPEC;
|
|
31353
31835
|
const anim = spec.animation ?? { compositorOnly: true, forbidLayoutProps: true };
|
|
@@ -31791,7 +32273,7 @@ var init_inlineJsAutofix = __esm({
|
|
|
31791
32273
|
});
|
|
31792
32274
|
|
|
31793
32275
|
// packages/core/dist/agents/councilApi.js
|
|
31794
|
-
import { existsSync as
|
|
32276
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
31795
32277
|
import { join as join8 } from "node:path";
|
|
31796
32278
|
function extractBalancedJsonObject(s) {
|
|
31797
32279
|
const start = s.indexOf("{");
|
|
@@ -32419,7 +32901,7 @@ async function* runCouncilPure(userMessage, config2, callbacks = {}) {
|
|
|
32419
32901
|
const zelariRoot = `${chairmanProjectRoot}/.zelari`;
|
|
32420
32902
|
const spec = loadNfrSpec(zelariRoot) ?? DEFAULT_NFR_SPEC;
|
|
32421
32903
|
for (const rel2 of spec.targets) {
|
|
32422
|
-
if (!
|
|
32904
|
+
if (!existsSync12(join8(chairmanProjectRoot, rel2)))
|
|
32423
32905
|
continue;
|
|
32424
32906
|
changedTargetFiles.add(rel2);
|
|
32425
32907
|
for (const w of runChairmanMicroGate({ projectRoot: chairmanProjectRoot, relPath: rel2, zelariRoot })) {
|
|
@@ -32439,7 +32921,7 @@ async function* runCouncilPure(userMessage, config2, callbacks = {}) {
|
|
|
32439
32921
|
const zelariRootReplay = `${chairmanProjectRoot}/.zelari`;
|
|
32440
32922
|
const specReplay = loadNfrSpec(zelariRootReplay) ?? DEFAULT_NFR_SPEC;
|
|
32441
32923
|
for (const rel2 of specReplay.targets) {
|
|
32442
|
-
if (!
|
|
32924
|
+
if (!existsSync12(join8(chairmanProjectRoot, rel2)))
|
|
32443
32925
|
continue;
|
|
32444
32926
|
changedTargetFiles.add(rel2);
|
|
32445
32927
|
for (const w of runChairmanMicroGate({
|
|
@@ -37549,7 +38031,7 @@ var CORE_VERSION;
|
|
|
37549
38031
|
var init_version = __esm({
|
|
37550
38032
|
"packages/core/dist/version.js"() {
|
|
37551
38033
|
"use strict";
|
|
37552
|
-
CORE_VERSION = "2.
|
|
38034
|
+
CORE_VERSION = "2.32.0";
|
|
37553
38035
|
}
|
|
37554
38036
|
});
|
|
37555
38037
|
|
|
@@ -38252,8 +38734,8 @@ var init_graphStatus = __esm({
|
|
|
38252
38734
|
});
|
|
38253
38735
|
|
|
38254
38736
|
// src/cli/sessionManager.ts
|
|
38255
|
-
import { promises as fs14, existsSync as
|
|
38256
|
-
import
|
|
38737
|
+
import { promises as fs14, existsSync as existsSync13, readFileSync as readFileSync15, writeFileSync as writeFileSync11, mkdirSync as mkdirSync6, unlinkSync as unlinkSync2, statSync } from "node:fs";
|
|
38738
|
+
import path30 from "node:path";
|
|
38257
38739
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
38258
38740
|
function getSessionBaseDir() {
|
|
38259
38741
|
return sessionsDir();
|
|
@@ -38266,7 +38748,7 @@ async function ensureSessionDir() {
|
|
|
38266
38748
|
}
|
|
38267
38749
|
function getCurrentSessionId() {
|
|
38268
38750
|
const file2 = getCurrentSessionFile();
|
|
38269
|
-
if (!
|
|
38751
|
+
if (!existsSync13(file2)) return null;
|
|
38270
38752
|
try {
|
|
38271
38753
|
const content = readFileSync15(file2, "utf-8").trim();
|
|
38272
38754
|
return content.length > 0 ? content : null;
|
|
@@ -38276,7 +38758,7 @@ function getCurrentSessionId() {
|
|
|
38276
38758
|
}
|
|
38277
38759
|
function setCurrentSessionId(id3) {
|
|
38278
38760
|
const file2 = getCurrentSessionFile();
|
|
38279
|
-
mkdirSync6(
|
|
38761
|
+
mkdirSync6(path30.dirname(file2), { recursive: true });
|
|
38280
38762
|
writeFileSync11(file2, id3, "utf-8");
|
|
38281
38763
|
}
|
|
38282
38764
|
function clearCurrentSessionId() {
|
|
@@ -38288,11 +38770,11 @@ function clearCurrentSessionId() {
|
|
|
38288
38770
|
}
|
|
38289
38771
|
}
|
|
38290
38772
|
function getCurrentBranchFile() {
|
|
38291
|
-
return process.env.ANATHEMA_CURRENT_BRANCH_FILE ??
|
|
38773
|
+
return process.env.ANATHEMA_CURRENT_BRANCH_FILE ?? path30.join(path30.dirname(getCurrentSessionFile()), "currentBranch.txt");
|
|
38292
38774
|
}
|
|
38293
38775
|
function getCurrentBranch() {
|
|
38294
38776
|
const file2 = getCurrentBranchFile();
|
|
38295
|
-
if (!
|
|
38777
|
+
if (!existsSync13(file2)) return null;
|
|
38296
38778
|
try {
|
|
38297
38779
|
const content = readFileSync15(file2, "utf-8").trim();
|
|
38298
38780
|
return content.length > 0 ? content : null;
|
|
@@ -38302,7 +38784,7 @@ function getCurrentBranch() {
|
|
|
38302
38784
|
}
|
|
38303
38785
|
function setCurrentBranch(name) {
|
|
38304
38786
|
const file2 = getCurrentBranchFile();
|
|
38305
|
-
mkdirSync6(
|
|
38787
|
+
mkdirSync6(path30.dirname(file2), { recursive: true });
|
|
38306
38788
|
writeFileSync11(file2, name, "utf-8");
|
|
38307
38789
|
}
|
|
38308
38790
|
function newSessionId() {
|
|
@@ -38321,7 +38803,7 @@ async function listSessions() {
|
|
|
38321
38803
|
for (const entry of entries) {
|
|
38322
38804
|
if (!entry.endsWith(".jsonl")) continue;
|
|
38323
38805
|
const id3 = entry.replace(/\.jsonl$/, "");
|
|
38324
|
-
const filePath =
|
|
38806
|
+
const filePath = path30.join(baseDir, entry);
|
|
38325
38807
|
try {
|
|
38326
38808
|
const events = await readSession(filePath);
|
|
38327
38809
|
let firstTs = 0;
|
|
@@ -38368,7 +38850,7 @@ ${lines.join("\n")}`
|
|
|
38368
38850
|
return { message: `[${kind2}] handled` };
|
|
38369
38851
|
}
|
|
38370
38852
|
async function loadSessionEvents(id3) {
|
|
38371
|
-
const filePath =
|
|
38853
|
+
const filePath = path30.join(getSessionBaseDir(), `${id3}.jsonl`);
|
|
38372
38854
|
return readSession(filePath);
|
|
38373
38855
|
}
|
|
38374
38856
|
var init_sessionManager = __esm({
|
|
@@ -38701,16 +39183,16 @@ var init_budgetRuntime = __esm({
|
|
|
38701
39183
|
});
|
|
38702
39184
|
|
|
38703
39185
|
// src/cli/budget/restoreRuntime.ts
|
|
38704
|
-
import
|
|
39186
|
+
import path31 from "node:path";
|
|
38705
39187
|
async function restoreBudgetRuntimeFromSession(budget, sessionId2, baseDir) {
|
|
38706
|
-
const eventsPath =
|
|
39188
|
+
const eventsPath = path31.join(resolveSessionsDir({ baseDir }), sessionId2, "events.jsonl");
|
|
38707
39189
|
const report = await readSessionLog(eventsPath).catch(() => null);
|
|
38708
39190
|
if (!report || report.events.length === 0) return false;
|
|
38709
39191
|
budget.adoptLedgerFromEvents(report.events);
|
|
38710
39192
|
return true;
|
|
38711
39193
|
}
|
|
38712
39194
|
async function lastHarnessManifestHash(sessionId2, baseDir) {
|
|
38713
|
-
const eventsPath =
|
|
39195
|
+
const eventsPath = path31.join(resolveSessionsDir({ baseDir }), sessionId2, "events.jsonl");
|
|
38714
39196
|
const report = await readSessionLog(eventsPath).catch(() => null);
|
|
38715
39197
|
if (!report) return null;
|
|
38716
39198
|
for (let i = report.events.length - 1; i >= 0; i--) {
|
|
@@ -38759,21 +39241,21 @@ __export(updater_exports, {
|
|
|
38759
39241
|
resolveBundledNpmCli: () => resolveBundledNpmCli
|
|
38760
39242
|
});
|
|
38761
39243
|
import { createRequire } from "node:module";
|
|
38762
|
-
import { spawn as
|
|
38763
|
-
import { existsSync as
|
|
38764
|
-
import
|
|
39244
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
39245
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
39246
|
+
import path32 from "node:path";
|
|
38765
39247
|
import { fileURLToPath } from "node:url";
|
|
38766
39248
|
function resolveBundledNpmCli(execPath = process.execPath) {
|
|
38767
|
-
const dir =
|
|
39249
|
+
const dir = path32.dirname(execPath);
|
|
38768
39250
|
const candidates = [
|
|
38769
39251
|
// Windows: C:\...\node.exe → C:\...\node_modules\npm\bin\npm-cli.js
|
|
38770
|
-
|
|
39252
|
+
path32.join(dir, "node_modules", "npm", "bin", "npm-cli.js"),
|
|
38771
39253
|
// POSIX: <prefix>/bin/node → <prefix>/lib/node_modules/npm/bin/npm-cli.js
|
|
38772
|
-
|
|
39254
|
+
path32.join(dir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
|
|
38773
39255
|
];
|
|
38774
39256
|
for (const candidate of candidates) {
|
|
38775
39257
|
try {
|
|
38776
|
-
if (
|
|
39258
|
+
if (existsSync14(candidate)) return candidate;
|
|
38777
39259
|
} catch {
|
|
38778
39260
|
}
|
|
38779
39261
|
}
|
|
@@ -38786,7 +39268,7 @@ function looksLikeBrokenShim(exitCode, output) {
|
|
|
38786
39268
|
}
|
|
38787
39269
|
function getCurrentVersion() {
|
|
38788
39270
|
try {
|
|
38789
|
-
const pkgPath =
|
|
39271
|
+
const pkgPath = path32.resolve(__dirname2, "..", "..", "package.json");
|
|
38790
39272
|
const pkg = require2(pkgPath);
|
|
38791
39273
|
return pkg.version;
|
|
38792
39274
|
} catch {
|
|
@@ -38856,7 +39338,7 @@ async function checkForUpdate(fetcher = fetch, registryUrl) {
|
|
|
38856
39338
|
updateAvailable: cmp < 0
|
|
38857
39339
|
};
|
|
38858
39340
|
}
|
|
38859
|
-
async function performUpdate(packageName = "zelari-code", executor =
|
|
39341
|
+
async function performUpdate(packageName = "zelari-code", executor = spawn6, resolveNpmCli = resolveBundledNpmCli, channel) {
|
|
38860
39342
|
const tag = channel ?? distTagForVersion(getCurrentVersion());
|
|
38861
39343
|
const args = ["install", "-g", `${packageName}@${tag}`];
|
|
38862
39344
|
const primary = await runNpm(executor, args, "shim");
|
|
@@ -38909,7 +39391,7 @@ var init_updater = __esm({
|
|
|
38909
39391
|
"use strict";
|
|
38910
39392
|
init_cmdline();
|
|
38911
39393
|
require2 = createRequire(import.meta.url);
|
|
38912
|
-
__dirname2 =
|
|
39394
|
+
__dirname2 = path32.dirname(fileURLToPath(import.meta.url));
|
|
38913
39395
|
REGISTRY_URL = "https://registry.npmjs.org/zelari-code/latest";
|
|
38914
39396
|
}
|
|
38915
39397
|
});
|
|
@@ -39068,7 +39550,7 @@ var init_spineFileEvents = __esm({
|
|
|
39068
39550
|
});
|
|
39069
39551
|
|
|
39070
39552
|
// src/cli/sessionSpine.ts
|
|
39071
|
-
import
|
|
39553
|
+
import path33 from "node:path";
|
|
39072
39554
|
function spineEnabled() {
|
|
39073
39555
|
return process.env.ZELARI_SESSION_SPINE !== "0";
|
|
39074
39556
|
}
|
|
@@ -39267,8 +39749,8 @@ var init_sessionSpine = __esm({
|
|
|
39267
39749
|
const mirror = new _SessionSpineMirror(sessionId2, options);
|
|
39268
39750
|
if (!spineEnabled()) return mirror;
|
|
39269
39751
|
try {
|
|
39270
|
-
const sessionDir =
|
|
39271
|
-
const report = await readSessionLog(
|
|
39752
|
+
const sessionDir = path33.join(mirror.sessionsDir, sessionId2);
|
|
39753
|
+
const report = await readSessionLog(path33.join(sessionDir, "events.jsonl"));
|
|
39272
39754
|
const existed = report.events.length > 0 || report.issues.length > 0;
|
|
39273
39755
|
if (report.events.some((e) => e.kind === "task.contract" || e.kind === "user.message")) {
|
|
39274
39756
|
mirror.contractSeeded = true;
|
|
@@ -39444,7 +39926,7 @@ var init_sessionSpine = __esm({
|
|
|
39444
39926
|
async derivedPriorTurns() {
|
|
39445
39927
|
if (this.status !== "active" && this.status !== "closed") return null;
|
|
39446
39928
|
const report = await readSessionLog(
|
|
39447
|
-
|
|
39929
|
+
path33.join(this.sessionsDir, this.sessionId, "events.jsonl")
|
|
39448
39930
|
).catch(() => null);
|
|
39449
39931
|
if (!report || report.events.length === 0) return null;
|
|
39450
39932
|
return deriveMessages(report.events);
|
|
@@ -39454,7 +39936,7 @@ var init_sessionSpine = __esm({
|
|
|
39454
39936
|
if (this.status !== "active" && this.status !== "closed") return null;
|
|
39455
39937
|
await this.flush();
|
|
39456
39938
|
const report = await readSessionLog(
|
|
39457
|
-
|
|
39939
|
+
path33.join(this.sessionsDir, this.sessionId, "events.jsonl")
|
|
39458
39940
|
).catch(() => null);
|
|
39459
39941
|
if (!report || report.events.length === 0) return null;
|
|
39460
39942
|
return buildCompactionStateSnapshot(report.events, toSeq);
|
|
@@ -39467,7 +39949,7 @@ var init_sessionSpine = __esm({
|
|
|
39467
39949
|
async lastVerificationRun() {
|
|
39468
39950
|
if (this.status !== "active" && this.status !== "closed") return null;
|
|
39469
39951
|
const report = await readSessionLog(
|
|
39470
|
-
|
|
39952
|
+
path33.join(this.sessionsDir, this.sessionId, "events.jsonl")
|
|
39471
39953
|
).catch(() => null);
|
|
39472
39954
|
if (!report) return null;
|
|
39473
39955
|
return lastVerificationRun(report.events);
|
|
@@ -39602,7 +40084,7 @@ var init_sessionSpine = __esm({
|
|
|
39602
40084
|
if (steerText) {
|
|
39603
40085
|
seq = seq.then(async (s) => {
|
|
39604
40086
|
try {
|
|
39605
|
-
const eventsPath =
|
|
40087
|
+
const eventsPath = path33.join(this.sessionsDir, this.sessionId, "events.jsonl");
|
|
39606
40088
|
const report = await readSessionLog(eventsPath).catch(() => null);
|
|
39607
40089
|
if (!report || typeof s !== "number") return s;
|
|
39608
40090
|
const current = latestTaskContract(report.events);
|
|
@@ -39849,10 +40331,10 @@ var init_sessionSurface = __esm({
|
|
|
39849
40331
|
});
|
|
39850
40332
|
|
|
39851
40333
|
// src/cli/hooks/observationStore.ts
|
|
39852
|
-
import { existsSync as
|
|
39853
|
-
import
|
|
40334
|
+
import { existsSync as existsSync15, statSync as statSync2 } from "node:fs";
|
|
40335
|
+
import path34 from "node:path";
|
|
39854
40336
|
function sessionFilePath(sessionId2, baseDir) {
|
|
39855
|
-
return
|
|
40337
|
+
return path34.join(baseDir ?? getSessionBaseDir(), `${sessionId2}.jsonl`);
|
|
39856
40338
|
}
|
|
39857
40339
|
function isToolEnd(e) {
|
|
39858
40340
|
return e.type === "tool_execution_end";
|
|
@@ -39862,7 +40344,7 @@ function isToolStart(e) {
|
|
|
39862
40344
|
}
|
|
39863
40345
|
async function loadObservationIndex(sessionId2, baseDir) {
|
|
39864
40346
|
const filePath = sessionFilePath(sessionId2, baseDir);
|
|
39865
|
-
const exists =
|
|
40347
|
+
const exists = existsSync15(filePath);
|
|
39866
40348
|
let mtimeMs = 0;
|
|
39867
40349
|
if (exists) {
|
|
39868
40350
|
try {
|
|
@@ -39874,7 +40356,7 @@ async function loadObservationIndex(sessionId2, baseDir) {
|
|
|
39874
40356
|
const hit = cache.get(sessionId2);
|
|
39875
40357
|
if (hit && !exists) return hit;
|
|
39876
40358
|
if (hit && hit.filePath === filePath && hit.mtimeMs === mtimeMs) return hit;
|
|
39877
|
-
const events =
|
|
40359
|
+
const events = existsSync15(filePath) ? await readSession(filePath) : [];
|
|
39878
40360
|
const names = /* @__PURE__ */ new Map();
|
|
39879
40361
|
const bySeq = /* @__PURE__ */ new Map();
|
|
39880
40362
|
const byToolCallId = /* @__PURE__ */ new Map();
|
|
@@ -39972,17 +40454,17 @@ var init_observationStore = __esm({
|
|
|
39972
40454
|
|
|
39973
40455
|
// packages/core/dist/core/tools/toolOutputSpill.js
|
|
39974
40456
|
import { createHash as createHash11, randomBytes as randomBytes3 } from "node:crypto";
|
|
39975
|
-
import { existsSync as
|
|
39976
|
-
import { homedir as
|
|
40457
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync7, writeFileSync as writeFileSync12 } from "node:fs";
|
|
40458
|
+
import { homedir as homedir5, tmpdir as tmpdir2 } from "node:os";
|
|
39977
40459
|
import { join as join14 } from "node:path";
|
|
39978
40460
|
function resolveToolOutputDir() {
|
|
39979
40461
|
const fromEnv = process.env.ZELARI_TOOL_OUTPUT_DIR?.trim();
|
|
39980
40462
|
if (fromEnv)
|
|
39981
40463
|
return fromEnv;
|
|
39982
40464
|
try {
|
|
39983
|
-
return join14(
|
|
40465
|
+
return join14(homedir5(), ".tmp", "zelari-code", "tool-output");
|
|
39984
40466
|
} catch {
|
|
39985
|
-
return join14(
|
|
40467
|
+
return join14(tmpdir2(), "zelari-code", "tool-output");
|
|
39986
40468
|
}
|
|
39987
40469
|
}
|
|
39988
40470
|
function isToolSpillEnabled() {
|
|
@@ -39998,7 +40480,7 @@ function spillToolOutput(fullText, meta3) {
|
|
|
39998
40480
|
return null;
|
|
39999
40481
|
try {
|
|
40000
40482
|
const dir = resolveToolOutputDir();
|
|
40001
|
-
if (!
|
|
40483
|
+
if (!existsSync16(dir)) {
|
|
40002
40484
|
mkdirSync7(dir, { recursive: true });
|
|
40003
40485
|
}
|
|
40004
40486
|
const hash3 = createHash11("sha256").update(fullText).digest("hex").slice(0, 12);
|
|
@@ -40303,7 +40785,7 @@ var init_registry2 = __esm({
|
|
|
40303
40785
|
});
|
|
40304
40786
|
|
|
40305
40787
|
// src/cli/safety/sandboxPath.ts
|
|
40306
|
-
import
|
|
40788
|
+
import path35 from "node:path";
|
|
40307
40789
|
import fs15 from "node:fs";
|
|
40308
40790
|
function normalizedCase(p3) {
|
|
40309
40791
|
return IS_CASE_FOLDING ? p3.toLowerCase() : p3;
|
|
@@ -40312,7 +40794,7 @@ function isWithin(candidate, base2) {
|
|
|
40312
40794
|
const c = normalizedCase(candidate);
|
|
40313
40795
|
const b = normalizedCase(base2);
|
|
40314
40796
|
if (c === b) return true;
|
|
40315
|
-
const baseWithSep = b.endsWith(
|
|
40797
|
+
const baseWithSep = b.endsWith(path35.sep) ? b : b + path35.sep;
|
|
40316
40798
|
return c.startsWith(baseWithSep);
|
|
40317
40799
|
}
|
|
40318
40800
|
function escapeError(userPath, attempted, real, realRoot) {
|
|
@@ -40323,7 +40805,7 @@ function escapeError(userPath, attempted, real, realRoot) {
|
|
|
40323
40805
|
);
|
|
40324
40806
|
}
|
|
40325
40807
|
function assertLexicalContainment(resolved, root, userPath) {
|
|
40326
|
-
const rootWithSep = root.endsWith(
|
|
40808
|
+
const rootWithSep = root.endsWith(path35.sep) ? root : root + path35.sep;
|
|
40327
40809
|
if (resolved !== root && !resolved.startsWith(rootWithSep)) {
|
|
40328
40810
|
throw new SandboxViolationError(
|
|
40329
40811
|
`Path escapes sandbox root: ${userPath} \u2192 ${resolved} (root: ${root})`,
|
|
@@ -40336,13 +40818,13 @@ function assertRealAncestorContained(resolvedLexical, realRoot, userPath) {
|
|
|
40336
40818
|
let probe = resolvedLexical;
|
|
40337
40819
|
let realProbe = null;
|
|
40338
40820
|
for (; ; ) {
|
|
40339
|
-
if (probe ===
|
|
40821
|
+
if (probe === path35.dirname(probe)) break;
|
|
40340
40822
|
try {
|
|
40341
40823
|
realProbe = fs15.realpathSync(probe);
|
|
40342
40824
|
break;
|
|
40343
40825
|
} catch (err) {
|
|
40344
40826
|
if (err?.code === "ENOENT") {
|
|
40345
|
-
probe =
|
|
40827
|
+
probe = path35.dirname(probe);
|
|
40346
40828
|
continue;
|
|
40347
40829
|
}
|
|
40348
40830
|
return;
|
|
@@ -40361,8 +40843,8 @@ function resolveSandboxedCore(userPath, options = {}) {
|
|
|
40361
40843
|
if (typeof userPath !== "string" || userPath.length === 0) {
|
|
40362
40844
|
throw new SandboxViolationError("Empty path", userPath, "");
|
|
40363
40845
|
}
|
|
40364
|
-
const root =
|
|
40365
|
-
const resolved =
|
|
40846
|
+
const root = path35.resolve(options.root ?? process.cwd());
|
|
40847
|
+
const resolved = path35.isAbsolute(userPath) ? path35.resolve(userPath) : path35.resolve(root, userPath);
|
|
40366
40848
|
assertLexicalContainment(resolved, root, userPath);
|
|
40367
40849
|
let realRoot = null;
|
|
40368
40850
|
try {
|
|
@@ -40380,8 +40862,8 @@ function verifyContainment(resolvedAbsolute, options = {}) {
|
|
|
40380
40862
|
if (typeof resolvedAbsolute !== "string" || resolvedAbsolute.length === 0) {
|
|
40381
40863
|
throw new SandboxViolationError("Empty path", resolvedAbsolute, "");
|
|
40382
40864
|
}
|
|
40383
|
-
const root =
|
|
40384
|
-
const resolved =
|
|
40865
|
+
const root = path35.resolve(options.root ?? process.cwd());
|
|
40866
|
+
const resolved = path35.resolve(resolvedAbsolute);
|
|
40385
40867
|
assertLexicalContainment(resolved, root, resolvedAbsolute);
|
|
40386
40868
|
let realRoot = null;
|
|
40387
40869
|
try {
|
|
@@ -40409,19 +40891,19 @@ var init_sandboxPath = __esm({
|
|
|
40409
40891
|
});
|
|
40410
40892
|
|
|
40411
40893
|
// src/cli/tools/krakenRadio.ts
|
|
40412
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
40413
|
-
import
|
|
40894
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync16, readdirSync as readdirSync3 } from "node:fs";
|
|
40895
|
+
import path36 from "node:path";
|
|
40414
40896
|
function radioDir(cwd) {
|
|
40415
|
-
return
|
|
40897
|
+
return path36.join(cwd, ".zelari", "radio");
|
|
40416
40898
|
}
|
|
40417
40899
|
function radioPath(cwd, sessionId2) {
|
|
40418
40900
|
const safe = (sessionId2 || "default").replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
40419
|
-
return
|
|
40901
|
+
return path36.join(radioDir(cwd), `${safe}.jsonl`);
|
|
40420
40902
|
}
|
|
40421
40903
|
function appendKrakenRadio(cwd, sessionId2, event) {
|
|
40422
40904
|
try {
|
|
40423
40905
|
const dir = radioDir(cwd);
|
|
40424
|
-
if (!
|
|
40906
|
+
if (!existsSync17(dir)) mkdirSync8(dir, { recursive: true });
|
|
40425
40907
|
const row = {
|
|
40426
40908
|
ts: event.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
40427
40909
|
kind: event.kind,
|
|
@@ -40451,7 +40933,7 @@ function appendKrakenRadio(cwd, sessionId2, event) {
|
|
|
40451
40933
|
function readKrakenRadio(cwd, sessionId2, limit = 50) {
|
|
40452
40934
|
try {
|
|
40453
40935
|
const file2 = radioPath(cwd, sessionId2);
|
|
40454
|
-
if (!
|
|
40936
|
+
if (!existsSync17(file2)) return [];
|
|
40455
40937
|
const lines = readFileSync16(file2, "utf8").split(/\r?\n/).filter(Boolean);
|
|
40456
40938
|
const slice = lines.slice(-Math.max(1, limit));
|
|
40457
40939
|
const out = [];
|
|
@@ -40475,7 +40957,7 @@ function formatKrakenRadioStatus(cwd, sessionId2, limit = 12) {
|
|
|
40475
40957
|
const flag = e.ok === false ? "\u2717" : e.ok === true ? "\u2713" : "\xB7";
|
|
40476
40958
|
const ms = e.durationMs != null ? ` ${e.durationMs}ms` : "";
|
|
40477
40959
|
const model = e.model ? ` [${e.model}]` : "";
|
|
40478
|
-
const wt = e.worktree ? ` wt=${
|
|
40960
|
+
const wt = e.worktree ? ` wt=${path36.basename(e.worktree)}` : "";
|
|
40479
40961
|
const detail = e.detail ? ` \u2014 ${e.detail.slice(0, 120)}` : "";
|
|
40480
40962
|
return `${flag} ${e.ts.slice(11, 19)} ${e.kind} ${e.agent} "${e.description}"${model}${wt}${ms}${detail}`;
|
|
40481
40963
|
});
|
|
@@ -40491,7 +40973,7 @@ var init_krakenRadio = __esm({
|
|
|
40491
40973
|
import {
|
|
40492
40974
|
mkdirSync as mkdirSync9,
|
|
40493
40975
|
writeFileSync as writeFileSync13,
|
|
40494
|
-
existsSync as
|
|
40976
|
+
existsSync as existsSync18,
|
|
40495
40977
|
accessSync,
|
|
40496
40978
|
constants,
|
|
40497
40979
|
realpathSync
|
|
@@ -40517,7 +40999,7 @@ function hashProject(projectPath) {
|
|
|
40517
40999
|
}
|
|
40518
41000
|
function isWritableDir(dir) {
|
|
40519
41001
|
try {
|
|
40520
|
-
if (!
|
|
41002
|
+
if (!existsSync18(dir)) return false;
|
|
40521
41003
|
accessSync(dir, constants.W_OK);
|
|
40522
41004
|
return true;
|
|
40523
41005
|
} catch {
|
|
@@ -40526,9 +41008,9 @@ function isWritableDir(dir) {
|
|
|
40526
41008
|
}
|
|
40527
41009
|
function ensureWorkspaceDir(workspaceDir) {
|
|
40528
41010
|
mkdirSync9(workspaceDir, { recursive: true });
|
|
40529
|
-
if (workspaceDir.endsWith("/.zelari") &&
|
|
41011
|
+
if (workspaceDir.endsWith("/.zelari") && existsSync18(join15(workspaceDir, "..", ".git"))) {
|
|
40530
41012
|
const gitignorePath = join15(workspaceDir, ".gitignore");
|
|
40531
|
-
if (!
|
|
41013
|
+
if (!existsSync18(gitignorePath)) {
|
|
40532
41014
|
writeFileSync13(gitignorePath, "*\n!.gitignore\n");
|
|
40533
41015
|
}
|
|
40534
41016
|
}
|
|
@@ -40569,7 +41051,7 @@ __export(storage_exports, {
|
|
|
40569
41051
|
import {
|
|
40570
41052
|
readFileSync as readFileSync17,
|
|
40571
41053
|
writeFileSync as writeFileSync14,
|
|
40572
|
-
existsSync as
|
|
41054
|
+
existsSync as existsSync19,
|
|
40573
41055
|
mkdirSync as mkdirSync10,
|
|
40574
41056
|
readdirSync as readdirSync4,
|
|
40575
41057
|
renameSync as renameSync2
|
|
@@ -40829,7 +41311,7 @@ var init_storage = __esm({
|
|
|
40829
41311
|
Storage = class {
|
|
40830
41312
|
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
40831
41313
|
read(path99) {
|
|
40832
|
-
if (!
|
|
41314
|
+
if (!existsSync19(path99)) {
|
|
40833
41315
|
throw new Error(`File not found: ${path99}`);
|
|
40834
41316
|
}
|
|
40835
41317
|
const md = readFileSync17(path99, "utf8");
|
|
@@ -40837,7 +41319,7 @@ var init_storage = __esm({
|
|
|
40837
41319
|
}
|
|
40838
41320
|
/** Read a Markdown file; returns null if not found. */
|
|
40839
41321
|
readIfExists(path99) {
|
|
40840
|
-
if (!
|
|
41322
|
+
if (!existsSync19(path99)) return null;
|
|
40841
41323
|
return this.read(path99);
|
|
40842
41324
|
}
|
|
40843
41325
|
/**
|
|
@@ -40853,7 +41335,7 @@ var init_storage = __esm({
|
|
|
40853
41335
|
}
|
|
40854
41336
|
/** List all .md files in a directory (non-recursive). */
|
|
40855
41337
|
listMarkdown(dir) {
|
|
40856
|
-
if (!
|
|
41338
|
+
if (!existsSync19(dir)) return [];
|
|
40857
41339
|
return readdirSync4(dir).filter((f) => f.endsWith(".md") && !f.startsWith(".")).map((f) => join16(dir, f));
|
|
40858
41340
|
}
|
|
40859
41341
|
};
|
|
@@ -40886,7 +41368,7 @@ var init_storage = __esm({
|
|
|
40886
41368
|
// src/cli/workspace/planStore.ts
|
|
40887
41369
|
import {
|
|
40888
41370
|
copyFileSync,
|
|
40889
|
-
existsSync as
|
|
41371
|
+
existsSync as existsSync20,
|
|
40890
41372
|
mkdirSync as mkdirSync11,
|
|
40891
41373
|
readFileSync as readFileSync18,
|
|
40892
41374
|
renameSync as renameSync3,
|
|
@@ -40950,7 +41432,7 @@ function writePlanTaskArtifact(rootDir, task) {
|
|
|
40950
41432
|
}
|
|
40951
41433
|
function loadHandle(rootDir) {
|
|
40952
41434
|
const jsonPath = join17(rootDir, "plan.json");
|
|
40953
|
-
if (!
|
|
41435
|
+
if (!existsSync20(jsonPath)) {
|
|
40954
41436
|
return { rootDir, tasks: [], counter: 0, rootFields: {} };
|
|
40955
41437
|
}
|
|
40956
41438
|
let parsed;
|
|
@@ -40985,7 +41467,7 @@ function saveHandle(rootDir, handle) {
|
|
|
40985
41467
|
}
|
|
40986
41468
|
const jsonPath = join17(rootDir, "plan.json");
|
|
40987
41469
|
mkdirSync11(rootDir, { recursive: true });
|
|
40988
|
-
if (
|
|
41470
|
+
if (existsSync20(jsonPath)) {
|
|
40989
41471
|
copyFileSync(jsonPath, `${jsonPath}.bak`);
|
|
40990
41472
|
}
|
|
40991
41473
|
const file2 = {
|
|
@@ -41073,8 +41555,8 @@ var init_planStore = __esm({
|
|
|
41073
41555
|
});
|
|
41074
41556
|
|
|
41075
41557
|
// src/cli/workspace/taskTouchGuard.ts
|
|
41076
|
-
import { existsSync as
|
|
41077
|
-
import
|
|
41558
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
41559
|
+
import path37 from "node:path";
|
|
41078
41560
|
function isMutatingToolName(name) {
|
|
41079
41561
|
return NATIVE_WRITE_TOOLS.has(name) || MCP_FS_WRITE_RE.test(name);
|
|
41080
41562
|
}
|
|
@@ -41083,11 +41565,11 @@ function toPosixRel(projectRoot, p3) {
|
|
|
41083
41565
|
if (raw.startsWith("/") || /^[a-zA-Z]:\//.test(raw)) {
|
|
41084
41566
|
let rel2;
|
|
41085
41567
|
try {
|
|
41086
|
-
rel2 =
|
|
41568
|
+
rel2 = path37.relative(projectRoot, p3);
|
|
41087
41569
|
} catch {
|
|
41088
41570
|
return null;
|
|
41089
41571
|
}
|
|
41090
|
-
if (!rel2 || rel2.startsWith("..") ||
|
|
41572
|
+
if (!rel2 || rel2.startsWith("..") || path37.isAbsolute(rel2)) return null;
|
|
41091
41573
|
return rel2.replace(/\\/g, "/");
|
|
41092
41574
|
}
|
|
41093
41575
|
return raw.replace(/^\.\//, "");
|
|
@@ -41142,7 +41624,7 @@ function createTaskTouchGuard(opts) {
|
|
|
41142
41624
|
async function inspectWrite(rel2) {
|
|
41143
41625
|
try {
|
|
41144
41626
|
const planPath = planJsonPathFor(root);
|
|
41145
|
-
if (!
|
|
41627
|
+
if (!existsSync21(planPath)) return;
|
|
41146
41628
|
const tasks = await withPlanStore(root, (store6) => store6.tasks);
|
|
41147
41629
|
for (const task of tasks) {
|
|
41148
41630
|
if (task.status !== "completed" || !task.files?.length || !task.completedAt) continue;
|
|
@@ -41197,7 +41679,7 @@ var init_taskTouchGuard = __esm({
|
|
|
41197
41679
|
// src/cli/gitOps.ts
|
|
41198
41680
|
import { execFile as execFile2 } from "node:child_process";
|
|
41199
41681
|
import { promisify } from "node:util";
|
|
41200
|
-
import
|
|
41682
|
+
import path38 from "node:path";
|
|
41201
41683
|
async function git2(cwd, args) {
|
|
41202
41684
|
try {
|
|
41203
41685
|
const { stdout } = await execFileAsync("git", ["-C", cwd, ...args], {
|
|
@@ -41250,7 +41732,7 @@ async function undoWorkingChanges(opts = {}) {
|
|
|
41250
41732
|
};
|
|
41251
41733
|
}
|
|
41252
41734
|
function defaultProjectRoot() {
|
|
41253
|
-
return
|
|
41735
|
+
return path38.resolve(__dirname, "..", "..", "..");
|
|
41254
41736
|
}
|
|
41255
41737
|
var execFileAsync;
|
|
41256
41738
|
var init_gitOps = __esm({
|
|
@@ -41261,7 +41743,7 @@ var init_gitOps = __esm({
|
|
|
41261
41743
|
});
|
|
41262
41744
|
|
|
41263
41745
|
// src/cli/workspace/taskStaleness.ts
|
|
41264
|
-
import { existsSync as
|
|
41746
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
41265
41747
|
function taskStaleHours() {
|
|
41266
41748
|
const raw = process.env.ZELARI_TASK_STALE_HOURS;
|
|
41267
41749
|
if (raw === void 0 || raw.trim() === "") return TASK_STALE_HOURS_DEFAULT;
|
|
@@ -41273,7 +41755,7 @@ async function runTaskStalenessCheck(opts) {
|
|
|
41273
41755
|
const root = opts.projectRoot;
|
|
41274
41756
|
const nowMs = (opts.now ?? Date.now)();
|
|
41275
41757
|
try {
|
|
41276
|
-
if (!
|
|
41758
|
+
if (!existsSync22(planJsonPathFor(root))) return [];
|
|
41277
41759
|
if (!await isGitRepo(root)) return [];
|
|
41278
41760
|
const hours = opts.hoursOverride ?? taskStaleHours();
|
|
41279
41761
|
const cutoff = nowMs - hours * 36e5;
|
|
@@ -41392,7 +41874,7 @@ __export(auditLogger_exports, {
|
|
|
41392
41874
|
AuditLogger: () => AuditLogger
|
|
41393
41875
|
});
|
|
41394
41876
|
import { promises as fs16 } from "node:fs";
|
|
41395
|
-
import
|
|
41877
|
+
import path39 from "node:path";
|
|
41396
41878
|
function defaultAuditPath() {
|
|
41397
41879
|
return auditLogPath();
|
|
41398
41880
|
}
|
|
@@ -41438,7 +41920,7 @@ var init_auditLogger = __esm({
|
|
|
41438
41920
|
async append(entry) {
|
|
41439
41921
|
const line = JSON.stringify(entry) + "\n";
|
|
41440
41922
|
this.writeQueue = this.writeQueue.then(async () => {
|
|
41441
|
-
await fs16.mkdir(
|
|
41923
|
+
await fs16.mkdir(path39.dirname(this.logPath), { recursive: true });
|
|
41442
41924
|
await fs16.appendFile(this.logPath, line, "utf-8");
|
|
41443
41925
|
});
|
|
41444
41926
|
return this.writeQueue;
|
|
@@ -41483,9 +41965,9 @@ var init_auditLogger = __esm({
|
|
|
41483
41965
|
});
|
|
41484
41966
|
|
|
41485
41967
|
// src/cli/diagnostics/engine.ts
|
|
41486
|
-
import { spawn as
|
|
41487
|
-
import { existsSync as
|
|
41488
|
-
import
|
|
41968
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
41969
|
+
import { existsSync as existsSync23 } from "node:fs";
|
|
41970
|
+
import path40 from "node:path";
|
|
41489
41971
|
function parseEslintJson(stdout, _file2) {
|
|
41490
41972
|
const json3 = safeJson(stdout);
|
|
41491
41973
|
if (!Array.isArray(json3)) return [];
|
|
@@ -41544,7 +42026,7 @@ function safeJson(s) {
|
|
|
41544
42026
|
}
|
|
41545
42027
|
}
|
|
41546
42028
|
function providerForFile(file2, providers = DEFAULT_PROVIDERS) {
|
|
41547
|
-
const ext =
|
|
42029
|
+
const ext = path40.extname(file2).toLowerCase();
|
|
41548
42030
|
return providers.find((p3) => p3.extensions.includes(ext)) ?? null;
|
|
41549
42031
|
}
|
|
41550
42032
|
function resolveBin(bin, cwd) {
|
|
@@ -41552,10 +42034,10 @@ function resolveBin(bin, cwd) {
|
|
|
41552
42034
|
let dir = cwd;
|
|
41553
42035
|
for (let i = 0; i < 6; i += 1) {
|
|
41554
42036
|
for (const suffix of suffixes) {
|
|
41555
|
-
const candidate =
|
|
41556
|
-
if (
|
|
42037
|
+
const candidate = path40.join(dir, "node_modules", ".bin", `${bin}${suffix}`);
|
|
42038
|
+
if (existsSync23(candidate)) return candidate;
|
|
41557
42039
|
}
|
|
41558
|
-
const parent =
|
|
42040
|
+
const parent = path40.dirname(dir);
|
|
41559
42041
|
if (parent === dir) break;
|
|
41560
42042
|
dir = parent;
|
|
41561
42043
|
}
|
|
@@ -41628,7 +42110,7 @@ var init_engine2 = __esm({
|
|
|
41628
42110
|
};
|
|
41629
42111
|
let child;
|
|
41630
42112
|
try {
|
|
41631
|
-
child = process.platform === "win32" ?
|
|
42113
|
+
child = process.platform === "win32" ? spawn7(buildCmdLine(cmd, args), { cwd: opts.cwd, shell: true }) : spawn7(cmd, args, { cwd: opts.cwd });
|
|
41632
42114
|
} catch {
|
|
41633
42115
|
done({ code: null, stdout: "", stderr: "" });
|
|
41634
42116
|
return;
|
|
@@ -41660,8 +42142,8 @@ var init_engine2 = __esm({
|
|
|
41660
42142
|
|
|
41661
42143
|
// src/cli/tools/krakenWorktree.ts
|
|
41662
42144
|
import { execFile as execFile3 } from "node:child_process";
|
|
41663
|
-
import { existsSync as
|
|
41664
|
-
import
|
|
42145
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync12, rmSync } from "node:fs";
|
|
42146
|
+
import path41 from "node:path";
|
|
41665
42147
|
import { promisify as promisify2 } from "node:util";
|
|
41666
42148
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
41667
42149
|
function isKrakenWorktreeEnabled(env = process.env) {
|
|
@@ -41709,10 +42191,10 @@ async function createKrakenWorktree(cwd, label) {
|
|
|
41709
42191
|
const id3 = `${Date.now().toString(36)}-${randomBytes4(3).toString("hex")}`;
|
|
41710
42192
|
const slug = (label ?? "task").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) || "task";
|
|
41711
42193
|
const branch = `kraken/${slug}-${id3}`;
|
|
41712
|
-
const wtRoot =
|
|
41713
|
-
const wtPath =
|
|
42194
|
+
const wtRoot = path41.join(repoRoot, ".zelari", "worktrees");
|
|
42195
|
+
const wtPath = path41.join(wtRoot, `kraken-${id3}`);
|
|
41714
42196
|
try {
|
|
41715
|
-
if (!
|
|
42197
|
+
if (!existsSync24(wtRoot)) mkdirSync12(wtRoot, { recursive: true });
|
|
41716
42198
|
} catch {
|
|
41717
42199
|
return null;
|
|
41718
42200
|
}
|
|
@@ -41824,7 +42306,7 @@ async function cleanupKrakenWorktree(handle, env = process.env) {
|
|
|
41824
42306
|
if (shouldKeepWorktree(env)) return;
|
|
41825
42307
|
await git3(handle.repoRoot, ["worktree", "remove", "--force", handle.path]);
|
|
41826
42308
|
try {
|
|
41827
|
-
if (
|
|
42309
|
+
if (existsSync24(handle.path)) {
|
|
41828
42310
|
rmSync(handle.path, { recursive: true, force: true });
|
|
41829
42311
|
}
|
|
41830
42312
|
} catch {
|
|
@@ -42192,8 +42674,8 @@ var init_tentacle = __esm({
|
|
|
42192
42674
|
import { execFile as execFile4 } from "node:child_process";
|
|
42193
42675
|
import { promisify as promisify3 } from "node:util";
|
|
42194
42676
|
import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
|
|
42195
|
-
import { tmpdir as
|
|
42196
|
-
import
|
|
42677
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
42678
|
+
import path42 from "node:path";
|
|
42197
42679
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
42198
42680
|
async function git4(cwd, args, env) {
|
|
42199
42681
|
const { stdout } = await execFileAsync3("git", ["-C", cwd, ...args], {
|
|
@@ -42213,8 +42695,8 @@ async function isGitRepo2(cwd) {
|
|
|
42213
42695
|
return await gitSafe(cwd, ["rev-parse", "--is-inside-work-tree"]) === "true";
|
|
42214
42696
|
}
|
|
42215
42697
|
async function withTempIndex(fn) {
|
|
42216
|
-
const dir = mkdtempSync(
|
|
42217
|
-
const indexFile =
|
|
42698
|
+
const dir = mkdtempSync(path42.join(tmpdir3(), "zelari-ckpt-"));
|
|
42699
|
+
const indexFile = path42.join(dir, "index");
|
|
42218
42700
|
try {
|
|
42219
42701
|
return await fn(indexFile);
|
|
42220
42702
|
} finally {
|
|
@@ -42305,7 +42787,7 @@ async function restoreCheckpoint(cwd, id3) {
|
|
|
42305
42787
|
const deleted = [];
|
|
42306
42788
|
for (const rel2 of added) {
|
|
42307
42789
|
try {
|
|
42308
|
-
rmSync2(
|
|
42790
|
+
rmSync2(path42.join(cwd, rel2), { force: true });
|
|
42309
42791
|
deleted.push(rel2);
|
|
42310
42792
|
} catch {
|
|
42311
42793
|
}
|
|
@@ -42385,10 +42867,10 @@ var init_transactional = __esm({
|
|
|
42385
42867
|
|
|
42386
42868
|
// src/cli/workspace/worldModel.ts
|
|
42387
42869
|
import { promises as fs17 } from "node:fs";
|
|
42388
|
-
import
|
|
42389
|
-
import { spawn as
|
|
42870
|
+
import path43 from "node:path";
|
|
42871
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
42390
42872
|
function worldDir(cwd) {
|
|
42391
|
-
return
|
|
42873
|
+
return path43.join(cwd, WORLD_DIR_NAME);
|
|
42392
42874
|
}
|
|
42393
42875
|
async function ensureWorldDir(cwd) {
|
|
42394
42876
|
const dir = worldDir(cwd);
|
|
@@ -42398,10 +42880,10 @@ async function ensureWorldDir(cwd) {
|
|
|
42398
42880
|
async function appendTimeline(cwd, entry) {
|
|
42399
42881
|
const dir = await ensureWorldDir(cwd);
|
|
42400
42882
|
const line = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }) + "\n";
|
|
42401
|
-
await fs17.appendFile(
|
|
42883
|
+
await fs17.appendFile(path43.join(dir, TIMELINE_FILE), line, "utf8");
|
|
42402
42884
|
}
|
|
42403
42885
|
async function readChecks(cwd) {
|
|
42404
|
-
const p3 =
|
|
42886
|
+
const p3 = path43.join(worldDir(cwd), CHECKS_FILE);
|
|
42405
42887
|
try {
|
|
42406
42888
|
const raw = await fs17.readFile(p3, "utf8");
|
|
42407
42889
|
const parsed = JSON.parse(raw);
|
|
@@ -42413,7 +42895,7 @@ async function readChecks(cwd) {
|
|
|
42413
42895
|
function runShell(command, cwd, timeoutMs2, signal) {
|
|
42414
42896
|
return new Promise((resolve9) => {
|
|
42415
42897
|
const isWin = process.platform === "win32";
|
|
42416
|
-
const child =
|
|
42898
|
+
const child = spawn8(isWin ? "cmd.exe" : "/bin/sh", isWin ? ["/c", command] : ["-c", command], {
|
|
42417
42899
|
cwd,
|
|
42418
42900
|
env: process.env,
|
|
42419
42901
|
windowsHide: true,
|
|
@@ -42476,8 +42958,8 @@ function runShell(command, cwd, timeoutMs2, signal) {
|
|
|
42476
42958
|
});
|
|
42477
42959
|
}
|
|
42478
42960
|
async function runBacktest(cwd, signal) {
|
|
42479
|
-
const checksPath =
|
|
42480
|
-
const hypothesisPath =
|
|
42961
|
+
const checksPath = path43.join(worldDir(cwd), CHECKS_FILE);
|
|
42962
|
+
const hypothesisPath = path43.join(worldDir(cwd), HYPOTHESIS_FILE);
|
|
42481
42963
|
const checks = await readChecks(cwd);
|
|
42482
42964
|
if (checks.length === 0) {
|
|
42483
42965
|
return {
|
|
@@ -42546,7 +43028,7 @@ var init_worldModel = __esm({
|
|
|
42546
43028
|
"use strict";
|
|
42547
43029
|
init_zod();
|
|
42548
43030
|
init_toolTypes();
|
|
42549
|
-
WORLD_DIR_NAME =
|
|
43031
|
+
WORLD_DIR_NAME = path43.join(".zelari", "world");
|
|
42550
43032
|
HYPOTHESIS_FILE = "hypothesis.md";
|
|
42551
43033
|
CHECKS_FILE = "checks.json";
|
|
42552
43034
|
TIMELINE_FILE = "timeline.jsonl";
|
|
@@ -42563,7 +43045,7 @@ var init_worldModel = __esm({
|
|
|
42563
43045
|
execute: async (args, ctx) => {
|
|
42564
43046
|
try {
|
|
42565
43047
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
42566
|
-
const file2 =
|
|
43048
|
+
const file2 = path43.join(dir, HYPOTHESIS_FILE);
|
|
42567
43049
|
if (args.append) {
|
|
42568
43050
|
const block = `
|
|
42569
43051
|
|
|
@@ -42602,7 +43084,7 @@ ${args.content}
|
|
|
42602
43084
|
execute: async (args, ctx) => {
|
|
42603
43085
|
try {
|
|
42604
43086
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
42605
|
-
const file2 =
|
|
43087
|
+
const file2 = path43.join(dir, CHECKS_FILE);
|
|
42606
43088
|
const body = { checks: args.checks };
|
|
42607
43089
|
await fs17.writeFile(file2, JSON.stringify(body, null, 2) + "\n", "utf8");
|
|
42608
43090
|
await appendTimeline(ctx.cwd, { kind: "checks_set", count: args.checks.length });
|
|
@@ -42641,8 +43123,8 @@ ${args.content}
|
|
|
42641
43123
|
stdoutPreview: "(dryRun)",
|
|
42642
43124
|
mismatch: "dryRun"
|
|
42643
43125
|
})),
|
|
42644
|
-
hypothesisPath:
|
|
42645
|
-
checksPath:
|
|
43126
|
+
hypothesisPath: path43.join(worldDir(ctx.cwd), HYPOTHESIS_FILE),
|
|
43127
|
+
checksPath: path43.join(worldDir(ctx.cwd), CHECKS_FILE)
|
|
42646
43128
|
});
|
|
42647
43129
|
}
|
|
42648
43130
|
const result = await runBacktest(ctx.cwd, ctx.signal);
|
|
@@ -42666,7 +43148,7 @@ ${args.content}
|
|
|
42666
43148
|
execute: async (args, ctx) => {
|
|
42667
43149
|
try {
|
|
42668
43150
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
42669
|
-
const file2 =
|
|
43151
|
+
const file2 = path43.join(dir, TIMELINE_FILE);
|
|
42670
43152
|
await appendTimeline(ctx.cwd, {
|
|
42671
43153
|
kind: args.kind,
|
|
42672
43154
|
summary: args.summary,
|
|
@@ -42690,9 +43172,9 @@ __export(graphMemory_exports, {
|
|
|
42690
43172
|
toGraphSnapshot: () => toGraphSnapshot
|
|
42691
43173
|
});
|
|
42692
43174
|
import { promises as fs18 } from "node:fs";
|
|
42693
|
-
import
|
|
43175
|
+
import path44 from "node:path";
|
|
42694
43176
|
function snapshotPath(cwd) {
|
|
42695
|
-
return
|
|
43177
|
+
return path44.join(cwd, SNAPSHOT_DIR, SNAPSHOT_FILE);
|
|
42696
43178
|
}
|
|
42697
43179
|
function toGraphSnapshot(graph, opts) {
|
|
42698
43180
|
const unresolved = (opts.unresolvedFindings ?? []).map((u) => ({
|
|
@@ -42719,7 +43201,7 @@ async function saveGraphSnapshot(cwd, snapshot) {
|
|
|
42719
43201
|
try {
|
|
42720
43202
|
await fs18.access(cwd);
|
|
42721
43203
|
const file2 = snapshotPath(cwd);
|
|
42722
|
-
await fs18.mkdir(
|
|
43204
|
+
await fs18.mkdir(path44.dirname(file2), { recursive: true });
|
|
42723
43205
|
await fs18.writeFile(file2, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
42724
43206
|
} catch {
|
|
42725
43207
|
}
|
|
@@ -42786,7 +43268,7 @@ var SNAPSHOT_DIR, SNAPSHOT_FILE, MAX_SNAPSHOT_FINDINGS_CHARS;
|
|
|
42786
43268
|
var init_graphMemory = __esm({
|
|
42787
43269
|
"src/cli/kraken/graphMemory.ts"() {
|
|
42788
43270
|
"use strict";
|
|
42789
|
-
SNAPSHOT_DIR =
|
|
43271
|
+
SNAPSHOT_DIR = path44.join(".zelari", "kraken");
|
|
42790
43272
|
SNAPSHOT_FILE = "last-graph.json";
|
|
42791
43273
|
MAX_SNAPSHOT_FINDINGS_CHARS = 400;
|
|
42792
43274
|
}
|
|
@@ -42794,14 +43276,14 @@ var init_graphMemory = __esm({
|
|
|
42794
43276
|
|
|
42795
43277
|
// src/cli/kraken/workbench.ts
|
|
42796
43278
|
import { promises as fs19 } from "node:fs";
|
|
42797
|
-
import
|
|
43279
|
+
import path45 from "node:path";
|
|
42798
43280
|
function isWorkbenchEnabled(env = process.env) {
|
|
42799
43281
|
const v = (env.ZELARI_KRAKEN_WORKBENCH ?? "1").trim().toLowerCase();
|
|
42800
43282
|
if (v === "0" || v === "false" || v === "no" || v === "off") return false;
|
|
42801
43283
|
return true;
|
|
42802
43284
|
}
|
|
42803
43285
|
function workbenchPath(cwd, graphId) {
|
|
42804
|
-
return
|
|
43286
|
+
return path45.join(cwd, ".zelari", "radio", `workbench-${graphId}.md`);
|
|
42805
43287
|
}
|
|
42806
43288
|
function countByStatus2(nodes) {
|
|
42807
43289
|
const out = { pending: 0, running: 0, done: 0, error: 0, skipped: 0 };
|
|
@@ -42964,7 +43446,7 @@ var init_workbench = __esm({
|
|
|
42964
43446
|
if (!this.enabled) return null;
|
|
42965
43447
|
if (!this.dirty && this.lastWrite) return this.lastWrite;
|
|
42966
43448
|
const out = workbenchPath(this.cwd, this.graphId);
|
|
42967
|
-
await fs19.mkdir(
|
|
43449
|
+
await fs19.mkdir(path45.dirname(out), { recursive: true });
|
|
42968
43450
|
const body = this.render();
|
|
42969
43451
|
const tmp = `${out}.${process.pid}.${Date.now()}.tmp`;
|
|
42970
43452
|
await fs19.writeFile(tmp, body, "utf8");
|
|
@@ -43110,9 +43592,9 @@ var init_semanticOwnership = __esm({
|
|
|
43110
43592
|
|
|
43111
43593
|
// src/cli/ast/engine.ts
|
|
43112
43594
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
43113
|
-
import
|
|
43595
|
+
import path46 from "node:path";
|
|
43114
43596
|
function isAstSupported(file2) {
|
|
43115
|
-
return TS_EXTENSIONS.has(
|
|
43597
|
+
return TS_EXTENSIONS.has(path46.extname(file2).toLowerCase());
|
|
43116
43598
|
}
|
|
43117
43599
|
function loadTs() {
|
|
43118
43600
|
if (!tsPromise) {
|
|
@@ -43124,8 +43606,8 @@ function errMessage(err) {
|
|
|
43124
43606
|
return err instanceof Error ? err.message : String(err);
|
|
43125
43607
|
}
|
|
43126
43608
|
async function parseFileSymbolsDiag(file2, cwd) {
|
|
43127
|
-
const resolvedPath =
|
|
43128
|
-
const extension =
|
|
43609
|
+
const resolvedPath = path46.isAbsolute(file2) ? file2 : path46.join(cwd ?? process.cwd(), file2);
|
|
43610
|
+
const extension = path46.extname(resolvedPath).toLowerCase();
|
|
43129
43611
|
if (!TS_EXTENSIONS.has(extension)) {
|
|
43130
43612
|
return {
|
|
43131
43613
|
status: "unsupported-extension",
|
|
@@ -43167,7 +43649,7 @@ async function parseFileSymbolsDiag(file2, cwd) {
|
|
|
43167
43649
|
}
|
|
43168
43650
|
let source2;
|
|
43169
43651
|
try {
|
|
43170
|
-
source2 = ts.createSourceFile(
|
|
43652
|
+
source2 = ts.createSourceFile(path46.basename(resolvedPath), text, ts.ScriptTarget.Latest, true);
|
|
43171
43653
|
} catch (err) {
|
|
43172
43654
|
return {
|
|
43173
43655
|
status: "parse-error",
|
|
@@ -43460,14 +43942,14 @@ var init_spawnRoi = __esm({
|
|
|
43460
43942
|
|
|
43461
43943
|
// src/cli/kraken/reputationStore.ts
|
|
43462
43944
|
import { appendFile as appendFile2, mkdir as mkdir2, readFile as readFile6, rename, writeFile as writeFile2 } from "node:fs/promises";
|
|
43463
|
-
import
|
|
43945
|
+
import path47 from "node:path";
|
|
43464
43946
|
function resolveReputationStorePath(cwd = process.cwd(), env = process.env) {
|
|
43465
43947
|
const override = env[REPUTATION_STORE_ENV]?.trim();
|
|
43466
43948
|
if (override) return override;
|
|
43467
|
-
return
|
|
43949
|
+
return path47.join(cwd, ".zelari", "reputation.jsonl");
|
|
43468
43950
|
}
|
|
43469
43951
|
async function appendRecord(storePath, record2) {
|
|
43470
|
-
await mkdir2(
|
|
43952
|
+
await mkdir2(path47.dirname(storePath), { recursive: true });
|
|
43471
43953
|
await appendFile2(storePath, `${JSON.stringify(record2)}
|
|
43472
43954
|
`, "utf8");
|
|
43473
43955
|
}
|
|
@@ -44019,8 +44501,8 @@ __export(executor_exports, {
|
|
|
44019
44501
|
resolveTransactional: () => resolveTransactional,
|
|
44020
44502
|
thoroughnessForKind: () => thoroughnessForKind
|
|
44021
44503
|
});
|
|
44022
|
-
import { existsSync as
|
|
44023
|
-
import
|
|
44504
|
+
import { existsSync as existsSync25 } from "node:fs";
|
|
44505
|
+
import path48 from "node:path";
|
|
44024
44506
|
async function defaultSymbolExtractor(file2) {
|
|
44025
44507
|
if (!isAstSupported(file2)) return null;
|
|
44026
44508
|
const r = await parseFileSymbolsDiag(file2);
|
|
@@ -44086,7 +44568,7 @@ function isWorldModelGateEnabled(cwd, env = process.env, checksExists = defaultC
|
|
|
44086
44568
|
}
|
|
44087
44569
|
function defaultChecksExists(cwd) {
|
|
44088
44570
|
try {
|
|
44089
|
-
return
|
|
44571
|
+
return existsSync25(path48.join(cwd, ".zelari", "world", "checks.json"));
|
|
44090
44572
|
} catch {
|
|
44091
44573
|
return false;
|
|
44092
44574
|
}
|
|
@@ -44594,7 +45076,7 @@ var init_executor = __esm({
|
|
|
44594
45076
|
try {
|
|
44595
45077
|
const summary = aggregate(
|
|
44596
45078
|
records,
|
|
44597
|
-
{ repo:
|
|
45079
|
+
{ repo: path48.basename(this.parentCwd), role: agentForNode(node) },
|
|
44598
45080
|
now
|
|
44599
45081
|
);
|
|
44600
45082
|
sample = summary.sample;
|
|
@@ -45071,7 +45553,7 @@ ${upstream}` : node.prompt,
|
|
|
45071
45553
|
const model = res.ok && res.model && res.model !== "n/a" ? res.model : null;
|
|
45072
45554
|
const reviewerVerdict = res.ok && this.isReviewerKind(node.kind) && typeof node.result === "string" && node.result.length > 0 ? parseVerifyVerdict(node.result).verdict : null;
|
|
45073
45555
|
const record2 = reputationRecordFromNodeRun({
|
|
45074
|
-
repo:
|
|
45556
|
+
repo: path48.basename(this.parentCwd),
|
|
45075
45557
|
role: agentForNode(node),
|
|
45076
45558
|
kind: node.kind,
|
|
45077
45559
|
ok: res.ok,
|
|
@@ -45459,7 +45941,7 @@ ${failed.error ?? "unknown error"}`,
|
|
|
45459
45941
|
});
|
|
45460
45942
|
|
|
45461
45943
|
// src/cli/tools/taskTool.ts
|
|
45462
|
-
import { existsSync as
|
|
45944
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
45463
45945
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
45464
45946
|
function resetTaskSpawnCount() {
|
|
45465
45947
|
const g = globalThis;
|
|
@@ -45527,7 +46009,7 @@ ${findings || "(the reviewer reported FAIL without detail)"}`;
|
|
|
45527
46009
|
async function runAutoVerifyAfterGeneral(opts) {
|
|
45528
46010
|
const g = globalThis;
|
|
45529
46011
|
g.__zelariGeneralVerifyDebt = { description: opts.original.description };
|
|
45530
|
-
const inheritedCwd = opts.general.worktreePath &&
|
|
46012
|
+
const inheritedCwd = opts.general.worktreePath && existsSync26(opts.general.worktreePath) ? opts.general.worktreePath : void 0;
|
|
45531
46013
|
const runVerify = (label) => runTentacle({
|
|
45532
46014
|
deps: opts.deps,
|
|
45533
46015
|
args: {
|
|
@@ -46653,7 +47135,7 @@ var init_askUser = __esm({
|
|
|
46653
47135
|
});
|
|
46654
47136
|
|
|
46655
47137
|
// src/cli/skillsMd.ts
|
|
46656
|
-
import { existsSync as
|
|
47138
|
+
import { existsSync as existsSync27, readdirSync as readdirSync5, readFileSync as readFileSync19 } from "node:fs";
|
|
46657
47139
|
import { join as join18 } from "node:path";
|
|
46658
47140
|
function skillMdSearchDirs(projectRoot = process.cwd()) {
|
|
46659
47141
|
return [
|
|
@@ -46718,7 +47200,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
46718
47200
|
const summary = { loaded: [], skipped: [] };
|
|
46719
47201
|
const seen = new Set(options.existingIds ?? []);
|
|
46720
47202
|
for (const dir of skillMdSearchDirs(projectRoot)) {
|
|
46721
|
-
if (!
|
|
47203
|
+
if (!existsSync27(dir)) continue;
|
|
46722
47204
|
let entries;
|
|
46723
47205
|
try {
|
|
46724
47206
|
entries = readdirSync5(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
@@ -46727,7 +47209,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
46727
47209
|
}
|
|
46728
47210
|
for (const entry of entries) {
|
|
46729
47211
|
const skillPath = join18(dir, entry, "SKILL.md");
|
|
46730
|
-
if (!
|
|
47212
|
+
if (!existsSync27(skillPath)) continue;
|
|
46731
47213
|
try {
|
|
46732
47214
|
const parsed = parseSkillMd(readFileSync19(skillPath, "utf8"), skillPath);
|
|
46733
47215
|
if (!parsed) {
|
|
@@ -46770,6 +47252,21 @@ var init_skillsMd = __esm({
|
|
|
46770
47252
|
});
|
|
46771
47253
|
|
|
46772
47254
|
// src/cli/budget/historySummary.ts
|
|
47255
|
+
function collectOpenObligations(text, out) {
|
|
47256
|
+
for (const rawLine of text.split("\n")) {
|
|
47257
|
+
const line = rawLine.trim();
|
|
47258
|
+
if (!line || line.length > 240) continue;
|
|
47259
|
+
if (OPEN_OBLIGATION_LINE.test(line) || OPEN_OBLIGATION_KEYWORD.test(line)) {
|
|
47260
|
+
out.push(oneLine(line, 200));
|
|
47261
|
+
}
|
|
47262
|
+
}
|
|
47263
|
+
}
|
|
47264
|
+
function collectEvidenceRefs(text, out) {
|
|
47265
|
+
for (const re of EVIDENCE_PATTERNS) {
|
|
47266
|
+
const matches = text.match(re);
|
|
47267
|
+
if (matches) out.push(...matches);
|
|
47268
|
+
}
|
|
47269
|
+
}
|
|
46773
47270
|
function extractiveHistorySummary(dropped, opts) {
|
|
46774
47271
|
const maxChars = opts?.maxChars ?? MAX_SUMMARY_CHARS;
|
|
46775
47272
|
if (dropped.length === 0) return "No prior turns.";
|
|
@@ -46781,8 +47278,12 @@ function extractiveHistorySummary(dropped, opts) {
|
|
|
46781
47278
|
const decisions = [];
|
|
46782
47279
|
const tools = /* @__PURE__ */ new Map();
|
|
46783
47280
|
const files = /* @__PURE__ */ new Set();
|
|
47281
|
+
const openObligations = [];
|
|
47282
|
+
const evidenceRefs = [];
|
|
46784
47283
|
let toolResults = 0;
|
|
46785
47284
|
for (const m of dropped) {
|
|
47285
|
+
collectOpenObligations(m.content ?? "", openObligations);
|
|
47286
|
+
collectEvidenceRefs(m.content ?? "", evidenceRefs);
|
|
46786
47287
|
if (m.role === "user" && m.content.trim()) {
|
|
46787
47288
|
const goal = oneLine(m.content, 220);
|
|
46788
47289
|
userGoals.push(goal);
|
|
@@ -46820,6 +47321,14 @@ function extractiveHistorySummary(dropped, opts) {
|
|
|
46820
47321
|
parts.push("## User constraints (preserve exactly)");
|
|
46821
47322
|
for (const item of [...new Set(userConstraints)].slice(-8)) parts.push(`- ${item}`);
|
|
46822
47323
|
}
|
|
47324
|
+
if (openObligations.length) {
|
|
47325
|
+
parts.push("## Open obligations (still owed \u2014 do not silently drop)");
|
|
47326
|
+
for (const item of [...new Set(openObligations)].slice(-10)) parts.push(`- ${item}`);
|
|
47327
|
+
}
|
|
47328
|
+
if (evidenceRefs.length) {
|
|
47329
|
+
parts.push("## Evidence anchors (verbatim refs, keep provenance)");
|
|
47330
|
+
for (const item of [...new Set(evidenceRefs)].slice(-12)) parts.push(`- ${oneLine(item, 160)}`);
|
|
47331
|
+
}
|
|
46823
47332
|
if (unresolved.length) {
|
|
46824
47333
|
parts.push("## Unresolved failures / pending repair");
|
|
46825
47334
|
for (const item of [...new Set(unresolved)].slice(-8)) parts.push(`- ${item}`);
|
|
@@ -46878,11 +47387,19 @@ function collectPathsFromText(text, out) {
|
|
|
46878
47387
|
n += 1;
|
|
46879
47388
|
}
|
|
46880
47389
|
}
|
|
46881
|
-
var MAX_SUMMARY_CHARS;
|
|
47390
|
+
var MAX_SUMMARY_CHARS, OPEN_OBLIGATION_LINE, OPEN_OBLIGATION_KEYWORD, EVIDENCE_PATTERNS;
|
|
46882
47391
|
var init_historySummary = __esm({
|
|
46883
47392
|
"src/cli/budget/historySummary.ts"() {
|
|
46884
47393
|
"use strict";
|
|
46885
47394
|
MAX_SUMMARY_CHARS = 3500;
|
|
47395
|
+
OPEN_OBLIGATION_LINE = /^\s*[-*]\s+\[\s\]/;
|
|
47396
|
+
OPEN_OBLIGATION_KEYWORD = /\b(TODO|PENDING|FIX ME|STILL OWED|DA FARE)\b\s*[:.]/;
|
|
47397
|
+
EVIDENCE_PATTERNS = [
|
|
47398
|
+
/OBSERVATION\s+ref=#\d+(?:[^,\n]{0,40})?/g,
|
|
47399
|
+
/\bcommit\s+[0-9a-f]{7,40}\b/gi,
|
|
47400
|
+
/\bpushed\s+[0-9a-f]{7,40}\b/gi,
|
|
47401
|
+
/\bexit code\s+\d+\b/gi
|
|
47402
|
+
];
|
|
46886
47403
|
}
|
|
46887
47404
|
});
|
|
46888
47405
|
|
|
@@ -47008,15 +47525,25 @@ function withDroppedRange(result, dropped, strategy) {
|
|
|
47008
47525
|
return { ...result, ...range, strategy };
|
|
47009
47526
|
}
|
|
47010
47527
|
function resolveMaxMessages(opts) {
|
|
47011
|
-
const envTurns = envNumber(process.env.ZELARI_HISTORY_TURNS, { default:
|
|
47528
|
+
const envTurns = envNumber(process.env.ZELARI_HISTORY_TURNS, { default: 40, min: 0 });
|
|
47012
47529
|
let turns = opts?.maxMessages ? Math.ceil(opts.maxMessages / 4) : envTurns;
|
|
47013
|
-
if (opts?.durableStatePresent && !opts?.maxMessages && process.env.ZELARI_HISTORY_TURNS === void 0) {
|
|
47014
|
-
turns = Math.min(turns, 3);
|
|
47015
|
-
}
|
|
47016
47530
|
if (turns <= 0) return 0;
|
|
47017
47531
|
if (opts?.force && opts?.maxMessages) return Math.max(1, opts.maxMessages);
|
|
47018
47532
|
return turns * 4;
|
|
47019
47533
|
}
|
|
47534
|
+
function resolveHistoryCharBudget(opts) {
|
|
47535
|
+
const halveForDurable = !!opts?.durableStatePresent && process.env.ZELARI_HISTORY_BUDGET_CHARS === void 0;
|
|
47536
|
+
return envNumber(process.env.ZELARI_HISTORY_BUDGET_CHARS, {
|
|
47537
|
+
default: halveForDurable ? 1e4 : 2e4,
|
|
47538
|
+
min: 2e3,
|
|
47539
|
+
max: 2e5
|
|
47540
|
+
});
|
|
47541
|
+
}
|
|
47542
|
+
function historyChars(messages) {
|
|
47543
|
+
let n = 0;
|
|
47544
|
+
for (const m of messages) n += (m.content ?? "").length;
|
|
47545
|
+
return n;
|
|
47546
|
+
}
|
|
47020
47547
|
function findValidCutIndex(messages, naiveCut) {
|
|
47021
47548
|
let cut = naiveCut;
|
|
47022
47549
|
while (cut < messages.length) {
|
|
@@ -47100,7 +47627,12 @@ function compactHistoryDetailed(messages, opts) {
|
|
|
47100
47627
|
"extractive"
|
|
47101
47628
|
);
|
|
47102
47629
|
}
|
|
47103
|
-
|
|
47630
|
+
const charBudget = resolveHistoryCharBudget(opts);
|
|
47631
|
+
const explicitCount = opts?.maxMessages !== void 0 || process.env.ZELARI_HISTORY_TURNS !== void 0;
|
|
47632
|
+
const overChars = historyChars(messages) > charBudget;
|
|
47633
|
+
const overCount = messages.length > maxMessages * 2;
|
|
47634
|
+
const shouldCompact = overChars || explicitCount && overCount || !!opts?.force;
|
|
47635
|
+
if (!shouldCompact) {
|
|
47104
47636
|
return {
|
|
47105
47637
|
messages,
|
|
47106
47638
|
compacted: false,
|
|
@@ -47108,7 +47640,18 @@ function compactHistoryDetailed(messages, opts) {
|
|
|
47108
47640
|
summary: ""
|
|
47109
47641
|
};
|
|
47110
47642
|
}
|
|
47111
|
-
|
|
47643
|
+
let naiveCut;
|
|
47644
|
+
if (overChars) {
|
|
47645
|
+
let cut2 = 0;
|
|
47646
|
+
let keptChars = historyChars(messages);
|
|
47647
|
+
while (cut2 < messages.length && keptChars > charBudget) {
|
|
47648
|
+
keptChars -= (messages[cut2].content ?? "").length;
|
|
47649
|
+
cut2 += 1;
|
|
47650
|
+
}
|
|
47651
|
+
naiveCut = Math.max(cut2, messages.length - maxMessages);
|
|
47652
|
+
} else {
|
|
47653
|
+
naiveCut = Math.max(0, messages.length - maxMessages);
|
|
47654
|
+
}
|
|
47112
47655
|
const cut = findValidCutIndex(messages, naiveCut);
|
|
47113
47656
|
if (cut === 0) {
|
|
47114
47657
|
return {
|
|
@@ -47372,7 +47915,11 @@ function resolveContextLimit(model, provider) {
|
|
|
47372
47915
|
}
|
|
47373
47916
|
function phaseKnobs(phase2) {
|
|
47374
47917
|
return {
|
|
47375
|
-
|
|
47918
|
+
// v2.32.0 (S3): count defaults raised to a runaway safety net — the
|
|
47919
|
+
// primary history gate is the adaptive char budget (see
|
|
47920
|
+
// historyCompaction.resolveHistoryCharBudget). An explicit
|
|
47921
|
+
// ZELARI_HISTORY_TURNS stays a user contract and is honored as before.
|
|
47922
|
+
historyTurns: phase2 === "plan" ? envNumber(process.env.ZELARI_HISTORY_TURNS, { default: 40, min: 0 }) : envNumber(process.env.ZELARI_HISTORY_TURNS, { default: 40, min: 0 }),
|
|
47376
47923
|
maxToolLoopIterations: phase2 === "plan" ? envNumber(process.env.ZELARI_MAX_TOOL_LOOP_ITERATIONS, { default: 60, min: 1 }) : envNumber(process.env.ZELARI_MAX_TOOL_LOOP_ITERATIONS, {
|
|
47377
47924
|
default: 120,
|
|
47378
47925
|
min: 1
|
|
@@ -48059,8 +48606,8 @@ var init_planTaskTools = __esm({
|
|
|
48059
48606
|
|
|
48060
48607
|
// src/cli/tools/inspectTypecheckSafety.ts
|
|
48061
48608
|
import { promises as fs20 } from "node:fs";
|
|
48062
|
-
import
|
|
48063
|
-
import { spawn as
|
|
48609
|
+
import path49 from "node:path";
|
|
48610
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
48064
48611
|
async function scanTsbuildinfo(root) {
|
|
48065
48612
|
const found = [];
|
|
48066
48613
|
const stack = [root];
|
|
@@ -48073,11 +48620,11 @@ async function scanTsbuildinfo(root) {
|
|
|
48073
48620
|
continue;
|
|
48074
48621
|
}
|
|
48075
48622
|
for (const entry of entries) {
|
|
48076
|
-
const p3 =
|
|
48623
|
+
const p3 = path49.join(dir, entry.name);
|
|
48077
48624
|
if (entry.isDirectory()) {
|
|
48078
48625
|
if (!SCAN_SKIP.has(entry.name)) stack.push(p3);
|
|
48079
48626
|
} else if (entry.name.endsWith(".tsbuildinfo")) {
|
|
48080
|
-
found.push(
|
|
48627
|
+
found.push(path49.relative(root, p3).split(path49.sep).join("/"));
|
|
48081
48628
|
}
|
|
48082
48629
|
}
|
|
48083
48630
|
}
|
|
@@ -48086,7 +48633,7 @@ async function scanTsbuildinfo(root) {
|
|
|
48086
48633
|
}
|
|
48087
48634
|
async function gitStatusPorcelain(root) {
|
|
48088
48635
|
return new Promise((resolve9) => {
|
|
48089
|
-
const child =
|
|
48636
|
+
const child = spawn9("git", ["status", "--porcelain"], { cwd: root, shell: false });
|
|
48090
48637
|
let out = "";
|
|
48091
48638
|
child.stdout.on("data", (d) => out += d.toString());
|
|
48092
48639
|
child.stderr.on("data", (d) => out += d.toString());
|
|
@@ -48113,7 +48660,7 @@ async function cleanupArtifacts(root, relPaths) {
|
|
|
48113
48660
|
const failed = [];
|
|
48114
48661
|
for (const rel2 of relPaths) {
|
|
48115
48662
|
try {
|
|
48116
|
-
await fs20.unlink(
|
|
48663
|
+
await fs20.unlink(path49.join(root, rel2));
|
|
48117
48664
|
cleaned.push(rel2);
|
|
48118
48665
|
} catch {
|
|
48119
48666
|
failed.push(rel2);
|
|
@@ -48136,17 +48683,17 @@ var init_inspectTypecheckSafety = __esm({
|
|
|
48136
48683
|
});
|
|
48137
48684
|
|
|
48138
48685
|
// src/cli/tools/inspectCommand.ts
|
|
48139
|
-
import { spawn as
|
|
48686
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
48140
48687
|
import { createHash as createHash13 } from "node:crypto";
|
|
48141
|
-
import { existsSync as
|
|
48688
|
+
import { existsSync as existsSync28, promises as fs21 } from "node:fs";
|
|
48142
48689
|
import os2 from "node:os";
|
|
48143
|
-
import
|
|
48690
|
+
import path50 from "node:path";
|
|
48144
48691
|
function resolveNodeModuleBin(start, rel2) {
|
|
48145
|
-
let dir =
|
|
48692
|
+
let dir = path50.resolve(start);
|
|
48146
48693
|
for (; ; ) {
|
|
48147
|
-
const candidate =
|
|
48148
|
-
if (
|
|
48149
|
-
const parent =
|
|
48694
|
+
const candidate = path50.join(dir, "node_modules", rel2);
|
|
48695
|
+
if (existsSync28(candidate)) return candidate;
|
|
48696
|
+
const parent = path50.dirname(dir);
|
|
48150
48697
|
if (parent === dir) return void 0;
|
|
48151
48698
|
dir = parent;
|
|
48152
48699
|
}
|
|
@@ -48214,7 +48761,7 @@ function buildInspectCommand(op, ctx) {
|
|
|
48214
48761
|
case "npm_ls":
|
|
48215
48762
|
case "npm_outdated":
|
|
48216
48763
|
case "npm_view": {
|
|
48217
|
-
const npmCli = ctx.npmCliPath ?? resolveNodeModuleBin(ctx.root,
|
|
48764
|
+
const npmCli = ctx.npmCliPath ?? resolveNodeModuleBin(ctx.root, path50.join("npm", "bin", "npm-cli.js")) ?? path50.join(ctx.root, "node_modules", "npm", "bin", "npm-cli.js");
|
|
48218
48765
|
if (op.operation === "npm_view") {
|
|
48219
48766
|
const err = rejectFlagLike("package", op.package);
|
|
48220
48767
|
if (err) return { ok: false, reason: err };
|
|
@@ -48223,14 +48770,14 @@ function buildInspectCommand(op, ctx) {
|
|
|
48223
48770
|
return { ok: true, command: process.execPath, argv: [npmCli, ...sub], inspectionClass: "env-info" };
|
|
48224
48771
|
}
|
|
48225
48772
|
case "typecheck": {
|
|
48226
|
-
const project =
|
|
48773
|
+
const project = path50.resolve(ctx.cwd, op.project ?? "tsconfig.json");
|
|
48227
48774
|
const hash3 = createHash13("sha256").update(project).digest("hex").slice(0, 16);
|
|
48228
|
-
const tsBuildInfoFile =
|
|
48775
|
+
const tsBuildInfoFile = path50.join(os2.tmpdir(), "zelari-inspect", `${hash3}.tsbuildinfo`);
|
|
48229
48776
|
return {
|
|
48230
48777
|
ok: true,
|
|
48231
48778
|
command: process.execPath,
|
|
48232
48779
|
argv: [
|
|
48233
|
-
ctx.tscPath ?? resolveNodeModuleBin(ctx.root,
|
|
48780
|
+
ctx.tscPath ?? resolveNodeModuleBin(ctx.root, path50.join("typescript", "bin", "tsc")) ?? resolveNodeModuleBin(ctx.cwd, path50.join("typescript", "bin", "tsc")) ?? path50.join(ctx.root, "node_modules", "typescript", "bin", "tsc"),
|
|
48234
48781
|
"--noEmit",
|
|
48235
48782
|
// S3.5 primary mechanism: redirect, never disable — composite forces
|
|
48236
48783
|
// incremental (TS#30661), so --incremental false would break on the
|
|
@@ -48252,7 +48799,7 @@ function runSpawn(command, argv, opts) {
|
|
|
48252
48799
|
return new Promise((resolve9) => {
|
|
48253
48800
|
let child;
|
|
48254
48801
|
try {
|
|
48255
|
-
child =
|
|
48802
|
+
child = spawn10(command, argv, { cwd: opts.cwd, shell: false });
|
|
48256
48803
|
} catch (err) {
|
|
48257
48804
|
resolve9({ code: null, stdout: "", stderr: String(err), timedOut: false, spawnError: String(err) });
|
|
48258
48805
|
return;
|
|
@@ -48538,379 +49085,6 @@ var init_selfKillGuard = __esm({
|
|
|
48538
49085
|
}
|
|
48539
49086
|
});
|
|
48540
49087
|
|
|
48541
|
-
// src/cli/safety/policyLoadMode.ts
|
|
48542
|
-
var policyLoadMode_exports = {};
|
|
48543
|
-
__export(policyLoadMode_exports, {
|
|
48544
|
-
POLICY_LOAD_BLOCK_REASON: () => POLICY_LOAD_BLOCK_REASON,
|
|
48545
|
-
POLICY_LOAD_EXIT_CODE: () => POLICY_LOAD_EXIT_CODE,
|
|
48546
|
-
POLICY_LOAD_MODE_ENV: () => POLICY_LOAD_MODE_ENV,
|
|
48547
|
-
activePolicyLoadMode: () => activePolicyLoadMode,
|
|
48548
|
-
activePolicyLoadSurface: () => activePolicyLoadSurface,
|
|
48549
|
-
resolvePolicyLoadMode: () => resolvePolicyLoadMode,
|
|
48550
|
-
setActivePolicyLoadSurface: () => setActivePolicyLoadSurface
|
|
48551
|
-
});
|
|
48552
|
-
function isTruthyFlag(v) {
|
|
48553
|
-
const n = v?.trim().toLowerCase();
|
|
48554
|
-
return n === "1" || n === "true" || n === "yes" || n === "on";
|
|
48555
|
-
}
|
|
48556
|
-
function resolvePolicyLoadMode(input) {
|
|
48557
|
-
const v = input.override?.trim().toLowerCase();
|
|
48558
|
-
if (v === "strict") return "strict";
|
|
48559
|
-
if (v === "permissive") return "permissive";
|
|
48560
|
-
if (input.surface === "headless" || input.surface === "mission") return "strict";
|
|
48561
|
-
if (isTruthyFlag(input.ci)) return "strict";
|
|
48562
|
-
return "permissive";
|
|
48563
|
-
}
|
|
48564
|
-
function setActivePolicyLoadSurface(surface) {
|
|
48565
|
-
activeSurface = surface;
|
|
48566
|
-
}
|
|
48567
|
-
function activePolicyLoadSurface() {
|
|
48568
|
-
return activeSurface;
|
|
48569
|
-
}
|
|
48570
|
-
function activePolicyLoadMode(env = process.env) {
|
|
48571
|
-
return resolvePolicyLoadMode({
|
|
48572
|
-
surface: activeSurface,
|
|
48573
|
-
override: env[POLICY_LOAD_MODE_ENV],
|
|
48574
|
-
ci: typeof env.CI === "string" ? env.CI : void 0
|
|
48575
|
-
});
|
|
48576
|
-
}
|
|
48577
|
-
var POLICY_LOAD_MODE_ENV, POLICY_LOAD_BLOCK_REASON, POLICY_LOAD_EXIT_CODE, activeSurface;
|
|
48578
|
-
var init_policyLoadMode = __esm({
|
|
48579
|
-
"src/cli/safety/policyLoadMode.ts"() {
|
|
48580
|
-
"use strict";
|
|
48581
|
-
POLICY_LOAD_MODE_ENV = "ZELARI_POLICY_LOAD_MODE";
|
|
48582
|
-
POLICY_LOAD_BLOCK_REASON = "policy-load-failed";
|
|
48583
|
-
POLICY_LOAD_EXIT_CODE = 2;
|
|
48584
|
-
activeSurface = "tui";
|
|
48585
|
-
}
|
|
48586
|
-
});
|
|
48587
|
-
|
|
48588
|
-
// src/cli/safety/jails/darwin.ts
|
|
48589
|
-
import { existsSync as existsSync27 } from "node:fs";
|
|
48590
|
-
function sbplQuote(p3) {
|
|
48591
|
-
return `"${p3.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
48592
|
-
}
|
|
48593
|
-
function buildSeatbeltProfile(spec) {
|
|
48594
|
-
const lines = [
|
|
48595
|
-
"(version 1)",
|
|
48596
|
-
`; zelari osJail (t28) \u2014 generated from JailSpec root=${spec.root}`,
|
|
48597
|
-
"(allow default)",
|
|
48598
|
-
"(deny file-write*)",
|
|
48599
|
-
"(allow file-write*"
|
|
48600
|
-
];
|
|
48601
|
-
for (const dir of spec.writable) {
|
|
48602
|
-
lines.push(` (subpath ${sbplQuote(dir)})`);
|
|
48603
|
-
}
|
|
48604
|
-
lines.push(")");
|
|
48605
|
-
switch (spec.network.mode) {
|
|
48606
|
-
case "deny":
|
|
48607
|
-
lines.push("(deny network*)");
|
|
48608
|
-
break;
|
|
48609
|
-
case "allow":
|
|
48610
|
-
lines.push("(allow network*)");
|
|
48611
|
-
break;
|
|
48612
|
-
case "allow-list":
|
|
48613
|
-
lines.push(
|
|
48614
|
-
`; allow-list hosts (${spec.network.hosts.join(", ")}) NOT kernel-filtered \u2014 degraded to allow`,
|
|
48615
|
-
"(allow network*)"
|
|
48616
|
-
);
|
|
48617
|
-
break;
|
|
48618
|
-
}
|
|
48619
|
-
return lines.join("\n");
|
|
48620
|
-
}
|
|
48621
|
-
function darwinProbe(platform, exists) {
|
|
48622
|
-
if (platform !== "darwin") {
|
|
48623
|
-
return {
|
|
48624
|
-
backend: "seatbelt",
|
|
48625
|
-
available: false,
|
|
48626
|
-
reason: `platform ${platform} is not darwin`
|
|
48627
|
-
};
|
|
48628
|
-
}
|
|
48629
|
-
if (!exists(SANDBOX_EXEC_PATH)) {
|
|
48630
|
-
return {
|
|
48631
|
-
backend: "seatbelt",
|
|
48632
|
-
available: false,
|
|
48633
|
-
reason: `${SANDBOX_EXEC_PATH} not found`
|
|
48634
|
-
};
|
|
48635
|
-
}
|
|
48636
|
-
return {
|
|
48637
|
-
backend: "seatbelt",
|
|
48638
|
-
available: true,
|
|
48639
|
-
reason: `sandbox-exec available at ${SANDBOX_EXEC_PATH}`
|
|
48640
|
-
};
|
|
48641
|
-
}
|
|
48642
|
-
var SANDBOX_EXEC_PATH, darwinBackend;
|
|
48643
|
-
var init_darwin = __esm({
|
|
48644
|
-
"src/cli/safety/jails/darwin.ts"() {
|
|
48645
|
-
"use strict";
|
|
48646
|
-
SANDBOX_EXEC_PATH = "/usr/bin/sandbox-exec";
|
|
48647
|
-
darwinBackend = {
|
|
48648
|
-
id: "seatbelt",
|
|
48649
|
-
probe: () => darwinProbe(process.platform, (p3) => existsSync27(p3)),
|
|
48650
|
-
wrap: (spec, program, argv) => ({
|
|
48651
|
-
program: SANDBOX_EXEC_PATH,
|
|
48652
|
-
argv: ["-p", buildSeatbeltProfile(spec), program, ...argv]
|
|
48653
|
-
})
|
|
48654
|
-
};
|
|
48655
|
-
}
|
|
48656
|
-
});
|
|
48657
|
-
|
|
48658
|
-
// src/cli/safety/jails/linux.ts
|
|
48659
|
-
import { existsSync as existsSync28 } from "node:fs";
|
|
48660
|
-
function findBinaryOnPath(bin, pathValue, exists) {
|
|
48661
|
-
for (const dir of pathValue.split(/[:;]/)) {
|
|
48662
|
-
if (!dir) continue;
|
|
48663
|
-
const full = `${dir}/${bin}`;
|
|
48664
|
-
if (exists(full)) return full;
|
|
48665
|
-
}
|
|
48666
|
-
return null;
|
|
48667
|
-
}
|
|
48668
|
-
function linuxProbe(platform, pathValue, exists) {
|
|
48669
|
-
if (platform !== "linux") {
|
|
48670
|
-
return { backend: "bwrap", available: false, reason: `platform ${platform} is not linux` };
|
|
48671
|
-
}
|
|
48672
|
-
const found = findBinaryOnPath(BWRAP_BIN, pathValue, exists);
|
|
48673
|
-
if (!found) {
|
|
48674
|
-
return {
|
|
48675
|
-
backend: "bwrap",
|
|
48676
|
-
available: false,
|
|
48677
|
-
reason: `${BWRAP_BIN} not found on PATH (landlock needs native syscalls Node does not expose)`
|
|
48678
|
-
};
|
|
48679
|
-
}
|
|
48680
|
-
return { backend: "bwrap", available: true, reason: `${BWRAP_BIN} found at ${found}` };
|
|
48681
|
-
}
|
|
48682
|
-
function buildBwrapArgs(spec, program, argv) {
|
|
48683
|
-
const args = ["--ro-bind", "/", "/", "--dev", "/dev", "--proc", "/proc"];
|
|
48684
|
-
for (const dir of spec.writable) {
|
|
48685
|
-
args.push("--bind-try", dir, dir);
|
|
48686
|
-
}
|
|
48687
|
-
if (spec.network.mode === "deny") {
|
|
48688
|
-
args.push("--unshare-net");
|
|
48689
|
-
}
|
|
48690
|
-
args.push("--", program, ...argv);
|
|
48691
|
-
return args;
|
|
48692
|
-
}
|
|
48693
|
-
var BWRAP_BIN, linuxBackend;
|
|
48694
|
-
var init_linux = __esm({
|
|
48695
|
-
"src/cli/safety/jails/linux.ts"() {
|
|
48696
|
-
"use strict";
|
|
48697
|
-
BWRAP_BIN = "bwrap";
|
|
48698
|
-
linuxBackend = {
|
|
48699
|
-
id: "bwrap",
|
|
48700
|
-
probe: () => linuxProbe(process.platform, process.env.PATH ?? "", (p3) => existsSync28(p3)),
|
|
48701
|
-
wrap: (spec, program, argv) => ({
|
|
48702
|
-
program: BWRAP_BIN,
|
|
48703
|
-
argv: buildBwrapArgs(spec, program, argv)
|
|
48704
|
-
})
|
|
48705
|
-
};
|
|
48706
|
-
}
|
|
48707
|
-
});
|
|
48708
|
-
|
|
48709
|
-
// src/cli/safety/jails/win32.ts
|
|
48710
|
-
function win32Probe(platform) {
|
|
48711
|
-
if (platform !== "win32") {
|
|
48712
|
-
return { backend: "win32-restricted-token", available: false, reason: `platform ${platform} is not win32` };
|
|
48713
|
-
}
|
|
48714
|
-
return { backend: "win32-restricted-token", available: false, reason: WIN32_UNAVAILABLE_REASON };
|
|
48715
|
-
}
|
|
48716
|
-
var WIN32_UNAVAILABLE_REASON, win32Backend;
|
|
48717
|
-
var init_win32 = __esm({
|
|
48718
|
-
"src/cli/safety/jails/win32.ts"() {
|
|
48719
|
-
"use strict";
|
|
48720
|
-
WIN32_UNAVAILABLE_REASON = "restricted-token + Job Object require native Windows APIs that pure Node does not expose (no native npm deps allowed, P5) \u2014 honest unavailable; see src/cli/safety/jails/win32.ts";
|
|
48721
|
-
win32Backend = {
|
|
48722
|
-
id: "win32-restricted-token",
|
|
48723
|
-
probe: () => win32Probe(process.platform),
|
|
48724
|
-
wrap: () => {
|
|
48725
|
-
throw new Error(`win32 jail backend unavailable: ${WIN32_UNAVAILABLE_REASON}`);
|
|
48726
|
-
}
|
|
48727
|
-
};
|
|
48728
|
-
}
|
|
48729
|
-
});
|
|
48730
|
-
|
|
48731
|
-
// src/cli/safety/osJail.ts
|
|
48732
|
-
import { spawn as spawn10 } from "node:child_process";
|
|
48733
|
-
import { homedir as homedir5, tmpdir as tmpdir3 } from "node:os";
|
|
48734
|
-
import path50 from "node:path";
|
|
48735
|
-
function resolveJailMode(override, env = process.env) {
|
|
48736
|
-
const v = override?.trim().toLowerCase();
|
|
48737
|
-
if (v === "off") return "off";
|
|
48738
|
-
if (v === "advisory") return "advisory";
|
|
48739
|
-
if (v === "required") return "required";
|
|
48740
|
-
if (activePolicyLoadMode(env) !== "strict") return "advisory";
|
|
48741
|
-
return probeJailBackend().available ? "required" : "advisory";
|
|
48742
|
-
}
|
|
48743
|
-
function activeJailMode(env = process.env) {
|
|
48744
|
-
return resolveJailMode(env[OS_JAIL_ENV], env);
|
|
48745
|
-
}
|
|
48746
|
-
function platformBackend(platform = process.platform) {
|
|
48747
|
-
switch (platform) {
|
|
48748
|
-
case "darwin":
|
|
48749
|
-
return darwinBackend;
|
|
48750
|
-
case "linux":
|
|
48751
|
-
return linuxBackend;
|
|
48752
|
-
default:
|
|
48753
|
-
return win32Backend;
|
|
48754
|
-
}
|
|
48755
|
-
}
|
|
48756
|
-
function currentBackend(platform = process.platform) {
|
|
48757
|
-
return testBackend ?? platformBackend(platform);
|
|
48758
|
-
}
|
|
48759
|
-
function probeJailBackend(platform = process.platform) {
|
|
48760
|
-
if (testBackend) return testBackend.probe();
|
|
48761
|
-
if (!probeCache || probeCache.platform !== platform) {
|
|
48762
|
-
probeCache = { platform, result: platformBackend(platform).probe() };
|
|
48763
|
-
}
|
|
48764
|
-
return probeCache.result;
|
|
48765
|
-
}
|
|
48766
|
-
function defaultEnvAllowlist(platform = process.platform) {
|
|
48767
|
-
return platform === "win32" ? [...BASE_ENV_ALLOWLIST, ...WIN32_ENV_ALLOWLIST] : BASE_ENV_ALLOWLIST;
|
|
48768
|
-
}
|
|
48769
|
-
function defaultWritable(root, home = homedir5(), tmp = tmpdir3(), platform = process.platform) {
|
|
48770
|
-
const raw = [path50.resolve(root), path50.resolve(tmp), path50.join(home, ".zelari-code")];
|
|
48771
|
-
const out = [];
|
|
48772
|
-
for (const p3 of raw) {
|
|
48773
|
-
const key = platform === "win32" ? p3.toLowerCase() : p3;
|
|
48774
|
-
if (!out.some((q) => (platform === "win32" ? q.toLowerCase() : q) === key)) out.push(p3);
|
|
48775
|
-
}
|
|
48776
|
-
return out;
|
|
48777
|
-
}
|
|
48778
|
-
function buildJailSpec(opts) {
|
|
48779
|
-
return {
|
|
48780
|
-
root: path50.resolve(opts.root),
|
|
48781
|
-
network: opts.network ?? { mode: "deny" },
|
|
48782
|
-
envAllowlist: opts.envAllowlist ?? defaultEnvAllowlist(),
|
|
48783
|
-
writable: opts.writable ?? defaultWritable(opts.root)
|
|
48784
|
-
};
|
|
48785
|
-
}
|
|
48786
|
-
function networkSpecFromClaimHosts(allowedHosts) {
|
|
48787
|
-
if (!allowedHosts || allowedHosts.length === 0) return { mode: "deny" };
|
|
48788
|
-
return { mode: "allow-list", hosts: [...new Set(allowedHosts)] };
|
|
48789
|
-
}
|
|
48790
|
-
function sanitizeEnv(env, allowlist, platform = process.platform) {
|
|
48791
|
-
const wanted = new Set(allowlist.map((k) => platform === "win32" ? k.toLowerCase() : k));
|
|
48792
|
-
const out = {};
|
|
48793
|
-
for (const [k, v] of Object.entries(env)) {
|
|
48794
|
-
if (v === void 0) continue;
|
|
48795
|
-
const key = platform === "win32" ? k.toLowerCase() : k;
|
|
48796
|
-
if (wanted.has(key)) out[k] = v;
|
|
48797
|
-
}
|
|
48798
|
-
return out;
|
|
48799
|
-
}
|
|
48800
|
-
function jailDenyReason(probe, mode) {
|
|
48801
|
-
return `OS jail backend unavailable (${probe.backend}: ${probe.reason}) with ZELARI_OS_JAIL=${mode} \u2014 execution is DENIED instead of running unjailed (t28 golden rule: missing backend + required \u21D2 deny, never warn/skip). Set ZELARI_OS_JAIL=advisory (visible fail-open) or =off to explicitly allow unjailed execution.`;
|
|
48802
|
-
}
|
|
48803
|
-
function jailAdvisoryNotice(probe) {
|
|
48804
|
-
return `advisory: OS jail backend unavailable (${probe.backend}: ${probe.reason}) \u2014 this process will run UNJAILED (visible fail-open). Set ZELARI_OS_JAIL=required to deny instead.`;
|
|
48805
|
-
}
|
|
48806
|
-
function decideJailSpawn(spec, input) {
|
|
48807
|
-
const mode = input.mode ?? activeJailMode();
|
|
48808
|
-
const merged = { ...input.env ?? process.env, ...input.envExtras ?? {} };
|
|
48809
|
-
if (mode === "off") return { action: "spawn-plain", env: merged };
|
|
48810
|
-
const probe = probeJailBackend();
|
|
48811
|
-
if (!probe.available) {
|
|
48812
|
-
if (mode === "required") return { action: "deny", reason: jailDenyReason(probe, mode) };
|
|
48813
|
-
return { action: "spawn-plain", env: sanitizeEnv(merged, spec.envAllowlist), notice: jailAdvisoryNotice(probe) };
|
|
48814
|
-
}
|
|
48815
|
-
const wrapped = currentBackend().wrap(spec, input.program, input.argv);
|
|
48816
|
-
return {
|
|
48817
|
-
action: "spawn-jailed",
|
|
48818
|
-
probe,
|
|
48819
|
-
program: wrapped.program,
|
|
48820
|
-
argv: wrapped.argv,
|
|
48821
|
-
env: sanitizeEnv(merged, spec.envAllowlist)
|
|
48822
|
-
};
|
|
48823
|
-
}
|
|
48824
|
-
function spawnJailed(spec, req) {
|
|
48825
|
-
const decision = decideJailSpawn(spec, {
|
|
48826
|
-
program: req.program,
|
|
48827
|
-
argv: req.argv,
|
|
48828
|
-
env: req.env,
|
|
48829
|
-
envExtras: req.envExtras
|
|
48830
|
-
});
|
|
48831
|
-
if (decision.action === "deny") {
|
|
48832
|
-
return { outcome: "denied", reason: `[jail] ${decision.reason}` };
|
|
48833
|
-
}
|
|
48834
|
-
const notice = decision.action === "spawn-plain" ? decision.notice : void 0;
|
|
48835
|
-
if (notice) {
|
|
48836
|
-
console.error(`[os-jail] ${notice}`);
|
|
48837
|
-
req.onNotice?.(notice);
|
|
48838
|
-
}
|
|
48839
|
-
const jailed = decision.action === "spawn-jailed";
|
|
48840
|
-
const program = jailed ? decision.program : req.program;
|
|
48841
|
-
const argv = jailed ? decision.argv : [...req.argv];
|
|
48842
|
-
try {
|
|
48843
|
-
const child = spawn10(program, argv, {
|
|
48844
|
-
cwd: req.cwd,
|
|
48845
|
-
signal: req.signal,
|
|
48846
|
-
shell: false,
|
|
48847
|
-
env: decision.env,
|
|
48848
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
48849
|
-
// non-interactive by construction
|
|
48850
|
-
});
|
|
48851
|
-
return {
|
|
48852
|
-
outcome: "spawned",
|
|
48853
|
-
child,
|
|
48854
|
-
backend: jailed ? decision.probe.backend : "none",
|
|
48855
|
-
jailed,
|
|
48856
|
-
...notice ? { notice } : {}
|
|
48857
|
-
};
|
|
48858
|
-
} catch (err) {
|
|
48859
|
-
return { outcome: "failed", reason: err instanceof Error ? err.message : String(err) };
|
|
48860
|
-
}
|
|
48861
|
-
}
|
|
48862
|
-
function jailAvailability(env = process.env) {
|
|
48863
|
-
const mode = activeJailMode(env);
|
|
48864
|
-
const probe = mode === "off" ? { backend: "none", available: false, reason: "jail disabled (ZELARI_OS_JAIL=off)" } : probeJailBackend();
|
|
48865
|
-
return { mode, probe };
|
|
48866
|
-
}
|
|
48867
|
-
var OS_JAIL_ENV, testBackend, probeCache, BASE_ENV_ALLOWLIST, WIN32_ENV_ALLOWLIST;
|
|
48868
|
-
var init_osJail = __esm({
|
|
48869
|
-
"src/cli/safety/osJail.ts"() {
|
|
48870
|
-
"use strict";
|
|
48871
|
-
init_policyLoadMode();
|
|
48872
|
-
init_darwin();
|
|
48873
|
-
init_linux();
|
|
48874
|
-
init_win32();
|
|
48875
|
-
OS_JAIL_ENV = "ZELARI_OS_JAIL";
|
|
48876
|
-
testBackend = null;
|
|
48877
|
-
probeCache = null;
|
|
48878
|
-
BASE_ENV_ALLOWLIST = [
|
|
48879
|
-
"PATH",
|
|
48880
|
-
"HOME",
|
|
48881
|
-
"USER",
|
|
48882
|
-
"LANG",
|
|
48883
|
-
"CI",
|
|
48884
|
-
"TERM",
|
|
48885
|
-
"NO_COLOR"
|
|
48886
|
-
];
|
|
48887
|
-
WIN32_ENV_ALLOWLIST = [
|
|
48888
|
-
"PATH",
|
|
48889
|
-
"Path",
|
|
48890
|
-
"HOMEDRIVE",
|
|
48891
|
-
"HOMEPATH",
|
|
48892
|
-
"SystemRoot",
|
|
48893
|
-
"SystemDrive",
|
|
48894
|
-
"ComSpec",
|
|
48895
|
-
"PATHEXT",
|
|
48896
|
-
"TEMP",
|
|
48897
|
-
"TMP",
|
|
48898
|
-
"APPDATA",
|
|
48899
|
-
"LOCALAPPDATA",
|
|
48900
|
-
"USERPROFILE",
|
|
48901
|
-
"USERNAME",
|
|
48902
|
-
"MSYSTEM",
|
|
48903
|
-
"PROGRAMFILES",
|
|
48904
|
-
"ProgramFiles",
|
|
48905
|
-
"ProgramData",
|
|
48906
|
-
"OS",
|
|
48907
|
-
"NUMBER_OF_PROCESSORS",
|
|
48908
|
-
"PROCESSOR_ARCHITECTURE",
|
|
48909
|
-
"WINDIR"
|
|
48910
|
-
];
|
|
48911
|
-
}
|
|
48912
|
-
});
|
|
48913
|
-
|
|
48914
49088
|
// src/cli/tools/execProcess.ts
|
|
48915
49089
|
function createExecProcessTool(root, opts = {}) {
|
|
48916
49090
|
const baseSpec = buildJailSpec({ root });
|
|
@@ -52425,6 +52599,21 @@ var init_resolveStream = __esm({
|
|
|
52425
52599
|
});
|
|
52426
52600
|
|
|
52427
52601
|
// src/cli/safety/toolPermissions.ts
|
|
52602
|
+
var toolPermissions_exports = {};
|
|
52603
|
+
__export(toolPermissions_exports, {
|
|
52604
|
+
PERMISSION_PRESETS: () => PERMISSION_PRESETS,
|
|
52605
|
+
activePermissionPreset: () => activePermissionPreset,
|
|
52606
|
+
clearSessionPermissionGrants: () => clearSessionPermissionGrants,
|
|
52607
|
+
defaultPermissionPolicy: () => defaultPermissionPolicy,
|
|
52608
|
+
grantSessionCategory: () => grantSessionCategory,
|
|
52609
|
+
grantSessionTool: () => grantSessionTool,
|
|
52610
|
+
intersectPermissionPolicy: () => intersectPermissionPolicy,
|
|
52611
|
+
isAutoPermissions: () => isAutoPermissions,
|
|
52612
|
+
isSessionGranted: () => isSessionGranted,
|
|
52613
|
+
listSessionPermissionGrants: () => listSessionPermissionGrants,
|
|
52614
|
+
parsePermissionPreset: () => parsePermissionPreset,
|
|
52615
|
+
resolveToolPermission: () => resolveToolPermission
|
|
52616
|
+
});
|
|
52428
52617
|
function grantSessionTool(toolName) {
|
|
52429
52618
|
const n = toolName.trim();
|
|
52430
52619
|
if (n) sessionToolGrants.add(n);
|
|
@@ -52436,6 +52625,12 @@ function clearSessionPermissionGrants() {
|
|
|
52436
52625
|
sessionToolGrants.clear();
|
|
52437
52626
|
sessionCategoryGrants.clear();
|
|
52438
52627
|
}
|
|
52628
|
+
function listSessionPermissionGrants() {
|
|
52629
|
+
return {
|
|
52630
|
+
tools: [...sessionToolGrants].sort(),
|
|
52631
|
+
categories: [...sessionCategoryGrants]
|
|
52632
|
+
};
|
|
52633
|
+
}
|
|
52439
52634
|
function isSessionGranted(toolName, required2) {
|
|
52440
52635
|
if (sessionToolGrants.has(toolName)) return true;
|
|
52441
52636
|
if (!required2.length) return false;
|
|
@@ -52532,6 +52727,49 @@ var init_toolPermissions = __esm({
|
|
|
52532
52727
|
}
|
|
52533
52728
|
});
|
|
52534
52729
|
|
|
52730
|
+
// src/cli/safety/destructiveCommands.ts
|
|
52731
|
+
function commandTextFrom(input) {
|
|
52732
|
+
const parts = [];
|
|
52733
|
+
if (typeof input.command === "string" && input.command) parts.push(input.command);
|
|
52734
|
+
if (typeof input.program === "string" && input.program) {
|
|
52735
|
+
const args = Array.isArray(input.args) ? input.args.filter((a) => typeof a === "string") : [];
|
|
52736
|
+
parts.push([input.program, ...args].join(" "));
|
|
52737
|
+
}
|
|
52738
|
+
return parts.join(" ; ");
|
|
52739
|
+
}
|
|
52740
|
+
function destructiveCommandHit(input) {
|
|
52741
|
+
const text = commandTextFrom(input);
|
|
52742
|
+
if (!text) return null;
|
|
52743
|
+
for (const rule of DESTRUCTIVE_RULES) {
|
|
52744
|
+
if (rule.pattern.test(text)) return rule.label;
|
|
52745
|
+
}
|
|
52746
|
+
return null;
|
|
52747
|
+
}
|
|
52748
|
+
var DESTRUCTIVE_RULES;
|
|
52749
|
+
var init_destructiveCommands = __esm({
|
|
52750
|
+
"src/cli/safety/destructiveCommands.ts"() {
|
|
52751
|
+
"use strict";
|
|
52752
|
+
DESTRUCTIVE_RULES = [
|
|
52753
|
+
// `rm` with BOTH recursive and force flags, any combination (-rf, -fr, -rvf).
|
|
52754
|
+
{ id: "rm-recursive-force", pattern: /\brm\s+(?:-{1,2}[a-z]*r[a-z]*f|-{1,2}[a-z]*f[a-z]*r)\b/i, label: "'rm' recursive+force delete" },
|
|
52755
|
+
// Windows del/rd with the /s (subdirectories) switch.
|
|
52756
|
+
{ id: "del-subtree", pattern: /\bdel\b[^&|;]*\/s\b/i, label: "'del /s' subtree delete" },
|
|
52757
|
+
{ id: "rd-subtree", pattern: /\brd\b[^&|;]*\/s\b/i, label: "'rd /s' subtree delete" },
|
|
52758
|
+
// PowerShell recursive delete.
|
|
52759
|
+
{ id: "remove-item-recurse", pattern: /\bremove-item\b[^&|;]*-recurse\b/i, label: "'Remove-Item -Recurse' recursive delete" },
|
|
52760
|
+
// Volume format (DOS/Windows drive letter form).
|
|
52761
|
+
{ id: "format-volume", pattern: /\bformat\s+[a-z]:/i, label: "'format <volume>:'" },
|
|
52762
|
+
// History rewrite on a shared ref.
|
|
52763
|
+
{ id: "git-push-force", pattern: /\bgit\s+push\b[^&|;]*--force\b/i, label: "'git push --force'" },
|
|
52764
|
+
// Filesystem-level destroyers.
|
|
52765
|
+
{ id: "mkfs", pattern: /\bmkfs(?:\.\w+)?\b/i, label: "'mkfs' filesystem format" },
|
|
52766
|
+
{ id: "dd-raw-device", pattern: /\bdd\b[^&|;]*of=\/dev\//i, label: "'dd' raw device write" },
|
|
52767
|
+
// Root-wide permission wipe.
|
|
52768
|
+
{ id: "chmod-root-777", pattern: /\bchmod\s+-R\s+777\s+\/(?:\s|$)/i, label: "'chmod -R 777 /' root permission wipe" }
|
|
52769
|
+
];
|
|
52770
|
+
}
|
|
52771
|
+
});
|
|
52772
|
+
|
|
52535
52773
|
// src/cli/safety/provenance.ts
|
|
52536
52774
|
function provenanceEnabled() {
|
|
52537
52775
|
return process.env.ZELARI_PROVENANCE !== "0";
|
|
@@ -53907,6 +54145,13 @@ function wrapWithPermissions(original, policy, onAsk, agentLayers, precedence =
|
|
|
53907
54145
|
}
|
|
53908
54146
|
}
|
|
53909
54147
|
}
|
|
54148
|
+
if (action === "allow" && required2.includes("execute") && activePermissionPreset() !== "yolo" && !isSessionGranted(original.name, required2)) {
|
|
54149
|
+
const destructiveHit = destructiveCommandHit(input ?? {});
|
|
54150
|
+
if (destructiveHit) {
|
|
54151
|
+
action = "ask";
|
|
54152
|
+
actionReason = `[destructive] ${destructiveHit} - confirm before execute`;
|
|
54153
|
+
}
|
|
54154
|
+
}
|
|
53910
54155
|
const claimHit = claims && claims.effect !== void 0 ? claims.matchedRules.find((x) => x.effect === claims.effect) : void 0;
|
|
53911
54156
|
const rulePrefix = contractRule ? `[contract] rule '${contractRule.match}'${contractRule.reason ? ` \u2014 ${contractRule.reason}` : ""}` : rule ? `[policy] rule '${rule.match}'${rule.reason ? ` \u2014 ${rule.reason}` : ""}` : claimHit ? `[policy] claim '${claimHit.match}'${claimHit.reason ? ` \u2014 ${claimHit.reason}` : ""}` : "";
|
|
53912
54157
|
if (action === "deny") {
|
|
@@ -54328,6 +54573,7 @@ var init_toolRegistry = __esm({
|
|
|
54328
54573
|
init_resolveStream();
|
|
54329
54574
|
init_providerConfig();
|
|
54330
54575
|
init_toolPermissions();
|
|
54576
|
+
init_destructiveCommands();
|
|
54331
54577
|
init_provenance();
|
|
54332
54578
|
init_lifecycleHooks();
|
|
54333
54579
|
init_astGate();
|
|
@@ -57039,6 +57285,113 @@ var init_claudeProvider = __esm({
|
|
|
57039
57285
|
}
|
|
57040
57286
|
});
|
|
57041
57287
|
|
|
57288
|
+
// src/cli/costBudget.ts
|
|
57289
|
+
var costBudget_exports = {};
|
|
57290
|
+
__export(costBudget_exports, {
|
|
57291
|
+
SessionBudgetTracker: () => SessionBudgetTracker,
|
|
57292
|
+
budgetChip: () => budgetChip,
|
|
57293
|
+
processSessionBudget: () => processSessionBudget,
|
|
57294
|
+
resetProcessSessionBudget: () => resetProcessSessionBudget,
|
|
57295
|
+
resolveSessionBudget: () => resolveSessionBudget,
|
|
57296
|
+
sessionBudgetHoldNotice: () => sessionBudgetHoldNotice
|
|
57297
|
+
});
|
|
57298
|
+
function resolveSessionBudget(env = process.env) {
|
|
57299
|
+
const maxUsd = parsePositiveFloat(env.ZELARI_SESSION_BUDGET_USD);
|
|
57300
|
+
const maxTokens = parsePositiveInt(env.ZELARI_SESSION_BUDGET_TOKENS);
|
|
57301
|
+
if (maxUsd === void 0 && maxTokens === void 0) return {};
|
|
57302
|
+
return { ...maxUsd !== void 0 ? { maxUsd } : {}, ...maxTokens !== void 0 ? { maxTokens } : {} };
|
|
57303
|
+
}
|
|
57304
|
+
function parsePositiveFloat(raw) {
|
|
57305
|
+
if (!raw) return void 0;
|
|
57306
|
+
const n = Number.parseFloat(raw);
|
|
57307
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
57308
|
+
}
|
|
57309
|
+
function parsePositiveInt(raw) {
|
|
57310
|
+
if (!raw) return void 0;
|
|
57311
|
+
const n = Number.parseInt(raw, 10);
|
|
57312
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
57313
|
+
}
|
|
57314
|
+
function round6(value) {
|
|
57315
|
+
return Math.round(value * 1e6) / 1e6;
|
|
57316
|
+
}
|
|
57317
|
+
function processSessionBudget(env = process.env) {
|
|
57318
|
+
if (!processTracker) processTracker = new SessionBudgetTracker(resolveSessionBudget(env));
|
|
57319
|
+
return processTracker;
|
|
57320
|
+
}
|
|
57321
|
+
function resetProcessSessionBudget() {
|
|
57322
|
+
processTracker = void 0;
|
|
57323
|
+
}
|
|
57324
|
+
function sessionBudgetHoldNotice(env = process.env) {
|
|
57325
|
+
const budget = processSessionBudget(env);
|
|
57326
|
+
if (!budget.isHold()) return null;
|
|
57327
|
+
const s = budget.status();
|
|
57328
|
+
return `[budget] HOLD \u2014 session budget exhausted (${s.usedUsd.toFixed(2)} USD \xB7 ${s.usedTokens} tokens). Raise ZELARI_SESSION_BUDGET_USD / ZELARI_SESSION_BUDGET_TOKENS or start /new. State preserved; no provider call was made.`;
|
|
57329
|
+
}
|
|
57330
|
+
function budgetChip(status) {
|
|
57331
|
+
if (status.state === "off") return null;
|
|
57332
|
+
const pct = Math.max(status.pctUsd ?? 0, status.pctTokens ?? 0);
|
|
57333
|
+
const label = status.state === "hold" ? "budget HOLD" : `budget ${Math.min(999, Math.round(pct * 100))}%`;
|
|
57334
|
+
const tone = status.state === "hold" ? "red" : status.state === "warn" ? "yellow" : "green";
|
|
57335
|
+
return { label, tone };
|
|
57336
|
+
}
|
|
57337
|
+
var SessionBudgetTracker, processTracker;
|
|
57338
|
+
var init_costBudget = __esm({
|
|
57339
|
+
"src/cli/costBudget.ts"() {
|
|
57340
|
+
"use strict";
|
|
57341
|
+
SessionBudgetTracker = class {
|
|
57342
|
+
constructor(budget = {}) {
|
|
57343
|
+
this.budget = budget;
|
|
57344
|
+
}
|
|
57345
|
+
usedUsd = 0;
|
|
57346
|
+
usedTokens = 0;
|
|
57347
|
+
get enabled() {
|
|
57348
|
+
return this.budget.maxUsd !== void 0 || this.budget.maxTokens !== void 0;
|
|
57349
|
+
}
|
|
57350
|
+
/** Idempotent per-turn accumulation; ignores NaN/negative inputs. */
|
|
57351
|
+
record(delta) {
|
|
57352
|
+
if (Number.isFinite(delta.costUsd) && (delta.costUsd ?? 0) > 0) this.usedUsd += delta.costUsd ?? 0;
|
|
57353
|
+
if (Number.isFinite(delta.tokens) && (delta.tokens ?? 0) > 0) this.usedTokens += Math.round(delta.tokens ?? 0);
|
|
57354
|
+
}
|
|
57355
|
+
status() {
|
|
57356
|
+
if (!this.enabled) return { state: "off", usedUsd: this.usedUsd, usedTokens: this.usedTokens, pctUsd: null, pctTokens: null };
|
|
57357
|
+
const pctUsd = this.budget.maxUsd !== void 0 ? this.usedUsd / this.budget.maxUsd : null;
|
|
57358
|
+
const pctTokens = this.budget.maxTokens !== void 0 ? this.usedTokens / this.budget.maxTokens : null;
|
|
57359
|
+
const worst = Math.max(pctUsd ?? 0, pctTokens ?? 0);
|
|
57360
|
+
const state3 = worst >= 1 ? "hold" : worst >= 0.8 ? "warn" : "ok";
|
|
57361
|
+
return { state: state3, usedUsd: round6(this.usedUsd), usedTokens: this.usedTokens, pctUsd, pctTokens };
|
|
57362
|
+
}
|
|
57363
|
+
/** True when no further provider turn should start. */
|
|
57364
|
+
isHold() {
|
|
57365
|
+
return this.status().state === "hold";
|
|
57366
|
+
}
|
|
57367
|
+
};
|
|
57368
|
+
}
|
|
57369
|
+
});
|
|
57370
|
+
|
|
57371
|
+
// src/cli/workspace/planDetect.ts
|
|
57372
|
+
var planDetect_exports = {};
|
|
57373
|
+
__export(planDetect_exports, {
|
|
57374
|
+
hasWorkspacePlan: () => hasWorkspacePlan
|
|
57375
|
+
});
|
|
57376
|
+
import { existsSync as existsSync35, readFileSync as readFileSync25 } from "node:fs";
|
|
57377
|
+
import { join as join23 } from "node:path";
|
|
57378
|
+
function hasWorkspacePlan(projectRoot = process.cwd()) {
|
|
57379
|
+
const planPath = join23(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
57380
|
+
if (!existsSync35(planPath)) return false;
|
|
57381
|
+
try {
|
|
57382
|
+
const parsed = JSON.parse(readFileSync25(planPath, "utf8"));
|
|
57383
|
+
return Array.isArray(parsed.phases) && parsed.phases.length > 0;
|
|
57384
|
+
} catch {
|
|
57385
|
+
return false;
|
|
57386
|
+
}
|
|
57387
|
+
}
|
|
57388
|
+
var init_planDetect = __esm({
|
|
57389
|
+
"src/cli/workspace/planDetect.ts"() {
|
|
57390
|
+
"use strict";
|
|
57391
|
+
init_paths3();
|
|
57392
|
+
}
|
|
57393
|
+
});
|
|
57394
|
+
|
|
57042
57395
|
// src/cli/memory/legacyImport.ts
|
|
57043
57396
|
import { createHash as createHash18 } from "node:crypto";
|
|
57044
57397
|
import { promises as fs27 } from "node:fs";
|
|
@@ -57241,7 +57594,7 @@ var init_sqliteCodec = __esm({
|
|
|
57241
57594
|
});
|
|
57242
57595
|
|
|
57243
57596
|
// src/cli/memory/sqliteRpc.ts
|
|
57244
|
-
import { existsSync as
|
|
57597
|
+
import { existsSync as existsSync36 } from "node:fs";
|
|
57245
57598
|
import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
57246
57599
|
import * as path67 from "node:path";
|
|
57247
57600
|
import { Worker } from "node:worker_threads";
|
|
@@ -57254,7 +57607,7 @@ function isBusy(error51) {
|
|
|
57254
57607
|
function resolveWorkerUrl() {
|
|
57255
57608
|
const here = path67.dirname(fileURLToPath2(import.meta.url));
|
|
57256
57609
|
const direct = path67.join(here, "sqliteWorker.mjs");
|
|
57257
|
-
if (
|
|
57610
|
+
if (existsSync36(direct)) return pathToFileURL2(direct);
|
|
57258
57611
|
return pathToFileURL2(path67.join(here, "memory", "sqliteWorker.mjs"));
|
|
57259
57612
|
}
|
|
57260
57613
|
var SqliteWorkerRpc;
|
|
@@ -58261,14 +58614,14 @@ var init_serviceFactory = __esm({
|
|
|
58261
58614
|
});
|
|
58262
58615
|
|
|
58263
58616
|
// src/cli/workspace/projectInstructions.ts
|
|
58264
|
-
import { existsSync as
|
|
58265
|
-
import { join as
|
|
58617
|
+
import { existsSync as existsSync37, readFileSync as readFileSync26 } from "node:fs";
|
|
58618
|
+
import { join as join27 } from "node:path";
|
|
58266
58619
|
function loadProjectInstructions(projectRoot = process.cwd(), maxChars = MAX_CHARS) {
|
|
58267
58620
|
for (const name of CANDIDATES) {
|
|
58268
|
-
const full =
|
|
58269
|
-
if (!
|
|
58621
|
+
const full = join27(projectRoot, name);
|
|
58622
|
+
if (!existsSync37(full)) continue;
|
|
58270
58623
|
try {
|
|
58271
|
-
let raw =
|
|
58624
|
+
let raw = readFileSync26(full, "utf8");
|
|
58272
58625
|
raw = raw.replace(/\r\n/g, "\n").trim();
|
|
58273
58626
|
if (!raw) continue;
|
|
58274
58627
|
if (raw.length <= maxChars) {
|
|
@@ -58312,8 +58665,8 @@ __export(workspaceSummary_exports, {
|
|
|
58312
58665
|
buildWorkspaceSummary: () => buildWorkspaceSummary,
|
|
58313
58666
|
buildZelariReadHint: () => buildZelariReadHint
|
|
58314
58667
|
});
|
|
58315
|
-
import { existsSync as
|
|
58316
|
-
import { join as
|
|
58668
|
+
import { existsSync as existsSync38, readFileSync as readFileSync27, readdirSync as readdirSync7, statSync as statSync5 } from "node:fs";
|
|
58669
|
+
import { join as join28, relative as relative2 } from "node:path";
|
|
58317
58670
|
function buildWorkspaceSummary(projectRoot = process.cwd(), options = {}) {
|
|
58318
58671
|
const { maxEntries = 30, maxChars = 3500, maxDeps = 24, maxScripts = 16 } = options;
|
|
58319
58672
|
const name = safeProjectName(projectRoot);
|
|
@@ -58346,11 +58699,11 @@ function formatTaskLine(t) {
|
|
|
58346
58699
|
}
|
|
58347
58700
|
function buildPlanSummary(projectRoot = process.cwd(), options) {
|
|
58348
58701
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
58349
|
-
const planPath =
|
|
58350
|
-
if (!
|
|
58702
|
+
const planPath = join28(zelariRoot, "plan.json");
|
|
58703
|
+
if (!existsSync38(planPath)) return null;
|
|
58351
58704
|
let plan;
|
|
58352
58705
|
try {
|
|
58353
|
-
plan = JSON.parse(
|
|
58706
|
+
plan = JSON.parse(readFileSync27(planPath, "utf8"));
|
|
58354
58707
|
} catch {
|
|
58355
58708
|
return null;
|
|
58356
58709
|
}
|
|
@@ -58489,8 +58842,8 @@ function pickNextTask(open2) {
|
|
|
58489
58842
|
)[0];
|
|
58490
58843
|
}
|
|
58491
58844
|
function buildZelariReadHint(projectRoot = process.cwd()) {
|
|
58492
|
-
const planPath =
|
|
58493
|
-
if (!
|
|
58845
|
+
const planPath = join28(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
58846
|
+
if (!existsSync38(planPath)) return "";
|
|
58494
58847
|
return [
|
|
58495
58848
|
"# Council workspace detected (.zelari/) \u2014 DRAFT vault",
|
|
58496
58849
|
"`.zelari/plan.json` and `.zelari/docs/` hold **design hypotheses**, not verified product state.",
|
|
@@ -58505,10 +58858,10 @@ function safeProjectName(root) {
|
|
|
58505
58858
|
}
|
|
58506
58859
|
}
|
|
58507
58860
|
function readPackageJson2(projectRoot) {
|
|
58508
|
-
const p3 =
|
|
58509
|
-
if (!
|
|
58861
|
+
const p3 = join28(projectRoot, "package.json");
|
|
58862
|
+
if (!existsSync38(p3)) return null;
|
|
58510
58863
|
try {
|
|
58511
|
-
return JSON.parse(
|
|
58864
|
+
return JSON.parse(readFileSync27(p3, "utf8"));
|
|
58512
58865
|
} catch {
|
|
58513
58866
|
return null;
|
|
58514
58867
|
}
|
|
@@ -58558,11 +58911,11 @@ function listShallow(projectRoot, maxEntries) {
|
|
|
58558
58911
|
out.push(`\u2026 (+${top.length - count} more)`);
|
|
58559
58912
|
break;
|
|
58560
58913
|
}
|
|
58561
|
-
const rel2 = relative2(projectRoot,
|
|
58914
|
+
const rel2 = relative2(projectRoot, join28(projectRoot, entry.name));
|
|
58562
58915
|
if (entry.isDirectory()) {
|
|
58563
58916
|
let inner = "";
|
|
58564
58917
|
try {
|
|
58565
|
-
const sub = readdirSync7(
|
|
58918
|
+
const sub = readdirSync7(join28(projectRoot, entry.name), {
|
|
58566
58919
|
withFileTypes: true
|
|
58567
58920
|
}).filter((e) => !e.name.startsWith(".")).slice(0, 4).map((e) => e.name);
|
|
58568
58921
|
if (sub.length > 0)
|
|
@@ -58610,12 +58963,12 @@ var init_workspaceSummary = __esm({
|
|
|
58610
58963
|
});
|
|
58611
58964
|
|
|
58612
58965
|
// src/cli/workspace/buildLessonsSummary.ts
|
|
58613
|
-
import { existsSync as
|
|
58614
|
-
import { join as
|
|
58966
|
+
import { existsSync as existsSync39 } from "node:fs";
|
|
58967
|
+
import { join as join29 } from "node:path";
|
|
58615
58968
|
function buildLessonsSummary(projectRoot = process.cwd(), taskText) {
|
|
58616
58969
|
if (process.env["ZELARI_LESSONS"] === "0") return null;
|
|
58617
58970
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
58618
|
-
if (!
|
|
58971
|
+
if (!existsSync39(join29(zelariRoot, "lessons.jsonl"))) return null;
|
|
58619
58972
|
const lessons = recallLessons(zelariRoot, {
|
|
58620
58973
|
maxLessons: 5,
|
|
58621
58974
|
maxBytes: 2048,
|
|
@@ -58636,8 +58989,8 @@ var composeContext_exports = {};
|
|
|
58636
58989
|
__export(composeContext_exports, {
|
|
58637
58990
|
composeProjectContext: () => composeProjectContext
|
|
58638
58991
|
});
|
|
58639
|
-
import { existsSync as
|
|
58640
|
-
import { join as
|
|
58992
|
+
import { existsSync as existsSync40, readdirSync as readdirSync8, readFileSync as readFileSync28 } from "node:fs";
|
|
58993
|
+
import { join as join30 } from "node:path";
|
|
58641
58994
|
function cap2(text, max, label) {
|
|
58642
58995
|
if (!text || text.length <= max) return { text: text || "", truncated: false };
|
|
58643
58996
|
return {
|
|
@@ -58649,13 +59002,13 @@ function cap2(text, max, label) {
|
|
|
58649
59002
|
}
|
|
58650
59003
|
function buildDesignIndex(projectRoot, maxChars) {
|
|
58651
59004
|
const root = resolveWorkspaceRoot(projectRoot);
|
|
58652
|
-
if (!
|
|
59005
|
+
if (!existsSync40(root)) return "";
|
|
58653
59006
|
const lines = [
|
|
58654
59007
|
"# Design vault index (.zelari/) \u2014 HYPOTHESES only",
|
|
58655
59008
|
"Full design docs are NOT product source of truth. Open with list_files / read_file / searchDocuments if needed."
|
|
58656
59009
|
];
|
|
58657
|
-
const docsDir =
|
|
58658
|
-
if (
|
|
59010
|
+
const docsDir = join30(root, "docs");
|
|
59011
|
+
if (existsSync40(docsDir)) {
|
|
58659
59012
|
try {
|
|
58660
59013
|
const docs = readdirSync8(docsDir).filter((n) => n.endsWith(".md")).slice(0, 12);
|
|
58661
59014
|
if (docs.length > 0) {
|
|
@@ -58669,12 +59022,12 @@ function buildDesignIndex(projectRoot, maxChars) {
|
|
|
58669
59022
|
}
|
|
58670
59023
|
}
|
|
58671
59024
|
for (const name of ["risks.md", "plan.json", "nfr-spec.json"]) {
|
|
58672
|
-
if (
|
|
59025
|
+
if (existsSync40(join30(root, name))) {
|
|
58673
59026
|
lines.push(`- .zelari/${name} present`);
|
|
58674
59027
|
}
|
|
58675
59028
|
}
|
|
58676
|
-
const decisionsDir =
|
|
58677
|
-
if (
|
|
59029
|
+
const decisionsDir = join30(root, "decisions");
|
|
59030
|
+
if (existsSync40(decisionsDir)) {
|
|
58678
59031
|
try {
|
|
58679
59032
|
const n = readdirSync8(decisionsDir).filter((f) => f.endsWith(".md")).length;
|
|
58680
59033
|
if (n > 0) lines.push(`- .zelari/decisions/ (${n} ADR file(s) \u2014 treat proposed as non-binding)`);
|
|
@@ -58775,17 +59128,17 @@ function composeProjectContext(input) {
|
|
|
58775
59128
|
}
|
|
58776
59129
|
function readDurableHeadSync(projectRoot) {
|
|
58777
59130
|
try {
|
|
58778
|
-
const headPath =
|
|
58779
|
-
if (!
|
|
58780
|
-
const head = JSON.parse(
|
|
59131
|
+
const headPath = join30(projectRoot, ".zelari", "state", "HEAD.json");
|
|
59132
|
+
if (!existsSync40(headPath)) return "";
|
|
59133
|
+
const head = JSON.parse(readFileSync28(headPath, "utf8"));
|
|
58781
59134
|
if (!head?.id) return "";
|
|
58782
|
-
const metaPath =
|
|
58783
|
-
if (!
|
|
58784
|
-
const meta3 = JSON.parse(
|
|
58785
|
-
const discPath = meta3.artifactDir ?
|
|
59135
|
+
const metaPath = join30(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
|
|
59136
|
+
if (!existsSync40(metaPath)) return "";
|
|
59137
|
+
const meta3 = JSON.parse(readFileSync28(metaPath, "utf8"));
|
|
59138
|
+
const discPath = meta3.artifactDir ? join30(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join30(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
|
|
58786
59139
|
let discoveries = [];
|
|
58787
|
-
if (
|
|
58788
|
-
discoveries = JSON.parse(
|
|
59140
|
+
if (existsSync40(discPath)) {
|
|
59141
|
+
discoveries = JSON.parse(readFileSync28(discPath, "utf8"));
|
|
58789
59142
|
}
|
|
58790
59143
|
const reusable = discoveries.filter((d) => d.reusable !== false);
|
|
58791
59144
|
const lines = [
|
|
@@ -58813,30 +59166,6 @@ var init_composeContext = __esm({
|
|
|
58813
59166
|
}
|
|
58814
59167
|
});
|
|
58815
59168
|
|
|
58816
|
-
// src/cli/workspace/planDetect.ts
|
|
58817
|
-
var planDetect_exports = {};
|
|
58818
|
-
__export(planDetect_exports, {
|
|
58819
|
-
hasWorkspacePlan: () => hasWorkspacePlan
|
|
58820
|
-
});
|
|
58821
|
-
import { existsSync as existsSync40, readFileSync as readFileSync28 } from "node:fs";
|
|
58822
|
-
import { join as join30 } from "node:path";
|
|
58823
|
-
function hasWorkspacePlan(projectRoot = process.cwd()) {
|
|
58824
|
-
const planPath = join30(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
58825
|
-
if (!existsSync40(planPath)) return false;
|
|
58826
|
-
try {
|
|
58827
|
-
const parsed = JSON.parse(readFileSync28(planPath, "utf8"));
|
|
58828
|
-
return Array.isArray(parsed.phases) && parsed.phases.length > 0;
|
|
58829
|
-
} catch {
|
|
58830
|
-
return false;
|
|
58831
|
-
}
|
|
58832
|
-
}
|
|
58833
|
-
var init_planDetect = __esm({
|
|
58834
|
-
"src/cli/workspace/planDetect.ts"() {
|
|
58835
|
-
"use strict";
|
|
58836
|
-
init_paths3();
|
|
58837
|
-
}
|
|
58838
|
-
});
|
|
58839
|
-
|
|
58840
59169
|
// src/cli/state/loadDurableContext.ts
|
|
58841
59170
|
var loadDurableContext_exports = {};
|
|
58842
59171
|
__export(loadDurableContext_exports, {
|
|
@@ -60499,82 +60828,6 @@ var init_mcpManager = __esm({
|
|
|
60499
60828
|
}
|
|
60500
60829
|
});
|
|
60501
60830
|
|
|
60502
|
-
// src/cli/costBudget.ts
|
|
60503
|
-
var costBudget_exports = {};
|
|
60504
|
-
__export(costBudget_exports, {
|
|
60505
|
-
SessionBudgetTracker: () => SessionBudgetTracker,
|
|
60506
|
-
budgetChip: () => budgetChip,
|
|
60507
|
-
processSessionBudget: () => processSessionBudget,
|
|
60508
|
-
resetProcessSessionBudget: () => resetProcessSessionBudget,
|
|
60509
|
-
resolveSessionBudget: () => resolveSessionBudget
|
|
60510
|
-
});
|
|
60511
|
-
function resolveSessionBudget(env = process.env) {
|
|
60512
|
-
const maxUsd = parsePositiveFloat(env.ZELARI_SESSION_BUDGET_USD);
|
|
60513
|
-
const maxTokens = parsePositiveInt(env.ZELARI_SESSION_BUDGET_TOKENS);
|
|
60514
|
-
if (maxUsd === void 0 && maxTokens === void 0) return {};
|
|
60515
|
-
return { ...maxUsd !== void 0 ? { maxUsd } : {}, ...maxTokens !== void 0 ? { maxTokens } : {} };
|
|
60516
|
-
}
|
|
60517
|
-
function parsePositiveFloat(raw) {
|
|
60518
|
-
if (!raw) return void 0;
|
|
60519
|
-
const n = Number.parseFloat(raw);
|
|
60520
|
-
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
60521
|
-
}
|
|
60522
|
-
function parsePositiveInt(raw) {
|
|
60523
|
-
if (!raw) return void 0;
|
|
60524
|
-
const n = Number.parseInt(raw, 10);
|
|
60525
|
-
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
60526
|
-
}
|
|
60527
|
-
function round6(value) {
|
|
60528
|
-
return Math.round(value * 1e6) / 1e6;
|
|
60529
|
-
}
|
|
60530
|
-
function processSessionBudget(env = process.env) {
|
|
60531
|
-
if (!processTracker) processTracker = new SessionBudgetTracker(resolveSessionBudget(env));
|
|
60532
|
-
return processTracker;
|
|
60533
|
-
}
|
|
60534
|
-
function resetProcessSessionBudget() {
|
|
60535
|
-
processTracker = void 0;
|
|
60536
|
-
}
|
|
60537
|
-
function budgetChip(status) {
|
|
60538
|
-
if (status.state === "off") return null;
|
|
60539
|
-
const pct = Math.max(status.pctUsd ?? 0, status.pctTokens ?? 0);
|
|
60540
|
-
const label = status.state === "hold" ? "budget HOLD" : `budget ${Math.min(999, Math.round(pct * 100))}%`;
|
|
60541
|
-
const tone = status.state === "hold" ? "red" : status.state === "warn" ? "yellow" : "green";
|
|
60542
|
-
return { label, tone };
|
|
60543
|
-
}
|
|
60544
|
-
var SessionBudgetTracker, processTracker;
|
|
60545
|
-
var init_costBudget = __esm({
|
|
60546
|
-
"src/cli/costBudget.ts"() {
|
|
60547
|
-
"use strict";
|
|
60548
|
-
SessionBudgetTracker = class {
|
|
60549
|
-
constructor(budget = {}) {
|
|
60550
|
-
this.budget = budget;
|
|
60551
|
-
}
|
|
60552
|
-
usedUsd = 0;
|
|
60553
|
-
usedTokens = 0;
|
|
60554
|
-
get enabled() {
|
|
60555
|
-
return this.budget.maxUsd !== void 0 || this.budget.maxTokens !== void 0;
|
|
60556
|
-
}
|
|
60557
|
-
/** Idempotent per-turn accumulation; ignores NaN/negative inputs. */
|
|
60558
|
-
record(delta) {
|
|
60559
|
-
if (Number.isFinite(delta.costUsd) && (delta.costUsd ?? 0) > 0) this.usedUsd += delta.costUsd ?? 0;
|
|
60560
|
-
if (Number.isFinite(delta.tokens) && (delta.tokens ?? 0) > 0) this.usedTokens += Math.round(delta.tokens ?? 0);
|
|
60561
|
-
}
|
|
60562
|
-
status() {
|
|
60563
|
-
if (!this.enabled) return { state: "off", usedUsd: this.usedUsd, usedTokens: this.usedTokens, pctUsd: null, pctTokens: null };
|
|
60564
|
-
const pctUsd = this.budget.maxUsd !== void 0 ? this.usedUsd / this.budget.maxUsd : null;
|
|
60565
|
-
const pctTokens = this.budget.maxTokens !== void 0 ? this.usedTokens / this.budget.maxTokens : null;
|
|
60566
|
-
const worst = Math.max(pctUsd ?? 0, pctTokens ?? 0);
|
|
60567
|
-
const state3 = worst >= 1 ? "hold" : worst >= 0.8 ? "warn" : "ok";
|
|
60568
|
-
return { state: state3, usedUsd: round6(this.usedUsd), usedTokens: this.usedTokens, pctUsd, pctTokens };
|
|
60569
|
-
}
|
|
60570
|
-
/** True when no further provider turn should start. */
|
|
60571
|
-
isHold() {
|
|
60572
|
-
return this.status().state === "hold";
|
|
60573
|
-
}
|
|
60574
|
-
};
|
|
60575
|
-
}
|
|
60576
|
-
});
|
|
60577
|
-
|
|
60578
60831
|
// src/cli/councilConfig.ts
|
|
60579
60832
|
function resolveCouncilTier(opts) {
|
|
60580
60833
|
const env = opts?.env ?? process.env;
|
|
@@ -66631,6 +66884,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
|
|
|
66631
66884
|
emitExtLog(`[extensions] strict load failed: ${extLoad.error.message} \u2014 continuing WITHOUT extensions`);
|
|
66632
66885
|
}
|
|
66633
66886
|
}
|
|
66887
|
+
const { defaultPermissionPolicy: defaultPermissionPolicy2 } = await Promise.resolve().then(() => (init_toolPermissions(), toolPermissions_exports));
|
|
66634
66888
|
const { registry: toolRegistry } = createBuiltinToolRegistry({
|
|
66635
66889
|
root: cwd,
|
|
66636
66890
|
onTentacleEvent: (ev) => emitEvent(ev),
|
|
@@ -66658,14 +66912,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
|
|
|
66658
66912
|
...ev.type === "task_update" ? { task: ev.task } : { tasks: ev.tasks }
|
|
66659
66913
|
});
|
|
66660
66914
|
},
|
|
66661
|
-
permissionPolicy:
|
|
66662
|
-
read: "allow",
|
|
66663
|
-
write: "allow",
|
|
66664
|
-
execute: "allow",
|
|
66665
|
-
network: "allow",
|
|
66666
|
-
ui: "allow",
|
|
66667
|
-
auto: true
|
|
66668
|
-
},
|
|
66915
|
+
permissionPolicy: defaultPermissionPolicy2(),
|
|
66669
66916
|
...nativeMemory ? { memoryService: nativeMemory } : {},
|
|
66670
66917
|
memoryAutoWrite,
|
|
66671
66918
|
...extensionRuntime ? { extensions: extensionRuntime } : {},
|
|
@@ -68420,6 +68667,7 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
68420
68667
|
}
|
|
68421
68668
|
const audit = new AuditLogger2();
|
|
68422
68669
|
const { runTentacle: runTentacle2 } = await Promise.resolve().then(() => (init_tentacle(), tentacle_exports));
|
|
68670
|
+
const { defaultPermissionPolicy: defaultPermissionPolicy2 } = await Promise.resolve().then(() => (init_toolPermissions(), toolPermissions_exports));
|
|
68423
68671
|
const executor = new KrakenGraphExecutor2({
|
|
68424
68672
|
taskToolDeps: {
|
|
68425
68673
|
createSubAgentContext: createKrakenSubAgentContextFactory2({
|
|
@@ -68427,17 +68675,11 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
68427
68675
|
audit,
|
|
68428
68676
|
sessionId: sessionId2,
|
|
68429
68677
|
// P0.4 capability inheritance: tentacles intersect the headless
|
|
68430
|
-
// parent policy. Headless
|
|
68431
|
-
//
|
|
68432
|
-
//
|
|
68433
|
-
|
|
68434
|
-
|
|
68435
|
-
write: "allow",
|
|
68436
|
-
execute: "allow",
|
|
68437
|
-
network: "allow",
|
|
68438
|
-
ui: "allow",
|
|
68439
|
-
auto: true
|
|
68440
|
-
},
|
|
68678
|
+
// parent policy. Headless now uses the shared preset engine
|
|
68679
|
+
// (defaultPermissionPolicy — standard = execute/network ask, and
|
|
68680
|
+
// ask without a UI fails closed), so this intersection actually
|
|
68681
|
+
// bites: tentacles can never exceed the preset.
|
|
68682
|
+
parentPolicy: defaultPermissionPolicy2(),
|
|
68441
68683
|
// Anchor every tentacle to the SAME provider/model this run
|
|
68442
68684
|
// resolved (Desktop's selector, or --provider/--model), instead
|
|
68443
68685
|
// of the persisted provider.json default the factory falls back
|
|
@@ -68548,18 +68790,12 @@ function nodeSpineEnvelopeRun(spine, runOpts, run) {
|
|
|
68548
68790
|
}
|
|
68549
68791
|
async function buildCouncilToolRegistry(planMode, opts, memoryService, memoryAutoWrite = false, extras) {
|
|
68550
68792
|
const cwd = opts ? resolveHeadlessCwd(opts) : process.cwd();
|
|
68793
|
+
const { defaultPermissionPolicy: defaultPermissionPolicy2 } = await Promise.resolve().then(() => (init_toolPermissions(), toolPermissions_exports));
|
|
68551
68794
|
const { registry: toolRegistry } = createBuiltinToolRegistry({
|
|
68552
68795
|
root: cwd,
|
|
68553
68796
|
planMode,
|
|
68554
68797
|
...extras?.lspProvider ? { lspProvider: extras.lspProvider } : {},
|
|
68555
|
-
permissionPolicy:
|
|
68556
|
-
read: "allow",
|
|
68557
|
-
write: "allow",
|
|
68558
|
-
execute: "allow",
|
|
68559
|
-
network: "allow",
|
|
68560
|
-
ui: "allow",
|
|
68561
|
-
auto: true
|
|
68562
|
-
},
|
|
68798
|
+
permissionPolicy: defaultPermissionPolicy2(),
|
|
68563
68799
|
...memoryService ? { memoryService } : {},
|
|
68564
68800
|
memoryAutoWrite
|
|
68565
68801
|
});
|
|
@@ -69025,7 +69261,10 @@ ${ragContext}` : slicePrompt;
|
|
|
69025
69261
|
userMessage: opts.task,
|
|
69026
69262
|
synthesisText: synthesisText || void 0,
|
|
69027
69263
|
degradedRun: d.degraded,
|
|
69028
|
-
degradedReasons: d.reasons
|
|
69264
|
+
degradedReasons: d.reasons,
|
|
69265
|
+
// 2.31 A1: without sessionId the spine-evidence gate in the hook
|
|
69266
|
+
// never fires, leaving headless with the legacy lint heuristic.
|
|
69267
|
+
sessionId: spine.sessionId
|
|
69029
69268
|
});
|
|
69030
69269
|
completionOk = hook.completion?.completion?.ok ?? false;
|
|
69031
69270
|
if (completionOk) {
|
|
@@ -69074,17 +69313,11 @@ ${ragContext}` : slicePrompt;
|
|
|
69074
69313
|
const { composeProjectContext: composeProjectContext2 } = await Promise.resolve().then(() => (init_composeContext(), composeContext_exports));
|
|
69075
69314
|
const { loadDurableContext: loadDurableContext2 } = await Promise.resolve().then(() => (init_loadDurableContext(), loadDurableContext_exports));
|
|
69076
69315
|
const { detectDegradedRun: detectDegradedRun2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
69316
|
+
const { defaultPermissionPolicy: defaultPermissionPolicy2 } = await Promise.resolve().then(() => (init_toolPermissions(), toolPermissions_exports));
|
|
69077
69317
|
const { registry: agentRegistry } = createBuiltinToolRegistry2({
|
|
69078
69318
|
root: projectRoot,
|
|
69079
69319
|
planMode: false,
|
|
69080
|
-
permissionPolicy:
|
|
69081
|
-
read: "allow",
|
|
69082
|
-
write: "allow",
|
|
69083
|
-
execute: "allow",
|
|
69084
|
-
network: "allow",
|
|
69085
|
-
ui: "allow",
|
|
69086
|
-
auto: true
|
|
69087
|
-
}
|
|
69320
|
+
permissionPolicy: defaultPermissionPolicy2()
|
|
69088
69321
|
});
|
|
69089
69322
|
await registerHeadlessMcp(agentRegistry, opts);
|
|
69090
69323
|
const durableState = await loadDurableContext2(projectRoot);
|
|
@@ -69131,7 +69364,9 @@ ${ragContext}` : slicePrompt;
|
|
|
69131
69364
|
userMessage: opts.task,
|
|
69132
69365
|
synthesisText: synthesisText || void 0,
|
|
69133
69366
|
degradedRun: d.degraded,
|
|
69134
|
-
degradedReasons: d.reasons
|
|
69367
|
+
degradedReasons: d.reasons,
|
|
69368
|
+
// 2.31 A1: same fix as the council path — evidence gate needs it.
|
|
69369
|
+
sessionId: spine.sessionId
|
|
69135
69370
|
});
|
|
69136
69371
|
if (hook.completion?.completion?.ok) {
|
|
69137
69372
|
emit(`[zelari] slice completion ok`);
|
|
@@ -72138,6 +72373,7 @@ var init_contextGrowthSummary = __esm({
|
|
|
72138
72373
|
// src/cli/utils/doctor.ts
|
|
72139
72374
|
var doctor_exports = {};
|
|
72140
72375
|
__export(doctor_exports, {
|
|
72376
|
+
collectDoctorReport: () => collectDoctorReport,
|
|
72141
72377
|
runDoctor: () => runDoctor
|
|
72142
72378
|
});
|
|
72143
72379
|
import { execSync as execSync2 } from "node:child_process";
|
|
@@ -72403,10 +72639,8 @@ async function checkContextGrowth() {
|
|
|
72403
72639
|
return WARN(`metrics unreadable: ${err instanceof Error ? err.message : String(err)}`);
|
|
72404
72640
|
}
|
|
72405
72641
|
}
|
|
72406
|
-
|
|
72407
|
-
|
|
72408
|
-
const pkgName = pkg?.name ?? "zelari-code";
|
|
72409
|
-
const checks = [
|
|
72642
|
+
function buildDoctorChecks(pkg, pkgName) {
|
|
72643
|
+
return [
|
|
72410
72644
|
// --- install-health checks (main-process probes) ---
|
|
72411
72645
|
{ name: "node", run: () => checkNode(pkg) },
|
|
72412
72646
|
{ name: "bin shim", run: () => checkShim(pkgName) },
|
|
@@ -72485,6 +72719,34 @@ async function runDoctor() {
|
|
|
72485
72719
|
// --- optional desktop computer-use (Cua Driver, trycua) ---
|
|
72486
72720
|
{ name: "cua-driver", run: () => checkCuaDriver() }
|
|
72487
72721
|
];
|
|
72722
|
+
}
|
|
72723
|
+
async function collectDoctorReport() {
|
|
72724
|
+
const pkg = readPackageJson4();
|
|
72725
|
+
const checks = buildDoctorChecks(pkg, pkg?.name ?? "zelari-code");
|
|
72726
|
+
const entries = [];
|
|
72727
|
+
for (const c of checks) {
|
|
72728
|
+
let result;
|
|
72729
|
+
try {
|
|
72730
|
+
result = await c.run();
|
|
72731
|
+
} catch (err) {
|
|
72732
|
+
result = FAIL(
|
|
72733
|
+
`unexpected error: ${err instanceof Error ? err.message : String(err)}`
|
|
72734
|
+
);
|
|
72735
|
+
}
|
|
72736
|
+
entries.push({
|
|
72737
|
+
name: c.name,
|
|
72738
|
+
ok: result.ok,
|
|
72739
|
+
severity: result.ok ? "none" : result.severity ?? "warn",
|
|
72740
|
+
message: result.message
|
|
72741
|
+
});
|
|
72742
|
+
}
|
|
72743
|
+
const firstRed = entries.find((e) => !e.ok) ?? null;
|
|
72744
|
+
return { entries, firstRed, healthy: entries.every((e) => e.ok) };
|
|
72745
|
+
}
|
|
72746
|
+
async function runDoctor() {
|
|
72747
|
+
const pkg = readPackageJson4();
|
|
72748
|
+
const pkgName = pkg?.name ?? "zelari-code";
|
|
72749
|
+
const checks = buildDoctorChecks(pkg, pkgName);
|
|
72488
72750
|
console.log(`zelari-code doctor (v${pkg?.version ?? "unknown"})`);
|
|
72489
72751
|
console.log("platform:", process.platform, process.arch);
|
|
72490
72752
|
console.log("node: ", process.version);
|
|
@@ -73342,12 +73604,13 @@ function StatusBar({
|
|
|
73342
73604
|
krakenLive = null,
|
|
73343
73605
|
krakenGraph = null,
|
|
73344
73606
|
verify = null,
|
|
73345
|
-
permissions = null
|
|
73607
|
+
permissions = null,
|
|
73608
|
+
jail = null
|
|
73346
73609
|
}) {
|
|
73347
73610
|
const ctxLabel = contextLimit > 0 ? `${formatTokens(contextUsed)}/${formatTokens(contextLimit)}` : contextUsed > 0 ? formatTokens(contextUsed) : null;
|
|
73348
73611
|
const modeLabel = mode === "council" ? "council" : mode === "zelari" ? "zelari" : "kraken";
|
|
73349
73612
|
const modeColor = mode === "council" ? "magenta" : mode === "zelari" ? "green" : "red";
|
|
73350
|
-
return /* @__PURE__ */ React6.createElement(Box5, { paddingX: 1, width: "100%", justifyContent: "space-between", gap: 2 }, /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 2 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, /* @__PURE__ */ React6.createElement(Text6, { color: sessionActive ? "green" : "gray" }, sessionActive ? "\u25CF" : "\u25CB"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: phase2 === "plan" ? "yellow" : "green" }, phase2 === "plan" ? "\u25C7 plan" : "\u25C6 build"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: modeColor }, modeLabel), verify ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: verify.tone }, verify.label)) : null, permissions ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: permissions.tone }, permissions.label)) : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, provider), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, null, model), cwd ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, cwd)) : null)), /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 1 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, busy && elapsedMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Spinner, { color: "yellow" }), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, " ", formatDuration(elapsedMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : lastMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "last ", formatDuration(lastMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, queueCount > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, "queue ", queueCount), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, todoSummary ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, todoSummary), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, krakenLive ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, krakenLive), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, krakenGraph ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, krakenGraph), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, ctxLabel ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan" }, ctxLabel), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, costUsd > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, formatCost(costUsd)), cachedTokens > 0 ? /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (", formatTokens(cachedTokens), " cached)") : null, cacheHitRate > 0 ? /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " ", Math.round(cacheHitRate * 100), "% hit") : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "session ", sessionId2))));
|
|
73613
|
+
return /* @__PURE__ */ React6.createElement(Box5, { paddingX: 1, width: "100%", justifyContent: "space-between", gap: 2 }, /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 2 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, /* @__PURE__ */ React6.createElement(Text6, { color: sessionActive ? "green" : "gray" }, sessionActive ? "\u25CF" : "\u25CB"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: phase2 === "plan" ? "yellow" : "green" }, phase2 === "plan" ? "\u25C7 plan" : "\u25C6 build"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: modeColor }, modeLabel), verify ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: verify.tone }, verify.label)) : null, permissions ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: permissions.tone }, permissions.label)) : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), jail ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: jail.tone }, jail.label)) : null, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, provider), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, null, model), cwd ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, cwd)) : null)), /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 1 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, busy && elapsedMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Spinner, { color: "yellow" }), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, " ", formatDuration(elapsedMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : lastMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "last ", formatDuration(lastMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, queueCount > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, "queue ", queueCount), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, todoSummary ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, todoSummary), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, krakenLive ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, krakenLive), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, krakenGraph ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, krakenGraph), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, ctxLabel ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan" }, ctxLabel), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, costUsd > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, formatCost(costUsd)), cachedTokens > 0 ? /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (", formatTokens(cachedTokens), " cached)") : null, cacheHitRate > 0 ? /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " ", Math.round(cacheHitRate * 100), "% hit") : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "session ", sessionId2))));
|
|
73351
73614
|
}
|
|
73352
73615
|
|
|
73353
73616
|
// src/cli/components/SelectList.tsx
|
|
@@ -73616,71 +73879,8 @@ function useExecutionTimer(busy, tickMs = 1e3) {
|
|
|
73616
73879
|
init_paths2();
|
|
73617
73880
|
init_sessionTodos();
|
|
73618
73881
|
init_krakenLive();
|
|
73619
|
-
|
|
73620
|
-
|
|
73621
|
-
init_verificationBridge();
|
|
73622
|
-
function verifyStateFromGate(evaluation) {
|
|
73623
|
-
if (!evaluation.blocked) return "pass";
|
|
73624
|
-
const verdict = evaluation.evaluation?.verdict;
|
|
73625
|
-
if (verdict === "BLOCKED") return "blocked";
|
|
73626
|
-
return "repair";
|
|
73627
|
-
}
|
|
73628
|
-
function formatVerifyChip(state3) {
|
|
73629
|
-
if (state3 === "pass") return { label: "prova: PASS", tone: "green" };
|
|
73630
|
-
if (state3 === "blocked") return { label: "prova: BLOCCATO", tone: "red" };
|
|
73631
|
-
return { label: "prova: RIPARA", tone: "yellow" };
|
|
73632
|
-
}
|
|
73633
|
-
function permissionsChip(phase2, strictOn = strictDoneEnabled()) {
|
|
73634
|
-
if (phase2 === "plan") return { label: "scrive: no (piano)", tone: "yellow" };
|
|
73635
|
-
return strictOn ? { label: "scrive: s\xEC \xB7 prova obbligatoria", tone: "green" } : { label: "scrive: s\xEC \xB7 senza prova (dichiarato)", tone: "yellow" };
|
|
73636
|
-
}
|
|
73637
|
-
function formatStrictBlockExplanation(evaluation) {
|
|
73638
|
-
const state3 = verifyStateFromGate(evaluation);
|
|
73639
|
-
const gate = evaluation.gate;
|
|
73640
|
-
if (state3 === "pass") {
|
|
73641
|
-
return `[verifica] PASS \u2014 ${gate.passed}/${gate.total} prove superate.`;
|
|
73642
|
-
}
|
|
73643
|
-
const word = state3 === "blocked" ? "BLOCCATO" : "RIPARA";
|
|
73644
|
-
const lines = [
|
|
73645
|
-
`[verifica] ${word} \u2014 ${gate.passed}/${gate.total} prove superate; il turno non pu\xF2 dichiararsi finito senza prova.`
|
|
73646
|
-
];
|
|
73647
|
-
const evalr = evaluation.evaluation ?? null;
|
|
73648
|
-
if (evalr) {
|
|
73649
|
-
const byId = /* @__PURE__ */ new Map();
|
|
73650
|
-
for (const c of evalr.criteria ?? []) byId.set(c.id, c.text);
|
|
73651
|
-
const unsatisfied = (evalr.results ?? []).filter((r) => r.status !== "pass");
|
|
73652
|
-
if (unsatisfied.length > 0) {
|
|
73653
|
-
lines.push("Mancano:");
|
|
73654
|
-
for (const r of unsatisfied.slice(0, 8)) {
|
|
73655
|
-
lines.push(` \u2022 ${byId.get(r.criterionId) ?? r.criterionId} [${r.status}]`);
|
|
73656
|
-
}
|
|
73657
|
-
if (unsatisfied.length > 8) {
|
|
73658
|
-
lines.push(` \u2022 \u2026 e altri ${unsatisfied.length - 8}`);
|
|
73659
|
-
}
|
|
73660
|
-
}
|
|
73661
|
-
}
|
|
73662
|
-
lines.push(
|
|
73663
|
-
"La prova \xE8 obbligatoria: chiudo il turno solo quando ogni criterio richiesto ha evidenza."
|
|
73664
|
-
);
|
|
73665
|
-
return lines.join("\n");
|
|
73666
|
-
}
|
|
73667
|
-
function recordStrictGateEvaluation(evaluation) {
|
|
73668
|
-
const g = globalThis;
|
|
73669
|
-
g.__zelariVerifyState = {
|
|
73670
|
-
state: verifyStateFromGate(evaluation),
|
|
73671
|
-
at: Date.now(),
|
|
73672
|
-
passed: evaluation.gate.passed,
|
|
73673
|
-
total: evaluation.gate.total
|
|
73674
|
-
};
|
|
73675
|
-
}
|
|
73676
|
-
function getVerifyChip() {
|
|
73677
|
-
const g = globalThis;
|
|
73678
|
-
const s = g.__zelariVerifyState;
|
|
73679
|
-
if (!s) return null;
|
|
73680
|
-
return formatVerifyChip(s.state);
|
|
73681
|
-
}
|
|
73682
|
-
|
|
73683
|
-
// src/cli/app.tsx
|
|
73882
|
+
init_verifyStatus();
|
|
73883
|
+
init_osJail();
|
|
73684
73884
|
init_graphStatus();
|
|
73685
73885
|
|
|
73686
73886
|
// packages/core/dist/agents/skills/builtin/debugging.js
|
|
@@ -76261,6 +76461,7 @@ init_delegationPolicy();
|
|
|
76261
76461
|
init_completionGate();
|
|
76262
76462
|
init_verificationBridge();
|
|
76263
76463
|
init_completionProof();
|
|
76464
|
+
init_verifyStatus();
|
|
76264
76465
|
init_nativeVerification();
|
|
76265
76466
|
init_spineTelemetry();
|
|
76266
76467
|
|
|
@@ -76468,6 +76669,28 @@ function useChatTurn(params) {
|
|
|
76468
76669
|
return;
|
|
76469
76670
|
}
|
|
76470
76671
|
}
|
|
76672
|
+
{
|
|
76673
|
+
const { sessionBudgetHoldNotice: sessionBudgetHoldNotice2 } = await Promise.resolve().then(() => (init_costBudget(), costBudget_exports));
|
|
76674
|
+
const hold = sessionBudgetHoldNotice2();
|
|
76675
|
+
if (hold) {
|
|
76676
|
+
appendSystem(setMessages, hold, Date.now());
|
|
76677
|
+
return;
|
|
76678
|
+
}
|
|
76679
|
+
}
|
|
76680
|
+
{
|
|
76681
|
+
const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
|
|
76682
|
+
const phaseMod = await Promise.resolve().then(() => (init_phaseState(), phaseState_exports));
|
|
76683
|
+
const g = globalThis;
|
|
76684
|
+
if (phaseMod.getPhase() === "build" && !hasWorkspacePlan2(process.cwd()) && !g.__zelariPlanFirstNotice) {
|
|
76685
|
+
g.__zelariPlanFirstNotice = true;
|
|
76686
|
+
phaseMod.setPhase("plan");
|
|
76687
|
+
appendSystem(
|
|
76688
|
+
setMessages,
|
|
76689
|
+
`[permessi] No workspace plan found \u2014 first turn forced to PLAN (no surprise writes). Type /build to switch to BUILD explicitly.`,
|
|
76690
|
+
Date.now()
|
|
76691
|
+
);
|
|
76692
|
+
}
|
|
76693
|
+
}
|
|
76471
76694
|
setBusy(true);
|
|
76472
76695
|
const workPhase = getPhase();
|
|
76473
76696
|
try {
|
|
@@ -78516,6 +78739,7 @@ function handleSlashCommand(text, availableSkills) {
|
|
|
78516
78739
|
/state restore [id] [--no-tree] \u2014 set HEAD + optional git checkpoint restore
|
|
78517
78740
|
/cache stats \u2014 prompt-cache hit rate, premium vs cached, stable busts
|
|
78518
78741
|
/index [status] \u2014 build the semantic code index for semantic_search
|
|
78742
|
+
/verify \u2014 re-evaluate the strict completion gate (deterministic, no LLM; criteria + next command)
|
|
78519
78743
|
/mode [kraken|council|zelari] \u2014 switch dispatch mode (same as shift+tab; agent=alias kraken)
|
|
78520
78744
|
/kraken [sessionId] \u2014 show Kraken tentacle radio (last spawns)
|
|
78521
78745
|
/trust [path] \u2014 trust a folder so project MCP + project hooks load
|
|
@@ -79017,6 +79241,9 @@ ${formatSkillList(availableSkills)}`
|
|
|
79017
79241
|
case "view-plan": {
|
|
79018
79242
|
return { handled: true, kind: "view_plan" };
|
|
79019
79243
|
}
|
|
79244
|
+
case "verify": {
|
|
79245
|
+
return { handled: true, kind: "verify" };
|
|
79246
|
+
}
|
|
79020
79247
|
case "index": {
|
|
79021
79248
|
return args[0] === "status" ? { handled: true, kind: "index_status" } : { handled: true, kind: "index_build" };
|
|
79022
79249
|
}
|
|
@@ -81752,6 +81979,21 @@ function useSlashDispatch(params) {
|
|
|
81752
81979
|
setInput("");
|
|
81753
81980
|
return;
|
|
81754
81981
|
}
|
|
81982
|
+
if (result.kind === "verify") {
|
|
81983
|
+
try {
|
|
81984
|
+
const { evaluateStrictBuildGate: evaluateStrictBuildGate2 } = await Promise.resolve().then(() => (init_verificationBridge(), verificationBridge_exports));
|
|
81985
|
+
const { formatStrictBlockExplanation: formatStrictBlockExplanation2 } = await Promise.resolve().then(() => (init_verifyStatus(), verifyStatus_exports));
|
|
81986
|
+
const evaluation = await evaluateStrictBuildGate2("build");
|
|
81987
|
+
appendSystem(setMessages, `[verify] ${formatStrictBlockExplanation2(evaluation)}`);
|
|
81988
|
+
} catch (err) {
|
|
81989
|
+
appendSystem(
|
|
81990
|
+
setMessages,
|
|
81991
|
+
`[verify] gate unavailable: ${err instanceof Error ? err.message : String(err)}`
|
|
81992
|
+
);
|
|
81993
|
+
}
|
|
81994
|
+
setInput("");
|
|
81995
|
+
return;
|
|
81996
|
+
}
|
|
81755
81997
|
if (result.kind === "promote_member" && result.promoteMemberId) {
|
|
81756
81998
|
await handlePromoteMember(baseCtx, result.promoteMemberId);
|
|
81757
81999
|
setInput("");
|
|
@@ -81940,6 +82182,15 @@ function useTerminalSize(options = {}) {
|
|
|
81940
82182
|
// src/cli/app.tsx
|
|
81941
82183
|
init_chatStats();
|
|
81942
82184
|
init_duration();
|
|
82185
|
+
function jailStatusChip() {
|
|
82186
|
+
const mode = activeJailMode();
|
|
82187
|
+
if (mode === "off") return null;
|
|
82188
|
+
const probe = probeJailBackend();
|
|
82189
|
+
if (!probe.available) {
|
|
82190
|
+
return { label: `jail: advisory (${probe.backend})`, tone: "yellow" };
|
|
82191
|
+
}
|
|
82192
|
+
return mode === "required" ? { label: `jail: on (${probe.backend})`, tone: "green" } : { label: `jail: advisory (${probe.backend})`, tone: "yellow" };
|
|
82193
|
+
}
|
|
81943
82194
|
var MODEL = process.env.OPENAI_MODEL ?? "grok-4.5";
|
|
81944
82195
|
var providerDefaults = {
|
|
81945
82196
|
"openai-compatible": "grok-4.5",
|
|
@@ -82155,7 +82406,8 @@ function App() {
|
|
|
82155
82406
|
krakenLive: formatKrakenLiveSummary() ?? void 0,
|
|
82156
82407
|
krakenGraph: formatKrakenGraphSummary() ?? void 0,
|
|
82157
82408
|
verify: getVerifyChip() ?? void 0,
|
|
82158
|
-
permissions: permissionsChip(phase2)
|
|
82409
|
+
permissions: permissionsChip(phase2),
|
|
82410
|
+
jail: jailStatusChip()
|
|
82159
82411
|
}
|
|
82160
82412
|
)), sidebarOpen && /* @__PURE__ */ React10.createElement(Sidebar, { version: VERSION, changes: gitChanges, rows: size.rows })));
|
|
82161
82413
|
}
|
|
@@ -83234,6 +83486,14 @@ function pickRootComponent() {
|
|
|
83234
83486
|
return { kind: "done" };
|
|
83235
83487
|
}
|
|
83236
83488
|
if (argv.includes("--doctor") || argv.includes("doctor")) {
|
|
83489
|
+
if (argv.includes("--json")) {
|
|
83490
|
+
const { collectDoctorReport: collectDoctorReport2 } = (init_doctor(), __toCommonJS(doctor_exports));
|
|
83491
|
+
void collectDoctorReport2().then((report) => {
|
|
83492
|
+
console.log(JSON.stringify(report));
|
|
83493
|
+
process.exit(report.healthy ? 0 : 1);
|
|
83494
|
+
});
|
|
83495
|
+
return { kind: "done" };
|
|
83496
|
+
}
|
|
83237
83497
|
const { runDoctor: runDoctor2 } = (init_doctor(), __toCommonJS(doctor_exports));
|
|
83238
83498
|
void runDoctor2().then((healthy) => process.exit(healthy ? 0 : 1));
|
|
83239
83499
|
return { kind: "done" };
|
|
@@ -83353,7 +83613,7 @@ proposals: npm run evolve:propose \u2014 decisions in npm run evolve:decide (P1:
|
|
|
83353
83613
|
}
|
|
83354
83614
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
83355
83615
|
console.log(
|
|
83356
|
-
"zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor
|
|
83616
|
+
"zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor [--json] Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --inspect [--json] Unified project inspection (config, skills, MCP,\n hooks, plugins, AGENTS.md, trust status)\n --trust [path] Trust the cwd (or path) so project MCP + hooks load\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --fix-budget Set recommended ZELARI_MAX_TOOL_LOOP_HARD=180,\n ZELARI_MAX_TOOL_LOOP_ITERATIONS=60, ZELARI_CONTEXT_LIMIT=400000\n at User scope (prevents the agent stopping mid-task)\n --permission-mcp <socket> MCP stdio server for external agent permission prompts\n (spawned by claude --permission-prompt-tool)\n --memory-mcp Optional MCP stdio server for project memory\n --cwd <path> Trusted project root (requires ZELARI_MEMORY_MCP=1)\n --client-id <id> Stable local owner identity for private memories\n --memory-json <json> Read-only project-memory bridge for Zelari Desktop\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --mode kraken|council|zelari Dispatch mode (default: kraken; agent=alias)\n --council Alias for --mode council\n --phase plan|build Work phase (default: build)\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n --profile <id> Capability profile (minimal/v1|kraken/v1|council/v1|mission/v1)\n --resume <id> Continue a 2.0 spine session\n --export-session <path> Write zelari-session-export/1 after the run\n --strict-done Evidence-based BUILD completion gate\n --task-file <path> Read the task prompt from a file (Windows argv cap)\n --once Single-cycle run (cron/git-hook triggers, ADR-0014)\n --kraken-graph <goal> Plan + execute a Kraken task graph\n (variant: --kraken-graph-file <path>; kill-switch\n ZELARI_KRAKEN_GRAPH=0)\n --plan-only Serialize the graph plan to .zelari/radio/ and exit 0\n --run-plan <id> Execute a pre-built .zelari/radio/plan-<id>.json\n --gauntlet Host-driven gauntlet loop (builder/critic tentacles)\n --session-export <id> Print a portable 2.0 session export (no LLM)\n serve Companion host for Android/remote clients (Tailscale)\n --bind <ip> Listen address (default: 127.0.0.1; use Tailscale IP)\n --port <n> Port (default: 7421)\n --token <secret> Bearer token (default: ~/.zelari-code/companion.token)\n --project <path> Allowlisted project root (repeatable)\n --save-projects Persist --project list to companion.json\n --serve-harness Long-lived harness kernel for hosts (NDJSON JSON-RPC\n on stdin/stdout; Desktop/companion transport)\n --print-config Print provider/model config as JSON (no secrets)\n --print-settings Print zelari.config.json values + the origin of\n each (default < user < project < env)\n --permissions <p> Permission preset: strict | standard | yolo \u2014 changes\n category DEFAULTS only (env vars and policy files win)\n --evolve-status Evolution ledger stats (read-only; ADR-0036; the\n ledger is written only when ZELARI_EVOLUTION=shadow)\n --plugins-status JSON status of optional plugins (Playwright, eslint, \u2026)\n --plugins-install <id> Install plugin (playwright also fetches Chromium)\n --cwd <path> Workspace for -D installs (default: process.cwd())\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --thinking <spec> Thinking effort (auto|off|low|medium|high|budget:N)\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --login-oauth Start subscription OAuth (grok, chatgpt, anthropic)\n --provider <id> grok | chatgpt | anthropic\n --code <paste> Anthropic magic-link code (CODE#STATE)\n --no-browser Do not open the system browser\n --refresh-oauth Force-refresh an OAuth access token\n --provider <id> grok | chatgpt | anthropic\n --logout-oauth Clear stored OAuth credentials\n --provider <id> grok | chatgpt | anthropic\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n --print-mcp Print MCP server config (user + project)\n --cwd <path> Project root for .zelari/mcp.json\n --set-mcp Add/update an MCP server entry\n --name <id> Server name (required)\n --command <bin> Executable for stdio servers\n --url <endpoint> Streamable HTTP endpoint (e.g. UE 5.8 editor)\n --args <json> JSON array of args (stdio, optional)\n --timeout <ms> Per-server request timeout (http, optional)\n --scope user|project Default: user\n --enabled true|false Default: true\n --cwd <path> Required when scope=project\n --set-mcp-preset Install a named MCP preset (e.g. cua)\n --preset cua Cua Driver desktop computer-use (MCP)\n --preset unreal-mcp Unreal Engine 5.8+ editor (MCP over HTTP)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-mcp Remove an MCP server entry\n --name <id> --scope user|project [--cwd <path>]\n --print-skills Print skills (builtin + user + project)\n --cwd <path> Project root for .zelari/skills\n --set-skill Add/update a SKILL.md skill\n --name <id> Skill id (required)\n --description <t> One-line description (required)\n --body <text> Markdown instructions (required)\n --category <c> plan|refactor|debug|review|test|docs|ops|git|db|maint\n --tools <csv> Comma-separated required tools (optional)\n --cost <l> low|medium|high (default: medium)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-skill Remove a user/project SKILL.md\n --name <id> --scope user|project [--cwd <path>]\n --generate-skill-from-url Fetch URL + draft skill via model (JSON)\n --url <https://...> Required\n --provider <id> Override active provider\n --model <name> Override model for the selected provider\n --print-ssh-targets Print SSH deploy/monitor targets\n --set-ssh-target Upsert target (--json '{...}' or flags)\n --remove-ssh-target --id <id>\n --test-ssh-target --id <id> (BatchMode ssh true)\n --print-ssh-pubkey --path <private-or-.pub> (display public key)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ZELARI_MEMORY_MCP=1 Enable the optional external memory MCP server\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
|
|
83357
83617
|
);
|
|
83358
83618
|
process.exit(0);
|
|
83359
83619
|
}
|
|
@@ -83913,19 +84173,57 @@ function main() {
|
|
|
83913
84173
|
});
|
|
83914
84174
|
return;
|
|
83915
84175
|
}
|
|
83916
|
-
|
|
83917
|
-
|
|
83918
|
-
unmount();
|
|
83919
|
-
|
|
83920
|
-
|
|
83921
|
-
|
|
83922
|
-
|
|
83923
|
-
|
|
83924
|
-
|
|
83925
|
-
|
|
83926
|
-
|
|
83927
|
-
void
|
|
84176
|
+
void (async () => {
|
|
84177
|
+
await runFirstRunDoctorGate();
|
|
84178
|
+
const { waitUntilExit, unmount } = render(picked.element);
|
|
84179
|
+
process.on("SIGINT", () => {
|
|
84180
|
+
unmount();
|
|
84181
|
+
void shutdown();
|
|
84182
|
+
});
|
|
84183
|
+
process.on("SIGTERM", () => {
|
|
84184
|
+
unmount();
|
|
84185
|
+
void shutdown();
|
|
84186
|
+
});
|
|
84187
|
+
void backgroundUpdateCheck();
|
|
84188
|
+
waitUntilExit().then(() => {
|
|
84189
|
+
void shutdown();
|
|
84190
|
+
});
|
|
84191
|
+
})();
|
|
84192
|
+
}
|
|
84193
|
+
async function runFirstRunDoctorGate() {
|
|
84194
|
+
try {
|
|
84195
|
+
const { getActiveProvider: getActiveProvider2 } = await Promise.resolve().then(() => (init_providerConfig(), providerConfig_exports));
|
|
84196
|
+
const { resolveApiKey: resolveApiKey2, getOAuthToken: getOAuthToken2 } = await Promise.resolve().then(() => (init_keyStore(), keyStore_exports));
|
|
84197
|
+
const active = getActiveProvider2();
|
|
84198
|
+
if (resolveApiKey2(active.id) || getOAuthToken2(active.id)) return;
|
|
84199
|
+
} catch {
|
|
84200
|
+
return;
|
|
84201
|
+
}
|
|
84202
|
+
const { collectDoctorReport: collectDoctorReport2 } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
|
|
84203
|
+
const report = await collectDoctorReport2();
|
|
84204
|
+
if (report.healthy) return;
|
|
84205
|
+
const red = report.firstRed;
|
|
84206
|
+
const line = (s) => process.stderr.write(s + "\n");
|
|
84207
|
+
line("");
|
|
84208
|
+
line("\u250C\u2500 first run: doctor");
|
|
84209
|
+
line(`\u2502 \u2717 ${red.name} \u2014 ${red.message.replace(/\n/g, "\n\u2502 ")}`);
|
|
84210
|
+
line("\u2502 Fix the red above (its message names the exact command), then re-run:");
|
|
84211
|
+
line("\u2502 zelari-code --doctor");
|
|
84212
|
+
line("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
84213
|
+
if (!process.stdin.isTTY) {
|
|
84214
|
+
line("[wizard] non-interactive session: continuing with a RED doctor (dichiarato).");
|
|
84215
|
+
return;
|
|
84216
|
+
}
|
|
84217
|
+
const rl = (await import("node:readline/promises")).createInterface({
|
|
84218
|
+
input: process.stdin,
|
|
84219
|
+
output: process.stdout
|
|
83928
84220
|
});
|
|
84221
|
+
const answer = (await rl.question('Continue anyway with a RED doctor? Type "si" to continue: ')).trim().toLowerCase();
|
|
84222
|
+
rl.close();
|
|
84223
|
+
if (answer !== "si" && answer !== "s\xEC" && answer !== "yes" && answer !== "y") {
|
|
84224
|
+
process.exit(1);
|
|
84225
|
+
}
|
|
84226
|
+
line("[wizard] continue-anyway dichiarato \u2014 doctor is still red.");
|
|
83929
84227
|
}
|
|
83930
84228
|
main();
|
|
83931
84229
|
export {
|