@event4u/agent-config 14.5.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 (203) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +384 -3
  3. package/README.md +1 -1
  4. package/dist/agent-src/commands/analyze/decision.md +7 -0
  5. package/dist/agent-src/commands/analyze/inbox.md +264 -10
  6. package/dist/agent-src/commands/analyze.md +1 -1
  7. package/dist/agent-src/commands/optimize/project.md +10 -0
  8. package/dist/agent-src/commands/roadmap/process-full.md +132 -4
  9. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +31 -0
  10. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +161 -1
  11. package/dist/agent-src/rules/context-hygiene.md +2 -0
  12. package/dist/agent-src/rules/decision-revisit-gate.md +111 -7
  13. package/dist/agent-src/rules/fix-what-you-see.md +108 -0
  14. package/dist/agent-src/rules/no-roadmap-references.md +0 -5
  15. package/dist/agent-src/rules/recurring-criticism.md +110 -0
  16. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  17. package/dist/agent-src/rules/rule-type-governance.md +0 -2
  18. package/dist/agent-src/rules/self-repair-loop.md +17 -0
  19. package/dist/agent-src/rules/skill-quality.md +0 -2
  20. package/dist/agent-src/rules/source-confidentiality.md +37 -7
  21. package/dist/agent-src/scripts/archival_sweep.ts +117 -0
  22. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +19 -3
  23. package/dist/agent-src/scripts/gate_budget.ts +282 -0
  24. package/dist/agent-src/scripts/gate_execute.ts +72 -31
  25. package/dist/agent-src/scripts/roadmap_gates.ts +74 -3
  26. package/dist/agent-src/scripts/update_roadmap_progress.ts +251 -7
  27. package/dist/agent-src/skills/adr-create/SKILL.md +25 -3
  28. package/dist/agent-src/skills/ai-council/SKILL.md +48 -807
  29. package/dist/agent-src/skills/ai-council/references/advanced-modes.md +320 -0
  30. package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +99 -0
  31. package/dist/agent-src/skills/ai-council/references/execution-modes.md +162 -0
  32. package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +125 -0
  33. package/dist/agent-src/skills/ai-council/references/procedure.md +143 -0
  34. package/dist/agent-src/skills/decision-review/SKILL.md +18 -0
  35. package/dist/agent-src/skills/quality-tools/SKILL.md +34 -326
  36. package/dist/agent-src/skills/quality-tools/references/js-ts-tools.md +113 -0
  37. package/dist/agent-src/skills/quality-tools/references/php-tools.md +222 -0
  38. package/dist/agent-src/skills/roadmap-management/SKILL.md +15 -409
  39. package/dist/agent-src/skills/roadmap-management/references/archival.md +226 -0
  40. package/dist/agent-src/skills/roadmap-management/references/authoring.md +107 -0
  41. package/dist/agent-src/skills/roadmap-management/references/dashboard.md +47 -0
  42. package/dist/agent-src/skills/roadmap-management/references/lifecycle.md +58 -0
  43. package/dist/agent-src/skills/skill-writing/SKILL.md +34 -570
  44. package/dist/agent-src/skills/skill-writing/references/procedure.md +275 -0
  45. package/dist/agent-src/skills/skill-writing/references/read-only-scripts.md +18 -0
  46. package/dist/agent-src/skills/skill-writing/references/section-patterns.md +298 -0
  47. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  48. package/dist/agent-src/templates/roadmaps.md +45 -2
  49. package/dist/agent-src/templates/scripts/telemetry/flush_sender.mjs +163 -0
  50. package/dist/agent-src/templates/scripts/telemetry/remote.ts +160 -7
  51. package/dist/agent-src/templates/scripts/telemetry/transport.ts +169 -0
  52. package/dist/cli/registry.js +1 -1
  53. package/dist/cli/registry.js.map +1 -1
  54. package/dist/cli-delegate/chunk-2GNWGMAL.js +172 -0
  55. package/dist/cli-delegate/{chunk-RLN73PR5.js → chunk-4VR4ORQ6.js} +10 -7
  56. package/dist/cli-delegate/chunk-6EOCNQAM.js +402 -0
  57. package/dist/cli-delegate/{chunk-XURJ4AQC.js → chunk-74E3TKWV.js} +381 -280
  58. package/dist/cli-delegate/{chunk-3UCJWMMP.js → chunk-7F3VYSM2.js} +4 -4
  59. package/dist/cli-delegate/{chunk-BKO2AZ7Z.js → chunk-B2ERU2VA.js} +1 -1
  60. package/dist/cli-delegate/{chunk-NXFWFAYV.js → chunk-G23AT6GD.js} +1 -0
  61. package/dist/cli-delegate/{chunk-63WSP6YZ.js → chunk-GJ5BVHXM.js} +72 -165
  62. package/dist/cli-delegate/{chunk-ZPSXJTLI.js → chunk-JZ4NR2TW.js} +353 -1
  63. package/dist/cli-delegate/chunk-MWRD5YOH.js +100 -0
  64. package/dist/cli-delegate/{chunk-GRRPEPRN.js → chunk-T7L2QK3K.js} +24 -5
  65. package/dist/cli-delegate/{chunk-EVTY7ISR.js → chunk-YM4GZDJG.js} +9 -1
  66. package/dist/cli-delegate/cmd_conformance.js +459 -709
  67. package/dist/cli-delegate/cmd_doctor.js +6 -6
  68. package/dist/cli-delegate/cmd_explain.js +1 -1
  69. package/dist/cli-delegate/cmd_export.js +7 -6
  70. package/dist/cli-delegate/cmd_handoff.js +6 -6
  71. package/dist/cli-delegate/cmd_packs_active.js +1 -1
  72. package/dist/cli-delegate/cmd_preflight.js +2 -2
  73. package/dist/cli-delegate/cmd_prune.js +7 -6
  74. package/dist/cli-delegate/cmd_session_recycle.js +840 -30
  75. package/dist/cli-delegate/cmd_settings_migrate.js +7 -6
  76. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  77. package/dist/cli-delegate/cmd_sync.js +7 -6
  78. package/dist/cli-delegate/cmd_uninstall.js +9 -7
  79. package/dist/cli-delegate/cmd_update.js +1 -1
  80. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  81. package/dist/cli-delegate/cmd_validate.js +7 -6
  82. package/dist/discovery/deprecation-report.md +1 -1
  83. package/dist/discovery/discovery-manifest.json +72 -29
  84. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  85. package/dist/discovery/discovery-manifest.summary.md +4 -4
  86. package/dist/discovery/dormancy-report.md +1 -1
  87. package/dist/discovery/orphan-report.md +1 -1
  88. package/dist/discovery/packs.json +10 -8
  89. package/dist/discovery/trust-report.md +3 -3
  90. package/dist/discovery/workspaces.json +8 -6
  91. package/dist/hooks/dispatch.js +3127 -2022
  92. package/dist/install/claudePathsPlan.js +187 -0
  93. package/dist/install/claudePathsPlan.js.map +1 -0
  94. package/dist/install/hostLayerFingerprint.js +136 -0
  95. package/dist/install/hostLayerFingerprint.js.map +1 -0
  96. package/dist/install/install.mjs +553 -425
  97. package/dist/install/partitionEligibility.js +276 -0
  98. package/dist/install/partitionEligibility.js.map +1 -0
  99. package/dist/mcp/registry-manifest.json +3 -3
  100. package/dist/mcp/server.json +2 -2
  101. package/dist/mcp/server.mjs +1744 -1191
  102. package/dist/router.json +1 -1
  103. package/dist/scripts/_lib/agent_src.js +41 -0
  104. package/dist/scripts/_lib/agent_src.js.map +1 -1
  105. package/dist/scripts/_lib/install_layout.js +83 -0
  106. package/dist/scripts/_lib/install_layout.js.map +1 -0
  107. package/dist/scripts/_lib/installed_lock.js +444 -0
  108. package/dist/scripts/_lib/installed_lock.js.map +1 -0
  109. package/dist/scripts/condense.js +13 -164
  110. package/dist/scripts/condense.js.map +1 -1
  111. package/dist/server/schemas/settings.js +4 -0
  112. package/dist/server/schemas/settings.js.map +1 -1
  113. package/docs/contracts/settings-classes.md +12 -6
  114. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +8 -3
  115. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +26 -0
  116. package/docs/guidelines/agent-infra/engineering-memory-data-format.md +49 -0
  117. package/docs/guidelines/agent-infra/memory-access.md +17 -0
  118. package/docs/guidelines/agent-infra/recurring-criticism-mechanics.md +96 -0
  119. package/package.json +1 -1
  120. package/src/agent-src/scripts/archival_sweep.ts +117 -0
  121. package/src/agent-src/scripts/archive_completed_roadmaps.ts +19 -3
  122. package/src/agent-src/scripts/gate_budget.ts +282 -0
  123. package/src/agent-src/scripts/gate_execute.ts +72 -31
  124. package/src/agent-src/scripts/roadmap_gates.ts +74 -3
  125. package/src/agent-src/scripts/update_roadmap_progress.ts +251 -7
  126. package/src/agent-src/templates/scripts/telemetry/flush_sender.mjs +163 -0
  127. package/src/agent-src/templates/scripts/telemetry/remote.ts +160 -7
  128. package/src/agent-src/templates/scripts/telemetry/transport.ts +169 -0
  129. package/src/config/agent-settings.template.yml +27 -2
  130. package/src/config/ci-local-parity.yml +18 -0
  131. package/src/config/estate-count-budget.json +367 -3
  132. package/src/config/gate-violation-baselines.json +41 -41
  133. package/src/config/pack-size-budget.json +3 -2
  134. package/src/config/rule-activation-census.json +14 -6
  135. package/src/config/rule-stub-ceilings.json +19 -6
  136. package/src/install/claudePathsPlan.ts +196 -0
  137. package/src/install/hostLayerFingerprint.ts +145 -0
  138. package/src/install/partitionEligibility.ts +325 -0
  139. package/src/scripts/_cli/cmd_session_recycle.ts +9 -1
  140. package/src/scripts/_dispatch.bash +6 -1
  141. package/src/scripts/_lib/ac_heading.ts +30 -0
  142. package/src/scripts/_lib/agent_src.ts +42 -0
  143. package/src/scripts/_lib/bench_ab_pinned_repo.ts +162 -0
  144. package/src/scripts/_lib/bench_ab_workspace.ts +10 -1
  145. package/src/scripts/_lib/envelope_grounding.ts +38 -8
  146. package/src/scripts/_lib/installed_lock.ts +50 -5
  147. package/src/scripts/_lib/layer_overlap_notice.ts +85 -0
  148. package/src/scripts/_lib/md_section.ts +129 -0
  149. package/src/scripts/_lib/scope_guard.sh +86 -4
  150. package/src/scripts/_lib/self_repair.ts +19 -0
  151. package/src/scripts/_lib/self_repair_class_b.ts +171 -0
  152. package/src/scripts/_lib/subagent_capsule.ts +81 -1
  153. package/src/scripts/adr/regenerate_index.ts +13 -2
  154. package/src/scripts/adr_cite_check.ts +424 -0
  155. package/src/scripts/ai_council/cli_help.ts +55 -0
  156. package/src/scripts/before_complete_hook.ts +153 -28
  157. package/src/scripts/bench_ab_v2_complexity.ts +27 -7
  158. package/src/scripts/check_adr_frontmatter.ts +187 -1
  159. package/src/scripts/check_references.ts +60 -0
  160. package/src/scripts/check_release_published.ts +32 -11
  161. package/src/scripts/check_single_delivery.ts +517 -0
  162. package/src/scripts/ci_settle.ts +170 -0
  163. package/src/scripts/condense.ts +20 -170
  164. package/src/scripts/council_cli.ts +3 -3
  165. package/src/scripts/dispatch_r2_reviewer.ts +6 -14
  166. package/src/scripts/hook_manifest.json +1 -1
  167. package/src/scripts/hook_manifest.yaml +77 -14
  168. package/src/scripts/hooks/block_no_verify.ts +61 -10
  169. package/src/scripts/hooks/block_unauthorized_git.ts +1 -1
  170. package/src/scripts/hooks/concern_registry.ts +4 -0
  171. package/src/scripts/hooks/rtk_wrap_hook.ts +8 -3
  172. package/src/scripts/hooks/run_continuation_hook.ts +887 -68
  173. package/src/scripts/hooks/ship_diff_volume_hook.ts +81 -15
  174. package/src/scripts/hooks/source_first_gate_hook.ts +464 -0
  175. package/src/scripts/hooks/state_io.ts +782 -20
  176. package/src/scripts/hooks/subagent_ledger_hook.ts +44 -15
  177. package/src/scripts/hooks/telemetry_flush_hook.ts +139 -0
  178. package/src/scripts/hooks/telemetry_self_repair.ts +128 -0
  179. package/src/scripts/hooks/telemetry_usage_hook.ts +22 -4
  180. package/src/scripts/hooks/turn_end_gate_hook.ts +81 -15
  181. package/src/scripts/install.sh +12 -2
  182. package/src/scripts/install.ts +16 -11
  183. package/src/scripts/language_mirror_hook.ts +561 -25
  184. package/src/scripts/lint_framework_leakage_allowlist.json +2 -2
  185. package/src/scripts/lint_plan_risk_register.ts +4 -3
  186. package/src/scripts/lint_skill_router_head.ts +4 -4
  187. package/src/scripts/mcp_server/tools.ts +2 -2
  188. package/src/scripts/memory_consolidation.ts +189 -0
  189. package/src/scripts/memory_eviction.ts +384 -0
  190. package/src/scripts/new_roadmap.ts +136 -0
  191. package/src/scripts/pack_mcp_content.ts +20 -5
  192. package/src/scripts/release.ts +37 -38
  193. package/src/scripts/report_layer_overlap.ts +78 -0
  194. package/src/scripts/report_memory_pointers.ts +622 -0
  195. package/src/scripts/self_repair_hook.ts +37 -5
  196. package/src/scripts/session_register_hook.ts +115 -15
  197. package/src/scripts/skill_usage_collect.ts +11 -1
  198. package/src/scripts/skill_usage_report.ts +278 -8
  199. package/src/scripts/sync_pr_branch.ts +7 -0
  200. package/src/server/schemas/settings.ts +8 -0
  201. package/dist/cli-delegate/chunk-EJITJBJX.js +0 -172
  202. package/dist/cli-delegate/chunk-PZWRPRWP.js +0 -38
  203. /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;
