zelari-code 2.30.0 → 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/cli/costBudget.js +16 -0
- package/dist/cli/costBudget.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +24 -0
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/kraken/verifyStatus.js +6 -0
- package/dist/cli/kraken/verifyStatus.js.map +1 -1
- package/dist/cli/main.bundled.js +261 -158
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +67 -13
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/runHeadless.js +5 -0
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/utils/doctor.js +29 -4
- package/dist/cli/utils/doctor.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -37549,7 +37549,7 @@ var CORE_VERSION;
|
|
|
37549
37549
|
var init_version = __esm({
|
|
37550
37550
|
"packages/core/dist/version.js"() {
|
|
37551
37551
|
"use strict";
|
|
37552
|
-
CORE_VERSION = "2.
|
|
37552
|
+
CORE_VERSION = "2.31.0";
|
|
37553
37553
|
}
|
|
37554
37554
|
});
|
|
37555
37555
|
|
|
@@ -57039,6 +57039,113 @@ var init_claudeProvider = __esm({
|
|
|
57039
57039
|
}
|
|
57040
57040
|
});
|
|
57041
57041
|
|
|
57042
|
+
// src/cli/costBudget.ts
|
|
57043
|
+
var costBudget_exports = {};
|
|
57044
|
+
__export(costBudget_exports, {
|
|
57045
|
+
SessionBudgetTracker: () => SessionBudgetTracker,
|
|
57046
|
+
budgetChip: () => budgetChip,
|
|
57047
|
+
processSessionBudget: () => processSessionBudget,
|
|
57048
|
+
resetProcessSessionBudget: () => resetProcessSessionBudget,
|
|
57049
|
+
resolveSessionBudget: () => resolveSessionBudget,
|
|
57050
|
+
sessionBudgetHoldNotice: () => sessionBudgetHoldNotice
|
|
57051
|
+
});
|
|
57052
|
+
function resolveSessionBudget(env = process.env) {
|
|
57053
|
+
const maxUsd = parsePositiveFloat(env.ZELARI_SESSION_BUDGET_USD);
|
|
57054
|
+
const maxTokens = parsePositiveInt(env.ZELARI_SESSION_BUDGET_TOKENS);
|
|
57055
|
+
if (maxUsd === void 0 && maxTokens === void 0) return {};
|
|
57056
|
+
return { ...maxUsd !== void 0 ? { maxUsd } : {}, ...maxTokens !== void 0 ? { maxTokens } : {} };
|
|
57057
|
+
}
|
|
57058
|
+
function parsePositiveFloat(raw) {
|
|
57059
|
+
if (!raw) return void 0;
|
|
57060
|
+
const n = Number.parseFloat(raw);
|
|
57061
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
57062
|
+
}
|
|
57063
|
+
function parsePositiveInt(raw) {
|
|
57064
|
+
if (!raw) return void 0;
|
|
57065
|
+
const n = Number.parseInt(raw, 10);
|
|
57066
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
57067
|
+
}
|
|
57068
|
+
function round6(value) {
|
|
57069
|
+
return Math.round(value * 1e6) / 1e6;
|
|
57070
|
+
}
|
|
57071
|
+
function processSessionBudget(env = process.env) {
|
|
57072
|
+
if (!processTracker) processTracker = new SessionBudgetTracker(resolveSessionBudget(env));
|
|
57073
|
+
return processTracker;
|
|
57074
|
+
}
|
|
57075
|
+
function resetProcessSessionBudget() {
|
|
57076
|
+
processTracker = void 0;
|
|
57077
|
+
}
|
|
57078
|
+
function sessionBudgetHoldNotice(env = process.env) {
|
|
57079
|
+
const budget = processSessionBudget(env);
|
|
57080
|
+
if (!budget.isHold()) return null;
|
|
57081
|
+
const s = budget.status();
|
|
57082
|
+
return `[budget] HOLD \u2014 session budget exhausted (${s.usedUsd.toFixed(2)} USD \xB7 ${s.usedTokens} tokens). Raise ZELARI_SESSION_BUDGET_USD / ZELARI_SESSION_BUDGET_TOKENS or start /new. State preserved; no provider call was made.`;
|
|
57083
|
+
}
|
|
57084
|
+
function budgetChip(status) {
|
|
57085
|
+
if (status.state === "off") return null;
|
|
57086
|
+
const pct = Math.max(status.pctUsd ?? 0, status.pctTokens ?? 0);
|
|
57087
|
+
const label = status.state === "hold" ? "budget HOLD" : `budget ${Math.min(999, Math.round(pct * 100))}%`;
|
|
57088
|
+
const tone = status.state === "hold" ? "red" : status.state === "warn" ? "yellow" : "green";
|
|
57089
|
+
return { label, tone };
|
|
57090
|
+
}
|
|
57091
|
+
var SessionBudgetTracker, processTracker;
|
|
57092
|
+
var init_costBudget = __esm({
|
|
57093
|
+
"src/cli/costBudget.ts"() {
|
|
57094
|
+
"use strict";
|
|
57095
|
+
SessionBudgetTracker = class {
|
|
57096
|
+
constructor(budget = {}) {
|
|
57097
|
+
this.budget = budget;
|
|
57098
|
+
}
|
|
57099
|
+
usedUsd = 0;
|
|
57100
|
+
usedTokens = 0;
|
|
57101
|
+
get enabled() {
|
|
57102
|
+
return this.budget.maxUsd !== void 0 || this.budget.maxTokens !== void 0;
|
|
57103
|
+
}
|
|
57104
|
+
/** Idempotent per-turn accumulation; ignores NaN/negative inputs. */
|
|
57105
|
+
record(delta) {
|
|
57106
|
+
if (Number.isFinite(delta.costUsd) && (delta.costUsd ?? 0) > 0) this.usedUsd += delta.costUsd ?? 0;
|
|
57107
|
+
if (Number.isFinite(delta.tokens) && (delta.tokens ?? 0) > 0) this.usedTokens += Math.round(delta.tokens ?? 0);
|
|
57108
|
+
}
|
|
57109
|
+
status() {
|
|
57110
|
+
if (!this.enabled) return { state: "off", usedUsd: this.usedUsd, usedTokens: this.usedTokens, pctUsd: null, pctTokens: null };
|
|
57111
|
+
const pctUsd = this.budget.maxUsd !== void 0 ? this.usedUsd / this.budget.maxUsd : null;
|
|
57112
|
+
const pctTokens = this.budget.maxTokens !== void 0 ? this.usedTokens / this.budget.maxTokens : null;
|
|
57113
|
+
const worst = Math.max(pctUsd ?? 0, pctTokens ?? 0);
|
|
57114
|
+
const state3 = worst >= 1 ? "hold" : worst >= 0.8 ? "warn" : "ok";
|
|
57115
|
+
return { state: state3, usedUsd: round6(this.usedUsd), usedTokens: this.usedTokens, pctUsd, pctTokens };
|
|
57116
|
+
}
|
|
57117
|
+
/** True when no further provider turn should start. */
|
|
57118
|
+
isHold() {
|
|
57119
|
+
return this.status().state === "hold";
|
|
57120
|
+
}
|
|
57121
|
+
};
|
|
57122
|
+
}
|
|
57123
|
+
});
|
|
57124
|
+
|
|
57125
|
+
// src/cli/workspace/planDetect.ts
|
|
57126
|
+
var planDetect_exports = {};
|
|
57127
|
+
__export(planDetect_exports, {
|
|
57128
|
+
hasWorkspacePlan: () => hasWorkspacePlan
|
|
57129
|
+
});
|
|
57130
|
+
import { existsSync as existsSync35, readFileSync as readFileSync25 } from "node:fs";
|
|
57131
|
+
import { join as join23 } from "node:path";
|
|
57132
|
+
function hasWorkspacePlan(projectRoot = process.cwd()) {
|
|
57133
|
+
const planPath = join23(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
57134
|
+
if (!existsSync35(planPath)) return false;
|
|
57135
|
+
try {
|
|
57136
|
+
const parsed = JSON.parse(readFileSync25(planPath, "utf8"));
|
|
57137
|
+
return Array.isArray(parsed.phases) && parsed.phases.length > 0;
|
|
57138
|
+
} catch {
|
|
57139
|
+
return false;
|
|
57140
|
+
}
|
|
57141
|
+
}
|
|
57142
|
+
var init_planDetect = __esm({
|
|
57143
|
+
"src/cli/workspace/planDetect.ts"() {
|
|
57144
|
+
"use strict";
|
|
57145
|
+
init_paths3();
|
|
57146
|
+
}
|
|
57147
|
+
});
|
|
57148
|
+
|
|
57042
57149
|
// src/cli/memory/legacyImport.ts
|
|
57043
57150
|
import { createHash as createHash18 } from "node:crypto";
|
|
57044
57151
|
import { promises as fs27 } from "node:fs";
|
|
@@ -57241,7 +57348,7 @@ var init_sqliteCodec = __esm({
|
|
|
57241
57348
|
});
|
|
57242
57349
|
|
|
57243
57350
|
// src/cli/memory/sqliteRpc.ts
|
|
57244
|
-
import { existsSync as
|
|
57351
|
+
import { existsSync as existsSync36 } from "node:fs";
|
|
57245
57352
|
import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
57246
57353
|
import * as path67 from "node:path";
|
|
57247
57354
|
import { Worker } from "node:worker_threads";
|
|
@@ -57254,7 +57361,7 @@ function isBusy(error51) {
|
|
|
57254
57361
|
function resolveWorkerUrl() {
|
|
57255
57362
|
const here = path67.dirname(fileURLToPath2(import.meta.url));
|
|
57256
57363
|
const direct = path67.join(here, "sqliteWorker.mjs");
|
|
57257
|
-
if (
|
|
57364
|
+
if (existsSync36(direct)) return pathToFileURL2(direct);
|
|
57258
57365
|
return pathToFileURL2(path67.join(here, "memory", "sqliteWorker.mjs"));
|
|
57259
57366
|
}
|
|
57260
57367
|
var SqliteWorkerRpc;
|
|
@@ -58261,14 +58368,14 @@ var init_serviceFactory = __esm({
|
|
|
58261
58368
|
});
|
|
58262
58369
|
|
|
58263
58370
|
// src/cli/workspace/projectInstructions.ts
|
|
58264
|
-
import { existsSync as
|
|
58265
|
-
import { join as
|
|
58371
|
+
import { existsSync as existsSync37, readFileSync as readFileSync26 } from "node:fs";
|
|
58372
|
+
import { join as join27 } from "node:path";
|
|
58266
58373
|
function loadProjectInstructions(projectRoot = process.cwd(), maxChars = MAX_CHARS) {
|
|
58267
58374
|
for (const name of CANDIDATES) {
|
|
58268
|
-
const full =
|
|
58269
|
-
if (!
|
|
58375
|
+
const full = join27(projectRoot, name);
|
|
58376
|
+
if (!existsSync37(full)) continue;
|
|
58270
58377
|
try {
|
|
58271
|
-
let raw =
|
|
58378
|
+
let raw = readFileSync26(full, "utf8");
|
|
58272
58379
|
raw = raw.replace(/\r\n/g, "\n").trim();
|
|
58273
58380
|
if (!raw) continue;
|
|
58274
58381
|
if (raw.length <= maxChars) {
|
|
@@ -58312,8 +58419,8 @@ __export(workspaceSummary_exports, {
|
|
|
58312
58419
|
buildWorkspaceSummary: () => buildWorkspaceSummary,
|
|
58313
58420
|
buildZelariReadHint: () => buildZelariReadHint
|
|
58314
58421
|
});
|
|
58315
|
-
import { existsSync as
|
|
58316
|
-
import { join as
|
|
58422
|
+
import { existsSync as existsSync38, readFileSync as readFileSync27, readdirSync as readdirSync7, statSync as statSync5 } from "node:fs";
|
|
58423
|
+
import { join as join28, relative as relative2 } from "node:path";
|
|
58317
58424
|
function buildWorkspaceSummary(projectRoot = process.cwd(), options = {}) {
|
|
58318
58425
|
const { maxEntries = 30, maxChars = 3500, maxDeps = 24, maxScripts = 16 } = options;
|
|
58319
58426
|
const name = safeProjectName(projectRoot);
|
|
@@ -58346,11 +58453,11 @@ function formatTaskLine(t) {
|
|
|
58346
58453
|
}
|
|
58347
58454
|
function buildPlanSummary(projectRoot = process.cwd(), options) {
|
|
58348
58455
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
58349
|
-
const planPath =
|
|
58350
|
-
if (!
|
|
58456
|
+
const planPath = join28(zelariRoot, "plan.json");
|
|
58457
|
+
if (!existsSync38(planPath)) return null;
|
|
58351
58458
|
let plan;
|
|
58352
58459
|
try {
|
|
58353
|
-
plan = JSON.parse(
|
|
58460
|
+
plan = JSON.parse(readFileSync27(planPath, "utf8"));
|
|
58354
58461
|
} catch {
|
|
58355
58462
|
return null;
|
|
58356
58463
|
}
|
|
@@ -58489,8 +58596,8 @@ function pickNextTask(open2) {
|
|
|
58489
58596
|
)[0];
|
|
58490
58597
|
}
|
|
58491
58598
|
function buildZelariReadHint(projectRoot = process.cwd()) {
|
|
58492
|
-
const planPath =
|
|
58493
|
-
if (!
|
|
58599
|
+
const planPath = join28(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
58600
|
+
if (!existsSync38(planPath)) return "";
|
|
58494
58601
|
return [
|
|
58495
58602
|
"# Council workspace detected (.zelari/) \u2014 DRAFT vault",
|
|
58496
58603
|
"`.zelari/plan.json` and `.zelari/docs/` hold **design hypotheses**, not verified product state.",
|
|
@@ -58505,10 +58612,10 @@ function safeProjectName(root) {
|
|
|
58505
58612
|
}
|
|
58506
58613
|
}
|
|
58507
58614
|
function readPackageJson2(projectRoot) {
|
|
58508
|
-
const p3 =
|
|
58509
|
-
if (!
|
|
58615
|
+
const p3 = join28(projectRoot, "package.json");
|
|
58616
|
+
if (!existsSync38(p3)) return null;
|
|
58510
58617
|
try {
|
|
58511
|
-
return JSON.parse(
|
|
58618
|
+
return JSON.parse(readFileSync27(p3, "utf8"));
|
|
58512
58619
|
} catch {
|
|
58513
58620
|
return null;
|
|
58514
58621
|
}
|
|
@@ -58558,11 +58665,11 @@ function listShallow(projectRoot, maxEntries) {
|
|
|
58558
58665
|
out.push(`\u2026 (+${top.length - count} more)`);
|
|
58559
58666
|
break;
|
|
58560
58667
|
}
|
|
58561
|
-
const rel2 = relative2(projectRoot,
|
|
58668
|
+
const rel2 = relative2(projectRoot, join28(projectRoot, entry.name));
|
|
58562
58669
|
if (entry.isDirectory()) {
|
|
58563
58670
|
let inner = "";
|
|
58564
58671
|
try {
|
|
58565
|
-
const sub = readdirSync7(
|
|
58672
|
+
const sub = readdirSync7(join28(projectRoot, entry.name), {
|
|
58566
58673
|
withFileTypes: true
|
|
58567
58674
|
}).filter((e) => !e.name.startsWith(".")).slice(0, 4).map((e) => e.name);
|
|
58568
58675
|
if (sub.length > 0)
|
|
@@ -58610,12 +58717,12 @@ var init_workspaceSummary = __esm({
|
|
|
58610
58717
|
});
|
|
58611
58718
|
|
|
58612
58719
|
// src/cli/workspace/buildLessonsSummary.ts
|
|
58613
|
-
import { existsSync as
|
|
58614
|
-
import { join as
|
|
58720
|
+
import { existsSync as existsSync39 } from "node:fs";
|
|
58721
|
+
import { join as join29 } from "node:path";
|
|
58615
58722
|
function buildLessonsSummary(projectRoot = process.cwd(), taskText) {
|
|
58616
58723
|
if (process.env["ZELARI_LESSONS"] === "0") return null;
|
|
58617
58724
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
58618
|
-
if (!
|
|
58725
|
+
if (!existsSync39(join29(zelariRoot, "lessons.jsonl"))) return null;
|
|
58619
58726
|
const lessons = recallLessons(zelariRoot, {
|
|
58620
58727
|
maxLessons: 5,
|
|
58621
58728
|
maxBytes: 2048,
|
|
@@ -58636,8 +58743,8 @@ var composeContext_exports = {};
|
|
|
58636
58743
|
__export(composeContext_exports, {
|
|
58637
58744
|
composeProjectContext: () => composeProjectContext
|
|
58638
58745
|
});
|
|
58639
|
-
import { existsSync as
|
|
58640
|
-
import { join as
|
|
58746
|
+
import { existsSync as existsSync40, readdirSync as readdirSync8, readFileSync as readFileSync28 } from "node:fs";
|
|
58747
|
+
import { join as join30 } from "node:path";
|
|
58641
58748
|
function cap2(text, max, label) {
|
|
58642
58749
|
if (!text || text.length <= max) return { text: text || "", truncated: false };
|
|
58643
58750
|
return {
|
|
@@ -58649,13 +58756,13 @@ function cap2(text, max, label) {
|
|
|
58649
58756
|
}
|
|
58650
58757
|
function buildDesignIndex(projectRoot, maxChars) {
|
|
58651
58758
|
const root = resolveWorkspaceRoot(projectRoot);
|
|
58652
|
-
if (!
|
|
58759
|
+
if (!existsSync40(root)) return "";
|
|
58653
58760
|
const lines = [
|
|
58654
58761
|
"# Design vault index (.zelari/) \u2014 HYPOTHESES only",
|
|
58655
58762
|
"Full design docs are NOT product source of truth. Open with list_files / read_file / searchDocuments if needed."
|
|
58656
58763
|
];
|
|
58657
|
-
const docsDir =
|
|
58658
|
-
if (
|
|
58764
|
+
const docsDir = join30(root, "docs");
|
|
58765
|
+
if (existsSync40(docsDir)) {
|
|
58659
58766
|
try {
|
|
58660
58767
|
const docs = readdirSync8(docsDir).filter((n) => n.endsWith(".md")).slice(0, 12);
|
|
58661
58768
|
if (docs.length > 0) {
|
|
@@ -58669,12 +58776,12 @@ function buildDesignIndex(projectRoot, maxChars) {
|
|
|
58669
58776
|
}
|
|
58670
58777
|
}
|
|
58671
58778
|
for (const name of ["risks.md", "plan.json", "nfr-spec.json"]) {
|
|
58672
|
-
if (
|
|
58779
|
+
if (existsSync40(join30(root, name))) {
|
|
58673
58780
|
lines.push(`- .zelari/${name} present`);
|
|
58674
58781
|
}
|
|
58675
58782
|
}
|
|
58676
|
-
const decisionsDir =
|
|
58677
|
-
if (
|
|
58783
|
+
const decisionsDir = join30(root, "decisions");
|
|
58784
|
+
if (existsSync40(decisionsDir)) {
|
|
58678
58785
|
try {
|
|
58679
58786
|
const n = readdirSync8(decisionsDir).filter((f) => f.endsWith(".md")).length;
|
|
58680
58787
|
if (n > 0) lines.push(`- .zelari/decisions/ (${n} ADR file(s) \u2014 treat proposed as non-binding)`);
|
|
@@ -58775,17 +58882,17 @@ function composeProjectContext(input) {
|
|
|
58775
58882
|
}
|
|
58776
58883
|
function readDurableHeadSync(projectRoot) {
|
|
58777
58884
|
try {
|
|
58778
|
-
const headPath =
|
|
58779
|
-
if (!
|
|
58780
|
-
const head = JSON.parse(
|
|
58885
|
+
const headPath = join30(projectRoot, ".zelari", "state", "HEAD.json");
|
|
58886
|
+
if (!existsSync40(headPath)) return "";
|
|
58887
|
+
const head = JSON.parse(readFileSync28(headPath, "utf8"));
|
|
58781
58888
|
if (!head?.id) return "";
|
|
58782
|
-
const metaPath =
|
|
58783
|
-
if (!
|
|
58784
|
-
const meta3 = JSON.parse(
|
|
58785
|
-
const discPath = meta3.artifactDir ?
|
|
58889
|
+
const metaPath = join30(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
|
|
58890
|
+
if (!existsSync40(metaPath)) return "";
|
|
58891
|
+
const meta3 = JSON.parse(readFileSync28(metaPath, "utf8"));
|
|
58892
|
+
const discPath = meta3.artifactDir ? join30(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join30(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
|
|
58786
58893
|
let discoveries = [];
|
|
58787
|
-
if (
|
|
58788
|
-
discoveries = JSON.parse(
|
|
58894
|
+
if (existsSync40(discPath)) {
|
|
58895
|
+
discoveries = JSON.parse(readFileSync28(discPath, "utf8"));
|
|
58789
58896
|
}
|
|
58790
58897
|
const reusable = discoveries.filter((d) => d.reusable !== false);
|
|
58791
58898
|
const lines = [
|
|
@@ -58813,30 +58920,6 @@ var init_composeContext = __esm({
|
|
|
58813
58920
|
}
|
|
58814
58921
|
});
|
|
58815
58922
|
|
|
58816
|
-
// src/cli/workspace/planDetect.ts
|
|
58817
|
-
var planDetect_exports = {};
|
|
58818
|
-
__export(planDetect_exports, {
|
|
58819
|
-
hasWorkspacePlan: () => hasWorkspacePlan
|
|
58820
|
-
});
|
|
58821
|
-
import { existsSync as existsSync40, readFileSync as readFileSync28 } from "node:fs";
|
|
58822
|
-
import { join as join30 } from "node:path";
|
|
58823
|
-
function hasWorkspacePlan(projectRoot = process.cwd()) {
|
|
58824
|
-
const planPath = join30(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
58825
|
-
if (!existsSync40(planPath)) return false;
|
|
58826
|
-
try {
|
|
58827
|
-
const parsed = JSON.parse(readFileSync28(planPath, "utf8"));
|
|
58828
|
-
return Array.isArray(parsed.phases) && parsed.phases.length > 0;
|
|
58829
|
-
} catch {
|
|
58830
|
-
return false;
|
|
58831
|
-
}
|
|
58832
|
-
}
|
|
58833
|
-
var init_planDetect = __esm({
|
|
58834
|
-
"src/cli/workspace/planDetect.ts"() {
|
|
58835
|
-
"use strict";
|
|
58836
|
-
init_paths3();
|
|
58837
|
-
}
|
|
58838
|
-
});
|
|
58839
|
-
|
|
58840
58923
|
// src/cli/state/loadDurableContext.ts
|
|
58841
58924
|
var loadDurableContext_exports = {};
|
|
58842
58925
|
__export(loadDurableContext_exports, {
|
|
@@ -60499,82 +60582,6 @@ var init_mcpManager = __esm({
|
|
|
60499
60582
|
}
|
|
60500
60583
|
});
|
|
60501
60584
|
|
|
60502
|
-
// src/cli/costBudget.ts
|
|
60503
|
-
var costBudget_exports = {};
|
|
60504
|
-
__export(costBudget_exports, {
|
|
60505
|
-
SessionBudgetTracker: () => SessionBudgetTracker,
|
|
60506
|
-
budgetChip: () => budgetChip,
|
|
60507
|
-
processSessionBudget: () => processSessionBudget,
|
|
60508
|
-
resetProcessSessionBudget: () => resetProcessSessionBudget,
|
|
60509
|
-
resolveSessionBudget: () => resolveSessionBudget
|
|
60510
|
-
});
|
|
60511
|
-
function resolveSessionBudget(env = process.env) {
|
|
60512
|
-
const maxUsd = parsePositiveFloat(env.ZELARI_SESSION_BUDGET_USD);
|
|
60513
|
-
const maxTokens = parsePositiveInt(env.ZELARI_SESSION_BUDGET_TOKENS);
|
|
60514
|
-
if (maxUsd === void 0 && maxTokens === void 0) return {};
|
|
60515
|
-
return { ...maxUsd !== void 0 ? { maxUsd } : {}, ...maxTokens !== void 0 ? { maxTokens } : {} };
|
|
60516
|
-
}
|
|
60517
|
-
function parsePositiveFloat(raw) {
|
|
60518
|
-
if (!raw) return void 0;
|
|
60519
|
-
const n = Number.parseFloat(raw);
|
|
60520
|
-
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
60521
|
-
}
|
|
60522
|
-
function parsePositiveInt(raw) {
|
|
60523
|
-
if (!raw) return void 0;
|
|
60524
|
-
const n = Number.parseInt(raw, 10);
|
|
60525
|
-
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
60526
|
-
}
|
|
60527
|
-
function round6(value) {
|
|
60528
|
-
return Math.round(value * 1e6) / 1e6;
|
|
60529
|
-
}
|
|
60530
|
-
function processSessionBudget(env = process.env) {
|
|
60531
|
-
if (!processTracker) processTracker = new SessionBudgetTracker(resolveSessionBudget(env));
|
|
60532
|
-
return processTracker;
|
|
60533
|
-
}
|
|
60534
|
-
function resetProcessSessionBudget() {
|
|
60535
|
-
processTracker = void 0;
|
|
60536
|
-
}
|
|
60537
|
-
function budgetChip(status) {
|
|
60538
|
-
if (status.state === "off") return null;
|
|
60539
|
-
const pct = Math.max(status.pctUsd ?? 0, status.pctTokens ?? 0);
|
|
60540
|
-
const label = status.state === "hold" ? "budget HOLD" : `budget ${Math.min(999, Math.round(pct * 100))}%`;
|
|
60541
|
-
const tone = status.state === "hold" ? "red" : status.state === "warn" ? "yellow" : "green";
|
|
60542
|
-
return { label, tone };
|
|
60543
|
-
}
|
|
60544
|
-
var SessionBudgetTracker, processTracker;
|
|
60545
|
-
var init_costBudget = __esm({
|
|
60546
|
-
"src/cli/costBudget.ts"() {
|
|
60547
|
-
"use strict";
|
|
60548
|
-
SessionBudgetTracker = class {
|
|
60549
|
-
constructor(budget = {}) {
|
|
60550
|
-
this.budget = budget;
|
|
60551
|
-
}
|
|
60552
|
-
usedUsd = 0;
|
|
60553
|
-
usedTokens = 0;
|
|
60554
|
-
get enabled() {
|
|
60555
|
-
return this.budget.maxUsd !== void 0 || this.budget.maxTokens !== void 0;
|
|
60556
|
-
}
|
|
60557
|
-
/** Idempotent per-turn accumulation; ignores NaN/negative inputs. */
|
|
60558
|
-
record(delta) {
|
|
60559
|
-
if (Number.isFinite(delta.costUsd) && (delta.costUsd ?? 0) > 0) this.usedUsd += delta.costUsd ?? 0;
|
|
60560
|
-
if (Number.isFinite(delta.tokens) && (delta.tokens ?? 0) > 0) this.usedTokens += Math.round(delta.tokens ?? 0);
|
|
60561
|
-
}
|
|
60562
|
-
status() {
|
|
60563
|
-
if (!this.enabled) return { state: "off", usedUsd: this.usedUsd, usedTokens: this.usedTokens, pctUsd: null, pctTokens: null };
|
|
60564
|
-
const pctUsd = this.budget.maxUsd !== void 0 ? this.usedUsd / this.budget.maxUsd : null;
|
|
60565
|
-
const pctTokens = this.budget.maxTokens !== void 0 ? this.usedTokens / this.budget.maxTokens : null;
|
|
60566
|
-
const worst = Math.max(pctUsd ?? 0, pctTokens ?? 0);
|
|
60567
|
-
const state3 = worst >= 1 ? "hold" : worst >= 0.8 ? "warn" : "ok";
|
|
60568
|
-
return { state: state3, usedUsd: round6(this.usedUsd), usedTokens: this.usedTokens, pctUsd, pctTokens };
|
|
60569
|
-
}
|
|
60570
|
-
/** True when no further provider turn should start. */
|
|
60571
|
-
isHold() {
|
|
60572
|
-
return this.status().state === "hold";
|
|
60573
|
-
}
|
|
60574
|
-
};
|
|
60575
|
-
}
|
|
60576
|
-
});
|
|
60577
|
-
|
|
60578
60585
|
// src/cli/councilConfig.ts
|
|
60579
60586
|
function resolveCouncilTier(opts) {
|
|
60580
60587
|
const env = opts?.env ?? process.env;
|
|
@@ -69025,7 +69032,10 @@ ${ragContext}` : slicePrompt;
|
|
|
69025
69032
|
userMessage: opts.task,
|
|
69026
69033
|
synthesisText: synthesisText || void 0,
|
|
69027
69034
|
degradedRun: d.degraded,
|
|
69028
|
-
degradedReasons: d.reasons
|
|
69035
|
+
degradedReasons: d.reasons,
|
|
69036
|
+
// 2.31 A1: without sessionId the spine-evidence gate in the hook
|
|
69037
|
+
// never fires, leaving headless with the legacy lint heuristic.
|
|
69038
|
+
sessionId: spine.sessionId
|
|
69029
69039
|
});
|
|
69030
69040
|
completionOk = hook.completion?.completion?.ok ?? false;
|
|
69031
69041
|
if (completionOk) {
|
|
@@ -69131,7 +69141,9 @@ ${ragContext}` : slicePrompt;
|
|
|
69131
69141
|
userMessage: opts.task,
|
|
69132
69142
|
synthesisText: synthesisText || void 0,
|
|
69133
69143
|
degradedRun: d.degraded,
|
|
69134
|
-
degradedReasons: d.reasons
|
|
69144
|
+
degradedReasons: d.reasons,
|
|
69145
|
+
// 2.31 A1: same fix as the council path — evidence gate needs it.
|
|
69146
|
+
sessionId: spine.sessionId
|
|
69135
69147
|
});
|
|
69136
69148
|
if (hook.completion?.completion?.ok) {
|
|
69137
69149
|
emit(`[zelari] slice completion ok`);
|
|
@@ -72138,6 +72150,7 @@ var init_contextGrowthSummary = __esm({
|
|
|
72138
72150
|
// src/cli/utils/doctor.ts
|
|
72139
72151
|
var doctor_exports = {};
|
|
72140
72152
|
__export(doctor_exports, {
|
|
72153
|
+
collectDoctorReport: () => collectDoctorReport,
|
|
72141
72154
|
runDoctor: () => runDoctor
|
|
72142
72155
|
});
|
|
72143
72156
|
import { execSync as execSync2 } from "node:child_process";
|
|
@@ -72403,10 +72416,8 @@ async function checkContextGrowth() {
|
|
|
72403
72416
|
return WARN(`metrics unreadable: ${err instanceof Error ? err.message : String(err)}`);
|
|
72404
72417
|
}
|
|
72405
72418
|
}
|
|
72406
|
-
|
|
72407
|
-
|
|
72408
|
-
const pkgName = pkg?.name ?? "zelari-code";
|
|
72409
|
-
const checks = [
|
|
72419
|
+
function buildDoctorChecks(pkg, pkgName) {
|
|
72420
|
+
return [
|
|
72410
72421
|
// --- install-health checks (main-process probes) ---
|
|
72411
72422
|
{ name: "node", run: () => checkNode(pkg) },
|
|
72412
72423
|
{ name: "bin shim", run: () => checkShim(pkgName) },
|
|
@@ -72485,6 +72496,34 @@ async function runDoctor() {
|
|
|
72485
72496
|
// --- optional desktop computer-use (Cua Driver, trycua) ---
|
|
72486
72497
|
{ name: "cua-driver", run: () => checkCuaDriver() }
|
|
72487
72498
|
];
|
|
72499
|
+
}
|
|
72500
|
+
async function collectDoctorReport() {
|
|
72501
|
+
const pkg = readPackageJson4();
|
|
72502
|
+
const checks = buildDoctorChecks(pkg, pkg?.name ?? "zelari-code");
|
|
72503
|
+
const entries = [];
|
|
72504
|
+
for (const c of checks) {
|
|
72505
|
+
let result;
|
|
72506
|
+
try {
|
|
72507
|
+
result = await c.run();
|
|
72508
|
+
} catch (err) {
|
|
72509
|
+
result = FAIL(
|
|
72510
|
+
`unexpected error: ${err instanceof Error ? err.message : String(err)}`
|
|
72511
|
+
);
|
|
72512
|
+
}
|
|
72513
|
+
entries.push({
|
|
72514
|
+
name: c.name,
|
|
72515
|
+
ok: result.ok,
|
|
72516
|
+
severity: result.ok ? "none" : result.severity ?? "warn",
|
|
72517
|
+
message: result.message
|
|
72518
|
+
});
|
|
72519
|
+
}
|
|
72520
|
+
const firstRed = entries.find((e) => !e.ok) ?? null;
|
|
72521
|
+
return { entries, firstRed, healthy: entries.every((e) => e.ok) };
|
|
72522
|
+
}
|
|
72523
|
+
async function runDoctor() {
|
|
72524
|
+
const pkg = readPackageJson4();
|
|
72525
|
+
const pkgName = pkg?.name ?? "zelari-code";
|
|
72526
|
+
const checks = buildDoctorChecks(pkg, pkgName);
|
|
72488
72527
|
console.log(`zelari-code doctor (v${pkg?.version ?? "unknown"})`);
|
|
72489
72528
|
console.log("platform:", process.platform, process.arch);
|
|
72490
72529
|
console.log("node: ", process.version);
|
|
@@ -73657,6 +73696,10 @@ function formatStrictBlockExplanation(evaluation) {
|
|
|
73657
73696
|
if (unsatisfied.length > 8) {
|
|
73658
73697
|
lines.push(` \u2022 \u2026 e altri ${unsatisfied.length - 8}`);
|
|
73659
73698
|
}
|
|
73699
|
+
const first = byId.get(unsatisfied[0].criterionId) ?? unsatisfied[0].criterionId;
|
|
73700
|
+
lines.push(
|
|
73701
|
+
state3 === "blocked" ? `Prossimo comando: /verify \u2014 poi porta evidenza per \xAB${first}\xBB e riprova.` : `Prossimo comando: ripara \xAB${first}\xBB, poi /verify per ricontrollare.`
|
|
73702
|
+
);
|
|
73660
73703
|
}
|
|
73661
73704
|
}
|
|
73662
73705
|
lines.push(
|
|
@@ -76468,6 +76511,28 @@ function useChatTurn(params) {
|
|
|
76468
76511
|
return;
|
|
76469
76512
|
}
|
|
76470
76513
|
}
|
|
76514
|
+
{
|
|
76515
|
+
const { sessionBudgetHoldNotice: sessionBudgetHoldNotice2 } = await Promise.resolve().then(() => (init_costBudget(), costBudget_exports));
|
|
76516
|
+
const hold = sessionBudgetHoldNotice2();
|
|
76517
|
+
if (hold) {
|
|
76518
|
+
appendSystem(setMessages, hold, Date.now());
|
|
76519
|
+
return;
|
|
76520
|
+
}
|
|
76521
|
+
}
|
|
76522
|
+
{
|
|
76523
|
+
const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
|
|
76524
|
+
const phaseMod = await Promise.resolve().then(() => (init_phaseState(), phaseState_exports));
|
|
76525
|
+
const g = globalThis;
|
|
76526
|
+
if (phaseMod.getPhase() === "build" && !hasWorkspacePlan2(process.cwd()) && !g.__zelariPlanFirstNotice) {
|
|
76527
|
+
g.__zelariPlanFirstNotice = true;
|
|
76528
|
+
phaseMod.setPhase("plan");
|
|
76529
|
+
appendSystem(
|
|
76530
|
+
setMessages,
|
|
76531
|
+
`[permessi] No workspace plan found \u2014 first turn forced to PLAN (no surprise writes). Type /build to switch to BUILD explicitly.`,
|
|
76532
|
+
Date.now()
|
|
76533
|
+
);
|
|
76534
|
+
}
|
|
76535
|
+
}
|
|
76471
76536
|
setBusy(true);
|
|
76472
76537
|
const workPhase = getPhase();
|
|
76473
76538
|
try {
|
|
@@ -83913,19 +83978,57 @@ function main() {
|
|
|
83913
83978
|
});
|
|
83914
83979
|
return;
|
|
83915
83980
|
}
|
|
83916
|
-
|
|
83917
|
-
|
|
83918
|
-
unmount();
|
|
83919
|
-
|
|
83920
|
-
|
|
83921
|
-
|
|
83922
|
-
|
|
83923
|
-
|
|
83924
|
-
|
|
83925
|
-
|
|
83926
|
-
|
|
83927
|
-
void
|
|
83981
|
+
void (async () => {
|
|
83982
|
+
await runFirstRunDoctorGate();
|
|
83983
|
+
const { waitUntilExit, unmount } = render(picked.element);
|
|
83984
|
+
process.on("SIGINT", () => {
|
|
83985
|
+
unmount();
|
|
83986
|
+
void shutdown();
|
|
83987
|
+
});
|
|
83988
|
+
process.on("SIGTERM", () => {
|
|
83989
|
+
unmount();
|
|
83990
|
+
void shutdown();
|
|
83991
|
+
});
|
|
83992
|
+
void backgroundUpdateCheck();
|
|
83993
|
+
waitUntilExit().then(() => {
|
|
83994
|
+
void shutdown();
|
|
83995
|
+
});
|
|
83996
|
+
})();
|
|
83997
|
+
}
|
|
83998
|
+
async function runFirstRunDoctorGate() {
|
|
83999
|
+
try {
|
|
84000
|
+
const { getActiveProvider: getActiveProvider2 } = await Promise.resolve().then(() => (init_providerConfig(), providerConfig_exports));
|
|
84001
|
+
const { resolveApiKey: resolveApiKey2, getOAuthToken: getOAuthToken2 } = await Promise.resolve().then(() => (init_keyStore(), keyStore_exports));
|
|
84002
|
+
const active = getActiveProvider2();
|
|
84003
|
+
if (resolveApiKey2(active.id) || getOAuthToken2(active.id)) return;
|
|
84004
|
+
} catch {
|
|
84005
|
+
return;
|
|
84006
|
+
}
|
|
84007
|
+
const { collectDoctorReport: collectDoctorReport2 } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
|
|
84008
|
+
const report = await collectDoctorReport2();
|
|
84009
|
+
if (report.healthy) return;
|
|
84010
|
+
const red = report.firstRed;
|
|
84011
|
+
const line = (s) => process.stderr.write(s + "\n");
|
|
84012
|
+
line("");
|
|
84013
|
+
line("\u250C\u2500 first run: doctor");
|
|
84014
|
+
line(`\u2502 \u2717 ${red.name} \u2014 ${red.message.replace(/\n/g, "\n\u2502 ")}`);
|
|
84015
|
+
line("\u2502 Fix the red above (its message names the exact command), then re-run:");
|
|
84016
|
+
line("\u2502 zelari-code --doctor");
|
|
84017
|
+
line("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
84018
|
+
if (!process.stdin.isTTY) {
|
|
84019
|
+
line("[wizard] non-interactive session: continuing with a RED doctor (dichiarato).");
|
|
84020
|
+
return;
|
|
84021
|
+
}
|
|
84022
|
+
const rl = (await import("node:readline/promises")).createInterface({
|
|
84023
|
+
input: process.stdin,
|
|
84024
|
+
output: process.stdout
|
|
83928
84025
|
});
|
|
84026
|
+
const answer = (await rl.question('Continue anyway with a RED doctor? Type "si" to continue: ')).trim().toLowerCase();
|
|
84027
|
+
rl.close();
|
|
84028
|
+
if (answer !== "si" && answer !== "s\xEC" && answer !== "yes" && answer !== "y") {
|
|
84029
|
+
process.exit(1);
|
|
84030
|
+
}
|
|
84031
|
+
line("[wizard] continue-anyway dichiarato \u2014 doctor is still red.");
|
|
83929
84032
|
}
|
|
83930
84033
|
main();
|
|
83931
84034
|
export {
|