@event4u/agent-config 14.20.0 → 14.22.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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +441 -0
- package/CREDITS.md +37 -0
- package/README.md +1 -1
- package/agents/templates/.ai-council.yml.example +10 -0
- package/dist/agent-src/commands/analyze/inbox.md +381 -6
- package/dist/agent-src/commands/analyze/{reference-repo.md → repo.md} +251 -34
- package/dist/agent-src/commands/analyze/roadmap-repos.md +129 -0
- package/dist/agent-src/commands/analyze.md +12 -7
- package/dist/agent-src/commands/feature/plan.md +55 -16
- package/dist/agent-src/commands/feature/refactor.md +8 -3
- package/dist/agent-src/commands/humanize.md +48 -4
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +69 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -5
- package/dist/agent-src/contexts/execution/contract-decision-sheet.md +22 -1
- package/dist/agent-src/contexts/execution/host-capability-manifest.md +4 -1
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +35 -2
- package/dist/agent-src/contexts/execution/terminal-states.md +4 -1
- package/dist/agent-src/rules/evaluator-independence.md +4 -4
- package/dist/agent-src/rules/external-code-graph-interop.md +19 -14
- package/dist/agent-src/rules/external-reference-deep-dive.md +2 -2
- package/dist/agent-src/rules/token-efficiency.md +26 -3
- package/dist/agent-src/scripts/_cli_entry.ts +51 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +14 -23
- package/dist/agent-src/scripts/roadmap_gates.ts +4 -20
- package/dist/agent-src/scripts/roadmap_set_step.ts +5 -2
- package/dist/agent-src/scripts/stubs_due.ts +4 -18
- package/dist/agent-src/scripts/update_roadmap_progress.ts +7 -24
- package/dist/agent-src/skills/code-intelligence/SKILL.md +25 -0
- package/dist/agent-src/skills/competitive-positioning/SKILL.md +2 -2
- package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +27 -11
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +1 -1
- package/dist/agent-src/skills/markitdown/SKILL.md +1 -1
- package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +17 -0
- package/dist/agent-src/skills/technical-specification/SKILL.md +4 -0
- package/dist/agent-src/templates/agent-settings.md +0 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/features.md +5 -0
- package/dist/agent-src/templates/roadmaps.md +15 -0
- package/dist/cli-delegate/_cli_entry.js +8 -0
- package/dist/cli-delegate/_lib/pin_resolver.js +170 -0
- package/dist/cli-delegate/archival_sweep.js +8 -0
- package/dist/cli-delegate/archive_completed_roadmaps.js +494 -0
- package/dist/cli-delegate/check_update_banner.js +923 -0
- package/dist/cli-delegate/{chunk-KPBWFOPZ.js → chunk-2FTMENJL.js} +194 -37
- package/dist/cli-delegate/{chunk-PI2GU3DP.js → chunk-2TAQ2K4V.js} +4 -1
- package/dist/cli-delegate/chunk-5EK5WQN6.js +28 -0
- package/dist/cli-delegate/chunk-7XGD2OEU.js +96 -0
- package/dist/cli-delegate/{chunk-C6IPZRDA.js → chunk-BIXEDQPZ.js} +7 -1
- package/dist/cli-delegate/chunk-DBH4AHDK.js +155 -0
- package/dist/cli-delegate/{chunk-NUMQHLS5.js → chunk-J3RFNKG4.js} +21 -2
- package/dist/cli-delegate/chunk-JO25G5H7.js +20 -0
- package/dist/cli-delegate/chunk-LTYVIY76.js +7961 -0
- package/dist/cli-delegate/chunk-QAJS5YWY.js +999 -0
- package/dist/cli-delegate/{chunk-ZVBOHSVF.js → chunk-TGIPZBCW.js} +1 -1
- package/dist/cli-delegate/{chunk-YS6XTLEK.js → chunk-TYSY33MD.js} +56 -6
- package/dist/cli-delegate/chunk-ULET4BYS.js +328 -0
- package/dist/cli-delegate/chunk-YDQSHTD7.js +187 -0
- package/dist/cli-delegate/chunk-YWVXLR44.js +48 -0
- package/dist/cli-delegate/chunk-ZZQBUHFK.js +273 -0
- package/dist/cli-delegate/cmd_conformance.js +19 -5
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +27 -3
- package/dist/cli-delegate/cmd_prune.js +2 -2
- package/dist/cli-delegate/cmd_session_recycle.js +2 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
- package/dist/cli-delegate/cmd_sync.js +2 -2
- package/dist/cli-delegate/cmd_uninstall.js +2 -2
- package/dist/cli-delegate/cmd_validate.js +2 -2
- package/dist/cli-delegate/dashboard_mode.js +16 -0
- package/dist/cli-delegate/gate_budget.js +24 -0
- package/dist/cli-delegate/gate_execute.js +25 -0
- package/dist/cli-delegate/guarded_baseline.js +18 -0
- package/dist/cli-delegate/resume_probe.js +22 -0
- package/dist/cli-delegate/roadmap_gates.js +638 -0
- package/dist/cli-delegate/roadmap_set_step.js +173 -0
- package/dist/cli-delegate/stub_queue.js +47 -0
- package/dist/cli-delegate/stubs_due.js +38 -0
- package/dist/cli-delegate/ticket_bundles.js +59 -0
- package/dist/cli-delegate/update_roadmap_progress.js +60 -0
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +60 -29
- 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 +7 -6
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -5
- package/dist/hooks/dispatch.js +1522 -1008
- package/dist/install/claudeLayerCarriage.js +237 -0
- package/dist/install/claudePathsPlan.js +79 -0
- package/dist/install/hostLayerFingerprint.js +1 -1
- package/dist/install/install.mjs +10 -1
- package/dist/install/partitionEligibility.js +231 -117
- package/dist/install/ruleLayerPartition.js +10 -7
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +39376 -38902
- package/dist/scripts/ai_council/content_ceiling.js +63 -0
- package/dist/scripts/ai_council/seat_policy.js +106 -0
- package/dist/scripts/ai_council/transport_resolver.js +21 -0
- package/dist/scripts/condense.js +32 -25
- package/docs/MIGRATION.md +49 -1
- package/docs/contracts/settings-classes.md +1 -1
- package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +73 -0
- package/llms.txt +14 -14
- package/package.json +7 -4
- package/src/agent-src/scripts/_cli_entry.ts +51 -0
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +14 -23
- package/src/agent-src/scripts/roadmap_gates.ts +4 -20
- package/src/agent-src/scripts/roadmap_set_step.ts +5 -2
- package/src/agent-src/scripts/stubs_due.ts +4 -18
- package/src/agent-src/scripts/update_roadmap_progress.ts +7 -24
- package/src/config/continuity-surface.json +509 -0
- package/src/config/estate-count-budget.json +1 -1
- package/src/config/gate-coverage.yml +29 -8
- package/src/config/gate-violation-baselines.json +8 -8
- package/src/config/gitignore-block.txt +19 -0
- package/src/config/host-injection-effect.json +73 -0
- package/src/config/packed-binary-manifest.json +33 -0
- package/src/config/preamble-payload-budget.json +112 -105
- package/src/config/publish-surface.json +4 -2
- package/src/config/release-gate-locality.yml +4 -3
- package/src/install/claudeLayerCarriage.ts +273 -0
- package/src/install/claudePathsPlan.ts +76 -0
- package/src/install/hostLayerFingerprint.ts +1 -1
- package/src/install/partitionEligibility.ts +261 -127
- package/src/install/ruleLayerPartition.ts +19 -23
- package/src/scripts/_dispatch.bash +77 -27
- package/src/scripts/_lib/auto_dispatch.ts +2 -2
- package/src/scripts/_lib/blocked_by_marker.ts +189 -0
- package/src/scripts/_lib/catalogue_layer_parity.ts +146 -0
- package/src/scripts/_lib/continuity_surface.ts +296 -0
- package/src/scripts/_lib/corpus_manifest.ts +26 -9
- package/src/scripts/_lib/hook_settings.ts +1 -1
- package/src/scripts/_lib/host_capability.ts +38 -1
- package/src/scripts/_lib/injection_effect.ts +151 -0
- package/src/scripts/_lib/layer_overlap_notice.ts +50 -6
- package/src/scripts/_lib/packed_binary_predicate.ts +225 -0
- package/src/scripts/_lib/pin_resolver.ts +13 -0
- package/src/scripts/_lib/regression_neighbourhood.ts +1 -1
- package/src/scripts/_lib/release_highlights.ts +19 -211
- package/src/scripts/_lib/release_material.ts +27 -77
- package/src/scripts/_lib/retired_status.ts +74 -0
- package/src/scripts/_lib/skill_catalogue.ts +156 -21
- package/src/scripts/_lib/structured_ask.ts +117 -0
- package/src/scripts/_lib/subagent_capsule.ts +117 -8
- package/src/scripts/_lib/tty_prompt.ts +76 -0
- package/src/scripts/ai_council/api_transport.ts +168 -0
- package/src/scripts/ai_council/clients.ts +58 -63
- package/src/scripts/ai_council/config.ts +13 -0
- package/src/scripts/ai_council/content_ceiling.ts +79 -0
- package/src/scripts/ai_council/deliberation_metrics.ts +353 -0
- package/src/scripts/ai_council/jury_aggregate.ts +178 -0
- package/src/scripts/ai_council/prompts.ts +9 -0
- package/src/scripts/ai_council/seat_policy.ts +137 -0
- package/src/scripts/ai_council/status_surface.ts +79 -0
- package/src/scripts/ai_council/synthesis_disagreement.ts +206 -0
- package/src/scripts/ai_council/transport_resolver.ts +59 -1
- package/src/scripts/ai_tells_rules.ts +446 -5
- package/src/scripts/ask_block_census.ts +499 -0
- package/src/scripts/bench_humanizer_eval.ts +264 -40
- package/src/scripts/bench_prose_tells_fp.ts +198 -0
- package/src/scripts/capture_skill_catalogue.ts +24 -11
- package/src/scripts/check_branch_work_committed.ts +234 -0
- package/src/scripts/check_candidate_lines.ts +499 -0
- package/src/scripts/check_continuity_surface.ts +475 -0
- package/src/scripts/check_dependency_floors.ts +13 -6
- package/src/scripts/check_estate_count.ts +40 -79
- package/src/scripts/check_pack_size.ts +263 -24
- package/src/scripts/check_release_highlights.ts +0 -157
- package/src/scripts/check_roadmap_trackable.ts +19 -16
- package/src/scripts/check_rule_layer_partition.ts +54 -34
- package/src/scripts/check_single_delivery.ts +97 -31
- package/src/scripts/check_update_banner.ts +13 -0
- package/src/scripts/code_graph/build.ts +138 -15
- package/src/scripts/code_graph/cli.ts +76 -8
- package/src/scripts/code_graph/extract.ts +11 -0
- package/src/scripts/code_graph/grammar_probe.ts +43 -0
- package/src/scripts/code_graph/loader.ts +88 -14
- package/src/scripts/code_graph/query.ts +121 -11
- package/src/scripts/code_graph/resolution_tiers.ts +238 -0
- package/src/scripts/code_graph/sqlite_store.ts +247 -6
- package/src/scripts/code_graph/types.ts +66 -1
- package/src/scripts/code_graph/validate.ts +23 -0
- package/src/scripts/condense.ts +34 -22
- package/src/scripts/corpus_manifest.ts +5 -5
- package/src/scripts/council_cli.ts +29 -39
- package/src/scripts/count_intent_disagreement.ts +426 -0
- package/src/scripts/detect_ai_tells.ts +142 -20
- package/src/scripts/handoff_context_hook.ts +79 -0
- package/src/scripts/harvest_reference_tokens.ts +698 -0
- package/src/scripts/hook_effect_doctor.ts +82 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +94 -12
- package/src/scripts/hooks/chain_nudge_hook.ts +282 -0
- package/src/scripts/hooks/code_graph_context_hook.ts +212 -0
- package/src/scripts/hooks/concern_registry.ts +6 -2
- package/src/scripts/hooks/delegation_nudge_hook.ts +45 -1
- package/src/scripts/hooks/host_semantics.ts +1 -1
- package/src/scripts/hooks/one_question_per_ask_hook.ts +191 -0
- package/src/scripts/hooks/orchestration_record_hook.ts +2 -2
- package/src/scripts/hooks/rule_inject_hook.ts +1 -1
- package/src/scripts/hooks/skill_route_hook.ts +11 -4
- package/src/scripts/inbox_source_census.ts +322 -0
- package/src/scripts/install-hooks.sh +134 -0
- package/src/scripts/{lint_carrier_integrity.ts → lint_deferral_integrity.ts} +60 -214
- package/src/scripts/lint_plan_risk_register.ts +13 -17
- package/src/scripts/lint_roadmap_blockers.ts +51 -1
- package/src/scripts/mcp_server/suggest_skill.ts +72 -0
- package/src/scripts/mcp_server/tools.ts +2 -56
- package/src/scripts/media/lib/adapter-contract.md +7 -2
- package/src/scripts/media/lib/fixtures/flux/asset-0001.png +0 -0
- package/src/scripts/media/lib/fixtures/gemini-image/asset-0001.png +0 -0
- package/src/scripts/media/lib/fixtures/ideogram/asset-0001.png +0 -0
- package/src/scripts/migrate_command_suggestions.ts +1 -1
- package/src/scripts/probe_unblocked_ask.ts +135 -2
- package/src/scripts/rdp_candidates_delta.ts +276 -0
- package/src/scripts/rdp_quality_eval.ts +217 -19
- package/src/scripts/release.ts +26 -71
- package/src/scripts/release_drill.ts +6 -10
- package/src/scripts/release_env.ts +1 -0
- package/src/scripts/release_mix_taxonomy.json +3 -2
- package/src/scripts/release_publication.ts +34 -29
- package/src/scripts/report_host_injection_effect.ts +189 -0
- package/src/scripts/report_layer_overlap.ts +41 -0
- package/src/scripts/report_skill_menu_census.ts +341 -0
- package/src/scripts/self_review_gate.ts +409 -15
- package/src/scripts/skill_tools/score_skill_relevance.ts +70 -6
- package/src/scripts/skill_tools/suggest_skill_for_task.ts +37 -3
- package/src/vendor/grammars/README.md +61 -0
- package/src/vendor/grammars/tree-sitter-javascript.wasm +0 -0
- package/src/vendor/grammars/tree-sitter-php.wasm +0 -0
- package/src/vendor/grammars/tree-sitter-typescript.wasm +0 -0
- package/src/scripts/_lib/carrier_status.ts +0 -118
- package/src/scripts/_lib/estate_carrier_cases.ts +0 -72
- package/src/scripts/hooks/code_graph_nudge_hook.ts +0 -191
|
@@ -81,7 +81,7 @@ __export(clients_exports, {
|
|
|
81
81
|
record_cli_call: () => record_cli_call,
|
|
82
82
|
reset_cli_call_counts: () => reset_cli_call_counts
|
|
83
83
|
});
|
|
84
|
-
import { spawnSync } from "node:child_process";
|
|
84
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
85
85
|
import * as fs3 from "node:fs";
|
|
86
86
|
import * as os from "node:os";
|
|
87
87
|
import * as path3 from "node:path";
|
|
@@ -205,6 +205,88 @@ function boundFor(member) {
|
|
|
205
205
|
return AGENCY_BOUNDS.find((b) => b.member === member)?.bound ?? [];
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
// src/scripts/ai_council/api_transport.ts
|
|
209
|
+
import { spawnSync } from "node:child_process";
|
|
210
|
+
var GEMINI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
|
|
211
|
+
function curlJsonPost(url, extraHeaders, body) {
|
|
212
|
+
const args = ["-sS", "-X", "POST", url, "-H", "content-type: application/json"];
|
|
213
|
+
for (const h of extraHeaders) {
|
|
214
|
+
args.push("-H", h);
|
|
215
|
+
}
|
|
216
|
+
args.push("--connect-timeout", "30", "--max-time", "290");
|
|
217
|
+
args.push("-w", "\n%{http_code}", "--data-binary", "@-");
|
|
218
|
+
const r = spawnSync("curl", args, {
|
|
219
|
+
input: JSON.stringify(body),
|
|
220
|
+
encoding: "utf8",
|
|
221
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
222
|
+
timeout: 3e5
|
|
223
|
+
});
|
|
224
|
+
if (r.error) {
|
|
225
|
+
throw new Error(`curl spawn failed: ${r.error.message}`);
|
|
226
|
+
}
|
|
227
|
+
if (r.status !== 0) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`curl exited ${r.status ?? "null"}: ${(r.stderr ?? "").toString().slice(0, 500)}`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
const out = (r.stdout ?? "").toString();
|
|
233
|
+
const nl = out.lastIndexOf("\n");
|
|
234
|
+
const httpCode = (nl >= 0 ? out.slice(nl + 1) : out).trim();
|
|
235
|
+
const bodyText = nl >= 0 ? out.slice(0, nl) : out;
|
|
236
|
+
if (!/^2\d\d$/.test(httpCode)) {
|
|
237
|
+
throw new Error(`HTTP ${httpCode}: ${bodyText.slice(0, 500)}`);
|
|
238
|
+
}
|
|
239
|
+
return JSON.parse(bodyText);
|
|
240
|
+
}
|
|
241
|
+
function openAiCompatibleClient(baseUrl, apiKey, post = curlJsonPost) {
|
|
242
|
+
const url = `${baseUrl.replace(/\/+$/, "")}/chat/completions`;
|
|
243
|
+
return {
|
|
244
|
+
chat: {
|
|
245
|
+
completions: {
|
|
246
|
+
create: (kwargs) => post(url, [`authorization: Bearer ${apiKey}`], kwargs)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
function geminiRestClient(apiKey, post = curlJsonPost, baseUrl = GEMINI_BASE_URL) {
|
|
252
|
+
return {
|
|
253
|
+
models: {
|
|
254
|
+
generate_content: (kwargs) => {
|
|
255
|
+
const model = String(kwargs["model"] ?? "");
|
|
256
|
+
const cfg = kwargs["config"] ?? {};
|
|
257
|
+
const url = `${baseUrl.replace(/\/+$/, "")}/models/${model}:generateContent`;
|
|
258
|
+
const raw = post(
|
|
259
|
+
url,
|
|
260
|
+
[`x-goog-api-key: ${apiKey}`],
|
|
261
|
+
{
|
|
262
|
+
contents: [{ role: "user", parts: [{ text: String(kwargs["contents"] ?? "") }] }],
|
|
263
|
+
generationConfig: { maxOutputTokens: cfg["max_output_tokens"] ?? null }
|
|
264
|
+
}
|
|
265
|
+
);
|
|
266
|
+
return normaliseGeminiRest(raw);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function normaliseGeminiRest(raw) {
|
|
272
|
+
const env = raw ?? {};
|
|
273
|
+
const candidates = Array.isArray(env["candidates"]) ? env["candidates"] : [];
|
|
274
|
+
const first = candidates[0] ?? {};
|
|
275
|
+
const content = first["content"] ?? {};
|
|
276
|
+
const parts = Array.isArray(content["parts"]) ? content["parts"] : [];
|
|
277
|
+
const text = parts.map((p) => String((p ?? {})["text"] ?? "")).join("");
|
|
278
|
+
const usage = env["usageMetadata"] ?? {};
|
|
279
|
+
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
280
|
+
return {
|
|
281
|
+
text,
|
|
282
|
+
model_version: String(env["modelVersion"] ?? ""),
|
|
283
|
+
usage_metadata: {
|
|
284
|
+
prompt_token_count: num(usage["promptTokenCount"]),
|
|
285
|
+
candidates_token_count: num(usage["candidatesTokenCount"])
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
208
290
|
// src/scripts/_lib/session_role.ts
|
|
209
291
|
var SESSION_ROLE_ENV = "AGENT_CONFIG_SESSION_ROLE";
|
|
210
292
|
var KNOWN_ROLES = /* @__PURE__ */ new Set(["orchestrator", "worker", "reviewer"]);
|
|
@@ -899,34 +981,6 @@ var ExternalAIClient = class {
|
|
|
899
981
|
return this.ask(system_prompt, user_prompt, max_tokens);
|
|
900
982
|
}
|
|
901
983
|
};
|
|
902
|
-
function _curlJsonPost(url, extraHeaders, body) {
|
|
903
|
-
const args = ["-sS", "-X", "POST", url, "-H", "content-type: application/json"];
|
|
904
|
-
for (const h of extraHeaders) {
|
|
905
|
-
args.push("-H", h);
|
|
906
|
-
}
|
|
907
|
-
args.push("--connect-timeout", "30", "--max-time", "290");
|
|
908
|
-
args.push("-w", "\n%{http_code}", "--data-binary", "@-");
|
|
909
|
-
const r = spawnSync("curl", args, {
|
|
910
|
-
input: JSON.stringify(body),
|
|
911
|
-
encoding: "utf8",
|
|
912
|
-
maxBuffer: 64 * 1024 * 1024,
|
|
913
|
-
timeout: 3e5
|
|
914
|
-
});
|
|
915
|
-
if (r.error) {
|
|
916
|
-
throw new Error(`curl spawn failed: ${r.error.message}`);
|
|
917
|
-
}
|
|
918
|
-
if (r.status !== 0) {
|
|
919
|
-
throw new Error(`curl exited ${r.status ?? "null"}: ${(r.stderr ?? "").toString().slice(0, 500)}`);
|
|
920
|
-
}
|
|
921
|
-
const out = (r.stdout ?? "").toString();
|
|
922
|
-
const nl = out.lastIndexOf("\n");
|
|
923
|
-
const httpCode = (nl >= 0 ? out.slice(nl + 1) : out).trim();
|
|
924
|
-
const bodyText = nl >= 0 ? out.slice(0, nl) : out;
|
|
925
|
-
if (!/^2\d\d$/.test(httpCode)) {
|
|
926
|
-
throw new Error(`HTTP ${httpCode}: ${bodyText.slice(0, 500)}`);
|
|
927
|
-
}
|
|
928
|
-
return JSON.parse(bodyText);
|
|
929
|
-
}
|
|
930
984
|
var AnthropicClient = class extends ExternalAIClient {
|
|
931
985
|
name = "anthropic";
|
|
932
986
|
billable = true;
|
|
@@ -957,7 +1011,7 @@ var AnthropicClient = class extends ExternalAIClient {
|
|
|
957
1011
|
}
|
|
958
1012
|
this._client = {
|
|
959
1013
|
messages: {
|
|
960
|
-
create: (kwargs) =>
|
|
1014
|
+
create: (kwargs) => curlJsonPost(
|
|
961
1015
|
"https://api.anthropic.com/v1/messages",
|
|
962
1016
|
[`x-api-key: ${api_key}`, "anthropic-version: 2023-06-01"],
|
|
963
1017
|
kwargs
|
|
@@ -1081,7 +1135,7 @@ var OpenAIClient = class extends ExternalAIClient {
|
|
|
1081
1135
|
this._client = {
|
|
1082
1136
|
chat: {
|
|
1083
1137
|
completions: {
|
|
1084
|
-
create: (kwargs) =>
|
|
1138
|
+
create: (kwargs) => curlJsonPost(
|
|
1085
1139
|
"https://api.openai.com/v1/chat/completions",
|
|
1086
1140
|
[`authorization: Bearer ${api_key}`],
|
|
1087
1141
|
kwargs
|
|
@@ -1164,7 +1218,7 @@ var GeminiClient = class extends ExternalAIClient {
|
|
|
1164
1218
|
"GeminiClient requires explicit api_key or injected client. Use `api_key_ref: env:GEMINI_API_KEY` in ~/.event4u/agent-config/settings/.ai-council.yml."
|
|
1165
1219
|
);
|
|
1166
1220
|
}
|
|
1167
|
-
|
|
1221
|
+
this._client = geminiRestClient(api_key, opts.transport ?? curlJsonPost);
|
|
1168
1222
|
}
|
|
1169
1223
|
ask(system_prompt, user_prompt, max_tokens = DEFAULT_MAX_TOKENS) {
|
|
1170
1224
|
const t0 = _nowMs();
|
|
@@ -1226,7 +1280,11 @@ var _OpenAICompatibleClient = class extends ExternalAIClient {
|
|
|
1226
1280
|
`${this.constructor.name} requires explicit api_key or injected client.`
|
|
1227
1281
|
);
|
|
1228
1282
|
}
|
|
1229
|
-
|
|
1283
|
+
this._client = openAiCompatibleClient(
|
|
1284
|
+
opts.base_url,
|
|
1285
|
+
api_key,
|
|
1286
|
+
opts.transport ?? curlJsonPost
|
|
1287
|
+
);
|
|
1230
1288
|
}
|
|
1231
1289
|
ask(system_prompt, user_prompt, max_tokens = DEFAULT_MAX_TOKENS) {
|
|
1232
1290
|
const t0 = _nowMs();
|
|
@@ -1279,7 +1337,13 @@ var XAIClient = class extends _OpenAICompatibleClient {
|
|
|
1279
1337
|
name = "xai";
|
|
1280
1338
|
base_url = XAI_BASE_URL;
|
|
1281
1339
|
constructor(opts = {}) {
|
|
1282
|
-
super({
|
|
1340
|
+
super({
|
|
1341
|
+
model: opts.model ?? DEFAULT_XAI_MODEL,
|
|
1342
|
+
client: opts.client,
|
|
1343
|
+
api_key: opts.api_key,
|
|
1344
|
+
transport: opts.transport,
|
|
1345
|
+
base_url: XAI_BASE_URL
|
|
1346
|
+
});
|
|
1283
1347
|
}
|
|
1284
1348
|
};
|
|
1285
1349
|
var PerplexityClient = class extends _OpenAICompatibleClient {
|
|
@@ -1289,7 +1353,9 @@ var PerplexityClient = class extends _OpenAICompatibleClient {
|
|
|
1289
1353
|
super({
|
|
1290
1354
|
model: opts.model ?? DEFAULT_PERPLEXITY_MODEL,
|
|
1291
1355
|
client: opts.client,
|
|
1292
|
-
api_key: opts.api_key
|
|
1356
|
+
api_key: opts.api_key,
|
|
1357
|
+
transport: opts.transport,
|
|
1358
|
+
base_url: PERPLEXITY_BASE_URL
|
|
1293
1359
|
});
|
|
1294
1360
|
}
|
|
1295
1361
|
};
|
|
@@ -1546,7 +1612,7 @@ var CliClient = class extends ExternalAIClient {
|
|
|
1546
1612
|
if (stdinPayload !== null) {
|
|
1547
1613
|
spawnOpts.input = stdinPayload;
|
|
1548
1614
|
}
|
|
1549
|
-
const r =
|
|
1615
|
+
const r = spawnSync2(argv0, cmd.slice(1), spawnOpts);
|
|
1550
1616
|
if (r.error) {
|
|
1551
1617
|
const err = r.error;
|
|
1552
1618
|
if (r.signal === "SIGTERM" || err.code === "ETIMEDOUT") {
|
|
@@ -2636,6 +2702,89 @@ import * as fs4 from "node:fs";
|
|
|
2636
2702
|
import * as os2 from "node:os";
|
|
2637
2703
|
import * as path4 from "node:path";
|
|
2638
2704
|
|
|
2705
|
+
// src/scripts/ai_council/content_ceiling.ts
|
|
2706
|
+
var CONTENT_CLASSES = ["public-artifact", "project-content"];
|
|
2707
|
+
var DEFAULT_CONTENT_CLASS = "project-content";
|
|
2708
|
+
var DEFAULT_SEAT_CEILING = "project-content";
|
|
2709
|
+
var _SET = new Set(CONTENT_CLASSES);
|
|
2710
|
+
function classifyContentClass(raw, fallback = DEFAULT_CONTENT_CLASS) {
|
|
2711
|
+
if (typeof raw === "string" && _SET.has(raw)) {
|
|
2712
|
+
return raw;
|
|
2713
|
+
}
|
|
2714
|
+
return fallback;
|
|
2715
|
+
}
|
|
2716
|
+
function admitsContent(seatCeiling, contentClass) {
|
|
2717
|
+
if (seatCeiling === "public-artifact" && contentClass === "project-content") {
|
|
2718
|
+
return {
|
|
2719
|
+
admitted: false,
|
|
2720
|
+
reason: "seat ceiling is 'public-artifact'; the payload is classified 'project-content' (consumer-supplied)"
|
|
2721
|
+
};
|
|
2722
|
+
}
|
|
2723
|
+
return { admitted: true, reason: null };
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
// src/scripts/ai_council/seat_policy.ts
|
|
2727
|
+
var POLICY_EXCLUSIONS = [
|
|
2728
|
+
/** The provider's terms forbid this use of the route. */
|
|
2729
|
+
"policy_terms",
|
|
2730
|
+
/** A privacy constraint forbids sending to this route. */
|
|
2731
|
+
"policy_privacy",
|
|
2732
|
+
/** The route's cost property is asserted rather than proven. */
|
|
2733
|
+
"policy_unproven_cost",
|
|
2734
|
+
/** The route serves a model other than the one requested. */
|
|
2735
|
+
"policy_model_mismatch",
|
|
2736
|
+
/** 2.2 — the payload's content class exceeds the seat's ceiling. */
|
|
2737
|
+
"policy_content_ceiling",
|
|
2738
|
+
/** The config named an exclusion this build does not understand. */
|
|
2739
|
+
"policy_unknown"
|
|
2740
|
+
];
|
|
2741
|
+
var _SET2 = new Set(POLICY_EXCLUSIONS);
|
|
2742
|
+
function isPolicyExclusion(v) {
|
|
2743
|
+
return typeof v === "string" && _SET2.has(v);
|
|
2744
|
+
}
|
|
2745
|
+
function classifyPolicyExclusion(raw) {
|
|
2746
|
+
if (raw === void 0 || raw === null) {
|
|
2747
|
+
return null;
|
|
2748
|
+
}
|
|
2749
|
+
return isPolicyExclusion(raw) ? raw : "policy_unknown";
|
|
2750
|
+
}
|
|
2751
|
+
function policyExclusionReason(p, provider) {
|
|
2752
|
+
const who = provider === void 0 ? "this seat" : provider;
|
|
2753
|
+
switch (p) {
|
|
2754
|
+
case "policy_terms":
|
|
2755
|
+
return `${who} is excluded by policy: the route's terms forbid this use`;
|
|
2756
|
+
case "policy_privacy":
|
|
2757
|
+
return `${who} is excluded by policy: a privacy constraint forbids this route`;
|
|
2758
|
+
case "policy_unproven_cost":
|
|
2759
|
+
return `${who} is excluded by policy: the route's cost property is asserted, not proven`;
|
|
2760
|
+
case "policy_model_mismatch":
|
|
2761
|
+
return `${who} is excluded by policy: the route serves a model other than the one requested`;
|
|
2762
|
+
case "policy_content_ceiling":
|
|
2763
|
+
return `${who} is excluded by policy: the payload exceeds the seat's content ceiling`;
|
|
2764
|
+
case "policy_unknown":
|
|
2765
|
+
return `${who} is excluded by policy: an exclusion this build does not understand (failing closed)`;
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
function parseSeatFields(name, raw) {
|
|
2769
|
+
const dr = raw["disabled_reason"];
|
|
2770
|
+
let disabled_reason = null;
|
|
2771
|
+
if (dr !== void 0 && dr !== null) {
|
|
2772
|
+
if (typeof dr !== "string" || dr.trim() === "") {
|
|
2773
|
+
return {
|
|
2774
|
+
error: `members.${name}.disabled_reason must be a non-empty string when set (got ${JSON.stringify(dr)}).`
|
|
2775
|
+
};
|
|
2776
|
+
}
|
|
2777
|
+
disabled_reason = dr.trim();
|
|
2778
|
+
}
|
|
2779
|
+
return {
|
|
2780
|
+
fields: {
|
|
2781
|
+
disabled_reason,
|
|
2782
|
+
policy_exclusion: classifyPolicyExclusion(raw["policy_exclusion"]),
|
|
2783
|
+
content_ceiling: classifyContentClass(raw["content_ceiling"], DEFAULT_SEAT_CEILING)
|
|
2784
|
+
}
|
|
2785
|
+
};
|
|
2786
|
+
}
|
|
2787
|
+
|
|
2639
2788
|
// src/scripts/ai_council/fallback_config.ts
|
|
2640
2789
|
var SECOND_MODEL_PROVIDERS = /* @__PURE__ */ new Set([
|
|
2641
2790
|
"anthropic",
|
|
@@ -3830,6 +3979,10 @@ function _build_member(name, cfg, default_mode = "auto", ignored = []) {
|
|
|
3830
3979
|
}
|
|
3831
3980
|
verified_at = coerced;
|
|
3832
3981
|
}
|
|
3982
|
+
const seat = parseSeatFields(name, cfg);
|
|
3983
|
+
if ("error" in seat) {
|
|
3984
|
+
throw new CouncilConfigError(seat.error);
|
|
3985
|
+
}
|
|
3833
3986
|
const prompt_cache_raw = _get(cfg, "prompt_cache", null);
|
|
3834
3987
|
let prompt_cache_ttl = "5m";
|
|
3835
3988
|
if (prompt_cache_raw !== null && prompt_cache_raw !== void 0 && !_isBool(prompt_cache_raw)) {
|
|
@@ -3857,7 +4010,8 @@ function _build_member(name, cfg, default_mode = "auto", ignored = []) {
|
|
|
3857
4010
|
participate_low_impact: participate_raw,
|
|
3858
4011
|
tier,
|
|
3859
4012
|
prompt_cache_ttl,
|
|
3860
|
-
verified_at
|
|
4013
|
+
verified_at,
|
|
4014
|
+
...seat.fields
|
|
3861
4015
|
};
|
|
3862
4016
|
}
|
|
3863
4017
|
var DEFAULT_CLI_CALLS_PER_DAY2 = DEFAULT_CLI_CALLS_PER_DAY;
|
|
@@ -4210,6 +4364,9 @@ export {
|
|
|
4210
4364
|
hardenedSpawnEnv,
|
|
4211
4365
|
load_cli_call_counts,
|
|
4212
4366
|
clients_exports,
|
|
4367
|
+
DEFAULT_SEAT_CEILING,
|
|
4368
|
+
admitsContent,
|
|
4369
|
+
policyExclusionReason,
|
|
4213
4370
|
_RAW_KEY_PREFIXES,
|
|
4214
4371
|
config_exports
|
|
4215
4372
|
};
|
|
@@ -978,6 +978,7 @@ var SAFE_DEFAULT = {
|
|
|
978
978
|
separate_quota_pool: false,
|
|
979
979
|
agent_teams: false,
|
|
980
980
|
worker_respawn: false,
|
|
981
|
+
structured_ask: false,
|
|
981
982
|
reads_project_mcp_config: false,
|
|
982
983
|
// `true` because the safe answer here is "there is still a step", not
|
|
983
984
|
// "there is nothing to do" — see the field's own note.
|
|
@@ -999,6 +1000,7 @@ function normalizeHostManifest(input) {
|
|
|
999
1000
|
separate_quota_pool: asBool(src.separate_quota_pool),
|
|
1000
1001
|
agent_teams: asBool(src.agent_teams),
|
|
1001
1002
|
worker_respawn: asBool(src.worker_respawn),
|
|
1003
|
+
structured_ask: asBool(src.structured_ask),
|
|
1002
1004
|
reads_project_mcp_config: asBool(src.reads_project_mcp_config),
|
|
1003
1005
|
// Inverted coercion, matching the inverted default: only an explicit
|
|
1004
1006
|
// `false` clears the residual, so an absent or malformed value keeps
|
|
@@ -1007,7 +1009,7 @@ function normalizeHostManifest(input) {
|
|
|
1007
1009
|
};
|
|
1008
1010
|
}
|
|
1009
1011
|
var HOST_CAPABILITY_REGISTRY = {
|
|
1010
|
-
claude: { subagent_spawn: true, parallel_spawn: true }
|
|
1012
|
+
claude: { subagent_spawn: true, parallel_spawn: true, structured_ask: false }
|
|
1011
1013
|
};
|
|
1012
1014
|
function resolveHostCapabilities(hostId, override) {
|
|
1013
1015
|
if (override !== void 0 && override !== null && typeof override === "object" && !Array.isArray(override)) {
|
|
@@ -1032,6 +1034,7 @@ var CAPABILITY_FIELDS = [
|
|
|
1032
1034
|
"separate_quota_pool",
|
|
1033
1035
|
"agent_teams",
|
|
1034
1036
|
"worker_respawn",
|
|
1037
|
+
"structured_ask",
|
|
1035
1038
|
"reads_project_mcp_config",
|
|
1036
1039
|
"mcp_needs_manual_activation"
|
|
1037
1040
|
];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/agent-src/scripts/_cli_entry.ts
|
|
4
|
+
import * as fs from "node:fs";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
|
+
function isCliEntry(moduleUrl, name) {
|
|
8
|
+
const argv1 = process.argv[1];
|
|
9
|
+
if (argv1 === void 0) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
if (path.basename(argv1, ".js") === name) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
const argvPath = path.resolve(argv1);
|
|
16
|
+
if (moduleUrl === pathToFileURL(argvPath).href) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
return fs.realpathSync(fileURLToPath(moduleUrl)) === fs.realpathSync(argvPath);
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
isCliEntry
|
|
28
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/agent-src/scripts/dashboard_mode.ts
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
function isTrackedInGit(abs, repo_root) {
|
|
7
|
+
const r = spawnSync("git", ["ls-files", "--error-unmatch", "--", abs], {
|
|
8
|
+
cwd: repo_root,
|
|
9
|
+
encoding: "utf-8",
|
|
10
|
+
timeout: 1e4
|
|
11
|
+
});
|
|
12
|
+
return r.status === 0;
|
|
13
|
+
}
|
|
14
|
+
var REGEN = "Run `./scripts-run src/agent-src/scripts/update_roadmap_progress` to regenerate (or `task roadmap-progress` in Taskfile projects).";
|
|
15
|
+
function evaluateDashboardState(inp) {
|
|
16
|
+
const { mode, present, trackedInGit, current, rel } = inp;
|
|
17
|
+
const regen = inp.regen ?? REGEN;
|
|
18
|
+
const noun = inp.noun ?? "dashboard";
|
|
19
|
+
if (mode === "untracked" && trackedInGit) {
|
|
20
|
+
return {
|
|
21
|
+
stale: true,
|
|
22
|
+
error: `\u274C ${rel} is still tracked by git, but this repository runs \`--untracked-mode\`. Untrack it, keeping the working-tree file:
|
|
23
|
+
git rm --cached ${rel}
|
|
24
|
+
`,
|
|
25
|
+
ok: null
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (!present) {
|
|
29
|
+
if (mode === "tracked") {
|
|
30
|
+
return {
|
|
31
|
+
stale: true,
|
|
32
|
+
error: `\u274C ${rel} is missing. ` + regen.replace("to regenerate", "to generate it") + ` If this repository deliberately does not commit the ${noun}, pass \`--untracked-mode\`.
|
|
33
|
+
`,
|
|
34
|
+
ok: null
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
stale: false,
|
|
39
|
+
error: null,
|
|
40
|
+
ok: `\u2705 ${rel} is not committed here (--untracked-mode) and no stale copy is on disk.
|
|
41
|
+
`
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (!current) {
|
|
45
|
+
return { stale: true, error: `\u274C ${rel} is stale. ${regen}
|
|
46
|
+
`, ok: null };
|
|
47
|
+
}
|
|
48
|
+
return { stale: false, error: null, ok: `\u2705 ${rel} is up to date.
|
|
49
|
+
` };
|
|
50
|
+
}
|
|
51
|
+
function evaluateDashboardOnDisk(opts) {
|
|
52
|
+
const present = fs.existsSync(opts.target);
|
|
53
|
+
return evaluateDashboardState({
|
|
54
|
+
mode: opts.mode,
|
|
55
|
+
present,
|
|
56
|
+
trackedInGit: opts.mode === "untracked" && isTrackedInGit(opts.target, opts.repo_root),
|
|
57
|
+
current: present && fs.readFileSync(opts.target, { encoding: "utf-8" }) === opts.rendered,
|
|
58
|
+
rel: opts.rel,
|
|
59
|
+
...opts.regen === void 0 ? {} : { regen: opts.regen },
|
|
60
|
+
...opts.noun === void 0 ? {} : { noun: opts.noun }
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function reportCheckVerdict(inp) {
|
|
64
|
+
const { verdict, dashboardOnly } = inp;
|
|
65
|
+
const complete = dashboardOnly ? [] : inp.complete;
|
|
66
|
+
const pending = dashboardOnly ? [] : inp.pending;
|
|
67
|
+
let err = verdict.error ?? "";
|
|
68
|
+
if (complete.length) {
|
|
69
|
+
err += "\u274C Completed roadmaps are still in `agents/roadmaps/` \u2014 move them to `agents/roadmaps/archive/` (per the `roadmap-progress-sync` rule):\n";
|
|
70
|
+
for (const r of complete) err += ` - ${r.rel} (${r.done}/${r.total_active} done)
|
|
71
|
+
`;
|
|
72
|
+
}
|
|
73
|
+
if (pending.length) {
|
|
74
|
+
err += "\u274C Iron Law 3 \u2014 roadmaps with unresolved `[~]` deferred items must NOT auto-archive. Resolve via `roadmap-management \xA7 4b` (spawn follow-up, restore, or cancel):\n";
|
|
75
|
+
for (const r of pending) {
|
|
76
|
+
err += ` - ${r.rel} (${r.done}/${r.total_active} done \xB7 ${r.deferred} deferred)
|
|
77
|
+
`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (!dashboardOnly && inp.gatedCount > 0) inp.warnMergeGated();
|
|
81
|
+
const rc = verdict.stale || complete.length > 0 || pending.length > 0 ? 1 : 0;
|
|
82
|
+
return { rc, stdout: rc === 0 ? verdict.ok ?? "" : "", stderr: err };
|
|
83
|
+
}
|
|
84
|
+
function parseModeToken(tok) {
|
|
85
|
+
if (tok === "--tracked-mode") return "tracked";
|
|
86
|
+
if (tok === "--untracked-mode") return "untracked";
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export {
|
|
91
|
+
isTrackedInGit,
|
|
92
|
+
evaluateDashboardState,
|
|
93
|
+
evaluateDashboardOnDisk,
|
|
94
|
+
reportCheckVerdict,
|
|
95
|
+
parseModeToken
|
|
96
|
+
};
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
save_inventory,
|
|
31
31
|
upsert_tool,
|
|
32
32
|
write_manifest
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-2TAQ2K4V.js";
|
|
34
34
|
import {
|
|
35
35
|
check_version,
|
|
36
36
|
classify_mismatch,
|
|
@@ -748,6 +748,12 @@ function format_drift_report(entries) {
|
|
|
748
748
|
// src/scripts/_lib/skill_catalogue.ts
|
|
749
749
|
import * as fs4 from "node:fs";
|
|
750
750
|
import * as path4 from "node:path";
|
|
751
|
+
var PROJECT_CATALOGUE_ROOTS = ["src/skills", ".claude/skills"];
|
|
752
|
+
var HOST_CATALOGUE_ROOT = ".claude/skills";
|
|
753
|
+
var DEFAULT_CATALOGUE_ROOTS = [
|
|
754
|
+
...PROJECT_CATALOGUE_ROOTS,
|
|
755
|
+
`~/${HOST_CATALOGUE_ROOT}`
|
|
756
|
+
];
|
|
751
757
|
var OBSERVATION_LOG = path4.join(
|
|
752
758
|
"agents",
|
|
753
759
|
"evidence",
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/agent-src/scripts/gate_budget.ts
|
|
4
|
+
import * as fs from "node:fs";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
var GATE_BUDGET_LEDGER_REL = path.join(
|
|
7
|
+
"agents",
|
|
8
|
+
"runtime",
|
|
9
|
+
"state",
|
|
10
|
+
"gate-budget-ledger.jsonl"
|
|
11
|
+
);
|
|
12
|
+
function gateBudgetLedgerPath(workspaceRoot) {
|
|
13
|
+
return path.join(workspaceRoot, GATE_BUDGET_LEDGER_REL);
|
|
14
|
+
}
|
|
15
|
+
var ROLLING_WINDOW_DAYS = 7;
|
|
16
|
+
function _num(value) {
|
|
17
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
function _dig(settings, keys) {
|
|
23
|
+
let cursor = settings;
|
|
24
|
+
for (const k of keys) {
|
|
25
|
+
if (cursor === null || typeof cursor !== "object" || Array.isArray(cursor)) {
|
|
26
|
+
return void 0;
|
|
27
|
+
}
|
|
28
|
+
cursor = cursor[k];
|
|
29
|
+
}
|
|
30
|
+
return cursor;
|
|
31
|
+
}
|
|
32
|
+
function readGateBudgetCaps(settings) {
|
|
33
|
+
const perRun = _num(_dig(settings, ["roadmap", "gate_budget", "max_cost_per_run_usd"]));
|
|
34
|
+
const rolling = _num(
|
|
35
|
+
_dig(settings, ["roadmap", "gate_budget", "max_cost_per_rolling_7d_usd"])
|
|
36
|
+
);
|
|
37
|
+
if (perRun === null || rolling === null) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return { maxCostPerRunUsd: perRun, maxCostPerRolling7dUsd: rolling };
|
|
41
|
+
}
|
|
42
|
+
function parseBudgetUsd(field) {
|
|
43
|
+
const text = field.trim();
|
|
44
|
+
if (text === "") {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const dollar = /\$\s*([0-9]+(?:[.,][0-9]+)?)/.exec(text);
|
|
48
|
+
if (dollar) {
|
|
49
|
+
return Number.parseFloat(dollar[1].replace(",", "."));
|
|
50
|
+
}
|
|
51
|
+
const usd = /([0-9]+(?:[.,][0-9]+)?)\s*(?:usd|dollars?)\b/i.exec(text);
|
|
52
|
+
if (usd) {
|
|
53
|
+
return Number.parseFloat(usd[1].replace(",", "."));
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
function readGateBudgetLedger(workspaceRoot) {
|
|
58
|
+
const file = gateBudgetLedgerPath(workspaceRoot);
|
|
59
|
+
if (!fs.existsSync(file)) {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
const out = [];
|
|
63
|
+
for (const line of fs.readFileSync(file, "utf-8").split("\n")) {
|
|
64
|
+
const trimmed = line.trim();
|
|
65
|
+
if (trimmed === "") {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
let parsed;
|
|
69
|
+
try {
|
|
70
|
+
parsed = JSON.parse(trimmed);
|
|
71
|
+
} catch {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (parsed === null || typeof parsed !== "object") {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const rec = parsed;
|
|
78
|
+
if (rec["kind"] !== "consumption" || typeof rec["blocker"] !== "string") {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
out.push({
|
|
82
|
+
kind: "consumption",
|
|
83
|
+
blocker: rec["blocker"],
|
|
84
|
+
authorization: "confirm-flag",
|
|
85
|
+
estimated_usd: _num(rec["estimated_usd"]) ?? 0,
|
|
86
|
+
actual_usd: _num(rec["actual_usd"]),
|
|
87
|
+
at: typeof rec["at"] === "string" ? rec["at"] : "",
|
|
88
|
+
single_use: true
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
function appendGateBudgetReceipt(workspaceRoot, receipt) {
|
|
94
|
+
const file = gateBudgetLedgerPath(workspaceRoot);
|
|
95
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
96
|
+
fs.appendFileSync(file, `${JSON.stringify(receipt)}
|
|
97
|
+
`, "utf-8");
|
|
98
|
+
}
|
|
99
|
+
function rollingSpendUsd(records, now) {
|
|
100
|
+
const cutoff = now.getTime() - ROLLING_WINDOW_DAYS * 24 * 60 * 60 * 1e3;
|
|
101
|
+
let total = 0;
|
|
102
|
+
for (const r of records) {
|
|
103
|
+
const stamp = Date.parse(r.at);
|
|
104
|
+
if (Number.isFinite(stamp) && stamp < cutoff) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
total += r.actual_usd ?? r.estimated_usd;
|
|
108
|
+
}
|
|
109
|
+
return total;
|
|
110
|
+
}
|
|
111
|
+
function evaluateGateBudget(opts) {
|
|
112
|
+
const { caps, records, estimateUsd, now } = opts;
|
|
113
|
+
if (caps === null) {
|
|
114
|
+
return {
|
|
115
|
+
ok: false,
|
|
116
|
+
reason: "no_caps",
|
|
117
|
+
detail: "no standing class-1 budget is configured (`roadmap.gate_budget.max_cost_per_run_usd` and `roadmap.gate_budget.max_cost_per_rolling_7d_usd`)"
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (estimateUsd === null) {
|
|
121
|
+
return {
|
|
122
|
+
ok: false,
|
|
123
|
+
reason: "no_estimate",
|
|
124
|
+
detail: "the entry states no USD estimate in its **Budget:** field, so no cap can be compared against it"
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
if (estimateUsd > caps.maxCostPerRunUsd) {
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
reason: "over_per_run",
|
|
131
|
+
detail: `the estimate ($${estimateUsd.toFixed(2)}) exceeds the per-run cap ($${caps.maxCostPerRunUsd.toFixed(2)})`
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
const spent = rollingSpendUsd(records, now);
|
|
135
|
+
if (spent + estimateUsd > caps.maxCostPerRolling7dUsd) {
|
|
136
|
+
return {
|
|
137
|
+
ok: false,
|
|
138
|
+
reason: "over_rolling_7d",
|
|
139
|
+
detail: `$${spent.toFixed(2)} is already receipted in the last ${String(ROLLING_WINDOW_DAYS)} days and this run would add $${estimateUsd.toFixed(2)}, over the rolling cap ($${caps.maxCostPerRolling7dUsd.toFixed(2)})`
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return { ok: true, estimateUsd, rollingUsd: spent };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export {
|
|
146
|
+
GATE_BUDGET_LEDGER_REL,
|
|
147
|
+
gateBudgetLedgerPath,
|
|
148
|
+
ROLLING_WINDOW_DAYS,
|
|
149
|
+
readGateBudgetCaps,
|
|
150
|
+
parseBudgetUsd,
|
|
151
|
+
readGateBudgetLedger,
|
|
152
|
+
appendGateBudgetReceipt,
|
|
153
|
+
rollingSpendUsd,
|
|
154
|
+
evaluateGateBudget
|
|
155
|
+
};
|