@event4u/agent-config 14.6.0 → 14.7.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.
Files changed (188) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +260 -7
  3. package/README.md +1 -1
  4. package/dist/agent-src/commands/analyze/inbox.md +264 -10
  5. package/dist/agent-src/commands/analyze.md +1 -1
  6. package/dist/agent-src/commands/roadmap/process-full.md +116 -30
  7. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +31 -0
  8. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +135 -104
  9. package/dist/agent-src/rules/context-hygiene.md +2 -0
  10. package/dist/agent-src/rules/decision-revisit-gate.md +3 -0
  11. package/dist/agent-src/rules/fix-what-you-see.md +108 -0
  12. package/dist/agent-src/rules/no-roadmap-references.md +0 -5
  13. package/dist/agent-src/rules/recurring-criticism.md +110 -0
  14. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  15. package/dist/agent-src/rules/rule-type-governance.md +0 -2
  16. package/dist/agent-src/rules/self-repair-loop.md +17 -0
  17. package/dist/agent-src/rules/skill-quality.md +0 -2
  18. package/dist/agent-src/rules/source-confidentiality.md +37 -7
  19. package/dist/agent-src/scripts/archival_sweep.ts +117 -0
  20. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +19 -3
  21. package/dist/agent-src/scripts/gate_budget.ts +282 -0
  22. package/dist/agent-src/scripts/gate_execute.ts +72 -31
  23. package/dist/agent-src/scripts/roadmap_gates.ts +74 -3
  24. package/dist/agent-src/scripts/update_roadmap_progress.ts +251 -7
  25. package/dist/agent-src/skills/ai-council/SKILL.md +48 -807
  26. package/dist/agent-src/skills/ai-council/references/advanced-modes.md +320 -0
  27. package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +99 -0
  28. package/dist/agent-src/skills/ai-council/references/execution-modes.md +162 -0
  29. package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +125 -0
  30. package/dist/agent-src/skills/ai-council/references/procedure.md +143 -0
  31. package/dist/agent-src/skills/quality-tools/SKILL.md +34 -326
  32. package/dist/agent-src/skills/quality-tools/references/js-ts-tools.md +113 -0
  33. package/dist/agent-src/skills/quality-tools/references/php-tools.md +222 -0
  34. package/dist/agent-src/skills/roadmap-management/SKILL.md +15 -409
  35. package/dist/agent-src/skills/roadmap-management/references/archival.md +226 -0
  36. package/dist/agent-src/skills/roadmap-management/references/authoring.md +107 -0
  37. package/dist/agent-src/skills/roadmap-management/references/dashboard.md +47 -0
  38. package/dist/agent-src/skills/roadmap-management/references/lifecycle.md +58 -0
  39. package/dist/agent-src/skills/skill-writing/SKILL.md +34 -570
  40. package/dist/agent-src/skills/skill-writing/references/procedure.md +275 -0
  41. package/dist/agent-src/skills/skill-writing/references/read-only-scripts.md +18 -0
  42. package/dist/agent-src/skills/skill-writing/references/section-patterns.md +298 -0
  43. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  44. package/dist/agent-src/templates/roadmaps.md +45 -2
  45. package/dist/agent-src/templates/scripts/telemetry/flush_sender.mjs +163 -0
  46. package/dist/agent-src/templates/scripts/telemetry/remote.ts +160 -7
  47. package/dist/agent-src/templates/scripts/telemetry/transport.ts +169 -0
  48. package/dist/cli/registry.js +1 -1
  49. package/dist/cli/registry.js.map +1 -1
  50. package/dist/cli-delegate/chunk-2GNWGMAL.js +172 -0
  51. package/dist/cli-delegate/{chunk-RLN73PR5.js → chunk-4VR4ORQ6.js} +10 -7
  52. package/dist/cli-delegate/chunk-6EOCNQAM.js +402 -0
  53. package/dist/cli-delegate/{chunk-XURJ4AQC.js → chunk-74E3TKWV.js} +381 -280
  54. package/dist/cli-delegate/{chunk-3UCJWMMP.js → chunk-7F3VYSM2.js} +4 -4
  55. package/dist/cli-delegate/{chunk-BKO2AZ7Z.js → chunk-B2ERU2VA.js} +1 -1
  56. package/dist/cli-delegate/{chunk-NXFWFAYV.js → chunk-G23AT6GD.js} +1 -0
  57. package/dist/cli-delegate/{chunk-63WSP6YZ.js → chunk-GJ5BVHXM.js} +72 -165
  58. package/dist/cli-delegate/{chunk-P6LQDIWK.js → chunk-JZ4NR2TW.js} +338 -0
  59. package/dist/cli-delegate/chunk-MWRD5YOH.js +100 -0
  60. package/dist/cli-delegate/{chunk-GRRPEPRN.js → chunk-T7L2QK3K.js} +24 -5
  61. package/dist/cli-delegate/{chunk-EVTY7ISR.js → chunk-YM4GZDJG.js} +9 -1
  62. package/dist/cli-delegate/cmd_conformance.js +459 -709
  63. package/dist/cli-delegate/cmd_doctor.js +6 -6
  64. package/dist/cli-delegate/cmd_explain.js +1 -1
  65. package/dist/cli-delegate/cmd_export.js +7 -6
  66. package/dist/cli-delegate/cmd_handoff.js +6 -6
  67. package/dist/cli-delegate/cmd_packs_active.js +1 -1
  68. package/dist/cli-delegate/cmd_preflight.js +2 -2
  69. package/dist/cli-delegate/cmd_prune.js +7 -6
  70. package/dist/cli-delegate/cmd_session_recycle.js +840 -30
  71. package/dist/cli-delegate/cmd_settings_migrate.js +7 -6
  72. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  73. package/dist/cli-delegate/cmd_sync.js +7 -6
  74. package/dist/cli-delegate/cmd_uninstall.js +9 -7
  75. package/dist/cli-delegate/cmd_update.js +1 -1
  76. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  77. package/dist/cli-delegate/cmd_validate.js +7 -6
  78. package/dist/discovery/deprecation-report.md +1 -1
  79. package/dist/discovery/discovery-manifest.json +68 -25
  80. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  81. package/dist/discovery/discovery-manifest.summary.md +4 -4
  82. package/dist/discovery/dormancy-report.md +1 -1
  83. package/dist/discovery/orphan-report.md +1 -1
  84. package/dist/discovery/packs.json +10 -8
  85. package/dist/discovery/trust-report.md +3 -3
  86. package/dist/discovery/workspaces.json +8 -6
  87. package/dist/hooks/dispatch.js +2901 -2053
  88. package/dist/install/claudePathsPlan.js +187 -0
  89. package/dist/install/claudePathsPlan.js.map +1 -0
  90. package/dist/install/hostLayerFingerprint.js +136 -0
  91. package/dist/install/hostLayerFingerprint.js.map +1 -0
  92. package/dist/install/install.mjs +553 -425
  93. package/dist/install/partitionEligibility.js +276 -0
  94. package/dist/install/partitionEligibility.js.map +1 -0
  95. package/dist/mcp/registry-manifest.json +3 -3
  96. package/dist/mcp/server.json +2 -2
  97. package/dist/mcp/server.mjs +1744 -1191
  98. package/dist/router.json +1 -1
  99. package/dist/scripts/_lib/agent_src.js +41 -0
  100. package/dist/scripts/_lib/agent_src.js.map +1 -1
  101. package/dist/scripts/_lib/install_layout.js +83 -0
  102. package/dist/scripts/_lib/install_layout.js.map +1 -0
  103. package/dist/scripts/_lib/installed_lock.js +444 -0
  104. package/dist/scripts/_lib/installed_lock.js.map +1 -0
  105. package/dist/scripts/condense.js +13 -164
  106. package/dist/scripts/condense.js.map +1 -1
  107. package/dist/server/schemas/settings.js +4 -0
  108. package/dist/server/schemas/settings.js.map +1 -1
  109. package/docs/contracts/settings-classes.md +12 -6
  110. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +8 -3
  111. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +26 -0
  112. package/docs/guidelines/agent-infra/memory-access.md +17 -0
  113. package/docs/guidelines/agent-infra/recurring-criticism-mechanics.md +96 -0
  114. package/package.json +1 -1
  115. package/src/agent-src/scripts/archival_sweep.ts +117 -0
  116. package/src/agent-src/scripts/archive_completed_roadmaps.ts +19 -3
  117. package/src/agent-src/scripts/gate_budget.ts +282 -0
  118. package/src/agent-src/scripts/gate_execute.ts +72 -31
  119. package/src/agent-src/scripts/roadmap_gates.ts +74 -3
  120. package/src/agent-src/scripts/update_roadmap_progress.ts +251 -7
  121. package/src/agent-src/templates/scripts/telemetry/flush_sender.mjs +163 -0
  122. package/src/agent-src/templates/scripts/telemetry/remote.ts +160 -7
  123. package/src/agent-src/templates/scripts/telemetry/transport.ts +169 -0
  124. package/src/config/agent-settings.template.yml +27 -2
  125. package/src/config/ci-local-parity.yml +18 -0
  126. package/src/config/estate-count-budget.json +339 -3
  127. package/src/config/gate-violation-baselines.json +41 -41
  128. package/src/config/rule-activation-census.json +14 -6
  129. package/src/config/rule-stub-ceilings.json +19 -6
  130. package/src/install/claudePathsPlan.ts +196 -0
  131. package/src/install/hostLayerFingerprint.ts +145 -0
  132. package/src/install/partitionEligibility.ts +325 -0
  133. package/src/scripts/_cli/cmd_session_recycle.ts +9 -1
  134. package/src/scripts/_dispatch.bash +6 -1
  135. package/src/scripts/_lib/ac_heading.ts +30 -0
  136. package/src/scripts/_lib/agent_src.ts +42 -0
  137. package/src/scripts/_lib/bench_ab_pinned_repo.ts +162 -0
  138. package/src/scripts/_lib/bench_ab_workspace.ts +10 -1
  139. package/src/scripts/_lib/envelope_grounding.ts +38 -8
  140. package/src/scripts/_lib/installed_lock.ts +50 -5
  141. package/src/scripts/_lib/md_section.ts +129 -0
  142. package/src/scripts/_lib/scope_guard.sh +26 -3
  143. package/src/scripts/_lib/self_repair.ts +19 -0
  144. package/src/scripts/_lib/self_repair_class_b.ts +171 -0
  145. package/src/scripts/ai_council/cli_help.ts +55 -0
  146. package/src/scripts/before_complete_hook.ts +153 -28
  147. package/src/scripts/bench_ab_v2_complexity.ts +27 -7
  148. package/src/scripts/check_references.ts +60 -0
  149. package/src/scripts/check_release_published.ts +32 -11
  150. package/src/scripts/check_single_delivery.ts +59 -15
  151. package/src/scripts/ci_settle.ts +170 -0
  152. package/src/scripts/condense.ts +20 -170
  153. package/src/scripts/council_cli.ts +3 -3
  154. package/src/scripts/dispatch_r2_reviewer.ts +6 -14
  155. package/src/scripts/hook_manifest.json +1 -1
  156. package/src/scripts/hook_manifest.yaml +77 -14
  157. package/src/scripts/hooks/block_no_verify.ts +61 -10
  158. package/src/scripts/hooks/block_unauthorized_git.ts +1 -1
  159. package/src/scripts/hooks/concern_registry.ts +4 -0
  160. package/src/scripts/hooks/rtk_wrap_hook.ts +8 -3
  161. package/src/scripts/hooks/run_continuation_hook.ts +8 -5
  162. package/src/scripts/hooks/ship_diff_volume_hook.ts +81 -15
  163. package/src/scripts/hooks/source_first_gate_hook.ts +464 -0
  164. package/src/scripts/hooks/state_io.ts +782 -20
  165. package/src/scripts/hooks/subagent_ledger_hook.ts +44 -15
  166. package/src/scripts/hooks/telemetry_flush_hook.ts +139 -0
  167. package/src/scripts/hooks/telemetry_self_repair.ts +128 -0
  168. package/src/scripts/hooks/telemetry_usage_hook.ts +22 -4
  169. package/src/scripts/hooks/turn_end_gate_hook.ts +81 -15
  170. package/src/scripts/install.ts +16 -11
  171. package/src/scripts/language_mirror_hook.ts +561 -25
  172. package/src/scripts/lint_framework_leakage_allowlist.json +2 -2
  173. package/src/scripts/lint_plan_risk_register.ts +4 -3
  174. package/src/scripts/lint_skill_router_head.ts +4 -4
  175. package/src/scripts/mcp_server/tools.ts +2 -2
  176. package/src/scripts/new_roadmap.ts +136 -0
  177. package/src/scripts/pack_mcp_content.ts +20 -5
  178. package/src/scripts/release.ts +37 -38
  179. package/src/scripts/report_layer_overlap.ts +6 -0
  180. package/src/scripts/self_repair_hook.ts +37 -5
  181. package/src/scripts/session_register_hook.ts +11 -0
  182. package/src/scripts/skill_usage_collect.ts +11 -1
  183. package/src/scripts/skill_usage_report.ts +278 -8
  184. package/src/scripts/sync_pr_branch.ts +7 -0
  185. package/src/server/schemas/settings.ts +8 -0
  186. package/dist/cli-delegate/chunk-EJITJBJX.js +0 -172
  187. package/dist/cli-delegate/chunk-PZWRPRWP.js +0 -38
  188. /package/dist/cli-delegate/{chunk-RYNADUFG.js → chunk-LWTYTX6F.js} +0 -0
