@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.
Files changed (235) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +164 -187
  5. package/CREDITS.md +37 -0
  6. package/README.md +1 -1
  7. package/dist/agent-src/commands/analyze/inbox.md +380 -5
  8. package/dist/agent-src/commands/analyze/repo.md +4 -2
  9. package/dist/agent-src/commands/pr/merge.md +47 -38
  10. package/dist/agent-src/commands/roadmap/next.md +8 -0
  11. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +69 -0
  12. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -5
  13. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +12 -0
  14. package/dist/agent-src/rules/external-code-graph-interop.md +19 -14
  15. package/dist/agent-src/rules/notes-first-reasoning.md +36 -25
  16. package/dist/agent-src/rules/token-efficiency.md +26 -3
  17. package/dist/agent-src/scripts/_cli_entry.ts +51 -0
  18. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +120 -27
  19. package/dist/agent-src/scripts/roadmap_gates.ts +4 -20
  20. package/dist/agent-src/scripts/roadmap_set_step.ts +5 -2
  21. package/dist/agent-src/scripts/stubs_due.ts +4 -18
  22. package/dist/agent-src/scripts/update_roadmap_progress.ts +7 -24
  23. package/dist/agent-src/skills/code-intelligence/SKILL.md +82 -1
  24. package/dist/agent-src/skills/git-workflow/references/push-closes-its-loop.md +9 -0
  25. package/dist/agent-src/skills/roadmap-writing/SKILL.md +17 -0
  26. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +52 -2
  27. package/dist/agent-src/templates/agent-settings.md +0 -1
  28. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  29. package/dist/cli/registry.js +1 -1
  30. package/dist/cli-delegate/_cli_entry.js +8 -0
  31. package/dist/cli-delegate/_lib/pin_resolver.js +170 -0
  32. package/dist/cli-delegate/archival_sweep.js +8 -0
  33. package/dist/cli-delegate/archive_completed_roadmaps.js +542 -0
  34. package/dist/cli-delegate/check_update_banner.js +923 -0
  35. package/dist/cli-delegate/{chunk-ZVBOHSVF.js → chunk-2KKXJW25.js} +23 -9
  36. package/dist/cli-delegate/chunk-5EK5WQN6.js +28 -0
  37. package/dist/cli-delegate/chunk-7XGD2OEU.js +96 -0
  38. package/dist/cli-delegate/chunk-DBH4AHDK.js +155 -0
  39. package/dist/cli-delegate/{chunk-4FS4WRXP.js → chunk-IAI3XL43.js} +15 -3
  40. package/dist/cli-delegate/chunk-JO25G5H7.js +20 -0
  41. package/dist/cli-delegate/{chunk-643Z7FIC.js → chunk-KCNTUSPI.js} +7 -1
  42. package/dist/cli-delegate/chunk-LTYVIY76.js +7961 -0
  43. package/dist/cli-delegate/chunk-QAJS5YWY.js +999 -0
  44. package/dist/cli-delegate/{chunk-YS6XTLEK.js → chunk-TYSY33MD.js} +56 -6
  45. package/dist/cli-delegate/chunk-ULET4BYS.js +328 -0
  46. package/dist/cli-delegate/chunk-YDQSHTD7.js +187 -0
  47. package/dist/cli-delegate/chunk-YWVXLR44.js +48 -0
  48. package/dist/cli-delegate/chunk-ZZQBUHFK.js +273 -0
  49. package/dist/cli-delegate/cmd_conformance.js +2 -2
  50. package/dist/cli-delegate/cmd_export.js +2 -2
  51. package/dist/cli-delegate/cmd_handoff.js +45 -13
  52. package/dist/cli-delegate/cmd_prune.js +2 -2
  53. package/dist/cli-delegate/cmd_session_recycle.js +4 -14
  54. package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
  55. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  56. package/dist/cli-delegate/cmd_sync.js +2 -2
  57. package/dist/cli-delegate/cmd_uninstall.js +2 -2
  58. package/dist/cli-delegate/cmd_validate.js +2 -2
  59. package/dist/cli-delegate/dashboard_mode.js +16 -0
  60. package/dist/cli-delegate/gate_budget.js +24 -0
  61. package/dist/cli-delegate/gate_execute.js +25 -0
  62. package/dist/cli-delegate/guarded_baseline.js +18 -0
  63. package/dist/cli-delegate/resume_probe.js +22 -0
  64. package/dist/cli-delegate/roadmap_gates.js +638 -0
  65. package/dist/cli-delegate/roadmap_set_step.js +173 -0
  66. package/dist/cli-delegate/stub_queue.js +47 -0
  67. package/dist/cli-delegate/stubs_due.js +38 -0
  68. package/dist/cli-delegate/ticket_bundles.js +59 -0
  69. package/dist/cli-delegate/update_roadmap_progress.js +60 -0
  70. package/dist/discovery/deprecation-report.md +1 -1
  71. package/dist/discovery/discovery-manifest.json +13 -13
  72. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  73. package/dist/discovery/discovery-manifest.summary.md +1 -1
  74. package/dist/discovery/dormancy-report.md +1 -1
  75. package/dist/discovery/orphan-report.md +1 -1
  76. package/dist/discovery/packs.json +2 -2
  77. package/dist/discovery/trust-report.md +1 -1
  78. package/dist/discovery/workspaces.json +2 -2
  79. package/dist/hooks/dispatch.js +1813 -946
  80. package/dist/install/claudeLayerCarriage.js +237 -0
  81. package/dist/install/claudePathsPlan.js +79 -0
  82. package/dist/install/hostLayerFingerprint.js +1 -1
  83. package/dist/install/install.mjs +21 -3
  84. package/dist/install/partitionEligibility.js +231 -117
  85. package/dist/install/ruleLayerPartition.js +10 -7
  86. package/dist/mcp/registry-manifest.json +2 -2
  87. package/dist/mcp/server.json +2 -2
  88. package/dist/mcp/server.mjs +10870 -7641
  89. package/dist/scripts/_lib/lean_projection_mode.js +108 -0
  90. package/dist/scripts/_lib/router_match.js +243 -0
  91. package/dist/scripts/_lib/rule_injection.js +216 -0
  92. package/dist/scripts/condense.js +52 -45
  93. package/dist/scripts/project_thin_rules.js +139 -19
  94. package/dist/server/schemas/settings.js +16 -3
  95. package/docs/MIGRATION.md +105 -1
  96. package/docs/contracts/settings-classes.md +40 -8
  97. package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +73 -0
  98. package/docs/guidelines/agent-infra/notes-horizon-mechanics.md +90 -0
  99. package/llms.txt +1 -1
  100. package/package.json +7 -4
  101. package/src/agent-src/scripts/_cli_entry.ts +51 -0
  102. package/src/agent-src/scripts/archive_completed_roadmaps.ts +120 -27
  103. package/src/agent-src/scripts/roadmap_gates.ts +4 -20
  104. package/src/agent-src/scripts/roadmap_set_step.ts +5 -2
  105. package/src/agent-src/scripts/stubs_due.ts +4 -18
  106. package/src/agent-src/scripts/update_roadmap_progress.ts +7 -24
  107. package/src/config/agent-settings.template.yml +47 -1
  108. package/src/config/continuity-surface.json +516 -0
  109. package/src/config/estate-count-budget.json +1 -1
  110. package/src/config/evaluator-budgets.json +4 -4
  111. package/src/config/gate-coverage.yml +29 -8
  112. package/src/config/gate-violation-baselines.json +8 -8
  113. package/src/config/gitignore-block.txt +19 -0
  114. package/src/config/hook-token-budget.json +7 -6
  115. package/src/config/host-injection-effect.json +73 -0
  116. package/src/config/packed-binary-manifest.json +33 -0
  117. package/src/config/preamble-payload-budget.json +112 -105
  118. package/src/config/publish-surface.json +4 -2
  119. package/src/config/routing-coverage-seed.json +9 -2
  120. package/src/install/claudeLayerCarriage.ts +273 -0
  121. package/src/install/claudePathsPlan.ts +76 -0
  122. package/src/install/hostLayerFingerprint.ts +1 -1
  123. package/src/install/partitionEligibility.ts +261 -127
  124. package/src/install/ruleLayerPartition.ts +19 -23
  125. package/src/scripts/_cli/cmd_session_recycle.ts +2 -25
  126. package/src/scripts/_cli/handoff_sessions.ts +14 -44
  127. package/src/scripts/_dispatch.bash +77 -27
  128. package/src/scripts/_lib/auto_dispatch.ts +2 -2
  129. package/src/scripts/_lib/catalogue_layer_parity.ts +146 -0
  130. package/src/scripts/_lib/continuity_slot.ts +295 -0
  131. package/src/scripts/_lib/continuity_surface.ts +296 -0
  132. package/src/scripts/_lib/continuity_writer.ts +253 -0
  133. package/src/scripts/_lib/corpus_manifest.ts +26 -9
  134. package/src/scripts/_lib/hook_settings.ts +86 -1
  135. package/src/scripts/_lib/injection_effect.ts +151 -0
  136. package/src/scripts/_lib/layer_overlap_notice.ts +50 -6
  137. package/src/scripts/_lib/lean_projection_mode.ts +127 -0
  138. package/src/scripts/_lib/packed_binary_predicate.ts +262 -0
  139. package/src/scripts/_lib/pin_resolver.ts +13 -0
  140. package/src/scripts/_lib/recycle_envelope_paths.ts +109 -21
  141. package/src/scripts/_lib/regression_neighbourhood.ts +159 -22
  142. package/src/scripts/_lib/retired_status.ts +74 -0
  143. package/src/scripts/_lib/session_eol.ts +44 -0
  144. package/src/scripts/_lib/session_index_trust.ts +346 -0
  145. package/src/scripts/_lib/skill_catalogue.ts +156 -21
  146. package/src/scripts/_lib/standing_bound_ratchet.ts +154 -0
  147. package/src/scripts/_lib/subagent_capsule.ts +117 -8
  148. package/src/scripts/_lib/vendored_grammar_upstream.ts +280 -0
  149. package/src/scripts/ai_council/api_transport.ts +5 -0
  150. package/src/scripts/ai_council/deliberation_metrics.ts +353 -0
  151. package/src/scripts/ai_council/prompts.ts +9 -0
  152. package/src/scripts/ai_council/synthesis_disagreement.ts +206 -0
  153. package/src/scripts/audit_mcp_tools.ts +69 -25
  154. package/src/scripts/build_mcp_catalog.ts +24 -1
  155. package/src/scripts/capture_skill_catalogue.ts +24 -11
  156. package/src/scripts/check_candidate_lines.ts +499 -0
  157. package/src/scripts/check_continuity_surface.ts +475 -0
  158. package/src/scripts/check_dependency_floors.ts +13 -6
  159. package/src/scripts/check_estate_count.ts +40 -79
  160. package/src/scripts/check_host_tree_parity.ts +291 -0
  161. package/src/scripts/check_pack_size.ts +262 -23
  162. package/src/scripts/check_preamble_payload_budget.ts +136 -7
  163. package/src/scripts/check_roadmap_trackable.ts +19 -16
  164. package/src/scripts/check_rule_layer_partition.ts +54 -34
  165. package/src/scripts/check_rule_projection_integrity.ts +102 -2
  166. package/src/scripts/check_single_delivery.ts +97 -31
  167. package/src/scripts/check_update_banner.ts +13 -0
  168. package/src/scripts/ci_settle.ts +205 -5
  169. package/src/scripts/code_graph/build.ts +217 -15
  170. package/src/scripts/code_graph/cli.ts +334 -15
  171. package/src/scripts/code_graph/detect.ts +38 -0
  172. package/src/scripts/code_graph/extract.ts +11 -0
  173. package/src/scripts/code_graph/grammar_probe.ts +43 -0
  174. package/src/scripts/code_graph/loader.ts +88 -14
  175. package/src/scripts/code_graph/query.ts +144 -11
  176. package/src/scripts/code_graph/resolution_tiers.ts +238 -0
  177. package/src/scripts/code_graph/sqlite_store.ts +262 -6
  178. package/src/scripts/code_graph/types.ts +117 -3
  179. package/src/scripts/code_graph/validate.ts +26 -1
  180. package/src/scripts/code_graph/verbs.ts +590 -0
  181. package/src/scripts/condense.ts +54 -42
  182. package/src/scripts/corpus_manifest.ts +5 -5
  183. package/src/scripts/council_cli.ts +11 -12
  184. package/src/scripts/count_intent_disagreement.ts +426 -0
  185. package/src/scripts/handoff_context_hook.ts +118 -1
  186. package/src/scripts/hook_effect_doctor.ts +82 -1
  187. package/src/scripts/hook_manifest.json +1 -1
  188. package/src/scripts/hook_manifest.yaml +87 -12
  189. package/src/scripts/hooks/block_speaking_inbox_dir.ts +182 -16
  190. package/src/scripts/hooks/chain_nudge_hook.ts +282 -0
  191. package/src/scripts/hooks/code_graph_context_hook.ts +201 -0
  192. package/src/scripts/hooks/concern_registry.ts +4 -2
  193. package/src/scripts/hooks/host_semantics.ts +1 -1
  194. package/src/scripts/hooks/orchestration_record_hook.ts +2 -2
  195. package/src/scripts/hooks/push_settle_hook.ts +3 -2
  196. package/src/scripts/hooks/rule_inject_hook.ts +108 -21
  197. package/src/scripts/hooks/session_eol_hook.ts +120 -2
  198. package/src/scripts/hooks/skill_route_hook.ts +11 -4
  199. package/src/scripts/hot_context_hook.ts +62 -7
  200. package/src/scripts/inbox_source_census.ts +322 -0
  201. package/src/scripts/install-hooks.sh +82 -0
  202. package/src/scripts/{lint_carrier_integrity.ts → lint_deferral_integrity.ts} +60 -214
  203. package/src/scripts/lint_plan_risk_register.ts +13 -17
  204. package/src/scripts/lint_roadmap_blockers.ts +164 -1
  205. package/src/scripts/mcp_server/consumer_tool_catalog.json +152 -2
  206. package/src/scripts/mcp_server/graph_tools.ts +294 -0
  207. package/src/scripts/mcp_server/path_util.ts +31 -0
  208. package/src/scripts/mcp_server/suggest_skill.ts +72 -0
  209. package/src/scripts/mcp_server/tool_catalog_source.ts +7 -1
  210. package/src/scripts/mcp_server/tools.ts +5 -69
  211. package/src/scripts/media/lib/adapter-contract.md +7 -2
  212. package/src/scripts/media/lib/fixtures/flux/asset-0001.png +0 -0
  213. package/src/scripts/media/lib/fixtures/gemini-image/asset-0001.png +0 -0
  214. package/src/scripts/media/lib/fixtures/ideogram/asset-0001.png +0 -0
  215. package/src/scripts/model_rule_injection.ts +61 -4
  216. package/src/scripts/project_thin_rules.ts +149 -16
  217. package/src/scripts/rdp_candidates_delta.ts +276 -0
  218. package/src/scripts/rdp_quality_eval.ts +217 -19
  219. package/src/scripts/release_mix_taxonomy.json +3 -2
  220. package/src/scripts/report_host_injection_effect.ts +189 -0
  221. package/src/scripts/report_layer_overlap.ts +41 -0
  222. package/src/scripts/report_skill_menu_census.ts +341 -0
  223. package/src/scripts/report_standing_payload_by_host.ts +650 -0
  224. package/src/scripts/schemas/agent-settings.schema.json +7 -1
  225. package/src/scripts/session_memory_index.ts +81 -8
  226. package/src/scripts/skill_tools/score_skill_relevance.ts +70 -6
  227. package/src/scripts/skill_tools/suggest_skill_for_task.ts +37 -3
  228. package/src/server/schemas/settings.ts +23 -4
  229. package/src/vendor/grammars/README.md +86 -0
  230. package/src/vendor/grammars/tree-sitter-javascript.wasm +0 -0
  231. package/src/vendor/grammars/tree-sitter-php.wasm +0 -0
  232. package/src/vendor/grammars/tree-sitter-typescript.wasm +0 -0
  233. package/src/scripts/_lib/carrier_status.ts +0 -118
  234. package/src/scripts/_lib/estate_carrier_cases.ts +0 -72
  235. package/src/scripts/hooks/code_graph_nudge_hook.ts +0 -191
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Does the CLAUDE host-global layer already carry a given artefact?
3
+ *
4
+ * **Why this module exists — the veto it replaces.**
5
+ *
6
+ * ADR-236 partitions artefacts between `~/.claude/**` and `<repo>/.claude/**`.
7
+ * Its first implementation asked ONE question for the whole run: does
8
+ * `installed.lock` record the same version as this checkout, and does a content
9
+ * fingerprint of the host layer still match what the installer stamped? Any
10
+ * answer but yes fell back to the full projection.
11
+ *
12
+ * That veto is repo-wide, and it fires on facts that have nothing to do with any
13
+ * individual artefact. Measured 2026-09-07 on the maintainer machine, `installed.lock`
14
+ * at 14.19.0 against a 14.21.0 checkout:
15
+ *
16
+ * ```
17
+ * rules global 104 · project 15 · BOTH 0 ← already correct
18
+ * skills global 307 · project 414 · BOTH 261 ← the veto's cost
19
+ * personas global 32 · project 29 · BOTH 29
20
+ * commands global 94 · project 0 · BOTH 0
21
+ * ```
22
+ *
23
+ * The rules row is correct because rules are partitioned by
24
+ * {@link hostLayerCarries} — per host directory, on that directory's own
25
+ * contents — while skills, personas and commands hung off the version veto and
26
+ * were therefore delivered twice, in every session, for as long as the install
27
+ * lagged a release. A version number is not evidence about an artefact.
28
+ *
29
+ * This module supplies the evidence the other three families were missing, in
30
+ * the shape rules already use: read the host directory, and answer per NAME.
31
+ *
32
+ * **Why per-name rather than per-family.**
33
+ *
34
+ * A partition is a removal and has no repair path — withholding a name the
35
+ * surviving layer does not hold deletes it from every session. Asking per name
36
+ * makes the fail-safe granular: an artefact the host layer lacks stays in the
37
+ * project layer on its own, and one absent name no longer keeps 300 duplicates
38
+ * alive with it. That is the property the repo-wide veto could not express.
39
+ *
40
+ * **Honest limits.**
41
+ *
42
+ * Presence of a NAME, never equality of CONTENT — and never PROVENANCE either.
43
+ * Two consequences, the second added 2026-09-07 after a neutral review named it.
44
+ *
45
+ * **Staleness.** A stale `~/.claude/skills/foo` satisfies this check, so an
46
+ * install that lags a release delivers that release's older copy of `foo` rather
47
+ * than two copies. That is the trade the
48
+ * owner chose on 2026-09-07, stated rather than implied: the remedy for a stale
49
+ * global layer is `agent-config install`, and {@link verifyHostLayer} still
50
+ * reports the staleness so a run says so out loud.
51
+ *
52
+ * **Shared namespace.** `~/.claude/skills` is not this package's directory. On
53
+ * the machine this was written, 307 entries = 299 package skills + 8 Cloudflare
54
+ * PLUGIN skills. No name collides today, but the mechanism needs no collision to
55
+ * be real: a plugin — or a hand-made `~/.claude/skills/<name>` — whose name
56
+ * matches a package skill makes this function withhold the package's project-layer
57
+ * copy, and the session then loads the foreign body under the package's skill
58
+ * name. The withhold is a removal with no repair path, which is what makes it
59
+ * worth naming rather than filing.
60
+ *
61
+ * **A NEIGHBOURING defect that WAS fixed, 2026-09-07.** This paragraph claimed
62
+ * "the skill is still delivered, under the right name, from one layer" — and that
63
+ * was false while `_readLayer` returned every directory name without checking
64
+ * that `SKILL.md` resolved: an empty `~/.claude/skills/<name>/` withheld the
65
+ * project copy and the artefact came from neither layer. A name now counts as
66
+ * carried only when the artefact behind it resolves, so the sentence above is
67
+ * true as written.
68
+ *
69
+ * NOT FIXED here, deliberately: distinguishing a package artefact from a foreign
70
+ * one needs a provenance marker the installer does not write today, and inventing
71
+ * one in this module would be a guess dressed as a check. What IS true is that
72
+ * the failure is loud in the direction that matters — the skill is still
73
+ * delivered, under the right name, from one layer — and silent only about whose
74
+ * body it is.
75
+ *
76
+ * Contract, same as its siblings in this directory: no `process.exit`, no CLI
77
+ * entry, node builtins only — it ships inside the consumer installer bundle.
78
+ */
79
+ import * as fs from 'node:fs';
80
+ import * as os from 'node:os';
81
+ import * as path from 'node:path';
82
+ /** Family → its directory under the user's home. */
83
+ export const CLAUDE_ARTEFACT_DIRS = {
84
+ skills: '.claude/skills',
85
+ personas: '.claude/personas',
86
+ commands: '.claude/commands',
87
+ };
88
+ const _defaultHome = () => process.env['HOME'] ?? os.homedir();
89
+ /**
90
+ * One directory read per (family, home) per process.
91
+ *
92
+ * The generators ask per NAME — hundreds of times for skills, ~90 for commands —
93
+ * and the `commands` read walks a tree. Without the memo the per-name grain that
94
+ * makes the fail-safe granular would also make it quadratic. `null` is memoised
95
+ * too: an unreadable layer stays unreadable for the run, and re-probing it once
96
+ * per name would answer the same thing 300 times.
97
+ */
98
+ const _memo = new Map();
99
+ /** Test seam — drop the memo so one process can read a layer it just changed. */
100
+ export function _resetClaudeLayerMemoForTest() {
101
+ _memo.clear();
102
+ }
103
+ /** Absolute path to the host-global directory for one family. */
104
+ export function claudeLayerPath(family, home = _defaultHome()) {
105
+ return path.join(home, CLAUDE_ARTEFACT_DIRS[family]);
106
+ }
107
+ /**
108
+ * The names the host layer holds for one family, or null when it cannot be read.
109
+ *
110
+ * Null is a real answer and every caller must read it as "no evidence, withhold
111
+ * nothing" — not as an empty layer, which would authorise withholding everything.
112
+ *
113
+ * The name shape is the family's own, because that is what the caller compares
114
+ * against: a skill is a directory basename (`design-tokens`), a persona a
115
+ * filename (`ai-agent.md`), and a command a posix path relative to the commands
116
+ * root (`roadmap/process-full.md` for the colon form, `agent-status.md` for a
117
+ * flat one). `commands` therefore walks; the other two list one level.
118
+ */
119
+ export function claudeLayerNames(family, home = _defaultHome()) {
120
+ const dir = claudeLayerPath(family, home);
121
+ const key = `${family}\u0000${dir}`;
122
+ const hit = _memo.get(key);
123
+ if (hit !== undefined) {
124
+ return hit;
125
+ }
126
+ const answer = _readLayer(family, dir);
127
+ _memo.set(key, answer);
128
+ return answer;
129
+ }
130
+ function _readLayer(family, dir) {
131
+ let entries;
132
+ try {
133
+ entries = fs.readdirSync(dir, { withFileTypes: true });
134
+ }
135
+ catch {
136
+ return null;
137
+ }
138
+ if (family !== 'commands') {
139
+ // A name is only CARRIED when the artefact behind it resolves. Corrected
140
+ // 2026-09-07 after a second neutral review: this returned every dirent
141
+ // name, so an empty `~/.claude/skills/<name>/` — no `SKILL.md` — made
142
+ // `claudeLayerHolds` true, the project layer withheld its copy, and the
143
+ // artefact was then delivered from NEITHER layer. That is the
144
+ // removal-with-no-repair-path this module's own limits section says it
145
+ // avoids, and the first fixture written for the wrapper gate created
146
+ // exactly that state and called the withhold correct.
147
+ //
148
+ // Reachable without a crash: a skill directory holding some other file
149
+ // survives `reap_stale`, and `install.ts` mkdirs before it writes.
150
+ // `readProjectedCatalogue` already keys on `SKILL.md` for this reason;
151
+ // the `commands` branch below already required a real `.md`. This is the
152
+ // same requirement for the two families that lacked it.
153
+ const carries = (name) => {
154
+ const abs = path.join(dir, name);
155
+ try {
156
+ if (fs.statSync(abs).isDirectory()) {
157
+ return fs.statSync(path.join(abs, 'SKILL.md')).isFile();
158
+ }
159
+ return name.endsWith('.md');
160
+ }
161
+ catch {
162
+ return false;
163
+ }
164
+ };
165
+ return new Set(entries
166
+ .map((e) => e.name)
167
+ .filter((n) => n !== 'README.md')
168
+ .filter(carries));
169
+ }
170
+ const out = new Set();
171
+ const walk = (abs, rel) => {
172
+ let kids;
173
+ try {
174
+ kids = fs.readdirSync(abs, { withFileTypes: true });
175
+ }
176
+ catch {
177
+ return;
178
+ }
179
+ for (const k of kids) {
180
+ const childRel = rel === '' ? k.name : `${rel}/${k.name}`;
181
+ if (k.isDirectory()) {
182
+ walk(path.join(abs, k.name), childRel);
183
+ }
184
+ else if (k.name.endsWith('.md') && k.name !== 'README.md') {
185
+ out.add(childRel);
186
+ }
187
+ }
188
+ };
189
+ walk(dir, '');
190
+ return out;
191
+ }
192
+ /**
193
+ * Does the host layer hold this one name?
194
+ *
195
+ * The single-name form of {@link keepInProjectLayer}, for a caller that decides
196
+ * inside a loop and already knows the host-side name. `false` on an unreadable
197
+ * layer — no evidence, so nothing is withheld.
198
+ */
199
+ export function claudeLayerHolds(family, name, home = _defaultHome()) {
200
+ return claudeLayerNames(family, home)?.has(name) ?? false;
201
+ }
202
+ /**
203
+ * Which of `names` the host layer carries, and which it does not.
204
+ *
205
+ * `carries` is the all-or-nothing answer the rules path reports; `missing` is the
206
+ * one callers act on, because withholding is decided per name. An empty `names`
207
+ * is vacuously carried — withholding nothing needs no evidence.
208
+ */
209
+ export function claudeLayerCarries(family, names, home = _defaultHome()) {
210
+ const layerPath = claudeLayerPath(family, home);
211
+ const have = claudeLayerNames(family, home);
212
+ if (have === null) {
213
+ return { carries: false, layerPath, missing: [...names], reason: 'layer-absent' };
214
+ }
215
+ const missing = names.filter((n) => !have.has(n));
216
+ return {
217
+ carries: missing.length === 0,
218
+ layerPath,
219
+ missing,
220
+ reason: missing.length === 0 ? 'carries' : 'missing-names',
221
+ };
222
+ }
223
+ /**
224
+ * The subset of `names` the project layer must still deliver.
225
+ *
226
+ * The one function the generators call. Returns the names the host layer does
227
+ * NOT hold, in the order given — so an unreadable layer returns everything
228
+ * (fail safe) and a complete layer returns nothing.
229
+ */
230
+ export function keepInProjectLayer(family, names, home = _defaultHome()) {
231
+ const have = claudeLayerNames(family, home);
232
+ if (have === null) {
233
+ return [...names];
234
+ }
235
+ return names.filter((n) => !have.has(n));
236
+ }
237
+ //# sourceMappingURL=claudeLayerCarriage.js.map
@@ -49,6 +49,85 @@ export function derive_trigger_globs(meta) {
49
49
  // De-dup, keep declaration order (deterministic output).
50
50
  return [...new Set(globs)];
51
51
  }