@@ -213,6 +223,20 @@ var CAPSULE_SCHEMA_VERSION = 3;
213
223
  function isShortLine(value, max) {
214
224
  return typeof value === "string" && value.length > 0 && value.length <= max && !value.includes("\n");
215
225
  }
226
+ function isPathRef(value) {
227
+ return typeof value === "string" && value.length > 0 && !/\s/.test(value);
228
+ }
229
+ function checkPathRefList(errors, field, value, max, required) {
230
+ checkList(errors, field, value, max, required);
231
+ if (!Array.isArray(value)) return;
232
+ if (value.some((x) => !isShortLine(x, max))) return;
233
+ const bad = value.filter((x) => !isPathRef(x));
234
+ if (bad.length === 0) return;
235
+ const shown = bad.slice(0, 3).map((x) => JSON.stringify(String(x))).join(", ");
236
+ errors.push(
237
+ `${field} carries ${bad.length} entr${bad.length === 1 ? "y" : "ies"} that are prose, not path refs: ${shown}${bad.length > 3 ? ", \u2026" : ""} \u2014 write the path (src/generated/api.ts, ../other-worktree/) or drop the entry; a sentence naming a file cannot be compared against a write target, and being comparable is the whole reason this is a field rather than a line of prose`
238
+ );
239
+ }
216
240
  function checkList(errors, field, value, max, required) {
217
241
  if (value === void 0) {
218
242
  if (required) errors.push(`${field} is required`);
@@ -402,7 +426,7 @@ function validateRecycleEnvelope(input) {
402
426
  checkList(errors, "decisions", e["decisions"], MAX_LINE_CHARS, false);
403
427
  errors.push(...decisionTagErrors(e["decisions"]));
404
428
  checkList(errors, "constraints", e["constraints"], MAX_LINE_CHARS, false);
405
- checkList(errors, "do_not_touch", e["do_not_touch"], MAX_REF_CHARS, false);
429
+ checkPathRefList(errors, "do_not_touch", e["do_not_touch"], MAX_REF_CHARS, false);
406
430
  checkList(errors, "open_worker_envelopes", e["open_worker_envelopes"], MAX_REF_CHARS, false);
407
431
  checkList(errors, "artifact_paths", e["artifact_paths"], MAX_REF_CHARS, false);
408
432
  checkList(errors, "suggested_skills", e["suggested_skills"], MAX_REF_CHARS, false);
@@ -455,7 +479,335 @@ function validateAssumption(input, label = "assumption") {
455
479
  return errors;
456
480
  }
457
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
+
458
806
  export {
807
+ statePathFor,
808
+ isVacuousOutput,
809
+ isCiPoll,
810
+ pendingCount,
459
811
  CAPSULE_SCHEMA_VERSION,
460
812
  scanEnvelopeDirectives,
461
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(