@@ -1,4 +1,14 @@
1
1
  import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
2
+ import {
3
+ readHookStdin
4
+ } from "./chunk-F7DQWYR5.js";
5
+ import {
6
+ has_stable_session_id,
7
+ prune_legacy_state_file,
8
+ prune_stale_session_states,
9
+ session_state_file,
10
+ update_json_under_lock
11
+ } from "./chunk-6EOCNQAM.js";
2
12
 
3
13
  // src/scripts/_lib/secret_detector.ts
4
14
  var ENTROPY_MIN_TOKEN_LENGTH = 20;
@@ -469,7 +479,335 @@ function validateAssumption(input, label = "assumption") {
469
479
  return errors;
470
480
  }
471
481
 
482
+ // src/scripts/before_complete_hook.ts
483
+ import fs from "node:fs";
484
+ import path from "node:path";
485
+ import { fileURLToPath, pathToFileURL } from "node:url";
486
+ var STATE_FILE = path.join("agents", "state", "verify-before-complete.json");
487
+ var STATE_DIR = path.join("agents", "state", "verify-before-complete");
488
+ var STATE_RETENTION_DAYS = 7;
489
+ function statePathFor(session_id) {
490
+ return session_state_file(STATE_DIR, session_id);
491
+ }
492
+ var COMMAND_TOOLS = /* @__PURE__ */ new Set([
493
+ "launch-process",
494
+ "launch_process",
495
+ // Augment
496
+ "Bash",
497
+ "BashTool",
498
+ // Claude Code
499
+ "run-process",
500
+ "runProcess",
501
+ // variants
502
+ "shell",
503
+ "execute_shell",
504
+ // generic / Cline
505
+ "RunShellCommand"
506
+ // Cursor
507
+ ]);
508
+ var _VERIFICATION_RE = new RegExp(
509
+ "(?:^|[\\s;&|`(])(task\\s+(?:ci|test|tests|lint|check|qa|phpstan|rector|ecs|pest|pytest)|(?:\\./|\\.venv/bin/|vendor/bin/)?(?:pest|phpunit|phpstan|psalm|rector|ecs)\\b|(?:python3?|\\.venv/bin/python3?)\\s+-m\\s+pytest|pytest\\b|(?:npm|pnpm|yarn|bun)\\s+(?:run\\s+)?(?:test|check|lint|typecheck|tsc)|cargo\\s+(?:test|check|clippy)|go\\s+test|make\\s+(?:test|check|lint)|composer\\s+(?:test|check|lint|phpstan)|(?:php\\s+)?artisan\\s+test)",
510
+ "i"
511
+ );
512
+ function _now() {
513
+ return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "+00:00");
514
+ }
515
+ function _empty_state() {
516
+ return {
517
+ schema_version: 1,
518
+ session_id: "",
519
+ turn_started_at: null,
520
+ last_verification: null,
521
+ verifications_this_turn: 0,
522
+ verifications_this_session: 0,
523
+ last_stop_at: null,
524
+ verified_this_turn: false,
525
+ ci_saw_pending: false,
526
+ nonevidence_this_turn: 0,
527
+ // Round 7 § Phase 1 — the last CI read, SESSION-scoped on purpose. Every
528
+ // other counter here is turn-scoped because a stale POSITIVE would wrongly
529
+ // vouch ("I verified"). This one is a NEGATIVE ("CI was not settled"), and a
530
+ // stale negative only ever refuses more often — so surviving the turn
531
+ // boundary preserves the freshness invariant rather than bypassing it. It
532
+ // has to survive it: the measured failure is a completion claim in a LATER
533
+ // turn than the poll it rests on.
534
+ ci_last: null,
535
+ checked_at: _now()
536
+ };
537
+ }
538
+ function _extract_command(payload) {
539
+ const toolRaw = payload["tool_name"] || payload["toolName"] || payload["tool"];
540
+ if (!(typeof toolRaw === "string" && COMMAND_TOOLS.has(toolRaw))) {
541
+ return [typeof toolRaw === "string" ? toolRaw : null, null];
542
+ }
543
+ const tool = toolRaw;
544
+ const ti = payload["tool_input"];
545
+ if (typeof ti === "object" && ti !== null && !Array.isArray(ti)) {
546
+ for (const key of ["command", "cmd", "shell_command"]) {
547
+ const v = ti[key];
548
+ if (typeof v === "string" && v) {
549
+ return [tool, v];
550
+ }
551
+ }
552
+ }
553
+ for (const key of ["command", "cmd"]) {
554
+ const v = payload[key];
555
+ if (typeof v === "string" && v) {
556
+ return [tool, v];
557
+ }
558
+ }
559
+ return [tool, null];
560
+ }
561
+ function _is_verification(command) {
562
+ return _VERIFICATION_RE.test(command) || isCiPoll(command);
563
+ }
564
+ var _VACUOUS_PATTERNS = [
565
+ // gh pr checks / gh run — no checks registered at all.
566
+ /\b0\s+(?:checks?|runs?)\b/i,
567
+ // Test runners reporting an empty run.
568
+ /\bno tests? (?:ran|found|to run|were run)\b/i,
569
+ /\bNo test files found\b/i,
570
+ /\b0\s+pass(?:ed|ing)?\b[\s,|·]*\b0\s+fail(?:ed|ing|ures)?\b/i,
571
+ /\bTests?\s+0\s+passed\b/i,
572
+ /\bRan 0 tests?\b/i,
573
+ // Linters / scanners with an empty target set.
574
+ /\bno files? (?:matched|to (?:lint|check|scan)|found)\b/i,
575
+ /\b0\s+files?\s+(?:checked|scanned|linted)\b/i,
576
+ /\bnothing to check\b/i
577
+ ];
578
+ function isVacuousOutput(output) {
579
+ const text = output.trim();
580
+ if (!text) {
581
+ return false;
582
+ }
583
+ const lines = text.split("\n").filter((l) => l.trim());
584
+ return lines.every((l) => _VACUOUS_PATTERNS.some((re) => re.test(l)));
585
+ }
586
+ var _CI_POLL_RE = /\bgh\s+(?:pr\s+checks|run\s+(?:watch|list|view))\b/i;
587
+ function isCiPoll(command) {
588
+ return _CI_POLL_RE.test(command);
589
+ }
590
+ function pendingCount(output) {
591
+ const m = /(\d+)\s+(?:checks? )?pending\b/i.exec(output) ?? /\bpending[:=]\s*(\d+)/i.exec(output);
592
+ if (m?.[1] !== void 0) {
593
+ return Number(m[1]);
594
+ }
595
+ const rows = output.match(/^\S.*\b(pending|in_progress|queued)\b/gim);
596
+ if (rows) {
597
+ return rows.length;
598
+ }
599
+ if (/\bno checks reported\b/i.test(output)) {
600
+ return null;
601
+ }
602
+ if (/^\S+\s+(pass|fail|skipping|successful|failing)\b/im.test(output)) {
603
+ return 0;
604
+ }
605
+ return null;
606
+ }
607
+ function _extract_output(payload) {
608
+ for (const key of ["tool_response", "toolResponse", "output", "stdout", "result"]) {
609
+ const v = payload[key];
610
+ if (typeof v === "string") {
611
+ return v;
612
+ }
613
+ if (v !== null && typeof v === "object") {
614
+ return JSON.stringify(v);
615
+ }
616
+ }
617
+ return null;
618
+ }
619
+ function _reset_turn(state, session_id) {
620
+ state["session_id"] = session_id || state["session_id"] || "";
621
+ state["turn_started_at"] = _now();
622
+ state["verifications_this_turn"] = 0;
623
+ state["verified_this_turn"] = false;
624
+ state["ci_saw_pending"] = false;
625
+ state["nonevidence_this_turn"] = 0;
626
+ return state;
627
+ }
628
+ function _asInt(v) {
629
+ if (!v) {
630
+ return 0;
631
+ }
632
+ if (typeof v === "number") {
633
+ return Math.trunc(v);
634
+ }
635
+ const n = Number(v);
636
+ return Number.isFinite(n) ? Math.trunc(n) : 0;
637
+ }
638
+ function _update(state, event, envelope) {
639
+ const session_id = envelope["session_id"] || state["session_id"] || "";
640
+ if (session_id && session_id !== state["session_id"]) {
641
+ state["session_id"] = session_id;
642
+ state["verifications_this_session"] = 0;
643
+ state["ci_last"] = null;
644
+ state = _reset_turn(state, session_id);
645
+ }
646
+ let payload = envelope["payload"];
647
+ if (!(typeof payload === "object" && payload !== null && !Array.isArray(payload))) {
648
+ payload = {};
649
+ }
650
+ const pl = payload;
651
+ if (event === "session_start" || event === "user_prompt_submit") {
652
+ state = _reset_turn(state, session_id);
653
+ } else if (event === "post_tool_use") {
654
+ const [tool, cmd] = _extract_command(pl);
655
+ if (cmd && _is_verification(cmd)) {
656
+ const output = _extract_output(pl);
657
+ const vacuous = output !== null && isVacuousOutput(output);
658
+ let counts = !vacuous;
659
+ if (isCiPoll(cmd)) {
660
+ const pending = output === null ? null : pendingCount(output);
661
+ if (pending !== null && pending > 0) {
662
+ state["ci_saw_pending"] = true;
663
+ counts = false;
664
+ } else if (pending === 0) {
665
+ counts = !vacuous && state["ci_saw_pending"] === true;
666
+ } else {
667
+ counts = false;
668
+ }
669
+ state["ci_last"] = {
670
+ at: _now(),
671
+ command: cmd.slice(0, 512),
672
+ pending,
673
+ settled: pending === 0 && counts === true
674
+ };
675
+ }
676
+ state["last_verification"] = {
677
+ command: cmd.slice(0, 512),
678
+ tool,
679
+ at: _now(),
680
+ platform: envelope["platform"] || "",
681
+ vacuous,
682
+ counted: counts
683
+ };
684
+ if (counts) {
685
+ state["verifications_this_turn"] = _asInt(state["verifications_this_turn"]) + 1;
686
+ state["verifications_this_session"] = _asInt(state["verifications_this_session"]) + 1;
687
+ state["verified_this_turn"] = true;
688
+ } else {
689
+ state["nonevidence_this_turn"] = _asInt(state["nonevidence_this_turn"]) + 1;
690
+ }
691
+ }
692
+ } else if (event === "stop") {
693
+ state["last_stop_at"] = _now();
694
+ }
695
+ state["checked_at"] = _now();
696
+ return state;
697
+ }
698
+ function run(stdin_text, options) {
699
+ const { consumer_root } = options;
700
+ const verbose = options.verbose ?? false;
701
+ let envelope = {};
702
+ if (stdin_text.trim()) {
703
+ try {
704
+ const decoded = JSON.parse(stdin_text);
705
+ if (typeof decoded === "object" && decoded !== null && !Array.isArray(decoded)) {
706
+ envelope = decoded;
707
+ }
708
+ } catch {
709
+ envelope = {};
710
+ }
711
+ }
712
+ const event = envelope["event"] || "";
713
+ const session_id = typeof envelope["session_id"] === "string" ? envelope["session_id"] : "";
714
+ if (!has_stable_session_id(session_id)) {
715
+ if (verbose) {
716
+ process.stderr.write(
717
+ "verify-before-complete-hook: no session_id \u2014 running stateless, nothing recorded\n"
718
+ );
719
+ }
720
+ return 0;
721
+ }
722
+ const target = path.join(consumer_root, statePathFor(session_id));
723
+ let state = {};
724
+ const outcome = update_json_under_lock(target, (loaded) => {
725
+ state = _update({ ..._empty_state(), ...loaded }, event, envelope);
726
+ return state;
727
+ });
728
+ if (outcome === "failed") {
729
+ if (verbose) {
730
+ process.stderr.write("verify-before-complete-hook: state write failed\n");
731
+ }
732
+ return 0;
733
+ }
734
+ if (event === "session_start" || event === "user_prompt_submit") {
735
+ prune_legacy_state_file(path.join(consumer_root, STATE_FILE));
736
+ prune_stale_session_states(
737
+ path.join(consumer_root, STATE_DIR),
738
+ Date.now(),
739
+ STATE_RETENTION_DAYS
740
+ );
741
+ }
742
+ if (verbose) {
743
+ process.stderr.write(
744
+ `verify-before-complete-hook: event=${event} verified_this_turn=${pyRepr(state["verified_this_turn"])} verifications_this_turn=${pyRepr(state["verifications_this_turn"])}
745
+ `
746
+ );
747
+ }
748
+ return 0;
749
+ }
750
+ function pyRepr(value) {
751
+ if (value === null || value === void 0) {
752
+ return "None";
753
+ }
754
+ if (typeof value === "boolean") {
755
+ return value ? "True" : "False";
756
+ }
757
+ return String(value);
758
+ }
759
+ function parse_args(argv) {
760
+ let platform = "generic";
761
+ let verbose = false;
762
+ for (let i = 0; i < argv.length; i += 1) {
763
+ const arg = argv[i];
764
+ if (arg === "--platform") {
765
+ platform = argv[i + 1] ?? "generic";
766
+ i += 1;
767
+ } else if (arg !== void 0 && arg.startsWith("--platform=")) {
768
+ platform = arg.slice("--platform=".length);
769
+ } else if (arg === "--verbose") {
770
+ verbose = true;
771
+ }
772
+ }
773
+ return { platform, verbose };
774
+ }
775
+ function _readStdin() {
776
+ return readHookStdin();
777
+ }
778
+ function main(argv) {
779
+ const args = parse_args(argv ?? process.argv.slice(2));
780
+ return run(_readStdin(), { consumer_root: process.cwd(), verbose: args.verbose });
781
+ }
782
+ function _isCliEntry() {
783
+ if (true) {
784
+ return false;
785
+ }
786
+ if (process.argv[1] === void 0) {
787
+ return false;
788
+ }
789
+ const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
790
+ if (import.meta.url === argvUrl) {
791
+ return true;
792
+ }
793
+ try {
794
+ const here = fs.realpathSync(fileURLToPath(import.meta.url));
795
+ const argv = fs.realpathSync(path.resolve(process.argv[1]));
796
+ return here === argv;
797
+ } catch {
798
+ return false;
799
+ }
800
+ }
801
+ var isCliEntry = _isCliEntry();
802
+ if (isCliEntry) {
803
+ process.exit(main(process.argv.slice(2)));
804
+ }
805
+
472
806
  export {
807
+ statePathFor,
808
+ isVacuousOutput,
809
+ isCiPoll,
810
+ pendingCount,
473
811
  CAPSULE_SCHEMA_VERSION,
474
812
  scanEnvelopeDirectives,
475
813
  wrapAsPriorSessionData,
@@ -0,0 +1,100 @@
1
+ import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
2
+
3
+ // src/scripts/_lib/fs_atomic.ts
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { randomBytes } from "node:crypto";
7
+ function _normalize_encoding(encoding) {
8
+ const compact = encoding.toLowerCase().replace(/[-_\s]/g, "");
9
+ const candidates = [encoding, compact];
10
+ if (compact === "latin1" || compact === "iso88591") candidates.push("latin1");
11
+ if (compact === "utf8") candidates.push("utf8");
12
+ if (compact === "utf16le" || compact === "utf16") candidates.push("utf16le");
13
+ if (compact === "usascii") candidates.push("ascii");
14
+ for (const c of candidates) {
15
+ if (Buffer.isEncoding(c)) return c;
16
+ }
17
+ throw new Error(`unknown encoding: ${encoding}`);
18
+ }
19
+ function write_atomic(p, data, options = {}) {
20
+ const encoding = options.encoding ?? "utf-8";
21
+ const target = path.normalize(p);
22
+ const parent = path.dirname(target);
23
+ fs.mkdirSync(parent, { recursive: true });
24
+ let payload;
25
+ if (typeof data === "string") {
26
+ payload = Buffer.from(data, _normalize_encoding(encoding));
27
+ } else if (data instanceof Uint8Array) {
28
+ payload = Buffer.from(data);
29
+ } else {
30
+ throw new TypeError(
31
+ `write_atomic: data must be str or bytes, got ${typeof data}`
32
+ );
33
+ }
34
+ let fd = null;
35
+ let tmp_path = "";
36
+ for (let attempt = 0; attempt < 32; attempt += 1) {
37
+ tmp_path = path.join(
38
+ parent,
39
+ `.${path.basename(target)}.tmp.${randomBytes(6).toString("hex")}`
40
+ );
41
+ try {
42
+ fd = fs.openSync(tmp_path, "wx", 384);
43
+ break;
44
+ } catch (err) {
45
+ if (err.code === "EEXIST") continue;
46
+ throw err;
47
+ }
48
+ }
49
+ if (fd === null) {
50
+ throw new Error("write_atomic: could not create a unique temp file");
51
+ }
52
+ let closed = false;
53
+ try {
54
+ let offset = 0;
55
+ while (offset < payload.length) {
56
+ offset += fs.writeSync(fd, payload, offset, payload.length - offset);
57
+ }
58
+ try {
59
+ fs.fsyncSync(fd);
60
+ } catch {
61
+ }
62
+ fs.closeSync(fd);
63
+ closed = true;
64
+ fs.renameSync(tmp_path, target);
65
+ } catch (err) {
66
+ if (!closed) {
67
+ try {
68
+ fs.closeSync(fd);
69
+ } catch {
70
+ }
71
+ }
72
+ try {
73
+ fs.unlinkSync(tmp_path);
74
+ } catch {
75
+ }
76
+ throw err;
77
+ }
78
+ _fsync_dir(parent);
79
+ return target;
80
+ }
81
+ function _fsync_dir(directory) {
82
+ let dir_fd;
83
+ try {
84
+ dir_fd = fs.openSync(directory, fs.constants.O_RDONLY);
85
+ } catch {
86
+ return;
87
+ }
88
+ try {
89
+ try {
90
+ fs.fsyncSync(dir_fd);
91
+ } catch {
92
+ }
93
+ } finally {
94
+ fs.closeSync(dir_fd);
95
+ }
96
+ }
97
+
98
+ export {
99
+ write_atomic
100
+ };
@@ -58,6 +58,7 @@ var _VERSION_RE = /^\s*agent_config_version\s*:\s*"?([^"\s]+)"?\s*$/;
58
58
  var _SCHEMA_RE = /^\s*schema_version\s*:\s*(\d+)\s*$/;
