@event4u/agent-config 9.14.0 → 9.16.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 (287) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +118 -99
  3. package/README.md +8 -0
  4. package/dist/agent-src/commands/agents/audit.md +7 -7
  5. package/dist/agent-src/commands/agents/optimize.md +1 -1
  6. package/dist/agent-src/commands/analyze/reference-repo.md +1 -1
  7. package/dist/agent-src/commands/chat-history.md +1 -0
  8. package/dist/agent-src/commands/context.md +1 -0
  9. package/dist/agent-src/commands/council.md +1 -1
  10. package/dist/agent-src/commands/ghostwriter.md +1 -1
  11. package/dist/agent-src/commands/memory.md +2 -1
  12. package/dist/agent-src/commands/module.md +1 -0
  13. package/dist/agent-src/commands/optimize/agents-dir.md +1 -1
  14. package/dist/agent-src/commands/optimize/deep.md +5 -2
  15. package/dist/agent-src/commands/optimize/skills.md +5 -5
  16. package/dist/agent-src/commands/override.md +1 -0
  17. package/dist/agent-src/commands/prediction-pool.md +4 -4
  18. package/dist/agent-src/commands/research/deep.md +1 -1
  19. package/dist/agent-src/commands/roadmap.md +2 -1
  20. package/dist/agent-src/commands/rule-compliance-audit.md +1 -1
  21. package/dist/agent-src/commands/tdd.md +1 -0
  22. package/dist/agent-src/commands/tests.md +1 -0
  23. package/dist/agent-src/commands/upstream-contribute.md +5 -5
  24. package/dist/agent-src/commands/video/from-script.md +1 -1
  25. package/dist/agent-src/commands/video/from-song.md +1 -1
  26. package/dist/agent-src/commands/video/scene.md +1 -1
  27. package/dist/agent-src/commands/video/stitch.md +1 -1
  28. package/dist/agent-src/commands/video/storyboard.md +1 -1
  29. package/dist/agent-src/commands/worktree/create.md +2 -1
  30. package/dist/agent-src/contexts/augment-infrastructure.md +1 -1
  31. package/dist/agent-src/contexts/contracts/artifact-engagement-flow.md +5 -5
  32. package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +3 -3
  33. package/dist/agent-src/contexts/contracts/emergency-triage-block.md +2 -2
  34. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +4 -3
  35. package/dist/agent-src/contexts/execution/subagent-routing.md +19 -0
  36. package/dist/agent-src/contexts/override-system.md +1 -1
  37. package/dist/agent-src/ghostwriter/fictional-fixture-v1.md +1 -1
  38. package/dist/agent-src/rules/augment-edit-discipline.md +1 -1
  39. package/dist/agent-src/rules/autonomous-execution.md +2 -1
  40. package/dist/agent-src/rules/brand-consistency.md +1 -0
  41. package/dist/agent-src/rules/brand-source-of-truth.md +1 -0
  42. package/dist/agent-src/rules/code-comment-discipline.md +2 -0
  43. package/dist/agent-src/rules/communication-through-line.md +1 -0
  44. package/dist/agent-src/rules/content-quoting-floor.md +1 -0
  45. package/dist/agent-src/rules/cross-source-consistency.md +0 -1
  46. package/dist/agent-src/rules/downstream-changes.md +1 -0
  47. package/dist/agent-src/rules/external-code-graph-interop.md +1 -0
  48. package/dist/agent-src/rules/external-reference-deep-dive.md +1 -0
  49. package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
  50. package/dist/agent-src/rules/finance-safety-floor.md +0 -1
  51. package/dist/agent-src/rules/icon-consistency.md +1 -0
  52. package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
  53. package/dist/agent-src/rules/improve-before-implement.md +1 -1
  54. package/dist/agent-src/rules/invite-challenge.md +1 -0
  55. package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
  56. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
  57. package/dist/agent-src/rules/markdown-safe-codeblocks.md +1 -0
  58. package/dist/agent-src/rules/media-governance-routing.md +4 -3
  59. package/dist/agent-src/rules/media-sync-ground-truth.md +1 -0
  60. package/dist/agent-src/rules/no-attribution-footers.md +1 -0
  61. package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +1 -0
  62. package/dist/agent-src/rules/no-pr-progress-comments.md +1 -0
  63. package/dist/agent-src/rules/onboarding-gate.md +1 -0
  64. package/dist/agent-src/rules/output-discipline.md +1 -0
  65. package/dist/agent-src/rules/prefer-enums-over-literals.md +1 -0
  66. package/dist/agent-src/rules/preservation-guard.md +1 -0
  67. package/dist/agent-src/rules/question-not-instruction.md +1 -0
  68. package/dist/agent-src/rules/roadmap-ci-steps-policy.md +1 -0
  69. package/dist/agent-src/rules/role-mode-adherence.md +1 -0
  70. package/dist/agent-src/rules/runtime-safety.md +1 -0
  71. package/dist/agent-src/rules/security-sensitive-stop.md +1 -0
  72. package/dist/agent-src/rules/session-canary.md +9 -2
  73. package/dist/agent-src/rules/source-confidentiality.md +1 -0
  74. package/dist/agent-src/rules/source-of-truth.md +1 -0
  75. package/dist/agent-src/rules/spreadsheet-source-quality.md +1 -0
  76. package/dist/agent-src/rules/think-before-action.md +1 -0
  77. package/dist/agent-src/rules/token-budget-discipline.md +1 -0
  78. package/dist/agent-src/rules/token-efficiency.md +1 -0
  79. package/dist/agent-src/rules/token-optimizer-maintenance.md +5 -5
  80. package/dist/agent-src/rules/tool-safety.md +1 -0
  81. package/dist/agent-src/rules/untrusted-input-defense.md +2 -0
  82. package/dist/agent-src/rules/user-interaction.md +1 -0
  83. package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
  84. package/dist/agent-src/skills/adr-create/SKILL.md +1 -1
  85. package/dist/agent-src/skills/check-refs/SKILL.md +1 -1
  86. package/dist/agent-src/skills/competitive-positioning/SKILL.md +1 -1
  87. package/dist/agent-src/skills/condense-memory/SKILL.md +1 -1
  88. package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
  89. package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +1 -1
  90. package/dist/agent-src/skills/description-assist/SKILL.md +1 -1
  91. package/dist/agent-src/skills/github-ci/SKILL.md +1 -0
  92. package/dist/agent-src/skills/guideline-writing/SKILL.md +1 -1
  93. package/dist/agent-src/skills/lint-skills/SKILL.md +1 -1
  94. package/dist/agent-src/skills/readme-reviewer/SKILL.md +1 -1
  95. package/dist/agent-src/skills/roadmap-management/SKILL.md +8 -1
  96. package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
  97. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
  98. package/dist/agent-src/skills/skill-writing/SKILL.md +4 -4
  99. package/dist/agent-src/skills/token-optimizer/SKILL.md +4 -4
  100. package/dist/agent-src/skills/upstream-contribute/SKILL.md +6 -6
  101. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +25 -0
  102. package/dist/agent-src/templates/AGENTS.md +1 -1
  103. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  104. package/dist/agent-src/templates/command.md +1 -1
  105. package/dist/agent-src/templates/copilot-instructions.md +3 -3
  106. package/dist/agent-src/templates/rule.md +2 -2
  107. package/dist/agent-src/templates/scripts/work_engine/orchestration.ts +1 -1
  108. package/dist/agent-src/templates/skill-archive-note.md +5 -5
  109. package/dist/agent-src/templates/skill.md +1 -1
  110. package/dist/cli/agent-config.js +66 -19
  111. package/dist/cli/agent-config.js.map +1 -1
  112. package/dist/cli/main.js +9 -4
  113. package/dist/cli/main.js.map +1 -1
  114. package/dist/cli/mcp/content.js +1 -1
  115. package/dist/cli/mcp/content.js.map +1 -1
  116. package/dist/cli/python/workspace_drive.js +2 -0
  117. package/dist/cli/python/workspace_drive.js.map +1 -1
  118. package/dist/cli/python/workspace_drive_health.js +2 -0
  119. package/dist/cli/python/workspace_drive_health.js.map +1 -1
  120. package/dist/cli/python/workspace_hosts.js +2 -0
  121. package/dist/cli/python/workspace_hosts.js.map +1 -1
  122. package/dist/cli/python/workspace_sessions.js +2 -0
  123. package/dist/cli/python/workspace_sessions.js.map +1 -1
  124. package/dist/cli/registry.js +1 -0
  125. package/dist/cli/registry.js.map +1 -1
  126. package/dist/cli-delegate/{chunk-A3HJ6NTI.js → chunk-63WSP6YZ.js} +2 -1
  127. package/dist/cli-delegate/{chunk-EJYIGZ3T.js → chunk-BKO2AZ7Z.js} +1 -1
  128. package/dist/cli-delegate/{chunk-GCVFLBP2.js → chunk-H574KOUH.js} +338 -494
  129. package/dist/cli-delegate/chunk-NXFWFAYV.js +339 -0
  130. package/dist/cli-delegate/{chunk-TEGJU2JX.js → chunk-ZXXJLL5K.js} +2 -2
  131. package/dist/cli-delegate/cmd_conformance.js +29 -23
  132. package/dist/cli-delegate/cmd_doctor.js +3 -3
  133. package/dist/cli-delegate/cmd_export.js +4 -4
  134. package/dist/cli-delegate/cmd_preflight.js +2 -2
  135. package/dist/cli-delegate/cmd_prune.js +4 -4
  136. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  137. package/dist/cli-delegate/cmd_sync.js +4 -4
  138. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  139. package/dist/cli-delegate/cmd_validate.js +4 -4
  140. package/dist/discovery/deprecation-report.md +1 -1
  141. package/dist/discovery/discovery-manifest.json +127 -95
  142. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  143. package/dist/discovery/discovery-manifest.summary.md +1 -1
  144. package/dist/discovery/orphan-report.md +1 -1
  145. package/dist/discovery/packs.json +2 -2
  146. package/dist/discovery/trust-report.md +1 -1
  147. package/dist/discovery/workspaces.json +2 -2
  148. package/dist/hooks/dispatch.js +729 -430
  149. package/dist/install/install.mjs +52 -11
  150. package/dist/install/rule_scope.js +18 -2
  151. package/dist/install/rule_scope.js.map +1 -1
  152. package/dist/mcp/registry-manifest.json +2 -2
  153. package/dist/mcp/server.json +2 -2
  154. package/dist/mcp/server.mjs +518 -411
  155. package/dist/router.json +1 -1
  156. package/dist/scripts/_lib/claude_settings_hooks.js +30 -5
  157. package/dist/scripts/_lib/claude_settings_hooks.js.map +1 -1
  158. package/dist/scripts/_lib/scoped_projection.js +223 -0
  159. package/dist/scripts/_lib/scoped_projection.js.map +1 -0
  160. package/dist/scripts/_lib/surface_tiers.js +125 -0
  161. package/dist/scripts/_lib/surface_tiers.js.map +1 -0
  162. package/dist/scripts/_lib/token_count.js +166 -0
  163. package/dist/scripts/_lib/token_count.js.map +1 -0
  164. package/dist/scripts/_lib/trigger_eval_floors.js +8 -0
  165. package/dist/scripts/_lib/trigger_eval_floors.js.map +1 -1
  166. package/dist/scripts/condense.js +139 -9
  167. package/dist/scripts/condense.js.map +1 -1
  168. package/dist/scripts/project_thin_rules.js +450 -0
  169. package/dist/scripts/project_thin_rules.js.map +1 -0
  170. package/dist/server/routes/workspace.js +3 -1
  171. package/dist/server/routes/workspace.js.map +1 -1
  172. package/dist/server/schemas/settings.js +9 -3
  173. package/dist/server/schemas/settings.js.map +1 -1
  174. package/dist/shared/userMd/utils.js +1 -1
  175. package/dist/shared/userMd/utils.js.map +1 -1
  176. package/dist/ui/assets/index-DmR0mbk4.js +26 -0
  177. package/dist/ui/assets/index-DmR0mbk4.js.map +1 -0
  178. package/dist/ui/index.html +1 -1
  179. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  180. package/package.json +14 -14
  181. package/src/agent-src/templates/AGENTS.md +1 -1
  182. package/src/agent-src/templates/scripts/work_engine/orchestration.ts +1 -1
  183. package/src/config/agent-settings.template.yml +61 -11
  184. package/src/config/budget-routing.json +7 -0
  185. package/src/config/ci-local-parity.yml +8 -0
  186. package/src/config/discovery/unassigned-artefacts.yml +23 -25
  187. package/src/config/evaluator-budgets.json +35 -5
  188. package/src/config/gate-coverage.yml +147 -0
  189. package/src/config/gate-violation-baselines.json +25 -0
  190. package/src/install/rule_scope.ts +27 -2
  191. package/src/scripts/_cli/cmd_conformance.ts +13 -24
  192. package/src/scripts/_dispatch.bash +10 -0
  193. package/src/scripts/_lib/claude_settings_hooks.ts +30 -4
  194. package/src/scripts/_lib/gate_baseline.ts +213 -0
  195. package/src/scripts/_lib/scoped_projection.ts +50 -0
  196. package/src/scripts/_lib/tier_budget_routing.ts +360 -0
  197. package/src/scripts/_lib/tool_adapter_registry.ts +8 -1
  198. package/src/scripts/_lib/trigger_eval_floors.ts +9 -0
  199. package/src/scripts/_lib/trigger_routers.ts +17 -5
  200. package/src/scripts/adr/regenerate_index.ts +4 -3
  201. package/src/scripts/ai-video/lib/parse-blueprint.sh +1 -1
  202. package/src/scripts/ai_council/compile_corpus.ts +1 -1
  203. package/src/scripts/anchor_scoring_run.ts +1 -1
  204. package/src/scripts/audit_cloud_compatibility.ts +37 -2
  205. package/src/scripts/audit_initial_context.ts +53 -19
  206. package/src/scripts/audit_likelihood.ts +31 -2
  207. package/src/scripts/audit_user_type_axis.ts +58 -11
  208. package/src/scripts/bench_hook_latency.ts +172 -41
  209. package/src/scripts/bench_persona_placebo.ts +1 -1
  210. package/src/scripts/bench_quality_run.ts +1 -1
  211. package/src/scripts/build_mcp_catalog.ts +12 -1
  212. package/src/scripts/check_always_budget.ts +122 -11
  213. package/src/scripts/check_augment_description_cap.ts +24 -3
  214. package/src/scripts/check_ci_strict_superset.ts +150 -0
  215. package/src/scripts/check_cli_registry_budget_sync.ts +168 -0
  216. package/src/scripts/check_cluster_patterns.ts +100 -0
  217. package/src/scripts/check_consumer_scope_flip.ts +26 -4
  218. package/src/scripts/check_evaluator_budgets.ts +198 -19
  219. package/src/scripts/check_gate_coverage.ts +338 -2
  220. package/src/scripts/check_generator_output_coverage.ts +2 -1
  221. package/src/scripts/check_iron_law_prominence.ts +1 -1
  222. package/src/scripts/check_kernel_rule_bundle.ts +1 -1
  223. package/src/scripts/check_no_new_legacy_path.ts +167 -3
  224. package/src/scripts/check_pack_size.ts +18 -4
  225. package/src/scripts/check_portability.ts +37 -7
  226. package/src/scripts/check_references.ts +19 -3
  227. package/src/scripts/check_release_pr_shape.ts +13 -0
  228. package/src/scripts/check_token_quality_golden.ts +1 -1
  229. package/src/scripts/check_token_regression.ts +9 -2
  230. package/src/scripts/condense.ts +155 -12
  231. package/src/scripts/cost/budget.mjs +77 -2
  232. package/src/scripts/evaluator_umbrella.sh +34 -1
  233. package/src/scripts/generate_capability_matrix.ts +8 -0
  234. package/src/scripts/generate_router_coverage_from_matrix.ts +155 -0
  235. package/src/scripts/hook_manifest.yaml +17 -3
  236. package/src/scripts/hooks/block_config_weakening.ts +337 -0
  237. package/src/scripts/hooks/concern_registry.ts +2 -0
  238. package/src/scripts/hooks/probe_throttle.ts +75 -0
  239. package/src/scripts/install-hooks.sh +24 -2
  240. package/src/scripts/install.ts +2 -2
  241. package/src/scripts/lint_agents_md.ts +9 -3
  242. package/src/scripts/lint_archived_skills.ts +1 -1
  243. package/src/scripts/lint_artefact_frontmatter.ts +185 -37
  244. package/src/scripts/lint_command_routing.ts +21 -52
  245. package/src/scripts/lint_command_verbs.ts +47 -28
  246. package/src/scripts/lint_context_spine_usage.ts +38 -12
  247. package/src/scripts/lint_framework_leakage.ts +25 -6
  248. package/src/scripts/lint_handoffs.ts +49 -2
  249. package/src/scripts/lint_media_policy_linkage.ts +62 -30
  250. package/src/scripts/lint_namespace.ts +92 -7
  251. package/src/scripts/lint_new_skill_gate.ts +39 -31
  252. package/src/scripts/lint_originality_shingles.ts +7 -1
  253. package/src/scripts/lint_override_kernel_guard.ts +21 -3
  254. package/src/scripts/lint_pack_boundaries.ts +461 -91
  255. package/src/scripts/lint_pack_dependencies.ts +24 -57
  256. package/src/scripts/lint_persona_governance.ts +1 -1
  257. package/src/scripts/lint_role_experiences.ts +34 -5
  258. package/src/scripts/lint_trigger_precision.ts +142 -0
  259. package/src/scripts/mcp_server/consumer_tool_catalog.json +12 -201
  260. package/src/scripts/mcp_server/tools.ts +1 -1
  261. package/src/scripts/prepack-check.mjs +40 -1
  262. package/src/scripts/prepack_router_targets.d.mts +7 -0
  263. package/src/scripts/prepack_router_targets.mjs +93 -0
  264. package/src/scripts/print_required_checks.ts +72 -18
  265. package/src/scripts/profile_staleness_hook.ts +12 -0
  266. package/src/scripts/record_evaluator_measurements.mjs +105 -0
  267. package/src/scripts/recruit_preflight.sh +1 -1
  268. package/src/scripts/release.ts +214 -7
  269. package/src/scripts/router_target_paths.d.mts +4 -0
  270. package/src/scripts/router_target_paths.mjs +69 -0
  271. package/src/scripts/router_telemetry.ts +52 -1
  272. package/src/scripts/routing_doctor.ts +560 -0
  273. package/src/scripts/rule_trigger_eval.ts +403 -0
  274. package/src/scripts/schemas/rule.schema.json +5 -1
  275. package/src/scripts/session_canary_hook.ts +96 -5
  276. package/src/scripts/skill_linter.ts +9 -28
  277. package/src/scripts/smoke/skills.sh +1 -1
  278. package/src/scripts/sweep_dead_scan_roots.ts +356 -10
  279. package/src/scripts/trigger_coverage.ts +13 -2
  280. package/src/scripts/update_counts.ts +1 -1
  281. package/src/scripts/validate_telegraph_carveouts.ts +1 -1
  282. package/src/scripts/wrapper_freshness_hook.ts +14 -0
  283. package/src/server/schemas/settings.ts +19 -5
  284. package/src/shared/userMd/utils.ts +1 -1
  285. package/dist/cli-delegate/chunk-TJIAM5FW.js +0 -133
  286. package/dist/ui/assets/index-BpSQt5vm.js +0 -40
  287. package/dist/ui/assets/index-BpSQt5vm.js.map +0 -1
