zelari-code 2.6.0 → 2.6.1
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 +108 -6
- 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/resourceSnapshot.js +1 -0
- package/dist/cli/budget/resourceSnapshot.js.map +1 -1
- package/dist/cli/budget/restoreRuntime.js +41 -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 +15 -8
- package/dist/cli/headlessSpine.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +21 -7
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/main.bundled.js +900 -436
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/runHeadless.js +30 -1
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/sessionSpine.js +134 -10
- 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",
|
|
@@ -28373,6 +28376,8 @@ var init_types8 = __esm({
|
|
|
28373
28376
|
"resource.snapshot",
|
|
28374
28377
|
"resource.limit_reached",
|
|
28375
28378
|
"resource.reserve_entered",
|
|
28379
|
+
// 2.6.1 (closure plan §9): hard-limit overrun telemetry — state-only.
|
|
28380
|
+
"resource.overrun",
|
|
28376
28381
|
"note"
|
|
28377
28382
|
];
|
|
28378
28383
|
SessionEventEnvelopeSchema = external_exports.object({
|
|
@@ -28703,11 +28708,15 @@ function asNumber(value) {
|
|
|
28703
28708
|
function formatResourceSnapshot(data) {
|
|
28704
28709
|
const used = asNumber(data.toolCallsUsed) ?? 0;
|
|
28705
28710
|
const remaining = asNumber(data.toolCallsRemaining) ?? 0;
|
|
28711
|
+
const limit = asNumber(data.toolCallsLimit) ?? used + remaining;
|
|
28706
28712
|
const lines = [
|
|
28707
28713
|
"RESOURCE STATUS",
|
|
28708
|
-
`Tool calls: ${used} / ${
|
|
28714
|
+
`Tool calls: ${used} / ${limit}`,
|
|
28709
28715
|
`Remaining: ${remaining}`
|
|
28710
28716
|
];
|
|
28717
|
+
const overrun = asNumber(data.overrun);
|
|
28718
|
+
if (overrun !== void 0 && overrun > 0)
|
|
28719
|
+
lines.push(`Overrun: ${overrun}`);
|
|
28711
28720
|
const wall = asNumber(data.wallMsRemaining);
|
|
28712
28721
|
if (wall !== void 0)
|
|
28713
28722
|
lines.push(`Wall clock remaining: ${Math.max(0, Math.round(wall / 1e3))}s`);
|
|
@@ -29608,8 +29617,14 @@ function validateResourceAndContractEvents(events) {
|
|
|
29608
29617
|
}
|
|
29609
29618
|
lastToolCallsUsed = used;
|
|
29610
29619
|
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: `
|
|
29620
|
+
if (remaining !== Math.max(0, limit - used)) {
|
|
29621
|
+
violations.push({ code: "RESOURCE_REMAINING_COHERENT", seq: e.seq, message: `remaining(${remaining}) != max(0, limit(${limit}) - used(${used}))` });
|
|
29622
|
+
}
|
|
29623
|
+
const overrun = e.data.overrun;
|
|
29624
|
+
if (overrun !== void 0) {
|
|
29625
|
+
if (typeof overrun !== "number" || overrun < 0 || overrun !== Math.max(0, used - limit)) {
|
|
29626
|
+
violations.push({ code: "RESOURCE_OVERRUN_COHERENT", seq: e.seq, message: `overrun(${String(overrun)}) != max(0, used(${used}) - limit(${limit}))` });
|
|
29627
|
+
}
|
|
29613
29628
|
}
|
|
29614
29629
|
for (const key of ["verificationReserve", "repairReserve"]) {
|
|
29615
29630
|
const v = e.data[key];
|
|
@@ -29706,27 +29721,53 @@ function contractToCompactionFields(contract) {
|
|
|
29706
29721
|
function deriveInitialContract(userSeq, text) {
|
|
29707
29722
|
const lines = text.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
29708
29723
|
const stripped = lines.map((l) => l.replace(/^[-*]\s+/, ""));
|
|
29709
|
-
const
|
|
29710
|
-
const
|
|
29724
|
+
const acceptanceCriteria = [];
|
|
29725
|
+
const criterionLines = /* @__PURE__ */ new Set();
|
|
29726
|
+
stripped.forEach((line, i) => {
|
|
29727
|
+
const checkbox = CHECKBOX_CRITERION.exec(line);
|
|
29728
|
+
if (checkbox) {
|
|
29729
|
+
criterionLines.add(i);
|
|
29730
|
+
acceptanceCriteria.push({
|
|
29731
|
+
id: `ac-${acceptanceCriteria.length + 1}`,
|
|
29732
|
+
text: checkbox[2].trim(),
|
|
29733
|
+
source: "user",
|
|
29734
|
+
required: true
|
|
29735
|
+
});
|
|
29736
|
+
return;
|
|
29737
|
+
}
|
|
29738
|
+
const keyword = KEYWORD_CRITERION.exec(line);
|
|
29739
|
+
if (keyword) {
|
|
29740
|
+
criterionLines.add(i);
|
|
29741
|
+
const value = keyword[2].trim();
|
|
29742
|
+
const lead = keyword[1].toLowerCase();
|
|
29743
|
+
const hint = (lead === "verify" || lead === "test") && COMMAND_HINT.test(value) ? { kind: "command", value } : void 0;
|
|
29744
|
+
acceptanceCriteria.push({
|
|
29745
|
+
id: `ac-${acceptanceCriteria.length + 1}`,
|
|
29746
|
+
text: value,
|
|
29747
|
+
source: "user",
|
|
29748
|
+
required: true,
|
|
29749
|
+
...hint ? { verificationHint: hint } : {}
|
|
29750
|
+
});
|
|
29751
|
+
}
|
|
29752
|
+
});
|
|
29753
|
+
const isConstraint = (i) => !criterionLines.has(i) && CONSTRAINT_LEAD.test(stripped[i] ?? "");
|
|
29754
|
+
const constraints = stripped.map((text2, i) => ({ text: text2, i })).filter(({ i }) => isConstraint(i)).map(({ text: text2 }, i) => ({
|
|
29755
|
+
id: `uc-${i + 1}`,
|
|
29756
|
+
text: text2,
|
|
29757
|
+
source: "user",
|
|
29758
|
+
required: true
|
|
29759
|
+
}));
|
|
29760
|
+
const goalIdx = lines.findIndex((_, i) => !criterionLines.has(i) && !isConstraint(i));
|
|
29761
|
+
const goal = goalIdx >= 0 ? lines[goalIdx] : lines[0] ?? text.slice(0, 200);
|
|
29711
29762
|
return TaskContractSchema.parse({
|
|
29712
29763
|
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
|
-
})),
|
|
29764
|
+
goal,
|
|
29765
|
+
constraints,
|
|
29766
|
+
acceptanceCriteria,
|
|
29726
29767
|
source: { userSeq }
|
|
29727
29768
|
});
|
|
29728
29769
|
}
|
|
29729
|
-
var TaskConstraintSchema, TaskCriterionSchema, TaskContractSchema, TaskContractConflictError;
|
|
29770
|
+
var TaskConstraintSchema, TaskCriterionSchema, TaskContractSchema, TaskContractConflictError, CHECKBOX_CRITERION, KEYWORD_CRITERION, COMMAND_HINT, CONSTRAINT_LEAD;
|
|
29730
29771
|
var init_taskContract = __esm({
|
|
29731
29772
|
"packages/core/dist/session/taskContract.js"() {
|
|
29732
29773
|
"use strict";
|
|
@@ -29766,6 +29807,10 @@ var init_taskContract = __esm({
|
|
|
29766
29807
|
this.name = "TaskContractConflictError";
|
|
29767
29808
|
}
|
|
29768
29809
|
};
|
|
29810
|
+
CHECKBOX_CRITERION = /^\[([ xX])\]\s*(.+)$/;
|
|
29811
|
+
KEYWORD_CRITERION = /^(acceptance|criterion|criteria|verify|test|success)\s*[:#]\s*(.+)$/i;
|
|
29812
|
+
COMMAND_HINT = /^(npm|pnpm|yarn|bun|npx|node|vitest|jest|tsc|eslint|prettier|git)\b/;
|
|
29813
|
+
CONSTRAINT_LEAD = /^(do not|don't|never|no\s|non\s|without changing|keep|must not|avoid)\b/i;
|
|
29769
29814
|
}
|
|
29770
29815
|
});
|
|
29771
29816
|
|
|
@@ -30233,9 +30278,13 @@ function classifyHarnessChanges(diff) {
|
|
|
30233
30278
|
const hit = FIELD_CLASSES.find((m) => field === m.prefix || field.startsWith(m.prefix + "."));
|
|
30234
30279
|
byField[field] = hit ? hit.cls : "cosmetic";
|
|
30235
30280
|
}
|
|
30281
|
+
const changeSet = { structural: [], behavioral: [], cosmetic: [] };
|
|
30282
|
+
for (const field of diff.changed) {
|
|
30283
|
+
changeSet[byField[field]].push(field);
|
|
30284
|
+
}
|
|
30236
30285
|
const order = { behavioral: 3, structural: 2, cosmetic: 1 };
|
|
30237
30286
|
const overall = Object.values(byField).reduce((acc, cls) => order[cls] > order[acc] ? cls : acc, "cosmetic");
|
|
30238
|
-
return { overall, byField };
|
|
30287
|
+
return { overall, byField, changeSet };
|
|
30239
30288
|
}
|
|
30240
30289
|
var HARNESS_MANIFEST_SCHEMA_VERSION, HarnessPromptsSchema, HarnessManifestV1Schema, FIELD_CLASSES;
|
|
30241
30290
|
var init_harnessManifest = __esm({
|
|
@@ -30446,12 +30495,14 @@ var init_resourcePolicy = __esm({
|
|
|
30446
30495
|
|
|
30447
30496
|
// packages/core/dist/runtime/resourceBudget.js
|
|
30448
30497
|
function computeBudget(policy, usage, stage = "explore") {
|
|
30449
|
-
const used = Math.max(0,
|
|
30498
|
+
const used = Math.max(0, usage.toolCallsUsed);
|
|
30499
|
+
const overrun = Math.max(0, used - policy.maxToolCalls);
|
|
30450
30500
|
return {
|
|
30451
30501
|
toolCalls: {
|
|
30452
30502
|
limit: policy.maxToolCalls,
|
|
30453
30503
|
used,
|
|
30454
|
-
remaining: policy.maxToolCalls - used
|
|
30504
|
+
remaining: Math.max(0, policy.maxToolCalls - used),
|
|
30505
|
+
overrun
|
|
30455
30506
|
},
|
|
30456
30507
|
wallTime: {
|
|
30457
30508
|
limitMs: policy.wallClockMs,
|
|
@@ -31465,6 +31516,48 @@ var init_resourceReserveGate = __esm({
|
|
|
31465
31516
|
});
|
|
31466
31517
|
|
|
31467
31518
|
// packages/core/dist/verification/index.js
|
|
31519
|
+
var verification_exports = {};
|
|
31520
|
+
__export(verification_exports, {
|
|
31521
|
+
BonConfigSchema: () => BonConfigSchema,
|
|
31522
|
+
CommandCheckSchema: () => CommandCheckSchema,
|
|
31523
|
+
CriterionSchema: () => CriterionSchema,
|
|
31524
|
+
CriterionSourceSchema: () => CriterionSourceSchema,
|
|
31525
|
+
DEFAULT_VERIFIER_CONFIG: () => DEFAULT_VERIFIER_CONFIG,
|
|
31526
|
+
DETERMINISTIC_EVIDENCE_TIERS: () => DETERMINISTIC_EVIDENCE_TIERS,
|
|
31527
|
+
DeterministicCheckSchema: () => DeterministicCheckSchema,
|
|
31528
|
+
EVENT_BACKED_EVIDENCE_TIERS: () => EVENT_BACKED_EVIDENCE_TIERS,
|
|
31529
|
+
EvidenceRefSchema: () => EvidenceRefSchema,
|
|
31530
|
+
EvidenceTierSchema: () => EvidenceTierSchema,
|
|
31531
|
+
FileAbsentCheckSchema: () => FileAbsentCheckSchema,
|
|
31532
|
+
FileContainsCheckSchema: () => FileContainsCheckSchema,
|
|
31533
|
+
FileExistsCheckSchema: () => FileExistsCheckSchema,
|
|
31534
|
+
ModelSelectionSchema: () => ModelSelectionSchema,
|
|
31535
|
+
NoneCheckSchema: () => NoneCheckSchema,
|
|
31536
|
+
STRICT_ALL_POLICY: () => STRICT_ALL_POLICY,
|
|
31537
|
+
STRICT_BUILD_POLICY: () => STRICT_BUILD_POLICY,
|
|
31538
|
+
VerificationEngine: () => VerificationEngine,
|
|
31539
|
+
VerificationResultSchema: () => VerificationResultSchema,
|
|
31540
|
+
VerificationSourceSchema: () => VerificationSourceSchema,
|
|
31541
|
+
VerificationStatusSchema: () => VerificationStatusSchema,
|
|
31542
|
+
VerifierConfigSchema: () => VerifierConfigSchema,
|
|
31543
|
+
VerifierService: () => VerifierService,
|
|
31544
|
+
ZELARI_CODING_PACK_ID: () => ZELARI_CODING_PACK_ID,
|
|
31545
|
+
analyzeScope: () => analyzeScope,
|
|
31546
|
+
codingCriteriaPack: () => codingCriteriaPack,
|
|
31547
|
+
computeFalseDoneRate: () => computeFalseDoneRate,
|
|
31548
|
+
costPerVerifiedSolve: () => costPerVerifiedSolve,
|
|
31549
|
+
evaluateCompletion: () => evaluateCompletion,
|
|
31550
|
+
evaluateResourceReserveGate: () => evaluateResourceReserveGate,
|
|
31551
|
+
isEventBackedEvidence: () => isEventBackedEvidence,
|
|
31552
|
+
isGeneratedPath: () => isGeneratedPath,
|
|
31553
|
+
lastVerificationRun: () => lastVerificationRun,
|
|
31554
|
+
parseNameOnlyDiff: () => parseNameOnlyDiff,
|
|
31555
|
+
parseVerificationRunPayload: () => parseVerificationRunPayload,
|
|
31556
|
+
snapshotToCompletionEvaluation: () => snapshotToCompletionEvaluation,
|
|
31557
|
+
strictBuildGate: () => strictBuildGate,
|
|
31558
|
+
verificationCostRatio: () => verificationCostRatio,
|
|
31559
|
+
verifiedSolveRate: () => verifiedSolveRate
|
|
31560
|
+
});
|
|
31468
31561
|
var init_verification2 = __esm({
|
|
31469
31562
|
"packages/core/dist/verification/index.js"() {
|
|
31470
31563
|
"use strict";
|
|
@@ -31621,6 +31714,42 @@ var init_mission2 = __esm({
|
|
|
31621
31714
|
}
|
|
31622
31715
|
});
|
|
31623
31716
|
|
|
31717
|
+
// packages/core/dist/version.js
|
|
31718
|
+
var CORE_VERSION;
|
|
31719
|
+
var init_version = __esm({
|
|
31720
|
+
"packages/core/dist/version.js"() {
|
|
31721
|
+
"use strict";
|
|
31722
|
+
CORE_VERSION = "2.6.1";
|
|
31723
|
+
}
|
|
31724
|
+
});
|
|
31725
|
+
|
|
31726
|
+
// packages/core/dist/runtime/fingerprints.js
|
|
31727
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
31728
|
+
function toolFingerprintHash(tools) {
|
|
31729
|
+
const canonical = [...tools].map((t) => ({
|
|
31730
|
+
name: t.name,
|
|
31731
|
+
...t.description !== void 0 ? { description: t.description } : {},
|
|
31732
|
+
...t.inputSchema !== void 0 ? { inputSchema: t.inputSchema } : {},
|
|
31733
|
+
...t.outputContractVersion !== void 0 ? { outputContractVersion: t.outputContractVersion } : {},
|
|
31734
|
+
...t.capabilityFlags !== void 0 ? { capabilityFlags: [...t.capabilityFlags].sort() } : {}
|
|
31735
|
+
})).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
31736
|
+
return createHash6("sha256").update(stableStringify(canonical)).digest("hex");
|
|
31737
|
+
}
|
|
31738
|
+
function skillFingerprintHash(skills) {
|
|
31739
|
+
const canonical = [...skills].map((s) => ({
|
|
31740
|
+
id: s.id,
|
|
31741
|
+
...s.version !== void 0 ? { version: s.version } : {},
|
|
31742
|
+
...s.contentDigest !== void 0 ? { contentDigest: s.contentDigest } : {}
|
|
31743
|
+
})).sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
31744
|
+
return createHash6("sha256").update(stableStringify(canonical)).digest("hex");
|
|
31745
|
+
}
|
|
31746
|
+
var init_fingerprints = __esm({
|
|
31747
|
+
"packages/core/dist/runtime/fingerprints.js"() {
|
|
31748
|
+
"use strict";
|
|
31749
|
+
init_requestSnapshot();
|
|
31750
|
+
}
|
|
31751
|
+
});
|
|
31752
|
+
|
|
31624
31753
|
// packages/core/dist/index.js
|
|
31625
31754
|
var dist_exports = {};
|
|
31626
31755
|
__export(dist_exports, {
|
|
@@ -31642,6 +31771,7 @@ __export(dist_exports, {
|
|
|
31642
31771
|
CODING_SKILL_CATALOG: () => CODING_SKILL_CATALOG,
|
|
31643
31772
|
COLLABORATION_DIRECTIVE: () => COLLABORATION_DIRECTIVE,
|
|
31644
31773
|
COMPOSITOR_ONLY_PROPS: () => COMPOSITOR_ONLY_PROPS,
|
|
31774
|
+
CORE_VERSION: () => CORE_VERSION,
|
|
31645
31775
|
COUNCIL_V1: () => COUNCIL_V1,
|
|
31646
31776
|
CommandCheckSchema: () => CommandCheckSchema,
|
|
31647
31777
|
CriterionSchema: () => CriterionSchema,
|
|
@@ -31986,6 +32116,7 @@ __export(dist_exports, {
|
|
|
31986
32116
|
shadowedSeqSet: () => shadowedSeqSet,
|
|
31987
32117
|
shouldRetryMember: () => shouldRetryMember,
|
|
31988
32118
|
sideEffectForTool: () => sideEffectForTool,
|
|
32119
|
+
skillFingerprintHash: () => skillFingerprintHash,
|
|
31989
32120
|
slugify: () => slugify2,
|
|
31990
32121
|
snapshotToCompletionEvaluation: () => snapshotToCompletionEvaluation,
|
|
31991
32122
|
specificityFromAssumptions: () => specificityFromAssumptions,
|
|
@@ -31997,6 +32128,7 @@ __export(dist_exports, {
|
|
|
31997
32128
|
taskMatchesNfrKeywords: () => taskMatchesNfrKeywords,
|
|
31998
32129
|
tierAtLeast: () => tierAtLeast,
|
|
31999
32130
|
tokenizeForSignature: () => tokenizeForSignature,
|
|
32131
|
+
toolFingerprintHash: () => toolFingerprintHash,
|
|
32000
32132
|
toolManifestHash: () => toolManifestHash,
|
|
32001
32133
|
toolMatches: () => toolMatches,
|
|
32002
32134
|
topoLevels: () => topoLevels,
|
|
@@ -32035,6 +32167,8 @@ var init_dist = __esm({
|
|
|
32035
32167
|
init_verification2();
|
|
32036
32168
|
init_mission2();
|
|
32037
32169
|
init_experimental();
|
|
32170
|
+
init_version();
|
|
32171
|
+
init_fingerprints();
|
|
32038
32172
|
}
|
|
32039
32173
|
});
|
|
32040
32174
|
|
|
@@ -32367,6 +32501,7 @@ function buildResourceSnapshot(budget, policy) {
|
|
|
32367
32501
|
toolCallsLimit: budget.toolCalls.limit,
|
|
32368
32502
|
toolCallsUsed: budget.toolCalls.used,
|
|
32369
32503
|
toolCallsRemaining: budget.toolCalls.remaining,
|
|
32504
|
+
overrun: budget.toolCalls.overrun,
|
|
32370
32505
|
...budget.wallTime.remainingMs !== void 0 ? { wallMsRemaining: budget.wallTime.remainingMs } : {},
|
|
32371
32506
|
verificationReserve: budget.reserve.verification,
|
|
32372
32507
|
repairReserve: budget.reserve.repair,
|
|
@@ -32394,7 +32529,29 @@ var init_resourceSnapshot = __esm({
|
|
|
32394
32529
|
function resolveResourceEnforcement(env = process.env) {
|
|
32395
32530
|
return env.ZELARI_RESOURCE_ENFORCEMENT === "protected" ? "protected" : "advisory";
|
|
32396
32531
|
}
|
|
32397
|
-
|
|
32532
|
+
function bashCommand(args) {
|
|
32533
|
+
if (!args || typeof args !== "object") return "";
|
|
32534
|
+
const rec = args;
|
|
32535
|
+
for (const key of ["command", "cmd", "script"]) {
|
|
32536
|
+
if (typeof rec[key] === "string") return rec[key];
|
|
32537
|
+
}
|
|
32538
|
+
return "";
|
|
32539
|
+
}
|
|
32540
|
+
function isVerificationEssential(toolName, args, _stage = "implement") {
|
|
32541
|
+
if (toolName === "bash") {
|
|
32542
|
+
const cmd = bashCommand(args);
|
|
32543
|
+
if (!cmd) return false;
|
|
32544
|
+
return ESSENTIAL_BASH.some((re) => re.test(cmd));
|
|
32545
|
+
}
|
|
32546
|
+
if (toolName === "grep_content") {
|
|
32547
|
+
if (!args || typeof args !== "object") return true;
|
|
32548
|
+
const rec = args;
|
|
32549
|
+
const hasScope = typeof rec.path === "string" && rec.path !== "." && rec.path !== "./";
|
|
32550
|
+
return hasScope || typeof rec.pattern === "string";
|
|
32551
|
+
}
|
|
32552
|
+
return DEFAULT_ESSENTIAL_TOOLS.includes(toolName);
|
|
32553
|
+
}
|
|
32554
|
+
var DEFAULT_ESSENTIAL_TOOLS, ADVISORY_NOTICE, PROTECTED_DENIAL, HARD_LIMIT_DENIAL, ESSENTIAL_BASH, BudgetRuntime;
|
|
32398
32555
|
var init_budgetRuntime = __esm({
|
|
32399
32556
|
"src/cli/budget/budgetRuntime.ts"() {
|
|
32400
32557
|
"use strict";
|
|
@@ -32402,7 +32559,6 @@ var init_budgetRuntime = __esm({
|
|
|
32402
32559
|
init_resourceLedger();
|
|
32403
32560
|
init_resourceSnapshot();
|
|
32404
32561
|
DEFAULT_ESSENTIAL_TOOLS = [
|
|
32405
|
-
"bash",
|
|
32406
32562
|
"read_file",
|
|
32407
32563
|
"edit_file",
|
|
32408
32564
|
"write_file",
|
|
@@ -32413,6 +32569,17 @@ var init_budgetRuntime = __esm({
|
|
|
32413
32569
|
];
|
|
32414
32570
|
ADVISORY_NOTICE = "Resource advisory: verification reserve reached. Prioritize test/typecheck/build/diff and targeted repair; avoid broad exploration or delegation.";
|
|
32415
32571
|
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.";
|
|
32572
|
+
HARD_LIMIT_DENIAL = "Resource exhausted: the session tool budget (maxToolCalls) is spent. No further billable tool calls are allowed \u2014 summarize what was verified and report BLOCKED/resource-exhausted with the evidence already collected.";
|
|
32573
|
+
ESSENTIAL_BASH = [
|
|
32574
|
+
/\b(npm|pnpm|yarn|bun)\s+(run\s+)?(test|vitest|jest)\b/,
|
|
32575
|
+
/\b(npm|pnpm|yarn|bun)\s+run\s+[\w:-]*(typecheck|lint|build)\b/,
|
|
32576
|
+
/\bnpx\s+(vitest|tsc|typescript|eslint)\b/,
|
|
32577
|
+
/\b(npx\s+)?tsc\b/,
|
|
32578
|
+
/\bvitest\b/,
|
|
32579
|
+
/\bjest\b/,
|
|
32580
|
+
/\bnode\s+--run\b/,
|
|
32581
|
+
/\bgit\s+(diff|status|log|show)\b/
|
|
32582
|
+
];
|
|
32416
32583
|
BudgetRuntime = class {
|
|
32417
32584
|
policy;
|
|
32418
32585
|
enforcement;
|
|
@@ -32420,8 +32587,11 @@ var init_budgetRuntime = __esm({
|
|
|
32420
32587
|
essential;
|
|
32421
32588
|
stage;
|
|
32422
32589
|
lastEmitted;
|
|
32590
|
+
hardLimitAnnounced = false;
|
|
32423
32591
|
constructor(profileId, opts = {}) {
|
|
32424
|
-
|
|
32592
|
+
const basePolicy = opts.policy ?? defaultResourcePolicy(profileId);
|
|
32593
|
+
const envCap = Number.parseInt(process.env.ZELARI_MAX_TOOL_CALLS ?? "", 10);
|
|
32594
|
+
this.policy = Number.isFinite(envCap) && envCap >= 1 ? { ...basePolicy, maxToolCalls: envCap } : basePolicy;
|
|
32425
32595
|
this.enforcement = opts.enforcement ?? "advisory";
|
|
32426
32596
|
this.essential = new Set(opts.essentialTools ?? DEFAULT_ESSENTIAL_TOOLS);
|
|
32427
32597
|
this.stage = opts.stage ?? "implement";
|
|
@@ -32432,8 +32602,27 @@ var init_budgetRuntime = __esm({
|
|
|
32432
32602
|
* (first sight, stage/pressure change, reserve crossing, any usage delta).
|
|
32433
32603
|
*/
|
|
32434
32604
|
noteToolCall() {
|
|
32605
|
+
return this.consumeToolCall().snapshot;
|
|
32606
|
+
}
|
|
32607
|
+
/**
|
|
32608
|
+
* 2.6.1 (plan §9): count one tool call AND surface the hard-limit event
|
|
32609
|
+
* due on this call — `resource.limit_reached` once at the crossing,
|
|
32610
|
+
* `resource.overrun` for every call past the limit. The spine appends the
|
|
32611
|
+
* event right after its tool.call.
|
|
32612
|
+
*/
|
|
32613
|
+
consumeToolCall() {
|
|
32435
32614
|
this.ledger.record("tool-call");
|
|
32436
|
-
|
|
32615
|
+
const next = this.current();
|
|
32616
|
+
let hardEvent = null;
|
|
32617
|
+
const data = { used: next.toolCallsUsed, limit: next.toolCallsLimit, overrun: next.overrun };
|
|
32618
|
+
if (!this.hardLimitAnnounced && next.toolCallsRemaining <= 0) {
|
|
32619
|
+
this.hardLimitAnnounced = true;
|
|
32620
|
+
hardEvent = { kind: "resource.limit_reached", data };
|
|
32621
|
+
} else if (next.overrun > 0) {
|
|
32622
|
+
hardEvent = { kind: "resource.overrun", data };
|
|
32623
|
+
}
|
|
32624
|
+
const snapshot = shouldEmitSnapshot(this.lastEmitted, next) ? (this.lastEmitted = next, next) : null;
|
|
32625
|
+
return { snapshot, hardEvent };
|
|
32437
32626
|
}
|
|
32438
32627
|
/** §10.4 verification start: stage change (and a zero-cost ledger mark). */
|
|
32439
32628
|
noteVerificationStart() {
|
|
@@ -32450,18 +32639,31 @@ var init_budgetRuntime = __esm({
|
|
|
32450
32639
|
this.stage = stage;
|
|
32451
32640
|
return this.emitIfDue();
|
|
32452
32641
|
}
|
|
32642
|
+
/** 2.6.1 (plan §14): canonical budget for the reserve gate. */
|
|
32643
|
+
budgetSnapshot() {
|
|
32644
|
+
return this.ledger.budget(this.policy, this.stage);
|
|
32645
|
+
}
|
|
32453
32646
|
/** Current projection without emitting. */
|
|
32454
32647
|
current() {
|
|
32455
32648
|
return buildResourceSnapshot(this.ledger.budget(this.policy, this.stage), this.policy);
|
|
32456
32649
|
}
|
|
32457
|
-
/**
|
|
32458
|
-
|
|
32650
|
+
/**
|
|
32651
|
+
* §11.3 gate — argument-aware (2.6.1 §13). Hard limit denies first in BOTH
|
|
32652
|
+
* modes; advisory mode never blocks inside the protected zone; protected
|
|
32653
|
+
* mode guards the zone with isVerificationEssential(tool, args).
|
|
32654
|
+
*/
|
|
32655
|
+
gateToolCall(toolNameOrInput) {
|
|
32656
|
+
const input = typeof toolNameOrInput === "string" ? { toolName: toolNameOrInput } : toolNameOrInput;
|
|
32459
32657
|
const snapshot = this.current();
|
|
32658
|
+
if (snapshot.toolCallsRemaining <= 0) {
|
|
32659
|
+
return { allowed: false, advisory: false, reason: HARD_LIMIT_DENIAL, snapshot, hardLimit: true };
|
|
32660
|
+
}
|
|
32460
32661
|
if (!snapshot.reserveProtected) return { allowed: true, advisory: false, snapshot };
|
|
32461
32662
|
if (this.enforcement === "advisory") {
|
|
32462
32663
|
return { allowed: true, advisory: true, reason: ADVISORY_NOTICE, snapshot };
|
|
32463
32664
|
}
|
|
32464
|
-
|
|
32665
|
+
const essential = input.toolName === "bash" || input.toolName === "grep_content" ? isVerificationEssential(input.toolName, input.args, input.stage ?? this.stage) : this.essential.has(input.toolName);
|
|
32666
|
+
if (essential) {
|
|
32465
32667
|
return { allowed: true, advisory: true, reason: ADVISORY_NOTICE, snapshot };
|
|
32466
32668
|
}
|
|
32467
32669
|
return { allowed: false, advisory: false, reason: PROTECTED_DENIAL, snapshot };
|
|
@@ -32471,6 +32673,8 @@ var init_budgetRuntime = __esm({
|
|
|
32471
32673
|
const rebuilt = rebuildLedgerFromEvents(events);
|
|
32472
32674
|
this.ledger.resetTo(rebuilt.snapshot());
|
|
32473
32675
|
this.lastEmitted = void 0;
|
|
32676
|
+
const now = this.current();
|
|
32677
|
+
this.hardLimitAnnounced = now.toolCallsRemaining <= 0;
|
|
32474
32678
|
}
|
|
32475
32679
|
/** Latest emitted snapshot (what the model surface shows), if any. */
|
|
32476
32680
|
latestEmitted() {
|
|
@@ -32488,8 +32692,293 @@ var init_budgetRuntime = __esm({
|
|
|
32488
32692
|
}
|
|
32489
32693
|
});
|
|
32490
32694
|
|
|
32491
|
-
// src/cli/
|
|
32695
|
+
// src/cli/budget/restoreRuntime.ts
|
|
32492
32696
|
import path21 from "node:path";
|
|
32697
|
+
async function restoreBudgetRuntimeFromSession(budget, sessionId2, baseDir) {
|
|
32698
|
+
const eventsPath = path21.join(resolveSessionsDir({ baseDir }), sessionId2, "events.jsonl");
|
|
32699
|
+
const report = await readSessionLog(eventsPath).catch(() => null);
|
|
32700
|
+
if (!report || report.events.length === 0) return false;
|
|
32701
|
+
budget.adoptLedgerFromEvents(report.events);
|
|
32702
|
+
return true;
|
|
32703
|
+
}
|
|
32704
|
+
async function lastHarnessManifestHash(sessionId2, baseDir) {
|
|
32705
|
+
const eventsPath = path21.join(resolveSessionsDir({ baseDir }), sessionId2, "events.jsonl");
|
|
32706
|
+
const report = await readSessionLog(eventsPath).catch(() => null);
|
|
32707
|
+
if (!report) return null;
|
|
32708
|
+
for (let i = report.events.length - 1; i >= 0; i--) {
|
|
32709
|
+
const e = report.events[i];
|
|
32710
|
+
if (e.kind === "session.harness_manifest") {
|
|
32711
|
+
const h = e.data.manifestHash;
|
|
32712
|
+
return typeof h === "string" ? h : null;
|
|
32713
|
+
}
|
|
32714
|
+
}
|
|
32715
|
+
return null;
|
|
32716
|
+
}
|
|
32717
|
+
var init_restoreRuntime = __esm({
|
|
32718
|
+
"src/cli/budget/restoreRuntime.ts"() {
|
|
32719
|
+
"use strict";
|
|
32720
|
+
init_session();
|
|
32721
|
+
}
|
|
32722
|
+
});
|
|
32723
|
+
|
|
32724
|
+
// src/cli/utils/cmdline.ts
|
|
32725
|
+
function quoteCmdArg(arg) {
|
|
32726
|
+
if (arg === "") return '""';
|
|
32727
|
+
if (!/[\s"^&|<>()%!]/.test(arg)) return arg;
|
|
32728
|
+
return `"${arg.replace(/"/g, '""')}"`;
|
|
32729
|
+
}
|
|
32730
|
+
function buildCmdLine(command, args) {
|
|
32731
|
+
return [command, ...args].map(quoteCmdArg).join(" ");
|
|
32732
|
+
}
|
|
32733
|
+
var init_cmdline = __esm({
|
|
32734
|
+
"src/cli/utils/cmdline.ts"() {
|
|
32735
|
+
"use strict";
|
|
32736
|
+
}
|
|
32737
|
+
});
|
|
32738
|
+
|
|
32739
|
+
// src/cli/updater.ts
|
|
32740
|
+
var updater_exports = {};
|
|
32741
|
+
__export(updater_exports, {
|
|
32742
|
+
REGISTRY_URL: () => REGISTRY_URL,
|
|
32743
|
+
checkForUpdate: () => checkForUpdate,
|
|
32744
|
+
compareSemver: () => compareSemver,
|
|
32745
|
+
distTagForVersion: () => distTagForVersion,
|
|
32746
|
+
fetchLatestVersion: () => fetchLatestVersion,
|
|
32747
|
+
getCurrentVersion: () => getCurrentVersion,
|
|
32748
|
+
looksLikeBrokenShim: () => looksLikeBrokenShim,
|
|
32749
|
+
performUpdate: () => performUpdate,
|
|
32750
|
+
registryUrlForTag: () => registryUrlForTag,
|
|
32751
|
+
resolveBundledNpmCli: () => resolveBundledNpmCli
|
|
32752
|
+
});
|
|
32753
|
+
import { createRequire } from "node:module";
|
|
32754
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
32755
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
32756
|
+
import path22 from "node:path";
|
|
32757
|
+
import { fileURLToPath } from "node:url";
|
|
32758
|
+
function resolveBundledNpmCli(execPath = process.execPath) {
|
|
32759
|
+
const dir = path22.dirname(execPath);
|
|
32760
|
+
const candidates = [
|
|
32761
|
+
// Windows: C:\...\node.exe → C:\...\node_modules\npm\bin\npm-cli.js
|
|
32762
|
+
path22.join(dir, "node_modules", "npm", "bin", "npm-cli.js"),
|
|
32763
|
+
// POSIX: <prefix>/bin/node → <prefix>/lib/node_modules/npm/bin/npm-cli.js
|
|
32764
|
+
path22.join(dir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
|
|
32765
|
+
];
|
|
32766
|
+
for (const candidate of candidates) {
|
|
32767
|
+
try {
|
|
32768
|
+
if (existsSync11(candidate)) return candidate;
|
|
32769
|
+
} catch {
|
|
32770
|
+
}
|
|
32771
|
+
}
|
|
32772
|
+
return null;
|
|
32773
|
+
}
|
|
32774
|
+
function looksLikeBrokenShim(exitCode, output) {
|
|
32775
|
+
if (exitCode === 127) return true;
|
|
32776
|
+
const h = output.toLowerCase();
|
|
32777
|
+
return h.includes("shim target not found") || h.includes("is not recognized");
|
|
32778
|
+
}
|
|
32779
|
+
function getCurrentVersion() {
|
|
32780
|
+
try {
|
|
32781
|
+
const pkgPath = path22.resolve(__dirname2, "..", "..", "package.json");
|
|
32782
|
+
const pkg = require2(pkgPath);
|
|
32783
|
+
return pkg.version;
|
|
32784
|
+
} catch {
|
|
32785
|
+
return "0.0.0";
|
|
32786
|
+
}
|
|
32787
|
+
}
|
|
32788
|
+
function compareSemver(a, b) {
|
|
32789
|
+
const parse3 = (v) => {
|
|
32790
|
+
const m = v.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
|
|
32791
|
+
if (!m) return [0, 0, 0, null];
|
|
32792
|
+
return [Number(m[1]), Number(m[2]), Number(m[3]), m[4] ?? null];
|
|
32793
|
+
};
|
|
32794
|
+
const [a1, a2, a3, aPre] = parse3(a);
|
|
32795
|
+
const [b1, b2, b3, bPre] = parse3(b);
|
|
32796
|
+
if (a1 !== b1) return a1 < b1 ? -1 : 1;
|
|
32797
|
+
if (a2 !== b2) return a2 < b2 ? -1 : 1;
|
|
32798
|
+
if (a3 !== b3) return a3 < b3 ? -1 : 1;
|
|
32799
|
+
if (aPre === bPre) return 0;
|
|
32800
|
+
if (aPre === null) return 1;
|
|
32801
|
+
if (bPre === null) return -1;
|
|
32802
|
+
return aPre < bPre ? -1 : 1;
|
|
32803
|
+
}
|
|
32804
|
+
function distTagForVersion(version2) {
|
|
32805
|
+
if (version2.includes("-alpha.")) return "alpha";
|
|
32806
|
+
if (version2.includes("-beta.")) return "beta";
|
|
32807
|
+
if (version2.includes("-next.")) return "next";
|
|
32808
|
+
return "latest";
|
|
32809
|
+
}
|
|
32810
|
+
function registryUrlForTag(tag = distTagForVersion(getCurrentVersion())) {
|
|
32811
|
+
return `https://registry.npmjs.org/zelari-code/${tag}`;
|
|
32812
|
+
}
|
|
32813
|
+
async function fetchLatestVersion(fetcher = fetch, registryUrl = REGISTRY_URL, timeoutMs2 = 5e3) {
|
|
32814
|
+
try {
|
|
32815
|
+
const controller = new AbortController();
|
|
32816
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs2);
|
|
32817
|
+
const response = await fetcher(registryUrl, { signal: controller.signal });
|
|
32818
|
+
clearTimeout(timer);
|
|
32819
|
+
if (!response.ok) {
|
|
32820
|
+
return { error: `Registry responded ${response.status}` };
|
|
32821
|
+
}
|
|
32822
|
+
const data = await response.json();
|
|
32823
|
+
if (!data.version || typeof data.version !== "string") {
|
|
32824
|
+
return { error: "Registry response missing version field" };
|
|
32825
|
+
}
|
|
32826
|
+
return { version: data.version };
|
|
32827
|
+
} catch (err) {
|
|
32828
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
32829
|
+
return { error: message };
|
|
32830
|
+
}
|
|
32831
|
+
}
|
|
32832
|
+
async function checkForUpdate(fetcher = fetch, registryUrl) {
|
|
32833
|
+
const currentVersion = getCurrentVersion();
|
|
32834
|
+
const url2 = registryUrl ?? registryUrlForTag();
|
|
32835
|
+
const latest = await fetchLatestVersion(fetcher, url2);
|
|
32836
|
+
if ("error" in latest) {
|
|
32837
|
+
return {
|
|
32838
|
+
currentVersion,
|
|
32839
|
+
latestVersion: currentVersion,
|
|
32840
|
+
updateAvailable: false,
|
|
32841
|
+
error: latest.error
|
|
32842
|
+
};
|
|
32843
|
+
}
|
|
32844
|
+
const cmp = compareSemver(currentVersion, latest.version);
|
|
32845
|
+
return {
|
|
32846
|
+
currentVersion,
|
|
32847
|
+
latestVersion: latest.version,
|
|
32848
|
+
updateAvailable: cmp < 0
|
|
32849
|
+
};
|
|
32850
|
+
}
|
|
32851
|
+
async function performUpdate(packageName = "zelari-code", executor = spawn5, resolveNpmCli = resolveBundledNpmCli, channel) {
|
|
32852
|
+
const tag = channel ?? distTagForVersion(getCurrentVersion());
|
|
32853
|
+
const args = ["install", "-g", `${packageName}@${tag}`];
|
|
32854
|
+
const primary = await runNpm(executor, args, "shim");
|
|
32855
|
+
if (primary.ok) return primary;
|
|
32856
|
+
const npmCli = resolveNpmCli();
|
|
32857
|
+
if (npmCli && looksLikeBrokenShim(primary.exitCode, primary.output)) {
|
|
32858
|
+
const fallback = await runNpm(executor, args, "bundled", npmCli);
|
|
32859
|
+
return {
|
|
32860
|
+
...fallback,
|
|
32861
|
+
output: `[update] npm shim failed (${primary.error ?? "exit " + primary.exitCode}); retried via bundled npm (${npmCli}).
|
|
32862
|
+
${fallback.output}`
|
|
32863
|
+
};
|
|
32864
|
+
}
|
|
32865
|
+
return primary;
|
|
32866
|
+
}
|
|
32867
|
+
function runNpm(executor, args, mode, npmCliPath) {
|
|
32868
|
+
return new Promise((resolve3) => {
|
|
32869
|
+
let stdout = "";
|
|
32870
|
+
let stderr = "";
|
|
32871
|
+
const stdio = ["ignore", "pipe", "pipe"];
|
|
32872
|
+
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 });
|
|
32873
|
+
child.stdout?.on("data", (chunk) => {
|
|
32874
|
+
stdout += chunk.toString();
|
|
32875
|
+
});
|
|
32876
|
+
child.stderr?.on("data", (chunk) => {
|
|
32877
|
+
stderr += chunk.toString();
|
|
32878
|
+
});
|
|
32879
|
+
child.on("error", (err) => {
|
|
32880
|
+
resolve3({
|
|
32881
|
+
ok: false,
|
|
32882
|
+
output: stdout + stderr,
|
|
32883
|
+
error: err.message,
|
|
32884
|
+
exitCode: null
|
|
32885
|
+
});
|
|
32886
|
+
});
|
|
32887
|
+
child.on("close", (code) => {
|
|
32888
|
+
const ok = code === 0;
|
|
32889
|
+
resolve3({
|
|
32890
|
+
ok,
|
|
32891
|
+
output: stdout + stderr,
|
|
32892
|
+
error: ok ? void 0 : `npm exited with code ${code}`,
|
|
32893
|
+
exitCode: code
|
|
32894
|
+
});
|
|
32895
|
+
});
|
|
32896
|
+
});
|
|
32897
|
+
}
|
|
32898
|
+
var require2, __dirname2, REGISTRY_URL;
|
|
32899
|
+
var init_updater = __esm({
|
|
32900
|
+
"src/cli/updater.ts"() {
|
|
32901
|
+
"use strict";
|
|
32902
|
+
init_cmdline();
|
|
32903
|
+
require2 = createRequire(import.meta.url);
|
|
32904
|
+
__dirname2 = path22.dirname(fileURLToPath(import.meta.url));
|
|
32905
|
+
REGISTRY_URL = "https://registry.npmjs.org/zelari-code/latest";
|
|
32906
|
+
}
|
|
32907
|
+
});
|
|
32908
|
+
|
|
32909
|
+
// src/cli/harnessManifest.ts
|
|
32910
|
+
function buildHarnessManifest(parts) {
|
|
32911
|
+
const prompts = {};
|
|
32912
|
+
for (const [role, text] of Object.entries(parts.prompts ?? {})) {
|
|
32913
|
+
if (typeof text === "string" && text.length > 0) {
|
|
32914
|
+
prompts[role] = harnessInputHash(text);
|
|
32915
|
+
}
|
|
32916
|
+
}
|
|
32917
|
+
const manifest = HarnessManifestV1Schema.parse({
|
|
32918
|
+
schemaVersion: 1,
|
|
32919
|
+
profile: {
|
|
32920
|
+
id: parts.profile.id,
|
|
32921
|
+
phase: parts.phase,
|
|
32922
|
+
hash: profileHash(parts.profile)
|
|
32923
|
+
},
|
|
32924
|
+
prompts,
|
|
32925
|
+
capabilities: {
|
|
32926
|
+
// 2.6.1 (plan §7): full fingerprints when specs are available.
|
|
32927
|
+
toolManifestHash: parts.toolSpecs ? toolFingerprintHash(parts.toolSpecs) : toolManifestHash(parts.toolNames),
|
|
32928
|
+
skillManifestHash: parts.skillSpecs ? skillFingerprintHash(parts.skillSpecs) : harnessInputHash([...parts.skillIds ?? []].sort())
|
|
32929
|
+
},
|
|
32930
|
+
policies: {
|
|
32931
|
+
routingHash: harnessInputHash(parts.routing ?? { unset: true }),
|
|
32932
|
+
verificationHash: harnessInputHash(parts.verification ?? { engine: "deterministic" }),
|
|
32933
|
+
completionPolicyHash: harnessInputHash(parts.completionPolicy ?? { mode: "strict", required: "*" }),
|
|
32934
|
+
compactionHash: harnessInputHash(parts.compaction ?? { version: 1 }),
|
|
32935
|
+
resourcePolicyHash: harnessInputHash(parts.resourcePolicy ?? { unset: true })
|
|
32936
|
+
},
|
|
32937
|
+
runtime: {
|
|
32938
|
+
// 2.6.1 (plan §7): canonical export — no more require.resolve.
|
|
32939
|
+
coreVersion: parts.coreVersion ?? CORE_VERSION,
|
|
32940
|
+
cliVersion: parts.cliVersion ?? getCurrentVersion()
|
|
32941
|
+
}
|
|
32942
|
+
});
|
|
32943
|
+
return { manifest, manifestHash: hashHarnessManifest(manifest) };
|
|
32944
|
+
}
|
|
32945
|
+
var init_harnessManifest2 = __esm({
|
|
32946
|
+
"src/cli/harnessManifest.ts"() {
|
|
32947
|
+
"use strict";
|
|
32948
|
+
init_dist();
|
|
32949
|
+
init_dist();
|
|
32950
|
+
init_updater();
|
|
32951
|
+
}
|
|
32952
|
+
});
|
|
32953
|
+
|
|
32954
|
+
// src/cli/kraken/taskContract.ts
|
|
32955
|
+
function latestTaskContract(events) {
|
|
32956
|
+
let latest;
|
|
32957
|
+
for (const e of events) {
|
|
32958
|
+
if (e.kind !== "task.contract" && e.kind !== "task.contract_updated") continue;
|
|
32959
|
+
const raw = e.data.contract;
|
|
32960
|
+
if (raw && typeof raw === "object") {
|
|
32961
|
+
const candidate = raw;
|
|
32962
|
+
if (!latest || candidate.version > latest.version) latest = candidate;
|
|
32963
|
+
}
|
|
32964
|
+
}
|
|
32965
|
+
return latest;
|
|
32966
|
+
}
|
|
32967
|
+
function updateTaskContract(contract, update) {
|
|
32968
|
+
return applyTaskContractUpdate(contract, update);
|
|
32969
|
+
}
|
|
32970
|
+
function contractEventData(contract, updated) {
|
|
32971
|
+
return { contract, kind: updated ? "task.contract_updated" : "task.contract" };
|
|
32972
|
+
}
|
|
32973
|
+
var init_taskContract2 = __esm({
|
|
32974
|
+
"src/cli/kraken/taskContract.ts"() {
|
|
32975
|
+
"use strict";
|
|
32976
|
+
init_dist();
|
|
32977
|
+
}
|
|
32978
|
+
});
|
|
32979
|
+
|
|
32980
|
+
// src/cli/sessionSpine.ts
|
|
32981
|
+
import path23 from "node:path";
|
|
32493
32982
|
function spineEnabled() {
|
|
32494
32983
|
return process.env.ZELARI_SESSION_SPINE !== "0";
|
|
32495
32984
|
}
|
|
@@ -32571,14 +33060,54 @@ async function wrapSessionWriter(inner, sessionId2, options = {}) {
|
|
|
32571
33060
|
const spine = await SessionSpineMirror.adopt(sessionId2, options);
|
|
32572
33061
|
if (spine.status === "active") {
|
|
32573
33062
|
const profile = options.extraStarted?.profile;
|
|
32574
|
-
|
|
32575
|
-
|
|
32576
|
-
|
|
32577
|
-
|
|
33063
|
+
const budget = new BudgetRuntime(typeof profile === "string" ? profile : "kraken/v1", {
|
|
33064
|
+
enforcement: resolveResourceEnforcement()
|
|
33065
|
+
});
|
|
33066
|
+
if (spine.resumedFromSeq !== void 0 && spine.resumedFromSeq > 0) {
|
|
33067
|
+
await restoreBudgetRuntimeFromSession(budget, sessionId2, options.baseDir);
|
|
33068
|
+
}
|
|
33069
|
+
spine.attachBudgetRuntime(budget);
|
|
33070
|
+
await noteHarnessLifecycle(
|
|
33071
|
+
spine,
|
|
33072
|
+
sessionId2,
|
|
33073
|
+
typeof profile === "string" ? profile : "kraken/v1",
|
|
33074
|
+
budget,
|
|
33075
|
+
options.baseDir,
|
|
33076
|
+
options.extraStarted?.phase
|
|
32578
33077
|
);
|
|
32579
33078
|
}
|
|
32580
33079
|
return new SpineMirroringWriter(inner, spine.status === "active" ? spine : null);
|
|
32581
33080
|
}
|
|
33081
|
+
function taskContractsEnabled() {
|
|
33082
|
+
return process.env.ZELARI_TASK_CONTRACT !== "0";
|
|
33083
|
+
}
|
|
33084
|
+
async function noteHarnessLifecycle(spine, sessionId2, profileId, budget, baseDir, phaseHint) {
|
|
33085
|
+
try {
|
|
33086
|
+
const profile = resolveProfile(profileId);
|
|
33087
|
+
const { manifest, manifestHash } = buildHarnessManifest({
|
|
33088
|
+
profile,
|
|
33089
|
+
phase: phaseHint === "plan" ? "plan" : "build",
|
|
33090
|
+
toolNames: profile.tools,
|
|
33091
|
+
// plan §7/§8: the REAL session policy — never the {unset:true} marker.
|
|
33092
|
+
resourcePolicy: budget.policy
|
|
33093
|
+
});
|
|
33094
|
+
if (spine.resumedFromSeq !== void 0 && spine.resumedFromSeq > 0) {
|
|
33095
|
+
const original = await lastHarnessManifestHash(sessionId2, baseDir);
|
|
33096
|
+
if (original === null) {
|
|
33097
|
+
spine.harnessManifest(manifest, manifestHash);
|
|
33098
|
+
} else if (original !== manifestHash) {
|
|
33099
|
+
await spine.appendEvent({
|
|
33100
|
+
kind: "session.harness_drift",
|
|
33101
|
+
actor: ACTOR_SYSTEM,
|
|
33102
|
+
data: { originalManifestHash: original, currentManifestHash: manifestHash }
|
|
33103
|
+
});
|
|
33104
|
+
}
|
|
33105
|
+
} else {
|
|
33106
|
+
spine.harnessManifest(manifest, manifestHash);
|
|
33107
|
+
}
|
|
33108
|
+
} catch {
|
|
33109
|
+
}
|
|
33110
|
+
}
|
|
32582
33111
|
var MAX_STREAM_BUFFERS, SessionSpineMirror, SpineMirroringWriter;
|
|
32583
33112
|
var init_sessionSpine = __esm({
|
|
32584
33113
|
"src/cli/sessionSpine.ts"() {
|
|
@@ -32587,6 +33116,10 @@ var init_sessionSpine = __esm({
|
|
|
32587
33116
|
init_session();
|
|
32588
33117
|
init_verification2();
|
|
32589
33118
|
init_budgetRuntime();
|
|
33119
|
+
init_restoreRuntime();
|
|
33120
|
+
init_runtime2();
|
|
33121
|
+
init_harnessManifest2();
|
|
33122
|
+
init_taskContract2();
|
|
32590
33123
|
MAX_STREAM_BUFFERS = 32;
|
|
32591
33124
|
SessionSpineMirror = class _SessionSpineMirror {
|
|
32592
33125
|
constructor(sessionId2, options) {
|
|
@@ -32615,8 +33148,8 @@ var init_sessionSpine = __esm({
|
|
|
32615
33148
|
const mirror = new _SessionSpineMirror(sessionId2, options);
|
|
32616
33149
|
if (!spineEnabled()) return mirror;
|
|
32617
33150
|
try {
|
|
32618
|
-
const sessionDir =
|
|
32619
|
-
const report = await readSessionLog(
|
|
33151
|
+
const sessionDir = path23.join(mirror.sessionsDir, sessionId2);
|
|
33152
|
+
const report = await readSessionLog(path23.join(sessionDir, "events.jsonl"));
|
|
32620
33153
|
const existed = report.events.length > 0 || report.issues.length > 0;
|
|
32621
33154
|
if (report.events.some((e) => e.kind === "task.contract" || e.kind === "user.message")) {
|
|
32622
33155
|
mirror.contractSeeded = true;
|
|
@@ -32702,19 +33235,45 @@ var init_sessionSpine = __esm({
|
|
|
32702
33235
|
latestResourceSnapshot() {
|
|
32703
33236
|
return this.budgetRuntime?.latestEmitted() ?? null;
|
|
32704
33237
|
}
|
|
33238
|
+
/**
|
|
33239
|
+
* 2.6.1 (plan §8): session ResourcePolicy cap for hosts that need to derive
|
|
33240
|
+
* per-turn limits — the policy stays the single authority. Null when no
|
|
33241
|
+
* runtime is attached (hosts keep their own default).
|
|
33242
|
+
*/
|
|
33243
|
+
/** Full budget shape for evaluateResourceReserveGate (plan §14). */
|
|
33244
|
+
resourceBudgetSummary() {
|
|
33245
|
+
return this.budgetRuntime?.budgetSnapshot() ?? null;
|
|
33246
|
+
}
|
|
33247
|
+
resourceBudgetLimit() {
|
|
33248
|
+
const snap = this.budgetRuntime?.current();
|
|
33249
|
+
return snap ? {
|
|
33250
|
+
maxToolCalls: snap.toolCallsLimit,
|
|
33251
|
+
remaining: snap.toolCallsRemaining,
|
|
33252
|
+
verificationReserve: snap.verificationReserve
|
|
33253
|
+
} : null;
|
|
33254
|
+
}
|
|
32705
33255
|
/**
|
|
32706
33256
|
* §11.3 pre-dispatch gate for hosts that enforce the protected zone
|
|
32707
33257
|
* (Phase 3): delegates to the attached runtime, never throws. Null when
|
|
32708
33258
|
* no runtime is attached (hosts treat as "no budget info, allow").
|
|
33259
|
+
* 2.6.1 (plan §13): argument-aware — pass the tool args so `bash` is only
|
|
33260
|
+
* essential when it is a test/typecheck/build/git-diff command.
|
|
32709
33261
|
*/
|
|
32710
|
-
gateResourceToolCall(toolName) {
|
|
32711
|
-
const gate = this.budgetRuntime?.gateToolCall(toolName);
|
|
33262
|
+
gateResourceToolCall(toolName, args) {
|
|
33263
|
+
const gate = this.budgetRuntime?.gateToolCall({ toolName, args });
|
|
32712
33264
|
if (!gate) return null;
|
|
32713
|
-
return {
|
|
33265
|
+
return {
|
|
33266
|
+
allowed: gate.allowed,
|
|
33267
|
+
...gate.reason ? { reason: gate.reason } : {},
|
|
33268
|
+
...gate.hardLimit ? { hardLimit: gate.hardLimit } : {}
|
|
33269
|
+
};
|
|
32714
33270
|
}
|
|
32715
|
-
/**
|
|
33271
|
+
/**
|
|
33272
|
+
* Count a landed tool.call; returns the snapshot due (§10.4) plus the
|
|
33273
|
+
* hard-limit event due on this call (2.6.1 plan §9), if any.
|
|
33274
|
+
*/
|
|
32716
33275
|
onToolCallBudget() {
|
|
32717
|
-
return this.budgetRuntime?.
|
|
33276
|
+
return this.budgetRuntime?.consumeToolCall() ?? { snapshot: null, hardEvent: null };
|
|
32718
33277
|
}
|
|
32719
33278
|
async flush() {
|
|
32720
33279
|
await this.chain;
|
|
@@ -32726,7 +33285,7 @@ var init_sessionSpine = __esm({
|
|
|
32726
33285
|
async derivedPriorTurns() {
|
|
32727
33286
|
if (this.status !== "active" && this.status !== "closed") return null;
|
|
32728
33287
|
const report = await readSessionLog(
|
|
32729
|
-
|
|
33288
|
+
path23.join(this.sessionsDir, this.sessionId, "events.jsonl")
|
|
32730
33289
|
).catch(() => null);
|
|
32731
33290
|
if (!report || report.events.length === 0) return null;
|
|
32732
33291
|
return deriveMessages(report.events);
|
|
@@ -32736,7 +33295,7 @@ var init_sessionSpine = __esm({
|
|
|
32736
33295
|
if (this.status !== "active" && this.status !== "closed") return null;
|
|
32737
33296
|
await this.flush();
|
|
32738
33297
|
const report = await readSessionLog(
|
|
32739
|
-
|
|
33298
|
+
path23.join(this.sessionsDir, this.sessionId, "events.jsonl")
|
|
32740
33299
|
).catch(() => null);
|
|
32741
33300
|
if (!report || report.events.length === 0) return null;
|
|
32742
33301
|
return buildCompactionStateSnapshot(report.events, toSeq);
|
|
@@ -32749,7 +33308,7 @@ var init_sessionSpine = __esm({
|
|
|
32749
33308
|
async lastVerificationRun() {
|
|
32750
33309
|
if (this.status !== "active" && this.status !== "closed") return null;
|
|
32751
33310
|
const report = await readSessionLog(
|
|
32752
|
-
|
|
33311
|
+
path23.join(this.sessionsDir, this.sessionId, "events.jsonl")
|
|
32753
33312
|
).catch(() => null);
|
|
32754
33313
|
if (!report) return null;
|
|
32755
33314
|
return lastVerificationRun(report.events);
|
|
@@ -32820,10 +33379,18 @@ var init_sessionSpine = __esm({
|
|
|
32820
33379
|
}
|
|
32821
33380
|
append(input) {
|
|
32822
33381
|
if (!this.writer || this.status === "closed") return Promise.resolve(null);
|
|
32823
|
-
const
|
|
32824
|
-
const dueContract = input.kind === "user.message" &&
|
|
33382
|
+
const budgetEffect = input.kind === "tool.call" ? this.onToolCallBudget() : null;
|
|
33383
|
+
const dueContract = input.kind === "user.message" && taskContractsEnabled() && !this.contractSeeded ? (this.contractSeeded = true, input.data?.text) : null;
|
|
33384
|
+
const steerText = input.kind === "user.message" && taskContractsEnabled() && this.contractSeeded && !dueContract ? input.data?.text ?? null : null;
|
|
32825
33385
|
let seq = this.chain.then(() => this.writer.append(input)).then((envelope) => envelope.seq);
|
|
32826
|
-
if (
|
|
33386
|
+
if (budgetEffect?.hardEvent) {
|
|
33387
|
+
const hard = budgetEffect.hardEvent;
|
|
33388
|
+
seq = seq.then(
|
|
33389
|
+
(s) => this.writer.append({ kind: hard.kind, actor: ACTOR_SYSTEM, data: { ...hard.data } }).then(() => s)
|
|
33390
|
+
);
|
|
33391
|
+
}
|
|
33392
|
+
if (budgetEffect?.snapshot) {
|
|
33393
|
+
const dueSnapshot = budgetEffect.snapshot;
|
|
32827
33394
|
seq = seq.then(
|
|
32828
33395
|
(s) => this.writer.append({ kind: "resource.snapshot", actor: ACTOR_SYSTEM, data: { ...dueSnapshot } }).then(() => s)
|
|
32829
33396
|
);
|
|
@@ -32844,6 +33411,30 @@ var init_sessionSpine = __esm({
|
|
|
32844
33411
|
return s;
|
|
32845
33412
|
});
|
|
32846
33413
|
}
|
|
33414
|
+
if (steerText) {
|
|
33415
|
+
seq = seq.then(async (s) => {
|
|
33416
|
+
try {
|
|
33417
|
+
const eventsPath = path23.join(this.sessionsDir, this.sessionId, "events.jsonl");
|
|
33418
|
+
const report = await readSessionLog(eventsPath).catch(() => null);
|
|
33419
|
+
if (!report || typeof s !== "number") return s;
|
|
33420
|
+
const current = latestTaskContract(report.events);
|
|
33421
|
+
if (!current) return s;
|
|
33422
|
+
const updated = updateTaskContract(current, {
|
|
33423
|
+
addConstraints: [{ id: `steer-${s}`, text: steerText, source: "user", required: false }],
|
|
33424
|
+
nextUserSeq: s
|
|
33425
|
+
});
|
|
33426
|
+
if (updated.version !== current.version) {
|
|
33427
|
+
await this.writer.append({
|
|
33428
|
+
kind: "task.contract_updated",
|
|
33429
|
+
actor: ACTOR_SYSTEM,
|
|
33430
|
+
data: contractEventData(updated, true)
|
|
33431
|
+
});
|
|
33432
|
+
}
|
|
33433
|
+
} catch {
|
|
33434
|
+
}
|
|
33435
|
+
return s;
|
|
33436
|
+
});
|
|
33437
|
+
}
|
|
32847
33438
|
this.chain = seq.catch((err) => {
|
|
32848
33439
|
this.status = "degraded";
|
|
32849
33440
|
this.writer = null;
|
|
@@ -33070,10 +33661,10 @@ var init_sessionSurface = __esm({
|
|
|
33070
33661
|
});
|
|
33071
33662
|
|
|
33072
33663
|
// src/cli/hooks/observationStore.ts
|
|
33073
|
-
import { existsSync as
|
|
33074
|
-
import
|
|
33664
|
+
import { existsSync as existsSync12, statSync as statSync2 } from "node:fs";
|
|
33665
|
+
import path24 from "node:path";
|
|
33075
33666
|
function sessionFilePath(sessionId2, baseDir) {
|
|
33076
|
-
return
|
|
33667
|
+
return path24.join(baseDir ?? getSessionBaseDir(), `${sessionId2}.jsonl`);
|
|
33077
33668
|
}
|
|
33078
33669
|
function isToolEnd(e) {
|
|
33079
33670
|
return e.type === "tool_execution_end";
|
|
@@ -33083,7 +33674,7 @@ function isToolStart(e) {
|
|
|
33083
33674
|
}
|
|
33084
33675
|
async function loadObservationIndex(sessionId2, baseDir) {
|
|
33085
33676
|
const filePath = sessionFilePath(sessionId2, baseDir);
|
|
33086
|
-
const exists =
|
|
33677
|
+
const exists = existsSync12(filePath);
|
|
33087
33678
|
let mtimeMs = 0;
|
|
33088
33679
|
if (exists) {
|
|
33089
33680
|
try {
|
|
@@ -33095,7 +33686,7 @@ async function loadObservationIndex(sessionId2, baseDir) {
|
|
|
33095
33686
|
const hit = cache.get(sessionId2);
|
|
33096
33687
|
if (hit && !exists) return hit;
|
|
33097
33688
|
if (hit && hit.filePath === filePath && hit.mtimeMs === mtimeMs) return hit;
|
|
33098
|
-
const events =
|
|
33689
|
+
const events = existsSync12(filePath) ? await readSession(filePath) : [];
|
|
33099
33690
|
const names = /* @__PURE__ */ new Map();
|
|
33100
33691
|
const bySeq = /* @__PURE__ */ new Map();
|
|
33101
33692
|
const byToolCallId = /* @__PURE__ */ new Map();
|
|
@@ -33192,8 +33783,8 @@ var init_observationStore = __esm({
|
|
|
33192
33783
|
});
|
|
33193
33784
|
|
|
33194
33785
|
// src/cli/metrics.ts
|
|
33195
|
-
import { promises as fs14, existsSync as
|
|
33196
|
-
import
|
|
33786
|
+
import { promises as fs14, existsSync as existsSync13, statSync as statSync3, renameSync, appendFileSync as appendFileSync2, mkdirSync as mkdirSync6 } from "node:fs";
|
|
33787
|
+
import path25 from "node:path";
|
|
33197
33788
|
import os6 from "node:os";
|
|
33198
33789
|
async function readMetrics(file2) {
|
|
33199
33790
|
let raw = "";
|
|
@@ -33242,8 +33833,8 @@ var init_metrics2 = __esm({
|
|
|
33242
33833
|
file;
|
|
33243
33834
|
writeQueue = Promise.resolve();
|
|
33244
33835
|
constructor(file2) {
|
|
33245
|
-
this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ??
|
|
33246
|
-
mkdirSync6(
|
|
33836
|
+
this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ?? path25.join(os6.homedir(), ".tmp", "zelari-code", "metrics.jsonl");
|
|
33837
|
+
mkdirSync6(path25.dirname(this.file), { recursive: true });
|
|
33247
33838
|
}
|
|
33248
33839
|
/** Metrics file path — doctor/summary readers use this. */
|
|
33249
33840
|
get filePath() {
|
|
@@ -33278,7 +33869,7 @@ var init_metrics2 = __esm({
|
|
|
33278
33869
|
}
|
|
33279
33870
|
/** If the file is over the rotation threshold, rotate it. */
|
|
33280
33871
|
maybeRotate() {
|
|
33281
|
-
if (!
|
|
33872
|
+
if (!existsSync13(this.file)) return;
|
|
33282
33873
|
try {
|
|
33283
33874
|
const stat = statSync3(this.file);
|
|
33284
33875
|
if (stat.size >= METRICS_ROTATE_BYTES) {
|
|
@@ -34459,8 +35050,8 @@ var init_resolveStream = __esm({
|
|
|
34459
35050
|
});
|
|
34460
35051
|
|
|
34461
35052
|
// packages/core/dist/core/tools/toolOutputSpill.js
|
|
34462
|
-
import { createHash as
|
|
34463
|
-
import { existsSync as
|
|
35053
|
+
import { createHash as createHash7, randomBytes as randomBytes2 } from "node:crypto";
|
|
35054
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7, writeFileSync as writeFileSync11 } from "node:fs";
|
|
34464
35055
|
import { homedir as homedir3, tmpdir } from "node:os";
|
|
34465
35056
|
import { join as join11 } from "node:path";
|
|
34466
35057
|
function resolveToolOutputDir() {
|
|
@@ -34486,10 +35077,10 @@ function spillToolOutput(fullText, meta3) {
|
|
|
34486
35077
|
return null;
|
|
34487
35078
|
try {
|
|
34488
35079
|
const dir = resolveToolOutputDir();
|
|
34489
|
-
if (!
|
|
35080
|
+
if (!existsSync14(dir)) {
|
|
34490
35081
|
mkdirSync7(dir, { recursive: true });
|
|
34491
35082
|
}
|
|
34492
|
-
const hash3 =
|
|
35083
|
+
const hash3 = createHash7("sha256").update(fullText).digest("hex").slice(0, 12);
|
|
34493
35084
|
const stamp = Date.now().toString(36);
|
|
34494
35085
|
const rnd = randomBytes2(3).toString("hex");
|
|
34495
35086
|
const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
|
|
@@ -34753,14 +35344,14 @@ var init_registry2 = __esm({
|
|
|
34753
35344
|
});
|
|
34754
35345
|
|
|
34755
35346
|
// src/cli/safety/sandboxPath.ts
|
|
34756
|
-
import
|
|
35347
|
+
import path26 from "node:path";
|
|
34757
35348
|
function resolveSandboxedPath(userPath, options = {}) {
|
|
34758
35349
|
if (typeof userPath !== "string" || userPath.length === 0) {
|
|
34759
35350
|
throw new SandboxViolationError("Empty path", userPath, "");
|
|
34760
35351
|
}
|
|
34761
|
-
const root =
|
|
34762
|
-
const resolved =
|
|
34763
|
-
const rootWithSep = root.endsWith(
|
|
35352
|
+
const root = path26.resolve(options.root ?? process.cwd());
|
|
35353
|
+
const resolved = path26.isAbsolute(userPath) ? path26.resolve(userPath) : path26.resolve(root, userPath);
|
|
35354
|
+
const rootWithSep = root.endsWith(path26.sep) ? root : root + path26.sep;
|
|
34764
35355
|
if (resolved !== root && !resolved.startsWith(rootWithSep)) {
|
|
34765
35356
|
throw new SandboxViolationError(
|
|
34766
35357
|
`Path escapes sandbox root: ${userPath} \u2192 ${resolved} (root: ${root})`,
|
|
@@ -34848,12 +35439,12 @@ __export(auditLogger_exports, {
|
|
|
34848
35439
|
AuditLogger: () => AuditLogger
|
|
34849
35440
|
});
|
|
34850
35441
|
import { promises as fs15 } from "node:fs";
|
|
34851
|
-
import
|
|
35442
|
+
import path27 from "node:path";
|
|
34852
35443
|
import os7 from "node:os";
|
|
34853
35444
|
function defaultAuditPath() {
|
|
34854
35445
|
const override = process.env.ANATHEMA_AUDIT_LOG;
|
|
34855
35446
|
if (override && override.trim().length > 0) return override;
|
|
34856
|
-
return
|
|
35447
|
+
return path27.join(os7.tmpdir(), "zelari-code", "audit.jsonl");
|
|
34857
35448
|
}
|
|
34858
35449
|
function redactArgs(args) {
|
|
34859
35450
|
const redacted = {};
|
|
@@ -34896,7 +35487,7 @@ var init_auditLogger = __esm({
|
|
|
34896
35487
|
async append(entry) {
|
|
34897
35488
|
const line = JSON.stringify(entry) + "\n";
|
|
34898
35489
|
this.writeQueue = this.writeQueue.then(async () => {
|
|
34899
|
-
await fs15.mkdir(
|
|
35490
|
+
await fs15.mkdir(path27.dirname(this.logPath), { recursive: true });
|
|
34900
35491
|
await fs15.appendFile(this.logPath, line, "utf-8");
|
|
34901
35492
|
});
|
|
34902
35493
|
return this.writeQueue;
|
|
@@ -34940,25 +35531,10 @@ var init_auditLogger = __esm({
|
|
|
34940
35531
|
}
|
|
34941
35532
|
});
|
|
34942
35533
|
|
|
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
35534
|
// src/cli/diagnostics/engine.ts
|
|
34959
|
-
import { spawn as
|
|
34960
|
-
import { existsSync as
|
|
34961
|
-
import
|
|
35535
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
35536
|
+
import { existsSync as existsSync15 } from "node:fs";
|
|
35537
|
+
import path28 from "node:path";
|
|
34962
35538
|
function parseEslintJson(stdout, _file2) {
|
|
34963
35539
|
const json2 = safeJson(stdout);
|
|
34964
35540
|
if (!Array.isArray(json2)) return [];
|
|
@@ -35017,7 +35593,7 @@ function safeJson(s) {
|
|
|
35017
35593
|
}
|
|
35018
35594
|
}
|
|
35019
35595
|
function providerForFile(file2, providers = DEFAULT_PROVIDERS) {
|
|
35020
|
-
const ext =
|
|
35596
|
+
const ext = path28.extname(file2).toLowerCase();
|
|
35021
35597
|
return providers.find((p3) => p3.extensions.includes(ext)) ?? null;
|
|
35022
35598
|
}
|
|
35023
35599
|
function resolveBin(bin, cwd) {
|
|
@@ -35025,10 +35601,10 @@ function resolveBin(bin, cwd) {
|
|
|
35025
35601
|
let dir = cwd;
|
|
35026
35602
|
for (let i = 0; i < 6; i += 1) {
|
|
35027
35603
|
for (const suffix of suffixes) {
|
|
35028
|
-
const candidate =
|
|
35029
|
-
if (
|
|
35604
|
+
const candidate = path28.join(dir, "node_modules", ".bin", `${bin}${suffix}`);
|
|
35605
|
+
if (existsSync15(candidate)) return candidate;
|
|
35030
35606
|
}
|
|
35031
|
-
const parent =
|
|
35607
|
+
const parent = path28.dirname(dir);
|
|
35032
35608
|
if (parent === dir) break;
|
|
35033
35609
|
dir = parent;
|
|
35034
35610
|
}
|
|
@@ -35101,7 +35677,7 @@ var init_engine2 = __esm({
|
|
|
35101
35677
|
};
|
|
35102
35678
|
let child;
|
|
35103
35679
|
try {
|
|
35104
|
-
child = process.platform === "win32" ?
|
|
35680
|
+
child = process.platform === "win32" ? spawn6(buildCmdLine(cmd, args), { cwd: opts.cwd, shell: true }) : spawn6(cmd, args, { cwd: opts.cwd });
|
|
35105
35681
|
} catch {
|
|
35106
35682
|
done({ code: null, stdout: "", stderr: "" });
|
|
35107
35683
|
return;
|
|
@@ -35132,19 +35708,19 @@ var init_engine2 = __esm({
|
|
|
35132
35708
|
});
|
|
35133
35709
|
|
|
35134
35710
|
// src/cli/tools/krakenRadio.ts
|
|
35135
|
-
import { appendFileSync as appendFileSync3, existsSync as
|
|
35136
|
-
import
|
|
35711
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync14, readdirSync as readdirSync2 } from "node:fs";
|
|
35712
|
+
import path29 from "node:path";
|
|
35137
35713
|
function radioDir(cwd) {
|
|
35138
|
-
return
|
|
35714
|
+
return path29.join(cwd, ".zelari", "radio");
|
|
35139
35715
|
}
|
|
35140
35716
|
function radioPath(cwd, sessionId2) {
|
|
35141
35717
|
const safe = (sessionId2 || "default").replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
35142
|
-
return
|
|
35718
|
+
return path29.join(radioDir(cwd), `${safe}.jsonl`);
|
|
35143
35719
|
}
|
|
35144
35720
|
function appendKrakenRadio(cwd, sessionId2, event) {
|
|
35145
35721
|
try {
|
|
35146
35722
|
const dir = radioDir(cwd);
|
|
35147
|
-
if (!
|
|
35723
|
+
if (!existsSync16(dir)) mkdirSync8(dir, { recursive: true });
|
|
35148
35724
|
const row = {
|
|
35149
35725
|
ts: event.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
35150
35726
|
kind: event.kind,
|
|
@@ -35165,7 +35741,7 @@ function appendKrakenRadio(cwd, sessionId2, event) {
|
|
|
35165
35741
|
function readKrakenRadio(cwd, sessionId2, limit = 50) {
|
|
35166
35742
|
try {
|
|
35167
35743
|
const file2 = radioPath(cwd, sessionId2);
|
|
35168
|
-
if (!
|
|
35744
|
+
if (!existsSync16(file2)) return [];
|
|
35169
35745
|
const lines = readFileSync14(file2, "utf8").split(/\r?\n/).filter(Boolean);
|
|
35170
35746
|
const slice = lines.slice(-Math.max(1, limit));
|
|
35171
35747
|
const out = [];
|
|
@@ -35189,7 +35765,7 @@ function formatKrakenRadioStatus(cwd, sessionId2, limit = 12) {
|
|
|
35189
35765
|
const flag = e.ok === false ? "\u2717" : e.ok === true ? "\u2713" : "\xB7";
|
|
35190
35766
|
const ms = e.durationMs != null ? ` ${e.durationMs}ms` : "";
|
|
35191
35767
|
const model = e.model ? ` [${e.model}]` : "";
|
|
35192
|
-
const wt = e.worktree ? ` wt=${
|
|
35768
|
+
const wt = e.worktree ? ` wt=${path29.basename(e.worktree)}` : "";
|
|
35193
35769
|
const detail = e.detail ? ` \u2014 ${e.detail.slice(0, 120)}` : "";
|
|
35194
35770
|
return `${flag} ${e.ts.slice(11, 19)} ${e.kind} ${e.agent} "${e.description}"${model}${wt}${ms}${detail}`;
|
|
35195
35771
|
});
|
|
@@ -35203,8 +35779,8 @@ var init_krakenRadio = __esm({
|
|
|
35203
35779
|
|
|
35204
35780
|
// src/cli/tools/krakenWorktree.ts
|
|
35205
35781
|
import { execFile as execFile2 } from "node:child_process";
|
|
35206
|
-
import { existsSync as
|
|
35207
|
-
import
|
|
35782
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync9, rmSync } from "node:fs";
|
|
35783
|
+
import path30 from "node:path";
|
|
35208
35784
|
import { promisify } from "node:util";
|
|
35209
35785
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
35210
35786
|
function isKrakenWorktreeEnabled(env = process.env) {
|
|
@@ -35252,10 +35828,10 @@ async function createKrakenWorktree(cwd, label) {
|
|
|
35252
35828
|
const id = `${Date.now().toString(36)}-${randomBytes3(3).toString("hex")}`;
|
|
35253
35829
|
const slug = (label ?? "task").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) || "task";
|
|
35254
35830
|
const branch = `kraken/${slug}-${id}`;
|
|
35255
|
-
const wtRoot =
|
|
35256
|
-
const wtPath =
|
|
35831
|
+
const wtRoot = path30.join(repoRoot, ".zelari", "worktrees");
|
|
35832
|
+
const wtPath = path30.join(wtRoot, `kraken-${id}`);
|
|
35257
35833
|
try {
|
|
35258
|
-
if (!
|
|
35834
|
+
if (!existsSync17(wtRoot)) mkdirSync9(wtRoot, { recursive: true });
|
|
35259
35835
|
} catch {
|
|
35260
35836
|
return null;
|
|
35261
35837
|
}
|
|
@@ -35367,7 +35943,7 @@ async function cleanupKrakenWorktree(handle, env = process.env) {
|
|
|
35367
35943
|
if (shouldKeepWorktree(env)) return;
|
|
35368
35944
|
await git2(handle.repoRoot, ["worktree", "remove", "--force", handle.path]);
|
|
35369
35945
|
try {
|
|
35370
|
-
if (
|
|
35946
|
+
if (existsSync17(handle.path)) {
|
|
35371
35947
|
rmSync(handle.path, { recursive: true, force: true });
|
|
35372
35948
|
}
|
|
35373
35949
|
} catch {
|
|
@@ -36704,7 +37280,7 @@ var init_askUser = __esm({
|
|
|
36704
37280
|
});
|
|
36705
37281
|
|
|
36706
37282
|
// src/cli/skillsMd.ts
|
|
36707
|
-
import { existsSync as
|
|
37283
|
+
import { existsSync as existsSync18, readdirSync as readdirSync3, readFileSync as readFileSync15 } from "node:fs";
|
|
36708
37284
|
import { join as join12 } from "node:path";
|
|
36709
37285
|
import { homedir as homedir4 } from "node:os";
|
|
36710
37286
|
function skillMdSearchDirs(projectRoot = process.cwd()) {
|
|
@@ -36770,7 +37346,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
36770
37346
|
const summary = { loaded: [], skipped: [] };
|
|
36771
37347
|
const seen = new Set(options.existingIds ?? []);
|
|
36772
37348
|
for (const dir of skillMdSearchDirs(projectRoot)) {
|
|
36773
|
-
if (!
|
|
37349
|
+
if (!existsSync18(dir)) continue;
|
|
36774
37350
|
let entries;
|
|
36775
37351
|
try {
|
|
36776
37352
|
entries = readdirSync3(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
@@ -36779,7 +37355,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
36779
37355
|
}
|
|
36780
37356
|
for (const entry of entries) {
|
|
36781
37357
|
const skillPath = join12(dir, entry, "SKILL.md");
|
|
36782
|
-
if (!
|
|
37358
|
+
if (!existsSync18(skillPath)) continue;
|
|
36783
37359
|
try {
|
|
36784
37360
|
const parsed = parseSkillMd(readFileSync15(skillPath, "utf8"), skillPath);
|
|
36785
37361
|
if (!parsed) {
|
|
@@ -36954,14 +37530,14 @@ var init_todoTools = __esm({
|
|
|
36954
37530
|
import {
|
|
36955
37531
|
mkdirSync as mkdirSync10,
|
|
36956
37532
|
writeFileSync as writeFileSync12,
|
|
36957
|
-
existsSync as
|
|
37533
|
+
existsSync as existsSync19,
|
|
36958
37534
|
accessSync,
|
|
36959
37535
|
constants,
|
|
36960
37536
|
realpathSync
|
|
36961
37537
|
} from "node:fs";
|
|
36962
37538
|
import { join as join13, basename } from "node:path";
|
|
36963
37539
|
import { homedir as homedir5 } from "node:os";
|
|
36964
|
-
import { createHash as
|
|
37540
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
36965
37541
|
function resolveWorkspaceRoot(projectRoot = process.cwd()) {
|
|
36966
37542
|
const candidates = [
|
|
36967
37543
|
join13(projectRoot, ".zelari"),
|
|
@@ -36977,11 +37553,11 @@ function resolveWorkspaceRoot(projectRoot = process.cwd()) {
|
|
|
36977
37553
|
return candidates[0];
|
|
36978
37554
|
}
|
|
36979
37555
|
function hashProject(projectPath) {
|
|
36980
|
-
return
|
|
37556
|
+
return createHash8("sha1").update(realpathSync(projectPath)).digest("hex").slice(0, 12);
|
|
36981
37557
|
}
|
|
36982
37558
|
function isWritableDir(dir) {
|
|
36983
37559
|
try {
|
|
36984
|
-
if (!
|
|
37560
|
+
if (!existsSync19(dir)) return false;
|
|
36985
37561
|
accessSync(dir, constants.W_OK);
|
|
36986
37562
|
return true;
|
|
36987
37563
|
} catch {
|
|
@@ -36990,9 +37566,9 @@ function isWritableDir(dir) {
|
|
|
36990
37566
|
}
|
|
36991
37567
|
function ensureWorkspaceDir(workspaceDir) {
|
|
36992
37568
|
mkdirSync10(workspaceDir, { recursive: true });
|
|
36993
|
-
if (workspaceDir.endsWith("/.zelari") &&
|
|
37569
|
+
if (workspaceDir.endsWith("/.zelari") && existsSync19(join13(workspaceDir, "..", ".git"))) {
|
|
36994
37570
|
const gitignorePath = join13(workspaceDir, ".gitignore");
|
|
36995
|
-
if (!
|
|
37571
|
+
if (!existsSync19(gitignorePath)) {
|
|
36996
37572
|
writeFileSync12(gitignorePath, "*\n!.gitignore\n");
|
|
36997
37573
|
}
|
|
36998
37574
|
}
|
|
@@ -37032,7 +37608,7 @@ __export(storage_exports, {
|
|
|
37032
37608
|
import {
|
|
37033
37609
|
readFileSync as readFileSync16,
|
|
37034
37610
|
writeFileSync as writeFileSync13,
|
|
37035
|
-
existsSync as
|
|
37611
|
+
existsSync as existsSync20,
|
|
37036
37612
|
mkdirSync as mkdirSync11,
|
|
37037
37613
|
readdirSync as readdirSync4,
|
|
37038
37614
|
renameSync as renameSync2
|
|
@@ -37292,7 +37868,7 @@ var init_storage = __esm({
|
|
|
37292
37868
|
Storage = class {
|
|
37293
37869
|
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
37294
37870
|
read(path65) {
|
|
37295
|
-
if (!
|
|
37871
|
+
if (!existsSync20(path65)) {
|
|
37296
37872
|
throw new Error(`File not found: ${path65}`);
|
|
37297
37873
|
}
|
|
37298
37874
|
const md = readFileSync16(path65, "utf8");
|
|
@@ -37300,7 +37876,7 @@ var init_storage = __esm({
|
|
|
37300
37876
|
}
|
|
37301
37877
|
/** Read a Markdown file; returns null if not found. */
|
|
37302
37878
|
readIfExists(path65) {
|
|
37303
|
-
if (!
|
|
37879
|
+
if (!existsSync20(path65)) return null;
|
|
37304
37880
|
return this.read(path65);
|
|
37305
37881
|
}
|
|
37306
37882
|
/**
|
|
@@ -37316,7 +37892,7 @@ var init_storage = __esm({
|
|
|
37316
37892
|
}
|
|
37317
37893
|
/** List all .md files in a directory (non-recursive). */
|
|
37318
37894
|
listMarkdown(dir) {
|
|
37319
|
-
if (!
|
|
37895
|
+
if (!existsSync20(dir)) return [];
|
|
37320
37896
|
return readdirSync4(dir).filter((f) => f.endsWith(".md") && !f.startsWith(".")).map((f) => join14(dir, f));
|
|
37321
37897
|
}
|
|
37322
37898
|
};
|
|
@@ -37349,7 +37925,7 @@ var init_storage = __esm({
|
|
|
37349
37925
|
// src/cli/workspace/planStore.ts
|
|
37350
37926
|
import {
|
|
37351
37927
|
copyFileSync,
|
|
37352
|
-
existsSync as
|
|
37928
|
+
existsSync as existsSync21,
|
|
37353
37929
|
mkdirSync as mkdirSync12,
|
|
37354
37930
|
readFileSync as readFileSync17,
|
|
37355
37931
|
renameSync as renameSync3,
|
|
@@ -37400,7 +37976,7 @@ function writePlanTaskArtifact(rootDir, task) {
|
|
|
37400
37976
|
}
|
|
37401
37977
|
function loadHandle(rootDir) {
|
|
37402
37978
|
const jsonPath = join15(rootDir, "plan.json");
|
|
37403
|
-
if (!
|
|
37979
|
+
if (!existsSync21(jsonPath)) {
|
|
37404
37980
|
return { rootDir, tasks: [], counter: 0, rootFields: {} };
|
|
37405
37981
|
}
|
|
37406
37982
|
let parsed;
|
|
@@ -37435,7 +38011,7 @@ function saveHandle(rootDir, handle) {
|
|
|
37435
38011
|
}
|
|
37436
38012
|
const jsonPath = join15(rootDir, "plan.json");
|
|
37437
38013
|
mkdirSync12(rootDir, { recursive: true });
|
|
37438
|
-
if (
|
|
38014
|
+
if (existsSync21(jsonPath)) {
|
|
37439
38015
|
copyFileSync(jsonPath, `${jsonPath}.bak`);
|
|
37440
38016
|
}
|
|
37441
38017
|
const file2 = {
|
|
@@ -37717,8 +38293,8 @@ var init_planTaskTools = __esm({
|
|
|
37717
38293
|
|
|
37718
38294
|
// src/cli/tools/inspectTypecheckSafety.ts
|
|
37719
38295
|
import { promises as fs16 } from "node:fs";
|
|
37720
|
-
import
|
|
37721
|
-
import { spawn as
|
|
38296
|
+
import path31 from "node:path";
|
|
38297
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
37722
38298
|
async function scanTsbuildinfo(root) {
|
|
37723
38299
|
const found = [];
|
|
37724
38300
|
const stack = [root];
|
|
@@ -37731,11 +38307,11 @@ async function scanTsbuildinfo(root) {
|
|
|
37731
38307
|
continue;
|
|
37732
38308
|
}
|
|
37733
38309
|
for (const entry of entries) {
|
|
37734
|
-
const p3 =
|
|
38310
|
+
const p3 = path31.join(dir, entry.name);
|
|
37735
38311
|
if (entry.isDirectory()) {
|
|
37736
38312
|
if (!SCAN_SKIP.has(entry.name)) stack.push(p3);
|
|
37737
38313
|
} else if (entry.name.endsWith(".tsbuildinfo")) {
|
|
37738
|
-
found.push(
|
|
38314
|
+
found.push(path31.relative(root, p3).split(path31.sep).join("/"));
|
|
37739
38315
|
}
|
|
37740
38316
|
}
|
|
37741
38317
|
}
|
|
@@ -37744,7 +38320,7 @@ async function scanTsbuildinfo(root) {
|
|
|
37744
38320
|
}
|
|
37745
38321
|
async function gitStatusPorcelain(root) {
|
|
37746
38322
|
return new Promise((resolve3) => {
|
|
37747
|
-
const child =
|
|
38323
|
+
const child = spawn7("git", ["status", "--porcelain"], { cwd: root, shell: false });
|
|
37748
38324
|
let out = "";
|
|
37749
38325
|
child.stdout.on("data", (d) => out += d.toString());
|
|
37750
38326
|
child.stderr.on("data", (d) => out += d.toString());
|
|
@@ -37771,7 +38347,7 @@ async function cleanupArtifacts(root, relPaths) {
|
|
|
37771
38347
|
const failed = [];
|
|
37772
38348
|
for (const rel2 of relPaths) {
|
|
37773
38349
|
try {
|
|
37774
|
-
await fs16.unlink(
|
|
38350
|
+
await fs16.unlink(path31.join(root, rel2));
|
|
37775
38351
|
cleaned.push(rel2);
|
|
37776
38352
|
} catch {
|
|
37777
38353
|
failed.push(rel2);
|
|
@@ -37794,17 +38370,17 @@ var init_inspectTypecheckSafety = __esm({
|
|
|
37794
38370
|
});
|
|
37795
38371
|
|
|
37796
38372
|
// src/cli/tools/inspectCommand.ts
|
|
37797
|
-
import { spawn as
|
|
37798
|
-
import { createHash as
|
|
37799
|
-
import { existsSync as
|
|
38373
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
38374
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
38375
|
+
import { existsSync as existsSync22, promises as fs17 } from "node:fs";
|
|
37800
38376
|
import os8 from "node:os";
|
|
37801
|
-
import
|
|
38377
|
+
import path32 from "node:path";
|
|
37802
38378
|
function resolveNodeModuleBin(start, rel2) {
|
|
37803
|
-
let dir =
|
|
38379
|
+
let dir = path32.resolve(start);
|
|
37804
38380
|
for (; ; ) {
|
|
37805
|
-
const candidate =
|
|
37806
|
-
if (
|
|
37807
|
-
const parent =
|
|
38381
|
+
const candidate = path32.join(dir, "node_modules", rel2);
|
|
38382
|
+
if (existsSync22(candidate)) return candidate;
|
|
38383
|
+
const parent = path32.dirname(dir);
|
|
37808
38384
|
if (parent === dir) return void 0;
|
|
37809
38385
|
dir = parent;
|
|
37810
38386
|
}
|
|
@@ -37872,7 +38448,7 @@ function buildInspectCommand(op, ctx) {
|
|
|
37872
38448
|
case "npm_ls":
|
|
37873
38449
|
case "npm_outdated":
|
|
37874
38450
|
case "npm_view": {
|
|
37875
|
-
const npmCli = ctx.npmCliPath ?? resolveNodeModuleBin(ctx.root,
|
|
38451
|
+
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
38452
|
if (op.operation === "npm_view") {
|
|
37877
38453
|
const err = rejectFlagLike("package", op.package);
|
|
37878
38454
|
if (err) return { ok: false, reason: err };
|
|
@@ -37881,14 +38457,14 @@ function buildInspectCommand(op, ctx) {
|
|
|
37881
38457
|
return { ok: true, command: process.execPath, argv: [npmCli, ...sub], inspectionClass: "env-info" };
|
|
37882
38458
|
}
|
|
37883
38459
|
case "typecheck": {
|
|
37884
|
-
const project =
|
|
37885
|
-
const hash3 =
|
|
37886
|
-
const tsBuildInfoFile =
|
|
38460
|
+
const project = path32.resolve(ctx.cwd, op.project ?? "tsconfig.json");
|
|
38461
|
+
const hash3 = createHash9("sha256").update(project).digest("hex").slice(0, 16);
|
|
38462
|
+
const tsBuildInfoFile = path32.join(os8.tmpdir(), "zelari-inspect", `${hash3}.tsbuildinfo`);
|
|
37887
38463
|
return {
|
|
37888
38464
|
ok: true,
|
|
37889
38465
|
command: process.execPath,
|
|
37890
38466
|
argv: [
|
|
37891
|
-
ctx.tscPath ?? resolveNodeModuleBin(ctx.root,
|
|
38467
|
+
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
38468
|
"--noEmit",
|
|
37893
38469
|
// S3.5 primary mechanism: redirect, never disable — composite forces
|
|
37894
38470
|
// incremental (TS#30661), so --incremental false would break on the
|
|
@@ -37910,7 +38486,7 @@ function runSpawn(command, argv, opts) {
|
|
|
37910
38486
|
return new Promise((resolve3) => {
|
|
37911
38487
|
let child;
|
|
37912
38488
|
try {
|
|
37913
|
-
child =
|
|
38489
|
+
child = spawn8(command, argv, { cwd: opts.cwd, shell: false });
|
|
37914
38490
|
} catch (err) {
|
|
37915
38491
|
resolve3({ code: null, stdout: "", stderr: String(err), timedOut: false, spawnError: String(err) });
|
|
37916
38492
|
return;
|
|
@@ -38648,9 +39224,9 @@ var init_client = __esm({
|
|
|
38648
39224
|
});
|
|
38649
39225
|
|
|
38650
39226
|
// src/cli/lsp/servers.ts
|
|
38651
|
-
import
|
|
39227
|
+
import path33 from "node:path";
|
|
38652
39228
|
function languageIdForFile(file2) {
|
|
38653
|
-
const ext =
|
|
39229
|
+
const ext = path33.extname(file2).toLowerCase();
|
|
38654
39230
|
const map2 = {
|
|
38655
39231
|
".ts": "typescript",
|
|
38656
39232
|
".tsx": "typescriptreact",
|
|
@@ -38665,7 +39241,7 @@ function languageIdForFile(file2) {
|
|
|
38665
39241
|
return map2[ext] ?? "plaintext";
|
|
38666
39242
|
}
|
|
38667
39243
|
function serverForFile(file2, servers = LSP_SERVERS) {
|
|
38668
|
-
const ext =
|
|
39244
|
+
const ext = path33.extname(file2).toLowerCase();
|
|
38669
39245
|
return servers.find((s) => s.extensions.includes(ext)) ?? null;
|
|
38670
39246
|
}
|
|
38671
39247
|
function resolveServerCommand(file2, cwd, servers = LSP_SERVERS) {
|
|
@@ -38714,7 +39290,7 @@ var init_servers = __esm({
|
|
|
38714
39290
|
});
|
|
38715
39291
|
|
|
38716
39292
|
// src/cli/lsp/manager.ts
|
|
38717
|
-
import { spawn as
|
|
39293
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
38718
39294
|
import { readFileSync as readFileSync18 } from "node:fs";
|
|
38719
39295
|
function processTransport(child) {
|
|
38720
39296
|
return {
|
|
@@ -38850,7 +39426,7 @@ var init_manager = __esm({
|
|
|
38850
39426
|
// languages already flagged as unavailable
|
|
38851
39427
|
constructor(options = {}) {
|
|
38852
39428
|
this.cwd = options.cwd ?? process.cwd();
|
|
38853
|
-
this.spawnImpl = options.spawnImpl ??
|
|
39429
|
+
this.spawnImpl = options.spawnImpl ?? spawn9;
|
|
38854
39430
|
this.timeoutMs = options.timeoutMs ?? 15e3;
|
|
38855
39431
|
this.onWarn = options.onWarn ?? ((m) => console.error(m));
|
|
38856
39432
|
}
|
|
@@ -39041,7 +39617,7 @@ var init_manager = __esm({
|
|
|
39041
39617
|
|
|
39042
39618
|
// src/cli/ast/engine.ts
|
|
39043
39619
|
import { readFile } from "node:fs/promises";
|
|
39044
|
-
import
|
|
39620
|
+
import path34 from "node:path";
|
|
39045
39621
|
function loadTs() {
|
|
39046
39622
|
if (!tsPromise) {
|
|
39047
39623
|
tsPromise = import("typescript").then((m) => m.default ?? m).catch(() => null);
|
|
@@ -39052,8 +39628,8 @@ function errMessage(err) {
|
|
|
39052
39628
|
return err instanceof Error ? err.message : String(err);
|
|
39053
39629
|
}
|
|
39054
39630
|
async function parseFileSymbolsDiag(file2, cwd) {
|
|
39055
|
-
const resolvedPath =
|
|
39056
|
-
const extension =
|
|
39631
|
+
const resolvedPath = path34.isAbsolute(file2) ? file2 : path34.join(cwd ?? process.cwd(), file2);
|
|
39632
|
+
const extension = path34.extname(resolvedPath).toLowerCase();
|
|
39057
39633
|
if (!TS_EXTENSIONS.has(extension)) {
|
|
39058
39634
|
return {
|
|
39059
39635
|
status: "unsupported-extension",
|
|
@@ -39095,7 +39671,7 @@ async function parseFileSymbolsDiag(file2, cwd) {
|
|
|
39095
39671
|
}
|
|
39096
39672
|
let source;
|
|
39097
39673
|
try {
|
|
39098
|
-
source = ts.createSourceFile(
|
|
39674
|
+
source = ts.createSourceFile(path34.basename(resolvedPath), text, ts.ScriptTarget.Latest, true);
|
|
39099
39675
|
} catch (err) {
|
|
39100
39676
|
return {
|
|
39101
39677
|
status: "parse-error",
|
|
@@ -39318,13 +39894,13 @@ var init_store2 = __esm({
|
|
|
39318
39894
|
});
|
|
39319
39895
|
|
|
39320
39896
|
// src/cli/semantic/index.ts
|
|
39321
|
-
import { promises as fs18, existsSync as
|
|
39897
|
+
import { promises as fs18, existsSync as existsSync23, readFileSync as readFileSync19 } from "node:fs";
|
|
39322
39898
|
import { homedir as homedir6 } from "node:os";
|
|
39323
|
-
import
|
|
39324
|
-
import { createHash as
|
|
39899
|
+
import path35 from "node:path";
|
|
39900
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
39325
39901
|
function getIndexPath(root) {
|
|
39326
|
-
const hash3 =
|
|
39327
|
-
return process.env.ZELARI_SEMANTIC_FILE ??
|
|
39902
|
+
const hash3 = createHash10("sha1").update(path35.resolve(root)).digest("hex").slice(0, 16);
|
|
39903
|
+
return process.env.ZELARI_SEMANTIC_FILE ?? path35.join(homedir6(), ".tmp", "zelari-code", "semantic", `${hash3}.json`);
|
|
39328
39904
|
}
|
|
39329
39905
|
async function collectSourceFiles(root, maxFiles = 1500) {
|
|
39330
39906
|
const out = [];
|
|
@@ -39342,11 +39918,11 @@ async function collectSourceFiles(root, maxFiles = 1500) {
|
|
|
39342
39918
|
if (entry.isDirectory() && IGNORE_DIRS.has(entry.name)) continue;
|
|
39343
39919
|
if (entry.isDirectory()) continue;
|
|
39344
39920
|
}
|
|
39345
|
-
const full =
|
|
39921
|
+
const full = path35.join(dir, entry.name);
|
|
39346
39922
|
if (entry.isDirectory()) {
|
|
39347
39923
|
if (IGNORE_DIRS.has(entry.name)) continue;
|
|
39348
39924
|
await walk2(full);
|
|
39349
|
-
} else if (SOURCE_EXTENSIONS.has(
|
|
39925
|
+
} else if (SOURCE_EXTENSIONS.has(path35.extname(entry.name).toLowerCase())) {
|
|
39350
39926
|
out.push(full);
|
|
39351
39927
|
}
|
|
39352
39928
|
}
|
|
@@ -39395,14 +39971,14 @@ async function buildIndex(files, embed, options) {
|
|
|
39395
39971
|
}
|
|
39396
39972
|
async function saveIndex(root, data) {
|
|
39397
39973
|
const file2 = getIndexPath(root);
|
|
39398
|
-
await fs18.mkdir(
|
|
39974
|
+
await fs18.mkdir(path35.dirname(file2), { recursive: true });
|
|
39399
39975
|
const tmp = `${file2}.tmp-${process.pid}`;
|
|
39400
39976
|
await fs18.writeFile(tmp, JSON.stringify(data), "utf8");
|
|
39401
39977
|
await fs18.rename(tmp, file2);
|
|
39402
39978
|
}
|
|
39403
39979
|
function loadIndex(root) {
|
|
39404
39980
|
const file2 = getIndexPath(root);
|
|
39405
|
-
if (!
|
|
39981
|
+
if (!existsSync23(file2)) return null;
|
|
39406
39982
|
try {
|
|
39407
39983
|
const parsed = JSON.parse(readFileSync19(file2, "utf8"));
|
|
39408
39984
|
if (parsed && Array.isArray(parsed.chunks)) return parsed;
|
|
@@ -39547,7 +40123,7 @@ var init_provider = __esm({
|
|
|
39547
40123
|
});
|
|
39548
40124
|
|
|
39549
40125
|
// src/cli/semantic/tools.ts
|
|
39550
|
-
import
|
|
40126
|
+
import path36 from "node:path";
|
|
39551
40127
|
function createSemanticTool(deps) {
|
|
39552
40128
|
const buildEmbedFn = deps.buildEmbedFn ?? buildProviderEmbedFn;
|
|
39553
40129
|
return {
|
|
@@ -39574,7 +40150,7 @@ function createSemanticTool(deps) {
|
|
|
39574
40150
|
return typedOk({
|
|
39575
40151
|
count: res.hits.length,
|
|
39576
40152
|
results: res.hits.map((h) => ({
|
|
39577
|
-
location: `${
|
|
40153
|
+
location: `${path36.relative(deps.root, h.file) || h.file}:${h.startLine}-${h.endLine}`,
|
|
39578
40154
|
score: Number(h.score.toFixed(3)),
|
|
39579
40155
|
preview: h.text.length > 400 ? `${h.text.slice(0, 400)}\u2026` : h.text
|
|
39580
40156
|
}))
|
|
@@ -39593,8 +40169,8 @@ var init_tools4 = __esm({
|
|
|
39593
40169
|
});
|
|
39594
40170
|
|
|
39595
40171
|
// src/cli/browser/driver.ts
|
|
39596
|
-
import { createRequire } from "node:module";
|
|
39597
|
-
import
|
|
40172
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
40173
|
+
import path37 from "node:path";
|
|
39598
40174
|
import { pathToFileURL } from "node:url";
|
|
39599
40175
|
function asPlaywright(mod) {
|
|
39600
40176
|
if (!mod || typeof mod !== "object") return null;
|
|
@@ -39605,10 +40181,10 @@ function asPlaywright(mod) {
|
|
|
39605
40181
|
return null;
|
|
39606
40182
|
}
|
|
39607
40183
|
async function loadPlaywright(cwd) {
|
|
39608
|
-
const base = cwd && cwd.length > 0 ?
|
|
40184
|
+
const base = cwd && cwd.length > 0 ? path37.resolve(cwd) : void 0;
|
|
39609
40185
|
if (base) {
|
|
39610
40186
|
try {
|
|
39611
|
-
const req =
|
|
40187
|
+
const req = createRequire2(path37.join(base, "package.json"));
|
|
39612
40188
|
const resolved = req.resolve("playwright");
|
|
39613
40189
|
const mod = await import(pathToFileURL(resolved).href);
|
|
39614
40190
|
const pw = asPlaywright(mod);
|
|
@@ -39823,7 +40399,7 @@ var init_driver = __esm({
|
|
|
39823
40399
|
});
|
|
39824
40400
|
|
|
39825
40401
|
// src/cli/browser/tools.ts
|
|
39826
|
-
import
|
|
40402
|
+
import path38 from "node:path";
|
|
39827
40403
|
import os9 from "node:os";
|
|
39828
40404
|
function createBrowserTool(deps = {}) {
|
|
39829
40405
|
return {
|
|
@@ -39842,7 +40418,7 @@ function createBrowserTool(deps = {}) {
|
|
|
39842
40418
|
execute: async (args, ctx) => {
|
|
39843
40419
|
const a = args;
|
|
39844
40420
|
const dir = deps.screenshotDir ?? os9.tmpdir();
|
|
39845
|
-
const screenshotPath = a.screenshot === false ? void 0 :
|
|
40421
|
+
const screenshotPath = a.screenshot === false ? void 0 : path38.join(dir, `zelari-browser-${Date.now()}.png`);
|
|
39846
40422
|
const result = await runBrowserCheck(
|
|
39847
40423
|
{
|
|
39848
40424
|
url: a.url,
|
|
@@ -39934,14 +40510,14 @@ __export(targets_exports, {
|
|
|
39934
40510
|
});
|
|
39935
40511
|
import {
|
|
39936
40512
|
chmodSync,
|
|
39937
|
-
existsSync as
|
|
40513
|
+
existsSync as existsSync24,
|
|
39938
40514
|
mkdirSync as mkdirSync13,
|
|
39939
40515
|
readFileSync as readFileSync20,
|
|
39940
40516
|
writeFileSync as writeFileSync15
|
|
39941
40517
|
} from "node:fs";
|
|
39942
40518
|
import { dirname as dirname4, join as join16 } from "node:path";
|
|
39943
40519
|
import { homedir as homedir7 } from "node:os";
|
|
39944
|
-
import { spawn as
|
|
40520
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
39945
40521
|
function getSshTargetsPath() {
|
|
39946
40522
|
return join16(homedir7(), ".zelari-code", "ssh-targets.json");
|
|
39947
40523
|
}
|
|
@@ -39955,7 +40531,7 @@ function normalizeAuth(auth) {
|
|
|
39955
40531
|
}
|
|
39956
40532
|
function readSecrets() {
|
|
39957
40533
|
const path65 = getSshSecretsPath();
|
|
39958
|
-
if (!
|
|
40534
|
+
if (!existsSync24(path65)) return {};
|
|
39959
40535
|
try {
|
|
39960
40536
|
return JSON.parse(readFileSync20(path65, "utf8"));
|
|
39961
40537
|
} catch {
|
|
@@ -39998,7 +40574,7 @@ function deleteSshPassword(id) {
|
|
|
39998
40574
|
}
|
|
39999
40575
|
function readStore2() {
|
|
40000
40576
|
const path65 = getSshTargetsPath();
|
|
40001
|
-
if (!
|
|
40577
|
+
if (!existsSync24(path65)) return [];
|
|
40002
40578
|
try {
|
|
40003
40579
|
const parsed = JSON.parse(readFileSync20(path65, "utf8"));
|
|
40004
40580
|
const list = Array.isArray(parsed.targets) ? parsed.targets : [];
|
|
@@ -40171,7 +40747,7 @@ function runSsh(target, remoteCommand, timeoutMs2 = 6e4) {
|
|
|
40171
40747
|
if (!env.DISPLAY) env.DISPLAY = "1";
|
|
40172
40748
|
env.ZELARI_SSH_ASKPASS_PASS = pass;
|
|
40173
40749
|
}
|
|
40174
|
-
const child =
|
|
40750
|
+
const child = spawn10("ssh", args, {
|
|
40175
40751
|
windowsHide: true,
|
|
40176
40752
|
env,
|
|
40177
40753
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -40212,7 +40788,7 @@ function readSshPublicKey(keyOrPubPath) {
|
|
|
40212
40788
|
if (!raw) return { ok: false, error: "Empty path" };
|
|
40213
40789
|
const candidates = raw.endsWith(".pub") ? [raw] : [`${raw}.pub`, raw];
|
|
40214
40790
|
for (const p3 of candidates) {
|
|
40215
|
-
if (!
|
|
40791
|
+
if (!existsSync24(p3)) continue;
|
|
40216
40792
|
try {
|
|
40217
40793
|
const content = readFileSync20(p3, "utf8").trim();
|
|
40218
40794
|
if (!content) continue;
|
|
@@ -40396,10 +40972,10 @@ var init_tools6 = __esm({
|
|
|
40396
40972
|
|
|
40397
40973
|
// src/cli/workspace/worldModel.ts
|
|
40398
40974
|
import { promises as fs19 } from "node:fs";
|
|
40399
|
-
import
|
|
40400
|
-
import { spawn as
|
|
40975
|
+
import path39 from "node:path";
|
|
40976
|
+
import { spawn as spawn11 } from "node:child_process";
|
|
40401
40977
|
function worldDir(cwd) {
|
|
40402
|
-
return
|
|
40978
|
+
return path39.join(cwd, WORLD_DIR_NAME);
|
|
40403
40979
|
}
|
|
40404
40980
|
async function ensureWorldDir(cwd) {
|
|
40405
40981
|
const dir = worldDir(cwd);
|
|
@@ -40409,10 +40985,10 @@ async function ensureWorldDir(cwd) {
|
|
|
40409
40985
|
async function appendTimeline(cwd, entry) {
|
|
40410
40986
|
const dir = await ensureWorldDir(cwd);
|
|
40411
40987
|
const line = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }) + "\n";
|
|
40412
|
-
await fs19.appendFile(
|
|
40988
|
+
await fs19.appendFile(path39.join(dir, TIMELINE_FILE), line, "utf8");
|
|
40413
40989
|
}
|
|
40414
40990
|
async function readChecks(cwd) {
|
|
40415
|
-
const p3 =
|
|
40991
|
+
const p3 = path39.join(worldDir(cwd), CHECKS_FILE);
|
|
40416
40992
|
try {
|
|
40417
40993
|
const raw = await fs19.readFile(p3, "utf8");
|
|
40418
40994
|
const parsed = JSON.parse(raw);
|
|
@@ -40424,7 +41000,7 @@ async function readChecks(cwd) {
|
|
|
40424
41000
|
function runShell(command, cwd, timeoutMs2, signal) {
|
|
40425
41001
|
return new Promise((resolve3) => {
|
|
40426
41002
|
const isWin = process.platform === "win32";
|
|
40427
|
-
const child =
|
|
41003
|
+
const child = spawn11(isWin ? "cmd.exe" : "/bin/sh", isWin ? ["/c", command] : ["-c", command], {
|
|
40428
41004
|
cwd,
|
|
40429
41005
|
env: process.env,
|
|
40430
41006
|
windowsHide: true,
|
|
@@ -40487,8 +41063,8 @@ function runShell(command, cwd, timeoutMs2, signal) {
|
|
|
40487
41063
|
});
|
|
40488
41064
|
}
|
|
40489
41065
|
async function runBacktest(cwd, signal) {
|
|
40490
|
-
const checksPath =
|
|
40491
|
-
const hypothesisPath =
|
|
41066
|
+
const checksPath = path39.join(worldDir(cwd), CHECKS_FILE);
|
|
41067
|
+
const hypothesisPath = path39.join(worldDir(cwd), HYPOTHESIS_FILE);
|
|
40492
41068
|
const checks = await readChecks(cwd);
|
|
40493
41069
|
if (checks.length === 0) {
|
|
40494
41070
|
return {
|
|
@@ -40557,7 +41133,7 @@ var init_worldModel = __esm({
|
|
|
40557
41133
|
"use strict";
|
|
40558
41134
|
init_zod();
|
|
40559
41135
|
init_toolTypes();
|
|
40560
|
-
WORLD_DIR_NAME =
|
|
41136
|
+
WORLD_DIR_NAME = path39.join(".zelari", "world");
|
|
40561
41137
|
HYPOTHESIS_FILE = "hypothesis.md";
|
|
40562
41138
|
CHECKS_FILE = "checks.json";
|
|
40563
41139
|
TIMELINE_FILE = "timeline.jsonl";
|
|
@@ -40574,7 +41150,7 @@ var init_worldModel = __esm({
|
|
|
40574
41150
|
execute: async (args, ctx) => {
|
|
40575
41151
|
try {
|
|
40576
41152
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
40577
|
-
const file2 =
|
|
41153
|
+
const file2 = path39.join(dir, HYPOTHESIS_FILE);
|
|
40578
41154
|
if (args.append) {
|
|
40579
41155
|
const block = `
|
|
40580
41156
|
|
|
@@ -40613,7 +41189,7 @@ ${args.content}
|
|
|
40613
41189
|
execute: async (args, ctx) => {
|
|
40614
41190
|
try {
|
|
40615
41191
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
40616
|
-
const file2 =
|
|
41192
|
+
const file2 = path39.join(dir, CHECKS_FILE);
|
|
40617
41193
|
const body = { checks: args.checks };
|
|
40618
41194
|
await fs19.writeFile(file2, JSON.stringify(body, null, 2) + "\n", "utf8");
|
|
40619
41195
|
await appendTimeline(ctx.cwd, { kind: "checks_set", count: args.checks.length });
|
|
@@ -40652,8 +41228,8 @@ ${args.content}
|
|
|
40652
41228
|
stdoutPreview: "(dryRun)",
|
|
40653
41229
|
mismatch: "dryRun"
|
|
40654
41230
|
})),
|
|
40655
|
-
hypothesisPath:
|
|
40656
|
-
checksPath:
|
|
41231
|
+
hypothesisPath: path39.join(worldDir(ctx.cwd), HYPOTHESIS_FILE),
|
|
41232
|
+
checksPath: path39.join(worldDir(ctx.cwd), CHECKS_FILE)
|
|
40657
41233
|
});
|
|
40658
41234
|
}
|
|
40659
41235
|
const result = await runBacktest(ctx.cwd, ctx.signal);
|
|
@@ -40677,7 +41253,7 @@ ${args.content}
|
|
|
40677
41253
|
execute: async (args, ctx) => {
|
|
40678
41254
|
try {
|
|
40679
41255
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
40680
|
-
const file2 =
|
|
41256
|
+
const file2 = path39.join(dir, TIMELINE_FILE);
|
|
40681
41257
|
await appendTimeline(ctx.cwd, {
|
|
40682
41258
|
kind: args.kind,
|
|
40683
41259
|
summary: args.summary,
|
|
@@ -40785,13 +41361,13 @@ __export(folderTrust_exports, {
|
|
|
40785
41361
|
untrustFolder: () => untrustFolder
|
|
40786
41362
|
});
|
|
40787
41363
|
import { homedir as homedir8 } from "node:os";
|
|
40788
|
-
import { existsSync as
|
|
40789
|
-
import
|
|
41364
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync14, readFileSync as readFileSync21, writeFileSync as writeFileSync16 } from "node:fs";
|
|
41365
|
+
import path40 from "node:path";
|
|
40790
41366
|
function trustStorePath() {
|
|
40791
|
-
return _overrideStorePath ??
|
|
41367
|
+
return _overrideStorePath ?? path40.join(homedir8(), ".zelari-code", "trust.json");
|
|
40792
41368
|
}
|
|
40793
41369
|
function normalize4(p3) {
|
|
40794
|
-
const resolved =
|
|
41370
|
+
const resolved = path40.resolve(p3);
|
|
40795
41371
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
40796
41372
|
}
|
|
40797
41373
|
function readStore3() {
|
|
@@ -40807,7 +41383,7 @@ function readStore3() {
|
|
|
40807
41383
|
function writeStore3(store6) {
|
|
40808
41384
|
const p3 = trustStorePath();
|
|
40809
41385
|
try {
|
|
40810
|
-
mkdirSync14(
|
|
41386
|
+
mkdirSync14(path40.dirname(p3), { recursive: true });
|
|
40811
41387
|
writeFileSync16(p3, JSON.stringify(store6, null, 2), "utf8");
|
|
40812
41388
|
} catch (err) {
|
|
40813
41389
|
throw new Error(
|
|
@@ -40833,7 +41409,7 @@ function isFolderTrusted(folderPath) {
|
|
|
40833
41409
|
}
|
|
40834
41410
|
function trustFolder(folderPath) {
|
|
40835
41411
|
const store6 = readStore3();
|
|
40836
|
-
const normalized =
|
|
41412
|
+
const normalized = path40.resolve(folderPath);
|
|
40837
41413
|
if (!store6.folders.some((f) => normalize4(f.path) === normalize4(normalized))) {
|
|
40838
41414
|
store6.folders.push({ path: normalized, trustedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
40839
41415
|
writeStore3(store6);
|
|
@@ -40863,7 +41439,7 @@ function getTrustStorePath() {
|
|
|
40863
41439
|
return trustStorePath();
|
|
40864
41440
|
}
|
|
40865
41441
|
function hasTrustStore() {
|
|
40866
|
-
return
|
|
41442
|
+
return existsSync25(trustStorePath());
|
|
40867
41443
|
}
|
|
40868
41444
|
function _setTrustStorePathForTests(p3) {
|
|
40869
41445
|
_overrideStorePath = p3;
|
|
@@ -40947,9 +41523,9 @@ var init_lifecycleHooks = __esm({
|
|
|
40947
41523
|
});
|
|
40948
41524
|
|
|
40949
41525
|
// src/cli/toolResultCache.ts
|
|
40950
|
-
import { createHash as
|
|
41526
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
40951
41527
|
import { promises as fs20 } from "node:fs";
|
|
40952
|
-
import
|
|
41528
|
+
import path41 from "node:path";
|
|
40953
41529
|
function isToolCacheEnabled() {
|
|
40954
41530
|
const raw = process.env.ZELARI_TOOL_CACHE;
|
|
40955
41531
|
return raw !== "0" && raw !== "false" && raw !== "off";
|
|
@@ -40960,7 +41536,7 @@ function resolveToolCacheTtlMs() {
|
|
|
40960
41536
|
return Number.isFinite(n) && n >= 0 ? n : TOOL_CACHE_DEFAULT_TTL_MS;
|
|
40961
41537
|
}
|
|
40962
41538
|
function hashKey(parts) {
|
|
40963
|
-
return
|
|
41539
|
+
return createHash11("sha256").update(JSON.stringify(parts), "utf8").digest("hex");
|
|
40964
41540
|
}
|
|
40965
41541
|
function resultBytes(result) {
|
|
40966
41542
|
try {
|
|
@@ -41034,7 +41610,7 @@ async function statKey(toolName, input, ctx) {
|
|
|
41034
41610
|
if (!input || typeof input !== "object") return null;
|
|
41035
41611
|
const rawPath = input.path;
|
|
41036
41612
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
41037
|
-
const abs =
|
|
41613
|
+
const abs = path41.isAbsolute(rawPath) ? rawPath : path41.join(ctx.cwd, rawPath);
|
|
41038
41614
|
try {
|
|
41039
41615
|
const st = await fs20.stat(abs);
|
|
41040
41616
|
return hashKey({
|
|
@@ -41715,14 +42291,14 @@ var init_toolRegistry = __esm({
|
|
|
41715
42291
|
});
|
|
41716
42292
|
|
|
41717
42293
|
// src/cli/state/fileStateStore.ts
|
|
41718
|
-
import { createHash as
|
|
42294
|
+
import { createHash as createHash13, randomUUID as randomUUID2 } from "node:crypto";
|
|
41719
42295
|
import { promises as fs21 } from "node:fs";
|
|
41720
|
-
import * as
|
|
42296
|
+
import * as path43 from "node:path";
|
|
41721
42297
|
function shortId() {
|
|
41722
42298
|
return randomUUID2().replace(/-/g, "").slice(0, 12);
|
|
41723
42299
|
}
|
|
41724
42300
|
async function writeJsonAtomic(filePath, data) {
|
|
41725
|
-
await fs21.mkdir(
|
|
42301
|
+
await fs21.mkdir(path43.dirname(filePath), { recursive: true });
|
|
41726
42302
|
const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
41727
42303
|
await fs21.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
41728
42304
|
await fs21.rename(tmp, filePath);
|
|
@@ -41767,7 +42343,7 @@ async function getStateStore(projectRoot, env = process.env) {
|
|
|
41767
42343
|
}
|
|
41768
42344
|
}
|
|
41769
42345
|
function hashStablePrompt(stable) {
|
|
41770
|
-
return
|
|
42346
|
+
return createHash13("sha256").update(stable, "utf8").digest("hex").slice(0, 16);
|
|
41771
42347
|
}
|
|
41772
42348
|
var DEFAULT_MATERIALIZE_CHARS, FileDurableStateStore, NoopDurableStateStore;
|
|
41773
42349
|
var init_fileStateStore = __esm({
|
|
@@ -41783,11 +42359,11 @@ var init_fileStateStore = __esm({
|
|
|
41783
42359
|
indexPath = "";
|
|
41784
42360
|
async init(projectRoot) {
|
|
41785
42361
|
this.root = projectRoot;
|
|
41786
|
-
this.stateDir =
|
|
41787
|
-
this.commitsDir =
|
|
41788
|
-
this.artifactsDir =
|
|
41789
|
-
this.headPath =
|
|
41790
|
-
this.indexPath =
|
|
42362
|
+
this.stateDir = path43.join(projectRoot, ".zelari", "state");
|
|
42363
|
+
this.commitsDir = path43.join(this.stateDir, "commits");
|
|
42364
|
+
this.artifactsDir = path43.join(this.stateDir, "artifacts");
|
|
42365
|
+
this.headPath = path43.join(this.stateDir, "HEAD.json");
|
|
42366
|
+
this.indexPath = path43.join(this.stateDir, "index.jsonl");
|
|
41791
42367
|
await fs21.mkdir(this.commitsDir, { recursive: true });
|
|
41792
42368
|
await fs21.mkdir(this.artifactsDir, { recursive: true });
|
|
41793
42369
|
}
|
|
@@ -41800,13 +42376,13 @@ var init_fileStateStore = __esm({
|
|
|
41800
42376
|
const discoveries = input.discoveries ?? [];
|
|
41801
42377
|
const parent = await this.head();
|
|
41802
42378
|
const id = shortId();
|
|
41803
|
-
const artifactRel =
|
|
41804
|
-
const artifactAbs =
|
|
42379
|
+
const artifactRel = path43.join("artifacts", id);
|
|
42380
|
+
const artifactAbs = path43.join(this.artifactsDir, id);
|
|
41805
42381
|
await fs21.mkdir(artifactAbs, { recursive: true });
|
|
41806
42382
|
const summary = defaultSummary(input, discoveries);
|
|
41807
|
-
await fs21.writeFile(
|
|
41808
|
-
await writeJsonAtomic(
|
|
41809
|
-
await writeJsonAtomic(
|
|
42383
|
+
await fs21.writeFile(path43.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
|
|
42384
|
+
await writeJsonAtomic(path43.join(artifactAbs, "discoveries.json"), discoveries);
|
|
42385
|
+
await writeJsonAtomic(path43.join(artifactAbs, "verification.json"), input.verification);
|
|
41810
42386
|
const meta3 = {
|
|
41811
42387
|
id,
|
|
41812
42388
|
parentId: parent?.id ?? null,
|
|
@@ -41818,14 +42394,14 @@ var init_fileStateStore = __esm({
|
|
|
41818
42394
|
workspaceCheckpointId: input.workspaceCheckpointId,
|
|
41819
42395
|
verification: {
|
|
41820
42396
|
...input.verification,
|
|
41821
|
-
reportPath: input.verification.reportPath ??
|
|
42397
|
+
reportPath: input.verification.reportPath ?? path43.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
|
|
41822
42398
|
},
|
|
41823
42399
|
changedPaths: input.changedPaths ?? [],
|
|
41824
42400
|
stablePromptHash: input.stablePromptHash,
|
|
41825
42401
|
discoveryCount: discoveries.length,
|
|
41826
42402
|
artifactDir: artifactRel.replace(/\\/g, "/")
|
|
41827
42403
|
};
|
|
41828
|
-
await writeJsonAtomic(
|
|
42404
|
+
await writeJsonAtomic(path43.join(this.commitsDir, `${id}.json`), meta3);
|
|
41829
42405
|
await writeJsonAtomic(this.headPath, { id, updatedAt: meta3.createdAt });
|
|
41830
42406
|
await fs21.appendFile(this.indexPath, JSON.stringify({ id, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
|
|
41831
42407
|
return stripStored(meta3);
|
|
@@ -41836,7 +42412,7 @@ var init_fileStateStore = __esm({
|
|
|
41836
42412
|
return this.get(head.id);
|
|
41837
42413
|
}
|
|
41838
42414
|
async get(id) {
|
|
41839
|
-
const stored = await readJsonFile(
|
|
42415
|
+
const stored = await readJsonFile(path43.join(this.commitsDir, `${id}.json`));
|
|
41840
42416
|
return stored ? stripStored(stored) : null;
|
|
41841
42417
|
}
|
|
41842
42418
|
async list(limit = 20) {
|
|
@@ -41875,9 +42451,9 @@ var init_fileStateStore = __esm({
|
|
|
41875
42451
|
async loadDiscoveries(id) {
|
|
41876
42452
|
const meta3 = id ? await this.get(id) : await this.head();
|
|
41877
42453
|
if (!meta3) return [];
|
|
41878
|
-
const stored = await readJsonFile(
|
|
42454
|
+
const stored = await readJsonFile(path43.join(this.commitsDir, `${meta3.id}.json`));
|
|
41879
42455
|
if (!stored?.artifactDir) return [];
|
|
41880
|
-
const discPath =
|
|
42456
|
+
const discPath = path43.join(this.stateDir, stored.artifactDir, "discoveries.json");
|
|
41881
42457
|
return await readJsonFile(discPath) ?? [];
|
|
41882
42458
|
}
|
|
41883
42459
|
async materializeContext(id, maxChars = DEFAULT_MATERIALIZE_CHARS) {
|
|
@@ -42531,7 +43107,7 @@ __export(conversationContext_exports, {
|
|
|
42531
43107
|
setHistory: () => setHistory,
|
|
42532
43108
|
setLastClarification: () => setLastClarification
|
|
42533
43109
|
});
|
|
42534
|
-
import { existsSync as
|
|
43110
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
42535
43111
|
import { join as join19 } from "node:path";
|
|
42536
43112
|
function getHistory() {
|
|
42537
43113
|
return history;
|
|
@@ -42541,7 +43117,7 @@ function setHistory(messages) {
|
|
|
42541
43117
|
history = projected === messages ? [...messages] : projected;
|
|
42542
43118
|
}
|
|
42543
43119
|
function compactInPlace(cwd = process.cwd()) {
|
|
42544
|
-
const durableStatePresent =
|
|
43120
|
+
const durableStatePresent = existsSync26(join19(cwd, ".zelari", "state", "HEAD.json"));
|
|
42545
43121
|
history = applySessionSurface(compactHistory(history, { durableStatePresent }));
|
|
42546
43122
|
}
|
|
42547
43123
|
function appendMessages(msgs) {
|
|
@@ -43124,7 +43700,6 @@ __export(headlessSpine_exports, {
|
|
|
43124
43700
|
seedHeadlessModelHistory: () => seedHeadlessModelHistory,
|
|
43125
43701
|
sessionStartedEvent: () => sessionStartedEvent
|
|
43126
43702
|
});
|
|
43127
|
-
import path42 from "node:path";
|
|
43128
43703
|
function sessionStartedEvent(handle) {
|
|
43129
43704
|
return {
|
|
43130
43705
|
type: "session_started",
|
|
@@ -43158,12 +43733,10 @@ async function openHeadlessSpine(opts) {
|
|
|
43158
43733
|
if (spine.status === "active") {
|
|
43159
43734
|
const budget = new BudgetRuntime(profileId, { enforcement: resolveResourceEnforcement() });
|
|
43160
43735
|
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);
|
|
43736
|
+
await restoreBudgetRuntimeFromSession(budget, opts.sessionId, opts.baseDir);
|
|
43165
43737
|
}
|
|
43166
43738
|
spine.attachBudgetRuntime(budget);
|
|
43739
|
+
await noteHarnessLifecycle(spine, opts.sessionId, profileId, budget, opts.baseDir);
|
|
43167
43740
|
spine.note("headless.profile", { profile: profileId, mode: opts.mode ?? "kraken" });
|
|
43168
43741
|
}
|
|
43169
43742
|
return {
|
|
@@ -43178,8 +43751,14 @@ async function openHeadlessSpine(opts) {
|
|
|
43178
43751
|
userMessage(text) {
|
|
43179
43752
|
spine.userMessage(text);
|
|
43180
43753
|
},
|
|
43181
|
-
gateResourceToolCall(toolName) {
|
|
43182
|
-
return spine.gateResourceToolCall(toolName);
|
|
43754
|
+
gateResourceToolCall(toolName, args) {
|
|
43755
|
+
return spine.gateResourceToolCall(toolName, args);
|
|
43756
|
+
},
|
|
43757
|
+
resourceBudgetLimit() {
|
|
43758
|
+
return spine.resourceBudgetLimit();
|
|
43759
|
+
},
|
|
43760
|
+
resourceBudgetSummary() {
|
|
43761
|
+
return spine.resourceBudgetSummary();
|
|
43183
43762
|
},
|
|
43184
43763
|
verificationRun(payload) {
|
|
43185
43764
|
spine.verificationRun(payload);
|
|
@@ -43297,10 +43876,11 @@ var init_headlessSpine = __esm({
|
|
|
43297
43876
|
init_dist();
|
|
43298
43877
|
init_session();
|
|
43299
43878
|
init_mission2();
|
|
43300
|
-
init_session();
|
|
43301
43879
|
init_runtime2();
|
|
43302
43880
|
init_sessionSpine();
|
|
43303
43881
|
init_budgetRuntime();
|
|
43882
|
+
init_restoreRuntime();
|
|
43883
|
+
init_sessionSpine();
|
|
43304
43884
|
init_headless();
|
|
43305
43885
|
}
|
|
43306
43886
|
});
|
|
@@ -43444,7 +44024,7 @@ var claudeProvider_exports = {};
|
|
|
43444
44024
|
__export(claudeProvider_exports, {
|
|
43445
44025
|
createLocalCliProvider: () => createLocalCliProvider
|
|
43446
44026
|
});
|
|
43447
|
-
import { spawn as
|
|
44027
|
+
import { spawn as spawn12 } from "node:child_process";
|
|
43448
44028
|
function waitForExit(child, timeoutMs2 = 2e3) {
|
|
43449
44029
|
return new Promise((resolve3) => {
|
|
43450
44030
|
if (child.exitCode != null) return resolve3(child.exitCode);
|
|
@@ -43473,7 +44053,7 @@ function createLocalCliProvider(opts = {}) {
|
|
|
43473
44053
|
);
|
|
43474
44054
|
}
|
|
43475
44055
|
}
|
|
43476
|
-
const spawnFn = opts.spawnFn ??
|
|
44056
|
+
const spawnFn = opts.spawnFn ?? spawn12;
|
|
43477
44057
|
let child;
|
|
43478
44058
|
try {
|
|
43479
44059
|
child = spawnFn(cli, args, {
|
|
@@ -43568,12 +44148,12 @@ var init_claudeProvider = __esm({
|
|
|
43568
44148
|
});
|
|
43569
44149
|
|
|
43570
44150
|
// src/cli/workspace/projectInstructions.ts
|
|
43571
|
-
import { existsSync as
|
|
44151
|
+
import { existsSync as existsSync27, readFileSync as readFileSync23 } from "node:fs";
|
|
43572
44152
|
import { join as join20 } from "node:path";
|
|
43573
44153
|
function loadProjectInstructions(projectRoot = process.cwd(), maxChars = MAX_CHARS) {
|
|
43574
44154
|
for (const name of CANDIDATES) {
|
|
43575
44155
|
const full = join20(projectRoot, name);
|
|
43576
|
-
if (!
|
|
44156
|
+
if (!existsSync27(full)) continue;
|
|
43577
44157
|
try {
|
|
43578
44158
|
let raw = readFileSync23(full, "utf8");
|
|
43579
44159
|
raw = raw.replace(/\r\n/g, "\n").trim();
|
|
@@ -43619,7 +44199,7 @@ __export(workspaceSummary_exports, {
|
|
|
43619
44199
|
buildWorkspaceSummary: () => buildWorkspaceSummary,
|
|
43620
44200
|
buildZelariReadHint: () => buildZelariReadHint
|
|
43621
44201
|
});
|
|
43622
|
-
import { existsSync as
|
|
44202
|
+
import { existsSync as existsSync28, readFileSync as readFileSync24, readdirSync as readdirSync6, statSync as statSync5 } from "node:fs";
|
|
43623
44203
|
import { join as join21, relative } from "node:path";
|
|
43624
44204
|
function buildWorkspaceSummary(projectRoot = process.cwd(), options = {}) {
|
|
43625
44205
|
const { maxEntries = 30, maxChars = 3500, maxDeps = 24, maxScripts = 16 } = options;
|
|
@@ -43654,7 +44234,7 @@ function formatTaskLine(t) {
|
|
|
43654
44234
|
function buildPlanSummary(projectRoot = process.cwd(), options) {
|
|
43655
44235
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
43656
44236
|
const planPath = join21(zelariRoot, "plan.json");
|
|
43657
|
-
if (!
|
|
44237
|
+
if (!existsSync28(planPath)) return null;
|
|
43658
44238
|
let plan;
|
|
43659
44239
|
try {
|
|
43660
44240
|
plan = JSON.parse(readFileSync24(planPath, "utf8"));
|
|
@@ -43797,7 +44377,7 @@ function pickNextTask(open) {
|
|
|
43797
44377
|
}
|
|
43798
44378
|
function buildZelariReadHint(projectRoot = process.cwd()) {
|
|
43799
44379
|
const planPath = join21(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
43800
|
-
if (!
|
|
44380
|
+
if (!existsSync28(planPath)) return "";
|
|
43801
44381
|
return [
|
|
43802
44382
|
"# Council workspace detected (.zelari/) \u2014 DRAFT vault",
|
|
43803
44383
|
"`.zelari/plan.json` and `.zelari/docs/` hold **design hypotheses**, not verified product state.",
|
|
@@ -43813,7 +44393,7 @@ function safeProjectName(root) {
|
|
|
43813
44393
|
}
|
|
43814
44394
|
function readPackageJson(projectRoot) {
|
|
43815
44395
|
const p3 = join21(projectRoot, "package.json");
|
|
43816
|
-
if (!
|
|
44396
|
+
if (!existsSync28(p3)) return null;
|
|
43817
44397
|
try {
|
|
43818
44398
|
return JSON.parse(readFileSync24(p3, "utf8"));
|
|
43819
44399
|
} catch {
|
|
@@ -43917,12 +44497,12 @@ var init_workspaceSummary = __esm({
|
|
|
43917
44497
|
});
|
|
43918
44498
|
|
|
43919
44499
|
// src/cli/workspace/buildLessonsSummary.ts
|
|
43920
|
-
import { existsSync as
|
|
44500
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
43921
44501
|
import { join as join22 } from "node:path";
|
|
43922
44502
|
function buildLessonsSummary(projectRoot = process.cwd(), taskText) {
|
|
43923
44503
|
if (process.env["ZELARI_LESSONS"] === "0") return null;
|
|
43924
44504
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
43925
|
-
if (!
|
|
44505
|
+
if (!existsSync29(join22(zelariRoot, "lessons.jsonl"))) return null;
|
|
43926
44506
|
const lessons = recallLessons(zelariRoot, {
|
|
43927
44507
|
maxLessons: 5,
|
|
43928
44508
|
maxBytes: 2048,
|
|
@@ -43943,7 +44523,7 @@ var composeContext_exports = {};
|
|
|
43943
44523
|
__export(composeContext_exports, {
|
|
43944
44524
|
composeProjectContext: () => composeProjectContext
|
|
43945
44525
|
});
|
|
43946
|
-
import { existsSync as
|
|
44526
|
+
import { existsSync as existsSync30, readdirSync as readdirSync7, readFileSync as readFileSync25 } from "node:fs";
|
|
43947
44527
|
import { join as join23 } from "node:path";
|
|
43948
44528
|
function cap2(text, max, label) {
|
|
43949
44529
|
if (!text || text.length <= max) return { text: text || "", truncated: false };
|
|
@@ -43956,13 +44536,13 @@ function cap2(text, max, label) {
|
|
|
43956
44536
|
}
|
|
43957
44537
|
function buildDesignIndex(projectRoot, maxChars) {
|
|
43958
44538
|
const root = resolveWorkspaceRoot(projectRoot);
|
|
43959
|
-
if (!
|
|
44539
|
+
if (!existsSync30(root)) return "";
|
|
43960
44540
|
const lines = [
|
|
43961
44541
|
"# Design vault index (.zelari/) \u2014 HYPOTHESES only",
|
|
43962
44542
|
"Full design docs are NOT product source of truth. Open with list_files / read_file / searchDocuments if needed."
|
|
43963
44543
|
];
|
|
43964
44544
|
const docsDir = join23(root, "docs");
|
|
43965
|
-
if (
|
|
44545
|
+
if (existsSync30(docsDir)) {
|
|
43966
44546
|
try {
|
|
43967
44547
|
const docs = readdirSync7(docsDir).filter((n) => n.endsWith(".md")).slice(0, 12);
|
|
43968
44548
|
if (docs.length > 0) {
|
|
@@ -43976,12 +44556,12 @@ function buildDesignIndex(projectRoot, maxChars) {
|
|
|
43976
44556
|
}
|
|
43977
44557
|
}
|
|
43978
44558
|
for (const name of ["risks.md", "plan.json", "nfr-spec.json"]) {
|
|
43979
|
-
if (
|
|
44559
|
+
if (existsSync30(join23(root, name))) {
|
|
43980
44560
|
lines.push(`- .zelari/${name} present`);
|
|
43981
44561
|
}
|
|
43982
44562
|
}
|
|
43983
44563
|
const decisionsDir = join23(root, "decisions");
|
|
43984
|
-
if (
|
|
44564
|
+
if (existsSync30(decisionsDir)) {
|
|
43985
44565
|
try {
|
|
43986
44566
|
const n = readdirSync7(decisionsDir).filter((f) => f.endsWith(".md")).length;
|
|
43987
44567
|
if (n > 0) lines.push(`- .zelari/decisions/ (${n} ADR file(s) \u2014 treat proposed as non-binding)`);
|
|
@@ -44083,15 +44663,15 @@ function composeProjectContext(input) {
|
|
|
44083
44663
|
function readDurableHeadSync(projectRoot) {
|
|
44084
44664
|
try {
|
|
44085
44665
|
const headPath = join23(projectRoot, ".zelari", "state", "HEAD.json");
|
|
44086
|
-
if (!
|
|
44666
|
+
if (!existsSync30(headPath)) return "";
|
|
44087
44667
|
const head = JSON.parse(readFileSync25(headPath, "utf8"));
|
|
44088
44668
|
if (!head?.id) return "";
|
|
44089
44669
|
const metaPath = join23(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
|
|
44090
|
-
if (!
|
|
44670
|
+
if (!existsSync30(metaPath)) return "";
|
|
44091
44671
|
const meta3 = JSON.parse(readFileSync25(metaPath, "utf8"));
|
|
44092
44672
|
const discPath = meta3.artifactDir ? join23(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join23(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
|
|
44093
44673
|
let discoveries = [];
|
|
44094
|
-
if (
|
|
44674
|
+
if (existsSync30(discPath)) {
|
|
44095
44675
|
discoveries = JSON.parse(readFileSync25(discPath, "utf8"));
|
|
44096
44676
|
}
|
|
44097
44677
|
const reusable = discoveries.filter((d) => d.reusable !== false);
|
|
@@ -44125,11 +44705,11 @@ var planDetect_exports = {};
|
|
|
44125
44705
|
__export(planDetect_exports, {
|
|
44126
44706
|
hasWorkspacePlan: () => hasWorkspacePlan
|
|
44127
44707
|
});
|
|
44128
|
-
import { existsSync as
|
|
44708
|
+
import { existsSync as existsSync31, readFileSync as readFileSync26 } from "node:fs";
|
|
44129
44709
|
import { join as join24 } from "node:path";
|
|
44130
44710
|
function hasWorkspacePlan(projectRoot = process.cwd()) {
|
|
44131
44711
|
const planPath = join24(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
44132
|
-
if (!
|
|
44712
|
+
if (!existsSync31(planPath)) return false;
|
|
44133
44713
|
try {
|
|
44134
44714
|
const parsed = JSON.parse(readFileSync26(planPath, "utf8"));
|
|
44135
44715
|
return Array.isArray(parsed.phases) && parsed.phases.length > 0;
|
|
@@ -44190,7 +44770,7 @@ __export(stubs_exports, {
|
|
|
44190
44770
|
resolveWorkspaceRoot: () => resolveWorkspaceRoot
|
|
44191
44771
|
});
|
|
44192
44772
|
import {
|
|
44193
|
-
existsSync as
|
|
44773
|
+
existsSync as existsSync32,
|
|
44194
44774
|
readdirSync as readdirSync8,
|
|
44195
44775
|
writeFileSync as writeFileSync17,
|
|
44196
44776
|
readFileSync as readFileSync27,
|
|
@@ -44211,7 +44791,7 @@ function planJsonPath(ctx) {
|
|
|
44211
44791
|
}
|
|
44212
44792
|
function readPlan(ctx) {
|
|
44213
44793
|
const jsonPath = planJsonPath(ctx);
|
|
44214
|
-
if (
|
|
44794
|
+
if (existsSync32(jsonPath)) {
|
|
44215
44795
|
try {
|
|
44216
44796
|
const parsed = JSON.parse(
|
|
44217
44797
|
readFileSync27(jsonPath, "utf8")
|
|
@@ -44321,7 +44901,7 @@ function renderPlanBody(summary) {
|
|
|
44321
44901
|
}
|
|
44322
44902
|
function nextAdrId(ctx) {
|
|
44323
44903
|
const decisionsDir = join25(ctx.rootDir, "decisions");
|
|
44324
|
-
if (!
|
|
44904
|
+
if (!existsSync32(decisionsDir)) return "001";
|
|
44325
44905
|
const existing = readdirSync8(decisionsDir).filter((f) => f.endsWith(".md")).map((f) => f.match(/^(\d+)-/)).filter((m) => !!m).map((m) => parseInt(m[1], 10));
|
|
44326
44906
|
const max = existing.length === 0 ? 0 : Math.max(...existing);
|
|
44327
44907
|
return String(max + 1).padStart(3, "0");
|
|
@@ -44777,7 +45357,7 @@ function searchDocumentsStub(ctx) {
|
|
|
44777
45357
|
];
|
|
44778
45358
|
const results = [];
|
|
44779
45359
|
for (const file2 of files) {
|
|
44780
|
-
if (!
|
|
45360
|
+
if (!existsSync32(file2)) continue;
|
|
44781
45361
|
const raw = readFileSync27(file2, "utf8");
|
|
44782
45362
|
const content = raw.toLowerCase();
|
|
44783
45363
|
let idx = -1;
|
|
@@ -44945,176 +45525,6 @@ var init_toolRegistry2 = __esm({
|
|
|
44945
45525
|
}
|
|
44946
45526
|
});
|
|
44947
45527
|
|
|
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
45528
|
// src/cli/mcp/mcpClient.ts
|
|
45119
45529
|
import { spawn as spawn13 } from "node:child_process";
|
|
45120
45530
|
var DEFAULT_REQUEST_TIMEOUT_MS, INIT_TIMEOUT_MS, MCP_PROTOCOL_VERSION, McpClient;
|
|
@@ -45784,7 +46194,7 @@ __export(agentsMd_exports, {
|
|
|
45784
46194
|
updateAgentsMd: () => updateAgentsMd
|
|
45785
46195
|
});
|
|
45786
46196
|
import { existsSync as existsSync35, readFileSync as readFileSync30, writeFileSync as writeFileSync19 } from "node:fs";
|
|
45787
|
-
import { createHash as
|
|
46197
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
45788
46198
|
import { join as join28 } from "node:path";
|
|
45789
46199
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
45790
46200
|
async function readPackageJson2(projectRoot) {
|
|
@@ -45999,7 +46409,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
45999
46409
|
return { changed: true, sections: changedSections };
|
|
46000
46410
|
}
|
|
46001
46411
|
function hash2(s) {
|
|
46002
|
-
return
|
|
46412
|
+
return createHash14("sha256").update(s).digest("hex").slice(0, 16);
|
|
46003
46413
|
}
|
|
46004
46414
|
var AUTO_SECTIONS, MARKER_OPEN, MARKER_CLOSE, GENERATORS;
|
|
46005
46415
|
var init_agentsMd = __esm({
|
|
@@ -51691,8 +52101,8 @@ function shouldRunGauntletHostLoop(opts) {
|
|
|
51691
52101
|
}
|
|
51692
52102
|
function budgetAwareGauntletGate(input) {
|
|
51693
52103
|
if (input.verdict === "PASS") return "proceed";
|
|
51694
|
-
if (input.toolCallsRemaining <= input.verificationReserve) return "finalize-verify";
|
|
51695
52104
|
if (input.toolCallsRemaining <= 0) return "hold";
|
|
52105
|
+
if (input.toolCallsRemaining <= input.verificationReserve) return "finalize-verify";
|
|
51696
52106
|
return "proceed";
|
|
51697
52107
|
}
|
|
51698
52108
|
var DEFAULT_MAX_PIECES, DEFAULT_MAX_ROUNDS, DEFAULT_MAX_PARALLEL2, DEFAULT_WALL_MS, GAUNTLET_PARENT_BLOCKED_TOOLS;
|
|
@@ -52162,7 +52572,8 @@ var init_schedule = __esm({
|
|
|
52162
52572
|
|
|
52163
52573
|
// src/cli/gauntlet/loop.ts
|
|
52164
52574
|
async function runGauntletLoop(args) {
|
|
52165
|
-
const { caps
|
|
52575
|
+
const { caps } = args;
|
|
52576
|
+
const deps = { ...args.deps, budgetGate: args.budgetGate ?? args.deps.budgetGate };
|
|
52166
52577
|
const pieces = args.pieces.slice(0, caps.maxPieces);
|
|
52167
52578
|
const started = (deps.now ?? Date.now)();
|
|
52168
52579
|
const results = [];
|
|
@@ -52229,6 +52640,21 @@ async function runGauntletLoop(args) {
|
|
|
52229
52640
|
builderError: built.error
|
|
52230
52641
|
});
|
|
52231
52642
|
winner = parseBlindWinner(criticized.result) ?? winner;
|
|
52643
|
+
if (last.kind !== "PASS") {
|
|
52644
|
+
const b = deps.budgetGate?.() ?? null;
|
|
52645
|
+
if (b) {
|
|
52646
|
+
const decision = budgetAwareGauntletGate({
|
|
52647
|
+
verdict: last.kind,
|
|
52648
|
+
toolCallsRemaining: b.remaining,
|
|
52649
|
+
verificationReserve: b.verificationReserve
|
|
52650
|
+
});
|
|
52651
|
+
if (decision === "hold") {
|
|
52652
|
+
gap = last.gap;
|
|
52653
|
+
break;
|
|
52654
|
+
}
|
|
52655
|
+
if (decision === "finalize-verify") break;
|
|
52656
|
+
}
|
|
52657
|
+
}
|
|
52232
52658
|
emitProgress({
|
|
52233
52659
|
phase: last.kind === "PASS" ? "settled" : last.kind === "BLOCKED" ? "blocked" : "repairing",
|
|
52234
52660
|
pieceId: piece.id,
|
|
@@ -52292,6 +52718,7 @@ var init_loop = __esm({
|
|
|
52292
52718
|
init_blind();
|
|
52293
52719
|
init_policy();
|
|
52294
52720
|
init_verdict2();
|
|
52721
|
+
init_policy();
|
|
52295
52722
|
init_prompts();
|
|
52296
52723
|
init_schedule();
|
|
52297
52724
|
init_events3();
|
|
@@ -52395,7 +52822,12 @@ async function runHeadlessGauntlet(opts, provider, model) {
|
|
|
52395
52822
|
type: "log",
|
|
52396
52823
|
message: `[gauntlet] ${decomposed.pieces.length} piece(s) from ${decomposed.source}${decomposed.error ? ` (${decomposed.error.slice(0, 80)})` : ""}`
|
|
52397
52824
|
});
|
|
52825
|
+
const budgetGate = () => {
|
|
52826
|
+
const lim = spine.resourceBudgetLimit();
|
|
52827
|
+
return lim ? { remaining: lim.remaining, verificationReserve: lim.verificationReserve } : null;
|
|
52828
|
+
};
|
|
52398
52829
|
const result = await runGauntletLoop({
|
|
52830
|
+
budgetGate,
|
|
52399
52831
|
pieces: decomposed.pieces,
|
|
52400
52832
|
caps,
|
|
52401
52833
|
deps: {
|
|
@@ -53470,7 +53902,7 @@ import {
|
|
|
53470
53902
|
} from "node:fs";
|
|
53471
53903
|
import { join as join38 } from "node:path";
|
|
53472
53904
|
import { homedir as homedir13 } from "node:os";
|
|
53473
|
-
import { createHash as
|
|
53905
|
+
import { createHash as createHash15, randomBytes as randomBytes5, timingSafeEqual } from "node:crypto";
|
|
53474
53906
|
function getZelariHome() {
|
|
53475
53907
|
return join38(homedir13(), ".zelari-code");
|
|
53476
53908
|
}
|
|
@@ -53546,8 +53978,8 @@ function loadOrCreateToken(explicit) {
|
|
|
53546
53978
|
}
|
|
53547
53979
|
function tokenMatches(expected, provided) {
|
|
53548
53980
|
if (!provided) return false;
|
|
53549
|
-
const a =
|
|
53550
|
-
const b =
|
|
53981
|
+
const a = createHash15("sha256").update(expected).digest();
|
|
53982
|
+
const b = createHash15("sha256").update(provided).digest();
|
|
53551
53983
|
try {
|
|
53552
53984
|
return timingSafeEqual(a, b);
|
|
53553
53985
|
} catch {
|
|
@@ -58143,13 +58575,13 @@ init_completionGate();
|
|
|
58143
58575
|
// src/cli/kraken/verificationBridge.ts
|
|
58144
58576
|
init_candidateRegistry();
|
|
58145
58577
|
init_completionGate();
|
|
58146
|
-
import { createHash as
|
|
58578
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
58147
58579
|
|
|
58148
58580
|
// src/cli/kraken/nativeVerification.ts
|
|
58149
58581
|
init_runtime2();
|
|
58150
58582
|
init_verification2();
|
|
58151
58583
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
58152
|
-
import
|
|
58584
|
+
import path42 from "node:path";
|
|
58153
58585
|
function nativePackEnabled(env = process.env) {
|
|
58154
58586
|
const v = env.ZELARI_VERIFY_PACK?.toLowerCase();
|
|
58155
58587
|
return v === "1" || v === "on" || v === "true";
|
|
@@ -58176,7 +58608,7 @@ function packTimeoutMs(env = process.env) {
|
|
|
58176
58608
|
}
|
|
58177
58609
|
async function readPackageScripts(cwd = process.cwd()) {
|
|
58178
58610
|
try {
|
|
58179
|
-
const raw = await readFile2(
|
|
58611
|
+
const raw = await readFile2(path42.join(cwd, "package.json"), "utf-8");
|
|
58180
58612
|
const parsed = JSON.parse(raw);
|
|
58181
58613
|
if (parsed && typeof parsed === "object" && typeof parsed.scripts === "object") {
|
|
58182
58614
|
return parsed.scripts;
|
|
@@ -58270,7 +58702,7 @@ function krakenResultsToContract(requiredChecks, results, now = Date.now()) {
|
|
|
58270
58702
|
return { criteria, results: verifications };
|
|
58271
58703
|
}
|
|
58272
58704
|
function sha256Hex2(input) {
|
|
58273
|
-
return
|
|
58705
|
+
return createHash12("sha256").update(input).digest("hex");
|
|
58274
58706
|
}
|
|
58275
58707
|
function matchNoteToToolTrace(note, trace) {
|
|
58276
58708
|
const n = normalize5(note);
|
|
@@ -58991,7 +59423,9 @@ async function buildModelContext(input) {
|
|
|
58991
59423
|
};
|
|
58992
59424
|
input.onCompactionMetric?.(compactionMetrics);
|
|
58993
59425
|
}
|
|
58994
|
-
if (input.resourceSnapshot
|
|
59426
|
+
if (input.resourceSnapshot && !history2.some(
|
|
59427
|
+
(m) => m.role === "system" && typeof m.content === "string" && m.content.startsWith("RESOURCE STATUS")
|
|
59428
|
+
)) {
|
|
58995
59429
|
history2 = [...history2, resourceStatusMessage(input.resourceSnapshot)];
|
|
58996
59430
|
}
|
|
58997
59431
|
if (requestSurface) {
|
|
@@ -59393,10 +59827,12 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
59393
59827
|
systemMessages = [{ role: "system", content: fallback }];
|
|
59394
59828
|
}
|
|
59395
59829
|
systemPrefixLen = systemMessages.length;
|
|
59396
|
-
const
|
|
59830
|
+
const perTurnEnv = envNumber(process.env.ZELARI_MAX_TOOL_CALLS, {
|
|
59397
59831
|
default: 25,
|
|
59398
59832
|
min: 1
|
|
59399
59833
|
});
|
|
59834
|
+
const sessionCap = writerRef.current?.spine?.resourceBudgetLimit();
|
|
59835
|
+
const maxToolCallsPerTurn = sessionCap ? Math.max(1, Math.min(perTurnEnv, sessionCap.maxToolCalls)) : perTurnEnv;
|
|
59400
59836
|
const maxToolLoopIterations = budget.maxToolLoopIterations;
|
|
59401
59837
|
const maxToolLoopHardCap = envNumber(process.env.ZELARI_MAX_TOOL_LOOP_HARD, {
|
|
59402
59838
|
default: 0,
|
|
@@ -59426,7 +59862,9 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
59426
59862
|
providerStream,
|
|
59427
59863
|
// 2.6 Phase 3: host-owned pre-dispatch resource gate via the spine
|
|
59428
59864
|
// mirror (doc section 11.3). Degrade-and-stop (null gate = allow).
|
|
59429
|
-
|
|
59865
|
+
// 2.6.1 (plan §13): argument-aware — bash is essential only when
|
|
59866
|
+
// the command is a test/typecheck/build/git-diff line.
|
|
59867
|
+
toolCallGate: (name, args) => writerRef.current?.spine?.gateResourceToolCall(name, args) ?? { allowed: true },
|
|
59430
59868
|
cwd,
|
|
59431
59869
|
maxToolCallsPerTurn,
|
|
59432
59870
|
maxToolLoopIterations,
|
|
@@ -60007,10 +60445,12 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
60007
60445
|
let streamContent = "";
|
|
60008
60446
|
let streamMemberId = null;
|
|
60009
60447
|
const streamScrub = createStreamScrubber(16);
|
|
60010
|
-
const
|
|
60448
|
+
const councilPerTurnEnv = envNumber(process.env.ZELARI_MAX_TOOL_CALLS, {
|
|
60011
60449
|
default: 15,
|
|
60012
60450
|
min: 1
|
|
60013
60451
|
});
|
|
60452
|
+
const councilSessionCap = writerRef.current?.spine?.resourceBudgetLimit();
|
|
60453
|
+
const councilMaxToolCalls = councilSessionCap ? Math.max(1, Math.min(councilPerTurnEnv, councilSessionCap.maxToolCalls)) : councilPerTurnEnv;
|
|
60014
60454
|
const councilMaxToolLoop = envNumber(
|
|
60015
60455
|
process.env.ZELARI_MAX_TOOL_LOOP_ITERATIONS,
|
|
60016
60456
|
{ default: 30, min: 1 }
|
|
@@ -65443,7 +65883,9 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
65443
65883
|
// 2.6 Phase 3: host-owned pre-dispatch resource gate (doc section 11.3).
|
|
65444
65884
|
// Advisory by default; ZELARI_RESOURCE_ENFORCEMENT=protected enables the
|
|
65445
65885
|
// protected verification reserve. Degrade-and-stop (null gate = allow).
|
|
65446
|
-
|
|
65886
|
+
// 2.6.1 (plan §13): argument-aware — bash is essential only when the
|
|
65887
|
+
// command is a test/typecheck/build/git-diff line.
|
|
65888
|
+
toolCallGate: (name, args) => spine.gateResourceToolCall(name, args) ?? { allowed: true },
|
|
65447
65889
|
maxToolLoopIterations: maxToolLoop
|
|
65448
65890
|
});
|
|
65449
65891
|
let finalReason = "completed";
|
|
@@ -66094,6 +66536,28 @@ ${ragContext}` : slicePrompt;
|
|
|
66094
66536
|
if (completionOk) {
|
|
66095
66537
|
emit(`[zelari] slice completion ok`);
|
|
66096
66538
|
}
|
|
66539
|
+
try {
|
|
66540
|
+
const budget = spine.resourceBudgetSummary();
|
|
66541
|
+
if (budget && !completionOk) {
|
|
66542
|
+
const { evaluateResourceReserveGate: evaluateResourceReserveGate2 } = await Promise.resolve().then(() => (init_verification2(), verification_exports));
|
|
66543
|
+
const gated = evaluateResourceReserveGate2({
|
|
66544
|
+
evaluation: {
|
|
66545
|
+
verdict: "REPAIR_REQUIRED",
|
|
66546
|
+
summary: "headless slice completion",
|
|
66547
|
+
satisfied: [],
|
|
66548
|
+
unsatisfied: [],
|
|
66549
|
+
evidenceComplete: false,
|
|
66550
|
+
eventBackedEvidenceComplete: false
|
|
66551
|
+
},
|
|
66552
|
+
budget
|
|
66553
|
+
});
|
|
66554
|
+
if (gated.verdict === "BLOCKED") {
|
|
66555
|
+
emit("[zelari] completion BLOCKED: resource budget exhausted (non-PASS + zero remaining)");
|
|
66556
|
+
}
|
|
66557
|
+
spine.note("completion.resource_gate", { decision: gated.verdict, remaining: budget.toolCalls.remaining });
|
|
66558
|
+
}
|
|
66559
|
+
} catch {
|
|
66560
|
+
}
|
|
66097
66561
|
} catch {
|
|
66098
66562
|
}
|
|
66099
66563
|
if (synthesisText.trim()) {
|