@event4u/agent-config 7.5.0 → 8.1.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 (429) hide show
  1. package/.claude-plugin/marketplace.json +8 -1
  2. package/AGENTS.md +9 -9
  3. package/CHANGELOG.md +317 -260
  4. package/README.md +35 -5
  5. package/dist/agent-src/commands/analytics/prune.md +1 -1
  6. package/dist/agent-src/commands/analytics/show.md +1 -1
  7. package/dist/agent-src/commands/analyze/decision.md +2 -2
  8. package/dist/agent-src/commands/analyze/incident.md +2 -2
  9. package/dist/agent-src/commands/analyze/near-miss.md +2 -2
  10. package/dist/agent-src/commands/analyze/postmortem.md +2 -2
  11. package/dist/agent-src/commands/analyze/premortem.md +2 -2
  12. package/dist/agent-src/commands/cost-report.md +25 -0
  13. package/dist/agent-src/commands/evals/analyze.json +30 -0
  14. package/dist/agent-src/commands/evals/mission-upgrade.json +30 -0
  15. package/dist/agent-src/commands/implement-ticket.md +1 -1
  16. package/dist/agent-src/commands/knowledge/forget.md +1 -1
  17. package/dist/agent-src/commands/knowledge/ingest.md +1 -1
  18. package/dist/agent-src/commands/knowledge/list.md +1 -1
  19. package/dist/agent-src/commands/memory/load.md +12 -11
  20. package/dist/agent-src/commands/memory/promote.md +30 -0
  21. package/dist/agent-src/commands/memory/propose.md +16 -2
  22. package/dist/agent-src/commands/mission/upgrade.md +1 -1
  23. package/dist/agent-src/commands/module/explore.md +11 -7
  24. package/dist/agent-src/commands/optimize-project.md +243 -0
  25. package/dist/agent-src/commands/optimize.md +5 -0
  26. package/dist/agent-src/commands/pr/create.md +37 -8
  27. package/dist/agent-src/commands/prediction-pool.md +2 -2
  28. package/dist/agent-src/commands/profile/activate.md +3 -3
  29. package/dist/agent-src/commands/profile/deactivate.md +2 -2
  30. package/dist/agent-src/commands/profile/show.md +3 -3
  31. package/dist/agent-src/commands/research/deep.md +5 -0
  32. package/dist/agent-src/commands/research/report.md +2 -1
  33. package/dist/agent-src/commands/roadmap/create.md +88 -10
  34. package/dist/agent-src/commands/roadmap/materialize.md +1 -1
  35. package/dist/agent-src/commands/roadmap/process-full.md +15 -2
  36. package/dist/agent-src/commands/roadmap/process-phase.md +18 -6
  37. package/dist/agent-src/commands/roadmap/process-step.md +4 -0
  38. package/dist/agent-src/commands/roadmap.md +1 -1
  39. package/dist/agent-src/commands/security-audit-config.md +1 -1
  40. package/dist/agent-src/commands/sync-agent-settings.md +1 -1
  41. package/dist/agent-src/commands/sync-gitignore/fix.md +42 -6
  42. package/dist/agent-src/commands/team-knowledge/bootstrap.md +106 -0
  43. package/dist/agent-src/commands/team-knowledge/consolidate.md +105 -0
  44. package/dist/agent-src/commands/team-knowledge.md +64 -0
  45. package/dist/agent-src/contexts/authority/commit-mechanics.md +8 -0
  46. package/dist/agent-src/contexts/authority/destructive-mechanics.md +11 -0
  47. package/dist/agent-src/contexts/authority/scope-mechanics.md +25 -0
  48. package/dist/agent-src/contexts/communication/rules-auto/reply-close-mechanics.md +43 -0
  49. package/dist/agent-src/contexts/contracts/agents-md-anatomy.md +1 -1
  50. package/dist/agent-src/contexts/contracts/artifact-engagement-flow.md +2 -2
  51. package/dist/agent-src/contexts/contracts/frugality-charter.md +1 -0
  52. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +14 -4
  53. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +11 -0
  54. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +32 -8
  55. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +107 -0
  56. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +71 -15
  57. package/dist/agent-src/contexts/execution/subagent-steering.md +41 -1
  58. package/dist/agent-src/contexts/override-system.md +1 -1
  59. package/dist/agent-src/personas/brand-strategist.md +0 -1
  60. package/dist/agent-src/personas/data-integrity.md +66 -0
  61. package/dist/agent-src/personas/design-director.md +0 -1
  62. package/dist/agent-src/personas/performance-engineer.md +66 -0
  63. package/dist/agent-src/personas/production-validator.md +73 -0
  64. package/dist/agent-src/rules/agent-authority.md +3 -4
  65. package/dist/agent-src/rules/analysis-skill-routing.md +3 -5
  66. package/dist/agent-src/rules/architecture.md +2 -4
  67. package/dist/agent-src/rules/artifact-drafting-protocol.md +35 -6
  68. package/dist/agent-src/rules/artifact-engagement-recording.md +2 -4
  69. package/dist/agent-src/rules/ask-when-uncertain.md +10 -14
  70. package/dist/agent-src/rules/augment-edit-discipline.md +3 -5
  71. package/dist/agent-src/rules/autonomous-execution.md +3 -5
  72. package/dist/agent-src/rules/brand-consistency.md +3 -5
  73. package/dist/agent-src/rules/brand-source-of-truth.md +3 -5
  74. package/dist/agent-src/rules/cli-output-handling.md +4 -6
  75. package/dist/agent-src/rules/command-suggestion-policy.md +3 -5
  76. package/dist/agent-src/rules/commit-conventions.md +3 -5
  77. package/dist/agent-src/rules/commit-policy.md +18 -10
  78. package/dist/agent-src/rules/content-quoting-floor.md +88 -0
  79. package/dist/agent-src/rules/context-hygiene.md +3 -5
  80. package/dist/agent-src/rules/copilot-routing.md +4 -6
  81. package/dist/agent-src/rules/decision-revisit-gate.md +120 -0
  82. package/dist/agent-src/rules/delegation-policy.md +10 -6
  83. package/dist/agent-src/rules/design-fidelity.md +3 -5
  84. package/dist/agent-src/rules/devcontainer-routing.md +4 -6
  85. package/dist/agent-src/rules/direct-answers.md +13 -17
  86. package/dist/agent-src/rules/docker-commands.md +3 -5
  87. package/dist/agent-src/rules/domain-adoption-policy.md +3 -5
  88. package/dist/agent-src/rules/domain-safety-disclaimer.md +3 -5
  89. package/dist/agent-src/rules/domain-safety-pii.md +3 -5
  90. package/dist/agent-src/rules/domain-safety-retention.md +3 -5
  91. package/dist/agent-src/rules/downstream-changes.md +3 -4
  92. package/dist/agent-src/rules/engineering-safety-floor.md +3 -5
  93. package/dist/agent-src/rules/external-reference-deep-dive.md +3 -5
  94. package/dist/agent-src/rules/fast-path-marker-visibility.md +3 -5
  95. package/dist/agent-src/rules/finance-safety-floor.md +3 -6
  96. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +3 -5
  97. package/dist/agent-src/rules/git-history-discipline.md +3 -5
  98. package/dist/agent-src/rules/guidelines.md +2 -4
  99. package/dist/agent-src/rules/icon-consistency.md +3 -5
  100. package/dist/agent-src/rules/image-likeness-and-rights.md +3 -5
  101. package/dist/agent-src/rules/improve-before-implement.md +5 -5
  102. package/dist/agent-src/rules/invite-challenge.md +3 -5
  103. package/dist/agent-src/rules/language-and-tone.md +13 -15
  104. package/dist/agent-src/rules/laravel-routing.md +3 -5
  105. package/dist/agent-src/rules/laravel-translations.md +3 -5
  106. package/dist/agent-src/rules/legal-safety-floor.md +3 -5
  107. package/dist/agent-src/rules/lethal-trifecta-guard.md +3 -5
  108. package/dist/agent-src/rules/linked-projects-onboarding-gate.md +4 -7
  109. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +3 -5
  110. package/dist/agent-src/rules/markdown-safe-codeblocks.md +2 -4
  111. package/dist/agent-src/rules/media-governance-routing.md +3 -5
  112. package/dist/agent-src/rules/media-sync-ground-truth.md +3 -5
  113. package/dist/agent-src/rules/minimal-safe-diff.md +5 -5
  114. package/dist/agent-src/rules/missing-tool-handling.md +3 -5
  115. package/dist/agent-src/rules/model-recommendation.md +4 -6
  116. package/dist/agent-src/rules/no-attribution-footers.md +3 -5
  117. package/dist/agent-src/rules/no-cheap-questions.md +5 -8
  118. package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +3 -6
  119. package/dist/agent-src/rules/no-pr-progress-comments.md +3 -6
  120. package/dist/agent-src/rules/no-roadmap-references.md +3 -5
  121. package/dist/agent-src/rules/non-destructive-by-default.md +11 -13
  122. package/dist/agent-src/rules/notes-first-reasoning.md +3 -5
  123. package/dist/agent-src/rules/onboarding-gate.md +4 -6
  124. package/dist/agent-src/rules/output-discipline.md +3 -5
  125. package/dist/agent-src/rules/package-ci-checks.md +3 -5
  126. package/dist/agent-src/rules/persona-governance.md +2 -4
  127. package/dist/agent-src/rules/php-coding.md +3 -5
  128. package/dist/agent-src/rules/preservation-guard.md +2 -4
  129. package/dist/agent-src/rules/provider-lifecycle-discipline.md +3 -5
  130. package/dist/agent-src/rules/reviewer-awareness.md +5 -6
  131. package/dist/agent-src/rules/roadmap-ci-steps-policy.md +3 -5
  132. package/dist/agent-src/rules/roadmap-progress-sync.md +5 -5
  133. package/dist/agent-src/rules/role-mode-adherence.md +2 -4
  134. package/dist/agent-src/rules/rule-type-governance.md +3 -5
  135. package/dist/agent-src/rules/runtime-safety.md +2 -4
  136. package/dist/agent-src/rules/scope-control.md +10 -11
  137. package/dist/agent-src/rules/security-sensitive-stop.md +4 -5
  138. package/dist/agent-src/rules/size-enforcement.md +2 -4
  139. package/dist/agent-src/rules/skill-improvement-trigger.md +3 -5
  140. package/dist/agent-src/rules/skill-quality.md +3 -5
  141. package/dist/agent-src/rules/slash-command-routing-policy.md +3 -5
  142. package/dist/agent-src/rules/source-confidentiality.md +3 -5
  143. package/dist/agent-src/rules/source-discovery-gate.md +3 -5
  144. package/dist/agent-src/rules/source-of-truth.md +3 -5
  145. package/dist/agent-src/rules/strategy-safety-floor.md +3 -5
  146. package/dist/agent-src/rules/symfony-routing.md +4 -6
  147. package/dist/agent-src/rules/telegraph-speak.md +4 -5
  148. package/dist/agent-src/rules/think-before-action.md +7 -4
  149. package/dist/agent-src/rules/token-budget-discipline.md +29 -5
  150. package/dist/agent-src/rules/token-efficiency.md +3 -5
  151. package/dist/agent-src/rules/token-optimizer-maintenance.md +3 -5
  152. package/dist/agent-src/rules/tool-safety.md +2 -4
  153. package/dist/agent-src/rules/ui-audit-gate.md +3 -6
  154. package/dist/agent-src/rules/untrusted-input-defense.md +3 -5
  155. package/dist/agent-src/rules/upstream-proposal.md +4 -6
  156. package/dist/agent-src/rules/user-interaction.md +7 -5
  157. package/dist/agent-src/rules/user-interrupt-priority.md +17 -8
  158. package/dist/agent-src/rules/verify-before-complete.md +12 -22
  159. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +3 -3
  160. package/dist/agent-src/scripts/update_roadmap_progress.ts +197 -7
  161. package/dist/agent-src/skills/adr-create/SKILL.md +48 -42
  162. package/dist/agent-src/skills/agent-docs-writing/SKILL.md +18 -0
  163. package/dist/agent-src/skills/agent-security-review/SKILL.md +1 -1
  164. package/dist/agent-src/skills/ai-council/SKILL.md +14 -1
  165. package/dist/agent-src/skills/blameless-post-mortem/SKILL.md +0 -3
  166. package/dist/agent-src/skills/brand/SKILL.md +1 -1
  167. package/dist/agent-src/skills/brand-identity/SKILL.md +3 -3
  168. package/dist/agent-src/skills/brand-strategy/SKILL.md +1 -1
  169. package/dist/agent-src/skills/brand-to-tokens/SKILL.md +3 -3
  170. package/dist/agent-src/skills/canvas-design/SKILL.md +6 -0
  171. package/dist/agent-src/skills/check-refs/SKILL.md +7 -4
  172. package/dist/agent-src/skills/code-review/SKILL.md +1 -0
  173. package/dist/agent-src/skills/complexity-first-planning/SKILL.md +6 -5
  174. package/dist/agent-src/skills/condense-memory/SKILL.md +11 -11
  175. package/dist/agent-src/skills/context-document/SKILL.md +17 -0
  176. package/dist/agent-src/skills/corpus-grounding/SKILL.md +3 -3
  177. package/dist/agent-src/skills/decision-record/SKILL.md +6 -0
  178. package/dist/agent-src/skills/decision-review/SKILL.md +5 -3
  179. package/dist/agent-src/skills/deep-reading-analyst/SKILL.md +6 -1
  180. package/dist/agent-src/skills/design-intelligence/SKILL.md +5 -2
  181. package/dist/agent-src/skills/design-intelligence/references/design-languages.md +1 -1
  182. package/dist/agent-src/skills/design-tokens/SKILL.md +10 -4
  183. package/dist/agent-src/skills/design-variations/SKILL.md +127 -0
  184. package/dist/agent-src/skills/design-variations/evals/triggers.json +17 -0
  185. package/dist/agent-src/skills/emit-tickets/SKILL.md +4 -4
  186. package/dist/agent-src/skills/fe-design/SKILL.md +20 -0
  187. package/dist/agent-src/skills/html-deck/SKILL.md +123 -0
  188. package/dist/agent-src/skills/html-deck/evals/triggers.json +17 -0
  189. package/dist/agent-src/skills/html-deck/templates/deck-shell.html +77 -0
  190. package/dist/agent-src/skills/judge-code-quality/SKILL.md +1 -0
  191. package/dist/agent-src/skills/laravel/SKILL.md +0 -1
  192. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +46 -0
  193. package/dist/agent-src/skills/lint-skills/SKILL.md +6 -6
  194. package/dist/agent-src/skills/md-language-check/SKILL.md +3 -3
  195. package/dist/agent-src/skills/memory-consolidation/SKILL.md +66 -1
  196. package/dist/agent-src/skills/migration-architect/SKILL.md +1 -0
  197. package/dist/agent-src/skills/module-detect-on-the-fly/SKILL.md +2 -2
  198. package/dist/agent-src/skills/performance-analysis/SKILL.md +2 -0
  199. package/dist/agent-src/skills/prediction-pool-optimizer/SKILL.md +4 -4
  200. package/dist/agent-src/skills/premortem/SKILL.md +0 -3
  201. package/dist/agent-src/skills/project-analysis-core/SKILL.md +16 -0
  202. package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +3 -1
  203. package/dist/agent-src/skills/release-comms/SKILL.md +46 -45
  204. package/dist/agent-src/skills/roadmap-management/SKILL.md +21 -0
  205. package/dist/agent-src/skills/roadmap-writing/SKILL.md +32 -2
  206. package/dist/agent-src/skills/root-cause-frameworks/SKILL.md +0 -3
  207. package/dist/agent-src/skills/security-audit/SKILL.md +1 -0
  208. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +4 -0
  209. package/dist/agent-src/skills/source-discovery/SKILL.md +22 -3
  210. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +33 -14
  211. package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +11 -0
  212. package/dist/agent-src/skills/subagent-orchestration/prompts/do-in-steps.md +8 -0
  213. package/dist/agent-src/skills/systematic-debugging/SKILL.md +29 -0
  214. package/dist/agent-src/skills/threat-modeling/SKILL.md +2 -2
  215. package/dist/agent-src/skills/typography-system/SKILL.md +2 -2
  216. package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +2 -0
  217. package/dist/agent-src/skills/wireframe/SKILL.md +118 -0
  218. package/dist/agent-src/skills/wireframe/evals/triggers.json +17 -0
  219. package/dist/agent-src/templates/agent-settings.md +22 -1
  220. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  221. package/dist/agent-src/templates/command.md +2 -2
  222. package/dist/agent-src/templates/contexts/knowledge-pages.md +116 -0
  223. package/dist/agent-src/templates/hooks/pre-commit-frontmatter +1 -1
  224. package/dist/agent-src/templates/roadmaps.md +70 -2
  225. package/dist/agent-src/templates/rule.md +1 -1
  226. package/dist/agent-src/templates/scripts/README.md +3 -3
  227. package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +109 -0
  228. package/dist/agent-src/templates/tickets.md +8 -8
  229. package/dist/cli/commands/recordTriggerEval.test.js +1 -1
  230. package/dist/cli/commands/recordTriggerEval.test.js.map +1 -1
  231. package/dist/cli/initRouting.js +4 -2
  232. package/dist/cli/initRouting.js.map +1 -1
  233. package/dist/cli/registry.js +1 -0
  234. package/dist/cli/registry.js.map +1 -1
  235. package/dist/discovery/deprecation-report.md +1 -1
  236. package/dist/discovery/discovery-manifest.json +718 -240
  237. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  238. package/dist/discovery/discovery-manifest.summary.md +8 -8
  239. package/dist/discovery/orphan-report.md +1 -1
  240. package/dist/discovery/packs.json +43 -28
  241. package/dist/discovery/trust-report.md +12 -11
  242. package/dist/discovery/workspaces.json +29 -18
  243. package/dist/install/preflight.js +173 -0
  244. package/dist/install/preflight.js.map +1 -0
  245. package/dist/mcp/registry-manifest.json +4 -4
  246. package/dist/router.json +1 -1
  247. package/dist/server/routes/settings.js +4 -0
  248. package/dist/server/routes/settings.js.map +1 -1
  249. package/dist/server/schemas/settings.js +3 -1
  250. package/dist/server/schemas/settings.js.map +1 -1
  251. package/docs/CLAIMS.md +108 -0
  252. package/docs/MIGRATION.md +3 -3
  253. package/docs/architecture.md +5 -5
  254. package/docs/archive/CHANGELOG-pre-8.0.0.md +301 -0
  255. package/docs/benchmark.md +133 -2
  256. package/docs/benchmark.pinned.yml +31 -0
  257. package/docs/capability-matrix.md +1 -0
  258. package/docs/catalog.md +70 -60
  259. package/docs/command-flows.md +15 -3
  260. package/docs/comparison.yaml +35 -0
  261. package/docs/contracts/agents-layout.md +148 -0
  262. package/docs/contracts/brand-token-consumption.md +5 -0
  263. package/docs/contracts/capability-boundary.md +5 -0
  264. package/docs/contracts/command-category-governance.md +5 -0
  265. package/docs/contracts/command-clusters.md +1 -0
  266. package/docs/contracts/command-surface-tiers.md +1 -1
  267. package/docs/contracts/conformance.md +84 -0
  268. package/docs/contracts/creative-pack-boundary.md +5 -0
  269. package/docs/contracts/discovery-manifest.schema.json +5 -4
  270. package/docs/contracts/file-ownership-matrix.json +4605 -985
  271. package/docs/contracts/governance-enforcement-projection.md +5 -0
  272. package/docs/contracts/gui-wizard.md +1 -1
  273. package/docs/contracts/hook-architecture-v1.md +2 -2
  274. package/docs/contracts/implement-ticket-flow.md +1 -1
  275. package/docs/contracts/kernel-membership.md +13 -0
  276. package/docs/contracts/mcp-tool-inventory.md +23 -23
  277. package/docs/contracts/no-runtime-boundary.md +6 -1
  278. package/docs/contracts/review-lens-schema.md +5 -0
  279. package/docs/contracts/rule-router.md +102 -8
  280. package/docs/contracts/skill-bundled-assets.md +1 -1
  281. package/docs/contracts/skill-dry-run.md +1 -1
  282. package/docs/contracts/subagent-boundary.md +5 -0
  283. package/docs/contracts/ticket-bundle-format.md +9 -4
  284. package/docs/contracts/tier-3-contrib-plugin.md +2 -2
  285. package/docs/contracts/write-engine.md +3 -0
  286. package/docs/customization.md +87 -15
  287. package/docs/decisions/ADR-107-legal-domain-pack-adoption.md +1 -1
  288. package/docs/decisions/ADR-109-subagent-v1-contract.md +246 -0
  289. package/docs/decisions/ADR-110-discipline-profile-resolution-locus.md +105 -0
  290. package/docs/decisions/INDEX.md +2 -0
  291. package/docs/distribution/awesome-list-submission.md +46 -0
  292. package/docs/distribution/launch-story-draft.md +58 -0
  293. package/docs/end-to-end-walkthroughs.md +2 -2
  294. package/docs/getting-started.md +2 -2
  295. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +24 -0
  296. package/docs/guidelines/agent-infra/corpus-grounding-authoring.md +1 -1
  297. package/docs/guidelines/agent-infra/linked-projects-onboarding-gate.md +2 -2
  298. package/docs/guidelines/agent-infra/missing-tool-handling.md +3 -3
  299. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
  300. package/docs/guidelines/augment-portability-patterns.md +1 -1
  301. package/docs/guidelines/code-clarity.md +19 -0
  302. package/docs/guidelines/design-antipatterns-triggers.json +2 -1
  303. package/docs/guidelines/design-antipatterns.md +10 -1
  304. package/docs/guidelines/design-modes.md +6 -0
  305. package/docs/guidelines/php/general.md +9 -1
  306. package/docs/guidelines/php/php-coding-patterns.md +7 -0
  307. package/docs/guides/cross-repo-retrieval.md +1 -1
  308. package/docs/guides/frontend-design-corpus-refresh.md +2 -2
  309. package/docs/guides/local-analytics.md +4 -4
  310. package/docs/guides/skill-discovery.md +1 -1
  311. package/docs/guides/skill-preview.md +1 -1
  312. package/docs/hook-payload-capture.md +6 -6
  313. package/docs/install-friction-report.md +66 -0
  314. package/docs/installation.md +1 -1
  315. package/docs/maintainers/optional-media-deps.md +50 -0
  316. package/docs/mcp-server.md +11 -12
  317. package/docs/media/proof-demo.cast +14 -0
  318. package/docs/media/proof-demo.gif +0 -0
  319. package/docs/migration/consumer-template-consumption-model.md +1 -1
  320. package/docs/migration/divergences/bench-stats-float-precision.md +1 -1
  321. package/docs/migration/node-floor.md +1 -1
  322. package/docs/migration/yaml-roundtrip-spike.md +1 -1
  323. package/docs/personas.md +16 -5
  324. package/docs/positioning-evidence.md +86 -0
  325. package/docs/proof.md +86 -0
  326. package/docs/skills-catalog.md +1 -1
  327. package/docs/troubleshooting.md +8 -8
  328. package/docs/wedge/production-validator/README.md +57 -0
  329. package/docs/wedge/production-validator/production-validator.md +56 -0
  330. package/docs/wizard.md +2 -2
  331. package/package.json +1 -1
  332. package/src/config/agent-settings.template.yml +59 -4
  333. package/src/config/agents-paths.yml +254 -0
  334. package/src/config/budgets.yml +16 -0
  335. package/src/config/discovery/packs.yml +1 -0
  336. package/src/config/discovery/unassigned-artefacts.yml +2 -0
  337. package/src/config/gitignore-block.txt +25 -0
  338. package/src/config/host-capabilities.yml +31 -0
  339. package/src/config/profiles/balanced.ini +4 -0
  340. package/src/config/profiles/full.ini +4 -0
  341. package/src/config/profiles/minimal.ini +4 -0
  342. package/src/scripts/_cli/cmd_conformance.ts +716 -0
  343. package/src/scripts/_cli/cmd_doctor.ts +23 -2
  344. package/src/scripts/_cli/cmd_fleet.ts +401 -0
  345. package/src/scripts/_cli/cmd_preflight.ts +159 -0
  346. package/src/scripts/_dispatch.bash +10 -0
  347. package/src/scripts/_lib/knowledge_events.ts +193 -0
  348. package/src/scripts/_lib/subagent_steering.ts +115 -3
  349. package/src/scripts/_lib/text_similarity.ts +75 -0
  350. package/src/scripts/ai-video/test-pipeline.sh +1 -1
  351. package/src/scripts/ai_council/clients.ts +19 -3
  352. package/src/scripts/append_contested.ts +112 -0
  353. package/src/scripts/audit_auto_rules.ts +11 -1
  354. package/src/scripts/audit_mcp_tools.ts +25 -11
  355. package/src/scripts/bench_ab_v2_run.ts +527 -40
  356. package/src/scripts/bench_ab_v2_stats.ts +6 -0
  357. package/src/scripts/bench_matrix.ts +266 -0
  358. package/src/scripts/bootstrap_knowledge.ts +267 -0
  359. package/src/scripts/build_discovery_manifest.ts +42 -2
  360. package/src/scripts/build_proof.ts +214 -0
  361. package/src/scripts/check_always_budget.ts +3 -0
  362. package/src/scripts/check_augment_description_cap.ts +2 -2
  363. package/src/scripts/check_claims.ts +270 -0
  364. package/src/scripts/check_comparison.ts +79 -0
  365. package/src/scripts/check_generated_artefact_headers.ts +109 -0
  366. package/src/scripts/check_generator_output_coverage.ts +142 -0
  367. package/src/scripts/check_gitignore_freshness.ts +127 -0
  368. package/src/scripts/check_knowledge_pages.ts +210 -0
  369. package/src/scripts/check_knowledge_sharing.ts +162 -0
  370. package/src/scripts/check_media_deps.ts +91 -0
  371. package/src/scripts/check_memory_contradiction.ts +280 -0
  372. package/src/scripts/check_memory_similarity.ts +134 -0
  373. package/src/scripts/check_quality_regression.ts +56 -10
  374. package/src/scripts/check_references.ts +3 -1
  375. package/src/scripts/check_release_pr_shape.ts +4 -0
  376. package/src/scripts/check_site_links.ts +135 -0
  377. package/src/scripts/check_skill_gaps.ts +99 -0
  378. package/src/scripts/check_token_quality_golden.ts +197 -11
  379. package/src/scripts/check_tracked_but_ignored.ts +67 -0
  380. package/src/scripts/cluster_near_miss_patterns.ts +0 -0
  381. package/src/scripts/compile_router.ts +30 -3
  382. package/src/scripts/condense.ts +350 -14
  383. package/src/scripts/consolidate_knowledge_events.ts +192 -0
  384. package/src/scripts/degrade_to_pointer.ts +136 -0
  385. package/src/scripts/design_slop_rules.test.ts +15 -0
  386. package/src/scripts/design_slop_rules.ts +28 -0
  387. package/src/scripts/emit_knowledge_event.ts +158 -0
  388. package/src/scripts/export_replay_corpus.ts +187 -0
  389. package/src/scripts/external_sources_denylist.json +7 -2
  390. package/src/scripts/fold_intake.ts +281 -0
  391. package/src/scripts/generate_capability_matrix.ts +9 -1
  392. package/src/scripts/generate_knowledge_index.ts +222 -0
  393. package/src/scripts/hook_manifest.yaml +26 -14
  394. package/src/scripts/hooks/dispatch_hook.ts +18 -0
  395. package/src/scripts/hot_context_hook.ts +372 -0
  396. package/src/scripts/install +47 -0
  397. package/src/scripts/install-hooks.sh +17 -0
  398. package/src/scripts/inventory_meta_layers.ts +11 -0
  399. package/src/scripts/janitor.ts +258 -0
  400. package/src/scripts/lint_agents_layout.ts +74 -15
  401. package/src/scripts/lint_bench_ab.ts +4 -1
  402. package/src/scripts/lint_featured_skills.ts +0 -0
  403. package/src/scripts/lint_framework_leakage_allowlist.json +26 -3
  404. package/src/scripts/lint_knowledge_scale.ts +250 -0
  405. package/src/scripts/lint_legal_pack.ts +67 -0
  406. package/src/scripts/lint_persona_governance.ts +8 -3
  407. package/src/scripts/lint_regression.ts +15 -0
  408. package/src/scripts/lint_roadmap_blockers.ts +202 -0
  409. package/src/scripts/lint_roadmap_complexity.ts +81 -2
  410. package/src/scripts/lint_subagent_determinism.ts +125 -0
  411. package/src/scripts/measure_augment_budget.ts +46 -6
  412. package/src/scripts/measure_patterns.ts +4 -3
  413. package/src/scripts/measure_skill_reduction.ts +6 -6
  414. package/src/scripts/migration_status.ts +6 -2
  415. package/src/scripts/mine_missing_guardrails.ts +189 -0
  416. package/src/scripts/parity/phase_gate.ts +1 -1
  417. package/src/scripts/parity/replay.ts +21 -0
  418. package/src/scripts/project_thin_rules.ts +120 -16
  419. package/src/scripts/release.ts +39 -1
  420. package/src/scripts/render_benchmark_composite.ts +378 -0
  421. package/src/scripts/roadmap_progress_hook.ts +101 -43
  422. package/src/scripts/schemas/skill.schema.json +27 -0
  423. package/src/scripts/schemas/subagent.schema.json +106 -0
  424. package/src/scripts/skill_linter.ts +1 -0
  425. package/src/scripts/smoke/kernel.sh +5 -4
  426. package/src/scripts/surface-tiers.yml +1 -0
  427. package/src/scripts/sync_gitignore.ts +4 -0
  428. package/src/scripts/update_skill_candidates.ts +172 -0
  429. package/src/scripts/validate_frontmatter.ts +1 -0
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Team-sharing gate for `agents/knowledge/` — road-to-knowledge-system
4
+ * Phase 3. Pre-commit check: storage location IS the sharing policy (per
5
+ * the 2026-07-05 council verdict), so this gate exists to catch the two
6
+ * ways that policy can be violated by accident:
7
+ *
8
+ * 1. A gitignored intake file staged anyway (via `git add -f` or a
9
+ * misconfigured .gitignore) — BLOCK. Intake is local scratch; it
10
+ * must never reach a commit.
11
+ * 2. A page under `agents/knowledge/` carrying `visibility: private`
12
+ * in its frontmatter — BLOCK. A private-scoped entry belongs in the
13
+ * user-global store, never in the team-shared repo path (mirrors
14
+ * the "link" reference's team-sync share-readiness gate).
15
+ *
16
+ * Creation budget (≥ 5 NEW files under `agents/knowledge/` in one
17
+ * commit) is a WARNING, not a block — large legitimate batches (e.g. a
18
+ * bootstrap run) should not be hard-refused, just flagged for a second
19
+ * look.
20
+ *
21
+ * Usage: check_knowledge_sharing.ts [--staged-files <path-list-file>]
22
+ * Without --staged-files, reads the real `git diff --cached` state.
23
+ *
24
+ * Exit codes: 0 = clean or warn-only, 1 = blocked, 3 = internal error.
25
+ */
26
+ import { execFileSync } from 'node:child_process';
27
+ import * as path from 'node:path';
28
+ import process from 'node:process';
29
+ import { fileURLToPath } from 'node:url';
30
+ import YAML from 'yaml';
31
+
32
+ const PROG = 'check_knowledge_sharing.ts';
33
+ const CREATION_BUDGET_WARN = 5;
34
+ const FRONTMATTER_RE = /^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n/;
35
+
36
+ export interface StagedFile {
37
+ path: string;
38
+ status: 'A' | 'M' | 'D' | 'R' | string;
39
+ }
40
+
41
+ function isPlainObject(v: unknown): v is Record<string, unknown> {
42
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
43
+ }
44
+
45
+ /** Parse `git diff --cached --name-status` output (also accepted pre-split for tests). */
46
+ export function parseNameStatus(raw: string): StagedFile[] {
47
+ const out: StagedFile[] = [];
48
+ for (const line of raw.split('\n')) {
49
+ if (!line.trim()) continue;
50
+ const [status, ...rest] = line.split('\t');
51
+ const path = rest[rest.length - 1]; // renames carry old\tnew — keep the new path
52
+ const statusChar = status?.[0];
53
+ if (!statusChar || !path) continue;
54
+ out.push({ path, status: statusChar });
55
+ }
56
+ return out;
57
+ }
58
+
59
+ export interface SharingReport {
60
+ blocked: string[]; // human-readable block reasons
61
+ warnings: string[]; // human-readable warnings
62
+ }
63
+
64
+ /** Pure — takes staged files + a content-reader so tests never touch the real filesystem or git. */
65
+ export function checkSharing(staged: StagedFile[], readContent: (path: string) => string | null): SharingReport {
66
+ const blocked: string[] = [];
67
+ const warnings: string[] = [];
68
+
69
+ const intakeFiles = staged.filter(
70
+ (f) => f.path.startsWith('agents/memory/intake/') || f.path.startsWith('agents/knowledge/intake/'),
71
+ );
72
+ for (const f of intakeFiles) {
73
+ blocked.push(`${f.path}: gitignored intake staged — intake is local scratch, never committed`);
74
+ }
75
+
76
+ const knowledgeFiles = staged.filter(
77
+ (f) => f.path.startsWith('agents/knowledge/') && !f.path.startsWith('agents/knowledge/intake/') && f.path.endsWith('.md'),
78
+ );
79
+ for (const f of knowledgeFiles) {
80
+ const content = readContent(f.path);
81
+ if (content === null) continue;
82
+ const match = FRONTMATTER_RE.exec(content);
83
+ if (match?.[1] === undefined) continue;
84
+ let fm: unknown;
85
+ try {
86
+ fm = YAML.parse(match[1]);
87
+ } catch {
88
+ continue;
89
+ }
90
+ if (isPlainObject(fm) && fm.visibility === 'private') {
91
+ blocked.push(`${f.path}: visibility: private — belongs in the user-global knowledge store, not the team-shared repo`);
92
+ }
93
+ }
94
+
95
+ const newKnowledgeFiles = staged.filter(
96
+ (f) => f.status === 'A' && f.path.startsWith('agents/knowledge/') && !f.path.startsWith('agents/knowledge/intake/'),
97
+ );
98
+ if (newKnowledgeFiles.length >= CREATION_BUDGET_WARN) {
99
+ warnings.push(
100
+ `${newKnowledgeFiles.length} new files under agents/knowledge/ in this commit — review the batch (creation budget: ${CREATION_BUDGET_WARN})`,
101
+ );
102
+ }
103
+
104
+ return { blocked, warnings };
105
+ }
106
+
107
+ function gitStagedNameStatus(): string {
108
+ return execFileSync('git', ['diff', '--cached', '--name-status'], { encoding: 'utf8' });
109
+ }
110
+
111
+ function gitStagedContent(path: string): string | null {
112
+ try {
113
+ return execFileSync('git', ['show', `:${path}`], { encoding: 'utf8' });
114
+ } catch {
115
+ return null;
116
+ }
117
+ }
118
+
119
+ function printUsage(): void {
120
+ process.stdout.write(`usage: ${PROG}\n`);
121
+ }
122
+
123
+ export function main(argv: string[]): number {
124
+ for (const arg of argv) {
125
+ if (arg === '-h' || arg === '--help') {
126
+ printUsage();
127
+ return 0;
128
+ }
129
+ process.stderr.write(`${PROG}: error: unrecognized argument: ${arg}\n`);
130
+ printUsage();
131
+ return 1;
132
+ }
133
+
134
+ let staged: StagedFile[];
135
+ try {
136
+ staged = parseNameStatus(gitStagedNameStatus());
137
+ } catch (err) {
138
+ process.stderr.write(`${PROG}: error: git diff --cached failed: ${(err as Error).message}\n`);
139
+ return 3;
140
+ }
141
+
142
+ const { blocked, warnings } = checkSharing(staged, gitStagedContent);
143
+
144
+ for (const w of warnings) {
145
+ process.stdout.write(`🟡 ${w}\n`);
146
+ }
147
+
148
+ if (blocked.length > 0) {
149
+ for (const b of blocked) {
150
+ process.stderr.write(`❌ ${b}\n`);
151
+ }
152
+ process.stderr.write(`${PROG}: commit blocked — ${blocked.length} sharing violation(s).\n`);
153
+ return 1;
154
+ }
155
+
156
+ process.stdout.write(`${PROG}: sharing gate clear.\n`);
157
+ return 0;
158
+ }
159
+
160
+ if (fileURLToPath(import.meta.url) === path.resolve(process.argv[1] ?? '')) {
161
+ process.exit(main(process.argv.slice(2)));
162
+ }
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Detect-and-instruct check for the optional **media tooling** (B8 recorded
4
+ * proof-page demos): `asciinema` (records a terminal session to a `.cast`) and
5
+ * `agg` (converts a `.cast` → animated GIF).
6
+ *
7
+ * Per the `missing-tool-handling` rule the package NEVER installs a system
8
+ * binary silently — it detects, prints the exact platform install command, and
9
+ * exits non-zero (the same shape as the docker check in taskfiles/mcp.yml). So
10
+ * every maintainer gets a consistent on-demand prompt; nobody gets a surprise
11
+ * install. Called as the prereq of any B8 recording task.
12
+ *
13
+ * Exit 0 = all present · 1 = at least one missing (prints install hints).
14
+ *
15
+ * Usage:
16
+ * ./scripts-run src/scripts/check_media_deps
17
+ * ./scripts-run src/scripts/check_media_deps --quiet # print only on failure
18
+ */
19
+ import { spawnSync } from 'node:child_process';
20
+ import * as path from 'node:path';
21
+ import { fileURLToPath, pathToFileURL } from 'node:url';
22
+
23
+ const _FILE = fileURLToPath(import.meta.url);
24
+
25
+ export interface MediaTool {
26
+ bin: string;
27
+ purpose: string;
28
+ install: { darwin: string; linux: string; other: string };
29
+ }
30
+
31
+ export const MEDIA_TOOLS: MediaTool[] = [
32
+ {
33
+ bin: 'asciinema',
34
+ purpose: 'record a terminal session to a .cast (B8 proof-page demos)',
35
+ install: {
36
+ darwin: 'brew install asciinema',
37
+ linux: 'pipx install asciinema # or your distro package manager',
38
+ other: 'see the asciinema install docs for your platform',
39
+ },
40
+ },
41
+ {
42
+ bin: 'agg',
43
+ purpose: 'convert a .cast → animated GIF (asciinema gif generator)',
44
+ install: {
45
+ darwin: 'brew install agg',
46
+ linux: 'cargo install --locked agg # or grab a release binary',
47
+ other: 'see the agg install docs for your platform',
48
+ },
49
+ },
50
+ ];
51
+
52
+ /** True when `bin` is runnable on PATH (probed with `--version`). */
53
+ export function isPresent(bin: string): boolean {
54
+ const r = spawnSync(bin, ['--version'], { stdio: 'ignore' });
55
+ // ENOENT → not on PATH. A non-zero exit with no spawn error still means the
56
+ // binary exists (some tools return non-zero for --version), so key off error.
57
+ return !r.error;
58
+ }
59
+
60
+ export function installHint(tool: MediaTool, platform: NodeJS.Platform = process.platform): string {
61
+ if (platform === 'darwin') return tool.install.darwin;
62
+ if (platform === 'linux') return tool.install.linux;
63
+ return tool.install.other;
64
+ }
65
+
66
+ /** Return the subset of `tools` that are not installed. */
67
+ export function missingTools(tools: MediaTool[] = MEDIA_TOOLS): MediaTool[] {
68
+ return tools.filter((t) => !isPresent(t.bin));
69
+ }
70
+
71
+ export function main(argv: string[] = process.argv.slice(2)): number {
72
+ const quiet = argv.includes('--quiet');
73
+ const missing = missingTools();
74
+ if (missing.length === 0) {
75
+ if (!quiet) {
76
+ process.stdout.write(`✅ media tooling: ${MEDIA_TOOLS.map((t) => t.bin).join(' + ')} present.\n`);
77
+ }
78
+ return 0;
79
+ }
80
+ process.stderr.write(`❌ media tooling missing (${missing.map((t) => t.bin).join(', ')}) — required for B8 recorded demos.\n`);
81
+ process.stderr.write(' The package never installs system binaries for you (missing-tool-handling). Install on demand:\n\n');
82
+ for (const t of missing) {
83
+ process.stderr.write(` ${t.bin} — ${t.purpose}\n ${installHint(t)}\n`);
84
+ }
85
+ process.stderr.write('\n Then re-run this check.\n');
86
+ return 1;
87
+ }
88
+
89
+ const _isCli =
90
+ process.argv[1] !== undefined && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href;
91
+ if (_isCli) process.exit(main());
@@ -0,0 +1,280 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Contradiction surfacing for `/memory promote` — road-to-second-brain
4
+ * Phase 2 (council 2026-07-07, verdict:
5
+ * `agents/settings/contexts/second-brain-delta-verdict.md`).
6
+ *
7
+ * Mechanical detector, deliberately NOT NLI: a candidate entry that shares a
8
+ * PRIMARY KEY with an existing curated entry of the same durable type but has
9
+ * LOW body similarity (Jaccard < 0.3) is a potential contradiction — same
10
+ * topic, different claim. High similarity on the same key is a rewording /
11
+ * extension (dedup territory, handled by `check_memory_similarity.ts`);
12
+ * different keys are different topics.
13
+ *
14
+ * Scoped to the behaviorally load-bearing durable types only
15
+ * (`incident-learnings`, `product-rules`, `domain-invariants` by default) —
16
+ * exploratory types evolve legitimately and are never checked.
17
+ *
18
+ * The detector SURFACES; it never resolves. Resolution goes through the
19
+ * existing contested flow in `/memory promote` (approve new + mark old
20
+ * `contested` with provenance, or revise the new entry). Auto-resolution is
21
+ * on the council REJECT list.
22
+ *
23
+ * Usage:
24
+ * check_memory_contradiction.ts --type <type> --key <primary-key> \
25
+ * --body "<text>" [--memory-root <dir>] [--durable-types a,b,c] [--format text|json]
26
+ *
27
+ * Exit codes: 0 = no contradiction (or type not durable — silent no-op),
28
+ * 1 = potential contradiction found (surface the pair, ask the human),
29
+ * 2 = usage error, 3 = internal error.
30
+ */
31
+ import * as fs from 'node:fs';
32
+ import * as path from 'node:path';
33
+ import process from 'node:process';
34
+ import { fileURLToPath } from 'node:url';
35
+ import YAML from 'yaml';
36
+
37
+ import { jaccardSimilarity } from './_lib/text_similarity.js';
38
+
39
+ const PROG = 'check_memory_contradiction.ts';
40
+
41
+ export const CONTRADICTION_THRESHOLD = 0.3;
42
+ export const DEFAULT_DURABLE_TYPES = new Set([
43
+ 'incident-learnings',
44
+ 'product-rules',
45
+ 'domain-invariants',
46
+ ]);
47
+
48
+ // Fields whose values carry the entry's CLAIM (compared via Jaccard).
49
+ const BODY_FIELDS = ['rule', 'symptom', 'body', 'description', 'text', 'summary'] as const;
50
+ // Fields that can serve as the entry's primary key, in precedence order.
51
+ const KEY_FIELDS = ['key', 'id'] as const;
52
+
53
+ export interface CuratedEntry {
54
+ file: string;
55
+ key: string;
56
+ body: string;
57
+ }
58
+
59
+ export interface ContradictionHit {
60
+ existing: CuratedEntry;
61
+ key: string;
62
+ similarity: number;
63
+ }
64
+
65
+ function isPlainObject(v: unknown): v is Record<string, unknown> {
66
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
67
+ }
68
+
69
+ function entryKey(entry: Record<string, unknown>): string {
70
+ for (const f of KEY_FIELDS) {
71
+ const v = entry[f];
72
+ if (typeof v === 'string' && v.trim()) {
73
+ return v.trim().toLowerCase();
74
+ }
75
+ }
76
+ return '';
77
+ }
78
+
79
+ function entryBody(entry: Record<string, unknown>): string {
80
+ const parts: string[] = [];
81
+ for (const f of BODY_FIELDS) {
82
+ const v = entry[f];
83
+ if (typeof v === 'string' && v.trim()) {
84
+ parts.push(v.trim());
85
+ }
86
+ }
87
+ return parts.join('\n');
88
+ }
89
+
90
+ function parseYamlDocs(file: string): Array<Record<string, unknown>> {
91
+ let text: string;
92
+ try {
93
+ text = fs.readFileSync(file, 'utf-8');
94
+ } catch {
95
+ return [];
96
+ }
97
+ const out: Array<Record<string, unknown>> = [];
98
+ let parsed: unknown;
99
+ try {
100
+ parsed = YAML.parse(text);
101
+ } catch {
102
+ return [];
103
+ }
104
+ if (Array.isArray(parsed)) {
105
+ for (const item of parsed) {
106
+ if (isPlainObject(item)) out.push(item);
107
+ }
108
+ } else if (isPlainObject(parsed)) {
109
+ // single-entry file (content-addressed layout) OR legacy
110
+ // `{entries: [...]}` shape.
111
+ const entries = parsed['entries'];
112
+ if (Array.isArray(entries)) {
113
+ for (const item of entries) {
114
+ if (isPlainObject(item)) out.push(item);
115
+ }
116
+ } else {
117
+ out.push(parsed);
118
+ }
119
+ }
120
+ return out;
121
+ }
122
+
123
+ /** Load curated entries of one type — content-addressed dir + legacy single file. */
124
+ export function loadCuratedEntries(memoryRoot: string, type: string): CuratedEntry[] {
125
+ const out: CuratedEntry[] = [];
126
+ const shardDir = path.join(memoryRoot, type);
127
+ let shardFiles: string[] = [];
128
+ try {
129
+ shardFiles = fs
130
+ .readdirSync(shardDir)
131
+ .filter((n) => n.endsWith('.yml') || n.endsWith('.yaml'))
132
+ .sort()
133
+ .map((n) => path.join(shardDir, n));
134
+ } catch {
135
+ // no shard dir — fine
136
+ }
137
+ const legacy = path.join(memoryRoot, `${type}.yml`);
138
+ const files = fs.existsSync(legacy) ? [...shardFiles, legacy] : shardFiles;
139
+ for (const file of files) {
140
+ for (const entry of parseYamlDocs(file)) {
141
+ const key = entryKey(entry);
142
+ const body = entryBody(entry);
143
+ if (key && body) {
144
+ out.push({ file, key, body });
145
+ }
146
+ }
147
+ }
148
+ return out;
149
+ }
150
+
151
+ /**
152
+ * Same primary key + Jaccard body similarity below the threshold →
153
+ * potential contradiction. Returns at most ONE hit (the lowest-similarity
154
+ * same-key entry) — one surfaced pair per promote is enough.
155
+ */
156
+ export function findContradiction(
157
+ candidateKey: string,
158
+ candidateBody: string,
159
+ existing: CuratedEntry[],
160
+ ): ContradictionHit | null {
161
+ const key = candidateKey.trim().toLowerCase();
162
+ if (!key || !candidateBody.trim()) return null;
163
+ let worst: ContradictionHit | null = null;
164
+ for (const entry of existing) {
165
+ if (entry.key !== key) continue;
166
+ const similarity = jaccardSimilarity(candidateBody, entry.body);
167
+ if (similarity < CONTRADICTION_THRESHOLD) {
168
+ if (worst === null || similarity < worst.similarity) {
169
+ worst = { existing: entry, key, similarity };
170
+ }
171
+ }
172
+ }
173
+ return worst;
174
+ }
175
+
176
+ function main(argv: string[]): number {
177
+ let type = '';
178
+ let key = '';
179
+ let body = '';
180
+ let memoryRoot = path.join('agents', 'memory');
181
+ let durableTypes = DEFAULT_DURABLE_TYPES;
182
+ let format = 'text';
183
+
184
+ for (let i = 0; i < argv.length; i++) {
185
+ const a = argv[i];
186
+ const next = (): string => {
187
+ const v = argv[++i];
188
+ if (v === undefined) {
189
+ process.stderr.write(`${PROG}: error: ${a} requires a value\n`);
190
+ process.exit(2);
191
+ }
192
+ return v;
193
+ };
194
+ if (a === '--type') type = next();
195
+ else if (a === '--key') key = next();
196
+ else if (a === '--body') body = next();
197
+ else if (a === '--memory-root') memoryRoot = next();
198
+ else if (a === '--durable-types')
199
+ durableTypes = new Set(
200
+ next()
201
+ .split(',')
202
+ .map((t) => t.trim())
203
+ .filter(Boolean),
204
+ );
205
+ else if (a === '--format') {
206
+ format = next();
207
+ if (format !== 'text' && format !== 'json') {
208
+ process.stderr.write(`${PROG}: error: --format must be text|json\n`);
209
+ return 2;
210
+ }
211
+ } else if (a === '-h' || a === '--help') {
212
+ process.stdout.write(
213
+ `usage: ${PROG} --type <type> --key <primary-key> --body <text> ` +
214
+ `[--memory-root <dir>] [--durable-types a,b,c] [--format text|json]\n`,
215
+ );
216
+ return 0;
217
+ } else {
218
+ process.stderr.write(`${PROG}: error: unknown argument ${a}\n`);
219
+ return 2;
220
+ }
221
+ }
222
+
223
+ if (!type || !key || !body) {
224
+ process.stderr.write(`${PROG}: error: --type, --key and --body are required\n`);
225
+ return 2;
226
+ }
227
+
228
+ if (!durableTypes.has(type)) {
229
+ if (format === 'json') {
230
+ process.stdout.write(JSON.stringify({ checked: false, reason: 'type-not-durable' }) + '\n');
231
+ }
232
+ return 0; // exploratory types are never contradiction-checked
233
+ }
234
+
235
+ let hit: ContradictionHit | null;
236
+ try {
237
+ hit = findContradiction(key, body, loadCuratedEntries(path.resolve(memoryRoot), type));
238
+ } catch (exc) {
239
+ process.stderr.write(`${PROG}: internal error: ${String(exc)}\n`);
240
+ return 3;
241
+ }
242
+
243
+ if (!hit) {
244
+ if (format === 'json') {
245
+ process.stdout.write(JSON.stringify({ checked: true, contradiction: null }) + '\n');
246
+ }
247
+ return 0;
248
+ }
249
+
250
+ if (format === 'json') {
251
+ process.stdout.write(
252
+ JSON.stringify(
253
+ {
254
+ checked: true,
255
+ contradiction: {
256
+ key: hit.key,
257
+ similarity: Number(hit.similarity.toFixed(4)),
258
+ threshold: CONTRADICTION_THRESHOLD,
259
+ existing_file: hit.existing.file,
260
+ },
261
+ },
262
+ null,
263
+ 2,
264
+ ) + '\n',
265
+ );
266
+ } else {
267
+ process.stdout.write(
268
+ `⚠️ potential contradiction on key '${hit.key}' (similarity ` +
269
+ `${hit.similarity.toFixed(2)} < ${CONTRADICTION_THRESHOLD}):\n` +
270
+ ` existing: ${hit.existing.file}\n` +
271
+ ` Resolve via the contested flow — approve new + mark old ` +
272
+ `'contested' (with provenance), or revise the new entry. NEVER auto-resolve.\n`,
273
+ );
274
+ }
275
+ return 1;
276
+ }
277
+
278
+ if (fileURLToPath(import.meta.url) === path.resolve(process.argv[1] ?? '')) {
279
+ process.exit(main(process.argv.slice(2)));
280
+ }
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Advisory near-duplicate check for `/memory propose` — road-to-knowledge-system
4
+ * Phase 2 (capture hygiene). Scans existing intake signals of the SAME type
5
+ * for the closest Jaccard match to a candidate body and classifies it.
6
+ *
7
+ * This is an ADDITIONAL, non-destructive check layered in front of
8
+ * `memory_signal.ts` — it never writes, and it never changes that script's
9
+ * own exact-match rate-limit behaviour (a documented, load-bearing parity
10
+ * contract). The `/memory propose` command runs this first; on `merge` it
11
+ * surfaces the matched entry and asks the human before emitting anyway.
12
+ *
13
+ * Usage:
14
+ * check_memory_similarity.ts --type <type> --body "<text>" [--intake-root <dir>]
15
+ *
16
+ * Exit codes: 0 = create or warn (proceed, optionally after surfacing the
17
+ * near match), 1 = merge threshold hit (surface the match, ask before
18
+ * emitting), 2 = usage error, 3 = internal error.
19
+ */
20
+ import * as fs from 'node:fs';
21
+ import * as path from 'node:path';
22
+ import process from 'node:process';
23
+ import { fileURLToPath } from 'node:url';
24
+
25
+ import { findMostSimilar, type Candidate } from './_lib/text_similarity.js';
26
+
27
+ const PROG = 'check_memory_similarity.ts';
28
+
29
+ function isPlainObject(v: unknown): v is Record<string, unknown> {
30
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
31
+ }
32
+
33
+ /** Sorted signals-*.jsonl file paths under root — mirrors memory_signal.ts's own glob order. */
34
+ function globSignals(root: string): string[] {
35
+ let names: string[];
36
+ try {
37
+ names = fs.readdirSync(root);
38
+ } catch {
39
+ return [];
40
+ }
41
+ return names
42
+ .filter((n) => n.startsWith('signals-') && n.endsWith('.jsonl'))
43
+ .sort()
44
+ .map((n) => path.join(root, n));
45
+ }
46
+
47
+ export function loadCandidates(intakeRoot: string, entryType: string): Candidate[] {
48
+ const out: Candidate[] = [];
49
+ for (const file of globSignals(intakeRoot)) {
50
+ let text: string;
51
+ try {
52
+ text = fs.readFileSync(file, 'utf8');
53
+ } catch {
54
+ continue;
55
+ }
56
+ for (const rawLine of text.split('\n')) {
57
+ const line = rawLine.trim();
58
+ if (!line) continue;
59
+ let obj: unknown;
60
+ try {
61
+ obj = JSON.parse(line);
62
+ } catch {
63
+ continue;
64
+ }
65
+ if (!isPlainObject(obj)) continue;
66
+ if (obj.entry_type !== entryType) continue;
67
+ const id = typeof obj.id === 'string' ? obj.id : '';
68
+ const body = typeof obj.body === 'string' ? obj.body : '';
69
+ if (!id || !body) continue;
70
+ out.push({ id, text: body });
71
+ }
72
+ }
73
+ return out;
74
+ }
75
+
76
+ function printUsage(): void {
77
+ process.stderr.write(`usage: ${PROG} --type TYPE --body BODY [--intake-root DIR]\n`);
78
+ }
79
+
80
+ export function main(argv: string[]): number {
81
+ let type: string | null = null;
82
+ let body: string | null = null;
83
+ let intakeRoot = path.join('agents', 'memory', 'intake');
84
+
85
+ for (let i = 0; i < argv.length; i++) {
86
+ const arg = argv[i];
87
+ if (arg === '-h' || arg === '--help') {
88
+ printUsage();
89
+ return 0;
90
+ } else if (arg === '--type') {
91
+ type = argv[++i] ?? null;
92
+ } else if (arg === '--body') {
93
+ body = argv[++i] ?? null;
94
+ } else if (arg === '--intake-root') {
95
+ intakeRoot = argv[++i] ?? intakeRoot;
96
+ } else {
97
+ process.stderr.write(`${PROG}: error: unrecognized argument: ${arg}\n`);
98
+ printUsage();
99
+ return 2;
100
+ }
101
+ }
102
+
103
+ if (!type || !body) {
104
+ process.stderr.write(`${PROG}: error: --type and --body are required\n`);
105
+ printUsage();
106
+ return 2;
107
+ }
108
+
109
+ const candidates = loadCandidates(intakeRoot, type);
110
+ const match = findMostSimilar(body, candidates);
111
+
112
+ if (!match || match.classification === 'create') {
113
+ process.stdout.write(`${PROG}: no near-duplicate found — proceed to create.\n`);
114
+ return 0;
115
+ }
116
+
117
+ const scorePct = (match.score * 100).toFixed(0);
118
+ if (match.classification === 'warn') {
119
+ process.stdout.write(
120
+ `${PROG}: nearest match ${match.id} (${scorePct}% similar) — review before proceeding, then create if distinct.\n`,
121
+ );
122
+ return 0;
123
+ }
124
+
125
+ // classification === 'merge'
126
+ process.stdout.write(
127
+ `${PROG}: likely duplicate of ${match.id} (${scorePct}% similar) — reuse or update that entry instead of creating a new one. Emit anyway only if this is a genuinely distinct finding.\n`,
128
+ );
129
+ return 1;
130
+ }
131
+
132
+ if (fileURLToPath(import.meta.url) === path.resolve(process.argv[1] ?? '')) {
133
+ process.exit(main(process.argv.slice(2)));
134
+ }