@@ -169,6 +169,8 @@ class CalledProcessError extends Error {
169
169
  // _lib/ and install.ts's REPO_ROOT computation).
170
170
  const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
171
171
  const PACKAGE_JSON = path.join(REPO_ROOT, 'package.json');
172
+ // Bumped alongside package.json — see set_lockfile_version for why.
173
+ const PACKAGE_LOCK_JSON = path.join(REPO_ROOT, 'package-lock.json');
172
174
  const MARKETPLACE_JSON = path.join(REPO_ROOT, '.claude-plugin', 'marketplace.json');
173
175
  // Source-of-truth project-settings template. Carries an `agent_config_version`
174
176
  // pin that check_template_pin_drift requires to equal package.json.version. We
@@ -562,6 +564,65 @@ function git(args: readonly string[], opts: { capture?: boolean } = {}): string
562
564
  return capture ? r.stdout.trim() : '';
563
565
  }
564
566
 
567
+ /**
568
+ * One name per failing check, from `gh pr checks --json name,bucket` output.
569
+ *
570
+ * Pure over the JSON text so the shape is testable without gh. Returns []
571
+ * when the payload is unparseable or nothing sits in the `fail` bucket —
572
+ * the caller then falls back to the raw watch output alone.
573
+ */
574
+ export function _failed_check_names(jsonText: string): string[] {
575
+ let parsed: unknown;
576
+ try {
577
+ parsed = JSON.parse(jsonText);
578
+ } catch {
579
+ return [];
580
+ }
581
+ if (!Array.isArray(parsed)) {
582
+ return [];
583
+ }
584
+ const names: string[] = [];
585
+ for (const entry of parsed) {
586
+ if (typeof entry !== 'object' || entry === null) {
587
+ continue;
588
+ }
589
+ const e = entry as Record<string, unknown>;
590
+ if (e['bucket'] === 'fail' && typeof e['name'] === 'string') {
591
+ names.push(e['name']);
592
+ }
593
+ }
594
+ return names;
595
+ }
596
+
597
+ /**
598
+ * Remediation lines for a set of failing check names.
599
+ *
600
+ * The watch table scrolls failures out of view on a busy PR, so the operator
601
+ * repeatedly saw only `pass`/`skipping` rows plus "PR checks failed" — the
602
+ * 9.14.0 failure mode, twice. Name the red checks explicitly and, for the
603
+ * shape detector, say where the fix belongs (main, never the release branch).
604
+ */
605
+ export function _failed_checks_report(names: readonly string[]): string {
606
+ if (names.length === 0) {
607
+ return '';
608
+ }
609
+ const lines: string[] = ['', 'Failing check(s):'];
610
+ for (const name of names) {
611
+ lines.push(` ❌ ${name}`);
612
+ }
613
+ if (names.includes('Release-PR shape detector')) {
614
+ lines.push(
615
+ '',
616
+ 'Release-PR shape: a release PR may only contain the version-bump',
617
+ 'allowlist. Land the out-of-shape files on main via their own PR, then',
618
+ 'merge main into the release branch — their release-PR diff becomes',
619
+ 'empty (docs/contracts/release-pr-gating.md § Mid-release fixes).',
620
+ );
621
+ }
622
+ lines.push('', 'After fixing, resume with: task release -- --resume --yes', '');
623
+ return lines.join('\n');
624
+ }
625
+
565
626
  /**
566
627
  * Watch PR checks and tolerate the 'no checks' case.
567
628
  *
@@ -573,13 +634,16 @@ function git(args: readonly string[], opts: { capture?: boolean } = {}): string
573
634
  * A short grace period gives GitHub time to register workflow runs on a
574
635
  * freshly-pushed branch.
575
636
  */