59
59
  var _LAYOUT_RE = /^\s*install_layout_version\s*:\s*(\d+)\s*$/;
60
60
  var _INSTALLED_AT_RE = /^\s*installed_at\s*:\s*"?([^"\s]+)"?\s*$/;
61
+ var _FINGERPRINT_RE = /^\s*host_layer_fingerprint\s*:\s*"?([0-9a-f]{64})"?\s*$/;
61
62
  var _TOOL_RE = /^\s*-\s*([A-Za-z0-9_\-.]+)\s*$/;
62
63
  function expanduser(p) {
63
64
  if (p === "~") {
@@ -123,6 +124,12 @@ function read_lockfile(path2) {
123
124
  in_tools = false;
124
125
  continue;
125
126
  }
127
+ const fp_m = _FINGERPRINT_RE.exec(raw_line);
128
+ if (fp_m) {
129
+ data.host_layer_fingerprint = fp_m[1];
130
+ in_tools = false;
131
+ continue;
132
+ }
126
133
  if (raw_line.trim().startsWith("tools:")) {
127
134
  in_tools = true;
128
135
  continue;
@@ -145,14 +152,17 @@ function splitlines(text) {
145
152
  }
146
153
  return parts;
147
154
  }
148
- function _render(version, tools, installed_at) {
155
+ function _render(version, tools, installed_at, fingerprint) {
149
156
  const lines = [
150
157
  `schema_version: ${SCHEMA_VERSION}`,
151
158
  `install_layout_version: ${INSTALL_LAYOUT_VERSION}`,
152
159
  `agent_config_version: "${version}"`,
153
- `installed_at: "${installed_at}"`,
154
- "tools:"
160
+ `installed_at: "${installed_at}"`
155
161
  ];
162
+ if (fingerprint) {
163
+ lines.push(`host_layer_fingerprint: "${fingerprint}"`);
164
+ }
165
+ lines.push("tools:");
156
166
  for (const tool of tools) {
157
167
  lines.push(` - ${tool}`);
158
168
  }
@@ -162,7 +172,12 @@ function write_lockfile(version, tools, options = {}) {
162
172
  const target = options.path ?? lockfile_path();
163
173
  fs.mkdirSync(path.dirname(target), { recursive: true });
164
174
  const stamp = strftime_iso_z(options.now ?? /* @__PURE__ */ new Date());
165
- const rendered = _render(version, sorted_unique(tools), stamp);
175
+ const rendered = _render(
176
+ version,
177
+ sorted_unique(tools),
178
+ stamp,
179
+ options.host_layer_fingerprint ?? null
180
+ );
166
181
  const parent = path.dirname(target);
167
182
  const { fd, tmp_name } = mkstemp(parent, ".installed.lock.");
168
183
  try {
@@ -218,7 +233,11 @@ function migrate_layout(options = {}) {
218
233
  const version = existing.agent_config_version || current_package_version();
219
234
  const tools = [...existing.tools ?? []];
220
235
  const when = options.now ?? _parse_installed_at(existing.installed_at);
221
- write_lockfile(version, tools, { path: target, now: when });
236
+ write_lockfile(version, tools, {
237
+ path: target,
238
+ now: when,
239
+ host_layer_fingerprint: existing.host_layer_fingerprint ?? null
240
+ });
222
241
  return {
223
242
  from: from_v,
224
243
  to: INSTALL_LAYOUT_VERSION,
@@ -4230,7 +4230,15 @@ var settingsSchema = external_exports.object({
4230
4230
  ),
4231
4231
  horizon_weeks: external_exports.number().int().min(0).default(0).describe(
4232
4232
  'Optional planning horizon (weeks) the agent shows in roadmap framing ("next 4 weeks"). Set 0 to omit the horizon \u2014 most teams prefer to ship without a hardcoded window.'
4233
- )
4233
+ ),
4234
+ gate_budget: external_exports.object({
4235
+ max_cost_per_run_usd: external_exports.number().min(0).default(5).describe(
4236
+ "Per-run USD ceiling for a CLASS-1 roadmap blocker executed via `agent-config gates --execute`. A class-1 entry whose **Budget:** field states a larger figure renders its consent line instead of running. Bounds the size of an authorised spend; never supplies the authorisation \u2014 `--confirm` is still required on every class-1 run."
4237
+ ),
4238
+ max_cost_per_rolling_7d_usd: external_exports.number().min(0).default(25).describe(
4239
+ "Rolling 7-day USD ceiling for class-1 gate execution, summed from the append-only receipt ledger at agents/runtime/state/gate-budget-ledger.jsonl. A run whose estimate would cross it renders instead of running. A per-run cap alone bounds one mistake, not a week of them, which is why option (a) of b-gate-budget-preauth carries two numbers."
4240
+ )
4241
+ }).default({ max_cost_per_run_usd: 5, max_cost_per_rolling_7d_usd: 25 })
4234
4242
  }),
4235
4243
  planning: external_exports.object({
4236
4244
  challenge_on_create: external_exports.boolean().default(true).describe(