@event4u/agent-config 14.21.0 → 14.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +164 -187
- package/CREDITS.md +37 -0
- package/README.md +1 -1
- package/dist/agent-src/commands/analyze/inbox.md +380 -5
- package/dist/agent-src/commands/analyze/repo.md +4 -2
- package/dist/agent-src/commands/pr/merge.md +47 -38
- package/dist/agent-src/commands/roadmap/next.md +8 -0
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +69 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -5
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +12 -0
- package/dist/agent-src/rules/external-code-graph-interop.md +19 -14
- package/dist/agent-src/rules/notes-first-reasoning.md +36 -25
- package/dist/agent-src/rules/token-efficiency.md +26 -3
- package/dist/agent-src/scripts/_cli_entry.ts +51 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +120 -27
- package/dist/agent-src/scripts/roadmap_gates.ts +4 -20
- package/dist/agent-src/scripts/roadmap_set_step.ts +5 -2
- package/dist/agent-src/scripts/stubs_due.ts +4 -18
- package/dist/agent-src/scripts/update_roadmap_progress.ts +7 -24
- package/dist/agent-src/skills/code-intelligence/SKILL.md +82 -1
- package/dist/agent-src/skills/git-workflow/references/push-closes-its-loop.md +9 -0
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +17 -0
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +52 -2
- package/dist/agent-src/templates/agent-settings.md +0 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/cli/registry.js +1 -1
- package/dist/cli-delegate/_cli_entry.js +8 -0
- package/dist/cli-delegate/_lib/pin_resolver.js +170 -0
- package/dist/cli-delegate/archival_sweep.js +8 -0
- package/dist/cli-delegate/archive_completed_roadmaps.js +542 -0
- package/dist/cli-delegate/check_update_banner.js +923 -0
- package/dist/cli-delegate/{chunk-ZVBOHSVF.js → chunk-2KKXJW25.js} +23 -9
- package/dist/cli-delegate/chunk-5EK5WQN6.js +28 -0
- package/dist/cli-delegate/chunk-7XGD2OEU.js +96 -0
- package/dist/cli-delegate/chunk-DBH4AHDK.js +155 -0
- package/dist/cli-delegate/{chunk-4FS4WRXP.js → chunk-IAI3XL43.js} +15 -3
- package/dist/cli-delegate/chunk-JO25G5H7.js +20 -0
- package/dist/cli-delegate/{chunk-643Z7FIC.js → chunk-KCNTUSPI.js} +7 -1
- package/dist/cli-delegate/chunk-LTYVIY76.js +7961 -0
- package/dist/cli-delegate/chunk-QAJS5YWY.js +999 -0
- package/dist/cli-delegate/{chunk-YS6XTLEK.js → chunk-TYSY33MD.js} +56 -6
- package/dist/cli-delegate/chunk-ULET4BYS.js +328 -0
- package/dist/cli-delegate/chunk-YDQSHTD7.js +187 -0
- package/dist/cli-delegate/chunk-YWVXLR44.js +48 -0
- package/dist/cli-delegate/chunk-ZZQBUHFK.js +273 -0
- package/dist/cli-delegate/cmd_conformance.js +2 -2
- package/dist/cli-delegate/cmd_export.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +45 -13
- package/dist/cli-delegate/cmd_prune.js +2 -2
- package/dist/cli-delegate/cmd_session_recycle.js +4 -14
- package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +2 -2
- package/dist/cli-delegate/cmd_uninstall.js +2 -2
- package/dist/cli-delegate/cmd_validate.js +2 -2
- package/dist/cli-delegate/dashboard_mode.js +16 -0
- package/dist/cli-delegate/gate_budget.js +24 -0
- package/dist/cli-delegate/gate_execute.js +25 -0
- package/dist/cli-delegate/guarded_baseline.js +18 -0
- package/dist/cli-delegate/resume_probe.js +22 -0
- package/dist/cli-delegate/roadmap_gates.js +638 -0
- package/dist/cli-delegate/roadmap_set_step.js +173 -0
- package/dist/cli-delegate/stub_queue.js +47 -0
- package/dist/cli-delegate/stubs_due.js +38 -0
- package/dist/cli-delegate/ticket_bundles.js +59 -0
- package/dist/cli-delegate/update_roadmap_progress.js +60 -0
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +13 -13
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +1813 -946
- package/dist/install/claudeLayerCarriage.js +237 -0
- package/dist/install/claudePathsPlan.js +79 -0
- package/dist/install/hostLayerFingerprint.js +1 -1
- package/dist/install/install.mjs +21 -3
- package/dist/install/partitionEligibility.js +231 -117
- package/dist/install/ruleLayerPartition.js +10 -7
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +10870 -7641
- package/dist/scripts/_lib/lean_projection_mode.js +108 -0
- package/dist/scripts/_lib/router_match.js +243 -0
- package/dist/scripts/_lib/rule_injection.js +216 -0
- package/dist/scripts/condense.js +52 -45
- package/dist/scripts/project_thin_rules.js +139 -19
- package/dist/server/schemas/settings.js +16 -3
- package/docs/MIGRATION.md +105 -1
- package/docs/contracts/settings-classes.md +40 -8
- package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +73 -0
- package/docs/guidelines/agent-infra/notes-horizon-mechanics.md +90 -0
- package/llms.txt +1 -1
- package/package.json +7 -4
- package/src/agent-src/scripts/_cli_entry.ts +51 -0
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +120 -27
- package/src/agent-src/scripts/roadmap_gates.ts +4 -20
- package/src/agent-src/scripts/roadmap_set_step.ts +5 -2
- package/src/agent-src/scripts/stubs_due.ts +4 -18
- package/src/agent-src/scripts/update_roadmap_progress.ts +7 -24
- package/src/config/agent-settings.template.yml +47 -1
- package/src/config/continuity-surface.json +516 -0
- package/src/config/estate-count-budget.json +1 -1
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +29 -8
- package/src/config/gate-violation-baselines.json +8 -8
- package/src/config/gitignore-block.txt +19 -0
- package/src/config/hook-token-budget.json +7 -6
- package/src/config/host-injection-effect.json +73 -0
- package/src/config/packed-binary-manifest.json +33 -0
- package/src/config/preamble-payload-budget.json +112 -105
- package/src/config/publish-surface.json +4 -2
- package/src/config/routing-coverage-seed.json +9 -2
- package/src/install/claudeLayerCarriage.ts +273 -0
- package/src/install/claudePathsPlan.ts +76 -0
- package/src/install/hostLayerFingerprint.ts +1 -1
- package/src/install/partitionEligibility.ts +261 -127
- package/src/install/ruleLayerPartition.ts +19 -23
- package/src/scripts/_cli/cmd_session_recycle.ts +2 -25
- package/src/scripts/_cli/handoff_sessions.ts +14 -44
- package/src/scripts/_dispatch.bash +77 -27
- package/src/scripts/_lib/auto_dispatch.ts +2 -2
- package/src/scripts/_lib/catalogue_layer_parity.ts +146 -0
- package/src/scripts/_lib/continuity_slot.ts +295 -0
- package/src/scripts/_lib/continuity_surface.ts +296 -0
- package/src/scripts/_lib/continuity_writer.ts +253 -0
- package/src/scripts/_lib/corpus_manifest.ts +26 -9
- package/src/scripts/_lib/hook_settings.ts +86 -1
- package/src/scripts/_lib/injection_effect.ts +151 -0
- package/src/scripts/_lib/layer_overlap_notice.ts +50 -6
- package/src/scripts/_lib/lean_projection_mode.ts +127 -0
- package/src/scripts/_lib/packed_binary_predicate.ts +262 -0
- package/src/scripts/_lib/pin_resolver.ts +13 -0
- package/src/scripts/_lib/recycle_envelope_paths.ts +109 -21
- package/src/scripts/_lib/regression_neighbourhood.ts +159 -22
- package/src/scripts/_lib/retired_status.ts +74 -0
- package/src/scripts/_lib/session_eol.ts +44 -0
- package/src/scripts/_lib/session_index_trust.ts +346 -0
- package/src/scripts/_lib/skill_catalogue.ts +156 -21
- package/src/scripts/_lib/standing_bound_ratchet.ts +154 -0
- package/src/scripts/_lib/subagent_capsule.ts +117 -8
- package/src/scripts/_lib/vendored_grammar_upstream.ts +280 -0
- package/src/scripts/ai_council/api_transport.ts +5 -0
- package/src/scripts/ai_council/deliberation_metrics.ts +353 -0
- package/src/scripts/ai_council/prompts.ts +9 -0
- package/src/scripts/ai_council/synthesis_disagreement.ts +206 -0
- package/src/scripts/audit_mcp_tools.ts +69 -25
- package/src/scripts/build_mcp_catalog.ts +24 -1
- package/src/scripts/capture_skill_catalogue.ts +24 -11
- package/src/scripts/check_candidate_lines.ts +499 -0
- package/src/scripts/check_continuity_surface.ts +475 -0
- package/src/scripts/check_dependency_floors.ts +13 -6
- package/src/scripts/check_estate_count.ts +40 -79
- package/src/scripts/check_host_tree_parity.ts +291 -0
- package/src/scripts/check_pack_size.ts +262 -23
- package/src/scripts/check_preamble_payload_budget.ts +136 -7
- package/src/scripts/check_roadmap_trackable.ts +19 -16
- package/src/scripts/check_rule_layer_partition.ts +54 -34
- package/src/scripts/check_rule_projection_integrity.ts +102 -2
- package/src/scripts/check_single_delivery.ts +97 -31
- package/src/scripts/check_update_banner.ts +13 -0
- package/src/scripts/ci_settle.ts +205 -5
- package/src/scripts/code_graph/build.ts +217 -15
- package/src/scripts/code_graph/cli.ts +334 -15
- package/src/scripts/code_graph/detect.ts +38 -0
- package/src/scripts/code_graph/extract.ts +11 -0
- package/src/scripts/code_graph/grammar_probe.ts +43 -0
- package/src/scripts/code_graph/loader.ts +88 -14
- package/src/scripts/code_graph/query.ts +144 -11
- package/src/scripts/code_graph/resolution_tiers.ts +238 -0
- package/src/scripts/code_graph/sqlite_store.ts +262 -6
- package/src/scripts/code_graph/types.ts +117 -3
- package/src/scripts/code_graph/validate.ts +26 -1
- package/src/scripts/code_graph/verbs.ts +590 -0
- package/src/scripts/condense.ts +54 -42
- package/src/scripts/corpus_manifest.ts +5 -5
- package/src/scripts/council_cli.ts +11 -12
- package/src/scripts/count_intent_disagreement.ts +426 -0
- package/src/scripts/handoff_context_hook.ts +118 -1
- package/src/scripts/hook_effect_doctor.ts +82 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +87 -12
- package/src/scripts/hooks/block_speaking_inbox_dir.ts +182 -16
- package/src/scripts/hooks/chain_nudge_hook.ts +282 -0
- package/src/scripts/hooks/code_graph_context_hook.ts +201 -0
- package/src/scripts/hooks/concern_registry.ts +4 -2
- package/src/scripts/hooks/host_semantics.ts +1 -1
- package/src/scripts/hooks/orchestration_record_hook.ts +2 -2
- package/src/scripts/hooks/push_settle_hook.ts +3 -2
- package/src/scripts/hooks/rule_inject_hook.ts +108 -21
- package/src/scripts/hooks/session_eol_hook.ts +120 -2
- package/src/scripts/hooks/skill_route_hook.ts +11 -4
- package/src/scripts/hot_context_hook.ts +62 -7
- package/src/scripts/inbox_source_census.ts +322 -0
- package/src/scripts/install-hooks.sh +82 -0
- package/src/scripts/{lint_carrier_integrity.ts → lint_deferral_integrity.ts} +60 -214
- package/src/scripts/lint_plan_risk_register.ts +13 -17
- package/src/scripts/lint_roadmap_blockers.ts +164 -1
- package/src/scripts/mcp_server/consumer_tool_catalog.json +152 -2
- package/src/scripts/mcp_server/graph_tools.ts +294 -0
- package/src/scripts/mcp_server/path_util.ts +31 -0
- package/src/scripts/mcp_server/suggest_skill.ts +72 -0
- package/src/scripts/mcp_server/tool_catalog_source.ts +7 -1
- package/src/scripts/mcp_server/tools.ts +5 -69
- package/src/scripts/media/lib/adapter-contract.md +7 -2
- package/src/scripts/media/lib/fixtures/flux/asset-0001.png +0 -0
- package/src/scripts/media/lib/fixtures/gemini-image/asset-0001.png +0 -0
- package/src/scripts/media/lib/fixtures/ideogram/asset-0001.png +0 -0
- package/src/scripts/model_rule_injection.ts +61 -4
- package/src/scripts/project_thin_rules.ts +149 -16
- package/src/scripts/rdp_candidates_delta.ts +276 -0
- package/src/scripts/rdp_quality_eval.ts +217 -19
- package/src/scripts/release_mix_taxonomy.json +3 -2
- package/src/scripts/report_host_injection_effect.ts +189 -0
- package/src/scripts/report_layer_overlap.ts +41 -0
- package/src/scripts/report_skill_menu_census.ts +341 -0
- package/src/scripts/report_standing_payload_by_host.ts +650 -0
- package/src/scripts/schemas/agent-settings.schema.json +7 -1
- package/src/scripts/session_memory_index.ts +81 -8
- package/src/scripts/skill_tools/score_skill_relevance.ts +70 -6
- package/src/scripts/skill_tools/suggest_skill_for_task.ts +37 -3
- package/src/server/schemas/settings.ts +23 -4
- package/src/vendor/grammars/README.md +86 -0
- package/src/vendor/grammars/tree-sitter-javascript.wasm +0 -0
- package/src/vendor/grammars/tree-sitter-php.wasm +0 -0
- package/src/vendor/grammars/tree-sitter-typescript.wasm +0 -0
- package/src/scripts/_lib/carrier_status.ts +0 -118
- package/src/scripts/_lib/estate_carrier_cases.ts +0 -72
- package/src/scripts/hooks/code_graph_nudge_hook.ts +0 -191
|
@@ -247,8 +247,33 @@ dispatch runs, not WHETHER the layer exists, so they keep their own C rows.
|
|
|
247
247
|
|---|---|
|
|
248
248
|
| A — preference | 26 |
|
|
249
249
|
| B — consent | 3 |
|
|
250
|
-
| C — guarded |
|
|
251
|
-
| **Total** | **
|
|
250
|
+
| C — guarded | 113 |
|
|
251
|
+
| **Total** | **142** |
|
|
252
|
+
|
|
253
|
+
It rose to 142 on 2026-09-08 from two independent additions that landed in the same
|
|
254
|
+
day and are counted together here: `lean_projection.hosts` (one C, `policy`, from
|
|
255
|
+
`road-to-delivery-for-every-host`) and the two continuity keys below. The merge that
|
|
256
|
+
combined them re-derived the total from the class table rather than adding either
|
|
257
|
+
side's figure to the other, which is the arithmetic `lint_settings_classes` checks.
|
|
258
|
+
|
|
259
|
+
It rose on 2026-09-08 when `road-to-continuity-writer-activation`
|
|
260
|
+
step 1.2 added `continuity.auto_record` — one C, `consent`: it arms an automatic
|
|
261
|
+
producer on the normal session-end path, and the roadmap step requires the
|
|
262
|
+
default to stay `off` until parity is measured, which is a decision no agent may
|
|
263
|
+
take by writing the key. Step 1.4 added
|
|
264
|
+
`continuity.run_checkpoints` the same day — a second C, shipping `on` because
|
|
265
|
+
that is the behavior the tree already had. It exists so the three session-end
|
|
266
|
+
handlers are independently disableable, which is what the 2026-09-07 council's
|
|
267
|
+
D2 asked for; it changes nothing that ships.
|
|
268
|
+
|
|
269
|
+
Its disposition is `consent`, and `derivable` was considered first and rejected:
|
|
270
|
+
`derivable` is the **deletion queue**, a claim that the key disappears once the
|
|
271
|
+
mechanism it names exists. This one is an operator kill switch over a recovery
|
|
272
|
+
artifact, so it is meant to survive — and nothing in the tree can derive whether
|
|
273
|
+
an operator wants resumability traded for quiet. It sits in the same shape as the
|
|
274
|
+
kill switches already classified `consent` (`knowledge.global_sharing.enabled`
|
|
275
|
+
and its allowlist): the mechanism's own preconditions are computable, the
|
|
276
|
+
operator's decision to suppress it is not.
|
|
252
277
|
|
|
253
278
|
The total was 140 until 2026-08-12, when five of the six keys no code path read were
|
|
254
279
|
deleted, minus the one held open (§ The six unread keys, below): one A
|
|
@@ -338,9 +363,9 @@ the template, which is the drift this contract exists to prevent.
|
|
|
338
363
|
|---|---|
|
|
339
364
|
| derivable | 83 |
|
|
340
365
|
| un-inferrable | 9 |
|
|
341
|
-
| consent |
|
|
342
|
-
| policy |
|
|
343
|
-
| **Total** | **
|
|
366
|
+
| consent | 43 |
|
|
367
|
+
| policy | 7 |
|
|
368
|
+
| **Total** | **142** |
|
|
344
369
|
|
|
345
370
|
First measured 2026-08-12 at 140 leaves (derivable 88 · consent 38 ·
|
|
346
371
|
un-inferrable 9 · policy 5), from the table below rather than predicted — the
|
|
@@ -355,8 +380,12 @@ mechanism it names actually exists, so 83 measures work outstanding, not keys
|
|
|
355
380
|
about to disappear. The count is expected to fall while `un-inferrable` does not
|
|
356
381
|
— those 9 plus whatever survives re-examination in `consent` are the floor this
|
|
357
382
|
surface has, and stating it is the point. `policy` is the smallest class and the
|
|
358
|
-
only one whose action is a *move* rather than a keep or a delete:
|
|
359
|
-
a project fact the tree could hold instead.
|
|
383
|
+
only one whose action is a *move* rather than a keep or a delete: seven keys carry
|
|
384
|
+
a project fact the tree could hold instead. (This sentence read "five" while the
|
|
385
|
+
counts table beside it read 6, and 2026-09-08 added `lean_projection.hosts` as the
|
|
386
|
+
seventh — corrected in both directions rather than only incremented, because a
|
|
387
|
+
prose number that disagrees with a computed one beside it is the exact defect
|
|
388
|
+
`lint_settings_classes` fails the two Total rows for.)
|
|
360
389
|
|
|
361
390
|
## The floor — the nine keys no mechanism can derive
|
|
362
391
|
|
|
@@ -440,6 +469,7 @@ Rows follow template order, so a diff against the template reads straight down.
|
|
|
440
469
|
| `discipline_profile` | C | `__DISCIPLINE_PROFILE__` | master switch for the discipline rule tier | derivable — its own `auto` resolution against `src/config/host-capabilities.yml` |
|
|
441
470
|
| `rule_loading_tier` | C | `__RULE_LOADING_TIER__` | legacy master switch for rule loading | derivable — `discipline_profile` supersedes it with a documented mapping (minimal→off, balanced→essential, full→full) |
|
|
442
471
|
| `lean_projection.mode` | C | `eager-all` | `thin` removes rule bodies from the agent's context | derivable — `probe_host_compliance.ts` already computes the per-host thin/eager recommendation |
|
|
472
|
+
| `lean_projection.hosts` | C | `[claude-code]` | decides WHICH hosts a thinning mode may thin, so an added id removes rule bodies from that host's context | policy — the value is a package-level decision the tree already holds: ADR-267 scopes the shipped `delivery` flip to `claude-code` alone. NOT `derivable`, and the distinction is the whole reason for this row: the mechanism that would compute an admissible host set, `admissibleUnderE3` in `src/scripts/_lib/injection_effect.ts`, admits **nothing** today — `src/config/host-injection-effect.json` carries 1 `observed-false` and 8 `unobserved` rows and no `observed-true` — so a derivation would yield `[]` rather than the shipped `[claude-code]`. Naming a mechanism that returns empty as the replacement would put a key in the deletion queue whose deletion would silently change the default. Move target: the ADR plus that census, once a host earns an `observed-true` row |
|
|
443
473
|
| `telegraph.speak` | C | `false` | ships a rule body; a token-cost lever in both directions | derivable — the telegraph kill-criterion bench verdict is a package-level decision, not a per-install one |
|
|
444
474
|
| `tokens.rich_skills` | C | `"on"` | token-spend lever | derivable — the skill's own `token_budget_class: rich` declaration plus the CI ceiling in `lint_token_budget_discipline.ts` |
|
|
445
475
|
| `cost.budgets.daily` | C | `0` | rolling spend ceiling | consent |
|
|
@@ -537,6 +567,8 @@ Rows follow template order, so a diff against the template reads straight down.
|
|
|
537
567
|
| `commands.create_pr.screenshots` | C | `false` | puts captured screenshots into a published PR body | consent |
|
|
538
568
|
| `commands.create_pr.ui_paths` | C | `[]` | glob allowlist | derivable — the frontend-surface heuristic the PR-description flow already applies when the glob list is empty |
|
|
539
569
|
| `commands.create_pr.api_paths` | C | `[]` | glob allowlist | derivable — the API-endpoint heuristic the same flow already applies as its documented empty-list fallback |
|
|
570
|
+
| `continuity.auto_record` | C | `"off"` | arms an automatic producer on the normal session-end path | consent |
|
|
571
|
+
| `continuity.run_checkpoints` | C | `"on"` | disabling it removes a recovery artifact a killed run resumes from | consent |
|
|
540
572
|
| `memory.cadence` | C | `always` | suppressing the visibility line hides what the agent learned from the user | derivable — the hits/asks count the memory-visibility summary already computes; the line only exists when memory was consulted |
|
|
541
573
|
| `memory.review_threshold` | A | `10` | when a review preview surfaces; governs no gate | derivable — the unreviewed-intake count `/memory load` already computes before rendering its preview |
|
|
542
574
|
| `memory.redact_patterns` | C | `[]` | deny-list of secret and PII regexes | policy |
|
|
@@ -558,7 +590,7 @@ Rows follow template order, so a diff against the template reads straight down.
|
|
|
558
590
|
| `hooks.runtime_journal.enabled` | C | `false` | configures code that runs on every dispatched hook event | consent |
|
|
559
591
|
| `hooks.ui_route_nudge.enabled` | C | `false` | configures code that runs on every tool call | derivable — the UI-surface predicate plus the hook's own two-nudges-per-session cap |
|
|
560
592
|
| `hooks.design_pass.enabled` | C | `false` | C-test 1 — it configures code that runs on every tool call and at every turn end, and unlike its two `hooks.*` neighbours its stop pass can BLOCK rather than warn | policy — whether an operator accepts a gate that can refuse a turn is a risk preference, not a fact the tree can compute. The two neighbours are `derivable` because they only ever warn; the block is the discriminator. `road-to-frontend-power` transfers the default flip to the owner for the same reason |
|
|
561
|
-
| `hooks.code_graph.enabled` | C | `false` |
|
|
593
|
+
| `hooks.code_graph.enabled` | C | `false` | INERT since 2026-09-07 — the nudge it gated was replaced by `code-graph-context`, which reads no flag. The KEY stays registered because `docs/MIGRATION.md` commits to exactly that ("the surfaces stay registered and disabled"): removing it is a breaking change for any consumer who set it, and the row was briefly marked REMOVED, which left the template's own leaf unclassified. Classified, not deleted. | derivable — the index-detection probe the replacement hook already runs; no index means silence |
|
|
562
594
|
| `hooks.suggestion_capture.enabled` | C | `false` | configures code that runs at every turn end and every prompt | consent |
|
|
563
595
|
| `decision_engine.surface_traces` | C | `false` | the decision engine’s own black box; the agent must not be able to close it | derivable — the engine's own active-gate state; there is nothing to surface when no gate fired |
|
|
564
596
|
| `decision_engine.min_confidence` | C | `"off"` | the confidence gate | derivable — the confidence band the scoring engine already computes at the plan phase |
|
|
@@ -166,3 +166,76 @@ reviewer has to untangle.
|
|
|
166
166
|
|
|
167
167
|
- `minimal-safe-diff` (rule) — Iron Law, the rule, the pre-fix shared-path repair clause, own-orphan cleanup. The pre-diff checklist, the red-flag catalog and the when-in-doubt line live HERE since A1.
|
|
168
168
|
- [`active-remediation-mechanics`](active-remediation-mechanics.md) — the fix-now / note+ask / follow-up-PR ladder detail.
|
|
169
|
+
|
|
170
|
+
## Re-derive the requirement, don't inherit the shape
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
A REPAIR INHERITS THE SHAPE OF WHAT IT REPAIRS UNLESS YOU ASK OTHERWISE.
|
|
174
|
+
STATE THE REQUIREMENT IN ONE LINE, THEN ASK WHETHER THE CURRENT FORM
|
|
175
|
+
*CAN* EXPRESS IT. A FORM THAT CANNOT IS NOT A PARAMETER BUG.
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Applies to a downstream repair — clearing a red, or fixing what your own diff
|
|
179
|
+
broke — where the smallest change is a different VALUE and the form is
|
|
180
|
+
unexamined.
|
|
181
|
+
|
|
182
|
+
### Why this is a guideline section and not a rule clause
|
|
183
|
+
|
|
184
|
+
It was drafted as a clause in `minimal-safe-diff` on 2026-09-07 and moved here
|
|
185
|
+
the same day, on the gate's own evidence rather than on preference.
|
|
186
|
+
`check_preamble_payload_budget` measured the clause at +460 delivered tokens,
|
|
187
|
+
then +271, then +180 after two rounds of cutting — a floor set by the Iron-Law
|
|
188
|
+
block itself. That payload is re-written on EVERY subagent spawn, and the rule it
|
|
189
|
+
would have lived in is `type: auto`: it fires on prompt keywords, not on tool
|
|
190
|
+
output, so a red test nobody mentioned never loads it.
|
|
191
|
+
|
|
192
|
+
Certain per-spawn cost against an activation path that misses the case the clause
|
|
193
|
+
was written for is a bad trade, and the deterministic half does not depend on it
|
|
194
|
+
— see § Honest limit below. The rule already routes here
|
|
195
|
+
(`routes_to: guideline:agent-infra/minimal-safe-diff-mechanics`), which is the
|
|
196
|
+
same reachability every other migrated body in this repository has.
|
|
197
|
+
|
|
198
|
+
### Worked failure — 2026-09-07
|
|
199
|
+
|
|
200
|
+
A change emptied `<repo>/.claude/skills` of skills and left ~49 flat-command
|
|
201
|
+
wrappers behind. `resolveSkillsRoot` tried two workspace-relative roots and took
|
|
202
|
+
the first non-empty one, so it resolved the wrappers, and the skill ranker ranked
|
|
203
|
+
49 command wrappers instead of 299 skills.
|
|
204
|
+
|
|
205
|
+
The repair chosen was to swap the ORDER of the two roots. The requirement was
|
|
206
|
+
*"rank every catalogue the session can reach"*, which **no ordering of a
|
|
207
|
+
first-hit loop can satisfy** — and the host-global root the whole task was about
|
|
208
|
+
appeared in neither position. The evidence had been measured an hour earlier and
|
|
209
|
+
sat in the same session's own notes: `~/.claude/skills` 307, `.claude/skills` 49,
|
|
210
|
+
`src/skills` 299.
|
|
211
|
+
|
|
212
|
+
Two things made it easy to miss, and both are the shape of the trap rather than
|
|
213
|
+
this instance of it:
|
|
214
|
+
|
|
215
|
+
- **The docstring framed the question.** It read *"First existing catalogue root
|
|
216
|
+
… `.claude/skills` before `src/skills` because a CONSUMER install carries the
|
|
217
|
+
former"* — i.e. it asked *which root wins*, and that question was answered. A
|
|
218
|
+
docstring records what the code decided; it never records whether that was the
|
|
219
|
+
decision to make.
|
|
220
|
+
- **The same docstring contained the premise of the correct answer.** If
|
|
221
|
+
consumers carry their own skills *and* the package ships skills, both must be
|
|
222
|
+
read. The sentence was read, used to justify an ordering, and its consequence
|
|
223
|
+
was not drawn.
|
|
224
|
+
|
|
225
|
+
### Why the pre-work rules do not cover it
|
|
226
|
+
|
|
227
|
+
[`improve-before-implement`](../../../src/rules/improve-before-implement.md) does
|
|
228
|
+
not activate for bug fixes ("the problem is already defined") and
|
|
229
|
+
[`invite-challenge`](../../../src/rules/invite-challenge.md) excludes "evidenced
|
|
230
|
+
bug fixes". Both exclusions are right for the case they were written for and
|
|
231
|
+
wrong for a downstream repair, which presents as a defined problem while its
|
|
232
|
+
definition came from the broken code.
|
|
233
|
+
|
|
234
|
+
### Honest limit
|
|
235
|
+
|
|
236
|
+
The rule is `type: auto`, so it fires on prompt keywords and not on tool output:
|
|
237
|
+
a red test nobody prompted about does not load it. The clause is the
|
|
238
|
+
model-carried half. The deterministic half is a comparison of the two lists that
|
|
239
|
+
diverged — `tests/contracts/catalogue_layer_parity.test.ts`, which reds when a
|
|
240
|
+
directory the delivery side treats as an artifact source is not a root the reader
|
|
241
|
+
reads, and which was measured to catch this exact defect on the pre-change tree.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Notes-first reasoning — horizon and reopening mechanics
|
|
2
|
+
|
|
3
|
+
Migrated out of [`notes-first-reasoning`](../../../src/rules/notes-first-reasoning.md)
|
|
4
|
+
on 2026-09-08. That rule is delivered on **every subagent spawn**, so its body is
|
|
5
|
+
paid per spawn; this material is reference read on demand. Nothing was dropped —
|
|
6
|
+
the four passages below are the rule's own text, verbatim, and the rule keeps
|
|
7
|
+
both Iron Laws and points here.
|
|
8
|
+
|
|
9
|
+
Same reason, and the same remedy, as the 2026-08-29 drain run recorded for
|
|
10
|
+
`source-confidentiality`: the addition had no room under the per-spawn ceiling,
|
|
11
|
+
and raising that ceiling is the config-weakening move this repository refuses.
|
|
12
|
+
|
|
13
|
+
### Why reasoning stays out of the reply, and what grounds the notes file
|
|
14
|
+
|
|
15
|
+
Reasoning dumped into the user-facing answer is both noise and a
|
|
16
|
+
`reasoning_extraction` refusal risk (see `rdp-gate`). Keep it in the notes file.
|
|
17
|
+
|
|
18
|
+
The notes file is grounded in the documented cross-run lessons memory
|
|
19
|
+
(consolidated via [`memory-consolidation`](../../../src/skills/memory-consolidation/SKILL.md));
|
|
20
|
+
the rule's in-task sections are a local derivation for within-task scope. The
|
|
21
|
+
gate itself reads settings + task-signal + host self-assessment.
|
|
22
|
+
|
|
23
|
+
### The two section fields, in full
|
|
24
|
+
|
|
25
|
+
The rule lists the sections and no count. That is deliberate: the structure
|
|
26
|
+
carries the enumeration, so there is no "write N hypotheses" instruction to
|
|
27
|
+
follow — a run records what the work actually surfaced, and an empty section is
|
|
28
|
+
a fact about the work rather than a gap in the notes.
|
|
29
|
+
|
|
30
|
+
`## Predictions` carries **chosen form** · prediction · confidence · result ·
|
|
31
|
+
lesson — the calibration loop: hypothesis → prediction → reality →
|
|
32
|
+
calibration. The form is named first because a prediction with no subject
|
|
33
|
+
cannot be contradicted: when the observation comes back, "the prediction
|
|
34
|
+
missed" has to point at *what* it was a prediction about, or nothing reopens.
|
|
35
|
+
|
|
36
|
+
`## Decisions` escalates to
|
|
37
|
+
[`decision-record`](../../../src/skills/decision-record/SKILL.md)/ADR when the
|
|
38
|
+
decision is cross-task or architectural — litmus: would a dev on a different
|
|
39
|
+
component next month need this context? And `next-commitment` is the boundary
|
|
40
|
+
this choice authorises work up to, not the plan for it: choosing a form is not
|
|
41
|
+
permission to execute a twelve-step plan on it without re-reading the position.
|
|
42
|
+
|
|
43
|
+
### The horizon — which boundaries count
|
|
44
|
+
|
|
45
|
+
The boundary is the nearest of these that the plan actually reaches: a **test
|
|
46
|
+
result** · a **type or schema inspection** · a **compile** · a **runtime probe**
|
|
47
|
+
· a **call-site inventory** · a **dry run** · a **browser observation** · a
|
|
48
|
+
**dependency-contract read**. The set is enumerable, which is the whole point —
|
|
49
|
+
"the work up to the nearest of those" is decidable from the plan, and `next
|
|
50
|
+
justified commitment` as prose degrades to *"implement solution"*, which is the
|
|
51
|
+
starting point wearing a label.
|
|
52
|
+
|
|
53
|
+
### Width scales with reversibility, never with task size
|
|
54
|
+
|
|
55
|
+
| The action is… | The horizon runs to… |
|
|
56
|
+
|---|---|
|
|
57
|
+
| a reversible local edit | a whole implementation slice — stopping at the first boundary costs more than it saves |
|
|
58
|
+
| stateful or cross-layer | the next boundary from the list above |
|
|
59
|
+
| irreversible or a public contract | **before** the irreversible step, unless direct evidence already covers it |
|
|
60
|
+
|
|
61
|
+
### The look-ahead ladder is a CEILING, never a quota
|
|
62
|
+
|
|
63
|
+
Three to five moves is the *maximum*, and only for a forcing, irreversible or
|
|
64
|
+
externally observable line. Stateful or cross-layer gets two to three. A quiet
|
|
65
|
+
reversible line gets **one, deliberately** — and no artifact anywhere requires a
|
|
66
|
+
minimum depth. Always-three-to-five across all variants is 1024 leaves at four
|
|
67
|
+
branches and depth five, which buys nothing and costs the run its budget.
|
|
68
|
+
|
|
69
|
+
### Reopening — the two consequences
|
|
70
|
+
|
|
71
|
+
A reopen driven by ritual rather than by contradicting evidence is ceremony, and
|
|
72
|
+
an uncapped reopen is a loop with better manners. Two consequences:
|
|
73
|
+
|
|
74
|
+
- **A rejection whose premise is falsified is not a rejection.** A candidate
|
|
75
|
+
killed by an assumption that later turns out false is *un-evaluated*, not
|
|
76
|
+
dead — it returns to the set. That is what makes a stated `killed-if`
|
|
77
|
+
condition worth carrying: without it, "we ruled that out" is unfalsifiable.
|
|
78
|
+
- **The first failure reads the candidate list before the retry**, where one
|
|
79
|
+
exists — see [`autonomy-mechanics`](../../../src/agent-src/contexts/execution/autonomy-mechanics.md)
|
|
80
|
+
§ Retry-budget escalation ladder. Where none exists the ladder is unchanged.
|
|
81
|
+
This adds a branch; it does not move the N=3 budget.
|
|
82
|
+
|
|
83
|
+
## See also
|
|
84
|
+
|
|
85
|
+
- [`notes-first-reasoning`](../../../src/rules/notes-first-reasoning.md) — the
|
|
86
|
+
rule this material was paid for in, and which keeps both Iron Laws.
|
|
87
|
+
- [`rdp-gate`](../../../src/agent-src/contexts/execution/rdp-gate.md) — the
|
|
88
|
+
engagement gate that decides whether the notes discipline runs at all.
|
|
89
|
+
- [`decision-record`](../../../src/skills/decision-record/SKILL.md) — where a
|
|
90
|
+
cross-task or architectural decision escalates to.
|
package/llms.txt
CHANGED
|
@@ -41,7 +41,7 @@ canvas-design: Creating static visual art — posters, marketing visuals, brand
|
|
|
41
41
|
character-consistency: Use when a character must stay visually identical across AI video scenes — locks identity tokens (silhouette, palette, wardrobe, prop) in JSON. Triggers 'character lock', 'same character'.
|
|
42
42
|
check-refs: Use when verifying cross-references between skills, rules, commands, guidelines, and context documents are not broken after edits, renames, or deletions.
|
|
43
43
|
churn-prevention: Use when designing churn defence — health-score signals, churn-cause split (involuntary / value / relationship / fit), early-warning loop. Triggers on 'why are accounts leaving'.
|
|
44
|
-
code-intelligence: Route codebase-structure questions (who calls X, where
|
|
44
|
+
code-intelligence: Route codebase-structure questions (who calls X, where used, change-impact) to an existing code-graph first: impact, tests-for, dead cheaper, never more precise; grep routine. Also 'call graph'.
|
|
45
45
|
code-refactoring: When the user says 'refactor this', 'rename class', or 'move method'. Safely refactors code in any language — finds all callers, updates downstream dependencies, verifies via quality tools.
|
|
46
46
|
code-review: Use when the user says \"review this\", \"check my code\", or wants feedback on changes. Reviews for correctness, quality, security, and coding standards.
|
|
47
47
|
command-routing: Use when the user invokes a slash command like /create-pr, /commit, /fix-ci, or pastes command file content — routes to the right command with context inference and GitHub API patterns.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@event4u/agent-config",
|
|
3
3
|
"mcpName": "io.github.event4u-app/agent-config",
|
|
4
|
-
"version": "14.
|
|
4
|
+
"version": "14.23.0",
|
|
5
5
|
"description": "Governed skills, rules and commands for AI coding tools (Claude Code, Cursor, Windsurf, Copilot) — every claim machine-checked, including the counts in these badges.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"private": false,
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"src/agent-src/scripts/",
|
|
49
49
|
"src/agent-src/templates/scripts/",
|
|
50
50
|
"src/templates/",
|
|
51
|
+
"src/vendor/grammars/",
|
|
51
52
|
"tests/fixtures/hooks/",
|
|
52
53
|
"AGENTS.md",
|
|
53
54
|
"CHANGELOG.md",
|
|
@@ -80,13 +81,15 @@
|
|
|
80
81
|
"build:hooks": "esbuild src/scripts/hooks/dispatch_entry.ts --bundle --platform=node --format=esm --target=node20 --define:__AGENT_CONFIG_BUNDLE__=true --outfile=dist/hooks/dispatch.js --banner:js=\"import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url); const __acPath = require('node:path'); const __acFs = require('node:fs'); const __acUrl = require('node:url'); const __acReal = (p) => { try { return __acFs.realpathSync(p); } catch { return p; } }; const __acSelf = __acReal(__acUrl.fileURLToPath(import.meta.url)); if (process.argv[1] !== undefined && __acReal(__acPath.resolve(process.argv[1])) === __acSelf) { globalThis.__AC_HOOKS_BUNDLE_DIRECT = true; process.argv = [process.argv[0], __acSelf + '.__direct__', ...process.argv.slice(2)]; }\"",
|
|
81
82
|
"build:mcp-bundle": "esbuild src/scripts/mcp_server/__main__.ts --bundle --platform=node --format=esm --target=node20 --define:__AGENT_CONFIG_BUNDLE__=true --outfile=dist/mcp/server.mjs --banner:js=\"import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url); const __acPath = require('node:path'); const __acFs = require('node:fs'); const __acUrl = require('node:url'); const __acReal = (p) => { try { return __acFs.realpathSync(p); } catch { return p; } }; const __acSelf = __acReal(__acUrl.fileURLToPath(import.meta.url)); if (process.argv[1] !== undefined && __acReal(__acPath.resolve(process.argv[1])) === __acSelf) { globalThis.__AC_MCP_BUNDLE_DIRECT = true; process.argv = [process.argv[0], __acSelf + '.__direct__', ...process.argv.slice(2)]; }\"",
|
|
82
83
|
"build:cli-delegate": "esbuild src/scripts/_cli/cmd_*.ts --bundle --splitting --platform=node --format=esm --target=node20 --define:__AGENT_CONFIG_BUNDLE__=true --define:__AGENT_CONFIG_CLI_DELEGATE__=true --outdir=dist/cli-delegate --banner:js=\"import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);\"",
|
|
84
|
+
"build:agent-src-delegate": "esbuild src/agent-src/scripts/*.ts --bundle --splitting --platform=node --format=esm --target=node20 --define:__AGENT_CONFIG_BUNDLE__=true --define:__AGENT_CONFIG_CLI_DELEGATE__=true --outdir=dist/cli-delegate --banner:js=\"import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);\"",
|
|
85
|
+
"build:delegate-aux": "esbuild src/scripts/_lib/pin_resolver.ts src/scripts/check_update_banner.ts --bundle --splitting --platform=node --format=esm --target=node20 --define:__AGENT_CONFIG_BUNDLE__=true --define:__AGENT_CONFIG_CLI_DELEGATE__=true --outbase=src/scripts --outdir=dist/cli-delegate --banner:js=\"import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);\"",
|
|
83
86
|
"build:ui": "vite build",
|
|
84
87
|
"tokens:build": "node tokens/build-ac.mjs && node tokens/build-as.mjs",
|
|
85
88
|
"tokens:check": "node tokens/build-ac.mjs --check && node tokens/build-as.mjs --check && node tokens/check-contrast.mjs",
|
|
86
89
|
"build:discovery": "./scripts-run src/scripts/build_discovery_manifest --write --strict",
|
|
87
90
|
"build:mcp-manifest": "./scripts-run src/scripts/build_mcp_registry_manifest --write --strict",
|
|
88
91
|
"build:mcp-catalog": "./scripts-run src/scripts/build_mcp_catalog --write --strict",
|
|
89
|
-
"build": "npm run build:cli && npm run build:install-bundle && npm run build:hooks && npm run build:mcp-bundle && npm run build:cli-delegate && npm run build:ui",
|
|
92
|
+
"build": "npm run build:cli && npm run build:install-bundle && npm run build:hooks && npm run build:mcp-bundle && npm run build:cli-delegate && npm run build:agent-src-delegate && npm run build:delegate-aux && npm run build:ui",
|
|
90
93
|
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.scripts.json",
|
|
91
94
|
"lint:ts": "eslint --cache --max-warnings 0 'src/**/*.ts'",
|
|
92
95
|
"test:ts": "vitest run",
|
|
@@ -116,8 +119,7 @@
|
|
|
116
119
|
"tsx": "^4.23.1",
|
|
117
120
|
"typescript": "^5.9.3",
|
|
118
121
|
"vite": "^5.4.21",
|
|
119
|
-
"vitest": "^2.1.9"
|
|
120
|
-
"web-tree-sitter": "0.24.7"
|
|
122
|
+
"vitest": "^2.1.9"
|
|
121
123
|
},
|
|
122
124
|
"dependencies": {
|
|
123
125
|
"@fastify/static": "^10.1.2",
|
|
@@ -129,6 +131,7 @@
|
|
|
129
131
|
"js-yaml": "^5.2.0",
|
|
130
132
|
"open": "^11.0.0",
|
|
131
133
|
"preact": "^10.29.0",
|
|
134
|
+
"web-tree-sitter": "0.24.7",
|
|
132
135
|
"yaml": "^2.9.0",
|
|
133
136
|
"zod": "^3.25.0",
|
|
134
137
|
"zod-to-json-schema": "^3.25.0"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Was this module invoked as the command?" — one definition for the scripts
|
|
3
|
+
* under `agents/scripts` that both run directly and are imported by siblings.
|
|
4
|
+
*
|
|
5
|
+
* Five of them carried a byte-identical copy of this logic, and the copies were
|
|
6
|
+
* about to gain a sixth clause each. The interesting part is why the obvious
|
|
7
|
+
* one-liner is not enough:
|
|
8
|
+
*
|
|
9
|
+
* - `--splitting` in `build:agent-src-delegate` can move a module body into a
|
|
10
|
+
* shared chunk, where `import.meta.url` names the CHUNK. The URL comparison
|
|
11
|
+
* then never matches and the command exits 0 having done nothing — measured
|
|
12
|
+
* on `update_roadmap_progress` before this guard existed. Inside the bundle
|
|
13
|
+
* the invoked file name is the reliable signal, so the delegate branch runs
|
|
14
|
+
* first and a miss falls through rather than returning false.
|
|
15
|
+
* - A symlinked invocation (`.augment/scripts` → `dist/agent-src/scripts`, or
|
|
16
|
+
* macOS `/var` → `/private/var`) makes the raw URLs differ: `import.meta.url`
|
|
17
|
+
* is the resolved real path while `argv[1]` keeps the symlink. Hence the
|
|
18
|
+
* realpath comparison last.
|
|
19
|
+
*
|
|
20
|
+
* `moduleUrl` is the caller's own `import.meta.url` — it cannot be read from
|
|
21
|
+
* here, which is why it is a parameter rather than a lookup.
|
|
22
|
+
*/
|
|
23
|
+
import * as fs from 'node:fs';
|
|
24
|
+
import * as path from 'node:path';
|
|
25
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
26
|
+
|
|
27
|
+
/** Defined only by the esbuild delegate builds; `undefined` under tsx and node. */
|
|
28
|
+
declare const __AGENT_CONFIG_CLI_DELEGATE__: boolean | undefined;
|
|
29
|
+
|
|
30
|
+
export function isCliEntry(moduleUrl: string, name: string): boolean {
|
|
31
|
+
const argv1 = process.argv[1];
|
|
32
|
+
if (argv1 === undefined) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (
|
|
36
|
+
typeof __AGENT_CONFIG_CLI_DELEGATE__ !== 'undefined' &&
|
|
37
|
+
__AGENT_CONFIG_CLI_DELEGATE__ &&
|
|
38
|
+
path.basename(argv1, '.js') === name
|
|
39
|
+
) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
const argvPath = path.resolve(argv1);
|
|
43
|
+
if (moduleUrl === pathToFileURL(argvPath).href) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
return fs.realpathSync(fileURLToPath(moduleUrl)) === fs.realpathSync(argvPath);
|
|
48
|
+
} catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -56,11 +56,17 @@ import { spawnSync } from 'node:child_process';
|
|
|
56
56
|
import * as fs from 'node:fs';
|
|
57
57
|
import * as path from 'node:path';
|
|
58
58
|
import process from 'node:process';
|
|
59
|
-
import { fileURLToPath
|
|
59
|
+
import { fileURLToPath } from 'node:url';
|
|
60
60
|
|
|
61
|
-
import {
|
|
61
|
+
import {
|
|
62
|
+
blocker_is_resolved,
|
|
63
|
+
collect,
|
|
64
|
+
parse_blockers,
|
|
65
|
+
} from './update_roadmap_progress.js';
|
|
62
66
|
import { guardedBaselineProblems, parseGuardedBaselines } from './guarded_baseline.js';
|
|
63
67
|
|
|
68
|
+
import { isCliEntry } from './_cli_entry.js';
|
|
69
|
+
|
|
64
70
|
const _HERE = fileURLToPath(import.meta.url);
|
|
65
71
|
|
|
66
72
|
interface CompletedProcess {
|
|
@@ -263,6 +269,80 @@ function _git_mv(root: string, src_rel: string, dst_rel: string, dry_run: boolea
|
|
|
263
269
|
}
|
|
264
270
|
}
|
|
265
271
|
|
|
272
|
+
// ---------------------------------------------------------------------
|
|
273
|
+
// The index/working-tree blocker divergence check (1b) + staging (1a)
|
|
274
|
+
// ---------------------------------------------------------------------
|
|
275
|
+
//
|
|
276
|
+
// The open-blocker refusal below reads the file with `fs.readFileSync`, i.e.
|
|
277
|
+
// the WORKING TREE. `git mv` then moves the INDEX ENTRY, which still carries
|
|
278
|
+
// whatever was staged. When the two disagree the commit ships the index
|
|
279
|
+
// content — content this gate never read.
|
|
280
|
+
//
|
|
281
|
+
// Measured, once, at full cost (2026-09-08): an edit removing a roadmap's
|
|
282
|
+
// blocker was made and never staged; `git mv` moved the stale index entry; the
|
|
283
|
+
// archived file shipped a blocker declared `Status: open` that had already been
|
|
284
|
+
// relocated to an active roadmap. The same blocker was open in two files at
|
|
285
|
+
// once, one of them archived, and it was caught by a human reading
|
|
286
|
+
// `git status` rather than by any gate.
|
|
287
|
+
//
|
|
288
|
+
// The check is scoped to blocker id → status and deliberately NOT to whole-file
|
|
289
|
+
// equality. An unstaged typo fix in a roadmap title has nothing to do with the
|
|
290
|
+
// defect, and refusing archival for it trains `git add -A`, which destroys the
|
|
291
|
+
// staging discipline this check depends on. AI council 2026-09-08, 2/2 present
|
|
292
|
+
// (anthropic/claude-sonnet-4-5 + openai/gpt-4o), on that scoping specifically:
|
|
293
|
+
// broad scoping is "user-hostile, trains developers to `git add -A`
|
|
294
|
+
// reflexively, defeating staging discipline".
|
|
295
|
+
|
|
296
|
+
/** Blocker id → status, as the archive-transition check compares them. */
|
|
297
|
+
function _blockerStatuses(text: string): Map<string, string> {
|
|
298
|
+
const out = new Map<string, string>();
|
|
299
|
+
for (const b of parse_blockers(text)) {
|
|
300
|
+
out.set(b.id, blocker_is_resolved(b) ? 'resolved' : 'open');
|
|
301
|
+
}
|
|
302
|
+
return out;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* `git show :<rel>` — the STAGED content of a path, or null when the path has
|
|
307
|
+
* no index entry.
|
|
308
|
+
*
|
|
309
|
+
* Null is the untracked / pre-first-commit case, which `_git_mv` already
|
|
310
|
+
* handles by falling back to a plain rename. There is no index entry to
|
|
311
|
+
* disagree with, so the divergence check has nothing to assert and says so by
|
|
312
|
+
* returning null rather than by guessing at an empty string — an empty staged
|
|
313
|
+
* file and an absent one differ, and only the second is legitimate here.
|
|
314
|
+
*/
|
|
315
|
+
function _indexContent(root: string, rel: string): string | null {
|
|
316
|
+
const cp = _run(['git', 'show', `:${rel}`], root);
|
|
317
|
+
return cp.returncode === 0 ? cp.stdout : null;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Human-readable disagreements between the staged and working-tree blocker
|
|
322
|
+
* maps of one path. Empty array = the two agree, or there is no index entry.
|
|
323
|
+
*/
|
|
324
|
+
function _blockerDivergence(root: string, rel: string, workTreeText: string): string[] {
|
|
325
|
+
const staged = _indexContent(root, rel);
|
|
326
|
+
if (staged === null) {
|
|
327
|
+
return [];
|
|
328
|
+
}
|
|
329
|
+
const wt = _blockerStatuses(workTreeText);
|
|
330
|
+
const idx = _blockerStatuses(staged);
|
|
331
|
+
const ids = [...new Set([...wt.keys(), ...idx.keys()])].sort();
|
|
332
|
+
const out: string[] = [];
|
|
333
|
+
for (const id of ids) {
|
|
334
|
+
const a = idx.get(id);
|
|
335
|
+
const b = wt.get(id);
|
|
336
|
+
if (a === b) {
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
out.push(
|
|
340
|
+
`blocker '${id}': staged=${a ?? 'absent'} vs working tree=${b ?? 'absent'}`,
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
return out;
|
|
344
|
+
}
|
|
345
|
+
|
|
266
346
|
/**
|
|
267
347
|
* Repo-relative paths of files containing `needle`, by walking the filesystem.
|
|
268
348
|
*
|
|
@@ -545,9 +625,8 @@ function archive_completed(
|
|
|
545
625
|
// and invisible in a sweep that only reports what it moved; a MALFORMED
|
|
546
626
|
// one on `[x]` would otherwise archive with an annotation claiming the
|
|
547
627
|
// opposite. Both are named here instead.
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
);
|
|
628
|
+
const roadmapText = fs.readFileSync(path.join(roadmap_root, stats.rel), 'utf-8');
|
|
629
|
+
const guarded = parseGuardedBaselines(roadmapText);
|
|
551
630
|
if (guarded.length > 0) {
|
|
552
631
|
process.stderr.write(
|
|
553
632
|
` ⚠️ ${stats.rel}: ${guarded.length} guarded-baseline step(s) — ` +
|
|
@@ -601,12 +680,37 @@ function archive_completed(
|
|
|
601
680
|
if (changed_only && !(touched as Set<string>).has(old_rel)) {
|
|
602
681
|
continue; // complete, but not this branch's work
|
|
603
682
|
}
|
|
683
|
+
// The gate above validated the WORKING TREE; `git mv` ships the INDEX.
|
|
684
|
+
// When they disagree about a blocker, the validated content is not the
|
|
685
|
+
// content that gets committed — see § the index/working-tree blocker
|
|
686
|
+
// divergence check above for the measured failure.
|
|
687
|
+
const divergence = _blockerDivergence(root, old_rel, roadmapText);
|
|
688
|
+
if (divergence.length > 0) {
|
|
689
|
+
process.stderr.write(
|
|
690
|
+
` ⚠️ ${stats.rel}: staged and working-tree blockers disagree ` +
|
|
691
|
+
`(${divergence.length}) — not archived. \`git mv\` would commit ` +
|
|
692
|
+
'the staged content, which this sweep never validated. Stage or ' +
|
|
693
|
+
'discard the change, then re-run.\n',
|
|
694
|
+
);
|
|
695
|
+
for (const d of divergence) {
|
|
696
|
+
process.stderr.write(` · ${d}\n`);
|
|
697
|
+
}
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
604
700
|
const new_rel = `agents/roadmaps/archive/${stats.rel}`;
|
|
605
701
|
const mv = _git_mv(root, old_rel, new_rel, dry_run);
|
|
606
702
|
if (!mv.ok) {
|
|
607
703
|
process.stderr.write(` ⚠️ could not archive ${old_rel} (mv failed)\n`);
|
|
608
704
|
continue;
|
|
609
705
|
}
|
|
706
|
+
// `git mv` moved the index ENTRY, not the working-tree content. Staging
|
|
707
|
+
// the destination makes what gets committed identical to what the checks
|
|
708
|
+
// above read — the divergence check refuses a disagreement that exists
|
|
709
|
+
// BEFORE the move, and this closes one created by an edit between the
|
|
710
|
+
// move and the commit.
|
|
711
|
+
if (!dry_run && mv.tracked) {
|
|
712
|
+
_run(['git', 'add', '--', new_rel], root);
|
|
713
|
+
}
|
|
610
714
|
const refs = _inbound_ref_rewrite(root, old_rel, new_rel, dry_run, mv.tracked);
|
|
611
715
|
// Stage rewritten refs only in a tracked repo; an untracked consumer's
|
|
612
716
|
// files are not in the index, so the filesystem rewrite is the whole job.
|
|
@@ -638,6 +742,16 @@ function _regen_dashboard(root: string, dry_run: boolean): void {
|
|
|
638
742
|
if (dry_run) {
|
|
639
743
|
return;
|
|
640
744
|
}
|
|
745
|
+
// Inside `dist/cli-delegate/` the twin sits next to us as a precompiled
|
|
746
|
+
// bundle, and plain `node` runs it — the tsx walk below would otherwise
|
|
747
|
+
// reach `npx tsx`, which resolves against the CONSUMER's npm config and
|
|
748
|
+
// hard-fails on a mismatched `engines`/`devEngines` pin (the very class
|
|
749
|
+
// ADR-204 removed from the dispatcher and left standing here).
|
|
750
|
+
const bundledTwin = path.join(path.dirname(_HERE), 'update_roadmap_progress.js');
|
|
751
|
+
if (_isFile(bundledTwin)) {
|
|
752
|
+
spawnSync(process.execPath, [bundledTwin], { cwd: root, encoding: 'utf-8' });
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
641
755
|
const script = path.join(path.dirname(_HERE), 'update_roadmap_progress.ts');
|
|
642
756
|
// Python: `_run([sys.executable, str(script)], root)`; the twin spawns the
|
|
643
757
|
// dashboard generator twin through the same `tsx` runtime, cwd=root.
|
|
@@ -800,28 +914,7 @@ function main(argv?: readonly string[]): number {
|
|
|
800
914
|
return 0;
|
|
801
915
|
}
|
|
802
916
|
|
|
803
|
-
|
|
804
|
-
if (process.argv[1] === undefined) {
|
|
805
|
-
return false;
|
|
806
|
-
}
|
|
807
|
-
const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
|
808
|
-
if (import.meta.url === argvUrl) {
|
|
809
|
-
return true;
|
|
810
|
-
}
|
|
811
|
-
// A symlinked invocation (e.g. via `.augment/scripts` → `dist/agent-src/scripts`,
|
|
812
|
-
// or macOS /var → /private/var temp dirs) makes the raw URLs differ:
|
|
813
|
-
// import.meta.url is the resolved real path while argv[1] keeps the symlink
|
|
814
|
-
// path. Compare realpaths so the entry guard still fires (without this the
|
|
815
|
-
// archival sweep silently no-ops when run through the symlink).
|
|
816
|
-
try {
|
|
817
|
-
const here = fs.realpathSync(fileURLToPath(import.meta.url));
|
|
818
|
-
const argv = fs.realpathSync(path.resolve(process.argv[1]));
|
|
819
|
-
return here === argv;
|
|
820
|
-
} catch {
|
|
821
|
-
return false;
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
if (_isCliEntry() || process.argv[1] === _HERE) {
|
|
917
|
+
if (isCliEntry(import.meta.url, 'archive_completed_roadmaps')) {
|
|
825
918
|
try {
|
|
826
919
|
process.exitCode = main();
|
|
827
920
|
} catch (exc) {
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
*/
|
|
66
66
|
|
|
67
67
|
import * as path from 'node:path';
|
|
68
|
-
import { fileURLToPath
|
|
68
|
+
import { fileURLToPath } from 'node:url';
|
|
69
69
|
import * as fs from 'node:fs';
|
|
70
70
|
import { spawnSync } from 'node:child_process';
|
|
71
71
|
|
|
@@ -80,6 +80,8 @@ import { execute } from './gate_execute.js';
|
|
|
80
80
|
import { listPending } from '../templates/scripts/work_engine/hooks/builtin/staged_confirmation_store.js';
|
|
81
81
|
import type { StagedAction } from '../templates/scripts/work_engine/hooks/builtin/staged_confirmation.js';
|
|
82
82
|
|
|
83
|
+
import { isCliEntry } from './_cli_entry.js';
|
|
84
|
+
|
|
83
85
|
const _HERE = fileURLToPath(import.meta.url);
|
|
84
86
|
|
|
85
87
|
/** Hard wrap for the rendered body — keeps output readable in a narrow pane. */
|
|
@@ -928,26 +930,8 @@ function main(argv?: readonly string[]): number {
|
|
|
928
930
|
return 0;
|
|
929
931
|
}
|
|
930
932
|
|
|
931
|
-
function _isCliEntry(): boolean {
|
|
932
|
-
if (process.argv[1] === undefined) {
|
|
933
|
-
return false;
|
|
934
|
-
}
|
|
935
|
-
const argvPath = path.resolve(process.argv[1]);
|
|
936
|
-
if (import.meta.url === pathToFileURL(argvPath).href) {
|
|
937
|
-
return true;
|
|
938
|
-
}
|
|
939
|
-
// A symlinked invocation (`.augment/scripts` → `dist/agent-src/scripts`, or
|
|
940
|
-
// macOS /var → /private/var) makes the raw URLs differ: import.meta.url is
|
|
941
|
-
// the resolved real path while argv[1] keeps the symlink. Compare realpaths
|
|
942
|
-
// so the entry guard still fires through the projection.
|
|
943
|
-
try {
|
|
944
|
-
return fs.realpathSync(_HERE) === fs.realpathSync(argvPath);
|
|
945
|
-
} catch {
|
|
946
|
-
return false;
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
933
|
|
|
950
|
-
if (
|
|
934
|
+
if (isCliEntry(import.meta.url, 'roadmap_gates')) {
|
|
951
935
|
process.exitCode = main();
|
|
952
936
|
}
|
|
953
937
|
|
|
@@ -30,7 +30,9 @@
|
|
|
30
30
|
import * as fs from 'node:fs';
|
|
31
31
|
import * as path from 'node:path';
|
|
32
32
|
import process from 'node:process';
|
|
33
|
-
import { fileURLToPath
|
|
33
|
+
import { fileURLToPath } from 'node:url';
|
|
34
|
+
|
|
35
|
+
import { isCliEntry } from './_cli_entry.js';
|
|
34
36
|
|
|
35
37
|
const _HERE = fileURLToPath(import.meta.url);
|
|
36
38
|
|
|
@@ -246,8 +248,9 @@ export function main(argv: string[] = process.argv.slice(2)): number {
|
|
|
246
248
|
}
|
|
247
249
|
}
|
|
248
250
|
|
|
251
|
+
|
|
249
252
|
/* c8 ignore start */
|
|
250
|
-
if (
|
|
253
|
+
if (isCliEntry(import.meta.url, 'roadmap_set_step')) {
|
|
251
254
|
process.exit(main());
|
|
252
255
|
}
|
|
253
256
|
/* c8 ignore stop */
|