zelari-code 2.6.0 → 2.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/budget/budgetRuntime.js +169 -10
- package/dist/cli/budget/budgetRuntime.js.map +1 -1
- package/dist/cli/budget/modelContextBuilder.js +8 -4
- package/dist/cli/budget/modelContextBuilder.js.map +1 -1
- package/dist/cli/budget/resourceLedger.js +4 -3
- package/dist/cli/budget/resourceLedger.js.map +1 -1
- package/dist/cli/budget/resourceSnapshot.js +11 -0
- package/dist/cli/budget/resourceSnapshot.js.map +1 -1
- package/dist/cli/budget/restoreRuntime.js +43 -0
- package/dist/cli/budget/restoreRuntime.js.map +1 -0
- package/dist/cli/gauntlet/loop.js +21 -1
- package/dist/cli/gauntlet/loop.js.map +1 -1
- package/dist/cli/gauntlet/policy.js +5 -2
- package/dist/cli/gauntlet/policy.js.map +1 -1
- package/dist/cli/gauntlet/run.js +6 -0
- package/dist/cli/gauntlet/run.js.map +1 -1
- package/dist/cli/harnessManifest.js +10 -15
- package/dist/cli/harnessManifest.js.map +1 -1
- package/dist/cli/headlessSpine.js +21 -9
- package/dist/cli/headlessSpine.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +22 -7
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/main.bundled.js +1063 -441
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/runHeadless.js +33 -1
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/sessionSpine.js +178 -14
- package/dist/cli/sessionSpine.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -28340,6 +28340,9 @@ var init_types8 = __esm({
|
|
|
28340
28340
|
// once at session start / manifest change. State-only (never model-surface):
|
|
28341
28341
|
// data = {manifest, manifestHash}. Schema review per ADR-0021.
|
|
28342
28342
|
"session.harness_manifest",
|
|
28343
|
+
// 2.6.1 (closure plan §6): resume-time harness drift record. State-only:
|
|
28344
|
+
// data = {originalManifestHash, currentManifestHash}. Non-blocking signal.
|
|
28345
|
+
"session.harness_drift",
|
|
28343
28346
|
"user.message",
|
|
28344
28347
|
"assistant.message",
|
|
28345
28348
|
"tool.call",
|
|
@@ -28370,9 +28373,12 @@ var init_types8 = __esm({
|
|
|
28370
28373
|
// 2.6 Track B (resource-aware execution, doc §9-§12): host-owned resource
|
|
28371
28374
|
// state. `resource.snapshot` is model-surface with LATEST-ONLY projection
|
|
28372
28375
|
// (doc §10.2 — see modelSurface.ts); limit/reserve events are state-only.
|
|
28376
|
+
"resource.epoch_started",
|
|
28373
28377
|
"resource.snapshot",
|
|
28374
28378
|
"resource.limit_reached",
|
|
28375
28379
|
"resource.reserve_entered",
|
|
28380
|
+
// 2.6.1 (closure plan §9): hard-limit overrun telemetry — state-only.
|
|
28381
|
+
"resource.overrun",
|
|
28376
28382
|
"note"
|
|
28377
28383
|
];
|
|
28378
28384
|
SessionEventEnvelopeSchema = external_exports.object({
|
|
@@ -28703,11 +28709,19 @@ function asNumber(value) {
|
|
|
28703
28709
|
function formatResourceSnapshot(data) {
|
|
28704
28710
|
const used = asNumber(data.toolCallsUsed) ?? 0;
|
|
28705
28711
|
const remaining = asNumber(data.toolCallsRemaining) ?? 0;
|
|
28712
|
+
const limit = asNumber(data.toolCallsLimit) ?? used + remaining;
|
|
28706
28713
|
const lines = [
|
|
28707
28714
|
"RESOURCE STATUS",
|
|
28708
|
-
`Tool calls: ${used} / ${
|
|
28715
|
+
`Tool calls: ${used} / ${limit}`,
|
|
28709
28716
|
`Remaining: ${remaining}`
|
|
28710
28717
|
];
|
|
28718
|
+
const sessionUsed = asNumber(data.sessionToolCallsUsed);
|
|
28719
|
+
if (sessionUsed !== void 0 && sessionUsed !== used) {
|
|
28720
|
+
lines.push(`Session total: ${sessionUsed}`);
|
|
28721
|
+
}
|
|
28722
|
+
const overrun = asNumber(data.overrun);
|
|
28723
|
+
if (overrun !== void 0 && overrun > 0)
|
|
28724
|
+
lines.push(`Overrun: ${overrun}`);
|
|
28711
28725
|
const wall = asNumber(data.wallMsRemaining);
|
|
28712
28726
|
if (wall !== void 0)
|
|
28713
28727
|
lines.push(`Wall clock remaining: ${Math.max(0, Math.round(wall / 1e3))}s`);
|
|
@@ -29595,7 +29609,24 @@ function pushCompactionViolations(events, knownSeq, pairs, violations) {
|
|
|
29595
29609
|
function validateResourceAndContractEvents(events) {
|
|
29596
29610
|
const violations = [];
|
|
29597
29611
|
let lastToolCallsUsed = -1;
|
|
29612
|
+
let lastEpoch = 0;
|
|
29613
|
+
let activeEpoch = 0;
|
|
29614
|
+
let lastSessionToolCallsUsed = -1;
|
|
29598
29615
|
for (const e of events) {
|
|
29616
|
+
if (e.kind === "resource.epoch_started") {
|
|
29617
|
+
const epoch = e.data.epoch;
|
|
29618
|
+
if (typeof epoch !== "number" || !Number.isInteger(epoch) || epoch <= lastEpoch) {
|
|
29619
|
+
violations.push({
|
|
29620
|
+
code: "RESOURCE_EPOCH_MONOTONIC",
|
|
29621
|
+
seq: e.seq,
|
|
29622
|
+
message: `resource epoch ${String(epoch)} did not increase past ${lastEpoch}`
|
|
29623
|
+
});
|
|
29624
|
+
} else {
|
|
29625
|
+
lastEpoch = epoch;
|
|
29626
|
+
activeEpoch = epoch;
|
|
29627
|
+
}
|
|
29628
|
+
lastToolCallsUsed = -1;
|
|
29629
|
+
}
|
|
29599
29630
|
if (e.kind === "resource.snapshot") {
|
|
29600
29631
|
const used = e.data.toolCallsUsed;
|
|
29601
29632
|
const remaining = e.data.toolCallsRemaining;
|
|
@@ -29607,9 +29638,41 @@ function validateResourceAndContractEvents(events) {
|
|
|
29607
29638
|
violations.push({ code: "RESOURCE_USED_MONOTONIC", seq: e.seq, message: `toolCallsUsed went ${lastToolCallsUsed} -> ${used}` });
|
|
29608
29639
|
}
|
|
29609
29640
|
lastToolCallsUsed = used;
|
|
29641
|
+
const epoch = e.data.epoch;
|
|
29642
|
+
if (epoch !== void 0 && (typeof epoch !== "number" || !Number.isInteger(epoch) || epoch !== activeEpoch)) {
|
|
29643
|
+
violations.push({
|
|
29644
|
+
code: "RESOURCE_SNAPSHOT_EPOCH_MISMATCH",
|
|
29645
|
+
seq: e.seq,
|
|
29646
|
+
message: `snapshot epoch ${String(epoch)} does not match active epoch ${activeEpoch}`
|
|
29647
|
+
});
|
|
29648
|
+
}
|
|
29649
|
+
const sessionUsed = e.data.sessionToolCallsUsed;
|
|
29650
|
+
if (sessionUsed !== void 0) {
|
|
29651
|
+
if (typeof sessionUsed !== "number" || !Number.isInteger(sessionUsed) || sessionUsed < used) {
|
|
29652
|
+
violations.push({
|
|
29653
|
+
code: "RESOURCE_SESSION_USAGE_INVALID",
|
|
29654
|
+
seq: e.seq,
|
|
29655
|
+
message: `sessionToolCallsUsed(${String(sessionUsed)}) must be an integer >= epoch used(${used})`
|
|
29656
|
+
});
|
|
29657
|
+
} else if (sessionUsed < lastSessionToolCallsUsed) {
|
|
29658
|
+
violations.push({
|
|
29659
|
+
code: "RESOURCE_SESSION_USAGE_MONOTONIC",
|
|
29660
|
+
seq: e.seq,
|
|
29661
|
+
message: `sessionToolCallsUsed went ${lastSessionToolCallsUsed} -> ${sessionUsed}`
|
|
29662
|
+
});
|
|
29663
|
+
}
|
|
29664
|
+
if (typeof sessionUsed === "number")
|
|
29665
|
+
lastSessionToolCallsUsed = sessionUsed;
|
|
29666
|
+
}
|
|
29610
29667
|
const limit = typeof e.data.toolCallsLimit === "number" ? e.data.toolCallsLimit : used + remaining;
|
|
29611
|
-
if (
|
|
29612
|
-
violations.push({ code: "RESOURCE_REMAINING_COHERENT", seq: e.seq, message: `
|
|
29668
|
+
if (remaining !== Math.max(0, limit - used)) {
|
|
29669
|
+
violations.push({ code: "RESOURCE_REMAINING_COHERENT", seq: e.seq, message: `remaining(${remaining}) != max(0, limit(${limit}) - used(${used}))` });
|
|
29670
|
+
}
|
|
29671
|
+
const overrun = e.data.overrun;
|
|
29672
|
+
if (overrun !== void 0) {
|
|
29673
|
+
if (typeof overrun !== "number" || overrun < 0 || overrun !== Math.max(0, used - limit)) {
|
|
29674
|
+
violations.push({ code: "RESOURCE_OVERRUN_COHERENT", seq: e.seq, message: `overrun(${String(overrun)}) != max(0, used(${used}) - limit(${limit}))` });
|
|
29675
|
+
}
|
|
29613
29676
|
}
|
|
29614
29677
|
for (const key of ["verificationReserve", "repairReserve"]) {
|
|
29615
29678
|
const v = e.data[key];
|
|
@@ -29706,27 +29769,53 @@ function contractToCompactionFields(contract) {
|
|
|
29706
29769
|
function deriveInitialContract(userSeq, text) {
|
|
29707
29770
|
const lines = text.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
29708
29771
|
const stripped = lines.map((l) => l.replace(/^[-*]\s+/, ""));
|
|
29709
|
-
const
|
|
29710
|
-
const
|
|
29772
|
+
const acceptanceCriteria = [];
|
|
29773
|
+
const criterionLines = /* @__PURE__ */ new Set();
|
|
29774
|
+
stripped.forEach((line, i) => {
|
|
29775
|
+
const checkbox = CHECKBOX_CRITERION.exec(line);
|
|
29776
|
+
if (checkbox) {
|
|
29777
|
+
criterionLines.add(i);
|
|
29778
|
+
acceptanceCriteria.push({
|
|
29779
|
+
id: `ac-${acceptanceCriteria.length + 1}`,
|
|
29780
|
+
text: checkbox[2].trim(),
|
|
29781
|
+
source: "user",
|
|
29782
|
+
required: true
|
|
29783
|
+
});
|
|
29784
|
+
return;
|
|
29785
|
+
}
|
|
29786
|
+
const keyword = KEYWORD_CRITERION.exec(line);
|
|
29787
|
+
if (keyword) {
|
|
29788
|
+
criterionLines.add(i);
|
|
29789
|
+
const value = keyword[2].trim();
|
|
29790
|
+
const lead = keyword[1].toLowerCase();
|
|
29791
|
+
const hint = (lead === "verify" || lead === "test") && COMMAND_HINT.test(value) ? { kind: "command", value } : void 0;
|
|
29792
|
+
acceptanceCriteria.push({
|
|
29793
|
+
id: `ac-${acceptanceCriteria.length + 1}`,
|
|
29794
|
+
text: value,
|
|
29795
|
+
source: "user",
|
|
29796
|
+
required: true,
|
|
29797
|
+
...hint ? { verificationHint: hint } : {}
|
|
29798
|
+
});
|
|
29799
|
+
}
|
|
29800
|
+
});
|
|
29801
|
+
const isConstraint = (i) => !criterionLines.has(i) && CONSTRAINT_LEAD.test(stripped[i] ?? "");
|
|
29802
|
+
const constraints = stripped.map((text2, i) => ({ text: text2, i })).filter(({ i }) => isConstraint(i)).map(({ text: text2 }, i) => ({
|
|
29803
|
+
id: `uc-${i + 1}`,
|
|
29804
|
+
text: text2,
|
|
29805
|
+
source: "user",
|
|
29806
|
+
required: true
|
|
29807
|
+
}));
|
|
29808
|
+
const goalIdx = lines.findIndex((_, i) => !criterionLines.has(i) && !isConstraint(i));
|
|
29809
|
+
const goal = goalIdx >= 0 ? lines[goalIdx] : lines[0] ?? text.slice(0, 200);
|
|
29711
29810
|
return TaskContractSchema.parse({
|
|
29712
29811
|
version: 1,
|
|
29713
|
-
goal
|
|
29714
|
-
constraints
|
|
29715
|
-
|
|
29716
|
-
text: t,
|
|
29717
|
-
source: "user",
|
|
29718
|
-
required: true
|
|
29719
|
-
})),
|
|
29720
|
-
acceptanceCriteria: criteriaLines.map((t, i) => ({
|
|
29721
|
-
id: `ac-${i + 1}`,
|
|
29722
|
-
text: t,
|
|
29723
|
-
source: "user",
|
|
29724
|
-
required: true
|
|
29725
|
-
})),
|
|
29812
|
+
goal,
|
|
29813
|
+
constraints,
|
|
29814
|
+
acceptanceCriteria,
|
|
29726
29815
|
source: { userSeq }
|
|
29727
29816
|
});
|
|
29728
29817
|
}
|
|
29729
|
-
var TaskConstraintSchema, TaskCriterionSchema, TaskContractSchema, TaskContractConflictError;
|
|
29818
|
+
var TaskConstraintSchema, TaskCriterionSchema, TaskContractSchema, TaskContractConflictError, CHECKBOX_CRITERION, KEYWORD_CRITERION, COMMAND_HINT, CONSTRAINT_LEAD;
|
|
29730
29819
|
var init_taskContract = __esm({
|
|
29731
29820
|
"packages/core/dist/session/taskContract.js"() {
|
|
29732
29821
|
"use strict";
|
|
@@ -29766,6 +29855,10 @@ var init_taskContract = __esm({
|
|
|
29766
29855
|
this.name = "TaskContractConflictError";
|
|
29767
29856
|
}
|
|
29768
29857
|
};
|
|
29858
|
+
CHECKBOX_CRITERION = /^\[([ xX])\]\s*(.+)$/;
|
|
29859
|
+
KEYWORD_CRITERION = /^(acceptance|criterion|criteria|verify|test|success)\s*[:#]\s*(.+)$/i;
|
|
29860
|
+
COMMAND_HINT = /^(npm|pnpm|yarn|bun|npx|node|vitest|jest|tsc|eslint|prettier|git)\b/;
|
|
29861
|
+
CONSTRAINT_LEAD = /^(do not|don't|never|no\s|non\s|without changing|keep|must not|avoid)\b/i;
|
|
29769
29862
|
}
|
|
29770
29863
|
});
|
|
29771
29864
|
|
|
@@ -30233,9 +30326,13 @@ function classifyHarnessChanges(diff) {
|
|
|
30233
30326
|
const hit = FIELD_CLASSES.find((m) => field === m.prefix || field.startsWith(m.prefix + "."));
|
|
30234
30327
|
byField[field] = hit ? hit.cls : "cosmetic";
|
|
30235
30328
|
}
|
|
30329
|
+
const changeSet = { structural: [], behavioral: [], cosmetic: [] };
|
|
30330
|
+
for (const field of diff.changed) {
|
|
30331
|
+
changeSet[byField[field]].push(field);
|
|
30332
|
+
}
|
|
30236
30333
|
const order = { behavioral: 3, structural: 2, cosmetic: 1 };
|
|
30237
30334
|
const overall = Object.values(byField).reduce((acc, cls) => order[cls] > order[acc] ? cls : acc, "cosmetic");
|
|
30238
|
-
return { overall, byField };
|
|
30335
|
+
return { overall, byField, changeSet };
|
|
30239
30336
|
}
|
|
30240
30337
|
var HARNESS_MANIFEST_SCHEMA_VERSION, HarnessPromptsSchema, HarnessManifestV1Schema, FIELD_CLASSES;
|
|
30241
30338
|
var init_harnessManifest = __esm({
|
|
@@ -30446,12 +30543,14 @@ var init_resourcePolicy = __esm({
|
|
|
30446
30543
|
|
|
30447
30544
|
// packages/core/dist/runtime/resourceBudget.js
|
|
30448
30545
|
function computeBudget(policy, usage, stage = "explore") {
|
|
30449
|
-
const used = Math.max(0,
|
|
30546
|
+
const used = Math.max(0, usage.toolCallsUsed);
|
|
30547
|
+
const overrun = Math.max(0, used - policy.maxToolCalls);
|
|
30450
30548
|
return {
|
|
30451
30549
|
toolCalls: {
|
|
30452
30550
|
limit: policy.maxToolCalls,
|
|
30453
30551
|
used,
|
|
30454
|
-
remaining: policy.maxToolCalls - used
|
|
30552
|
+
remaining: Math.max(0, policy.maxToolCalls - used),
|
|
30553
|
+
overrun
|
|
30455
30554
|
},
|
|
30456
30555
|
wallTime: {
|
|
30457
30556
|
limitMs: policy.wallClockMs,
|
|
@@ -31465,6 +31564,48 @@ var init_resourceReserveGate = __esm({
|
|
|
31465
31564
|
});
|
|
31466
31565
|
|
|
31467
31566
|
// packages/core/dist/verification/index.js
|
|
31567
|
+
var verification_exports = {};
|
|
31568
|
+
__export(verification_exports, {
|
|
31569
|
+
BonConfigSchema: () => BonConfigSchema,
|
|
31570
|
+
CommandCheckSchema: () => CommandCheckSchema,
|
|
31571
|
+
CriterionSchema: () => CriterionSchema,
|
|
31572
|
+
CriterionSourceSchema: () => CriterionSourceSchema,
|
|
31573
|
+
DEFAULT_VERIFIER_CONFIG: () => DEFAULT_VERIFIER_CONFIG,
|
|
31574
|
+
DETERMINISTIC_EVIDENCE_TIERS: () => DETERMINISTIC_EVIDENCE_TIERS,
|
|
31575
|
+
DeterministicCheckSchema: () => DeterministicCheckSchema,
|
|
31576
|
+
EVENT_BACKED_EVIDENCE_TIERS: () => EVENT_BACKED_EVIDENCE_TIERS,
|
|
31577
|
+
EvidenceRefSchema: () => EvidenceRefSchema,
|
|
31578
|
+
EvidenceTierSchema: () => EvidenceTierSchema,
|
|
31579
|
+
FileAbsentCheckSchema: () => FileAbsentCheckSchema,
|
|
31580
|
+
FileContainsCheckSchema: () => FileContainsCheckSchema,
|
|
31581
|
+
FileExistsCheckSchema: () => FileExistsCheckSchema,
|
|
31582
|
+
ModelSelectionSchema: () => ModelSelectionSchema,
|
|
31583
|
+
NoneCheckSchema: () => NoneCheckSchema,
|
|
31584
|
+
STRICT_ALL_POLICY: () => STRICT_ALL_POLICY,
|
|
31585
|
+
STRICT_BUILD_POLICY: () => STRICT_BUILD_POLICY,
|
|
31586
|
+
VerificationEngine: () => VerificationEngine,
|
|
31587
|
+
VerificationResultSchema: () => VerificationResultSchema,
|
|
31588
|
+
VerificationSourceSchema: () => VerificationSourceSchema,
|
|
31589
|
+
VerificationStatusSchema: () => VerificationStatusSchema,
|
|
31590
|
+
VerifierConfigSchema: () => VerifierConfigSchema,
|
|
31591
|
+
VerifierService: () => VerifierService,
|
|
31592
|
+
ZELARI_CODING_PACK_ID: () => ZELARI_CODING_PACK_ID,
|
|
31593
|
+
analyzeScope: () => analyzeScope,
|
|
31594
|
+
codingCriteriaPack: () => codingCriteriaPack,
|
|
31595
|
+
computeFalseDoneRate: () => computeFalseDoneRate,
|
|
31596
|
+
costPerVerifiedSolve: () => costPerVerifiedSolve,
|
|
31597
|
+
evaluateCompletion: () => evaluateCompletion,
|
|
31598
|
+
evaluateResourceReserveGate: () => evaluateResourceReserveGate,
|
|
31599
|
+
isEventBackedEvidence: () => isEventBackedEvidence,
|
|
31600
|
+
isGeneratedPath: () => isGeneratedPath,
|
|
31601
|
+
lastVerificationRun: () => lastVerificationRun,
|
|
31602
|
+
parseNameOnlyDiff: () => parseNameOnlyDiff,
|
|
31603
|
+
parseVerificationRunPayload: () => parseVerificationRunPayload,
|
|
31604
|
+
snapshotToCompletionEvaluation: () => snapshotToCompletionEvaluation,
|
|
31605
|
+
strictBuildGate: () => strictBuildGate,
|
|
31606
|
+
verificationCostRatio: () => verificationCostRatio,
|
|
31607
|
+
verifiedSolveRate: () => verifiedSolveRate
|
|
31608
|
+
});
|
|
31468
31609
|
var init_verification2 = __esm({
|
|
31469
31610
|
"packages/core/dist/verification/index.js"() {
|
|
31470
31611
|
"use strict";
|
|
@@ -31621,6 +31762,42 @@ var init_mission2 = __esm({
|
|
|
31621
31762
|
}
|
|
31622
31763
|
});
|
|
31623
31764
|
|
|
31765
|
+
// packages/core/dist/version.js
|
|
31766
|
+
var CORE_VERSION;
|
|
31767
|
+
var init_version = __esm({
|
|
31768
|
+
"packages/core/dist/version.js"() {
|
|
31769
|
+
"use strict";
|
|
31770
|
+
CORE_VERSION = "2.6.2";
|
|
31771
|
+
}
|
|
31772
|
+
});
|
|
31773
|
+
|
|
31774
|
+
// packages/core/dist/runtime/fingerprints.js
|
|
31775
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
31776
|
+
function toolFingerprintHash(tools) {
|
|
31777
|
+
const canonical = [...tools].map((t) => ({
|
|
31778
|
+
name: t.name,
|
|
31779
|
+
...t.description !== void 0 ? { description: t.description } : {},
|
|
31780
|
+
...t.inputSchema !== void 0 ? { inputSchema: t.inputSchema } : {},
|
|
31781
|
+
...t.outputContractVersion !== void 0 ? { outputContractVersion: t.outputContractVersion } : {},
|
|
31782
|
+
...t.capabilityFlags !== void 0 ? { capabilityFlags: [...t.capabilityFlags].sort() } : {}
|
|
31783
|
+
})).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
31784
|
+
return createHash6("sha256").update(stableStringify(canonical)).digest("hex");
|
|
31785
|
+
}
|
|
31786
|
+
function skillFingerprintHash(skills) {
|
|
31787
|
+
const canonical = [...skills].map((s) => ({
|
|
31788
|
+
id: s.id,
|
|
31789
|
+
...s.version !== void 0 ? { version: s.version } : {},
|
|
31790
|
+
...s.contentDigest !== void 0 ? { contentDigest: s.contentDigest } : {}
|
|
31791
|
+
})).sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
31792
|
+
return createHash6("sha256").update(stableStringify(canonical)).digest("hex");
|
|
31793
|
+
}
|
|
31794
|
+
var init_fingerprints = __esm({
|
|
31795
|
+
"packages/core/dist/runtime/fingerprints.js"() {
|
|
31796
|
+
"use strict";
|
|
31797
|
+
init_requestSnapshot();
|
|
31798
|
+
}
|
|
31799
|
+
});
|
|
31800
|
+
|
|
31624
31801
|
// packages/core/dist/index.js
|
|
31625
31802
|
var dist_exports = {};
|
|
31626
31803
|
__export(dist_exports, {
|
|
@@ -31642,6 +31819,7 @@ __export(dist_exports, {
|
|
|
31642
31819
|
CODING_SKILL_CATALOG: () => CODING_SKILL_CATALOG,
|
|
31643
31820
|
COLLABORATION_DIRECTIVE: () => COLLABORATION_DIRECTIVE,
|
|
31644
31821
|
COMPOSITOR_ONLY_PROPS: () => COMPOSITOR_ONLY_PROPS,
|
|
31822
|
+
CORE_VERSION: () => CORE_VERSION,
|
|
31645
31823
|
COUNCIL_V1: () => COUNCIL_V1,
|
|
31646
31824
|
CommandCheckSchema: () => CommandCheckSchema,
|
|
31647
31825
|
CriterionSchema: () => CriterionSchema,
|
|
@@ -31986,6 +32164,7 @@ __export(dist_exports, {
|
|
|
31986
32164
|
shadowedSeqSet: () => shadowedSeqSet,
|
|
31987
32165
|
shouldRetryMember: () => shouldRetryMember,
|
|
31988
32166
|
sideEffectForTool: () => sideEffectForTool,
|
|
32167
|
+
skillFingerprintHash: () => skillFingerprintHash,
|
|
31989
32168
|
slugify: () => slugify2,
|
|
31990
32169
|
snapshotToCompletionEvaluation: () => snapshotToCompletionEvaluation,
|
|
31991
32170
|
specificityFromAssumptions: () => specificityFromAssumptions,
|
|
@@ -31997,6 +32176,7 @@ __export(dist_exports, {
|
|
|
31997
32176
|
taskMatchesNfrKeywords: () => taskMatchesNfrKeywords,
|
|
31998
32177
|
tierAtLeast: () => tierAtLeast,
|
|
31999
32178
|
tokenizeForSignature: () => tokenizeForSignature,
|
|
32179
|
+
toolFingerprintHash: () => toolFingerprintHash,
|
|
32000
32180
|
toolManifestHash: () => toolManifestHash,
|
|
32001
32181
|
toolMatches: () => toolMatches,
|
|
32002
32182
|
topoLevels: () => topoLevels,
|
|
@@ -32035,6 +32215,8 @@ var init_dist = __esm({
|
|
|
32035
32215
|
init_verification2();
|
|
32036
32216
|
init_mission2();
|
|
32037
32217
|
init_experimental();
|
|
32218
|
+
init_version();
|
|
32219
|
+
init_fingerprints();
|
|
32038
32220
|
}
|
|
32039
32221
|
});
|
|
32040
32222
|
|
|
@@ -32367,6 +32549,7 @@ function buildResourceSnapshot(budget, policy) {
|
|
|
32367
32549
|
toolCallsLimit: budget.toolCalls.limit,
|
|
32368
32550
|
toolCallsUsed: budget.toolCalls.used,
|
|
32369
32551
|
toolCallsRemaining: budget.toolCalls.remaining,
|
|
32552
|
+
overrun: budget.toolCalls.overrun,
|
|
32370
32553
|
...budget.wallTime.remainingMs !== void 0 ? { wallMsRemaining: budget.wallTime.remainingMs } : {},
|
|
32371
32554
|
verificationReserve: budget.reserve.verification,
|
|
32372
32555
|
repairReserve: budget.reserve.repair,
|
|
@@ -32375,6 +32558,13 @@ function buildResourceSnapshot(budget, policy) {
|
|
|
32375
32558
|
reserveProtected: isVerificationReserveProtected(budget)
|
|
32376
32559
|
};
|
|
32377
32560
|
}
|
|
32561
|
+
function withResourceSnapshotContext(snapshot, context) {
|
|
32562
|
+
return {
|
|
32563
|
+
...snapshot,
|
|
32564
|
+
...context.epoch !== void 0 ? { epoch: context.epoch } : {},
|
|
32565
|
+
...context.sessionToolCallsUsed !== void 0 ? { sessionToolCallsUsed: context.sessionToolCallsUsed } : {}
|
|
32566
|
+
};
|
|
32567
|
+
}
|
|
32378
32568
|
function shouldEmitSnapshot(previous, next) {
|
|
32379
32569
|
if (!previous) return true;
|
|
32380
32570
|
if (previous.stage !== next.stage) return true;
|
|
@@ -32394,7 +32584,29 @@ var init_resourceSnapshot = __esm({
|
|
|
32394
32584
|
function resolveResourceEnforcement(env = process.env) {
|
|
32395
32585
|
return env.ZELARI_RESOURCE_ENFORCEMENT === "protected" ? "protected" : "advisory";
|
|
32396
32586
|
}
|
|
32397
|
-
|
|
32587
|
+
function bashCommand(args) {
|
|
32588
|
+
if (!args || typeof args !== "object") return "";
|
|
32589
|
+
const rec = args;
|
|
32590
|
+
for (const key of ["command", "cmd", "script"]) {
|
|
32591
|
+
if (typeof rec[key] === "string") return rec[key];
|
|
32592
|
+
}
|
|
32593
|
+
return "";
|
|
32594
|
+
}
|
|
32595
|
+
function isVerificationEssential(toolName, args, _stage = "implement") {
|
|
32596
|
+
if (toolName === "bash") {
|
|
32597
|
+
const cmd = bashCommand(args);
|
|
32598
|
+
if (!cmd) return false;
|
|
32599
|
+
return ESSENTIAL_BASH.some((re) => re.test(cmd));
|
|
32600
|
+
}
|
|
32601
|
+
if (toolName === "grep_content") {
|
|
32602
|
+
if (!args || typeof args !== "object") return true;
|
|
32603
|
+
const rec = args;
|
|
32604
|
+
const hasScope = typeof rec.path === "string" && rec.path !== "." && rec.path !== "./";
|
|
32605
|
+
return hasScope || typeof rec.pattern === "string";
|
|
32606
|
+
}
|
|
32607
|
+
return DEFAULT_ESSENTIAL_TOOLS.includes(toolName);
|
|
32608
|
+
}
|
|
32609
|
+
var DEFAULT_ESSENTIAL_TOOLS, ADVISORY_NOTICE, PROTECTED_DENIAL, HARD_LIMIT_DENIAL, ESSENTIAL_BASH, BudgetRuntime;
|
|
32398
32610
|
var init_budgetRuntime = __esm({
|
|
32399
32611
|
"src/cli/budget/budgetRuntime.ts"() {
|
|
32400
32612
|
"use strict";
|
|
@@ -32402,7 +32614,6 @@ var init_budgetRuntime = __esm({
|
|
|
32402
32614
|
init_resourceLedger();
|
|
32403
32615
|
init_resourceSnapshot();
|
|
32404
32616
|
DEFAULT_ESSENTIAL_TOOLS = [
|
|
32405
|
-
"bash",
|
|
32406
32617
|
"read_file",
|
|
32407
32618
|
"edit_file",
|
|
32408
32619
|
"write_file",
|
|
@@ -32413,27 +32624,88 @@ var init_budgetRuntime = __esm({
|
|
|
32413
32624
|
];
|
|
32414
32625
|
ADVISORY_NOTICE = "Resource advisory: verification reserve reached. Prioritize test/typecheck/build/diff and targeted repair; avoid broad exploration or delegation.";
|
|
32415
32626
|
PROTECTED_DENIAL = "Resource protected: remaining tool calls are reserved for verification and targeted repair. Run the required checks (test/typecheck/build), read the failure, apply a minimal fix, retest \u2014 or report BLOCKED with the evidence you have.";
|
|
32627
|
+
HARD_LIMIT_DENIAL = "Resource exhausted: this turn's execution budget (maxToolCalls) is spent. No further billable tool calls are allowed in this turn \u2014 summarize what was verified and report BLOCKED/resource-exhausted with the evidence already collected. A later user turn starts a fresh execution budget.";
|
|
32628
|
+
ESSENTIAL_BASH = [
|
|
32629
|
+
/\b(npm|pnpm|yarn|bun)\s+(run\s+)?(test|vitest|jest)\b/,
|
|
32630
|
+
/\b(npm|pnpm|yarn|bun)\s+run\s+[\w:-]*(typecheck|lint|build)\b/,
|
|
32631
|
+
/\bnpx\s+(vitest|tsc|typescript|eslint)\b/,
|
|
32632
|
+
/\b(npx\s+)?tsc\b/,
|
|
32633
|
+
/\bvitest\b/,
|
|
32634
|
+
/\bjest\b/,
|
|
32635
|
+
/\bnode\s+--run\b/,
|
|
32636
|
+
/\bgit\s+(diff|status|log|show)\b/
|
|
32637
|
+
];
|
|
32416
32638
|
BudgetRuntime = class {
|
|
32417
32639
|
policy;
|
|
32418
32640
|
enforcement;
|
|
32419
32641
|
ledger;
|
|
32420
32642
|
essential;
|
|
32643
|
+
initialStage;
|
|
32421
32644
|
stage;
|
|
32645
|
+
epoch = 0;
|
|
32646
|
+
executionBaseline = { toolCallsUsed: 0, wallMs: 0, tokensUsed: 0 };
|
|
32422
32647
|
lastEmitted;
|
|
32648
|
+
hardLimitAnnounced = false;
|
|
32423
32649
|
constructor(profileId, opts = {}) {
|
|
32424
|
-
|
|
32650
|
+
const basePolicy = opts.policy ?? defaultResourcePolicy(profileId);
|
|
32651
|
+
const envCap = Number.parseInt(process.env.ZELARI_MAX_TOOL_CALLS ?? "", 10);
|
|
32652
|
+
this.policy = Number.isFinite(envCap) && envCap >= 1 ? { ...basePolicy, maxToolCalls: envCap } : basePolicy;
|
|
32425
32653
|
this.enforcement = opts.enforcement ?? "advisory";
|
|
32426
32654
|
this.essential = new Set(opts.essentialTools ?? DEFAULT_ESSENTIAL_TOOLS);
|
|
32427
|
-
this.
|
|
32655
|
+
this.initialStage = opts.stage ?? "implement";
|
|
32656
|
+
this.stage = this.initialStage;
|
|
32428
32657
|
this.ledger = new ResourceLedger();
|
|
32429
32658
|
}
|
|
32659
|
+
/**
|
|
32660
|
+
* Start a fresh user-turn execution epoch. The durable ledger remains
|
|
32661
|
+
* cumulative for telemetry; only the enforcement baseline moves forward.
|
|
32662
|
+
*/
|
|
32663
|
+
beginTurn() {
|
|
32664
|
+
this.executionBaseline = this.ledger.usage();
|
|
32665
|
+
this.epoch += 1;
|
|
32666
|
+
this.stage = this.initialStage;
|
|
32667
|
+
this.hardLimitAnnounced = false;
|
|
32668
|
+
this.lastEmitted = void 0;
|
|
32669
|
+
const next = this.current();
|
|
32670
|
+
this.lastEmitted = next;
|
|
32671
|
+
return next;
|
|
32672
|
+
}
|
|
32673
|
+
/** Cumulative session telemetry (never reset by beginTurn). */
|
|
32674
|
+
sessionUsage() {
|
|
32675
|
+
return this.ledger.usage();
|
|
32676
|
+
}
|
|
32430
32677
|
/**
|
|
32431
32678
|
* Count one tool call; returns the snapshot to emit when §10.4 says so
|
|
32432
32679
|
* (first sight, stage/pressure change, reserve crossing, any usage delta).
|
|
32433
32680
|
*/
|
|
32434
32681
|
noteToolCall() {
|
|
32682
|
+
return this.consumeToolCall().snapshot;
|
|
32683
|
+
}
|
|
32684
|
+
/**
|
|
32685
|
+
* 2.6.1 (plan §9): count one tool call AND surface the hard-limit event
|
|
32686
|
+
* due on this call — `resource.limit_reached` once at the crossing,
|
|
32687
|
+
* `resource.overrun` for every call past the limit. The spine appends the
|
|
32688
|
+
* event right after its tool.call.
|
|
32689
|
+
*/
|
|
32690
|
+
consumeToolCall() {
|
|
32435
32691
|
this.ledger.record("tool-call");
|
|
32436
|
-
|
|
32692
|
+
const next = this.current();
|
|
32693
|
+
let hardEvent = null;
|
|
32694
|
+
const data = {
|
|
32695
|
+
epoch: next.epoch,
|
|
32696
|
+
used: next.toolCallsUsed,
|
|
32697
|
+
limit: next.toolCallsLimit,
|
|
32698
|
+
overrun: next.overrun,
|
|
32699
|
+
sessionToolCallsUsed: next.sessionToolCallsUsed
|
|
32700
|
+
};
|
|
32701
|
+
if (!this.hardLimitAnnounced && next.toolCallsRemaining <= 0) {
|
|
32702
|
+
this.hardLimitAnnounced = true;
|
|
32703
|
+
hardEvent = { kind: "resource.limit_reached", data };
|
|
32704
|
+
} else if (next.overrun > 0) {
|
|
32705
|
+
hardEvent = { kind: "resource.overrun", data };
|
|
32706
|
+
}
|
|
32707
|
+
const snapshot = shouldEmitSnapshot(this.lastEmitted, next) ? (this.lastEmitted = next, next) : null;
|
|
32708
|
+
return { snapshot, hardEvent };
|
|
32437
32709
|
}
|
|
32438
32710
|
/** §10.4 verification start: stage change (and a zero-cost ledger mark). */
|
|
32439
32711
|
noteVerificationStart() {
|
|
@@ -32450,18 +32722,44 @@ var init_budgetRuntime = __esm({
|
|
|
32450
32722
|
this.stage = stage;
|
|
32451
32723
|
return this.emitIfDue();
|
|
32452
32724
|
}
|
|
32725
|
+
/** 2.6.1 (plan §14): canonical budget for the reserve gate. */
|
|
32726
|
+
budgetSnapshot() {
|
|
32727
|
+
const cumulative = this.ledger.usage();
|
|
32728
|
+
return computeBudget(
|
|
32729
|
+
this.policy,
|
|
32730
|
+
{
|
|
32731
|
+
toolCallsUsed: Math.max(0, cumulative.toolCallsUsed - this.executionBaseline.toolCallsUsed),
|
|
32732
|
+
elapsedMs: Math.max(0, cumulative.wallMs - this.executionBaseline.wallMs),
|
|
32733
|
+
tokensUsed: Math.max(0, cumulative.tokensUsed - this.executionBaseline.tokensUsed)
|
|
32734
|
+
},
|
|
32735
|
+
this.stage
|
|
32736
|
+
);
|
|
32737
|
+
}
|
|
32453
32738
|
/** Current projection without emitting. */
|
|
32454
32739
|
current() {
|
|
32455
|
-
|
|
32740
|
+
const cumulative = this.ledger.usage();
|
|
32741
|
+
return withResourceSnapshotContext(buildResourceSnapshot(this.budgetSnapshot(), this.policy), {
|
|
32742
|
+
epoch: this.epoch,
|
|
32743
|
+
sessionToolCallsUsed: cumulative.toolCallsUsed
|
|
32744
|
+
});
|
|
32456
32745
|
}
|
|
32457
|
-
/**
|
|
32458
|
-
|
|
32746
|
+
/**
|
|
32747
|
+
* §11.3 gate — argument-aware (2.6.1 §13). Hard limit denies first in BOTH
|
|
32748
|
+
* modes; advisory mode never blocks inside the protected zone; protected
|
|
32749
|
+
* mode guards the zone with isVerificationEssential(tool, args).
|
|
32750
|
+
*/
|
|
32751
|
+
gateToolCall(toolNameOrInput) {
|
|
32752
|
+
const input = typeof toolNameOrInput === "string" ? { toolName: toolNameOrInput } : toolNameOrInput;
|
|
32459
32753
|
const snapshot = this.current();
|
|
32754
|
+
if (snapshot.toolCallsRemaining <= 0) {
|
|
32755
|
+
return { allowed: false, advisory: false, reason: HARD_LIMIT_DENIAL, snapshot, hardLimit: true };
|
|
32756
|
+
}
|
|
32460
32757
|
if (!snapshot.reserveProtected) return { allowed: true, advisory: false, snapshot };
|
|
32461
32758
|
if (this.enforcement === "advisory") {
|
|
32462
32759
|
return { allowed: true, advisory: true, reason: ADVISORY_NOTICE, snapshot };
|
|
32463
32760
|
}
|
|
32464
|
-
|
|
32761
|
+
const essential = input.toolName === "bash" || input.toolName === "grep_content" ? isVerificationEssential(input.toolName, input.args, input.stage ?? this.stage) : this.essential.has(input.toolName);
|
|
32762
|
+
if (essential) {
|
|
32465
32763
|
return { allowed: true, advisory: true, reason: ADVISORY_NOTICE, snapshot };
|
|
32466
32764
|
}
|
|
32467
32765
|
return { allowed: false, advisory: false, reason: PROTECTED_DENIAL, snapshot };
|
|
@@ -32470,7 +32768,26 @@ var init_budgetRuntime = __esm({
|
|
|
32470
32768
|
adoptLedgerFromEvents(events) {
|
|
32471
32769
|
const rebuilt = rebuildLedgerFromEvents(events);
|
|
32472
32770
|
this.ledger.resetTo(rebuilt.snapshot());
|
|
32771
|
+
let epochStart = -1;
|
|
32772
|
+
let fallbackUserStart = -1;
|
|
32773
|
+
let restoredEpoch = 0;
|
|
32774
|
+
for (let i = 0; i < events.length; i++) {
|
|
32775
|
+
const event = events[i];
|
|
32776
|
+
if (event.kind === "user.message") fallbackUserStart = i;
|
|
32777
|
+
if (event.kind === "resource.epoch_started") {
|
|
32778
|
+
epochStart = i;
|
|
32779
|
+
const value = event.data.epoch;
|
|
32780
|
+
if (typeof value === "number" && Number.isInteger(value) && value > restoredEpoch) {
|
|
32781
|
+
restoredEpoch = value;
|
|
32782
|
+
}
|
|
32783
|
+
}
|
|
32784
|
+
}
|
|
32785
|
+
const activeStart = epochStart >= 0 ? epochStart : fallbackUserStart;
|
|
32786
|
+
this.executionBaseline = activeStart >= 0 ? rebuildLedgerFromEvents(events.slice(0, activeStart + 1)).usage() : { toolCallsUsed: 0, wallMs: 0, tokensUsed: 0 };
|
|
32787
|
+
this.epoch = restoredEpoch;
|
|
32473
32788
|
this.lastEmitted = void 0;
|
|
32789
|
+
const now = this.current();
|
|
32790
|
+
this.hardLimitAnnounced = now.toolCallsRemaining <= 0;
|
|
32474
32791
|
}
|
|
32475
32792
|
/** Latest emitted snapshot (what the model surface shows), if any. */
|
|
32476
32793
|
latestEmitted() {
|
|
@@ -32488,8 +32805,293 @@ var init_budgetRuntime = __esm({
|
|
|
32488
32805
|
}
|
|
32489
32806
|
});
|
|
32490
32807
|
|
|
32491
|
-
// src/cli/
|
|
32808
|
+
// src/cli/budget/restoreRuntime.ts
|
|
32492
32809
|
import path21 from "node:path";
|
|
32810
|
+
async function restoreBudgetRuntimeFromSession(budget, sessionId2, baseDir) {
|
|
32811
|
+
const eventsPath = path21.join(resolveSessionsDir({ baseDir }), sessionId2, "events.jsonl");
|
|
32812
|
+
const report = await readSessionLog(eventsPath).catch(() => null);
|
|
32813
|
+
if (!report || report.events.length === 0) return false;
|
|
32814
|
+
budget.adoptLedgerFromEvents(report.events);
|
|
32815
|
+
return true;
|
|
32816
|
+
}
|
|
32817
|
+
async function lastHarnessManifestHash(sessionId2, baseDir) {
|
|
32818
|
+
const eventsPath = path21.join(resolveSessionsDir({ baseDir }), sessionId2, "events.jsonl");
|
|
32819
|
+
const report = await readSessionLog(eventsPath).catch(() => null);
|
|
32820
|
+
if (!report) return null;
|
|
32821
|
+
for (let i = report.events.length - 1; i >= 0; i--) {
|
|
32822
|
+
const e = report.events[i];
|
|
32823
|
+
if (e.kind === "session.harness_manifest") {
|
|
32824
|
+
const h = e.data.manifestHash;
|
|
32825
|
+
return typeof h === "string" ? h : null;
|
|
32826
|
+
}
|
|
32827
|
+
}
|
|
32828
|
+
return null;
|
|
32829
|
+
}
|
|
32830
|
+
var init_restoreRuntime = __esm({
|
|
32831
|
+
"src/cli/budget/restoreRuntime.ts"() {
|
|
32832
|
+
"use strict";
|
|
32833
|
+
init_session();
|
|
32834
|
+
}
|
|
32835
|
+
});
|
|
32836
|
+
|
|
32837
|
+
// src/cli/utils/cmdline.ts
|
|
32838
|
+
function quoteCmdArg(arg) {
|
|
32839
|
+
if (arg === "") return '""';
|
|
32840
|
+
if (!/[\s"^&|<>()%!]/.test(arg)) return arg;
|
|
32841
|
+
return `"${arg.replace(/"/g, '""')}"`;
|
|
32842
|
+
}
|
|
32843
|
+
function buildCmdLine(command, args) {
|
|
32844
|
+
return [command, ...args].map(quoteCmdArg).join(" ");
|
|
32845
|
+
}
|
|
32846
|
+
var init_cmdline = __esm({
|
|
32847
|
+
"src/cli/utils/cmdline.ts"() {
|
|
32848
|
+
"use strict";
|
|
32849
|
+
}
|
|
32850
|
+
});
|
|
32851
|
+
|
|
32852
|
+
// src/cli/updater.ts
|
|
32853
|
+
var updater_exports = {};
|
|
32854
|
+
__export(updater_exports, {
|
|
32855
|
+
REGISTRY_URL: () => REGISTRY_URL,
|
|
32856
|
+
checkForUpdate: () => checkForUpdate,
|
|
32857
|
+
compareSemver: () => compareSemver,
|
|
32858
|
+
distTagForVersion: () => distTagForVersion,
|
|
32859
|
+
fetchLatestVersion: () => fetchLatestVersion,
|
|
32860
|
+
getCurrentVersion: () => getCurrentVersion,
|
|
32861
|
+
looksLikeBrokenShim: () => looksLikeBrokenShim,
|
|
32862
|
+
performUpdate: () => performUpdate,
|
|
32863
|
+
registryUrlForTag: () => registryUrlForTag,
|
|
32864
|
+
resolveBundledNpmCli: () => resolveBundledNpmCli
|
|
32865
|
+
});
|
|
32866
|
+
import { createRequire } from "node:module";
|
|
32867
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
32868
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
32869
|
+
import path22 from "node:path";
|
|
32870
|
+
import { fileURLToPath } from "node:url";
|
|
32871
|
+
function resolveBundledNpmCli(execPath = process.execPath) {
|
|
32872
|
+
const dir = path22.dirname(execPath);
|
|
32873
|
+
const candidates = [
|
|
32874
|
+
// Windows: C:\...\node.exe → C:\...\node_modules\npm\bin\npm-cli.js
|
|
32875
|
+
path22.join(dir, "node_modules", "npm", "bin", "npm-cli.js"),
|
|
32876
|
+
// POSIX: <prefix>/bin/node → <prefix>/lib/node_modules/npm/bin/npm-cli.js
|
|
32877
|
+
path22.join(dir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
|
|
32878
|
+
];
|
|
32879
|
+
for (const candidate of candidates) {
|
|
32880
|
+
try {
|
|
32881
|
+
if (existsSync11(candidate)) return candidate;
|
|
32882
|
+
} catch {
|
|
32883
|
+
}
|
|
32884
|
+
}
|
|
32885
|
+
return null;
|
|
32886
|
+
}
|
|
32887
|
+
function looksLikeBrokenShim(exitCode, output) {
|
|
32888
|
+
if (exitCode === 127) return true;
|
|
32889
|
+
const h = output.toLowerCase();
|
|
32890
|
+
return h.includes("shim target not found") || h.includes("is not recognized");
|
|
32891
|
+
}
|
|
32892
|
+
function getCurrentVersion() {
|
|
32893
|
+
try {
|
|
32894
|
+
const pkgPath = path22.resolve(__dirname2, "..", "..", "package.json");
|
|
32895
|
+
const pkg = require2(pkgPath);
|
|
32896
|
+
return pkg.version;
|
|
32897
|
+
} catch {
|
|
32898
|
+
return "0.0.0";
|
|
32899
|
+
}
|
|
32900
|
+
}
|
|
32901
|
+
function compareSemver(a, b) {
|
|
32902
|
+
const parse3 = (v) => {
|
|
32903
|
+
const m = v.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
|
|
32904
|
+
if (!m) return [0, 0, 0, null];
|
|
32905
|
+
return [Number(m[1]), Number(m[2]), Number(m[3]), m[4] ?? null];
|
|
32906
|
+
};
|
|
32907
|
+
const [a1, a2, a3, aPre] = parse3(a);
|
|
32908
|
+
const [b1, b2, b3, bPre] = parse3(b);
|
|
32909
|
+
if (a1 !== b1) return a1 < b1 ? -1 : 1;
|
|
32910
|
+
if (a2 !== b2) return a2 < b2 ? -1 : 1;
|
|
32911
|
+
if (a3 !== b3) return a3 < b3 ? -1 : 1;
|
|
32912
|
+
if (aPre === bPre) return 0;
|
|
32913
|
+
if (aPre === null) return 1;
|
|
32914
|
+
if (bPre === null) return -1;
|
|
32915
|
+
return aPre < bPre ? -1 : 1;
|
|
32916
|
+
}
|
|
32917
|
+
function distTagForVersion(version2) {
|
|
32918
|
+
if (version2.includes("-alpha.")) return "alpha";
|
|
32919
|
+
if (version2.includes("-beta.")) return "beta";
|
|
32920
|
+
if (version2.includes("-next.")) return "next";
|
|
32921
|
+
return "latest";
|
|
32922
|
+
}
|
|
32923
|
+
function registryUrlForTag(tag = distTagForVersion(getCurrentVersion())) {
|
|
32924
|
+
return `https://registry.npmjs.org/zelari-code/${tag}`;
|
|
32925
|
+
}
|
|
32926
|
+
async function fetchLatestVersion(fetcher = fetch, registryUrl = REGISTRY_URL, timeoutMs2 = 5e3) {
|
|
32927
|
+
try {
|
|
32928
|
+
const controller = new AbortController();
|
|
32929
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs2);
|
|
32930
|
+
const response = await fetcher(registryUrl, { signal: controller.signal });
|
|
32931
|
+
clearTimeout(timer);
|
|
32932
|
+
if (!response.ok) {
|
|
32933
|
+
return { error: `Registry responded ${response.status}` };
|
|
32934
|
+
}
|
|
32935
|
+
const data = await response.json();
|
|
32936
|
+
if (!data.version || typeof data.version !== "string") {
|
|
32937
|
+
return { error: "Registry response missing version field" };
|
|
32938
|
+
}
|
|
32939
|
+
return { version: data.version };
|
|
32940
|
+
} catch (err) {
|
|
32941
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
32942
|
+
return { error: message };
|
|
32943
|
+
}
|
|
32944
|
+
}
|
|
32945
|
+
async function checkForUpdate(fetcher = fetch, registryUrl) {
|
|
32946
|
+
const currentVersion = getCurrentVersion();
|
|
32947
|
+
const url2 = registryUrl ?? registryUrlForTag();
|
|
32948
|
+
const latest = await fetchLatestVersion(fetcher, url2);
|
|
32949
|
+
if ("error" in latest) {
|
|
32950
|
+
return {
|
|
32951
|
+
currentVersion,
|
|
32952
|
+
latestVersion: currentVersion,
|
|
32953
|
+
updateAvailable: false,
|
|
32954
|
+
error: latest.error
|
|
32955
|
+
};
|
|
32956
|
+
}
|
|
32957
|
+
const cmp = compareSemver(currentVersion, latest.version);
|
|
32958
|
+
return {
|
|
32959
|
+
currentVersion,
|
|
32960
|
+
latestVersion: latest.version,
|
|
32961
|
+
updateAvailable: cmp < 0
|
|
32962
|
+
};
|
|
32963
|
+
}
|
|
32964
|
+
async function performUpdate(packageName = "zelari-code", executor = spawn5, resolveNpmCli = resolveBundledNpmCli, channel) {
|
|
32965
|
+
const tag = channel ?? distTagForVersion(getCurrentVersion());
|
|
32966
|
+
const args = ["install", "-g", `${packageName}@${tag}`];
|
|
32967
|
+
const primary = await runNpm(executor, args, "shim");
|
|
32968
|
+
if (primary.ok) return primary;
|
|
32969
|
+
const npmCli = resolveNpmCli();
|
|
32970
|
+
if (npmCli && looksLikeBrokenShim(primary.exitCode, primary.output)) {
|
|
32971
|
+
const fallback = await runNpm(executor, args, "bundled", npmCli);
|
|
32972
|
+
return {
|
|
32973
|
+
...fallback,
|
|
32974
|
+
output: `[update] npm shim failed (${primary.error ?? "exit " + primary.exitCode}); retried via bundled npm (${npmCli}).
|
|
32975
|
+
${fallback.output}`
|
|
32976
|
+
};
|
|
32977
|
+
}
|
|
32978
|
+
return primary;
|
|
32979
|
+
}
|
|
32980
|
+
function runNpm(executor, args, mode, npmCliPath) {
|
|
32981
|
+
return new Promise((resolve3) => {
|
|
32982
|
+
let stdout = "";
|
|
32983
|
+
let stderr = "";
|
|
32984
|
+
const stdio = ["ignore", "pipe", "pipe"];
|
|
32985
|
+
const child = mode === "bundled" && npmCliPath ? executor(process.execPath, [npmCliPath, ...args], { stdio }) : process.platform === "win32" ? executor(buildCmdLine("npm", args), { stdio, shell: true }) : executor("npm", args, { stdio });
|
|
32986
|
+
child.stdout?.on("data", (chunk) => {
|
|
32987
|
+
stdout += chunk.toString();
|
|
32988
|
+
});
|
|
32989
|
+
child.stderr?.on("data", (chunk) => {
|
|
32990
|
+
stderr += chunk.toString();
|
|
32991
|
+
});
|
|
32992
|
+
child.on("error", (err) => {
|
|
32993
|
+
resolve3({
|
|
32994
|
+
ok: false,
|
|
32995
|
+
output: stdout + stderr,
|
|
32996
|
+
error: err.message,
|
|
32997
|
+
exitCode: null
|
|
32998
|
+
});
|
|
32999
|
+
});
|
|
33000
|
+
child.on("close", (code) => {
|
|
33001
|
+
const ok = code === 0;
|
|
33002
|
+
resolve3({
|
|
33003
|
+
ok,
|
|
33004
|
+
output: stdout + stderr,
|
|
33005
|
+
error: ok ? void 0 : `npm exited with code ${code}`,
|
|
33006
|
+
exitCode: code
|
|
33007
|
+
});
|
|
33008
|
+
});
|
|
33009
|
+
});
|
|
33010
|
+
}
|
|
33011
|
+
var require2, __dirname2, REGISTRY_URL;
|
|
33012
|
+
var init_updater = __esm({
|
|
33013
|
+
"src/cli/updater.ts"() {
|
|
33014
|
+
"use strict";
|
|
33015
|
+
init_cmdline();
|
|
33016
|
+
require2 = createRequire(import.meta.url);
|
|
33017
|
+
__dirname2 = path22.dirname(fileURLToPath(import.meta.url));
|
|
33018
|
+
REGISTRY_URL = "https://registry.npmjs.org/zelari-code/latest";
|
|
33019
|
+
}
|
|
33020
|
+
});
|
|
33021
|
+
|
|
33022
|
+
// src/cli/harnessManifest.ts
|
|
33023
|
+
function buildHarnessManifest(parts) {
|
|
33024
|
+
const prompts = {};
|
|
33025
|
+
for (const [role, text] of Object.entries(parts.prompts ?? {})) {
|
|
33026
|
+
if (typeof text === "string" && text.length > 0) {
|
|
33027
|
+
prompts[role] = harnessInputHash(text);
|
|
33028
|
+
}
|
|
33029
|
+
}
|
|
33030
|
+
const manifest = HarnessManifestV1Schema.parse({
|
|
33031
|
+
schemaVersion: 1,
|
|
33032
|
+
profile: {
|
|
33033
|
+
id: parts.profile.id,
|
|
33034
|
+
phase: parts.phase,
|
|
33035
|
+
hash: profileHash(parts.profile)
|
|
33036
|
+
},
|
|
33037
|
+
prompts,
|
|
33038
|
+
capabilities: {
|
|
33039
|
+
// 2.6.1 (plan §7): full fingerprints when specs are available.
|
|
33040
|
+
toolManifestHash: parts.toolSpecs ? toolFingerprintHash(parts.toolSpecs) : toolManifestHash(parts.toolNames),
|
|
33041
|
+
skillManifestHash: parts.skillSpecs ? skillFingerprintHash(parts.skillSpecs) : harnessInputHash([...parts.skillIds ?? []].sort())
|
|
33042
|
+
},
|
|
33043
|
+
policies: {
|
|
33044
|
+
routingHash: harnessInputHash(parts.routing ?? { unset: true }),
|
|
33045
|
+
verificationHash: harnessInputHash(parts.verification ?? { engine: "deterministic" }),
|
|
33046
|
+
completionPolicyHash: harnessInputHash(parts.completionPolicy ?? { mode: "strict", required: "*" }),
|
|
33047
|
+
compactionHash: harnessInputHash(parts.compaction ?? { version: 1 }),
|
|
33048
|
+
resourcePolicyHash: harnessInputHash(parts.resourcePolicy ?? { unset: true })
|
|
33049
|
+
},
|
|
33050
|
+
runtime: {
|
|
33051
|
+
// 2.6.1 (plan §7): canonical export — no more require.resolve.
|
|
33052
|
+
coreVersion: parts.coreVersion ?? CORE_VERSION,
|
|
33053
|
+
cliVersion: parts.cliVersion ?? getCurrentVersion()
|
|
33054
|
+
}
|
|
33055
|
+
});
|
|
33056
|
+
return { manifest, manifestHash: hashHarnessManifest(manifest) };
|
|
33057
|
+
}
|
|
33058
|
+
var init_harnessManifest2 = __esm({
|
|
33059
|
+
"src/cli/harnessManifest.ts"() {
|
|
33060
|
+
"use strict";
|
|
33061
|
+
init_dist();
|
|
33062
|
+
init_dist();
|
|
33063
|
+
init_updater();
|
|
33064
|
+
}
|
|
33065
|
+
});
|
|
33066
|
+
|
|
33067
|
+
// src/cli/kraken/taskContract.ts
|
|
33068
|
+
function latestTaskContract(events) {
|
|
33069
|
+
let latest;
|
|
33070
|
+
for (const e of events) {
|
|
33071
|
+
if (e.kind !== "task.contract" && e.kind !== "task.contract_updated") continue;
|
|
33072
|
+
const raw = e.data.contract;
|
|
33073
|
+
if (raw && typeof raw === "object") {
|
|
33074
|
+
const candidate = raw;
|
|
33075
|
+
if (!latest || candidate.version > latest.version) latest = candidate;
|
|
33076
|
+
}
|
|
33077
|
+
}
|
|
33078
|
+
return latest;
|
|
33079
|
+
}
|
|
33080
|
+
function updateTaskContract(contract, update) {
|
|
33081
|
+
return applyTaskContractUpdate(contract, update);
|
|
33082
|
+
}
|
|
33083
|
+
function contractEventData(contract, updated) {
|
|
33084
|
+
return { contract, kind: updated ? "task.contract_updated" : "task.contract" };
|
|
33085
|
+
}
|
|
33086
|
+
var init_taskContract2 = __esm({
|
|
33087
|
+
"src/cli/kraken/taskContract.ts"() {
|
|
33088
|
+
"use strict";
|
|
33089
|
+
init_dist();
|
|
33090
|
+
}
|
|
33091
|
+
});
|
|
33092
|
+
|
|
33093
|
+
// src/cli/sessionSpine.ts
|
|
33094
|
+
import path23 from "node:path";
|
|
32493
33095
|
function spineEnabled() {
|
|
32494
33096
|
return process.env.ZELARI_SESSION_SPINE !== "0";
|
|
32495
33097
|
}
|
|
@@ -32571,14 +33173,54 @@ async function wrapSessionWriter(inner, sessionId2, options = {}) {
|
|
|
32571
33173
|
const spine = await SessionSpineMirror.adopt(sessionId2, options);
|
|
32572
33174
|
if (spine.status === "active") {
|
|
32573
33175
|
const profile = options.extraStarted?.profile;
|
|
32574
|
-
|
|
32575
|
-
|
|
32576
|
-
|
|
32577
|
-
|
|
33176
|
+
const budget = new BudgetRuntime(typeof profile === "string" ? profile : "kraken/v1", {
|
|
33177
|
+
enforcement: resolveResourceEnforcement()
|
|
33178
|
+
});
|
|
33179
|
+
if (spine.resumedFromSeq !== void 0 && spine.resumedFromSeq > 0) {
|
|
33180
|
+
await restoreBudgetRuntimeFromSession(budget, sessionId2, options.baseDir);
|
|
33181
|
+
}
|
|
33182
|
+
spine.attachBudgetRuntime(budget);
|
|
33183
|
+
await noteHarnessLifecycle(
|
|
33184
|
+
spine,
|
|
33185
|
+
sessionId2,
|
|
33186
|
+
typeof profile === "string" ? profile : "kraken/v1",
|
|
33187
|
+
budget,
|
|
33188
|
+
options.baseDir,
|
|
33189
|
+
options.extraStarted?.phase
|
|
32578
33190
|
);
|
|
32579
33191
|
}
|
|
32580
33192
|
return new SpineMirroringWriter(inner, spine.status === "active" ? spine : null);
|
|
32581
33193
|
}
|
|
33194
|
+
function taskContractsEnabled() {
|
|
33195
|
+
return process.env.ZELARI_TASK_CONTRACT !== "0";
|
|
33196
|
+
}
|
|
33197
|
+
async function noteHarnessLifecycle(spine, sessionId2, profileId, budget, baseDir, phaseHint) {
|
|
33198
|
+
try {
|
|
33199
|
+
const profile = resolveProfile(profileId);
|
|
33200
|
+
const { manifest, manifestHash } = buildHarnessManifest({
|
|
33201
|
+
profile,
|
|
33202
|
+
phase: phaseHint === "plan" ? "plan" : "build",
|
|
33203
|
+
toolNames: profile.tools,
|
|
33204
|
+
// plan §7/§8: the REAL session policy — never the {unset:true} marker.
|
|
33205
|
+
resourcePolicy: budget.policy
|
|
33206
|
+
});
|
|
33207
|
+
if (spine.resumedFromSeq !== void 0 && spine.resumedFromSeq > 0) {
|
|
33208
|
+
const original = await lastHarnessManifestHash(sessionId2, baseDir);
|
|
33209
|
+
if (original === null) {
|
|
33210
|
+
spine.harnessManifest(manifest, manifestHash);
|
|
33211
|
+
} else if (original !== manifestHash) {
|
|
33212
|
+
await spine.appendEvent({
|
|
33213
|
+
kind: "session.harness_drift",
|
|
33214
|
+
actor: ACTOR_SYSTEM,
|
|
33215
|
+
data: { originalManifestHash: original, currentManifestHash: manifestHash }
|
|
33216
|
+
});
|
|
33217
|
+
}
|
|
33218
|
+
} else {
|
|
33219
|
+
spine.harnessManifest(manifest, manifestHash);
|
|
33220
|
+
}
|
|
33221
|
+
} catch {
|
|
33222
|
+
}
|
|
33223
|
+
}
|
|
32582
33224
|
var MAX_STREAM_BUFFERS, SessionSpineMirror, SpineMirroringWriter;
|
|
32583
33225
|
var init_sessionSpine = __esm({
|
|
32584
33226
|
"src/cli/sessionSpine.ts"() {
|
|
@@ -32587,6 +33229,10 @@ var init_sessionSpine = __esm({
|
|
|
32587
33229
|
init_session();
|
|
32588
33230
|
init_verification2();
|
|
32589
33231
|
init_budgetRuntime();
|
|
33232
|
+
init_restoreRuntime();
|
|
33233
|
+
init_runtime2();
|
|
33234
|
+
init_harnessManifest2();
|
|
33235
|
+
init_taskContract2();
|
|
32590
33236
|
MAX_STREAM_BUFFERS = 32;
|
|
32591
33237
|
SessionSpineMirror = class _SessionSpineMirror {
|
|
32592
33238
|
constructor(sessionId2, options) {
|
|
@@ -32600,6 +33246,8 @@ var init_sessionSpine = __esm({
|
|
|
32600
33246
|
warned = false;
|
|
32601
33247
|
/** Host-owned budget runtime (attached via attachBudgetRuntime). */
|
|
32602
33248
|
budgetRuntime = null;
|
|
33249
|
+
/** True after the host prepared an epoch but before its user.message lands. */
|
|
33250
|
+
resourceTurnPrepared = false;
|
|
32603
33251
|
/** 2.6 Track A: set once a task.contract has been seeded (or the log had one). */
|
|
32604
33252
|
contractSeeded = false;
|
|
32605
33253
|
status = "disabled";
|
|
@@ -32615,8 +33263,8 @@ var init_sessionSpine = __esm({
|
|
|
32615
33263
|
const mirror = new _SessionSpineMirror(sessionId2, options);
|
|
32616
33264
|
if (!spineEnabled()) return mirror;
|
|
32617
33265
|
try {
|
|
32618
|
-
const sessionDir =
|
|
32619
|
-
const report = await readSessionLog(
|
|
33266
|
+
const sessionDir = path23.join(mirror.sessionsDir, sessionId2);
|
|
33267
|
+
const report = await readSessionLog(path23.join(sessionDir, "events.jsonl"));
|
|
32620
33268
|
const existed = report.events.length > 0 || report.issues.length > 0;
|
|
32621
33269
|
if (report.events.some((e) => e.kind === "task.contract" || e.kind === "user.message")) {
|
|
32622
33270
|
mirror.contractSeeded = true;
|
|
@@ -32660,8 +33308,16 @@ var init_sessionSpine = __esm({
|
|
|
32660
33308
|
return mirror;
|
|
32661
33309
|
}
|
|
32662
33310
|
/** Log the user prompt — the P1 gap the 1.x log never closed. */
|
|
32663
|
-
userMessage(text) {
|
|
32664
|
-
|
|
33311
|
+
userMessage(text, options = {}) {
|
|
33312
|
+
if (options.beginResourceTurn !== false) {
|
|
33313
|
+
void this.beginResourceTurn();
|
|
33314
|
+
this.resourceTurnPrepared = false;
|
|
33315
|
+
}
|
|
33316
|
+
const seqP = this.append({
|
|
33317
|
+
kind: "user.message",
|
|
33318
|
+
actor: ACTOR_USER,
|
|
33319
|
+
data: { text, ...options.imported ? { imported: options.imported } : {} }
|
|
33320
|
+
});
|
|
32665
33321
|
void seqP;
|
|
32666
33322
|
}
|
|
32667
33323
|
/**
|
|
@@ -32697,24 +33353,77 @@ var init_sessionSpine = __esm({
|
|
|
32697
33353
|
*/
|
|
32698
33354
|
attachBudgetRuntime(runtime) {
|
|
32699
33355
|
this.budgetRuntime = runtime;
|
|
33356
|
+
this.resourceTurnPrepared = false;
|
|
33357
|
+
}
|
|
33358
|
+
/**
|
|
33359
|
+
* Prepare a fresh per-user-turn execution epoch before model context is
|
|
33360
|
+
* derived. The cumulative ResourceLedger is retained; enforcement and the
|
|
33361
|
+
* latest RESOURCE STATUS restart at 0 / policy.maxToolCalls.
|
|
33362
|
+
*/
|
|
33363
|
+
beginResourceTurn() {
|
|
33364
|
+
if (!this.budgetRuntime || this.resourceTurnPrepared) {
|
|
33365
|
+
return this.chain.then(() => void 0);
|
|
33366
|
+
}
|
|
33367
|
+
const snapshot = this.budgetRuntime.beginTurn();
|
|
33368
|
+
this.resourceTurnPrepared = true;
|
|
33369
|
+
void this.append({
|
|
33370
|
+
kind: "resource.epoch_started",
|
|
33371
|
+
actor: ACTOR_SYSTEM,
|
|
33372
|
+
data: {
|
|
33373
|
+
epoch: snapshot.epoch,
|
|
33374
|
+
kind: "turn",
|
|
33375
|
+
sessionToolCallsUsed: snapshot.sessionToolCallsUsed
|
|
33376
|
+
}
|
|
33377
|
+
});
|
|
33378
|
+
return this.append({
|
|
33379
|
+
kind: "resource.snapshot",
|
|
33380
|
+
actor: ACTOR_SYSTEM,
|
|
33381
|
+
data: { ...snapshot }
|
|
33382
|
+
}).then(() => void 0);
|
|
32700
33383
|
}
|
|
32701
33384
|
/** Latest emitted resource snapshot (the model-visible one), or null. */
|
|
32702
33385
|
latestResourceSnapshot() {
|
|
32703
33386
|
return this.budgetRuntime?.latestEmitted() ?? null;
|
|
32704
33387
|
}
|
|
33388
|
+
/**
|
|
33389
|
+
* 2.6.1 (plan §8): session ResourcePolicy cap for hosts that need to derive
|
|
33390
|
+
* per-turn limits — the policy stays the single authority. Null when no
|
|
33391
|
+
* runtime is attached (hosts keep their own default).
|
|
33392
|
+
*/
|
|
33393
|
+
/** Full budget shape for evaluateResourceReserveGate (plan §14). */
|
|
33394
|
+
resourceBudgetSummary() {
|
|
33395
|
+
return this.budgetRuntime?.budgetSnapshot() ?? null;
|
|
33396
|
+
}
|
|
33397
|
+
resourceBudgetLimit() {
|
|
33398
|
+
const snap = this.budgetRuntime?.current();
|
|
33399
|
+
return snap ? {
|
|
33400
|
+
maxToolCalls: snap.toolCallsLimit,
|
|
33401
|
+
remaining: snap.toolCallsRemaining,
|
|
33402
|
+
verificationReserve: snap.verificationReserve
|
|
33403
|
+
} : null;
|
|
33404
|
+
}
|
|
32705
33405
|
/**
|
|
32706
33406
|
* §11.3 pre-dispatch gate for hosts that enforce the protected zone
|
|
32707
33407
|
* (Phase 3): delegates to the attached runtime, never throws. Null when
|
|
32708
33408
|
* no runtime is attached (hosts treat as "no budget info, allow").
|
|
33409
|
+
* 2.6.1 (plan §13): argument-aware — pass the tool args so `bash` is only
|
|
33410
|
+
* essential when it is a test/typecheck/build/git-diff command.
|
|
32709
33411
|
*/
|
|
32710
|
-
gateResourceToolCall(toolName) {
|
|
32711
|
-
const gate = this.budgetRuntime?.gateToolCall(toolName);
|
|
33412
|
+
gateResourceToolCall(toolName, args) {
|
|
33413
|
+
const gate = this.budgetRuntime?.gateToolCall({ toolName, args });
|
|
32712
33414
|
if (!gate) return null;
|
|
32713
|
-
return {
|
|
33415
|
+
return {
|
|
33416
|
+
allowed: gate.allowed,
|
|
33417
|
+
...gate.reason ? { reason: gate.reason } : {},
|
|
33418
|
+
...gate.hardLimit ? { hardLimit: gate.hardLimit } : {}
|
|
33419
|
+
};
|
|
32714
33420
|
}
|
|
32715
|
-
/**
|
|
33421
|
+
/**
|
|
33422
|
+
* Count a landed tool.call; returns the snapshot due (§10.4) plus the
|
|
33423
|
+
* hard-limit event due on this call (2.6.1 plan §9), if any.
|
|
33424
|
+
*/
|
|
32716
33425
|
onToolCallBudget() {
|
|
32717
|
-
return this.budgetRuntime?.
|
|
33426
|
+
return this.budgetRuntime?.consumeToolCall() ?? { snapshot: null, hardEvent: null };
|
|
32718
33427
|
}
|
|
32719
33428
|
async flush() {
|
|
32720
33429
|
await this.chain;
|
|
@@ -32726,7 +33435,7 @@ var init_sessionSpine = __esm({
|
|
|
32726
33435
|
async derivedPriorTurns() {
|
|
32727
33436
|
if (this.status !== "active" && this.status !== "closed") return null;
|
|
32728
33437
|
const report = await readSessionLog(
|
|
32729
|
-
|
|
33438
|
+
path23.join(this.sessionsDir, this.sessionId, "events.jsonl")
|
|
32730
33439
|
).catch(() => null);
|
|
32731
33440
|
if (!report || report.events.length === 0) return null;
|
|
32732
33441
|
return deriveMessages(report.events);
|
|
@@ -32736,7 +33445,7 @@ var init_sessionSpine = __esm({
|
|
|
32736
33445
|
if (this.status !== "active" && this.status !== "closed") return null;
|
|
32737
33446
|
await this.flush();
|
|
32738
33447
|
const report = await readSessionLog(
|
|
32739
|
-
|
|
33448
|
+
path23.join(this.sessionsDir, this.sessionId, "events.jsonl")
|
|
32740
33449
|
).catch(() => null);
|
|
32741
33450
|
if (!report || report.events.length === 0) return null;
|
|
32742
33451
|
return buildCompactionStateSnapshot(report.events, toSeq);
|
|
@@ -32749,7 +33458,7 @@ var init_sessionSpine = __esm({
|
|
|
32749
33458
|
async lastVerificationRun() {
|
|
32750
33459
|
if (this.status !== "active" && this.status !== "closed") return null;
|
|
32751
33460
|
const report = await readSessionLog(
|
|
32752
|
-
|
|
33461
|
+
path23.join(this.sessionsDir, this.sessionId, "events.jsonl")
|
|
32753
33462
|
).catch(() => null);
|
|
32754
33463
|
if (!report) return null;
|
|
32755
33464
|
return lastVerificationRun(report.events);
|
|
@@ -32820,10 +33529,18 @@ var init_sessionSpine = __esm({
|
|
|
32820
33529
|
}
|
|
32821
33530
|
append(input) {
|
|
32822
33531
|
if (!this.writer || this.status === "closed") return Promise.resolve(null);
|
|
32823
|
-
const
|
|
32824
|
-
const dueContract = input.kind === "user.message" &&
|
|
33532
|
+
const budgetEffect = input.kind === "tool.call" ? this.onToolCallBudget() : null;
|
|
33533
|
+
const dueContract = input.kind === "user.message" && taskContractsEnabled() && !this.contractSeeded ? (this.contractSeeded = true, input.data?.text) : null;
|
|
33534
|
+
const steerText = input.kind === "user.message" && taskContractsEnabled() && this.contractSeeded && !dueContract ? input.data?.text ?? null : null;
|
|
32825
33535
|
let seq = this.chain.then(() => this.writer.append(input)).then((envelope) => envelope.seq);
|
|
32826
|
-
if (
|
|
33536
|
+
if (budgetEffect?.hardEvent) {
|
|
33537
|
+
const hard = budgetEffect.hardEvent;
|
|
33538
|
+
seq = seq.then(
|
|
33539
|
+
(s) => this.writer.append({ kind: hard.kind, actor: ACTOR_SYSTEM, data: { ...hard.data } }).then(() => s)
|
|
33540
|
+
);
|
|
33541
|
+
}
|
|
33542
|
+
if (budgetEffect?.snapshot) {
|
|
33543
|
+
const dueSnapshot = budgetEffect.snapshot;
|
|
32827
33544
|
seq = seq.then(
|
|
32828
33545
|
(s) => this.writer.append({ kind: "resource.snapshot", actor: ACTOR_SYSTEM, data: { ...dueSnapshot } }).then(() => s)
|
|
32829
33546
|
);
|
|
@@ -32844,6 +33561,30 @@ var init_sessionSpine = __esm({
|
|
|
32844
33561
|
return s;
|
|
32845
33562
|
});
|
|
32846
33563
|
}
|
|
33564
|
+
if (steerText) {
|
|
33565
|
+
seq = seq.then(async (s) => {
|
|
33566
|
+
try {
|
|
33567
|
+
const eventsPath = path23.join(this.sessionsDir, this.sessionId, "events.jsonl");
|
|
33568
|
+
const report = await readSessionLog(eventsPath).catch(() => null);
|
|
33569
|
+
if (!report || typeof s !== "number") return s;
|
|
33570
|
+
const current = latestTaskContract(report.events);
|
|
33571
|
+
if (!current) return s;
|
|
33572
|
+
const updated = updateTaskContract(current, {
|
|
33573
|
+
addConstraints: [{ id: `steer-${s}`, text: steerText, source: "user", required: false }],
|
|
33574
|
+
nextUserSeq: s
|
|
33575
|
+
});
|
|
33576
|
+
if (updated.version !== current.version) {
|
|
33577
|
+
await this.writer.append({
|
|
33578
|
+
kind: "task.contract_updated",
|
|
33579
|
+
actor: ACTOR_SYSTEM,
|
|
33580
|
+
data: contractEventData(updated, true)
|
|
33581
|
+
});
|
|
33582
|
+
}
|
|
33583
|
+
} catch {
|
|
33584
|
+
}
|
|
33585
|
+
return s;
|
|
33586
|
+
});
|
|
33587
|
+
}
|
|
32847
33588
|
this.chain = seq.catch((err) => {
|
|
32848
33589
|
this.status = "degraded";
|
|
32849
33590
|
this.writer = null;
|
|
@@ -33070,10 +33811,10 @@ var init_sessionSurface = __esm({
|
|
|
33070
33811
|
});
|
|
33071
33812
|
|
|
33072
33813
|
// src/cli/hooks/observationStore.ts
|
|
33073
|
-
import { existsSync as
|
|
33074
|
-
import
|
|
33814
|
+
import { existsSync as existsSync12, statSync as statSync2 } from "node:fs";
|
|
33815
|
+
import path24 from "node:path";
|
|
33075
33816
|
function sessionFilePath(sessionId2, baseDir) {
|
|
33076
|
-
return
|
|
33817
|
+
return path24.join(baseDir ?? getSessionBaseDir(), `${sessionId2}.jsonl`);
|
|
33077
33818
|
}
|
|
33078
33819
|
function isToolEnd(e) {
|
|
33079
33820
|
return e.type === "tool_execution_end";
|
|
@@ -33083,7 +33824,7 @@ function isToolStart(e) {
|
|
|
33083
33824
|
}
|
|
33084
33825
|
async function loadObservationIndex(sessionId2, baseDir) {
|
|
33085
33826
|
const filePath = sessionFilePath(sessionId2, baseDir);
|
|
33086
|
-
const exists =
|
|
33827
|
+
const exists = existsSync12(filePath);
|
|
33087
33828
|
let mtimeMs = 0;
|
|
33088
33829
|
if (exists) {
|
|
33089
33830
|
try {
|
|
@@ -33095,7 +33836,7 @@ async function loadObservationIndex(sessionId2, baseDir) {
|
|
|
33095
33836
|
const hit = cache.get(sessionId2);
|
|
33096
33837
|
if (hit && !exists) return hit;
|
|
33097
33838
|
if (hit && hit.filePath === filePath && hit.mtimeMs === mtimeMs) return hit;
|
|
33098
|
-
const events =
|
|
33839
|
+
const events = existsSync12(filePath) ? await readSession(filePath) : [];
|
|
33099
33840
|
const names = /* @__PURE__ */ new Map();
|
|
33100
33841
|
const bySeq = /* @__PURE__ */ new Map();
|
|
33101
33842
|
const byToolCallId = /* @__PURE__ */ new Map();
|
|
@@ -33192,8 +33933,8 @@ var init_observationStore = __esm({
|
|
|
33192
33933
|
});
|
|
33193
33934
|
|
|
33194
33935
|
// src/cli/metrics.ts
|
|
33195
|
-
import { promises as fs14, existsSync as
|
|
33196
|
-
import
|
|
33936
|
+
import { promises as fs14, existsSync as existsSync13, statSync as statSync3, renameSync, appendFileSync as appendFileSync2, mkdirSync as mkdirSync6 } from "node:fs";
|
|
33937
|
+
import path25 from "node:path";
|
|
33197
33938
|
import os6 from "node:os";
|
|
33198
33939
|
async function readMetrics(file2) {
|
|
33199
33940
|
let raw = "";
|
|
@@ -33242,8 +33983,8 @@ var init_metrics2 = __esm({
|
|
|
33242
33983
|
file;
|
|
33243
33984
|
writeQueue = Promise.resolve();
|
|
33244
33985
|
constructor(file2) {
|
|
33245
|
-
this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ??
|
|
33246
|
-
mkdirSync6(
|
|
33986
|
+
this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ?? path25.join(os6.homedir(), ".tmp", "zelari-code", "metrics.jsonl");
|
|
33987
|
+
mkdirSync6(path25.dirname(this.file), { recursive: true });
|
|
33247
33988
|
}
|
|
33248
33989
|
/** Metrics file path — doctor/summary readers use this. */
|
|
33249
33990
|
get filePath() {
|
|
@@ -33278,7 +34019,7 @@ var init_metrics2 = __esm({
|
|
|
33278
34019
|
}
|
|
33279
34020
|
/** If the file is over the rotation threshold, rotate it. */
|
|
33280
34021
|
maybeRotate() {
|
|
33281
|
-
if (!
|
|
34022
|
+
if (!existsSync13(this.file)) return;
|
|
33282
34023
|
try {
|
|
33283
34024
|
const stat = statSync3(this.file);
|
|
33284
34025
|
if (stat.size >= METRICS_ROTATE_BYTES) {
|
|
@@ -34459,8 +35200,8 @@ var init_resolveStream = __esm({
|
|
|
34459
35200
|
});
|
|
34460
35201
|
|
|
34461
35202
|
// packages/core/dist/core/tools/toolOutputSpill.js
|
|
34462
|
-
import { createHash as
|
|
34463
|
-
import { existsSync as
|
|
35203
|
+
import { createHash as createHash7, randomBytes as randomBytes2 } from "node:crypto";
|
|
35204
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7, writeFileSync as writeFileSync11 } from "node:fs";
|
|
34464
35205
|
import { homedir as homedir3, tmpdir } from "node:os";
|
|
34465
35206
|
import { join as join11 } from "node:path";
|
|
34466
35207
|
function resolveToolOutputDir() {
|
|
@@ -34486,10 +35227,10 @@ function spillToolOutput(fullText, meta3) {
|
|
|
34486
35227
|
return null;
|
|
34487
35228
|
try {
|
|
34488
35229
|
const dir = resolveToolOutputDir();
|
|
34489
|
-
if (!
|
|
35230
|
+
if (!existsSync14(dir)) {
|
|
34490
35231
|
mkdirSync7(dir, { recursive: true });
|
|
34491
35232
|
}
|
|
34492
|
-
const hash3 =
|
|
35233
|
+
const hash3 = createHash7("sha256").update(fullText).digest("hex").slice(0, 12);
|
|
34493
35234
|
const stamp = Date.now().toString(36);
|
|
34494
35235
|
const rnd = randomBytes2(3).toString("hex");
|
|
34495
35236
|
const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
|
|
@@ -34753,14 +35494,14 @@ var init_registry2 = __esm({
|
|
|
34753
35494
|
});
|
|
34754
35495
|
|
|
34755
35496
|
// src/cli/safety/sandboxPath.ts
|
|
34756
|
-
import
|
|
35497
|
+
import path26 from "node:path";
|
|
34757
35498
|
function resolveSandboxedPath(userPath, options = {}) {
|
|
34758
35499
|
if (typeof userPath !== "string" || userPath.length === 0) {
|
|
34759
35500
|
throw new SandboxViolationError("Empty path", userPath, "");
|
|
34760
35501
|
}
|
|
34761
|
-
const root =
|
|
34762
|
-
const resolved =
|
|
34763
|
-
const rootWithSep = root.endsWith(
|
|
35502
|
+
const root = path26.resolve(options.root ?? process.cwd());
|
|
35503
|
+
const resolved = path26.isAbsolute(userPath) ? path26.resolve(userPath) : path26.resolve(root, userPath);
|
|
35504
|
+
const rootWithSep = root.endsWith(path26.sep) ? root : root + path26.sep;
|
|
34764
35505
|
if (resolved !== root && !resolved.startsWith(rootWithSep)) {
|
|
34765
35506
|
throw new SandboxViolationError(
|
|
34766
35507
|
`Path escapes sandbox root: ${userPath} \u2192 ${resolved} (root: ${root})`,
|
|
@@ -34848,12 +35589,12 @@ __export(auditLogger_exports, {
|
|
|
34848
35589
|
AuditLogger: () => AuditLogger
|
|
34849
35590
|
});
|
|
34850
35591
|
import { promises as fs15 } from "node:fs";
|
|
34851
|
-
import
|
|
35592
|
+
import path27 from "node:path";
|
|
34852
35593
|
import os7 from "node:os";
|
|
34853
35594
|
function defaultAuditPath() {
|
|
34854
35595
|
const override = process.env.ANATHEMA_AUDIT_LOG;
|
|
34855
35596
|
if (override && override.trim().length > 0) return override;
|
|
34856
|
-
return
|
|
35597
|
+
return path27.join(os7.tmpdir(), "zelari-code", "audit.jsonl");
|
|
34857
35598
|
}
|
|
34858
35599
|
function redactArgs(args) {
|
|
34859
35600
|
const redacted = {};
|
|
@@ -34896,7 +35637,7 @@ var init_auditLogger = __esm({
|
|
|
34896
35637
|
async append(entry) {
|
|
34897
35638
|
const line = JSON.stringify(entry) + "\n";
|
|
34898
35639
|
this.writeQueue = this.writeQueue.then(async () => {
|
|
34899
|
-
await fs15.mkdir(
|
|
35640
|
+
await fs15.mkdir(path27.dirname(this.logPath), { recursive: true });
|
|
34900
35641
|
await fs15.appendFile(this.logPath, line, "utf-8");
|
|
34901
35642
|
});
|
|
34902
35643
|
return this.writeQueue;
|
|
@@ -34940,25 +35681,10 @@ var init_auditLogger = __esm({
|
|
|
34940
35681
|
}
|
|
34941
35682
|
});
|
|
34942
35683
|
|
|
34943
|
-
// src/cli/utils/cmdline.ts
|
|
34944
|
-
function quoteCmdArg(arg) {
|
|
34945
|
-
if (arg === "") return '""';
|
|
34946
|
-
if (!/[\s"^&|<>()%!]/.test(arg)) return arg;
|
|
34947
|
-
return `"${arg.replace(/"/g, '""')}"`;
|
|
34948
|
-
}
|
|
34949
|
-
function buildCmdLine(command, args) {
|
|
34950
|
-
return [command, ...args].map(quoteCmdArg).join(" ");
|
|
34951
|
-
}
|
|
34952
|
-
var init_cmdline = __esm({
|
|
34953
|
-
"src/cli/utils/cmdline.ts"() {
|
|
34954
|
-
"use strict";
|
|
34955
|
-
}
|
|
34956
|
-
});
|
|
34957
|
-
|
|
34958
35684
|
// src/cli/diagnostics/engine.ts
|
|
34959
|
-
import { spawn as
|
|
34960
|
-
import { existsSync as
|
|
34961
|
-
import
|
|
35685
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
35686
|
+
import { existsSync as existsSync15 } from "node:fs";
|
|
35687
|
+
import path28 from "node:path";
|
|
34962
35688
|
function parseEslintJson(stdout, _file2) {
|
|
34963
35689
|
const json2 = safeJson(stdout);
|
|
34964
35690
|
if (!Array.isArray(json2)) return [];
|
|
@@ -35017,7 +35743,7 @@ function safeJson(s) {
|
|
|
35017
35743
|
}
|
|
35018
35744
|
}
|
|
35019
35745
|
function providerForFile(file2, providers = DEFAULT_PROVIDERS) {
|
|
35020
|
-
const ext =
|
|
35746
|
+
const ext = path28.extname(file2).toLowerCase();
|
|
35021
35747
|
return providers.find((p3) => p3.extensions.includes(ext)) ?? null;
|
|
35022
35748
|
}
|
|
35023
35749
|
function resolveBin(bin, cwd) {
|
|
@@ -35025,10 +35751,10 @@ function resolveBin(bin, cwd) {
|
|
|
35025
35751
|
let dir = cwd;
|
|
35026
35752
|
for (let i = 0; i < 6; i += 1) {
|
|
35027
35753
|
for (const suffix of suffixes) {
|
|
35028
|
-
const candidate =
|
|
35029
|
-
if (
|
|
35754
|
+
const candidate = path28.join(dir, "node_modules", ".bin", `${bin}${suffix}`);
|
|
35755
|
+
if (existsSync15(candidate)) return candidate;
|
|
35030
35756
|
}
|
|
35031
|
-
const parent =
|
|
35757
|
+
const parent = path28.dirname(dir);
|
|
35032
35758
|
if (parent === dir) break;
|
|
35033
35759
|
dir = parent;
|
|
35034
35760
|
}
|
|
@@ -35101,7 +35827,7 @@ var init_engine2 = __esm({
|
|
|
35101
35827
|
};
|
|
35102
35828
|
let child;
|
|
35103
35829
|
try {
|
|
35104
|
-
child = process.platform === "win32" ?
|
|
35830
|
+
child = process.platform === "win32" ? spawn6(buildCmdLine(cmd, args), { cwd: opts.cwd, shell: true }) : spawn6(cmd, args, { cwd: opts.cwd });
|
|
35105
35831
|
} catch {
|
|
35106
35832
|
done({ code: null, stdout: "", stderr: "" });
|
|
35107
35833
|
return;
|
|
@@ -35132,19 +35858,19 @@ var init_engine2 = __esm({
|
|
|
35132
35858
|
});
|
|
35133
35859
|
|
|
35134
35860
|
// src/cli/tools/krakenRadio.ts
|
|
35135
|
-
import { appendFileSync as appendFileSync3, existsSync as
|
|
35136
|
-
import
|
|
35861
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync14, readdirSync as readdirSync2 } from "node:fs";
|
|
35862
|
+
import path29 from "node:path";
|
|
35137
35863
|
function radioDir(cwd) {
|
|
35138
|
-
return
|
|
35864
|
+
return path29.join(cwd, ".zelari", "radio");
|
|
35139
35865
|
}
|
|
35140
35866
|
function radioPath(cwd, sessionId2) {
|
|
35141
35867
|
const safe = (sessionId2 || "default").replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
35142
|
-
return
|
|
35868
|
+
return path29.join(radioDir(cwd), `${safe}.jsonl`);
|
|
35143
35869
|
}
|
|
35144
35870
|
function appendKrakenRadio(cwd, sessionId2, event) {
|
|
35145
35871
|
try {
|
|
35146
35872
|
const dir = radioDir(cwd);
|
|
35147
|
-
if (!
|
|
35873
|
+
if (!existsSync16(dir)) mkdirSync8(dir, { recursive: true });
|
|
35148
35874
|
const row = {
|
|
35149
35875
|
ts: event.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
35150
35876
|
kind: event.kind,
|
|
@@ -35165,7 +35891,7 @@ function appendKrakenRadio(cwd, sessionId2, event) {
|
|
|
35165
35891
|
function readKrakenRadio(cwd, sessionId2, limit = 50) {
|
|
35166
35892
|
try {
|
|
35167
35893
|
const file2 = radioPath(cwd, sessionId2);
|
|
35168
|
-
if (!
|
|
35894
|
+
if (!existsSync16(file2)) return [];
|
|
35169
35895
|
const lines = readFileSync14(file2, "utf8").split(/\r?\n/).filter(Boolean);
|
|
35170
35896
|
const slice = lines.slice(-Math.max(1, limit));
|
|
35171
35897
|
const out = [];
|
|
@@ -35189,7 +35915,7 @@ function formatKrakenRadioStatus(cwd, sessionId2, limit = 12) {
|
|
|
35189
35915
|
const flag = e.ok === false ? "\u2717" : e.ok === true ? "\u2713" : "\xB7";
|
|
35190
35916
|
const ms = e.durationMs != null ? ` ${e.durationMs}ms` : "";
|
|
35191
35917
|
const model = e.model ? ` [${e.model}]` : "";
|
|
35192
|
-
const wt = e.worktree ? ` wt=${
|
|
35918
|
+
const wt = e.worktree ? ` wt=${path29.basename(e.worktree)}` : "";
|
|
35193
35919
|
const detail = e.detail ? ` \u2014 ${e.detail.slice(0, 120)}` : "";
|
|
35194
35920
|
return `${flag} ${e.ts.slice(11, 19)} ${e.kind} ${e.agent} "${e.description}"${model}${wt}${ms}${detail}`;
|
|
35195
35921
|
});
|
|
@@ -35203,8 +35929,8 @@ var init_krakenRadio = __esm({
|
|
|
35203
35929
|
|
|
35204
35930
|
// src/cli/tools/krakenWorktree.ts
|
|
35205
35931
|
import { execFile as execFile2 } from "node:child_process";
|
|
35206
|
-
import { existsSync as
|
|
35207
|
-
import
|
|
35932
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync9, rmSync } from "node:fs";
|
|
35933
|
+
import path30 from "node:path";
|
|
35208
35934
|
import { promisify } from "node:util";
|
|
35209
35935
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
35210
35936
|
function isKrakenWorktreeEnabled(env = process.env) {
|
|
@@ -35252,10 +35978,10 @@ async function createKrakenWorktree(cwd, label) {
|
|
|
35252
35978
|
const id = `${Date.now().toString(36)}-${randomBytes3(3).toString("hex")}`;
|
|
35253
35979
|
const slug = (label ?? "task").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) || "task";
|
|
35254
35980
|
const branch = `kraken/${slug}-${id}`;
|
|
35255
|
-
const wtRoot =
|
|
35256
|
-
const wtPath =
|
|
35981
|
+
const wtRoot = path30.join(repoRoot, ".zelari", "worktrees");
|
|
35982
|
+
const wtPath = path30.join(wtRoot, `kraken-${id}`);
|
|
35257
35983
|
try {
|
|
35258
|
-
if (!
|
|
35984
|
+
if (!existsSync17(wtRoot)) mkdirSync9(wtRoot, { recursive: true });
|
|
35259
35985
|
} catch {
|
|
35260
35986
|
return null;
|
|
35261
35987
|
}
|
|
@@ -35367,7 +36093,7 @@ async function cleanupKrakenWorktree(handle, env = process.env) {
|
|
|
35367
36093
|
if (shouldKeepWorktree(env)) return;
|
|
35368
36094
|
await git2(handle.repoRoot, ["worktree", "remove", "--force", handle.path]);
|
|
35369
36095
|
try {
|
|
35370
|
-
if (
|
|
36096
|
+
if (existsSync17(handle.path)) {
|
|
35371
36097
|
rmSync(handle.path, { recursive: true, force: true });
|
|
35372
36098
|
}
|
|
35373
36099
|
} catch {
|
|
@@ -36704,7 +37430,7 @@ var init_askUser = __esm({
|
|
|
36704
37430
|
});
|
|
36705
37431
|
|
|
36706
37432
|
// src/cli/skillsMd.ts
|
|
36707
|
-
import { existsSync as
|
|
37433
|
+
import { existsSync as existsSync18, readdirSync as readdirSync3, readFileSync as readFileSync15 } from "node:fs";
|
|
36708
37434
|
import { join as join12 } from "node:path";
|
|
36709
37435
|
import { homedir as homedir4 } from "node:os";
|
|
36710
37436
|
function skillMdSearchDirs(projectRoot = process.cwd()) {
|
|
@@ -36770,7 +37496,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
36770
37496
|
const summary = { loaded: [], skipped: [] };
|
|
36771
37497
|
const seen = new Set(options.existingIds ?? []);
|
|
36772
37498
|
for (const dir of skillMdSearchDirs(projectRoot)) {
|
|
36773
|
-
if (!
|
|
37499
|
+
if (!existsSync18(dir)) continue;
|
|
36774
37500
|
let entries;
|
|
36775
37501
|
try {
|
|
36776
37502
|
entries = readdirSync3(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
@@ -36779,7 +37505,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
36779
37505
|
}
|
|
36780
37506
|
for (const entry of entries) {
|
|
36781
37507
|
const skillPath = join12(dir, entry, "SKILL.md");
|
|
36782
|
-
if (!
|
|
37508
|
+
if (!existsSync18(skillPath)) continue;
|
|
36783
37509
|
try {
|
|
36784
37510
|
const parsed = parseSkillMd(readFileSync15(skillPath, "utf8"), skillPath);
|
|
36785
37511
|
if (!parsed) {
|
|
@@ -36954,14 +37680,14 @@ var init_todoTools = __esm({
|
|
|
36954
37680
|
import {
|
|
36955
37681
|
mkdirSync as mkdirSync10,
|
|
36956
37682
|
writeFileSync as writeFileSync12,
|
|
36957
|
-
existsSync as
|
|
37683
|
+
existsSync as existsSync19,
|
|
36958
37684
|
accessSync,
|
|
36959
37685
|
constants,
|
|
36960
37686
|
realpathSync
|
|
36961
37687
|
} from "node:fs";
|
|
36962
37688
|
import { join as join13, basename } from "node:path";
|
|
36963
37689
|
import { homedir as homedir5 } from "node:os";
|
|
36964
|
-
import { createHash as
|
|
37690
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
36965
37691
|
function resolveWorkspaceRoot(projectRoot = process.cwd()) {
|
|
36966
37692
|
const candidates = [
|
|
36967
37693
|
join13(projectRoot, ".zelari"),
|
|
@@ -36977,11 +37703,11 @@ function resolveWorkspaceRoot(projectRoot = process.cwd()) {
|
|
|
36977
37703
|
return candidates[0];
|
|
36978
37704
|
}
|
|
36979
37705
|
function hashProject(projectPath) {
|
|
36980
|
-
return
|
|
37706
|
+
return createHash8("sha1").update(realpathSync(projectPath)).digest("hex").slice(0, 12);
|
|
36981
37707
|
}
|
|
36982
37708
|
function isWritableDir(dir) {
|
|
36983
37709
|
try {
|
|
36984
|
-
if (!
|
|
37710
|
+
if (!existsSync19(dir)) return false;
|
|
36985
37711
|
accessSync(dir, constants.W_OK);
|
|
36986
37712
|
return true;
|
|
36987
37713
|
} catch {
|
|
@@ -36990,9 +37716,9 @@ function isWritableDir(dir) {
|
|
|
36990
37716
|
}
|
|
36991
37717
|
function ensureWorkspaceDir(workspaceDir) {
|
|
36992
37718
|
mkdirSync10(workspaceDir, { recursive: true });
|
|
36993
|
-
if (workspaceDir.endsWith("/.zelari") &&
|
|
37719
|
+
if (workspaceDir.endsWith("/.zelari") && existsSync19(join13(workspaceDir, "..", ".git"))) {
|
|
36994
37720
|
const gitignorePath = join13(workspaceDir, ".gitignore");
|
|
36995
|
-
if (!
|
|
37721
|
+
if (!existsSync19(gitignorePath)) {
|
|
36996
37722
|
writeFileSync12(gitignorePath, "*\n!.gitignore\n");
|
|
36997
37723
|
}
|
|
36998
37724
|
}
|
|
@@ -37032,7 +37758,7 @@ __export(storage_exports, {
|
|
|
37032
37758
|
import {
|
|
37033
37759
|
readFileSync as readFileSync16,
|
|
37034
37760
|
writeFileSync as writeFileSync13,
|
|
37035
|
-
existsSync as
|
|
37761
|
+
existsSync as existsSync20,
|
|
37036
37762
|
mkdirSync as mkdirSync11,
|
|
37037
37763
|
readdirSync as readdirSync4,
|
|
37038
37764
|
renameSync as renameSync2
|
|
@@ -37292,7 +38018,7 @@ var init_storage = __esm({
|
|
|
37292
38018
|
Storage = class {
|
|
37293
38019
|
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
37294
38020
|
read(path65) {
|
|
37295
|
-
if (!
|
|
38021
|
+
if (!existsSync20(path65)) {
|
|
37296
38022
|
throw new Error(`File not found: ${path65}`);
|
|
37297
38023
|
}
|
|
37298
38024
|
const md = readFileSync16(path65, "utf8");
|
|
@@ -37300,7 +38026,7 @@ var init_storage = __esm({
|
|
|
37300
38026
|
}
|
|
37301
38027
|
/** Read a Markdown file; returns null if not found. */
|
|
37302
38028
|
readIfExists(path65) {
|
|
37303
|
-
if (!
|
|
38029
|
+
if (!existsSync20(path65)) return null;
|
|
37304
38030
|
return this.read(path65);
|
|
37305
38031
|
}
|
|
37306
38032
|
/**
|
|
@@ -37316,7 +38042,7 @@ var init_storage = __esm({
|
|
|
37316
38042
|
}
|
|
37317
38043
|
/** List all .md files in a directory (non-recursive). */
|
|
37318
38044
|
listMarkdown(dir) {
|
|
37319
|
-
if (!
|
|
38045
|
+
if (!existsSync20(dir)) return [];
|
|
37320
38046
|
return readdirSync4(dir).filter((f) => f.endsWith(".md") && !f.startsWith(".")).map((f) => join14(dir, f));
|
|
37321
38047
|
}
|
|
37322
38048
|
};
|
|
@@ -37349,7 +38075,7 @@ var init_storage = __esm({
|
|
|
37349
38075
|
// src/cli/workspace/planStore.ts
|
|
37350
38076
|
import {
|
|
37351
38077
|
copyFileSync,
|
|
37352
|
-
existsSync as
|
|
38078
|
+
existsSync as existsSync21,
|
|
37353
38079
|
mkdirSync as mkdirSync12,
|
|
37354
38080
|
readFileSync as readFileSync17,
|
|
37355
38081
|
renameSync as renameSync3,
|
|
@@ -37400,7 +38126,7 @@ function writePlanTaskArtifact(rootDir, task) {
|
|
|
37400
38126
|
}
|
|
37401
38127
|
function loadHandle(rootDir) {
|
|
37402
38128
|
const jsonPath = join15(rootDir, "plan.json");
|
|
37403
|
-
if (!
|
|
38129
|
+
if (!existsSync21(jsonPath)) {
|
|
37404
38130
|
return { rootDir, tasks: [], counter: 0, rootFields: {} };
|
|
37405
38131
|
}
|
|
37406
38132
|
let parsed;
|
|
@@ -37435,7 +38161,7 @@ function saveHandle(rootDir, handle) {
|
|
|
37435
38161
|
}
|
|
37436
38162
|
const jsonPath = join15(rootDir, "plan.json");
|
|
37437
38163
|
mkdirSync12(rootDir, { recursive: true });
|
|
37438
|
-
if (
|
|
38164
|
+
if (existsSync21(jsonPath)) {
|
|
37439
38165
|
copyFileSync(jsonPath, `${jsonPath}.bak`);
|
|
37440
38166
|
}
|
|
37441
38167
|
const file2 = {
|
|
@@ -37717,8 +38443,8 @@ var init_planTaskTools = __esm({
|
|
|
37717
38443
|
|
|
37718
38444
|
// src/cli/tools/inspectTypecheckSafety.ts
|
|
37719
38445
|
import { promises as fs16 } from "node:fs";
|
|
37720
|
-
import
|
|
37721
|
-
import { spawn as
|
|
38446
|
+
import path31 from "node:path";
|
|
38447
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
37722
38448
|
async function scanTsbuildinfo(root) {
|
|
37723
38449
|
const found = [];
|
|
37724
38450
|
const stack = [root];
|
|
@@ -37731,11 +38457,11 @@ async function scanTsbuildinfo(root) {
|
|
|
37731
38457
|
continue;
|
|
37732
38458
|
}
|
|
37733
38459
|
for (const entry of entries) {
|
|
37734
|
-
const p3 =
|
|
38460
|
+
const p3 = path31.join(dir, entry.name);
|
|
37735
38461
|
if (entry.isDirectory()) {
|
|
37736
38462
|
if (!SCAN_SKIP.has(entry.name)) stack.push(p3);
|
|
37737
38463
|
} else if (entry.name.endsWith(".tsbuildinfo")) {
|
|
37738
|
-
found.push(
|
|
38464
|
+
found.push(path31.relative(root, p3).split(path31.sep).join("/"));
|
|
37739
38465
|
}
|
|
37740
38466
|
}
|
|
37741
38467
|
}
|
|
@@ -37744,7 +38470,7 @@ async function scanTsbuildinfo(root) {
|
|
|
37744
38470
|
}
|
|
37745
38471
|
async function gitStatusPorcelain(root) {
|
|
37746
38472
|
return new Promise((resolve3) => {
|
|
37747
|
-
const child =
|
|
38473
|
+
const child = spawn7("git", ["status", "--porcelain"], { cwd: root, shell: false });
|
|
37748
38474
|
let out = "";
|
|
37749
38475
|
child.stdout.on("data", (d) => out += d.toString());
|
|
37750
38476
|
child.stderr.on("data", (d) => out += d.toString());
|
|
@@ -37771,7 +38497,7 @@ async function cleanupArtifacts(root, relPaths) {
|
|
|
37771
38497
|
const failed = [];
|
|
37772
38498
|
for (const rel2 of relPaths) {
|
|
37773
38499
|
try {
|
|
37774
|
-
await fs16.unlink(
|
|
38500
|
+
await fs16.unlink(path31.join(root, rel2));
|
|
37775
38501
|
cleaned.push(rel2);
|
|
37776
38502
|
} catch {
|
|
37777
38503
|
failed.push(rel2);
|
|
@@ -37794,17 +38520,17 @@ var init_inspectTypecheckSafety = __esm({
|
|
|
37794
38520
|
});
|
|
37795
38521
|
|
|
37796
38522
|
// src/cli/tools/inspectCommand.ts
|
|
37797
|
-
import { spawn as
|
|
37798
|
-
import { createHash as
|
|
37799
|
-
import { existsSync as
|
|
38523
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
38524
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
38525
|
+
import { existsSync as existsSync22, promises as fs17 } from "node:fs";
|
|
37800
38526
|
import os8 from "node:os";
|
|
37801
|
-
import
|
|
38527
|
+
import path32 from "node:path";
|
|
37802
38528
|
function resolveNodeModuleBin(start, rel2) {
|
|
37803
|
-
let dir =
|
|
38529
|
+
let dir = path32.resolve(start);
|
|
37804
38530
|
for (; ; ) {
|
|
37805
|
-
const candidate =
|
|
37806
|
-
if (
|
|
37807
|
-
const parent =
|
|
38531
|
+
const candidate = path32.join(dir, "node_modules", rel2);
|
|
38532
|
+
if (existsSync22(candidate)) return candidate;
|
|
38533
|
+
const parent = path32.dirname(dir);
|
|
37808
38534
|
if (parent === dir) return void 0;
|
|
37809
38535
|
dir = parent;
|
|
37810
38536
|
}
|
|
@@ -37872,7 +38598,7 @@ function buildInspectCommand(op, ctx) {
|
|
|
37872
38598
|
case "npm_ls":
|
|
37873
38599
|
case "npm_outdated":
|
|
37874
38600
|
case "npm_view": {
|
|
37875
|
-
const npmCli = ctx.npmCliPath ?? resolveNodeModuleBin(ctx.root,
|
|
38601
|
+
const npmCli = ctx.npmCliPath ?? resolveNodeModuleBin(ctx.root, path32.join("npm", "bin", "npm-cli.js")) ?? path32.join(ctx.root, "node_modules", "npm", "bin", "npm-cli.js");
|
|
37876
38602
|
if (op.operation === "npm_view") {
|
|
37877
38603
|
const err = rejectFlagLike("package", op.package);
|
|
37878
38604
|
if (err) return { ok: false, reason: err };
|
|
@@ -37881,14 +38607,14 @@ function buildInspectCommand(op, ctx) {
|
|
|
37881
38607
|
return { ok: true, command: process.execPath, argv: [npmCli, ...sub], inspectionClass: "env-info" };
|
|
37882
38608
|
}
|
|
37883
38609
|
case "typecheck": {
|
|
37884
|
-
const project =
|
|
37885
|
-
const hash3 =
|
|
37886
|
-
const tsBuildInfoFile =
|
|
38610
|
+
const project = path32.resolve(ctx.cwd, op.project ?? "tsconfig.json");
|
|
38611
|
+
const hash3 = createHash9("sha256").update(project).digest("hex").slice(0, 16);
|
|
38612
|
+
const tsBuildInfoFile = path32.join(os8.tmpdir(), "zelari-inspect", `${hash3}.tsbuildinfo`);
|
|
37887
38613
|
return {
|
|
37888
38614
|
ok: true,
|
|
37889
38615
|
command: process.execPath,
|
|
37890
38616
|
argv: [
|
|
37891
|
-
ctx.tscPath ?? resolveNodeModuleBin(ctx.root,
|
|
38617
|
+
ctx.tscPath ?? resolveNodeModuleBin(ctx.root, path32.join("typescript", "bin", "tsc")) ?? resolveNodeModuleBin(ctx.cwd, path32.join("typescript", "bin", "tsc")) ?? path32.join(ctx.root, "node_modules", "typescript", "bin", "tsc"),
|
|
37892
38618
|
"--noEmit",
|
|
37893
38619
|
// S3.5 primary mechanism: redirect, never disable — composite forces
|
|
37894
38620
|
// incremental (TS#30661), so --incremental false would break on the
|
|
@@ -37910,7 +38636,7 @@ function runSpawn(command, argv, opts) {
|
|
|
37910
38636
|
return new Promise((resolve3) => {
|
|
37911
38637
|
let child;
|
|
37912
38638
|
try {
|
|
37913
|
-
child =
|
|
38639
|
+
child = spawn8(command, argv, { cwd: opts.cwd, shell: false });
|
|
37914
38640
|
} catch (err) {
|
|
37915
38641
|
resolve3({ code: null, stdout: "", stderr: String(err), timedOut: false, spawnError: String(err) });
|
|
37916
38642
|
return;
|
|
@@ -38648,9 +39374,9 @@ var init_client = __esm({
|
|
|
38648
39374
|
});
|
|
38649
39375
|
|
|
38650
39376
|
// src/cli/lsp/servers.ts
|
|
38651
|
-
import
|
|
39377
|
+
import path33 from "node:path";
|
|
38652
39378
|
function languageIdForFile(file2) {
|
|
38653
|
-
const ext =
|
|
39379
|
+
const ext = path33.extname(file2).toLowerCase();
|
|
38654
39380
|
const map2 = {
|
|
38655
39381
|
".ts": "typescript",
|
|
38656
39382
|
".tsx": "typescriptreact",
|
|
@@ -38665,7 +39391,7 @@ function languageIdForFile(file2) {
|
|
|
38665
39391
|
return map2[ext] ?? "plaintext";
|
|
38666
39392
|
}
|
|
38667
39393
|
function serverForFile(file2, servers = LSP_SERVERS) {
|
|
38668
|
-
const ext =
|
|
39394
|
+
const ext = path33.extname(file2).toLowerCase();
|
|
38669
39395
|
return servers.find((s) => s.extensions.includes(ext)) ?? null;
|
|
38670
39396
|
}
|
|
38671
39397
|
function resolveServerCommand(file2, cwd, servers = LSP_SERVERS) {
|
|
@@ -38714,7 +39440,7 @@ var init_servers = __esm({
|
|
|
38714
39440
|
});
|
|
38715
39441
|
|
|
38716
39442
|
// src/cli/lsp/manager.ts
|
|
38717
|
-
import { spawn as
|
|
39443
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
38718
39444
|
import { readFileSync as readFileSync18 } from "node:fs";
|
|
38719
39445
|
function processTransport(child) {
|
|
38720
39446
|
return {
|
|
@@ -38850,7 +39576,7 @@ var init_manager = __esm({
|
|
|
38850
39576
|
// languages already flagged as unavailable
|
|
38851
39577
|
constructor(options = {}) {
|
|
38852
39578
|
this.cwd = options.cwd ?? process.cwd();
|
|
38853
|
-
this.spawnImpl = options.spawnImpl ??
|
|
39579
|
+
this.spawnImpl = options.spawnImpl ?? spawn9;
|
|
38854
39580
|
this.timeoutMs = options.timeoutMs ?? 15e3;
|
|
38855
39581
|
this.onWarn = options.onWarn ?? ((m) => console.error(m));
|
|
38856
39582
|
}
|
|
@@ -39041,7 +39767,7 @@ var init_manager = __esm({
|
|
|
39041
39767
|
|
|
39042
39768
|
// src/cli/ast/engine.ts
|
|
39043
39769
|
import { readFile } from "node:fs/promises";
|
|
39044
|
-
import
|
|
39770
|
+
import path34 from "node:path";
|
|
39045
39771
|
function loadTs() {
|
|
39046
39772
|
if (!tsPromise) {
|
|
39047
39773
|
tsPromise = import("typescript").then((m) => m.default ?? m).catch(() => null);
|
|
@@ -39052,8 +39778,8 @@ function errMessage(err) {
|
|
|
39052
39778
|
return err instanceof Error ? err.message : String(err);
|
|
39053
39779
|
}
|
|
39054
39780
|
async function parseFileSymbolsDiag(file2, cwd) {
|
|
39055
|
-
const resolvedPath =
|
|
39056
|
-
const extension =
|
|
39781
|
+
const resolvedPath = path34.isAbsolute(file2) ? file2 : path34.join(cwd ?? process.cwd(), file2);
|
|
39782
|
+
const extension = path34.extname(resolvedPath).toLowerCase();
|
|
39057
39783
|
if (!TS_EXTENSIONS.has(extension)) {
|
|
39058
39784
|
return {
|
|
39059
39785
|
status: "unsupported-extension",
|
|
@@ -39095,7 +39821,7 @@ async function parseFileSymbolsDiag(file2, cwd) {
|
|
|
39095
39821
|
}
|
|
39096
39822
|
let source;
|
|
39097
39823
|
try {
|
|
39098
|
-
source = ts.createSourceFile(
|
|
39824
|
+
source = ts.createSourceFile(path34.basename(resolvedPath), text, ts.ScriptTarget.Latest, true);
|
|
39099
39825
|
} catch (err) {
|
|
39100
39826
|
return {
|
|
39101
39827
|
status: "parse-error",
|
|
@@ -39318,13 +40044,13 @@ var init_store2 = __esm({
|
|
|
39318
40044
|
});
|
|
39319
40045
|
|
|
39320
40046
|
// src/cli/semantic/index.ts
|
|
39321
|
-
import { promises as fs18, existsSync as
|
|
40047
|
+
import { promises as fs18, existsSync as existsSync23, readFileSync as readFileSync19 } from "node:fs";
|
|
39322
40048
|
import { homedir as homedir6 } from "node:os";
|
|
39323
|
-
import
|
|
39324
|
-
import { createHash as
|
|
40049
|
+
import path35 from "node:path";
|
|
40050
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
39325
40051
|
function getIndexPath(root) {
|
|
39326
|
-
const hash3 =
|
|
39327
|
-
return process.env.ZELARI_SEMANTIC_FILE ??
|
|
40052
|
+
const hash3 = createHash10("sha1").update(path35.resolve(root)).digest("hex").slice(0, 16);
|
|
40053
|
+
return process.env.ZELARI_SEMANTIC_FILE ?? path35.join(homedir6(), ".tmp", "zelari-code", "semantic", `${hash3}.json`);
|
|
39328
40054
|
}
|
|
39329
40055
|
async function collectSourceFiles(root, maxFiles = 1500) {
|
|
39330
40056
|
const out = [];
|
|
@@ -39342,11 +40068,11 @@ async function collectSourceFiles(root, maxFiles = 1500) {
|
|
|
39342
40068
|
if (entry.isDirectory() && IGNORE_DIRS.has(entry.name)) continue;
|
|
39343
40069
|
if (entry.isDirectory()) continue;
|
|
39344
40070
|
}
|
|
39345
|
-
const full =
|
|
40071
|
+
const full = path35.join(dir, entry.name);
|
|
39346
40072
|
if (entry.isDirectory()) {
|
|
39347
40073
|
if (IGNORE_DIRS.has(entry.name)) continue;
|
|
39348
40074
|
await walk2(full);
|
|
39349
|
-
} else if (SOURCE_EXTENSIONS.has(
|
|
40075
|
+
} else if (SOURCE_EXTENSIONS.has(path35.extname(entry.name).toLowerCase())) {
|
|
39350
40076
|
out.push(full);
|
|
39351
40077
|
}
|
|
39352
40078
|
}
|
|
@@ -39395,14 +40121,14 @@ async function buildIndex(files, embed, options) {
|
|
|
39395
40121
|
}
|
|
39396
40122
|
async function saveIndex(root, data) {
|
|
39397
40123
|
const file2 = getIndexPath(root);
|
|
39398
|
-
await fs18.mkdir(
|
|
40124
|
+
await fs18.mkdir(path35.dirname(file2), { recursive: true });
|
|
39399
40125
|
const tmp = `${file2}.tmp-${process.pid}`;
|
|
39400
40126
|
await fs18.writeFile(tmp, JSON.stringify(data), "utf8");
|
|
39401
40127
|
await fs18.rename(tmp, file2);
|
|
39402
40128
|
}
|
|
39403
40129
|
function loadIndex(root) {
|
|
39404
40130
|
const file2 = getIndexPath(root);
|
|
39405
|
-
if (!
|
|
40131
|
+
if (!existsSync23(file2)) return null;
|
|
39406
40132
|
try {
|
|
39407
40133
|
const parsed = JSON.parse(readFileSync19(file2, "utf8"));
|
|
39408
40134
|
if (parsed && Array.isArray(parsed.chunks)) return parsed;
|
|
@@ -39547,7 +40273,7 @@ var init_provider = __esm({
|
|
|
39547
40273
|
});
|
|
39548
40274
|
|
|
39549
40275
|
// src/cli/semantic/tools.ts
|
|
39550
|
-
import
|
|
40276
|
+
import path36 from "node:path";
|
|
39551
40277
|
function createSemanticTool(deps) {
|
|
39552
40278
|
const buildEmbedFn = deps.buildEmbedFn ?? buildProviderEmbedFn;
|
|
39553
40279
|
return {
|
|
@@ -39574,7 +40300,7 @@ function createSemanticTool(deps) {
|
|
|
39574
40300
|
return typedOk({
|
|
39575
40301
|
count: res.hits.length,
|
|
39576
40302
|
results: res.hits.map((h) => ({
|
|
39577
|
-
location: `${
|
|
40303
|
+
location: `${path36.relative(deps.root, h.file) || h.file}:${h.startLine}-${h.endLine}`,
|
|
39578
40304
|
score: Number(h.score.toFixed(3)),
|
|
39579
40305
|
preview: h.text.length > 400 ? `${h.text.slice(0, 400)}\u2026` : h.text
|
|
39580
40306
|
}))
|
|
@@ -39593,8 +40319,8 @@ var init_tools4 = __esm({
|
|
|
39593
40319
|
});
|
|
39594
40320
|
|
|
39595
40321
|
// src/cli/browser/driver.ts
|
|
39596
|
-
import { createRequire } from "node:module";
|
|
39597
|
-
import
|
|
40322
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
40323
|
+
import path37 from "node:path";
|
|
39598
40324
|
import { pathToFileURL } from "node:url";
|
|
39599
40325
|
function asPlaywright(mod) {
|
|
39600
40326
|
if (!mod || typeof mod !== "object") return null;
|
|
@@ -39605,10 +40331,10 @@ function asPlaywright(mod) {
|
|
|
39605
40331
|
return null;
|
|
39606
40332
|
}
|
|
39607
40333
|
async function loadPlaywright(cwd) {
|
|
39608
|
-
const base = cwd && cwd.length > 0 ?
|
|
40334
|
+
const base = cwd && cwd.length > 0 ? path37.resolve(cwd) : void 0;
|
|
39609
40335
|
if (base) {
|
|
39610
40336
|
try {
|
|
39611
|
-
const req =
|
|
40337
|
+
const req = createRequire2(path37.join(base, "package.json"));
|
|
39612
40338
|
const resolved = req.resolve("playwright");
|
|
39613
40339
|
const mod = await import(pathToFileURL(resolved).href);
|
|
39614
40340
|
const pw = asPlaywright(mod);
|
|
@@ -39823,7 +40549,7 @@ var init_driver = __esm({
|
|
|
39823
40549
|
});
|
|
39824
40550
|
|
|
39825
40551
|
// src/cli/browser/tools.ts
|
|
39826
|
-
import
|
|
40552
|
+
import path38 from "node:path";
|
|
39827
40553
|
import os9 from "node:os";
|
|
39828
40554
|
function createBrowserTool(deps = {}) {
|
|
39829
40555
|
return {
|
|
@@ -39842,7 +40568,7 @@ function createBrowserTool(deps = {}) {
|
|
|
39842
40568
|
execute: async (args, ctx) => {
|
|
39843
40569
|
const a = args;
|
|
39844
40570
|
const dir = deps.screenshotDir ?? os9.tmpdir();
|
|
39845
|
-
const screenshotPath = a.screenshot === false ? void 0 :
|
|
40571
|
+
const screenshotPath = a.screenshot === false ? void 0 : path38.join(dir, `zelari-browser-${Date.now()}.png`);
|
|
39846
40572
|
const result = await runBrowserCheck(
|
|
39847
40573
|
{
|
|
39848
40574
|
url: a.url,
|
|
@@ -39934,14 +40660,14 @@ __export(targets_exports, {
|
|
|
39934
40660
|
});
|
|
39935
40661
|
import {
|
|
39936
40662
|
chmodSync,
|
|
39937
|
-
existsSync as
|
|
40663
|
+
existsSync as existsSync24,
|
|
39938
40664
|
mkdirSync as mkdirSync13,
|
|
39939
40665
|
readFileSync as readFileSync20,
|
|
39940
40666
|
writeFileSync as writeFileSync15
|
|
39941
40667
|
} from "node:fs";
|
|
39942
40668
|
import { dirname as dirname4, join as join16 } from "node:path";
|
|
39943
40669
|
import { homedir as homedir7 } from "node:os";
|
|
39944
|
-
import { spawn as
|
|
40670
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
39945
40671
|
function getSshTargetsPath() {
|
|
39946
40672
|
return join16(homedir7(), ".zelari-code", "ssh-targets.json");
|
|
39947
40673
|
}
|
|
@@ -39955,7 +40681,7 @@ function normalizeAuth(auth) {
|
|
|
39955
40681
|
}
|
|
39956
40682
|
function readSecrets() {
|
|
39957
40683
|
const path65 = getSshSecretsPath();
|
|
39958
|
-
if (!
|
|
40684
|
+
if (!existsSync24(path65)) return {};
|
|
39959
40685
|
try {
|
|
39960
40686
|
return JSON.parse(readFileSync20(path65, "utf8"));
|
|
39961
40687
|
} catch {
|
|
@@ -39998,7 +40724,7 @@ function deleteSshPassword(id) {
|
|
|
39998
40724
|
}
|
|
39999
40725
|
function readStore2() {
|
|
40000
40726
|
const path65 = getSshTargetsPath();
|
|
40001
|
-
if (!
|
|
40727
|
+
if (!existsSync24(path65)) return [];
|
|
40002
40728
|
try {
|
|
40003
40729
|
const parsed = JSON.parse(readFileSync20(path65, "utf8"));
|
|
40004
40730
|
const list = Array.isArray(parsed.targets) ? parsed.targets : [];
|
|
@@ -40171,7 +40897,7 @@ function runSsh(target, remoteCommand, timeoutMs2 = 6e4) {
|
|
|
40171
40897
|
if (!env.DISPLAY) env.DISPLAY = "1";
|
|
40172
40898
|
env.ZELARI_SSH_ASKPASS_PASS = pass;
|
|
40173
40899
|
}
|
|
40174
|
-
const child =
|
|
40900
|
+
const child = spawn10("ssh", args, {
|
|
40175
40901
|
windowsHide: true,
|
|
40176
40902
|
env,
|
|
40177
40903
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -40212,7 +40938,7 @@ function readSshPublicKey(keyOrPubPath) {
|
|
|
40212
40938
|
if (!raw) return { ok: false, error: "Empty path" };
|
|
40213
40939
|
const candidates = raw.endsWith(".pub") ? [raw] : [`${raw}.pub`, raw];
|
|
40214
40940
|
for (const p3 of candidates) {
|
|
40215
|
-
if (!
|
|
40941
|
+
if (!existsSync24(p3)) continue;
|
|
40216
40942
|
try {
|
|
40217
40943
|
const content = readFileSync20(p3, "utf8").trim();
|
|
40218
40944
|
if (!content) continue;
|
|
@@ -40396,10 +41122,10 @@ var init_tools6 = __esm({
|
|
|
40396
41122
|
|
|
40397
41123
|
// src/cli/workspace/worldModel.ts
|
|
40398
41124
|
import { promises as fs19 } from "node:fs";
|
|
40399
|
-
import
|
|
40400
|
-
import { spawn as
|
|
41125
|
+
import path39 from "node:path";
|
|
41126
|
+
import { spawn as spawn11 } from "node:child_process";
|
|
40401
41127
|
function worldDir(cwd) {
|
|
40402
|
-
return
|
|
41128
|
+
return path39.join(cwd, WORLD_DIR_NAME);
|
|
40403
41129
|
}
|
|
40404
41130
|
async function ensureWorldDir(cwd) {
|
|
40405
41131
|
const dir = worldDir(cwd);
|
|
@@ -40409,10 +41135,10 @@ async function ensureWorldDir(cwd) {
|
|
|
40409
41135
|
async function appendTimeline(cwd, entry) {
|
|
40410
41136
|
const dir = await ensureWorldDir(cwd);
|
|
40411
41137
|
const line = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }) + "\n";
|
|
40412
|
-
await fs19.appendFile(
|
|
41138
|
+
await fs19.appendFile(path39.join(dir, TIMELINE_FILE), line, "utf8");
|
|
40413
41139
|
}
|
|
40414
41140
|
async function readChecks(cwd) {
|
|
40415
|
-
const p3 =
|
|
41141
|
+
const p3 = path39.join(worldDir(cwd), CHECKS_FILE);
|
|
40416
41142
|
try {
|
|
40417
41143
|
const raw = await fs19.readFile(p3, "utf8");
|
|
40418
41144
|
const parsed = JSON.parse(raw);
|
|
@@ -40424,7 +41150,7 @@ async function readChecks(cwd) {
|
|
|
40424
41150
|
function runShell(command, cwd, timeoutMs2, signal) {
|
|
40425
41151
|
return new Promise((resolve3) => {
|
|
40426
41152
|
const isWin = process.platform === "win32";
|
|
40427
|
-
const child =
|
|
41153
|
+
const child = spawn11(isWin ? "cmd.exe" : "/bin/sh", isWin ? ["/c", command] : ["-c", command], {
|
|
40428
41154
|
cwd,
|
|
40429
41155
|
env: process.env,
|
|
40430
41156
|
windowsHide: true,
|
|
@@ -40487,8 +41213,8 @@ function runShell(command, cwd, timeoutMs2, signal) {
|
|
|
40487
41213
|
});
|
|
40488
41214
|
}
|
|
40489
41215
|
async function runBacktest(cwd, signal) {
|
|
40490
|
-
const checksPath =
|
|
40491
|
-
const hypothesisPath =
|
|
41216
|
+
const checksPath = path39.join(worldDir(cwd), CHECKS_FILE);
|
|
41217
|
+
const hypothesisPath = path39.join(worldDir(cwd), HYPOTHESIS_FILE);
|
|
40492
41218
|
const checks = await readChecks(cwd);
|
|
40493
41219
|
if (checks.length === 0) {
|
|
40494
41220
|
return {
|
|
@@ -40557,7 +41283,7 @@ var init_worldModel = __esm({
|
|
|
40557
41283
|
"use strict";
|
|
40558
41284
|
init_zod();
|
|
40559
41285
|
init_toolTypes();
|
|
40560
|
-
WORLD_DIR_NAME =
|
|
41286
|
+
WORLD_DIR_NAME = path39.join(".zelari", "world");
|
|
40561
41287
|
HYPOTHESIS_FILE = "hypothesis.md";
|
|
40562
41288
|
CHECKS_FILE = "checks.json";
|
|
40563
41289
|
TIMELINE_FILE = "timeline.jsonl";
|
|
@@ -40574,7 +41300,7 @@ var init_worldModel = __esm({
|
|
|
40574
41300
|
execute: async (args, ctx) => {
|
|
40575
41301
|
try {
|
|
40576
41302
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
40577
|
-
const file2 =
|
|
41303
|
+
const file2 = path39.join(dir, HYPOTHESIS_FILE);
|
|
40578
41304
|
if (args.append) {
|
|
40579
41305
|
const block = `
|
|
40580
41306
|
|
|
@@ -40613,7 +41339,7 @@ ${args.content}
|
|
|
40613
41339
|
execute: async (args, ctx) => {
|
|
40614
41340
|
try {
|
|
40615
41341
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
40616
|
-
const file2 =
|
|
41342
|
+
const file2 = path39.join(dir, CHECKS_FILE);
|
|
40617
41343
|
const body = { checks: args.checks };
|
|
40618
41344
|
await fs19.writeFile(file2, JSON.stringify(body, null, 2) + "\n", "utf8");
|
|
40619
41345
|
await appendTimeline(ctx.cwd, { kind: "checks_set", count: args.checks.length });
|
|
@@ -40652,8 +41378,8 @@ ${args.content}
|
|
|
40652
41378
|
stdoutPreview: "(dryRun)",
|
|
40653
41379
|
mismatch: "dryRun"
|
|
40654
41380
|
})),
|
|
40655
|
-
hypothesisPath:
|
|
40656
|
-
checksPath:
|
|
41381
|
+
hypothesisPath: path39.join(worldDir(ctx.cwd), HYPOTHESIS_FILE),
|
|
41382
|
+
checksPath: path39.join(worldDir(ctx.cwd), CHECKS_FILE)
|
|
40657
41383
|
});
|
|
40658
41384
|
}
|
|
40659
41385
|
const result = await runBacktest(ctx.cwd, ctx.signal);
|
|
@@ -40677,7 +41403,7 @@ ${args.content}
|
|
|
40677
41403
|
execute: async (args, ctx) => {
|
|
40678
41404
|
try {
|
|
40679
41405
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
40680
|
-
const file2 =
|
|
41406
|
+
const file2 = path39.join(dir, TIMELINE_FILE);
|
|
40681
41407
|
await appendTimeline(ctx.cwd, {
|
|
40682
41408
|
kind: args.kind,
|
|
40683
41409
|
summary: args.summary,
|
|
@@ -40785,13 +41511,13 @@ __export(folderTrust_exports, {
|
|
|
40785
41511
|
untrustFolder: () => untrustFolder
|
|
40786
41512
|
});
|
|
40787
41513
|
import { homedir as homedir8 } from "node:os";
|
|
40788
|
-
import { existsSync as
|
|
40789
|
-
import
|
|
41514
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync14, readFileSync as readFileSync21, writeFileSync as writeFileSync16 } from "node:fs";
|
|
41515
|
+
import path40 from "node:path";
|
|
40790
41516
|
function trustStorePath() {
|
|
40791
|
-
return _overrideStorePath ??
|
|
41517
|
+
return _overrideStorePath ?? path40.join(homedir8(), ".zelari-code", "trust.json");
|
|
40792
41518
|
}
|
|
40793
41519
|
function normalize4(p3) {
|
|
40794
|
-
const resolved =
|
|
41520
|
+
const resolved = path40.resolve(p3);
|
|
40795
41521
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
40796
41522
|
}
|
|
40797
41523
|
function readStore3() {
|
|
@@ -40807,7 +41533,7 @@ function readStore3() {
|
|
|
40807
41533
|
function writeStore3(store6) {
|
|
40808
41534
|
const p3 = trustStorePath();
|
|
40809
41535
|
try {
|
|
40810
|
-
mkdirSync14(
|
|
41536
|
+
mkdirSync14(path40.dirname(p3), { recursive: true });
|
|
40811
41537
|
writeFileSync16(p3, JSON.stringify(store6, null, 2), "utf8");
|
|
40812
41538
|
} catch (err) {
|
|
40813
41539
|
throw new Error(
|
|
@@ -40833,7 +41559,7 @@ function isFolderTrusted(folderPath) {
|
|
|
40833
41559
|
}
|
|
40834
41560
|
function trustFolder(folderPath) {
|
|
40835
41561
|
const store6 = readStore3();
|
|
40836
|
-
const normalized =
|
|
41562
|
+
const normalized = path40.resolve(folderPath);
|
|
40837
41563
|
if (!store6.folders.some((f) => normalize4(f.path) === normalize4(normalized))) {
|
|
40838
41564
|
store6.folders.push({ path: normalized, trustedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
40839
41565
|
writeStore3(store6);
|
|
@@ -40863,7 +41589,7 @@ function getTrustStorePath() {
|
|
|
40863
41589
|
return trustStorePath();
|
|
40864
41590
|
}
|
|
40865
41591
|
function hasTrustStore() {
|
|
40866
|
-
return
|
|
41592
|
+
return existsSync25(trustStorePath());
|
|
40867
41593
|
}
|
|
40868
41594
|
function _setTrustStorePathForTests(p3) {
|
|
40869
41595
|
_overrideStorePath = p3;
|
|
@@ -40947,9 +41673,9 @@ var init_lifecycleHooks = __esm({
|
|
|
40947
41673
|
});
|
|
40948
41674
|
|
|
40949
41675
|
// src/cli/toolResultCache.ts
|
|
40950
|
-
import { createHash as
|
|
41676
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
40951
41677
|
import { promises as fs20 } from "node:fs";
|
|
40952
|
-
import
|
|
41678
|
+
import path41 from "node:path";
|
|
40953
41679
|
function isToolCacheEnabled() {
|
|
40954
41680
|
const raw = process.env.ZELARI_TOOL_CACHE;
|
|
40955
41681
|
return raw !== "0" && raw !== "false" && raw !== "off";
|
|
@@ -40960,7 +41686,7 @@ function resolveToolCacheTtlMs() {
|
|
|
40960
41686
|
return Number.isFinite(n) && n >= 0 ? n : TOOL_CACHE_DEFAULT_TTL_MS;
|
|
40961
41687
|
}
|
|
40962
41688
|
function hashKey(parts) {
|
|
40963
|
-
return
|
|
41689
|
+
return createHash11("sha256").update(JSON.stringify(parts), "utf8").digest("hex");
|
|
40964
41690
|
}
|
|
40965
41691
|
function resultBytes(result) {
|
|
40966
41692
|
try {
|
|
@@ -41034,7 +41760,7 @@ async function statKey(toolName, input, ctx) {
|
|
|
41034
41760
|
if (!input || typeof input !== "object") return null;
|
|
41035
41761
|
const rawPath = input.path;
|
|
41036
41762
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
41037
|
-
const abs =
|
|
41763
|
+
const abs = path41.isAbsolute(rawPath) ? rawPath : path41.join(ctx.cwd, rawPath);
|
|
41038
41764
|
try {
|
|
41039
41765
|
const st = await fs20.stat(abs);
|
|
41040
41766
|
return hashKey({
|
|
@@ -41715,14 +42441,14 @@ var init_toolRegistry = __esm({
|
|
|
41715
42441
|
});
|
|
41716
42442
|
|
|
41717
42443
|
// src/cli/state/fileStateStore.ts
|
|
41718
|
-
import { createHash as
|
|
42444
|
+
import { createHash as createHash13, randomUUID as randomUUID2 } from "node:crypto";
|
|
41719
42445
|
import { promises as fs21 } from "node:fs";
|
|
41720
|
-
import * as
|
|
42446
|
+
import * as path43 from "node:path";
|
|
41721
42447
|
function shortId() {
|
|
41722
42448
|
return randomUUID2().replace(/-/g, "").slice(0, 12);
|
|
41723
42449
|
}
|
|
41724
42450
|
async function writeJsonAtomic(filePath, data) {
|
|
41725
|
-
await fs21.mkdir(
|
|
42451
|
+
await fs21.mkdir(path43.dirname(filePath), { recursive: true });
|
|
41726
42452
|
const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
41727
42453
|
await fs21.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
41728
42454
|
await fs21.rename(tmp, filePath);
|
|
@@ -41767,7 +42493,7 @@ async function getStateStore(projectRoot, env = process.env) {
|
|
|
41767
42493
|
}
|
|
41768
42494
|
}
|
|
41769
42495
|
function hashStablePrompt(stable) {
|
|
41770
|
-
return
|
|
42496
|
+
return createHash13("sha256").update(stable, "utf8").digest("hex").slice(0, 16);
|
|
41771
42497
|
}
|
|
41772
42498
|
var DEFAULT_MATERIALIZE_CHARS, FileDurableStateStore, NoopDurableStateStore;
|
|
41773
42499
|
var init_fileStateStore = __esm({
|
|
@@ -41783,11 +42509,11 @@ var init_fileStateStore = __esm({
|
|
|
41783
42509
|
indexPath = "";
|
|
41784
42510
|
async init(projectRoot) {
|
|
41785
42511
|
this.root = projectRoot;
|
|
41786
|
-
this.stateDir =
|
|
41787
|
-
this.commitsDir =
|
|
41788
|
-
this.artifactsDir =
|
|
41789
|
-
this.headPath =
|
|
41790
|
-
this.indexPath =
|
|
42512
|
+
this.stateDir = path43.join(projectRoot, ".zelari", "state");
|
|
42513
|
+
this.commitsDir = path43.join(this.stateDir, "commits");
|
|
42514
|
+
this.artifactsDir = path43.join(this.stateDir, "artifacts");
|
|
42515
|
+
this.headPath = path43.join(this.stateDir, "HEAD.json");
|
|
42516
|
+
this.indexPath = path43.join(this.stateDir, "index.jsonl");
|
|
41791
42517
|
await fs21.mkdir(this.commitsDir, { recursive: true });
|
|
41792
42518
|
await fs21.mkdir(this.artifactsDir, { recursive: true });
|
|
41793
42519
|
}
|
|
@@ -41800,13 +42526,13 @@ var init_fileStateStore = __esm({
|
|
|
41800
42526
|
const discoveries = input.discoveries ?? [];
|
|
41801
42527
|
const parent = await this.head();
|
|
41802
42528
|
const id = shortId();
|
|
41803
|
-
const artifactRel =
|
|
41804
|
-
const artifactAbs =
|
|
42529
|
+
const artifactRel = path43.join("artifacts", id);
|
|
42530
|
+
const artifactAbs = path43.join(this.artifactsDir, id);
|
|
41805
42531
|
await fs21.mkdir(artifactAbs, { recursive: true });
|
|
41806
42532
|
const summary = defaultSummary(input, discoveries);
|
|
41807
|
-
await fs21.writeFile(
|
|
41808
|
-
await writeJsonAtomic(
|
|
41809
|
-
await writeJsonAtomic(
|
|
42533
|
+
await fs21.writeFile(path43.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
|
|
42534
|
+
await writeJsonAtomic(path43.join(artifactAbs, "discoveries.json"), discoveries);
|
|
42535
|
+
await writeJsonAtomic(path43.join(artifactAbs, "verification.json"), input.verification);
|
|
41810
42536
|
const meta3 = {
|
|
41811
42537
|
id,
|
|
41812
42538
|
parentId: parent?.id ?? null,
|
|
@@ -41818,14 +42544,14 @@ var init_fileStateStore = __esm({
|
|
|
41818
42544
|
workspaceCheckpointId: input.workspaceCheckpointId,
|
|
41819
42545
|
verification: {
|
|
41820
42546
|
...input.verification,
|
|
41821
|
-
reportPath: input.verification.reportPath ??
|
|
42547
|
+
reportPath: input.verification.reportPath ?? path43.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
|
|
41822
42548
|
},
|
|
41823
42549
|
changedPaths: input.changedPaths ?? [],
|
|
41824
42550
|
stablePromptHash: input.stablePromptHash,
|
|
41825
42551
|
discoveryCount: discoveries.length,
|
|
41826
42552
|
artifactDir: artifactRel.replace(/\\/g, "/")
|
|
41827
42553
|
};
|
|
41828
|
-
await writeJsonAtomic(
|
|
42554
|
+
await writeJsonAtomic(path43.join(this.commitsDir, `${id}.json`), meta3);
|
|
41829
42555
|
await writeJsonAtomic(this.headPath, { id, updatedAt: meta3.createdAt });
|
|
41830
42556
|
await fs21.appendFile(this.indexPath, JSON.stringify({ id, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
|
|
41831
42557
|
return stripStored(meta3);
|
|
@@ -41836,7 +42562,7 @@ var init_fileStateStore = __esm({
|
|
|
41836
42562
|
return this.get(head.id);
|
|
41837
42563
|
}
|
|
41838
42564
|
async get(id) {
|
|
41839
|
-
const stored = await readJsonFile(
|
|
42565
|
+
const stored = await readJsonFile(path43.join(this.commitsDir, `${id}.json`));
|
|
41840
42566
|
return stored ? stripStored(stored) : null;
|
|
41841
42567
|
}
|
|
41842
42568
|
async list(limit = 20) {
|
|
@@ -41875,9 +42601,9 @@ var init_fileStateStore = __esm({
|
|
|
41875
42601
|
async loadDiscoveries(id) {
|
|
41876
42602
|
const meta3 = id ? await this.get(id) : await this.head();
|
|
41877
42603
|
if (!meta3) return [];
|
|
41878
|
-
const stored = await readJsonFile(
|
|
42604
|
+
const stored = await readJsonFile(path43.join(this.commitsDir, `${meta3.id}.json`));
|
|
41879
42605
|
if (!stored?.artifactDir) return [];
|
|
41880
|
-
const discPath =
|
|
42606
|
+
const discPath = path43.join(this.stateDir, stored.artifactDir, "discoveries.json");
|
|
41881
42607
|
return await readJsonFile(discPath) ?? [];
|
|
41882
42608
|
}
|
|
41883
42609
|
async materializeContext(id, maxChars = DEFAULT_MATERIALIZE_CHARS) {
|
|
@@ -42531,7 +43257,7 @@ __export(conversationContext_exports, {
|
|
|
42531
43257
|
setHistory: () => setHistory,
|
|
42532
43258
|
setLastClarification: () => setLastClarification
|
|
42533
43259
|
});
|
|
42534
|
-
import { existsSync as
|
|
43260
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
42535
43261
|
import { join as join19 } from "node:path";
|
|
42536
43262
|
function getHistory() {
|
|
42537
43263
|
return history;
|
|
@@ -42541,7 +43267,7 @@ function setHistory(messages) {
|
|
|
42541
43267
|
history = projected === messages ? [...messages] : projected;
|
|
42542
43268
|
}
|
|
42543
43269
|
function compactInPlace(cwd = process.cwd()) {
|
|
42544
|
-
const durableStatePresent =
|
|
43270
|
+
const durableStatePresent = existsSync26(join19(cwd, ".zelari", "state", "HEAD.json"));
|
|
42545
43271
|
history = applySessionSurface(compactHistory(history, { durableStatePresent }));
|
|
42546
43272
|
}
|
|
42547
43273
|
function appendMessages(msgs) {
|
|
@@ -43124,7 +43850,6 @@ __export(headlessSpine_exports, {
|
|
|
43124
43850
|
seedHeadlessModelHistory: () => seedHeadlessModelHistory,
|
|
43125
43851
|
sessionStartedEvent: () => sessionStartedEvent
|
|
43126
43852
|
});
|
|
43127
|
-
import path42 from "node:path";
|
|
43128
43853
|
function sessionStartedEvent(handle) {
|
|
43129
43854
|
return {
|
|
43130
43855
|
type: "session_started",
|
|
@@ -43158,12 +43883,10 @@ async function openHeadlessSpine(opts) {
|
|
|
43158
43883
|
if (spine.status === "active") {
|
|
43159
43884
|
const budget = new BudgetRuntime(profileId, { enforcement: resolveResourceEnforcement() });
|
|
43160
43885
|
if (spine.resumedFromSeq !== void 0 && spine.resumedFromSeq > 0) {
|
|
43161
|
-
|
|
43162
|
-
path42.join(spine.sessionsDir, opts.sessionId, "events.jsonl")
|
|
43163
|
-
).catch(() => null);
|
|
43164
|
-
if (prior) budget.adoptLedgerFromEvents(prior.events);
|
|
43886
|
+
await restoreBudgetRuntimeFromSession(budget, opts.sessionId, opts.baseDir);
|
|
43165
43887
|
}
|
|
43166
43888
|
spine.attachBudgetRuntime(budget);
|
|
43889
|
+
await noteHarnessLifecycle(spine, opts.sessionId, profileId, budget, opts.baseDir);
|
|
43167
43890
|
spine.note("headless.profile", { profile: profileId, mode: opts.mode ?? "kraken" });
|
|
43168
43891
|
}
|
|
43169
43892
|
return {
|
|
@@ -43175,11 +43898,20 @@ async function openHeadlessSpine(opts) {
|
|
|
43175
43898
|
spine.mirrorBrainEvent(ev);
|
|
43176
43899
|
}
|
|
43177
43900
|
},
|
|
43901
|
+
beginResourceTurn() {
|
|
43902
|
+
return spine.beginResourceTurn();
|
|
43903
|
+
},
|
|
43178
43904
|
userMessage(text) {
|
|
43179
43905
|
spine.userMessage(text);
|
|
43180
43906
|
},
|
|
43181
|
-
gateResourceToolCall(toolName) {
|
|
43182
|
-
return spine.gateResourceToolCall(toolName);
|
|
43907
|
+
gateResourceToolCall(toolName, args) {
|
|
43908
|
+
return spine.gateResourceToolCall(toolName, args);
|
|
43909
|
+
},
|
|
43910
|
+
resourceBudgetLimit() {
|
|
43911
|
+
return spine.resourceBudgetLimit();
|
|
43912
|
+
},
|
|
43913
|
+
resourceBudgetSummary() {
|
|
43914
|
+
return spine.resourceBudgetSummary();
|
|
43183
43915
|
},
|
|
43184
43916
|
verificationRun(payload) {
|
|
43185
43917
|
spine.verificationRun(payload);
|
|
@@ -43253,7 +43985,7 @@ async function seedHeadlessModelHistory(handle, legacy) {
|
|
|
43253
43985
|
}
|
|
43254
43986
|
for (const m of legacySeed) {
|
|
43255
43987
|
if (m.role === "user") {
|
|
43256
|
-
mirror.userMessage(m.content);
|
|
43988
|
+
mirror.userMessage(m.content, { beginResourceTurn: false, imported: "legacy-history" });
|
|
43257
43989
|
} else {
|
|
43258
43990
|
mirror.assistantMessage(m.content, { imported: "legacy-history" });
|
|
43259
43991
|
}
|
|
@@ -43297,10 +44029,11 @@ var init_headlessSpine = __esm({
|
|
|
43297
44029
|
init_dist();
|
|
43298
44030
|
init_session();
|
|
43299
44031
|
init_mission2();
|
|
43300
|
-
init_session();
|
|
43301
44032
|
init_runtime2();
|
|
43302
44033
|
init_sessionSpine();
|
|
43303
44034
|
init_budgetRuntime();
|
|
44035
|
+
init_restoreRuntime();
|
|
44036
|
+
init_sessionSpine();
|
|
43304
44037
|
init_headless();
|
|
43305
44038
|
}
|
|
43306
44039
|
});
|
|
@@ -43444,7 +44177,7 @@ var claudeProvider_exports = {};
|
|
|
43444
44177
|
__export(claudeProvider_exports, {
|
|
43445
44178
|
createLocalCliProvider: () => createLocalCliProvider
|
|
43446
44179
|
});
|
|
43447
|
-
import { spawn as
|
|
44180
|
+
import { spawn as spawn12 } from "node:child_process";
|
|
43448
44181
|
function waitForExit(child, timeoutMs2 = 2e3) {
|
|
43449
44182
|
return new Promise((resolve3) => {
|
|
43450
44183
|
if (child.exitCode != null) return resolve3(child.exitCode);
|
|
@@ -43473,7 +44206,7 @@ function createLocalCliProvider(opts = {}) {
|
|
|
43473
44206
|
);
|
|
43474
44207
|
}
|
|
43475
44208
|
}
|
|
43476
|
-
const spawnFn = opts.spawnFn ??
|
|
44209
|
+
const spawnFn = opts.spawnFn ?? spawn12;
|
|
43477
44210
|
let child;
|
|
43478
44211
|
try {
|
|
43479
44212
|
child = spawnFn(cli, args, {
|
|
@@ -43568,12 +44301,12 @@ var init_claudeProvider = __esm({
|
|
|
43568
44301
|
});
|
|
43569
44302
|
|
|
43570
44303
|
// src/cli/workspace/projectInstructions.ts
|
|
43571
|
-
import { existsSync as
|
|
44304
|
+
import { existsSync as existsSync27, readFileSync as readFileSync23 } from "node:fs";
|
|
43572
44305
|
import { join as join20 } from "node:path";
|
|
43573
44306
|
function loadProjectInstructions(projectRoot = process.cwd(), maxChars = MAX_CHARS) {
|
|
43574
44307
|
for (const name of CANDIDATES) {
|
|
43575
44308
|
const full = join20(projectRoot, name);
|
|
43576
|
-
if (!
|
|
44309
|
+
if (!existsSync27(full)) continue;
|
|
43577
44310
|
try {
|
|
43578
44311
|
let raw = readFileSync23(full, "utf8");
|
|
43579
44312
|
raw = raw.replace(/\r\n/g, "\n").trim();
|
|
@@ -43619,7 +44352,7 @@ __export(workspaceSummary_exports, {
|
|
|
43619
44352
|
buildWorkspaceSummary: () => buildWorkspaceSummary,
|
|
43620
44353
|
buildZelariReadHint: () => buildZelariReadHint
|
|
43621
44354
|
});
|
|
43622
|
-
import { existsSync as
|
|
44355
|
+
import { existsSync as existsSync28, readFileSync as readFileSync24, readdirSync as readdirSync6, statSync as statSync5 } from "node:fs";
|
|
43623
44356
|
import { join as join21, relative } from "node:path";
|
|
43624
44357
|
function buildWorkspaceSummary(projectRoot = process.cwd(), options = {}) {
|
|
43625
44358
|
const { maxEntries = 30, maxChars = 3500, maxDeps = 24, maxScripts = 16 } = options;
|
|
@@ -43654,7 +44387,7 @@ function formatTaskLine(t) {
|
|
|
43654
44387
|
function buildPlanSummary(projectRoot = process.cwd(), options) {
|
|
43655
44388
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
43656
44389
|
const planPath = join21(zelariRoot, "plan.json");
|
|
43657
|
-
if (!
|
|
44390
|
+
if (!existsSync28(planPath)) return null;
|
|
43658
44391
|
let plan;
|
|
43659
44392
|
try {
|
|
43660
44393
|
plan = JSON.parse(readFileSync24(planPath, "utf8"));
|
|
@@ -43797,7 +44530,7 @@ function pickNextTask(open) {
|
|
|
43797
44530
|
}
|
|
43798
44531
|
function buildZelariReadHint(projectRoot = process.cwd()) {
|
|
43799
44532
|
const planPath = join21(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
43800
|
-
if (!
|
|
44533
|
+
if (!existsSync28(planPath)) return "";
|
|
43801
44534
|
return [
|
|
43802
44535
|
"# Council workspace detected (.zelari/) \u2014 DRAFT vault",
|
|
43803
44536
|
"`.zelari/plan.json` and `.zelari/docs/` hold **design hypotheses**, not verified product state.",
|
|
@@ -43813,7 +44546,7 @@ function safeProjectName(root) {
|
|
|
43813
44546
|
}
|
|
43814
44547
|
function readPackageJson(projectRoot) {
|
|
43815
44548
|
const p3 = join21(projectRoot, "package.json");
|
|
43816
|
-
if (!
|
|
44549
|
+
if (!existsSync28(p3)) return null;
|
|
43817
44550
|
try {
|
|
43818
44551
|
return JSON.parse(readFileSync24(p3, "utf8"));
|
|
43819
44552
|
} catch {
|
|
@@ -43917,12 +44650,12 @@ var init_workspaceSummary = __esm({
|
|
|
43917
44650
|
});
|
|
43918
44651
|
|
|
43919
44652
|
// src/cli/workspace/buildLessonsSummary.ts
|
|
43920
|
-
import { existsSync as
|
|
44653
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
43921
44654
|
import { join as join22 } from "node:path";
|
|
43922
44655
|
function buildLessonsSummary(projectRoot = process.cwd(), taskText) {
|
|
43923
44656
|
if (process.env["ZELARI_LESSONS"] === "0") return null;
|
|
43924
44657
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
43925
|
-
if (!
|
|
44658
|
+
if (!existsSync29(join22(zelariRoot, "lessons.jsonl"))) return null;
|
|
43926
44659
|
const lessons = recallLessons(zelariRoot, {
|
|
43927
44660
|
maxLessons: 5,
|
|
43928
44661
|
maxBytes: 2048,
|
|
@@ -43943,7 +44676,7 @@ var composeContext_exports = {};
|
|
|
43943
44676
|
__export(composeContext_exports, {
|
|
43944
44677
|
composeProjectContext: () => composeProjectContext
|
|
43945
44678
|
});
|
|
43946
|
-
import { existsSync as
|
|
44679
|
+
import { existsSync as existsSync30, readdirSync as readdirSync7, readFileSync as readFileSync25 } from "node:fs";
|
|
43947
44680
|
import { join as join23 } from "node:path";
|
|
43948
44681
|
function cap2(text, max, label) {
|
|
43949
44682
|
if (!text || text.length <= max) return { text: text || "", truncated: false };
|
|
@@ -43956,13 +44689,13 @@ function cap2(text, max, label) {
|
|
|
43956
44689
|
}
|
|
43957
44690
|
function buildDesignIndex(projectRoot, maxChars) {
|
|
43958
44691
|
const root = resolveWorkspaceRoot(projectRoot);
|
|
43959
|
-
if (!
|
|
44692
|
+
if (!existsSync30(root)) return "";
|
|
43960
44693
|
const lines = [
|
|
43961
44694
|
"# Design vault index (.zelari/) \u2014 HYPOTHESES only",
|
|
43962
44695
|
"Full design docs are NOT product source of truth. Open with list_files / read_file / searchDocuments if needed."
|
|
43963
44696
|
];
|
|
43964
44697
|
const docsDir = join23(root, "docs");
|
|
43965
|
-
if (
|
|
44698
|
+
if (existsSync30(docsDir)) {
|
|
43966
44699
|
try {
|
|
43967
44700
|
const docs = readdirSync7(docsDir).filter((n) => n.endsWith(".md")).slice(0, 12);
|
|
43968
44701
|
if (docs.length > 0) {
|
|
@@ -43976,12 +44709,12 @@ function buildDesignIndex(projectRoot, maxChars) {
|
|
|
43976
44709
|
}
|
|
43977
44710
|
}
|
|
43978
44711
|
for (const name of ["risks.md", "plan.json", "nfr-spec.json"]) {
|
|
43979
|
-
if (
|
|
44712
|
+
if (existsSync30(join23(root, name))) {
|
|
43980
44713
|
lines.push(`- .zelari/${name} present`);
|
|
43981
44714
|
}
|
|
43982
44715
|
}
|
|
43983
44716
|
const decisionsDir = join23(root, "decisions");
|
|
43984
|
-
if (
|
|
44717
|
+
if (existsSync30(decisionsDir)) {
|
|
43985
44718
|
try {
|
|
43986
44719
|
const n = readdirSync7(decisionsDir).filter((f) => f.endsWith(".md")).length;
|
|
43987
44720
|
if (n > 0) lines.push(`- .zelari/decisions/ (${n} ADR file(s) \u2014 treat proposed as non-binding)`);
|
|
@@ -44083,15 +44816,15 @@ function composeProjectContext(input) {
|
|
|
44083
44816
|
function readDurableHeadSync(projectRoot) {
|
|
44084
44817
|
try {
|
|
44085
44818
|
const headPath = join23(projectRoot, ".zelari", "state", "HEAD.json");
|
|
44086
|
-
if (!
|
|
44819
|
+
if (!existsSync30(headPath)) return "";
|
|
44087
44820
|
const head = JSON.parse(readFileSync25(headPath, "utf8"));
|
|
44088
44821
|
if (!head?.id) return "";
|
|
44089
44822
|
const metaPath = join23(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
|
|
44090
|
-
if (!
|
|
44823
|
+
if (!existsSync30(metaPath)) return "";
|
|
44091
44824
|
const meta3 = JSON.parse(readFileSync25(metaPath, "utf8"));
|
|
44092
44825
|
const discPath = meta3.artifactDir ? join23(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join23(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
|
|
44093
44826
|
let discoveries = [];
|
|
44094
|
-
if (
|
|
44827
|
+
if (existsSync30(discPath)) {
|
|
44095
44828
|
discoveries = JSON.parse(readFileSync25(discPath, "utf8"));
|
|
44096
44829
|
}
|
|
44097
44830
|
const reusable = discoveries.filter((d) => d.reusable !== false);
|
|
@@ -44125,11 +44858,11 @@ var planDetect_exports = {};
|
|
|
44125
44858
|
__export(planDetect_exports, {
|
|
44126
44859
|
hasWorkspacePlan: () => hasWorkspacePlan
|
|
44127
44860
|
});
|
|
44128
|
-
import { existsSync as
|
|
44861
|
+
import { existsSync as existsSync31, readFileSync as readFileSync26 } from "node:fs";
|
|
44129
44862
|
import { join as join24 } from "node:path";
|
|
44130
44863
|
function hasWorkspacePlan(projectRoot = process.cwd()) {
|
|
44131
44864
|
const planPath = join24(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
44132
|
-
if (!
|
|
44865
|
+
if (!existsSync31(planPath)) return false;
|
|
44133
44866
|
try {
|
|
44134
44867
|
const parsed = JSON.parse(readFileSync26(planPath, "utf8"));
|
|
44135
44868
|
return Array.isArray(parsed.phases) && parsed.phases.length > 0;
|
|
@@ -44190,7 +44923,7 @@ __export(stubs_exports, {
|
|
|
44190
44923
|
resolveWorkspaceRoot: () => resolveWorkspaceRoot
|
|
44191
44924
|
});
|
|
44192
44925
|
import {
|
|
44193
|
-
existsSync as
|
|
44926
|
+
existsSync as existsSync32,
|
|
44194
44927
|
readdirSync as readdirSync8,
|
|
44195
44928
|
writeFileSync as writeFileSync17,
|
|
44196
44929
|
readFileSync as readFileSync27,
|
|
@@ -44211,7 +44944,7 @@ function planJsonPath(ctx) {
|
|
|
44211
44944
|
}
|
|
44212
44945
|
function readPlan(ctx) {
|
|
44213
44946
|
const jsonPath = planJsonPath(ctx);
|
|
44214
|
-
if (
|
|
44947
|
+
if (existsSync32(jsonPath)) {
|
|
44215
44948
|
try {
|
|
44216
44949
|
const parsed = JSON.parse(
|
|
44217
44950
|
readFileSync27(jsonPath, "utf8")
|
|
@@ -44321,7 +45054,7 @@ function renderPlanBody(summary) {
|
|
|
44321
45054
|
}
|
|
44322
45055
|
function nextAdrId(ctx) {
|
|
44323
45056
|
const decisionsDir = join25(ctx.rootDir, "decisions");
|
|
44324
|
-
if (!
|
|
45057
|
+
if (!existsSync32(decisionsDir)) return "001";
|
|
44325
45058
|
const existing = readdirSync8(decisionsDir).filter((f) => f.endsWith(".md")).map((f) => f.match(/^(\d+)-/)).filter((m) => !!m).map((m) => parseInt(m[1], 10));
|
|
44326
45059
|
const max = existing.length === 0 ? 0 : Math.max(...existing);
|
|
44327
45060
|
return String(max + 1).padStart(3, "0");
|
|
@@ -44777,7 +45510,7 @@ function searchDocumentsStub(ctx) {
|
|
|
44777
45510
|
];
|
|
44778
45511
|
const results = [];
|
|
44779
45512
|
for (const file2 of files) {
|
|
44780
|
-
if (!
|
|
45513
|
+
if (!existsSync32(file2)) continue;
|
|
44781
45514
|
const raw = readFileSync27(file2, "utf8");
|
|
44782
45515
|
const content = raw.toLowerCase();
|
|
44783
45516
|
let idx = -1;
|
|
@@ -44945,176 +45678,6 @@ var init_toolRegistry2 = __esm({
|
|
|
44945
45678
|
}
|
|
44946
45679
|
});
|
|
44947
45680
|
|
|
44948
|
-
// src/cli/updater.ts
|
|
44949
|
-
var updater_exports = {};
|
|
44950
|
-
__export(updater_exports, {
|
|
44951
|
-
REGISTRY_URL: () => REGISTRY_URL,
|
|
44952
|
-
checkForUpdate: () => checkForUpdate,
|
|
44953
|
-
compareSemver: () => compareSemver,
|
|
44954
|
-
distTagForVersion: () => distTagForVersion,
|
|
44955
|
-
fetchLatestVersion: () => fetchLatestVersion,
|
|
44956
|
-
getCurrentVersion: () => getCurrentVersion,
|
|
44957
|
-
looksLikeBrokenShim: () => looksLikeBrokenShim,
|
|
44958
|
-
performUpdate: () => performUpdate,
|
|
44959
|
-
registryUrlForTag: () => registryUrlForTag,
|
|
44960
|
-
resolveBundledNpmCli: () => resolveBundledNpmCli
|
|
44961
|
-
});
|
|
44962
|
-
import { createRequire as createRequire2 } from "node:module";
|
|
44963
|
-
import { spawn as spawn12 } from "node:child_process";
|
|
44964
|
-
import { existsSync as existsSync32 } from "node:fs";
|
|
44965
|
-
import path43 from "node:path";
|
|
44966
|
-
import { fileURLToPath } from "node:url";
|
|
44967
|
-
function resolveBundledNpmCli(execPath = process.execPath) {
|
|
44968
|
-
const dir = path43.dirname(execPath);
|
|
44969
|
-
const candidates = [
|
|
44970
|
-
// Windows: C:\...\node.exe → C:\...\node_modules\npm\bin\npm-cli.js
|
|
44971
|
-
path43.join(dir, "node_modules", "npm", "bin", "npm-cli.js"),
|
|
44972
|
-
// POSIX: <prefix>/bin/node → <prefix>/lib/node_modules/npm/bin/npm-cli.js
|
|
44973
|
-
path43.join(dir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
|
|
44974
|
-
];
|
|
44975
|
-
for (const candidate of candidates) {
|
|
44976
|
-
try {
|
|
44977
|
-
if (existsSync32(candidate)) return candidate;
|
|
44978
|
-
} catch {
|
|
44979
|
-
}
|
|
44980
|
-
}
|
|
44981
|
-
return null;
|
|
44982
|
-
}
|
|
44983
|
-
function looksLikeBrokenShim(exitCode, output) {
|
|
44984
|
-
if (exitCode === 127) return true;
|
|
44985
|
-
const h = output.toLowerCase();
|
|
44986
|
-
return h.includes("shim target not found") || h.includes("is not recognized");
|
|
44987
|
-
}
|
|
44988
|
-
function getCurrentVersion() {
|
|
44989
|
-
try {
|
|
44990
|
-
const pkgPath = path43.resolve(__dirname2, "..", "..", "package.json");
|
|
44991
|
-
const pkg = require2(pkgPath);
|
|
44992
|
-
return pkg.version;
|
|
44993
|
-
} catch {
|
|
44994
|
-
return "0.0.0";
|
|
44995
|
-
}
|
|
44996
|
-
}
|
|
44997
|
-
function compareSemver(a, b) {
|
|
44998
|
-
const parse3 = (v) => {
|
|
44999
|
-
const m = v.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
|
|
45000
|
-
if (!m) return [0, 0, 0, null];
|
|
45001
|
-
return [Number(m[1]), Number(m[2]), Number(m[3]), m[4] ?? null];
|
|
45002
|
-
};
|
|
45003
|
-
const [a1, a2, a3, aPre] = parse3(a);
|
|
45004
|
-
const [b1, b2, b3, bPre] = parse3(b);
|
|
45005
|
-
if (a1 !== b1) return a1 < b1 ? -1 : 1;
|
|
45006
|
-
if (a2 !== b2) return a2 < b2 ? -1 : 1;
|
|
45007
|
-
if (a3 !== b3) return a3 < b3 ? -1 : 1;
|
|
45008
|
-
if (aPre === bPre) return 0;
|
|
45009
|
-
if (aPre === null) return 1;
|
|
45010
|
-
if (bPre === null) return -1;
|
|
45011
|
-
return aPre < bPre ? -1 : 1;
|
|
45012
|
-
}
|
|
45013
|
-
function distTagForVersion(version2) {
|
|
45014
|
-
if (version2.includes("-alpha.")) return "alpha";
|
|
45015
|
-
if (version2.includes("-beta.")) return "beta";
|
|
45016
|
-
if (version2.includes("-next.")) return "next";
|
|
45017
|
-
return "latest";
|
|
45018
|
-
}
|
|
45019
|
-
function registryUrlForTag(tag = distTagForVersion(getCurrentVersion())) {
|
|
45020
|
-
return `https://registry.npmjs.org/zelari-code/${tag}`;
|
|
45021
|
-
}
|
|
45022
|
-
async function fetchLatestVersion(fetcher = fetch, registryUrl = REGISTRY_URL, timeoutMs2 = 5e3) {
|
|
45023
|
-
try {
|
|
45024
|
-
const controller = new AbortController();
|
|
45025
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs2);
|
|
45026
|
-
const response = await fetcher(registryUrl, { signal: controller.signal });
|
|
45027
|
-
clearTimeout(timer);
|
|
45028
|
-
if (!response.ok) {
|
|
45029
|
-
return { error: `Registry responded ${response.status}` };
|
|
45030
|
-
}
|
|
45031
|
-
const data = await response.json();
|
|
45032
|
-
if (!data.version || typeof data.version !== "string") {
|
|
45033
|
-
return { error: "Registry response missing version field" };
|
|
45034
|
-
}
|
|
45035
|
-
return { version: data.version };
|
|
45036
|
-
} catch (err) {
|
|
45037
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
45038
|
-
return { error: message };
|
|
45039
|
-
}
|
|
45040
|
-
}
|
|
45041
|
-
async function checkForUpdate(fetcher = fetch, registryUrl) {
|
|
45042
|
-
const currentVersion = getCurrentVersion();
|
|
45043
|
-
const url2 = registryUrl ?? registryUrlForTag();
|
|
45044
|
-
const latest = await fetchLatestVersion(fetcher, url2);
|
|
45045
|
-
if ("error" in latest) {
|
|
45046
|
-
return {
|
|
45047
|
-
currentVersion,
|
|
45048
|
-
latestVersion: currentVersion,
|
|
45049
|
-
updateAvailable: false,
|
|
45050
|
-
error: latest.error
|
|
45051
|
-
};
|
|
45052
|
-
}
|
|
45053
|
-
const cmp = compareSemver(currentVersion, latest.version);
|
|
45054
|
-
return {
|
|
45055
|
-
currentVersion,
|
|
45056
|
-
latestVersion: latest.version,
|
|
45057
|
-
updateAvailable: cmp < 0
|
|
45058
|
-
};
|
|
45059
|
-
}
|
|
45060
|
-
async function performUpdate(packageName = "zelari-code", executor = spawn12, resolveNpmCli = resolveBundledNpmCli, channel) {
|
|
45061
|
-
const tag = channel ?? distTagForVersion(getCurrentVersion());
|
|
45062
|
-
const args = ["install", "-g", `${packageName}@${tag}`];
|
|
45063
|
-
const primary = await runNpm(executor, args, "shim");
|
|
45064
|
-
if (primary.ok) return primary;
|
|
45065
|
-
const npmCli = resolveNpmCli();
|
|
45066
|
-
if (npmCli && looksLikeBrokenShim(primary.exitCode, primary.output)) {
|
|
45067
|
-
const fallback = await runNpm(executor, args, "bundled", npmCli);
|
|
45068
|
-
return {
|
|
45069
|
-
...fallback,
|
|
45070
|
-
output: `[update] npm shim failed (${primary.error ?? "exit " + primary.exitCode}); retried via bundled npm (${npmCli}).
|
|
45071
|
-
${fallback.output}`
|
|
45072
|
-
};
|
|
45073
|
-
}
|
|
45074
|
-
return primary;
|
|
45075
|
-
}
|
|
45076
|
-
function runNpm(executor, args, mode, npmCliPath) {
|
|
45077
|
-
return new Promise((resolve3) => {
|
|
45078
|
-
let stdout = "";
|
|
45079
|
-
let stderr = "";
|
|
45080
|
-
const stdio = ["ignore", "pipe", "pipe"];
|
|
45081
|
-
const child = mode === "bundled" && npmCliPath ? executor(process.execPath, [npmCliPath, ...args], { stdio }) : process.platform === "win32" ? executor(buildCmdLine("npm", args), { stdio, shell: true }) : executor("npm", args, { stdio });
|
|
45082
|
-
child.stdout?.on("data", (chunk) => {
|
|
45083
|
-
stdout += chunk.toString();
|
|
45084
|
-
});
|
|
45085
|
-
child.stderr?.on("data", (chunk) => {
|
|
45086
|
-
stderr += chunk.toString();
|
|
45087
|
-
});
|
|
45088
|
-
child.on("error", (err) => {
|
|
45089
|
-
resolve3({
|
|
45090
|
-
ok: false,
|
|
45091
|
-
output: stdout + stderr,
|
|
45092
|
-
error: err.message,
|
|
45093
|
-
exitCode: null
|
|
45094
|
-
});
|
|
45095
|
-
});
|
|
45096
|
-
child.on("close", (code) => {
|
|
45097
|
-
const ok = code === 0;
|
|
45098
|
-
resolve3({
|
|
45099
|
-
ok,
|
|
45100
|
-
output: stdout + stderr,
|
|
45101
|
-
error: ok ? void 0 : `npm exited with code ${code}`,
|
|
45102
|
-
exitCode: code
|
|
45103
|
-
});
|
|
45104
|
-
});
|
|
45105
|
-
});
|
|
45106
|
-
}
|
|
45107
|
-
var require2, __dirname2, REGISTRY_URL;
|
|
45108
|
-
var init_updater = __esm({
|
|
45109
|
-
"src/cli/updater.ts"() {
|
|
45110
|
-
"use strict";
|
|
45111
|
-
init_cmdline();
|
|
45112
|
-
require2 = createRequire2(import.meta.url);
|
|
45113
|
-
__dirname2 = path43.dirname(fileURLToPath(import.meta.url));
|
|
45114
|
-
REGISTRY_URL = "https://registry.npmjs.org/zelari-code/latest";
|
|
45115
|
-
}
|
|
45116
|
-
});
|
|
45117
|
-
|
|
45118
45681
|
// src/cli/mcp/mcpClient.ts
|
|
45119
45682
|
import { spawn as spawn13 } from "node:child_process";
|
|
45120
45683
|
var DEFAULT_REQUEST_TIMEOUT_MS, INIT_TIMEOUT_MS, MCP_PROTOCOL_VERSION, McpClient;
|
|
@@ -45784,7 +46347,7 @@ __export(agentsMd_exports, {
|
|
|
45784
46347
|
updateAgentsMd: () => updateAgentsMd
|
|
45785
46348
|
});
|
|
45786
46349
|
import { existsSync as existsSync35, readFileSync as readFileSync30, writeFileSync as writeFileSync19 } from "node:fs";
|
|
45787
|
-
import { createHash as
|
|
46350
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
45788
46351
|
import { join as join28 } from "node:path";
|
|
45789
46352
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
45790
46353
|
async function readPackageJson2(projectRoot) {
|
|
@@ -45999,7 +46562,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
45999
46562
|
return { changed: true, sections: changedSections };
|
|
46000
46563
|
}
|
|
46001
46564
|
function hash2(s) {
|
|
46002
|
-
return
|
|
46565
|
+
return createHash14("sha256").update(s).digest("hex").slice(0, 16);
|
|
46003
46566
|
}
|
|
46004
46567
|
var AUTO_SECTIONS, MARKER_OPEN, MARKER_CLOSE, GENERATORS;
|
|
46005
46568
|
var init_agentsMd = __esm({
|
|
@@ -51691,8 +52254,8 @@ function shouldRunGauntletHostLoop(opts) {
|
|
|
51691
52254
|
}
|
|
51692
52255
|
function budgetAwareGauntletGate(input) {
|
|
51693
52256
|
if (input.verdict === "PASS") return "proceed";
|
|
51694
|
-
if (input.toolCallsRemaining <= input.verificationReserve) return "finalize-verify";
|
|
51695
52257
|
if (input.toolCallsRemaining <= 0) return "hold";
|
|
52258
|
+
if (input.toolCallsRemaining <= input.verificationReserve) return "finalize-verify";
|
|
51696
52259
|
return "proceed";
|
|
51697
52260
|
}
|
|
51698
52261
|
var DEFAULT_MAX_PIECES, DEFAULT_MAX_ROUNDS, DEFAULT_MAX_PARALLEL2, DEFAULT_WALL_MS, GAUNTLET_PARENT_BLOCKED_TOOLS;
|
|
@@ -52162,7 +52725,8 @@ var init_schedule = __esm({
|
|
|
52162
52725
|
|
|
52163
52726
|
// src/cli/gauntlet/loop.ts
|
|
52164
52727
|
async function runGauntletLoop(args) {
|
|
52165
|
-
const { caps
|
|
52728
|
+
const { caps } = args;
|
|
52729
|
+
const deps = { ...args.deps, budgetGate: args.budgetGate ?? args.deps.budgetGate };
|
|
52166
52730
|
const pieces = args.pieces.slice(0, caps.maxPieces);
|
|
52167
52731
|
const started = (deps.now ?? Date.now)();
|
|
52168
52732
|
const results = [];
|
|
@@ -52229,6 +52793,21 @@ async function runGauntletLoop(args) {
|
|
|
52229
52793
|
builderError: built.error
|
|
52230
52794
|
});
|
|
52231
52795
|
winner = parseBlindWinner(criticized.result) ?? winner;
|
|
52796
|
+
if (last.kind !== "PASS") {
|
|
52797
|
+
const b = deps.budgetGate?.() ?? null;
|
|
52798
|
+
if (b) {
|
|
52799
|
+
const decision = budgetAwareGauntletGate({
|
|
52800
|
+
verdict: last.kind,
|
|
52801
|
+
toolCallsRemaining: b.remaining,
|
|
52802
|
+
verificationReserve: b.verificationReserve
|
|
52803
|
+
});
|
|
52804
|
+
if (decision === "hold") {
|
|
52805
|
+
gap = last.gap;
|
|
52806
|
+
break;
|
|
52807
|
+
}
|
|
52808
|
+
if (decision === "finalize-verify") break;
|
|
52809
|
+
}
|
|
52810
|
+
}
|
|
52232
52811
|
emitProgress({
|
|
52233
52812
|
phase: last.kind === "PASS" ? "settled" : last.kind === "BLOCKED" ? "blocked" : "repairing",
|
|
52234
52813
|
pieceId: piece.id,
|
|
@@ -52292,6 +52871,7 @@ var init_loop = __esm({
|
|
|
52292
52871
|
init_blind();
|
|
52293
52872
|
init_policy();
|
|
52294
52873
|
init_verdict2();
|
|
52874
|
+
init_policy();
|
|
52295
52875
|
init_prompts();
|
|
52296
52876
|
init_schedule();
|
|
52297
52877
|
init_events3();
|
|
@@ -52395,7 +52975,12 @@ async function runHeadlessGauntlet(opts, provider, model) {
|
|
|
52395
52975
|
type: "log",
|
|
52396
52976
|
message: `[gauntlet] ${decomposed.pieces.length} piece(s) from ${decomposed.source}${decomposed.error ? ` (${decomposed.error.slice(0, 80)})` : ""}`
|
|
52397
52977
|
});
|
|
52978
|
+
const budgetGate = () => {
|
|
52979
|
+
const lim = spine.resourceBudgetLimit();
|
|
52980
|
+
return lim ? { remaining: lim.remaining, verificationReserve: lim.verificationReserve } : null;
|
|
52981
|
+
};
|
|
52398
52982
|
const result = await runGauntletLoop({
|
|
52983
|
+
budgetGate,
|
|
52399
52984
|
pieces: decomposed.pieces,
|
|
52400
52985
|
caps,
|
|
52401
52986
|
deps: {
|
|
@@ -53470,7 +54055,7 @@ import {
|
|
|
53470
54055
|
} from "node:fs";
|
|
53471
54056
|
import { join as join38 } from "node:path";
|
|
53472
54057
|
import { homedir as homedir13 } from "node:os";
|
|
53473
|
-
import { createHash as
|
|
54058
|
+
import { createHash as createHash15, randomBytes as randomBytes5, timingSafeEqual } from "node:crypto";
|
|
53474
54059
|
function getZelariHome() {
|
|
53475
54060
|
return join38(homedir13(), ".zelari-code");
|
|
53476
54061
|
}
|
|
@@ -53546,8 +54131,8 @@ function loadOrCreateToken(explicit) {
|
|
|
53546
54131
|
}
|
|
53547
54132
|
function tokenMatches(expected, provided) {
|
|
53548
54133
|
if (!provided) return false;
|
|
53549
|
-
const a =
|
|
53550
|
-
const b =
|
|
54134
|
+
const a = createHash15("sha256").update(expected).digest();
|
|
54135
|
+
const b = createHash15("sha256").update(provided).digest();
|
|
53551
54136
|
try {
|
|
53552
54137
|
return timingSafeEqual(a, b);
|
|
53553
54138
|
} catch {
|
|
@@ -58143,13 +58728,13 @@ init_completionGate();
|
|
|
58143
58728
|
// src/cli/kraken/verificationBridge.ts
|
|
58144
58729
|
init_candidateRegistry();
|
|
58145
58730
|
init_completionGate();
|
|
58146
|
-
import { createHash as
|
|
58731
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
58147
58732
|
|
|
58148
58733
|
// src/cli/kraken/nativeVerification.ts
|
|
58149
58734
|
init_runtime2();
|
|
58150
58735
|
init_verification2();
|
|
58151
58736
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
58152
|
-
import
|
|
58737
|
+
import path42 from "node:path";
|
|
58153
58738
|
function nativePackEnabled(env = process.env) {
|
|
58154
58739
|
const v = env.ZELARI_VERIFY_PACK?.toLowerCase();
|
|
58155
58740
|
return v === "1" || v === "on" || v === "true";
|
|
@@ -58176,7 +58761,7 @@ function packTimeoutMs(env = process.env) {
|
|
|
58176
58761
|
}
|
|
58177
58762
|
async function readPackageScripts(cwd = process.cwd()) {
|
|
58178
58763
|
try {
|
|
58179
|
-
const raw = await readFile2(
|
|
58764
|
+
const raw = await readFile2(path42.join(cwd, "package.json"), "utf-8");
|
|
58180
58765
|
const parsed = JSON.parse(raw);
|
|
58181
58766
|
if (parsed && typeof parsed === "object" && typeof parsed.scripts === "object") {
|
|
58182
58767
|
return parsed.scripts;
|
|
@@ -58270,7 +58855,7 @@ function krakenResultsToContract(requiredChecks, results, now = Date.now()) {
|
|
|
58270
58855
|
return { criteria, results: verifications };
|
|
58271
58856
|
}
|
|
58272
58857
|
function sha256Hex2(input) {
|
|
58273
|
-
return
|
|
58858
|
+
return createHash12("sha256").update(input).digest("hex");
|
|
58274
58859
|
}
|
|
58275
58860
|
function matchNoteToToolTrace(note, trace) {
|
|
58276
58861
|
const n = normalize5(note);
|
|
@@ -58991,7 +59576,9 @@ async function buildModelContext(input) {
|
|
|
58991
59576
|
};
|
|
58992
59577
|
input.onCompactionMetric?.(compactionMetrics);
|
|
58993
59578
|
}
|
|
58994
|
-
if (input.resourceSnapshot
|
|
59579
|
+
if (input.resourceSnapshot && !history2.some(
|
|
59580
|
+
(m) => m.role === "system" && typeof m.content === "string" && m.content.startsWith("RESOURCE STATUS")
|
|
59581
|
+
)) {
|
|
58995
59582
|
history2 = [...history2, resourceStatusMessage(input.resourceSnapshot)];
|
|
58996
59583
|
}
|
|
58997
59584
|
if (requestSurface) {
|
|
@@ -59195,6 +59782,7 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
59195
59782
|
}
|
|
59196
59783
|
const cwd = process.cwd();
|
|
59197
59784
|
const requestSnapshot = getRequestSnapshotWithUsage(sessionId2);
|
|
59785
|
+
await writerRef.current?.spine?.beginResourceTurn();
|
|
59198
59786
|
const modelContext = await buildModelContext({
|
|
59199
59787
|
fallbackHistory: historyForModel,
|
|
59200
59788
|
session: writerRef.current?.spine ?? null,
|
|
@@ -59393,10 +59981,12 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
59393
59981
|
systemMessages = [{ role: "system", content: fallback }];
|
|
59394
59982
|
}
|
|
59395
59983
|
systemPrefixLen = systemMessages.length;
|
|
59396
|
-
const
|
|
59984
|
+
const perTurnEnv = envNumber(process.env.ZELARI_MAX_TOOL_CALLS, {
|
|
59397
59985
|
default: 25,
|
|
59398
59986
|
min: 1
|
|
59399
59987
|
});
|
|
59988
|
+
const sessionCap = writerRef.current?.spine?.resourceBudgetLimit();
|
|
59989
|
+
const maxToolCallsPerTurn = sessionCap ? Math.max(1, Math.min(perTurnEnv, sessionCap.maxToolCalls)) : perTurnEnv;
|
|
59400
59990
|
const maxToolLoopIterations = budget.maxToolLoopIterations;
|
|
59401
59991
|
const maxToolLoopHardCap = envNumber(process.env.ZELARI_MAX_TOOL_LOOP_HARD, {
|
|
59402
59992
|
default: 0,
|
|
@@ -59426,7 +60016,9 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
59426
60016
|
providerStream,
|
|
59427
60017
|
// 2.6 Phase 3: host-owned pre-dispatch resource gate via the spine
|
|
59428
60018
|
// mirror (doc section 11.3). Degrade-and-stop (null gate = allow).
|
|
59429
|
-
|
|
60019
|
+
// 2.6.1 (plan §13): argument-aware — bash is essential only when
|
|
60020
|
+
// the command is a test/typecheck/build/git-diff line.
|
|
60021
|
+
toolCallGate: (name, args) => writerRef.current?.spine?.gateResourceToolCall(name, args) ?? { allowed: true },
|
|
59430
60022
|
cwd,
|
|
59431
60023
|
maxToolCallsPerTurn,
|
|
59432
60024
|
maxToolLoopIterations,
|
|
@@ -59874,6 +60466,7 @@ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
|
|
|
59874
60466
|
setBusy(true);
|
|
59875
60467
|
const anchored = maybeAnchorShortAnswer(text);
|
|
59876
60468
|
const effectiveText = anchored ?? text;
|
|
60469
|
+
await writerRef.current?.spine?.beginResourceTurn();
|
|
59877
60470
|
const councilContext = await buildModelContext({
|
|
59878
60471
|
fallbackHistory: getHistory(),
|
|
59879
60472
|
session: writerRef.current?.spine ?? null,
|
|
@@ -60007,10 +60600,12 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
60007
60600
|
let streamContent = "";
|
|
60008
60601
|
let streamMemberId = null;
|
|
60009
60602
|
const streamScrub = createStreamScrubber(16);
|
|
60010
|
-
const
|
|
60603
|
+
const councilPerTurnEnv = envNumber(process.env.ZELARI_MAX_TOOL_CALLS, {
|
|
60011
60604
|
default: 15,
|
|
60012
60605
|
min: 1
|
|
60013
60606
|
});
|
|
60607
|
+
const councilSessionCap = writerRef.current?.spine?.resourceBudgetLimit();
|
|
60608
|
+
const councilMaxToolCalls = councilSessionCap ? Math.max(1, Math.min(councilPerTurnEnv, councilSessionCap.maxToolCalls)) : councilPerTurnEnv;
|
|
60014
60609
|
const councilMaxToolLoop = envNumber(
|
|
60015
60610
|
process.env.ZELARI_MAX_TOOL_LOOP_ITERATIONS,
|
|
60016
60611
|
{ default: 30, min: 1 }
|
|
@@ -65397,6 +65992,7 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
65397
65992
|
}
|
|
65398
65993
|
];
|
|
65399
65994
|
}
|
|
65995
|
+
await spine.beginResourceTurn();
|
|
65400
65996
|
const modelContext = await buildModelContext({
|
|
65401
65997
|
fallbackHistory: seededHistory.history,
|
|
65402
65998
|
session: spine.spine,
|
|
@@ -65443,7 +66039,9 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
65443
66039
|
// 2.6 Phase 3: host-owned pre-dispatch resource gate (doc section 11.3).
|
|
65444
66040
|
// Advisory by default; ZELARI_RESOURCE_ENFORCEMENT=protected enables the
|
|
65445
66041
|
// protected verification reserve. Degrade-and-stop (null gate = allow).
|
|
65446
|
-
|
|
66042
|
+
// 2.6.1 (plan §13): argument-aware — bash is essential only when the
|
|
66043
|
+
// command is a test/typecheck/build/git-diff line.
|
|
66044
|
+
toolCallGate: (name, args) => spine.gateResourceToolCall(name, args) ?? { allowed: true },
|
|
65447
66045
|
maxToolLoopIterations: maxToolLoop
|
|
65448
66046
|
});
|
|
65449
66047
|
let finalReason = "completed";
|
|
@@ -65755,6 +66353,7 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
65755
66353
|
description: tool.function.description,
|
|
65756
66354
|
parameters: tool.function.parameters
|
|
65757
66355
|
}));
|
|
66356
|
+
await spine.beginResourceTurn();
|
|
65758
66357
|
const councilContext = await buildModelContext({
|
|
65759
66358
|
fallbackHistory: seededHistory.history,
|
|
65760
66359
|
session: spine.spine,
|
|
@@ -65925,6 +66524,7 @@ async function runHeadlessZelari(opts, provider, model, providerStream) {
|
|
|
65925
66524
|
description: tool.function.description,
|
|
65926
66525
|
parameters: tool.function.parameters
|
|
65927
66526
|
}));
|
|
66527
|
+
await spine.beginResourceTurn();
|
|
65928
66528
|
const missionContext = await buildModelContext({
|
|
65929
66529
|
fallbackHistory: seededHistory.history,
|
|
65930
66530
|
session: spine.spine,
|
|
@@ -66094,6 +66694,28 @@ ${ragContext}` : slicePrompt;
|
|
|
66094
66694
|
if (completionOk) {
|
|
66095
66695
|
emit(`[zelari] slice completion ok`);
|
|
66096
66696
|
}
|
|
66697
|
+
try {
|
|
66698
|
+
const budget = spine.resourceBudgetSummary();
|
|
66699
|
+
if (budget && !completionOk) {
|
|
66700
|
+
const { evaluateResourceReserveGate: evaluateResourceReserveGate2 } = await Promise.resolve().then(() => (init_verification2(), verification_exports));
|
|
66701
|
+
const gated = evaluateResourceReserveGate2({
|
|
66702
|
+
evaluation: {
|
|
66703
|
+
verdict: "REPAIR_REQUIRED",
|
|
66704
|
+
summary: "headless slice completion",
|
|
66705
|
+
satisfied: [],
|
|
66706
|
+
unsatisfied: [],
|
|
66707
|
+
evidenceComplete: false,
|
|
66708
|
+
eventBackedEvidenceComplete: false
|
|
66709
|
+
},
|
|
66710
|
+
budget
|
|
66711
|
+
});
|
|
66712
|
+
if (gated.verdict === "BLOCKED") {
|
|
66713
|
+
emit("[zelari] completion BLOCKED: resource budget exhausted (non-PASS + zero remaining)");
|
|
66714
|
+
}
|
|
66715
|
+
spine.note("completion.resource_gate", { decision: gated.verdict, remaining: budget.toolCalls.remaining });
|
|
66716
|
+
}
|
|
66717
|
+
} catch {
|
|
66718
|
+
}
|
|
66097
66719
|
} catch {
|
|
66098
66720
|
}
|
|
66099
66721
|
if (synthesisText.trim()) {
|