@event4u/agent-config 13.0.0 → 14.0.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +160 -333
- package/README.md +1 -1
- package/dist/agent-src/commands/evals/roadmap.json +8 -0
- package/dist/agent-src/commands/fix/ci.md +39 -1
- package/dist/agent-src/commands/pr/create.md +65 -4
- package/dist/agent-src/commands/roadmap/next.md +28 -5
- package/dist/agent-src/commands/work.md +16 -0
- package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +47 -0
- package/dist/agent-src/contexts/execution/contract-decision-sheet.md +94 -0
- package/dist/agent-src/contexts/execution/plan-confidence-gate.md +30 -0
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +21 -8
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +55 -8
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +42 -0
- package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +29 -0
- package/dist/agent-src/rules/command-suggestion-policy.md +33 -0
- package/dist/agent-src/rules/design-review-after-ui-write.md +25 -8
- package/dist/agent-src/rules/ui-audit-gate.md +25 -8
- package/dist/agent-src/scripts/gate_execute.ts +395 -0
- package/dist/agent-src/scripts/resume_probe.ts +422 -0
- package/dist/agent-src/scripts/roadmap_gates.ts +138 -4
- package/dist/agent-src/scripts/update_roadmap_progress.ts +53 -2
- package/dist/agent-src/skills/ai-council/SKILL.md +61 -0
- package/dist/agent-src/skills/experiment-loop/SKILL.md +116 -0
- package/dist/agent-src/skills/experiment-loop/evals/output-schema.yml +27 -0
- package/dist/agent-src/skills/experiment-loop/evals/triggers.json +17 -0
- package/dist/agent-src/skills/experiment-loop/references/pivot-ladder.md +54 -0
- package/dist/agent-src/skills/experiment-loop/references/protocol.md +61 -0
- package/dist/agent-src/skills/experiment-loop/references/register-format.md +66 -0
- package/dist/agent-src/skills/roadmap-management/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/subagent-orchestration/schemas/team-review-status.json +8 -3
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +43 -3
- package/dist/cli/registry.js +1 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-N7FEST6D.js → chunk-7PZ4FSZB.js} +351 -174
- package/dist/cli-delegate/{chunk-3B72LSZL.js → chunk-F3YUF7SA.js} +1 -1
- package/dist/cli-delegate/cmd_conformance.js +224 -104
- package/dist/cli-delegate/cmd_doctor.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +40 -18
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +6 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +5 -4
- package/dist/hooks/dispatch.js +2018 -1320
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1652 -892
- package/dist/router.json +1 -1
- package/dist/scripts/condense.js +1 -1
- package/dist/scripts/condense.js.map +1 -1
- package/dist/ui/assets/{index-B0aMJnuz.js → index-C1pBRm1f.js} +2 -2
- package/dist/ui/assets/index-C1pBRm1f.js.map +1 -0
- package/dist/ui/index.html +1 -1
- package/package.json +1 -1
- package/src/agent-src/scripts/gate_execute.ts +395 -0
- package/src/agent-src/scripts/resume_probe.ts +422 -0
- package/src/agent-src/scripts/roadmap_gates.ts +138 -4
- package/src/agent-src/scripts/update_roadmap_progress.ts +53 -2
- package/src/config/ci-local-parity.yml +13 -0
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +111 -5
- package/src/config/gate-violation-baselines.json +2 -2
- package/src/config/rule-activation-census.json +41 -0
- package/src/config/rule-stub-ceilings.json +52 -0
- package/src/scripts/_dispatch.bash +4 -0
- package/src/scripts/_lib/evaluator_contract.ts +159 -0
- package/src/scripts/_lib/gh_transient.ts +80 -0
- package/src/scripts/_lib/release_material.ts +16 -5
- package/src/scripts/_lib/review_independence.ts +111 -0
- package/src/scripts/_lib/session_register.ts +14 -0
- package/src/scripts/_lib/skill_catalogue.ts +20 -0
- package/src/scripts/_lib/skill_catalogue_series.ts +411 -0
- package/src/scripts/_lib/turn_end_refusals.ts +482 -0
- package/src/scripts/ai_council/_py_json.ts +96 -0
- package/src/scripts/ai_council/cli_call_budget.ts +357 -0
- package/src/scripts/ai_council/clients.ts +80 -143
- package/src/scripts/ai_council/config.ts +25 -11
- package/src/scripts/ai_council/probe_store.ts +196 -0
- package/src/scripts/ai_council/qualification.ts +425 -0
- package/src/scripts/ai_council/qualification_wiring.ts +243 -0
- package/src/scripts/ai_council/quorum_wiring.ts +211 -0
- package/src/scripts/ai_team/team_dispatch.ts +40 -6
- package/src/scripts/capture_skill_catalogue.ts +264 -4
- package/src/scripts/check_evaluator_schema.ts +249 -0
- package/src/scripts/check_pr_ci_current.ts +409 -0
- package/src/scripts/check_review_schema.ts +195 -0
- package/src/scripts/check_rule_activation_census.ts +451 -0
- package/src/scripts/check_rule_stub_ceiling.ts +1128 -0
- package/src/scripts/condense.ts +1 -1
- package/src/scripts/council_cli.ts +141 -191
- package/src/scripts/dispatch_r2_reviewer.ts +8 -1
- package/src/scripts/hook_manifest.yaml +72 -5
- package/src/scripts/hooks/concern_registry.ts +4 -0
- package/src/scripts/hooks/dispatch_hook.ts +43 -1
- package/src/scripts/hooks/interruption_ledger_hook.ts +256 -0
- package/src/scripts/hooks/ship_diff_volume_hook.ts +180 -0
- package/src/scripts/hooks/turn_end_gate_hook.ts +119 -26
- package/src/scripts/hooks_doctor.ts +112 -0
- package/src/scripts/interruption_report.ts +443 -0
- package/src/scripts/lint_evidence_artifacts.ts +359 -0
- package/src/scripts/lint_roadmap_blockers.ts +65 -0
- package/src/scripts/lint_roadmap_complexity.ts +7 -1
- package/src/scripts/release.ts +38 -53
- package/src/scripts/rule_activation_census.ts +292 -0
- package/src/scripts/schemas/evaluator-output.schema.json +60 -0
- package/src/scripts/schemas/review-findings.schema.json +31 -0
- package/src/scripts/self_review_gate.ts +6 -0
- package/src/scripts/session_register_hook.ts +30 -1
- package/src/scripts/sync_pr_branch.ts +271 -0
- package/src/scripts/test_council_qualification.ts +213 -0
- package/dist/ui/assets/index-B0aMJnuz.js.map +0 -1
|
@@ -21,7 +21,11 @@ __export(clients_exports, {
|
|
|
21
21
|
ANTHROPIC_KEY_PATH: () => ANTHROPIC_KEY_PATH,
|
|
22
22
|
AnthropicCliClient: () => AnthropicCliClient,
|
|
23
23
|
AnthropicClient: () => AnthropicClient,
|
|
24
|
+
CLI_CALLS_ATTRIBUTION_SUFFIX: () => CLI_CALLS_ATTRIBUTION_SUFFIX,
|
|
24
25
|
CLI_CALLS_FILENAME: () => CLI_CALLS_FILENAME,
|
|
26
|
+
CLI_CONSUMER_COUNCIL: () => CLI_CONSUMER_COUNCIL,
|
|
27
|
+
CLI_CONSUMER_TEAM: () => CLI_CONSUMER_TEAM,
|
|
28
|
+
CLI_CONSUMER_UNKNOWN: () => CLI_CONSUMER_UNKNOWN,
|
|
25
29
|
CODEX_MEASURED_UNSERVABLE: () => CODEX_MEASURED_UNSERVABLE,
|
|
26
30
|
CliClient: () => CliClient,
|
|
27
31
|
CliClientError: () => CliClientError,
|
|
@@ -52,6 +56,8 @@ __export(clients_exports, {
|
|
|
52
56
|
PERPLEXITY_BASE_URL: () => PERPLEXITY_BASE_URL,
|
|
53
57
|
PerplexityCliClient: () => PerplexityCliClient,
|
|
54
58
|
PerplexityClient: () => PerplexityClient,
|
|
59
|
+
QUOTA_SOURCE_LOCAL_BUDGET: () => QUOTA_SOURCE_LOCAL_BUDGET,
|
|
60
|
+
QUOTA_SOURCE_PROVIDER: () => QUOTA_SOURCE_PROVIDER,
|
|
55
61
|
SubprocessError: () => SubprocessError,
|
|
56
62
|
UNLIMITED_TOKENS_FALLBACK: () => UNLIMITED_TOKENS_FALLBACK,
|
|
57
63
|
ValueError: () => ValueError,
|
|
@@ -68,6 +74,7 @@ __export(clients_exports, {
|
|
|
68
74
|
_today_utc_iso: () => _today_utc_iso,
|
|
69
75
|
assertCacheBreakpointOrder: () => assertCacheBreakpointOrder,
|
|
70
76
|
load_anthropic_key: () => load_anthropic_key,
|
|
77
|
+
load_cli_call_attribution: () => load_cli_call_attribution,
|
|
71
78
|
load_cli_call_counts: () => load_cli_call_counts,
|
|
72
79
|
load_openai_key: () => load_openai_key,
|
|
73
80
|
quota_summary_line: () => quota_summary_line,
|
|
@@ -75,9 +82,9 @@ __export(clients_exports, {
|
|
|
75
82
|
reset_cli_call_counts: () => reset_cli_call_counts
|
|
76
83
|
});
|
|
77
84
|
import { spawnSync } from "node:child_process";
|
|
78
|
-
import * as
|
|
85
|
+
import * as fs3 from "node:fs";
|
|
79
86
|
import * as os from "node:os";
|
|
80
|
-
import * as
|
|
87
|
+
import * as path3 from "node:path";
|
|
81
88
|
|
|
82
89
|
// src/scripts/_lib/spawn_env.ts
|
|
83
90
|
var DENY_EXACT = /* @__PURE__ */ new Set([
|
|
@@ -151,10 +158,268 @@ function resolveSessionRole(env = process.env) {
|
|
|
151
158
|
return KNOWN_ROLES.has(raw) ? raw : "orchestrator";
|
|
152
159
|
}
|
|
153
160
|
|
|
154
|
-
// src/scripts/ai_council/
|
|
155
|
-
|
|
161
|
+
// src/scripts/ai_council/_py_json.ts
|
|
162
|
+
function jsonDumpsIndent2(value) {
|
|
163
|
+
return _jsonDumpsIndented(value, 2, 0);
|
|
164
|
+
}
|
|
165
|
+
function _jsonDumpsIndented(value, indent, level) {
|
|
166
|
+
if (value === null || value === void 0) {
|
|
167
|
+
return "null";
|
|
168
|
+
}
|
|
169
|
+
switch (typeof value) {
|
|
170
|
+
case "boolean":
|
|
171
|
+
return value ? "true" : "false";
|
|
172
|
+
case "number":
|
|
173
|
+
return _pyJsonNumber(value);
|
|
174
|
+
case "string":
|
|
175
|
+
return _pyJsonStringAscii(value);
|
|
176
|
+
case "object":
|
|
177
|
+
break;
|
|
178
|
+
default:
|
|
179
|
+
throw new TypeError(`Object of type ${typeof value} is not JSON serializable`);
|
|
180
|
+
}
|
|
181
|
+
const pad = " ".repeat(indent * (level + 1));
|
|
182
|
+
const closePad = " ".repeat(indent * level);
|
|
183
|
+
if (Array.isArray(value)) {
|
|
184
|
+
if (value.length === 0) {
|
|
185
|
+
return "[]";
|
|
186
|
+
}
|
|
187
|
+
const items2 = value.map((v) => pad + _jsonDumpsIndented(v, indent, level + 1));
|
|
188
|
+
return `[
|
|
189
|
+
${items2.join(",\n")}
|
|
190
|
+
${closePad}]`;
|
|
191
|
+
}
|
|
192
|
+
const obj = value;
|
|
193
|
+
const keys = Object.keys(obj);
|
|
194
|
+
if (keys.length === 0) {
|
|
195
|
+
return "{}";
|
|
196
|
+
}
|
|
197
|
+
const items = keys.map(
|
|
198
|
+
(k) => `${pad}${_pyJsonStringAscii(k)}: ${_jsonDumpsIndented(obj[k], indent, level + 1)}`
|
|
199
|
+
);
|
|
200
|
+
return `{
|
|
201
|
+
${items.join(",\n")}
|
|
202
|
+
${closePad}}`;
|
|
203
|
+
}
|
|
204
|
+
function _pyJsonNumber(n) {
|
|
205
|
+
if (!Number.isFinite(n)) {
|
|
206
|
+
if (Number.isNaN(n)) {
|
|
207
|
+
return "NaN";
|
|
208
|
+
}
|
|
209
|
+
return n > 0 ? "Infinity" : "-Infinity";
|
|
210
|
+
}
|
|
211
|
+
return String(n);
|
|
212
|
+
}
|
|
213
|
+
function _pyJsonStringAscii(s) {
|
|
214
|
+
let out = '"';
|
|
215
|
+
for (const ch of s) {
|
|
216
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
217
|
+
if (ch === '"') {
|
|
218
|
+
out += '\\"';
|
|
219
|
+
} else if (ch === "\\") {
|
|
220
|
+
out += "\\\\";
|
|
221
|
+
} else if (ch === "\b") {
|
|
222
|
+
out += "\\b";
|
|
223
|
+
} else if (ch === "\f") {
|
|
224
|
+
out += "\\f";
|
|
225
|
+
} else if (ch === "\n") {
|
|
226
|
+
out += "\\n";
|
|
227
|
+
} else if (ch === "\r") {
|
|
228
|
+
out += "\\r";
|
|
229
|
+
} else if (ch === " ") {
|
|
230
|
+
out += "\\t";
|
|
231
|
+
} else if (code < 32) {
|
|
232
|
+
out += `\\u${code.toString(16).padStart(4, "0")}`;
|
|
233
|
+
} else if (code < 127) {
|
|
234
|
+
out += ch;
|
|
235
|
+
} else if (code <= 65535) {
|
|
236
|
+
out += `\\u${code.toString(16).padStart(4, "0")}`;
|
|
237
|
+
} else {
|
|
238
|
+
const c = code - 65536;
|
|
239
|
+
const hi = 55296 + (c >> 10);
|
|
240
|
+
const lo = 56320 + (c & 1023);
|
|
241
|
+
out += `\\u${hi.toString(16).padStart(4, "0")}\\u${lo.toString(16).padStart(4, "0")}`;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return out + '"';
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/scripts/ai_council/cli_call_budget.ts
|
|
156
248
|
import * as fs from "node:fs";
|
|
157
249
|
import * as path from "node:path";
|
|
250
|
+
var CLI_CALLS_ATTRIBUTION_SUFFIX = ".attribution.json";
|
|
251
|
+
var CLI_CONSUMER_COUNCIL = "council";
|
|
252
|
+
var CLI_CONSUMER_TEAM = "team";
|
|
253
|
+
var CLI_CONSUMER_UNKNOWN = "unknown";
|
|
254
|
+
var QUOTA_SOURCE_LOCAL_BUDGET = "local_budget";
|
|
255
|
+
var QUOTA_SOURCE_PROVIDER = "provider";
|
|
256
|
+
var DEFAULT_CLI_CALLS_PER_DAY = 50;
|
|
257
|
+
function attributionPath(target) {
|
|
258
|
+
return `${target}${CLI_CALLS_ATTRIBUTION_SUFFIX}`;
|
|
259
|
+
}
|
|
260
|
+
function resolveCliCallCaps(raw, validProviders) {
|
|
261
|
+
const out = {};
|
|
262
|
+
for (const provider of validProviders) {
|
|
263
|
+
out[provider] = DEFAULT_CLI_CALLS_PER_DAY;
|
|
264
|
+
}
|
|
265
|
+
if (!_isObject(raw)) {
|
|
266
|
+
return out;
|
|
267
|
+
}
|
|
268
|
+
const known = new Set(Object.keys(out));
|
|
269
|
+
for (const [provider, value] of Object.entries(raw)) {
|
|
270
|
+
if (!known.has(provider)) {
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
out[provider] = value;
|
|
277
|
+
}
|
|
278
|
+
return out;
|
|
279
|
+
}
|
|
280
|
+
function writeStateAtomically(target, payload) {
|
|
281
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
282
|
+
const tmp = `${target}.${process.pid}.${_monotonicish()}.tmp`;
|
|
283
|
+
try {
|
|
284
|
+
fs.writeFileSync(tmp, payload, { encoding: "utf-8" });
|
|
285
|
+
fs.renameSync(tmp, target);
|
|
286
|
+
} catch (exc) {
|
|
287
|
+
try {
|
|
288
|
+
fs.unlinkSync(tmp);
|
|
289
|
+
} catch {
|
|
290
|
+
}
|
|
291
|
+
throw exc;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function withStateLock(target, fn) {
|
|
295
|
+
const lockPath = `${target}.lock`;
|
|
296
|
+
const waitMs = 1e3;
|
|
297
|
+
let held = false;
|
|
298
|
+
const started = _monotonicish();
|
|
299
|
+
while (_monotonicish() - started < waitMs) {
|
|
300
|
+
try {
|
|
301
|
+
fs.mkdirSync(path.dirname(lockPath), { recursive: true });
|
|
302
|
+
fs.closeSync(fs.openSync(lockPath, "wx"));
|
|
303
|
+
held = true;
|
|
304
|
+
break;
|
|
305
|
+
} catch {
|
|
306
|
+
try {
|
|
307
|
+
if (_monotonicish() - fs.statSync(lockPath).mtimeMs > waitMs) {
|
|
308
|
+
fs.unlinkSync(lockPath);
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
} catch {
|
|
312
|
+
}
|
|
313
|
+
_spin(20);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
try {
|
|
317
|
+
return fn();
|
|
318
|
+
} finally {
|
|
319
|
+
if (held) {
|
|
320
|
+
try {
|
|
321
|
+
fs.unlinkSync(lockPath);
|
|
322
|
+
} catch {
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function readAttribution(target, todayIso) {
|
|
328
|
+
const p = attributionPath(target);
|
|
329
|
+
if (!fs.existsSync(p)) {
|
|
330
|
+
return {};
|
|
331
|
+
}
|
|
332
|
+
let data;
|
|
333
|
+
try {
|
|
334
|
+
data = JSON.parse(fs.readFileSync(p, { encoding: "utf-8" }));
|
|
335
|
+
} catch {
|
|
336
|
+
return {};
|
|
337
|
+
}
|
|
338
|
+
if (!_isObject(data) || data["date"] !== todayIso) {
|
|
339
|
+
return {};
|
|
340
|
+
}
|
|
341
|
+
const raw = data["by_consumer"];
|
|
342
|
+
if (!_isObject(raw)) {
|
|
343
|
+
return {};
|
|
344
|
+
}
|
|
345
|
+
const out = {};
|
|
346
|
+
for (const [provider, perConsumer] of Object.entries(raw)) {
|
|
347
|
+
if (!_isObject(perConsumer)) {
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
const bucket = {};
|
|
351
|
+
for (const [consumer, v] of Object.entries(perConsumer)) {
|
|
352
|
+
if (typeof v === "number" && Number.isInteger(v)) {
|
|
353
|
+
bucket[consumer] = v;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
out[provider] = bucket;
|
|
357
|
+
}
|
|
358
|
+
return out;
|
|
359
|
+
}
|
|
360
|
+
function recordAttribution(target, provider, consumer, todayIso, serialize) {
|
|
361
|
+
try {
|
|
362
|
+
const by_consumer = readAttribution(target, todayIso);
|
|
363
|
+
const bucket = by_consumer[provider] ?? {};
|
|
364
|
+
bucket[consumer] = (bucket[consumer] ?? 0) + 1;
|
|
365
|
+
by_consumer[provider] = bucket;
|
|
366
|
+
writeStateAtomically(attributionPath(target), serialize({ date: todayIso, by_consumer }));
|
|
367
|
+
} catch {
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function resetAttribution(target, provider, todayIso, serialize) {
|
|
371
|
+
try {
|
|
372
|
+
let by_consumer = readAttribution(target, todayIso);
|
|
373
|
+
if (provider === null) {
|
|
374
|
+
by_consumer = {};
|
|
375
|
+
} else {
|
|
376
|
+
delete by_consumer[provider];
|
|
377
|
+
}
|
|
378
|
+
writeStateAtomically(attributionPath(target), serialize({ date: todayIso, by_consumer }));
|
|
379
|
+
} catch {
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
function quotaSummaryLine(clients, counts) {
|
|
383
|
+
const capOf = (c) => typeof c.max_calls_per_day === "number" && Number.isFinite(c.max_calls_per_day) ? c.max_calls_per_day : null;
|
|
384
|
+
const nameOf = (c) => typeof c.name === "string" && c.name !== "" ? c.name : "?";
|
|
385
|
+
const usedOf = (c) => Math.trunc(counts[nameOf(c)] ?? 0);
|
|
386
|
+
if (clients.length === 0) {
|
|
387
|
+
return ["", []];
|
|
388
|
+
}
|
|
389
|
+
const parts = [];
|
|
390
|
+
const warn = [];
|
|
391
|
+
for (const c of clients) {
|
|
392
|
+
const limit = capOf(c);
|
|
393
|
+
const used = usedOf(c);
|
|
394
|
+
if (limit === null) {
|
|
395
|
+
parts.push(`${nameOf(c)} ${used}/uncapped`);
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
parts.push(`${nameOf(c)} ${used}/${Math.trunc(limit)}`);
|
|
399
|
+
const warnAt = typeof c.warn_at === "number" ? c.warn_at : 0.8;
|
|
400
|
+
if (limit === 0 ? used > 0 : used / limit >= warnAt) {
|
|
401
|
+
warn.push(nameOf(c));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
const prefix = warn.length > 0 ? "\u26A0\uFE0F " : "";
|
|
405
|
+
return [`${prefix}council:quota \xB7 ${parts.join(" \xB7 ")}`, warn];
|
|
406
|
+
}
|
|
407
|
+
function _isObject(x) {
|
|
408
|
+
return typeof x === "object" && x !== null && !Array.isArray(x);
|
|
409
|
+
}
|
|
410
|
+
function _monotonicish() {
|
|
411
|
+
return performance.now();
|
|
412
|
+
}
|
|
413
|
+
function _spin(ms) {
|
|
414
|
+
const until = _monotonicish() + ms;
|
|
415
|
+
while (_monotonicish() < until) {
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// src/scripts/ai_council/events_log.ts
|
|
420
|
+
import * as crypto from "node:crypto";
|
|
421
|
+
import * as fs2 from "node:fs";
|
|
422
|
+
import * as path2 from "node:path";
|
|
158
423
|
import { fileURLToPath } from "node:url";
|
|
159
424
|
|
|
160
425
|
// src/scripts/_lib/env_kill_switch.ts
|
|
@@ -176,8 +441,8 @@ var _VALID_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
176
441
|
]);
|
|
177
442
|
var _KILL_SWITCH_ENV = "AGENT_CONFIG_NO_EVENTS_LOG";
|
|
178
443
|
var _HERE = fileURLToPath(import.meta.url);
|
|
179
|
-
var _REPO_ROOT =
|
|
180
|
-
var _DEFAULT_LOG_PATH =
|
|
444
|
+
var _REPO_ROOT = path2.resolve(path2.dirname(_HERE), "..", "..", "..");
|
|
445
|
+
var _DEFAULT_LOG_PATH = path2.join(
|
|
181
446
|
_REPO_ROOT,
|
|
182
447
|
"agents",
|
|
183
448
|
"runtime",
|
|
@@ -277,9 +542,9 @@ function appendEvent(event, opts = {}) {
|
|
|
277
542
|
}
|
|
278
543
|
}
|
|
279
544
|
const target = opts.logPath != null ? opts.logPath : _DEFAULT_LOG_PATH;
|
|
280
|
-
|
|
545
|
+
fs2.mkdirSync(path2.dirname(target), { recursive: true });
|
|
281
546
|
const line = _pyJsonDumpsCompact(record);
|
|
282
|
-
|
|
547
|
+
fs2.appendFileSync(target, line + "\n", { encoding: "utf-8" });
|
|
283
548
|
return true;
|
|
284
549
|
}
|
|
285
550
|
function _isoSecondsZ(d) {
|
|
@@ -312,7 +577,7 @@ function _pyJsonDumpsCompact(value) {
|
|
|
312
577
|
case "boolean":
|
|
313
578
|
return value ? "true" : "false";
|
|
314
579
|
case "number":
|
|
315
|
-
return
|
|
580
|
+
return _pyJsonNumber2(value);
|
|
316
581
|
case "string":
|
|
317
582
|
return _pyJsonStringRaw(value);
|
|
318
583
|
case "object":
|
|
@@ -330,7 +595,7 @@ function _pyJsonDumpsCompact(value) {
|
|
|
330
595
|
}
|
|
331
596
|
return `{${parts.join(",")}}`;
|
|
332
597
|
}
|
|
333
|
-
function
|
|
598
|
+
function _pyJsonNumber2(n) {
|
|
334
599
|
if (!Number.isFinite(n)) {
|
|
335
600
|
if (Number.isNaN(n)) {
|
|
336
601
|
return "NaN";
|
|
@@ -501,13 +766,13 @@ function _setMonotonicSource(fn) {
|
|
|
501
766
|
return prev;
|
|
502
767
|
}
|
|
503
768
|
function _loadKey(p, prefix, installScript) {
|
|
504
|
-
if (!
|
|
769
|
+
if (!fs3.existsSync(p)) {
|
|
505
770
|
throw new KeyGateError(
|
|
506
771
|
`Key not found at ${p}.
|
|
507
772
|
Install it with: bash ${installScript}`
|
|
508
773
|
);
|
|
509
774
|
}
|
|
510
|
-
const st =
|
|
775
|
+
const st = fs3.statSync(p);
|
|
511
776
|
const mode = st.mode & 511;
|
|
512
777
|
if (mode !== 384) {
|
|
513
778
|
throw new KeyGateError(
|
|
@@ -515,7 +780,7 @@ function _loadKey(p, prefix, installScript) {
|
|
|
515
780
|
Fix: chmod 600 ${p}`
|
|
516
781
|
);
|
|
517
782
|
}
|
|
518
|
-
const key =
|
|
783
|
+
const key = fs3.readFileSync(p, { encoding: "utf-8" }).trim();
|
|
519
784
|
if (!key) {
|
|
520
785
|
throw new KeyGateError(`${p} is empty.`);
|
|
521
786
|
}
|
|
@@ -978,12 +1243,12 @@ function _today_utc_iso() {
|
|
|
978
1243
|
}
|
|
979
1244
|
function load_cli_call_counts(p = null) {
|
|
980
1245
|
const target = p !== null ? p : _cliCallsStatePath();
|
|
981
|
-
if (!
|
|
1246
|
+
if (!fs3.existsSync(target)) {
|
|
982
1247
|
return {};
|
|
983
1248
|
}
|
|
984
1249
|
let data;
|
|
985
1250
|
try {
|
|
986
|
-
data = JSON.parse(
|
|
1251
|
+
data = JSON.parse(fs3.readFileSync(target, { encoding: "utf-8" }));
|
|
987
1252
|
} catch {
|
|
988
1253
|
return {};
|
|
989
1254
|
}
|
|
@@ -1006,56 +1271,38 @@ function load_cli_call_counts(p = null) {
|
|
|
1006
1271
|
}
|
|
1007
1272
|
return out;
|
|
1008
1273
|
}
|
|
1009
|
-
function
|
|
1274
|
+
function load_cli_call_attribution(p = null) {
|
|
1010
1275
|
const target = p !== null ? p : _cliCallsStatePath();
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1276
|
+
return readAttribution(target, _today_utc_iso());
|
|
1277
|
+
}
|
|
1278
|
+
function record_cli_call(provider, p = null, consumer = CLI_CONSUMER_UNKNOWN) {
|
|
1279
|
+
const target = p !== null ? p : _cliCallsStatePath();
|
|
1280
|
+
const today = _today_utc_iso();
|
|
1281
|
+
return withStateLock(target, () => {
|
|
1282
|
+
const counts = load_cli_call_counts(target);
|
|
1283
|
+
counts[provider] = (counts[provider] ?? 0) + 1;
|
|
1284
|
+
writeStateAtomically(target, jsonDumpsIndent2({ date: today, counts }));
|
|
1285
|
+
recordAttribution(target, provider, consumer, today, jsonDumpsIndent2);
|
|
1286
|
+
return counts[provider];
|
|
1287
|
+
});
|
|
1020
1288
|
}
|
|
1021
1289
|
function reset_cli_call_counts(provider = null, p = null) {
|
|
1022
1290
|
const target = p !== null ? p : _cliCallsStatePath();
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
counts =
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
target,
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
);
|
|
1035
|
-
return counts;
|
|
1291
|
+
const today = _today_utc_iso();
|
|
1292
|
+
return withStateLock(target, () => {
|
|
1293
|
+
let counts = load_cli_call_counts(target);
|
|
1294
|
+
if (provider === null) {
|
|
1295
|
+
counts = {};
|
|
1296
|
+
} else {
|
|
1297
|
+
delete counts[provider];
|
|
1298
|
+
}
|
|
1299
|
+
writeStateAtomically(target, jsonDumpsIndent2({ date: today, counts }));
|
|
1300
|
+
resetAttribution(target, provider, today, jsonDumpsIndent2);
|
|
1301
|
+
return counts;
|
|
1302
|
+
});
|
|
1036
1303
|
}
|
|
1037
1304
|
function quota_summary_line(clients, opts = {}) {
|
|
1038
|
-
|
|
1039
|
-
const capped = clients.filter((c) => _pyTruthy(_getattr(c, "max_calls_per_day", null)));
|
|
1040
|
-
if (capped.length === 0) {
|
|
1041
|
-
return ["", []];
|
|
1042
|
-
}
|
|
1043
|
-
const counts = load_cli_call_counts(cliCallsPath);
|
|
1044
|
-
const parts = [];
|
|
1045
|
-
const warn = [];
|
|
1046
|
-
for (const c of capped) {
|
|
1047
|
-
const name = _getattr(c, "name", "?");
|
|
1048
|
-
const used = _pyInt(counts[name] ?? 0);
|
|
1049
|
-
const limit = _pyInt(c.max_calls_per_day);
|
|
1050
|
-
parts.push(`${name} ${used}/${limit}`);
|
|
1051
|
-
const ratio = limit > 0 ? used / limit : 0;
|
|
1052
|
-
const warnAt = Number(_getattr(c, "warn_at", 0.8));
|
|
1053
|
-
if (ratio >= warnAt) {
|
|
1054
|
-
warn.push(name);
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
const prefix = warn.length > 0 ? "\u26A0\uFE0F " : "";
|
|
1058
|
-
return [`${prefix}council:quota \xB7 ${parts.join(" \xB7 ")}`, warn];
|
|
1305
|
+
return quotaSummaryLine(clients, load_cli_call_counts(opts.cli_calls_path ?? null));
|
|
1059
1306
|
}
|
|
1060
1307
|
var SubprocessError = class extends Error {
|
|
1061
1308
|
kind;
|
|
@@ -1076,6 +1323,8 @@ var CliClient = class extends ExternalAIClient {
|
|
|
1076
1323
|
warn_at;
|
|
1077
1324
|
binary;
|
|
1078
1325
|
_cli_calls_path;
|
|
1326
|
+
/** Attribution label for every booking this client makes. */
|
|
1327
|
+
_consumer;
|
|
1079
1328
|
static _AUTH_FAILURE_PATTERNS = [
|
|
1080
1329
|
"authentication",
|
|
1081
1330
|
"unauthorized",
|
|
@@ -1114,6 +1363,7 @@ var CliClient = class extends ExternalAIClient {
|
|
|
1114
1363
|
this.max_calls_per_day = opts.max_calls_per_day ?? null;
|
|
1115
1364
|
this.warn_at = opts.warn_at ?? 0.8;
|
|
1116
1365
|
this._cli_calls_path = opts.cli_calls_path ?? null;
|
|
1366
|
+
this._consumer = opts.consumer ?? CLI_CONSUMER_UNKNOWN;
|
|
1117
1367
|
const binary = opts.binary ?? null;
|
|
1118
1368
|
if (binary !== null) {
|
|
1119
1369
|
this.binary = binary;
|
|
@@ -1145,7 +1395,7 @@ var CliClient = class extends ExternalAIClient {
|
|
|
1145
1395
|
*/
|
|
1146
1396
|
_recordCallQuietly() {
|
|
1147
1397
|
try {
|
|
1148
|
-
record_cli_call(this.name, this._cli_calls_path);
|
|
1398
|
+
record_cli_call(this.name, this._cli_calls_path, this._consumer);
|
|
1149
1399
|
} catch {
|
|
1150
1400
|
}
|
|
1151
1401
|
}
|
|
@@ -1283,7 +1533,10 @@ var CliClient = class extends ExternalAIClient {
|
|
|
1283
1533
|
metadata: {
|
|
1284
1534
|
cli: true,
|
|
1285
1535
|
cli_calls_used: used,
|
|
1286
|
-
cli_calls_max: this.max_calls_per_day
|
|
1536
|
+
cli_calls_max: this.max_calls_per_day,
|
|
1537
|
+
// Our counter refused before any spawn — nothing sent,
|
|
1538
|
+
// nothing booked for this call.
|
|
1539
|
+
quota_source: QUOTA_SOURCE_LOCAL_BUDGET
|
|
1287
1540
|
}
|
|
1288
1541
|
});
|
|
1289
1542
|
}
|
|
@@ -1360,7 +1613,12 @@ var CliClient = class extends ExternalAIClient {
|
|
|
1360
1613
|
metadata: {
|
|
1361
1614
|
cli: true,
|
|
1362
1615
|
returncode: proc.returncode,
|
|
1363
|
-
stderr_tail: (proc.stderr || "").slice(-500)
|
|
1616
|
+
stderr_tail: (proc.stderr || "").slice(-500),
|
|
1617
|
+
// The vendor refused us; the local-budget refusal above
|
|
1618
|
+
// returns before spawning. Opposite remedies, one error
|
|
1619
|
+
// string — so discriminate explicitly rather than leaving it
|
|
1620
|
+
// inferable from which metadata keys happen to be absent.
|
|
1621
|
+
...code === "cli_quota_exhausted" ? { quota_source: QUOTA_SOURCE_PROVIDER } : {}
|
|
1364
1622
|
}
|
|
1365
1623
|
});
|
|
1366
1624
|
}
|
|
@@ -2203,92 +2461,8 @@ function _excMessage(exc) {
|
|
|
2203
2461
|
}
|
|
2204
2462
|
return String(exc);
|
|
2205
2463
|
}
|
|
2206
|
-
function _jsonDumpsIndent2(value) {
|
|
2207
|
-
return _jsonDumpsIndented(value, 2, 0);
|
|
2208
|
-
}
|
|
2209
|
-
function _jsonDumpsIndented(value, indent, level) {
|
|
2210
|
-
if (value === null || value === void 0) {
|
|
2211
|
-
return "null";
|
|
2212
|
-
}
|
|
2213
|
-
switch (typeof value) {
|
|
2214
|
-
case "boolean":
|
|
2215
|
-
return value ? "true" : "false";
|
|
2216
|
-
case "number":
|
|
2217
|
-
return _pyJsonNumber2(value);
|
|
2218
|
-
case "string":
|
|
2219
|
-
return _pyJsonStringAscii(value);
|
|
2220
|
-
case "object":
|
|
2221
|
-
break;
|
|
2222
|
-
default:
|
|
2223
|
-
throw new TypeError(`Object of type ${typeof value} is not JSON serializable`);
|
|
2224
|
-
}
|
|
2225
|
-
const pad = " ".repeat(indent * (level + 1));
|
|
2226
|
-
const closePad = " ".repeat(indent * level);
|
|
2227
|
-
if (Array.isArray(value)) {
|
|
2228
|
-
if (value.length === 0) {
|
|
2229
|
-
return "[]";
|
|
2230
|
-
}
|
|
2231
|
-
const items2 = value.map((v) => pad + _jsonDumpsIndented(v, indent, level + 1));
|
|
2232
|
-
return `[
|
|
2233
|
-
${items2.join(",\n")}
|
|
2234
|
-
${closePad}]`;
|
|
2235
|
-
}
|
|
2236
|
-
const obj = value;
|
|
2237
|
-
const keys = Object.keys(obj);
|
|
2238
|
-
if (keys.length === 0) {
|
|
2239
|
-
return "{}";
|
|
2240
|
-
}
|
|
2241
|
-
const items = keys.map(
|
|
2242
|
-
(k) => `${pad}${_pyJsonStringAscii(k)}: ${_jsonDumpsIndented(obj[k], indent, level + 1)}`
|
|
2243
|
-
);
|
|
2244
|
-
return `{
|
|
2245
|
-
${items.join(",\n")}
|
|
2246
|
-
${closePad}}`;
|
|
2247
|
-
}
|
|
2248
|
-
function _pyJsonNumber2(n) {
|
|
2249
|
-
if (!Number.isFinite(n)) {
|
|
2250
|
-
if (Number.isNaN(n)) {
|
|
2251
|
-
return "NaN";
|
|
2252
|
-
}
|
|
2253
|
-
return n > 0 ? "Infinity" : "-Infinity";
|
|
2254
|
-
}
|
|
2255
|
-
return String(n);
|
|
2256
|
-
}
|
|
2257
|
-
function _pyJsonStringAscii(s) {
|
|
2258
|
-
let out = '"';
|
|
2259
|
-
for (const ch of s) {
|
|
2260
|
-
const code = ch.codePointAt(0) ?? 0;
|
|
2261
|
-
if (ch === '"') {
|
|
2262
|
-
out += '\\"';
|
|
2263
|
-
} else if (ch === "\\") {
|
|
2264
|
-
out += "\\\\";
|
|
2265
|
-
} else if (ch === "\b") {
|
|
2266
|
-
out += "\\b";
|
|
2267
|
-
} else if (ch === "\f") {
|
|
2268
|
-
out += "\\f";
|
|
2269
|
-
} else if (ch === "\n") {
|
|
2270
|
-
out += "\\n";
|
|
2271
|
-
} else if (ch === "\r") {
|
|
2272
|
-
out += "\\r";
|
|
2273
|
-
} else if (ch === " ") {
|
|
2274
|
-
out += "\\t";
|
|
2275
|
-
} else if (code < 32) {
|
|
2276
|
-
out += `\\u${code.toString(16).padStart(4, "0")}`;
|
|
2277
|
-
} else if (code < 127) {
|
|
2278
|
-
out += ch;
|
|
2279
|
-
} else if (code <= 65535) {
|
|
2280
|
-
out += `\\u${code.toString(16).padStart(4, "0")}`;
|
|
2281
|
-
} else {
|
|
2282
|
-
const c = code - 65536;
|
|
2283
|
-
const hi = 55296 + (c >> 10);
|
|
2284
|
-
const lo = 56320 + (c & 1023);
|
|
2285
|
-
out += `\\u${hi.toString(16).padStart(4, "0")}\\u${lo.toString(16).padStart(4, "0")}`;
|
|
2286
|
-
}
|
|
2287
|
-
}
|
|
2288
|
-
return out + '"';
|
|
2289
|
-
}
|
|
2290
2464
|
function _which(name) {
|
|
2291
|
-
if (name.includes(
|
|
2465
|
+
if (name.includes(path3.sep) || path3.sep !== "/" && name.includes("/")) {
|
|
2292
2466
|
return _isExecutable(name) ? name : null;
|
|
2293
2467
|
}
|
|
2294
2468
|
const pathEnv = process.env.PATH ?? "";
|
|
@@ -2296,12 +2470,12 @@ function _which(name) {
|
|
|
2296
2470
|
return null;
|
|
2297
2471
|
}
|
|
2298
2472
|
const exts = process.platform === "win32" ? (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
2299
|
-
for (const dir of pathEnv.split(
|
|
2473
|
+
for (const dir of pathEnv.split(path3.delimiter)) {
|
|
2300
2474
|
if (!dir) {
|
|
2301
2475
|
continue;
|
|
2302
2476
|
}
|
|
2303
2477
|
for (const ext of exts) {
|
|
2304
|
-
const candidate =
|
|
2478
|
+
const candidate = path3.join(dir, name + ext);
|
|
2305
2479
|
if (_isExecutable(candidate)) {
|
|
2306
2480
|
return candidate;
|
|
2307
2481
|
}
|
|
@@ -2311,7 +2485,7 @@ function _which(name) {
|
|
|
2311
2485
|
}
|
|
2312
2486
|
function _isExecutable(p) {
|
|
2313
2487
|
try {
|
|
2314
|
-
const st =
|
|
2488
|
+
const st = fs3.statSync(p);
|
|
2315
2489
|
if (!st.isFile()) {
|
|
2316
2490
|
return false;
|
|
2317
2491
|
}
|
|
@@ -2338,7 +2512,7 @@ function _defaultStdin() {
|
|
|
2338
2512
|
function ensure() {
|
|
2339
2513
|
if (buffer === null) {
|
|
2340
2514
|
try {
|
|
2341
|
-
buffer =
|
|
2515
|
+
buffer = fs3.readFileSync(0, { encoding: "utf-8" });
|
|
2342
2516
|
} catch {
|
|
2343
2517
|
buffer = "";
|
|
2344
2518
|
}
|
|
@@ -2385,16 +2559,18 @@ __export(config_exports, {
|
|
|
2385
2559
|
COUNCIL_CONFIG_RELNAME: () => COUNCIL_CONFIG_RELNAME,
|
|
2386
2560
|
COUNCIL_CONFIG_USER_GLOBAL_REL: () => COUNCIL_CONFIG_USER_GLOBAL_REL,
|
|
2387
2561
|
CouncilConfigError: () => CouncilConfigError,
|
|
2562
|
+
DEFAULT_CLI_CALLS_PER_DAY: () => DEFAULT_CLI_CALLS_PER_DAY2,
|
|
2388
2563
|
_RAW_KEY_PREFIXES: () => _RAW_KEY_PREFIXES,
|
|
2389
2564
|
_build_config: () => _build_config,
|
|
2390
2565
|
load_council_config: () => load_council_config,
|
|
2391
2566
|
resolve_api_key: () => resolve_api_key,
|
|
2567
|
+
resolve_cli_call_caps: () => resolve_cli_call_caps,
|
|
2392
2568
|
resolve_config_path: () => resolve_config_path
|
|
2393
2569
|
});
|
|
2394
2570
|
var import_yaml = __toESM(require_dist(), 1);
|
|
2395
|
-
import * as
|
|
2571
|
+
import * as fs4 from "node:fs";
|
|
2396
2572
|
import * as os2 from "node:os";
|
|
2397
|
-
import * as
|
|
2573
|
+
import * as path4 from "node:path";
|
|
2398
2574
|
var _VALID_PROVIDERS = /* @__PURE__ */ new Set([
|
|
2399
2575
|
"anthropic",
|
|
2400
2576
|
"openai",
|
|
@@ -2608,7 +2784,7 @@ function _expanduser(p) {
|
|
|
2608
2784
|
return os2.homedir();
|
|
2609
2785
|
}
|
|
2610
2786
|
if (p.startsWith("~/") || process.platform === "win32" && p.startsWith("~\\")) {
|
|
2611
|
-
return
|
|
2787
|
+
return path4.join(os2.homedir(), p.slice(2));
|
|
2612
2788
|
}
|
|
2613
2789
|
return p;
|
|
2614
2790
|
}
|
|
@@ -2637,14 +2813,14 @@ function resolve_config_path(project_root, options = {}) {
|
|
|
2637
2813
|
});
|
|
2638
2814
|
}
|
|
2639
2815
|
function load_council_config(p) {
|
|
2640
|
-
if (!
|
|
2816
|
+
if (!fs4.existsSync(p)) {
|
|
2641
2817
|
throw new CouncilConfigError(
|
|
2642
2818
|
`Council config not found at ${p}. Create it per docs/contracts/ai-council-config.md.`
|
|
2643
2819
|
);
|
|
2644
2820
|
}
|
|
2645
2821
|
let raw;
|
|
2646
2822
|
try {
|
|
2647
|
-
const text =
|
|
2823
|
+
const text = fs4.readFileSync(p, "utf-8");
|
|
2648
2824
|
const parsed = (0, import_yaml.parse)(text, { version: "1.1" });
|
|
2649
2825
|
raw = parsed === null || parsed === void 0 ? {} : parsed;
|
|
2650
2826
|
} catch (exc) {
|
|
@@ -3541,7 +3717,10 @@ function _build_member(name, cfg, default_mode = "auto", ignored = []) {
|
|
|
3541
3717
|
prompt_cache_ttl
|
|
3542
3718
|
};
|
|
3543
3719
|
}
|
|
3544
|
-
var
|
|
3720
|
+
var DEFAULT_CLI_CALLS_PER_DAY2 = DEFAULT_CLI_CALLS_PER_DAY;
|
|
3721
|
+
function resolve_cli_call_caps(raw) {
|
|
3722
|
+
return resolveCliCallCaps(raw, _VALID_PROVIDERS);
|
|
3723
|
+
}
|
|
3545
3724
|
function _build_cli_call_budget(d) {
|
|
3546
3725
|
if (!_isDict(d)) {
|
|
3547
3726
|
throw new CouncilConfigError("`cli_call_budget` must be a mapping.");
|
|
@@ -3552,10 +3731,6 @@ function _build_cli_call_budget(d) {
|
|
|
3552
3731
|
"`cli_call_budget.max_calls_per_day` must be a mapping."
|
|
3553
3732
|
);
|
|
3554
3733
|
}
|
|
3555
|
-
const caps = /* @__PURE__ */ new Map();
|
|
3556
|
-
for (const provider of _VALID_PROVIDERS) {
|
|
3557
|
-
caps.set(provider, _DEFAULT_CLI_CALLS_PER_DAY);
|
|
3558
|
-
}
|
|
3559
3734
|
for (const [provider, value] of Object.entries(raw_caps)) {
|
|
3560
3735
|
if (!_VALID_PROVIDERS.has(provider)) {
|
|
3561
3736
|
throw new CouncilConfigError(
|
|
@@ -3567,8 +3742,10 @@ function _build_cli_call_budget(d) {
|
|
|
3567
3742
|
`cli_call_budget.max_calls_per_day.${provider} must be a non-negative integer (got ${_pyRepr3(value)}).`
|
|
3568
3743
|
);
|
|
3569
3744
|
}
|
|
3570
|
-
caps.set(provider, value);
|
|
3571
3745
|
}
|
|
3746
|
+
const caps = new Map(
|
|
3747
|
+
Object.entries(resolve_cli_call_caps(raw_caps))
|
|
3748
|
+
);
|
|
3572
3749
|
const warn_at_raw = _get(d, "warn_at", 0.8);
|
|
3573
3750
|
if (_isBool(warn_at_raw) || !_isNumber(warn_at_raw)) {
|
|
3574
3751
|
throw new CouncilConfigError(
|
|
@@ -3686,16 +3863,16 @@ function resolve_api_key(ref, scope = "api_key_ref") {
|
|
|
3686
3863
|
}
|
|
3687
3864
|
resolved = found;
|
|
3688
3865
|
}
|
|
3689
|
-
if (!
|
|
3866
|
+
if (!fs4.existsSync(resolved)) {
|
|
3690
3867
|
throw new CouncilConfigError(`${scope}: key file does not exist at ${resolved}.`);
|
|
3691
3868
|
}
|
|
3692
|
-
const mode =
|
|
3869
|
+
const mode = fs4.statSync(resolved).mode & 4095;
|
|
3693
3870
|
if (mode !== 384) {
|
|
3694
3871
|
throw new CouncilConfigError(
|
|
3695
3872
|
`${scope}: unsafe permissions on ${resolved}: got ${_pyOct(mode)}, expected 0o600. Fix: chmod 600 ${resolved}`
|
|
3696
3873
|
);
|
|
3697
3874
|
}
|
|
3698
|
-
const value =
|
|
3875
|
+
const value = fs4.readFileSync(resolved, "utf-8").trim();
|
|
3699
3876
|
if (value === "") {
|
|
3700
3877
|
throw new CouncilConfigError(`${scope}: key file at ${resolved} is empty.`);
|
|
3701
3878
|
}
|
|
@@ -3724,10 +3901,10 @@ function _pyTruthy2(value) {
|
|
|
3724
3901
|
}
|
|
3725
3902
|
|
|
3726
3903
|
// src/scripts/_lib/cc_transcript.ts
|
|
3727
|
-
import * as
|
|
3728
|
-
import * as
|
|
3904
|
+
import * as fs5 from "node:fs";
|
|
3905
|
+
import * as path5 from "node:path";
|
|
3729
3906
|
import { homedir as homedir2 } from "node:os";
|
|
3730
|
-
var DEFAULT_PROJECTS_ROOT =
|
|
3907
|
+
var DEFAULT_PROJECTS_ROOT = path5.join(homedir2(), ".claude", "projects");
|
|
3731
3908
|
function projectStoreSlug(cwd) {
|
|
3732
3909
|
return cwd.replace(/[^A-Za-z0-9-]/g, "-");
|
|
3733
3910
|
}
|
|
@@ -3772,8 +3949,8 @@ function parseLine(line) {
|
|
|
3772
3949
|
}
|
|
3773
3950
|
function listTranscriptFiles(opts = {}) {
|
|
3774
3951
|
const root = opts.root ?? DEFAULT_PROJECTS_ROOT;
|
|
3775
|
-
const base = opts.projectDir ?
|
|
3776
|
-
if (!
|
|
3952
|
+
const base = opts.projectDir ? path5.isAbsolute(opts.projectDir) ? opts.projectDir : path5.join(root, opts.projectDir) : root;
|
|
3953
|
+
if (!fs5.existsSync(base)) return [];
|
|
3777
3954
|
const cutoffMs = opts.maxAgeDays !== void 0 ? (opts.now ?? /* @__PURE__ */ new Date()).getTime() - opts.maxAgeDays * 24 * 60 * 60 * 1e3 : null;
|
|
3778
3955
|
const out = [];
|
|
3779
3956
|
const stack = [base];
|
|
@@ -3781,12 +3958,12 @@ function listTranscriptFiles(opts = {}) {
|
|
|
3781
3958
|
const dir = stack.pop();
|
|
3782
3959
|
let entries;
|
|
3783
3960
|
try {
|
|
3784
|
-
entries =
|
|
3961
|
+
entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
3785
3962
|
} catch {
|
|
3786
3963
|
continue;
|
|
3787
3964
|
}
|
|
3788
3965
|
for (const entry of entries) {
|
|
3789
|
-
const full =
|
|
3966
|
+
const full = path5.join(dir, entry.name);
|
|
3790
3967
|
if (entry.isDirectory()) {
|
|
3791
3968
|
stack.push(full);
|
|
3792
3969
|
continue;
|
|
@@ -3795,7 +3972,7 @@ function listTranscriptFiles(opts = {}) {
|
|
|
3795
3972
|
if (cutoffMs !== null) {
|
|
3796
3973
|
let mtimeMs;
|
|
3797
3974
|
try {
|
|
3798
|
-
mtimeMs =
|
|
3975
|
+
mtimeMs = fs5.statSync(full).mtimeMs;
|
|
3799
3976
|
} catch {
|
|
3800
3977
|
continue;
|
|
3801
3978
|
}
|
|
@@ -3814,7 +3991,7 @@ function scanTranscripts(opts = {}) {
|
|
|
3814
3991
|
for (const file of files) {
|
|
3815
3992
|
let text;
|
|
3816
3993
|
try {
|
|
3817
|
-
text =
|
|
3994
|
+
text = fs5.readFileSync(file, "utf-8");
|
|
3818
3995
|
} catch {
|
|
3819
3996
|
continue;
|
|
3820
3997
|
}
|