576
- function watch_pr_checks(): void {
637
+ function watch_pr_checks(branch: string): void {
577
638
  // time.sleep(5) — blocking grace period. Never reached on any test path.
578
639
  const until = Date.now() + 5000;
579
640
  while (Date.now() < until) {
580
641
  // busy-wait stand-in for time.sleep(5) without an event-loop yield.
581
642
  }
582
- const proc = spawnSync('gh', ['pr', 'checks', '--watch'], {
643
+ // The branch is passed explicitly — `gh` inferring the PR from HEAD
644
+ // resolved to `main` mid-run once (2026-08-03, 9.16.0 resume) and the
645
+ // whole release died on "no pull requests found for branch main".
646
+ const proc = spawnSync('gh', ['pr', 'checks', branch, '--watch'], {
583
647
  cwd: REPO_ROOT,
584
648
  encoding: 'utf-8',
585
649
  stdio: ['ignore', 'pipe', 'pipe'],
@@ -606,9 +670,117 @@ function watch_pr_checks(): void {
606
670
  if (output) {
607
671
  process.stderr.write(output + '\n');
608
672
  }
673
+ const summary = spawnSync('gh', ['pr', 'checks', branch, '--json', 'name,bucket'], {
674
+ cwd: REPO_ROOT,
675
+ encoding: 'utf-8',
676
+ stdio: ['ignore', 'pipe', 'pipe'],
677
+ });
678
+ const report = _failed_checks_report(_failed_check_names(summary.stdout ?? ''));
679
+ if (report) {
680
+ process.stderr.write(report + '\n');
681
+ }
609
682
  die(`PR checks failed (exit ${returncode})`);
610
683
  }
611
684
 
685
+ /**
686
+ * Push the release branch, integrating a remote that moved under us.
687
+ *
688
+ * A GitHub-side "Update branch" click (or a concurrent resume run) advances
689
+ * `origin/<branch>` while the local ref stays behind; a bare `git push` is
690
+ * then rejected with "fetch first" and the whole release run dies (measured
691
+ * 2026-08-03, 9.15.0). Same-branch commits are never ours to drop, so the
692
+ * recovery is merge-and-retry, never force-push.
693
+ */
694
+ function push_release_branch(branch: string): void {
695
+ const first = run(['git', 'push', '-u', REMOTE, branch], { check: false });
696
+ if (first.returncode === 0) {
697
+ return;
698
+ }
699
+ process.stdout.write(`↻ ${REMOTE}/${branch} moved — integrating and retrying push\n`);
700
+ run(['git', 'fetch', REMOTE, branch]);
701
+ run(['git', 'merge', '--no-edit', `${REMOTE}/${branch}`]);
702
+ run(['git', 'push', '-u', REMOTE, branch]);
703
+ }
704
+
705
+ /** mergeStateStatus of the branch's PR ('' when the probe fails). */
706
+ function _pr_merge_state(branch: string): string {
707
+ const r = run(
708
+ ['gh', 'pr', 'view', branch, '--json', 'mergeStateStatus', '--jq', '.mergeStateStatus'],
709
+ {
710
+ check: false,
711
+ capture: true,
712
+ },
713
+ );
714
+ return r.returncode === 0 ? r.stdout.trim() : '';
715
+ }
716
+
717
+ /**
718
+ * Bound on update-and-retry rounds in merge_release_pr. Three is deliberate:
719
+ * main receiving unrelated merges three times inside one checks-wait window
720
+ * means the queue is hot and a human should decide, not a loop.
721
+ */
722
+ const _MERGE_UPDATE_ROUNDS = 3;
723
+
724
+ /**
725
+ * Merge the release PR, absorbing a moving base branch.
726
+ *
727
+ * Branch protection requires the head to be up to date with `main`, and
728
+ * `main` moves constantly (dependabot, unrelated merges) — so between the
729
+ * checks-wait and the merge the PR routinely flips to BEHIND and a bare
730
+ * `gh pr merge` dies with "the head branch is not up to date with the base
731
+ * branch" (measured 2026-08-03, 9.16.0). Recovery is mechanical and safe by
732
+ * construction: merging `origin/main` into `release/X.Y.Z` makes the fix
733
+ * files identical on both sides, so the release-PR diff stays inside the
734
+ * version-bump allowlist (docs/contracts/release-pr-gating.md § Mid-release
735
+ * fixes) — do it here instead of aborting the run.
736
+ */
737
+ function merge_release_pr(branch: string, wait_for_checks: boolean): void {
738
+ if (git(['rev-parse', '--abbrev-ref', 'HEAD'], { capture: true }) !== branch) {
739
+ run(['git', 'checkout', branch]);
740
+ }
741
+ for (let round = 0; round <= _MERGE_UPDATE_ROUNDS; round++) {
742
+ if (_pr_merge_state(branch) !== 'BEHIND') {
743
+ const merged = run(['gh', 'pr', 'merge', branch, '--merge', '--delete-branch'], {
744
+ check: false,
745
+ });
746
+ if (merged.returncode === 0) {
747
+ return;
748
+ }
749
+ if (_pr_merge_state(branch) !== 'BEHIND') {
750
+ // Not the moving-base failure — surface it unchanged.
751
+ throw new CalledProcessError(merged.returncode, [
752
+ 'gh',
753
+ 'pr',
754
+ 'merge',
755
+ branch,
756
+ '--merge',
757
+ '--delete-branch',
758
+ ]);
759
+ }
760
+ // BEHIND appeared between the probe and the merge — fall through
761
+ // to the update below.
762
+ }
763
+ if (round === _MERGE_UPDATE_ROUNDS) {
764
+ break;
765
+ }
766
+ process.stdout.write(
767
+ `↻ head behind ${MAIN_BRANCH} (update round ${round + 1}/${_MERGE_UPDATE_ROUNDS}) — ` +
768
+ `merging ${REMOTE}/${MAIN_BRANCH} into ${branch} and re-running checks\n`,
769
+ );
770
+ run(['git', 'fetch', REMOTE, MAIN_BRANCH]);
771
+ run(['git', 'merge', '--no-edit', `${REMOTE}/${MAIN_BRANCH}`]);
772
+ push_release_branch(branch);
773
+ if (wait_for_checks) {
774
+ watch_pr_checks(branch);
775
+ }
776
+ }
777
+ die(
778
+ `release PR is still behind ${MAIN_BRANCH} after ${_MERGE_UPDATE_ROUNDS} update round(s) — ` +
779
+ `${MAIN_BRANCH} is moving faster than the checks complete. ` +
780
+ 'Re-run when the queue quiets down: task release -- --resume --yes',
781
+ );
782
+ }
783
+
612
784
  function have(bin: string): boolean {
613
785
  const res = spawnSync('which', [bin], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
614
786
  if (res.error) {
@@ -1064,6 +1236,34 @@ function set_package_version(p: string, version: string): void {
1064
1236
  fs.writeFileSync(p, jsonDumpsIndent(data, 4) + '\n', 'utf-8');
1065
1237
  }
1066
1238
 
1239
+ /**
1240
+ * Update BOTH version fields npm keeps in a lockfile — the top-level one and
1241
+ * the root package entry (`packages[""]`).
1242
+ *
1243
+ * The bump previously touched package.json and left the lock behind, so every
1244
+ * release shipped a `main` whose two files disagreed and every subsequent
1245
+ * local `npm install` produced a spurious modification (measured 2026-08-02:
1246
+ * package.json 9.13.0 vs package-lock.json 9.12.0). Rewriting the two fields
1247
+ * rather than shelling out to `npm install --package-lock-only` keeps the bump
1248
+ * offline and cannot re-resolve a dependency mid-release.
1249
+ * road-to-gates-that-can-fail Phase 5.
1250
+ */
1251
+ function set_lockfile_version(p: string, version: string): void {
1252
+ if (!fs.existsSync(p)) {
1253
+ return;
1254
+ }
1255
+ const data = JSON.parse(fs.readFileSync(p, 'utf-8')) as Record<string, unknown>;
1256
+ data['version'] = version;
1257
+ const packages = data['packages'];
1258
+ if (typeof packages === 'object' && packages !== null && !Array.isArray(packages)) {
1259
+ const root = (packages as Record<string, unknown>)[''];
1260
+ if (typeof root === 'object' && root !== null && !Array.isArray(root)) {
1261
+ (root as Record<string, unknown>)['version'] = version;
1262
+ }
1263
+ }
1264
+ fs.writeFileSync(p, jsonDumpsIndent(data, 4) + '\n', 'utf-8');
1265
+ }
1266
+
1067
1267
  /** Update `metadata.version`; preserve 2-space indentation + UTF-8. */
1068
1268
  function set_marketplace_version(p: string, version: string): void {
1069
1269
  const data = JSON.parse(fs.readFileSync(p, 'utf-8')) as Record<string, unknown>;
@@ -1442,8 +1642,13 @@ function execute(
1442
1642
  if (resume && current_pkg === plan.target) {
1443
1643
  _step(2, total, `Files already at ${plan.target} — skip bump`);
1444
1644
  } else {
1445
- _step(2, total, 'Bump package.json + marketplace.json + template pin, prepend CHANGELOG');
1645
+ _step(
1646
+ 2,
1647
+ total,
1648
+ 'Bump package.json + package-lock.json + marketplace.json + template pin, prepend CHANGELOG',
1649
+ );
1446
1650
  set_package_version(PACKAGE_JSON, plan.target);
1651
+ set_lockfile_version(PACKAGE_LOCK_JSON, plan.target);
1447
1652
  set_marketplace_version(MARKETPLACE_JSON, plan.target);
1448
1653
  set_template_pin(PROJECT_TEMPLATE, plan.target);
1449
1654
  prepend_changelog(CHANGELOG, plan.changelog_entry);
@@ -1493,9 +1698,10 @@ function execute(
1493
1698
  _step(4, total, 'PR already merged — skip push');
1494
1699
  } else {
1495
1700
  // `git push -u` is naturally idempotent — it prints "Everything
1496
- // up-to-date" when remote already matches. No probe needed.
1701
+ // up-to-date" when remote already matches. push_release_branch
1702
+ // additionally absorbs a remote that moved under us.
1497
1703
  _step(4, total, `Push ${branch} to ${REMOTE}`);
1498
- run(['git', 'push', '-u', REMOTE, branch]);
1704
+ push_release_branch(branch);
1499
1705
  }
1500
1706
 
1501
1707
  // ─── 5. PR ──────────────────────────────────────────────────────────────
@@ -1534,7 +1740,7 @@ function execute(
1534
1740
  _step(6, total, 'PR already merged — skip checks wait');
1535
1741
  } else if (wait_for_checks) {
1536
1742
  _step(6, total, 'Wait for PR checks');
1537
- watch_pr_checks();
1743
+ watch_pr_checks(branch);
1538
1744
  } else {
1539
1745
  _step(6, total, 'Skip waiting for checks (--no-wait)');
1540
1746
  }
@@ -1544,7 +1750,7 @@ function execute(
1544
1750
  _step(7, total, `PR #${pr_info!['number']} already merged — skip`);
1545
1751
  } else {
1546
1752
  _step(7, total, 'Merge pull request (merge commit) and delete branch');
1547
- run(['gh', 'pr', 'merge', '--merge', '--delete-branch']);
1753
+ merge_release_pr(branch, wait_for_checks);
1548
1754
  }
1549
1755
 
1550
1756
  // ─── 8. tag main + push tag ─────────────────────────────────────────────
@@ -2135,6 +2341,7 @@ export {
2135
2341
  _cap_body,
2136
2342
  prepend_changelog,
2137
2343
  set_package_version,
2344
+ set_lockfile_version,
2138
2345
  set_marketplace_version,
2139
2346
  set_template_pin,
2140
2347
  resolve_bump,
@@ -0,0 +1,4 @@
1
+ /** Type declarations for router_target_paths.mjs (the shared kind→path table). */
2
+ export declare const ROUTE_TARGET_TEMPLATES: Readonly<Record<string, readonly string[]>>;
3
+ export declare function parseRouteTarget(target: string): { kind: string; id: string } | null;
4
+ export declare function routeTargetPathsPosix(target: string): string[];
@@ -0,0 +1,69 @@
1
+ /**
2
+ * router_target_paths.mjs — the ONE kind→path table for `dist/router.json`
3
+ * `routes_to` targets.
4
+ *
5
+ * Two consumers read it and they must not disagree:
6
+ * * `src/scripts/_cli/cmd_conformance.ts::routeTargetPaths` — resolves a
7
+ * pointer against the INSTALLED package tree at runtime.
8
+ * * `src/scripts/prepack-check.mjs` gate 4 — asserts the same pointer lands
9
+ * inside the `files[]` whitelist BEFORE the tarball is built.
10
+ *
11
+ * A copied table would let one side ship a target the other cannot see, which
12
+ * is exactly the packaging↔runtime gap the pack gate exists to close
13
+ * (road-to-gates-that-can-fail Phase 4). Plain `.mjs` because `prepack-check`
14
+ * runs as raw Node during the npm lifecycle and cannot load TypeScript; the
15
+ * TS side reads the sibling `router_target_paths.d.mts` declarations. Same
16
+ * shape as `prepack_lifecycle_check.mjs`.
17
+ *
18
+ * Templates are POSIX-relative with a single `{id}` placeholder. Callers that
19
+ * need platform separators split on `/` and `path.join` the segments.
20
+ */
21
+
22
+ /**
23
+ * Candidate homes per target kind, in resolution order — the FIRST existing
24
+ * candidate wins.
25
+ *
26
+ * `contract:` has two legitimate homes in the shipped tree: the public
27
+ * contract pages under `docs/contracts/` (per the rule-router contract) and
28
+ * the agent-facing contract contexts under
29
+ * `dist/agent-src/contexts/contracts/` (e.g. artifact-engagement-flow).
30
+ */
31
+ export const ROUTE_TARGET_TEMPLATES = Object.freeze({
32
+ skill: Object.freeze(['dist/agent-src/skills/{id}/SKILL.md']),
33
+ command: Object.freeze(['dist/agent-src/commands/{id}.md']),
34
+ guideline: Object.freeze(['docs/guidelines/{id}.md']),
35
+ contract: Object.freeze([
36
+ 'docs/contracts/{id}.md',
37
+ 'dist/agent-src/contexts/contracts/{id}.md',
38
+ ]),
39
+ });
40
+
41
+ /**
42
+ * Split a `<kind>:<id>` target. Returns `null` for a malformed target (no
43
+ * colon, empty kind, empty id, or an unknown kind).
44
+ *
45
+ * @param {string} target
46
+ * @returns {{ kind: string, id: string } | null}
47
+ */
48
+ export function parseRouteTarget(target) {
49
+ const sep = target.indexOf(':');
50
+ if (sep <= 0) return null;
51
+ const kind = target.slice(0, sep);
52
+ const id = target.slice(sep + 1);
53
+ if (!id) return null;
54
+ if (!Object.prototype.hasOwnProperty.call(ROUTE_TARGET_TEMPLATES, kind)) return null;
55
+ return { kind, id };
56
+ }
57
+
58
+ /**
59
+ * POSIX package-relative candidate paths for one `routes_to` target.
60
+ * Empty array = the target is unparseable or its kind is unknown.
61
+ *
62
+ * @param {string} target
63
+ * @returns {string[]}
64
+ */
65
+ export function routeTargetPathsPosix(target) {
66
+ const parsed = parseRouteTarget(target);
67
+ if (parsed === null) return [];
68
+ return ROUTE_TARGET_TEMPLATES[parsed.kind].map((tpl) => tpl.replace('{id}', parsed.id));
69
+ }
@@ -183,6 +183,57 @@ function _fnmatch(name: string, pat: string): boolean {
183
183
  // ── Trigger matching ─────────────────────────────────────────────────────
184
184
 
185
185
  /** Apply one trigger to a prompt + context; return True on match. */
186
+ /** Unicode word character — letters, digits, underscore (incl. umlauts). */
187
+ const _WORD_CHAR = /[\p{L}\p{N}_]/u;
188
+
189
+ function _isWordChar(c: string | undefined): boolean {
190
+ return c !== undefined && _WORD_CHAR.test(c);
191
+ }
192
+
193
+ /**
194
+ * Word-boundary-anchored keyword match (road-to-tested-routing Phase 3).
195
+ *
196
+ * A `keyword` occurrence counts only when its word-character edges sit on
197
+ * word boundaries: `ac` no longer fires inside "black", `plan` no longer
198
+ * fires inside "planet". Two deliberate reliefs:
199
+ *
200
+ * - An edge that is itself a NON-word character (e.g. `__()`, `/image:`,
201
+ * `trans(`, an emoji) carries no boundary requirement on that side —
202
+ * punctuation-shaped keywords keep their exact substring semantics.
203
+ * - The right boundary accepts one optional plural `s` ("icons", "options",
204
+ * "secrets" still fire their singular keyword). Richer inflection (German
205
+ * verb endings: "implementiere", "committen") is a DOCUMENTED accepted
206
+ * recall cost of anchoring — the matrices carry standalone-token phrasings
207
+ * for those languages instead.
208
+ *
209
+ * `phrase` deliberately stays unanchored substring; since this change the
210
+ * two trigger kinds genuinely differ.
211
+ */
212
+ export function keyword_matches_anchored(prompt_lower: string, kw_lower: string): boolean {
213
+ if (kw_lower === "") {
214
+ return false;
215
+ }
216
+ const needLeft = _isWordChar(kw_lower[0]);
217
+ const needRight = _isWordChar(kw_lower[kw_lower.length - 1]);
218
+ let idx = prompt_lower.indexOf(kw_lower);
219
+ while (idx !== -1) {
220
+ const leftOk = !needLeft || !_isWordChar(prompt_lower[idx - 1]);
221
+ let rightOk = true;
222
+ if (needRight) {
223
+ let end = idx + kw_lower.length;
224
+ if (prompt_lower[end] === "s") {
225
+ end += 1; // optional plural `s`
226
+ }
227
+ rightOk = !_isWordChar(prompt_lower[end]);
228
+ }
229
+ if (leftOk && rightOk) {
230
+ return true;
231
+ }
232
+ idx = prompt_lower.indexOf(kw_lower, idx + 1);
233
+ }
234
+ return false;
235
+ }
236
+
186
237
  export function trigger_matches(
187
238
  trigger: Trigger,
188
239
  prompt: string,
@@ -191,7 +242,7 @@ export function trigger_matches(
191
242
  ): boolean {
192
243
  const prompt_lower = prompt.toLowerCase();
193
244
  if ("keyword" in trigger) {
194
- return prompt_lower.includes(String(trigger["keyword"]).toLowerCase());
245
+ return keyword_matches_anchored(prompt_lower, String(trigger["keyword"]).toLowerCase());
195
246
  }
196
247
  if ("phrase" in trigger) {
197
248
  return prompt_lower.includes(String(trigger["phrase"]).toLowerCase());