52
+ /**
53
+ * The ceiling for a description a native lazy form routes on.
54
+ *
55
+ * NOT a host-published limit, and saying so is the point: nothing in this tree
56
+ * records what Cursor or Windsurf actually truncate at, so a number claiming to
57
+ * be theirs would be invented. This is a PACKAGE cap, chosen against the corpus
58
+ * it applies to — the 119 projected rule descriptions measure max 187 and mean
59
+ * 115 characters, so 400 leaves every existing description intact and gives the
60
+ * appended trigger terms roughly twice the mean to work in.
61
+ *
62
+ * Lower it if a host publishes a real limit below 400, or if a rule's emitted
63
+ * description is ever observed truncated by one.
64
+ */
65
+ export const APPLIES_WHEN_CAP = 400;
66
+ /** How the appended clause opens. Exported so a detector cannot re-spell it. */
67
+ export const APPLIES_WHEN_PREFIX = ' Applies when: ';
68
+ /**
69
+ * Keyword and phrase trigger terms, in declaration order, de-duplicated.
70
+ *
71
+ * Path-shaped triggers are deliberately excluded: they already activate the
72
+ * host natively through `globs`, so repeating them in prose spends description
73
+ * budget to say something the host is already acting on.
74
+ */
75
+ export function trigger_terms(meta) {
76
+ const triggers = meta['triggers'];
77
+ if (!Array.isArray(triggers))
78
+ return [];
79
+ const out = [];
80
+ for (const t of triggers) {
81
+ if (t === null || typeof t !== 'object' || Array.isArray(t))
82
+ continue;
83
+ const obj = t;
84
+ for (const key of ['keyword', 'phrase']) {
85
+ const v = obj[key];
86
+ if (typeof v === 'string' && v.trim() !== '')
87
+ out.push(v.trim());
88
+ }
89
+ }
90
+ return [...new Set(out)];
91
+ }
92
+ /**
93
+ * Lower a rule's keyword and phrase triggers into the description a native lazy
94
+ * form routes on (road-to-delivery-on-hook-hosts 3.1).
95
+ *
96
+ * Cursor and Windsurf have no delivery mechanism: an `auto` rule with no
97
+ * path-shaped trigger reaches them as `alwaysApply: false` / `model_decision`
98
+ * with nothing but the description to route on. The rule's own trigger terms
99
+ * are the most routing-relevant text that exists for it, and they were going
100
+ * nowhere.
101
+ *
102
+ * Three properties, each of which is a way this could go wrong:
103
+ *
104
+ * · **Never truncates the original description.** Terms are appended and the
105
+ * clause is dropped WHOLE when it will not fit, so a description can only
106
+ * gain. A cap that ate the sentence would trade routing for readability
107
+ * without saying so.
108
+ * · **Whole terms only.** Terms are added one at a time while they fit; a
109
+ * half term is never emitted, because a truncated phrase routes on nothing
110
+ * and reads as a typo.
111
+ * · **Idempotent.** A description that already carries the clause is returned
112
+ * unchanged, so a re-run of the emitter cannot stack clauses.
113
+ */
114
+ export function applies_when(description, meta, cap = APPLIES_WHEN_CAP) {
115
+ if (description.includes(APPLIES_WHEN_PREFIX.trim()))
116
+ return description;
117
+ const terms = trigger_terms(meta);
118
+ if (terms.length === 0)
119
+ return description;
120
+ const kept = [];
121
+ for (const term of terms) {
122
+ const candidate = `${description}${APPLIES_WHEN_PREFIX}${[...kept, term].join(', ')}.`;
123
+ if (candidate.length > cap)
124
+ break;
125
+ kept.push(term);
126
+ }
127
+ if (kept.length === 0)
128
+ return description;
129
+ return `${description}${APPLIES_WHEN_PREFIX}${kept.join(', ')}.`;
130
+ }
52
131
  /**
53
132
  * A brace group the host expands, versus an agent-config placeholder that only
54
133
  * LOOKS like one.
@@ -4,7 +4,7 @@
4
4
  * ## Why a fingerprint and not a version number
5
5
  *
6
6
  * The single-delivery partition is a *removal*: after it, `task generate-tools`
7
- * writes 16 rules and zero skills into `<repo>/.claude/` and every other
7
+ * writes 13 rules and zero skills (15 package-only, 2 byte-identically deduped at user scope) plus 49 flat-command wrappers into `<repo>/.claude/` and every other
8
8
  * artefact is delivered ONLY by the host-global layer. That removes the build's
9
9
  * own repair path — regeneration can no longer heal a stale global layer,
10
10
  * because it stops writing the affected files at all.
@@ -9720,6 +9720,12 @@ function format_drift_report(entries) {
9720
9720
  // src/scripts/_lib/skill_catalogue.ts
9721
9721
  import * as fs11 from "node:fs";
9722
9722
  import * as path10 from "node:path";
9723
+ var PROJECT_CATALOGUE_ROOTS = ["src/skills", ".claude/skills"];
9724
+ var HOST_CATALOGUE_ROOT = ".claude/skills";
9725
+ var DEFAULT_CATALOGUE_ROOTS = [
9726
+ ...PROJECT_CATALOGUE_ROOTS,
9727
+ `~/${HOST_CATALOGUE_ROOT}`
9728
+ ];
9723
9729
  var OBSERVATION_LOG = path10.join(
9724
9730
  "agents",
9725
9731
  "evidence",
@@ -15544,7 +15550,8 @@ var confidenceBand = external_exports.enum(["off", "low", "medium", "high"]);
15544
15550
  var onBlock = external_exports.enum(["stop", "ask", "warn"]);
15545
15551
  var onBlockFallback = external_exports.enum(["stop", "warn"]);
15546
15552
  var modelAutoSwitch = external_exports.enum(["auto", "suggest", "off"]);
15547
- var leanProjectionMode = external_exports.enum(["eager-all", "thin"]);
15553
+ var leanProjectionMode = external_exports.enum(["eager-all", "thin", "delivery"]);
15554
+ var leanProjectionHost = external_exports.enum(["claude-code", "cursor", "cline"]);
15548
15555
  var projectionMode = external_exports.enum(["legacy-all", "scoped"]);
15549
15556
  var memoryCadence = external_exports.enum(["auto", "always", "never"]);
15550
15557
  var projectAudience = external_exports.enum(["self", "internal", "client", "public"]);
@@ -15576,9 +15583,12 @@ var settingsSchema = external_exports.object({
15576
15583
  ),
15577
15584
  lean_projection: external_exports.object({
15578
15585
  mode: leanProjectionMode.default("eager-all").describe(
15579
- "How the per-tool projector emits the rule layer. eager-all = every rule body inlined into every projection (default, safe). thin = kernel rules full-bodied + non-kernel rules as router-resolved pointers (~45k GPT-tok lighter per session). EXPERIMENTAL: validate with the live A/B before flipping; one-flip revert to eager-all."
15586
+ "How the per-tool projector emits the rule layer. eager-all = every rule body inlined into every projection (safe; what an ABSENT key still resolves to, per ADR-267 decision point 4). thin = kernel rules full-bodied + non-kernel rules as router-resolved pointers (~45k GPT-tok lighter per session), with no delivery mechanism. delivery = thin stubs PLUS the rule-inject hook concern, which delivers a body back on a trigger match; this is the value the SHIPPED TEMPLATE carries for Claude Code since ADR-267, and the activation charge for it is paid in src/config/hook-token-budget.json (user_prompt_submit slot sum 4,096 -> 16,384)."
15587
+ ),
15588
+ hosts: external_exports.array(leanProjectionHost).default(["claude-code"]).describe(
15589
+ "Which hosts a thinning mode may thin (ADR-267). Absent resolves to [claude-code]. Only the three hosts with a per-rule rule tree are accepted, and this enum is the AUTHORING layer: an id outside it is a hard validation FAILURE here and under validate_agent_settings, never a warning. resolveLeanProjectionHosts is the READ-TIME backstop for a hand-edited .agent-settings.yml that passed neither, and THERE the id is dropped with a warning (R2 finding 6 \u2014 the two layers answer differently and neither said so). Every host outside this list receives exactly what eager-all writes, asserted byte-for-byte by check_host_tree_parity."
15580
15590
  )
15581
- }).default({ mode: "eager-all" }),
15591
+ }).default({ mode: "eager-all", hosts: ["claude-code"] }),
15582
15592
  cost: external_exports.object({
15583
15593
  budgets: external_exports.object({
15584
15594
  daily: external_exports.number().min(0).default(0).describe(
@@ -15943,6 +15953,14 @@ var settingsSchema = external_exports.object({
15943
15953
  )
15944
15954
  })
15945
15955
  }),
15956
+ continuity: external_exports.object({
15957
+ auto_record: external_exports.enum(["on", "off"]).default("off").describe(
15958
+ "Deterministic continuity-record writer at session end (road-to-continuity-writer-activation Phase 1). on = the session-eol concern writes the continuity_record capsule variant on Stop for a substantive session that has claimed a roadmap; every field is computed from on-disk state, with no model spend and no subprocess. off (default) = no automatic record \u2014 while session:recycle is still the normal path, a second producer on it before the parity evidence is in would be unverified."
15959
+ ),
15960
+ run_checkpoints: external_exports.enum(["on", "off"]).default("on").describe(
15961
+ "Deterministic run-checkpoint production at session end (road-to-continuity-writer-activation Phase 1.4). on (default) = a session above the recycle threshold and inside a running roadmap contract leaves agents/runtime/state/checkpoints/<run>.json, so a killed run resumes from a derived checkpoint rather than from bookkeeping. off = no checkpoint; continuity writing, the recycle advisory and the context-fill surface are unaffected. Default ON because it is the behaviour the tree already had \u2014 the switch exists to make the three session-end handlers independently disableable, not to change what ships."
15962
+ )
15963
+ }),
15946
15964
  memory: external_exports.object({
15947
15965
  cadence: memoryCadence.default("always").describe(
15948
15966
  "Cadence of the \u{1F9E0} memory-visibility line after a memory-consulting step. always (default) = show whenever a memory type was asked; auto = show only when 3+ types were consulted (less noise); never = suppress. Distinct from rule_loading_tier \u2014 owns its own key since the 2026-06-01 untangle."