zelari-code 2.31.0 → 2.33.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 +4 -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/headless/runOneTurn.js +13 -11
- package/dist/cli/headless/runOneTurn.js.map +1 -1
- package/dist/cli/headless.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/useSlashDispatch.js +16 -0
- package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
- package/dist/cli/main.bundled.js +962 -668
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +15 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/runHeadless.js +13 -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/serve/harnessServer.js +34 -2
- package/dist/cli/serve/harnessServer.js.map +1 -1
- package/dist/cli/serve/permissionBridge.js +118 -0
- package/dist/cli/serve/permissionBridge.js.map +1 -0
- 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/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.33.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();
|
|
@@ -66638,6 +66884,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
|
|
|
66638
66884
|
emitExtLog(`[extensions] strict load failed: ${extLoad.error.message} \u2014 continuing WITHOUT extensions`);
|
|
66639
66885
|
}
|
|
66640
66886
|
}
|
|
66887
|
+
const { defaultPermissionPolicy: defaultPermissionPolicy2 } = await Promise.resolve().then(() => (init_toolPermissions(), toolPermissions_exports));
|
|
66641
66888
|
const { registry: toolRegistry } = createBuiltinToolRegistry({
|
|
66642
66889
|
root: cwd,
|
|
66643
66890
|
onTentacleEvent: (ev) => emitEvent(ev),
|
|
@@ -66665,14 +66912,11 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
|
|
|
66665
66912
|
...ev.type === "task_update" ? { task: ev.task } : { tasks: ev.tasks }
|
|
66666
66913
|
});
|
|
66667
66914
|
},
|
|
66668
|
-
|
|
66669
|
-
|
|
66670
|
-
|
|
66671
|
-
|
|
66672
|
-
|
|
66673
|
-
ui: "allow",
|
|
66674
|
-
auto: true
|
|
66675
|
-
},
|
|
66915
|
+
// Serve/Desktop ask-bridge: an injected handler turns "ask" rules into
|
|
66916
|
+
// an interactive approval (permission.request over NDJSON) instead of
|
|
66917
|
+
// the fail-closed typedErr. Absent handler ⇒ unchanged fail-closed.
|
|
66918
|
+
...opts.onPermissionAsk ? { onPermissionAsk: opts.onPermissionAsk } : {},
|
|
66919
|
+
permissionPolicy: defaultPermissionPolicy2(),
|
|
66676
66920
|
...nativeMemory ? { memoryService: nativeMemory } : {},
|
|
66677
66921
|
memoryAutoWrite,
|
|
66678
66922
|
...extensionRuntime ? { extensions: extensionRuntime } : {},
|
|
@@ -68427,6 +68671,7 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
68427
68671
|
}
|
|
68428
68672
|
const audit = new AuditLogger2();
|
|
68429
68673
|
const { runTentacle: runTentacle2 } = await Promise.resolve().then(() => (init_tentacle(), tentacle_exports));
|
|
68674
|
+
const { defaultPermissionPolicy: defaultPermissionPolicy2 } = await Promise.resolve().then(() => (init_toolPermissions(), toolPermissions_exports));
|
|
68430
68675
|
const executor = new KrakenGraphExecutor2({
|
|
68431
68676
|
taskToolDeps: {
|
|
68432
68677
|
createSubAgentContext: createKrakenSubAgentContextFactory2({
|
|
@@ -68434,17 +68679,11 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
68434
68679
|
audit,
|
|
68435
68680
|
sessionId: sessionId2,
|
|
68436
68681
|
// P0.4 capability inheritance: tentacles intersect the headless
|
|
68437
|
-
// parent policy. Headless
|
|
68438
|
-
//
|
|
68439
|
-
//
|
|
68440
|
-
|
|
68441
|
-
|
|
68442
|
-
write: "allow",
|
|
68443
|
-
execute: "allow",
|
|
68444
|
-
network: "allow",
|
|
68445
|
-
ui: "allow",
|
|
68446
|
-
auto: true
|
|
68447
|
-
},
|
|
68682
|
+
// parent policy. Headless now uses the shared preset engine
|
|
68683
|
+
// (defaultPermissionPolicy — standard = execute/network ask, and
|
|
68684
|
+
// ask without a UI fails closed), so this intersection actually
|
|
68685
|
+
// bites: tentacles can never exceed the preset.
|
|
68686
|
+
parentPolicy: defaultPermissionPolicy2(),
|
|
68448
68687
|
// Anchor every tentacle to the SAME provider/model this run
|
|
68449
68688
|
// resolved (Desktop's selector, or --provider/--model), instead
|
|
68450
68689
|
// of the persisted provider.json default the factory falls back
|
|
@@ -68555,18 +68794,12 @@ function nodeSpineEnvelopeRun(spine, runOpts, run) {
|
|
|
68555
68794
|
}
|
|
68556
68795
|
async function buildCouncilToolRegistry(planMode, opts, memoryService, memoryAutoWrite = false, extras) {
|
|
68557
68796
|
const cwd = opts ? resolveHeadlessCwd(opts) : process.cwd();
|
|
68797
|
+
const { defaultPermissionPolicy: defaultPermissionPolicy2 } = await Promise.resolve().then(() => (init_toolPermissions(), toolPermissions_exports));
|
|
68558
68798
|
const { registry: toolRegistry } = createBuiltinToolRegistry({
|
|
68559
68799
|
root: cwd,
|
|
68560
68800
|
planMode,
|
|
68561
68801
|
...extras?.lspProvider ? { lspProvider: extras.lspProvider } : {},
|
|
68562
|
-
permissionPolicy:
|
|
68563
|
-
read: "allow",
|
|
68564
|
-
write: "allow",
|
|
68565
|
-
execute: "allow",
|
|
68566
|
-
network: "allow",
|
|
68567
|
-
ui: "allow",
|
|
68568
|
-
auto: true
|
|
68569
|
-
},
|
|
68802
|
+
permissionPolicy: defaultPermissionPolicy2(),
|
|
68570
68803
|
...memoryService ? { memoryService } : {},
|
|
68571
68804
|
memoryAutoWrite
|
|
68572
68805
|
});
|
|
@@ -69084,17 +69317,11 @@ ${ragContext}` : slicePrompt;
|
|
|
69084
69317
|
const { composeProjectContext: composeProjectContext2 } = await Promise.resolve().then(() => (init_composeContext(), composeContext_exports));
|
|
69085
69318
|
const { loadDurableContext: loadDurableContext2 } = await Promise.resolve().then(() => (init_loadDurableContext(), loadDurableContext_exports));
|
|
69086
69319
|
const { detectDegradedRun: detectDegradedRun2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
69320
|
+
const { defaultPermissionPolicy: defaultPermissionPolicy2 } = await Promise.resolve().then(() => (init_toolPermissions(), toolPermissions_exports));
|
|
69087
69321
|
const { registry: agentRegistry } = createBuiltinToolRegistry2({
|
|
69088
69322
|
root: projectRoot,
|
|
69089
69323
|
planMode: false,
|
|
69090
|
-
permissionPolicy:
|
|
69091
|
-
read: "allow",
|
|
69092
|
-
write: "allow",
|
|
69093
|
-
execute: "allow",
|
|
69094
|
-
network: "allow",
|
|
69095
|
-
ui: "allow",
|
|
69096
|
-
auto: true
|
|
69097
|
-
}
|
|
69324
|
+
permissionPolicy: defaultPermissionPolicy2()
|
|
69098
69325
|
});
|
|
69099
69326
|
await registerHeadlessMcp(agentRegistry, opts);
|
|
69100
69327
|
const durableState = await loadDurableContext2(projectRoot);
|
|
@@ -70821,6 +71048,87 @@ var init_config = __esm({
|
|
|
70821
71048
|
}
|
|
70822
71049
|
});
|
|
70823
71050
|
|
|
71051
|
+
// src/cli/serve/permissionBridge.ts
|
|
71052
|
+
function applyTurnPermissionPreset(input) {
|
|
71053
|
+
if (!input || typeof input !== "object") return false;
|
|
71054
|
+
const raw = input.permissionPreset;
|
|
71055
|
+
if (typeof raw !== "string") return false;
|
|
71056
|
+
const value = raw.trim().toLowerCase();
|
|
71057
|
+
if (!SERVE_PERMISSION_PRESETS.includes(value)) {
|
|
71058
|
+
return false;
|
|
71059
|
+
}
|
|
71060
|
+
process.env[PRESET_ENV] = value;
|
|
71061
|
+
return true;
|
|
71062
|
+
}
|
|
71063
|
+
function createServePermissionBridge(write, timeoutMs2 = 12e4) {
|
|
71064
|
+
const pending = /* @__PURE__ */ new Map();
|
|
71065
|
+
let seq = 0;
|
|
71066
|
+
const settle = (requestId, decision) => {
|
|
71067
|
+
const entry = pending.get(requestId);
|
|
71068
|
+
if (!entry) return false;
|
|
71069
|
+
pending.delete(requestId);
|
|
71070
|
+
clearTimeout(entry.timer);
|
|
71071
|
+
entry.resolve(decision);
|
|
71072
|
+
return true;
|
|
71073
|
+
};
|
|
71074
|
+
return {
|
|
71075
|
+
onPermissionAsk(payload) {
|
|
71076
|
+
const requestId = `perm-${Date.now()}-${++seq}`;
|
|
71077
|
+
return new Promise((resolve9) => {
|
|
71078
|
+
const timer = setTimeout(() => {
|
|
71079
|
+
settle(requestId, "deny");
|
|
71080
|
+
}, timeoutMs2);
|
|
71081
|
+
pending.set(requestId, { resolve: resolve9, timer });
|
|
71082
|
+
write(
|
|
71083
|
+
JSON.stringify({
|
|
71084
|
+
type: "permission.request",
|
|
71085
|
+
requestId,
|
|
71086
|
+
tool: payload.tool,
|
|
71087
|
+
category: payload.category,
|
|
71088
|
+
...payload.inputPreview !== void 0 ? { inputPreview: payload.inputPreview } : {},
|
|
71089
|
+
...payload.reason !== void 0 ? { reason: payload.reason } : {}
|
|
71090
|
+
})
|
|
71091
|
+
);
|
|
71092
|
+
});
|
|
71093
|
+
},
|
|
71094
|
+
respond: settle,
|
|
71095
|
+
pendingCount: () => pending.size
|
|
71096
|
+
};
|
|
71097
|
+
}
|
|
71098
|
+
function servePermissionRespond(bridge, params) {
|
|
71099
|
+
if (!params || typeof params !== "object") {
|
|
71100
|
+
return { accepted: false, reason: "permission.respond requires an object params" };
|
|
71101
|
+
}
|
|
71102
|
+
const { requestId, decision } = params;
|
|
71103
|
+
if (typeof requestId !== "string" || requestId.length === 0) {
|
|
71104
|
+
return { accepted: false, reason: "permission.respond requires a non-empty string requestId" };
|
|
71105
|
+
}
|
|
71106
|
+
if (decision !== "allow" && decision !== "deny") {
|
|
71107
|
+
return { accepted: false, reason: "permission.respond decision must be 'allow' or 'deny'" };
|
|
71108
|
+
}
|
|
71109
|
+
return { accepted: bridge.respond(requestId, decision) };
|
|
71110
|
+
}
|
|
71111
|
+
function asRegistryAskHandler(bridge) {
|
|
71112
|
+
return async (req) => {
|
|
71113
|
+
const reason = req.policyNote !== void 0 ? `${req.reason} ${req.policyNote}`.trim() : req.reason;
|
|
71114
|
+
const decision = await bridge.onPermissionAsk({
|
|
71115
|
+
tool: req.toolName,
|
|
71116
|
+
category: req.categories.join(",") || "other",
|
|
71117
|
+
reason,
|
|
71118
|
+
...req.claims && req.claims.length > 0 ? { inputPreview: req.claims.map((c) => c.summary).join(" \xB7 ") } : {}
|
|
71119
|
+
});
|
|
71120
|
+
return decision === "allow";
|
|
71121
|
+
};
|
|
71122
|
+
}
|
|
71123
|
+
var SERVE_PERMISSION_PRESETS, PRESET_ENV;
|
|
71124
|
+
var init_permissionBridge = __esm({
|
|
71125
|
+
"src/cli/serve/permissionBridge.ts"() {
|
|
71126
|
+
"use strict";
|
|
71127
|
+
SERVE_PERMISSION_PRESETS = ["standard", "strict", "yolo"];
|
|
71128
|
+
PRESET_ENV = "ZELARI_PERMISSION_PRESET";
|
|
71129
|
+
}
|
|
71130
|
+
});
|
|
71131
|
+
|
|
70824
71132
|
// src/cli/serve/spineLockSweep.ts
|
|
70825
71133
|
import { promises as fs47 } from "node:fs";
|
|
70826
71134
|
import path94 from "node:path";
|
|
@@ -70934,7 +71242,7 @@ function resolveTurnLspProvider(services) {
|
|
|
70934
71242
|
const candidate = services?.lspManager;
|
|
70935
71243
|
return candidate instanceof LspManager ? candidate : void 0;
|
|
70936
71244
|
}
|
|
70937
|
-
function createCliRunTurn() {
|
|
71245
|
+
function createCliRunTurn(onPermissionAsk) {
|
|
70938
71246
|
let streamPromise = null;
|
|
70939
71247
|
const ensureStream = () => {
|
|
70940
71248
|
if (!streamPromise) {
|
|
@@ -70960,6 +71268,8 @@ function createCliRunTurn() {
|
|
|
70960
71268
|
return async (input, deps) => {
|
|
70961
71269
|
const { provider, model, stream } = await ensureStream();
|
|
70962
71270
|
const opts = bindHarnessTurnOptions(input, deps.session.workspaceRoot);
|
|
71271
|
+
if (onPermissionAsk) opts.onPermissionAsk = onPermissionAsk;
|
|
71272
|
+
applyTurnPermissionPreset(input);
|
|
70963
71273
|
const lspProvider = resolveTurnLspProvider(deps.services);
|
|
70964
71274
|
const exitCode = await dispatchHeadlessTurn(
|
|
70965
71275
|
opts,
|
|
@@ -70993,15 +71303,26 @@ function startHarnessServer(options = {}) {
|
|
|
70993
71303
|
const respond = (envelope) => {
|
|
70994
71304
|
write(JSON.stringify(envelope));
|
|
70995
71305
|
};
|
|
71306
|
+
const permissionBridge = createServePermissionBridge(write);
|
|
70996
71307
|
const dispatch = async (req) => {
|
|
70997
71308
|
if (typeof req.method !== "string") {
|
|
70998
71309
|
return { id: req.id ?? null, ok: false, error: { code: "bad_request", message: "missing method" } };
|
|
70999
71310
|
}
|
|
71000
71311
|
const params = req.params ?? {};
|
|
71001
71312
|
switch (req.method) {
|
|
71313
|
+
case "permission.respond": {
|
|
71314
|
+
return {
|
|
71315
|
+
id: req.id ?? null,
|
|
71316
|
+
ok: true,
|
|
71317
|
+
result: servePermissionRespond(permissionBridge, params)
|
|
71318
|
+
};
|
|
71319
|
+
}
|
|
71002
71320
|
case "session.create": {
|
|
71003
71321
|
const root = typeof params.workspaceRoot === "string" ? params.workspaceRoot : process.cwd();
|
|
71004
|
-
const session = server.createSession({
|
|
71322
|
+
const session = server.createSession({
|
|
71323
|
+
workspaceRoot: root,
|
|
71324
|
+
runTurn: options.runTurn ?? createCliRunTurn(asRegistryAskHandler(permissionBridge))
|
|
71325
|
+
});
|
|
71005
71326
|
return { id: req.id ?? null, ok: true, result: { sessionId: session.id, workspaceRoot: session.workspaceRoot } };
|
|
71006
71327
|
}
|
|
71007
71328
|
case "run.turn": {
|
|
@@ -71153,6 +71474,7 @@ var init_harnessServer = __esm({
|
|
|
71153
71474
|
init_completionProofPersist();
|
|
71154
71475
|
init_policyGate();
|
|
71155
71476
|
init_policyLoadMode();
|
|
71477
|
+
init_permissionBridge();
|
|
71156
71478
|
init_spineLockSweep();
|
|
71157
71479
|
}
|
|
71158
71480
|
});
|
|
@@ -73381,12 +73703,13 @@ function StatusBar({
|
|
|
73381
73703
|
krakenLive = null,
|
|
73382
73704
|
krakenGraph = null,
|
|
73383
73705
|
verify = null,
|
|
73384
|
-
permissions = null
|
|
73706
|
+
permissions = null,
|
|
73707
|
+
jail = null
|
|
73385
73708
|
}) {
|
|
73386
73709
|
const ctxLabel = contextLimit > 0 ? `${formatTokens(contextUsed)}/${formatTokens(contextLimit)}` : contextUsed > 0 ? formatTokens(contextUsed) : null;
|
|
73387
73710
|
const modeLabel = mode === "council" ? "council" : mode === "zelari" ? "zelari" : "kraken";
|
|
73388
73711
|
const modeColor = mode === "council" ? "magenta" : mode === "zelari" ? "green" : "red";
|
|
73389
|
-
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))));
|
|
73712
|
+
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))));
|
|
73390
73713
|
}
|
|
73391
73714
|
|
|
73392
73715
|
// src/cli/components/SelectList.tsx
|
|
@@ -73655,75 +73978,8 @@ function useExecutionTimer(busy, tickMs = 1e3) {
|
|
|
73655
73978
|
init_paths2();
|
|
73656
73979
|
init_sessionTodos();
|
|
73657
73980
|
init_krakenLive();
|
|
73658
|
-
|
|
73659
|
-
|
|
73660
|
-
init_verificationBridge();
|
|
73661
|
-
function verifyStateFromGate(evaluation) {
|
|
73662
|
-
if (!evaluation.blocked) return "pass";
|
|
73663
|
-
const verdict = evaluation.evaluation?.verdict;
|
|
73664
|
-
if (verdict === "BLOCKED") return "blocked";
|
|
73665
|
-
return "repair";
|
|
73666
|
-
}
|
|
73667
|
-
function formatVerifyChip(state3) {
|
|
73668
|
-
if (state3 === "pass") return { label: "prova: PASS", tone: "green" };
|
|
73669
|
-
if (state3 === "blocked") return { label: "prova: BLOCCATO", tone: "red" };
|
|
73670
|
-
return { label: "prova: RIPARA", tone: "yellow" };
|
|
73671
|
-
}
|
|
73672
|
-
function permissionsChip(phase2, strictOn = strictDoneEnabled()) {
|
|
73673
|
-
if (phase2 === "plan") return { label: "scrive: no (piano)", tone: "yellow" };
|
|
73674
|
-
return strictOn ? { label: "scrive: s\xEC \xB7 prova obbligatoria", tone: "green" } : { label: "scrive: s\xEC \xB7 senza prova (dichiarato)", tone: "yellow" };
|
|
73675
|
-
}
|
|
73676
|
-
function formatStrictBlockExplanation(evaluation) {
|
|
73677
|
-
const state3 = verifyStateFromGate(evaluation);
|
|
73678
|
-
const gate = evaluation.gate;
|
|
73679
|
-
if (state3 === "pass") {
|
|
73680
|
-
return `[verifica] PASS \u2014 ${gate.passed}/${gate.total} prove superate.`;
|
|
73681
|
-
}
|
|
73682
|
-
const word = state3 === "blocked" ? "BLOCCATO" : "RIPARA";
|
|
73683
|
-
const lines = [
|
|
73684
|
-
`[verifica] ${word} \u2014 ${gate.passed}/${gate.total} prove superate; il turno non pu\xF2 dichiararsi finito senza prova.`
|
|
73685
|
-
];
|
|
73686
|
-
const evalr = evaluation.evaluation ?? null;
|
|
73687
|
-
if (evalr) {
|
|
73688
|
-
const byId = /* @__PURE__ */ new Map();
|
|
73689
|
-
for (const c of evalr.criteria ?? []) byId.set(c.id, c.text);
|
|
73690
|
-
const unsatisfied = (evalr.results ?? []).filter((r) => r.status !== "pass");
|
|
73691
|
-
if (unsatisfied.length > 0) {
|
|
73692
|
-
lines.push("Mancano:");
|
|
73693
|
-
for (const r of unsatisfied.slice(0, 8)) {
|
|
73694
|
-
lines.push(` \u2022 ${byId.get(r.criterionId) ?? r.criterionId} [${r.status}]`);
|
|
73695
|
-
}
|
|
73696
|
-
if (unsatisfied.length > 8) {
|
|
73697
|
-
lines.push(` \u2022 \u2026 e altri ${unsatisfied.length - 8}`);
|
|
73698
|
-
}
|
|
73699
|
-
const first = byId.get(unsatisfied[0].criterionId) ?? unsatisfied[0].criterionId;
|
|
73700
|
-
lines.push(
|
|
73701
|
-
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.`
|
|
73702
|
-
);
|
|
73703
|
-
}
|
|
73704
|
-
}
|
|
73705
|
-
lines.push(
|
|
73706
|
-
"La prova \xE8 obbligatoria: chiudo il turno solo quando ogni criterio richiesto ha evidenza."
|
|
73707
|
-
);
|
|
73708
|
-
return lines.join("\n");
|
|
73709
|
-
}
|
|
73710
|
-
function recordStrictGateEvaluation(evaluation) {
|
|
73711
|
-
const g = globalThis;
|
|
73712
|
-
g.__zelariVerifyState = {
|
|
73713
|
-
state: verifyStateFromGate(evaluation),
|
|
73714
|
-
at: Date.now(),
|
|
73715
|
-
passed: evaluation.gate.passed,
|
|
73716
|
-
total: evaluation.gate.total
|
|
73717
|
-
};
|
|
73718
|
-
}
|
|
73719
|
-
function getVerifyChip() {
|
|
73720
|
-
const g = globalThis;
|
|
73721
|
-
const s = g.__zelariVerifyState;
|
|
73722
|
-
if (!s) return null;
|
|
73723
|
-
return formatVerifyChip(s.state);
|
|
73724
|
-
}
|
|
73725
|
-
|
|
73726
|
-
// src/cli/app.tsx
|
|
73981
|
+
init_verifyStatus();
|
|
73982
|
+
init_osJail();
|
|
73727
73983
|
init_graphStatus();
|
|
73728
73984
|
|
|
73729
73985
|
// packages/core/dist/agents/skills/builtin/debugging.js
|
|
@@ -76304,6 +76560,7 @@ init_delegationPolicy();
|
|
|
76304
76560
|
init_completionGate();
|
|
76305
76561
|
init_verificationBridge();
|
|
76306
76562
|
init_completionProof();
|
|
76563
|
+
init_verifyStatus();
|
|
76307
76564
|
init_nativeVerification();
|
|
76308
76565
|
init_spineTelemetry();
|
|
76309
76566
|
|
|
@@ -78581,6 +78838,7 @@ function handleSlashCommand(text, availableSkills) {
|
|
|
78581
78838
|
/state restore [id] [--no-tree] \u2014 set HEAD + optional git checkpoint restore
|
|
78582
78839
|
/cache stats \u2014 prompt-cache hit rate, premium vs cached, stable busts
|
|
78583
78840
|
/index [status] \u2014 build the semantic code index for semantic_search
|
|
78841
|
+
/verify \u2014 re-evaluate the strict completion gate (deterministic, no LLM; criteria + next command)
|
|
78584
78842
|
/mode [kraken|council|zelari] \u2014 switch dispatch mode (same as shift+tab; agent=alias kraken)
|
|
78585
78843
|
/kraken [sessionId] \u2014 show Kraken tentacle radio (last spawns)
|
|
78586
78844
|
/trust [path] \u2014 trust a folder so project MCP + project hooks load
|
|
@@ -79082,6 +79340,9 @@ ${formatSkillList(availableSkills)}`
|
|
|
79082
79340
|
case "view-plan": {
|
|
79083
79341
|
return { handled: true, kind: "view_plan" };
|
|
79084
79342
|
}
|
|
79343
|
+
case "verify": {
|
|
79344
|
+
return { handled: true, kind: "verify" };
|
|
79345
|
+
}
|
|
79085
79346
|
case "index": {
|
|
79086
79347
|
return args[0] === "status" ? { handled: true, kind: "index_status" } : { handled: true, kind: "index_build" };
|
|
79087
79348
|
}
|
|
@@ -81817,6 +82078,21 @@ function useSlashDispatch(params) {
|
|
|
81817
82078
|
setInput("");
|
|
81818
82079
|
return;
|
|
81819
82080
|
}
|
|
82081
|
+
if (result.kind === "verify") {
|
|
82082
|
+
try {
|
|
82083
|
+
const { evaluateStrictBuildGate: evaluateStrictBuildGate2 } = await Promise.resolve().then(() => (init_verificationBridge(), verificationBridge_exports));
|
|
82084
|
+
const { formatStrictBlockExplanation: formatStrictBlockExplanation2 } = await Promise.resolve().then(() => (init_verifyStatus(), verifyStatus_exports));
|
|
82085
|
+
const evaluation = await evaluateStrictBuildGate2("build");
|
|
82086
|
+
appendSystem(setMessages, `[verify] ${formatStrictBlockExplanation2(evaluation)}`);
|
|
82087
|
+
} catch (err) {
|
|
82088
|
+
appendSystem(
|
|
82089
|
+
setMessages,
|
|
82090
|
+
`[verify] gate unavailable: ${err instanceof Error ? err.message : String(err)}`
|
|
82091
|
+
);
|
|
82092
|
+
}
|
|
82093
|
+
setInput("");
|
|
82094
|
+
return;
|
|
82095
|
+
}
|
|
81820
82096
|
if (result.kind === "promote_member" && result.promoteMemberId) {
|
|
81821
82097
|
await handlePromoteMember(baseCtx, result.promoteMemberId);
|
|
81822
82098
|
setInput("");
|
|
@@ -82005,6 +82281,15 @@ function useTerminalSize(options = {}) {
|
|
|
82005
82281
|
// src/cli/app.tsx
|
|
82006
82282
|
init_chatStats();
|
|
82007
82283
|
init_duration();
|
|
82284
|
+
function jailStatusChip() {
|
|
82285
|
+
const mode = activeJailMode();
|
|
82286
|
+
if (mode === "off") return null;
|
|
82287
|
+
const probe = probeJailBackend();
|
|
82288
|
+
if (!probe.available) {
|
|
82289
|
+
return { label: `jail: advisory (${probe.backend})`, tone: "yellow" };
|
|
82290
|
+
}
|
|
82291
|
+
return mode === "required" ? { label: `jail: on (${probe.backend})`, tone: "green" } : { label: `jail: advisory (${probe.backend})`, tone: "yellow" };
|
|
82292
|
+
}
|
|
82008
82293
|
var MODEL = process.env.OPENAI_MODEL ?? "grok-4.5";
|
|
82009
82294
|
var providerDefaults = {
|
|
82010
82295
|
"openai-compatible": "grok-4.5",
|
|
@@ -82220,7 +82505,8 @@ function App() {
|
|
|
82220
82505
|
krakenLive: formatKrakenLiveSummary() ?? void 0,
|
|
82221
82506
|
krakenGraph: formatKrakenGraphSummary() ?? void 0,
|
|
82222
82507
|
verify: getVerifyChip() ?? void 0,
|
|
82223
|
-
permissions: permissionsChip(phase2)
|
|
82508
|
+
permissions: permissionsChip(phase2),
|
|
82509
|
+
jail: jailStatusChip()
|
|
82224
82510
|
}
|
|
82225
82511
|
)), sidebarOpen && /* @__PURE__ */ React10.createElement(Sidebar, { version: VERSION, changes: gitChanges, rows: size.rows })));
|
|
82226
82512
|
}
|
|
@@ -83299,6 +83585,14 @@ function pickRootComponent() {
|
|
|
83299
83585
|
return { kind: "done" };
|
|
83300
83586
|
}
|
|
83301
83587
|
if (argv.includes("--doctor") || argv.includes("doctor")) {
|
|
83588
|
+
if (argv.includes("--json")) {
|
|
83589
|
+
const { collectDoctorReport: collectDoctorReport2 } = (init_doctor(), __toCommonJS(doctor_exports));
|
|
83590
|
+
void collectDoctorReport2().then((report) => {
|
|
83591
|
+
console.log(JSON.stringify(report));
|
|
83592
|
+
process.exit(report.healthy ? 0 : 1);
|
|
83593
|
+
});
|
|
83594
|
+
return { kind: "done" };
|
|
83595
|
+
}
|
|
83302
83596
|
const { runDoctor: runDoctor2 } = (init_doctor(), __toCommonJS(doctor_exports));
|
|
83303
83597
|
void runDoctor2().then((healthy) => process.exit(healthy ? 0 : 1));
|
|
83304
83598
|
return { kind: "done" };
|
|
@@ -83418,7 +83712,7 @@ proposals: npm run evolve:propose \u2014 decisions in npm run evolve:decide (P1:
|
|
|
83418
83712
|
}
|
|
83419
83713
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
83420
83714
|
console.log(
|
|
83421
|
-
"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
|
|
83715
|
+
"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"
|
|
83422
83716
|
);
|
|
83423
83717
|
process.exit(0);
|
|
83424
83718
|
}
|