@event4u/agent-config 3.3.0 → 4.2.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 (561) hide show
  1. package/.agent-src/README.md +2 -2
  2. package/.agent-src/commands/agent-handoff.md +31 -2
  3. package/.agent-src/commands/agent-status.md +5 -5
  4. package/.agent-src/commands/agents/audit.md +8 -8
  5. package/.agent-src/commands/agents/init.md +25 -1
  6. package/.agent-src/commands/agents/optimize.md +3 -3
  7. package/.agent-src/commands/agents/user.md +1 -1
  8. package/.agent-src/commands/agents.md +1 -1
  9. package/.agent-src/commands/analyze-reference-repo.md +1 -1
  10. package/.agent-src/commands/check-current-md.md +8 -8
  11. package/.agent-src/commands/{compress.md → condense.md} +55 -55
  12. package/.agent-src/commands/context/create.md +7 -4
  13. package/.agent-src/commands/context/refactor.md +3 -1
  14. package/.agent-src/commands/feature/dev.md +1 -1
  15. package/.agent-src/commands/feature/explore.md +1 -1
  16. package/.agent-src/commands/feature/plan.md +10 -8
  17. package/.agent-src/commands/feature/refactor.md +3 -1
  18. package/.agent-src/commands/feature/roadmap.md +7 -4
  19. package/.agent-src/commands/fix/portability.md +3 -3
  20. package/.agent-src/commands/fix/refs.md +4 -4
  21. package/.agent-src/commands/ghostwriter.md +2 -2
  22. package/.agent-src/commands/memory/learn-low-impact.md +3 -3
  23. package/.agent-src/commands/module/explore.md +34 -8
  24. package/.agent-src/commands/optimize/agents-dir.md +9 -7
  25. package/.agent-src/commands/optimize/augmentignore.md +2 -2
  26. package/.agent-src/commands/optimize/skills.md +9 -9
  27. package/.agent-src/commands/post-as.md +1 -1
  28. package/.agent-src/commands/project-analyze.md +2 -2
  29. package/.agent-src/commands/project-health.md +3 -2
  30. package/.agent-src/commands/research/deep.md +1 -1
  31. package/.agent-src/commands/research/report.md +1 -1
  32. package/.agent-src/commands/research.md +1 -1
  33. package/.agent-src/commands/roadmap/ai-council.md +1 -1
  34. package/.agent-src/commands/roadmap/create.md +9 -4
  35. package/.agent-src/commands/rule-compliance-audit.md +1 -1
  36. package/.agent-src/commands/upstream-contribute.md +14 -14
  37. package/.agent-src/commands/video/from-script.md +1 -1
  38. package/.agent-src/commands/video/scene.md +1 -1
  39. package/.agent-src/commands/video/stitch.md +1 -1
  40. package/.agent-src/commands/video/storyboard.md +1 -1
  41. package/.agent-src/commands/video.md +1 -1
  42. package/.agent-src/contexts/augment-infrastructure.md +1 -1
  43. package/.agent-src/contexts/authority/commit-mechanics.md +15 -0
  44. package/.agent-src/contexts/authority/kernel-rule-edits.md +3 -3
  45. package/.agent-src/contexts/authority/scope-mechanics.md +1 -1
  46. package/.agent-src/contexts/communication/rules-auto/augment-source-of-truth-mechanics.md +28 -28
  47. package/.agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +4 -4
  48. package/.agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +2 -2
  49. package/.agent-src/contexts/contracts/artifact-engagement-flow.md +6 -6
  50. package/.agent-src/contexts/contracts/command-suggestion-flow.md +3 -3
  51. package/.agent-src/contexts/contracts/emergency-triage-block.md +4 -4
  52. package/.agent-src/contexts/contracts/frugality-charter.md +3 -3
  53. package/.agent-src/contexts/documentation-hierarchy.md +14 -7
  54. package/.agent-src/contexts/execution/autonomy-examples.md +1 -1
  55. package/.agent-src/contexts/execution/cheap-question-mechanics.md +39 -2
  56. package/.agent-src/contexts/execution/roadmap-process-loop.md +28 -5
  57. package/.agent-src/contexts/override-system.md +5 -5
  58. package/.agent-src/ghostwriter/fictional-fixture-v1.md +1 -1
  59. package/.agent-src/personas/advisors/first-principles.md +1 -1
  60. package/.agent-src/personas/hollywood-director.md +1 -1
  61. package/.agent-src/rules/architecture.md +5 -1
  62. package/.agent-src/rules/augment-edit-discipline.md +5 -5
  63. package/.agent-src/rules/augment-source-of-truth.md +15 -15
  64. package/.agent-src/rules/commit-conventions.md +1 -1
  65. package/.agent-src/rules/commit-policy.md +10 -0
  66. package/.agent-src/rules/domain-adoption-policy.md +3 -3
  67. package/.agent-src/rules/fast-path-marker-visibility.md +3 -3
  68. package/.agent-src/rules/finance-safety-floor.md +1 -1
  69. package/.agent-src/rules/framework-neutrality-in-generic-skills.md +8 -8
  70. package/.agent-src/rules/git-history-discipline.md +1 -1
  71. package/.agent-src/rules/improve-before-implement.md +2 -2
  72. package/.agent-src/rules/language-and-tone.md +2 -2
  73. package/.agent-src/rules/media-governance-routing.md +5 -5
  74. package/.agent-src/rules/no-attribution-footers.md +1 -0
  75. package/.agent-src/rules/no-cheap-questions.md +3 -0
  76. package/.agent-src/rules/no-decorative-emojis-in-git-surfaces.md +111 -0
  77. package/.agent-src/rules/no-pr-progress-comments.md +118 -0
  78. package/.agent-src/rules/no-roadmap-references.md +3 -3
  79. package/.agent-src/rules/non-destructive-by-default.md +1 -1
  80. package/.agent-src/rules/persona-governance.md +3 -3
  81. package/.agent-src/rules/preservation-guard.md +15 -15
  82. package/.agent-src/rules/roadmap-ci-steps-policy.md +7 -3
  83. package/.agent-src/rules/rule-type-governance.md +1 -1
  84. package/.agent-src/rules/skill-quality.md +1 -1
  85. package/.agent-src/rules/{caveman-speak.md → telegraph-speak.md} +15 -15
  86. package/.agent-src/rules/token-optimizer-maintenance.md +6 -6
  87. package/.agent-src/skills/agent-docs-writing/SKILL.md +17 -11
  88. package/.agent-src/skills/agents-md-thin-root/SKILL.md +9 -9
  89. package/.agent-src/skills/check-refs/SKILL.md +2 -2
  90. package/.agent-src/skills/code-refactoring/SKILL.md +2 -2
  91. package/.agent-src/skills/command-writing/SKILL.md +19 -19
  92. package/.agent-src/skills/comp-banding/SKILL.md +1 -1
  93. package/.agent-src/skills/condense-memory/SKILL.md +131 -0
  94. package/.agent-src/skills/context-authoring/SKILL.md +2 -2
  95. package/.agent-src/skills/context-document/SKILL.md +5 -3
  96. package/.agent-src/skills/copilot-agents-optimization/SKILL.md +3 -3
  97. package/.agent-src/skills/description-assist/SKILL.md +2 -2
  98. package/.agent-src/skills/git-workflow/SKILL.md +1 -1
  99. package/.agent-src/skills/guideline-writing/SKILL.md +5 -5
  100. package/.agent-src/skills/learning-to-rule-or-skill/SKILL.md +4 -4
  101. package/.agent-src/skills/lint-skills/SKILL.md +3 -3
  102. package/.agent-src/skills/md-language-check/SKILL.md +2 -2
  103. package/.agent-src/skills/module-detect-on-the-fly/SKILL.md +138 -0
  104. package/.agent-src/skills/module-management/SKILL.md +166 -94
  105. package/.agent-src/skills/override-management/SKILL.md +1 -1
  106. package/.agent-src/skills/persona-writing/SKILL.md +5 -5
  107. package/.agent-src/skills/positioning-strategy/SKILL.md +1 -1
  108. package/.agent-src/skills/project-docs/SKILL.md +6 -4
  109. package/.agent-src/skills/readme-reviewer/SKILL.md +2 -2
  110. package/.agent-src/skills/roadmap-management/SKILL.md +13 -1
  111. package/.agent-src/skills/roadmap-writing/SKILL.md +4 -2
  112. package/.agent-src/skills/rule-refactor/SKILL.md +5 -5
  113. package/.agent-src/skills/rule-writing/SKILL.md +18 -18
  114. package/.agent-src/skills/script-writing/SKILL.md +1 -1
  115. package/.agent-src/skills/skill-improvement-pipeline/SKILL.md +6 -6
  116. package/.agent-src/skills/skill-management/SKILL.md +21 -21
  117. package/.agent-src/skills/skill-reviewer/SKILL.md +2 -2
  118. package/.agent-src/skills/skill-writing/SKILL.md +8 -8
  119. package/.agent-src/skills/skill-writing/evals/triggers.json +1 -1
  120. package/.agent-src/skills/token-optimizer/SKILL.md +4 -4
  121. package/.agent-src/skills/unit-economics-modeling/SKILL.md +1 -1
  122. package/.agent-src/skills/upstream-contribute/SKILL.md +17 -17
  123. package/.agent-src/templates/AGENTS.md +1 -0
  124. package/.agent-src/templates/agent-settings.md +24 -13
  125. package/.agent-src/templates/agents/agent-project-settings.example.yml +61 -2
  126. package/.agent-src/templates/command.md +5 -5
  127. package/.agent-src/templates/contexts.md +1 -1
  128. package/.agent-src/templates/copilot-instructions.md +8 -8
  129. package/.agent-src/templates/features.md +1 -1
  130. package/.agent-src/templates/hooks/pre-commit-frontmatter +2 -2
  131. package/.agent-src/templates/hooks/pre-commit-roadmap-progress +3 -3
  132. package/.agent-src/templates/persona.md +2 -2
  133. package/.agent-src/templates/roadmaps.md +1 -1
  134. package/.agent-src/templates/rule.md +13 -13
  135. package/.agent-src/templates/scripts/memory_lookup.py +1 -1
  136. package/.agent-src/templates/scripts/memory_status.py +2 -2
  137. package/.agent-src/templates/scripts/work_engine/_lib/agent_settings.py +195 -1
  138. package/.agent-src/templates/scripts/work_engine/orchestration.py +1 -1
  139. package/.agent-src/templates/skill-archive-note.md +5 -5
  140. package/.agent-src/templates/skill.md +1 -1
  141. package/.claude-plugin/marketplace.json +4 -4
  142. package/AGENTS.md +16 -17
  143. package/CHANGELOG.md +216 -3
  144. package/CONTRIBUTING.md +31 -12
  145. package/README.md +21 -12
  146. package/config/agent-settings.template.yml +22 -2
  147. package/config/discovery/unassigned-artefacts.yml +24 -24
  148. package/config/profiles/full.ini +1 -1
  149. package/dist/cli/agent-config.js +52 -3
  150. package/dist/cli/agent-config.js.map +1 -1
  151. package/dist/cli/commands/uiServe.js +9 -0
  152. package/dist/cli/commands/uiServe.js.map +1 -1
  153. package/dist/cli/registry.js +2 -1
  154. package/dist/cli/registry.js.map +1 -1
  155. package/dist/discovery/deprecation-report.md +1 -1
  156. package/dist/discovery/discovery-manifest.json +649 -606
  157. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  158. package/dist/discovery/discovery-manifest.summary.md +4 -4
  159. package/dist/discovery/orphan-report.md +1 -1
  160. package/dist/discovery/packs.json +439 -437
  161. package/dist/discovery/trust-report.md +5 -5
  162. package/dist/discovery/workspaces.json +450 -448
  163. package/dist/install/atomic.js +92 -0
  164. package/dist/install/atomic.js.map +1 -0
  165. package/dist/install/conflict.js +196 -0
  166. package/dist/install/conflict.js.map +1 -0
  167. package/dist/install/detect.js +218 -0
  168. package/dist/install/detect.js.map +1 -0
  169. package/dist/install/paths.js +82 -0
  170. package/dist/install/paths.js.map +1 -0
  171. package/dist/install/plan.js +157 -0
  172. package/dist/install/plan.js.map +1 -0
  173. package/dist/install/txlog.js +140 -0
  174. package/dist/install/txlog.js.map +1 -0
  175. package/dist/install/types.js +19 -0
  176. package/dist/install/types.js.map +1 -0
  177. package/dist/install/wizard-plan.js +184 -0
  178. package/dist/install/wizard-plan.js.map +1 -0
  179. package/dist/mcp/registry-manifest.json +4 -4
  180. package/dist/router.json +67 -19
  181. package/dist/server/app.js +6 -0
  182. package/dist/server/app.js.map +1 -1
  183. package/dist/server/routes/install.js +358 -0
  184. package/dist/server/routes/install.js.map +1 -0
  185. package/dist/server/routes/wizard.js +468 -32
  186. package/dist/server/routes/wizard.js.map +1 -1
  187. package/dist/server/routes/workspace.js +396 -0
  188. package/dist/server/routes/workspace.js.map +1 -0
  189. package/dist/server/schemas/settings.js +5 -3
  190. package/dist/server/schemas/settings.js.map +1 -1
  191. package/dist/ui/assets/index-BDAhhpDV.js +40 -0
  192. package/dist/ui/assets/index-BDAhhpDV.js.map +1 -0
  193. package/dist/ui/assets/index-BXZILUxe.css +1 -0
  194. package/dist/ui/index.html +2 -2
  195. package/docs/MIGRATION.md +1 -1
  196. package/docs/adrs/cost/0001-hard-stop-hook.md +1 -1
  197. package/docs/adrs/router/0001-three-tier-routing.md +4 -4
  198. package/docs/adrs/schema/0001-json-schema-frontmatter.md +1 -1
  199. package/docs/adrs/smoke/0001-per-tier-smoke-scripts.md +4 -4
  200. package/docs/adrs/{caveman → telegraph}/0001-default-off-until-bench.md +9 -9
  201. package/docs/adrs/telegraph/README.md +9 -0
  202. package/docs/architecture/augment-projection.md +4 -4
  203. package/docs/architecture/claude-bundle.md +1 -1
  204. package/docs/architecture/current-onboard-baseline.md +3 -3
  205. package/docs/architecture/multi-tool-projection.md +10 -10
  206. package/docs/architecture/source-projection.md +27 -27
  207. package/docs/architecture.md +19 -15
  208. package/docs/archive/CHANGELOG-pre-2.11.0.md +2 -2
  209. package/docs/archive/CHANGELOG-pre-2.15.0.md +3 -3
  210. package/docs/archive/CHANGELOG-pre-2.16.0.md +1 -1
  211. package/docs/archive/CHANGELOG-pre-2.2.0.md +70 -70
  212. package/docs/archive/CHANGELOG-pre-2.20.0.md +2 -2
  213. package/docs/archive/CHANGELOG-pre-2.25.0.md +15 -15
  214. package/docs/archive/CHANGELOG-pre-3.0.0.md +4 -4
  215. package/docs/archive/CHANGELOG-pre-3.1.0.md +2 -2
  216. package/docs/archive/CHANGELOG-pre-3.2.0.md +3 -3
  217. package/docs/benchmark.md +65 -0
  218. package/docs/benchmarks.md +16 -16
  219. package/docs/catalog.md +17 -15
  220. package/docs/contracts/CHANGELOG-conventions.md +1 -1
  221. package/docs/contracts/STABILITY.md +2 -2
  222. package/docs/contracts/adoption-signal-floor.md +110 -0
  223. package/docs/contracts/adr-chat-history-split.md +4 -4
  224. package/docs/contracts/adr-command-suggestion.md +4 -4
  225. package/docs/contracts/adr-gtm-context-spine.md +1 -1
  226. package/docs/contracts/adr-implement-ticket-runtime.md +4 -4
  227. package/docs/contracts/adr-install-user-type-axis.md +1 -1
  228. package/docs/contracts/adr-layout.md +2 -2
  229. package/docs/contracts/adr-product-ui-track.md +10 -10
  230. package/docs/contracts/adr-user-types-axis.md +3 -3
  231. package/docs/contracts/adr-wing4-context-spine.md +1 -1
  232. package/docs/contracts/agent-memory-contract.md +3 -3
  233. package/docs/contracts/agents-md-tech-stack.md +2 -2
  234. package/docs/contracts/ai-council-config.md +2 -2
  235. package/docs/contracts/at-rest-encryption.md +4 -0
  236. package/docs/contracts/audit-log-v1.md +1 -1
  237. package/docs/contracts/benchmark-ab-contract.md +101 -0
  238. package/docs/contracts/benchmark-corpus-spec.md +1 -1
  239. package/docs/contracts/branch-protection-policy.md +98 -0
  240. package/docs/contracts/ci-cost-budget.md +106 -0
  241. package/docs/contracts/ci-green-floor.md +141 -0
  242. package/docs/contracts/command-clusters.md +6 -6
  243. package/docs/contracts/command-surface-tiers.md +2 -2
  244. package/docs/contracts/command-taxonomy.md +2 -2
  245. package/docs/contracts/{compression-default-kill-criterion.md → condensation-default-kill-criterion.md} +29 -29
  246. package/docs/contracts/config-presets.md +1 -1
  247. package/docs/contracts/context-paths.md +3 -3
  248. package/docs/contracts/context-spine.md +1 -1
  249. package/docs/contracts/cost-summary-schema.md +12 -12
  250. package/docs/contracts/cross-wing-handoff.md +4 -4
  251. package/docs/contracts/daily-workspace.md +4 -0
  252. package/docs/contracts/decision-trace-v1.md +2 -2
  253. package/docs/contracts/discovery-manifest.md +4 -4
  254. package/docs/contracts/explain-modes.md +4 -0
  255. package/docs/contracts/file-ownership-matrix.json +3493 -3318
  256. package/docs/contracts/file-ownership-matrix.md +3 -3
  257. package/docs/contracts/frontmatter-contract.md +4 -4
  258. package/docs/contracts/ghostwriter-schema.md +3 -3
  259. package/docs/contracts/gui-wizard.md +110 -97
  260. package/docs/contracts/harness-expectations.md +123 -0
  261. package/docs/contracts/host-agent-protocol.md +4 -0
  262. package/docs/contracts/implement-ticket-flow.md +9 -9
  263. package/docs/contracts/install-scopes.md +77 -0
  264. package/docs/contracts/iron-law-overrides.txt +1 -1
  265. package/docs/contracts/kernel-membership.md +26 -26
  266. package/docs/contracts/linear-ai-rules-inclusion.md +1 -1
  267. package/docs/contracts/linter-structural-model.md +2 -2
  268. package/docs/contracts/load-context-budget-model.md +4 -4
  269. package/docs/contracts/load-context-schema.md +13 -13
  270. package/docs/contracts/local-analytics.md +4 -0
  271. package/docs/contracts/local-knowledge-ingestion.md +1 -1
  272. package/docs/contracts/mcp-cloud-scope.md +2 -2
  273. package/docs/contracts/mcp-phase-1-scope.md +3 -3
  274. package/docs/contracts/measurement-baseline.md +5 -5
  275. package/docs/contracts/mental-models.md +30 -30
  276. package/docs/contracts/multi-tool-projection-fidelity.md +4 -4
  277. package/docs/contracts/namespace.md +4 -4
  278. package/docs/contracts/orchestration-dsl-v1.md +7 -7
  279. package/docs/contracts/package-self-orientation.md +12 -12
  280. package/docs/contracts/persona-schema.md +6 -6
  281. package/docs/contracts/pilot/language-and-tone.md +1 -1
  282. package/docs/contracts/plain-language-surface.md +117 -0
  283. package/docs/contracts/profile-system.md +3 -3
  284. package/docs/contracts/release-pr-gating.md +103 -0
  285. package/docs/contracts/role-experience.md +3 -3
  286. package/docs/contracts/rule-classification.md +13 -13
  287. package/docs/contracts/rule-interactions.md +4 -4
  288. package/docs/contracts/rule-interactions.yml +30 -30
  289. package/docs/contracts/rule-priority-hierarchy.md +13 -13
  290. package/docs/contracts/rule-router.md +2 -2
  291. package/docs/contracts/safety-model.md +1 -1
  292. package/docs/contracts/skill-distribution-channels.md +61 -0
  293. package/docs/contracts/skill-domains.md +2 -2
  294. package/docs/contracts/smoke-contracts.md +5 -5
  295. package/docs/contracts/telegraph-telemetry.md +83 -0
  296. package/docs/contracts/trust-and-safety.md +5 -5
  297. package/docs/contracts/ui-stack-extension.md +7 -7
  298. package/docs/contracts/ui-track-flow.md +9 -9
  299. package/docs/contracts/user-type-schema.md +4 -4
  300. package/docs/contracts/workflow-packs.md +4 -4
  301. package/docs/contracts/workspace-documents.md +4 -0
  302. package/docs/customization.md +28 -8
  303. package/docs/decisions/ADR-001-kernel-swap-deferred.md +6 -6
  304. package/docs/decisions/ADR-002-kernel-bucket-overrides.md +11 -11
  305. package/docs/decisions/ADR-003-flat-cluster-subs-and-colon-syntax.md +2 -2
  306. package/docs/decisions/ADR-004-rule-governance-pruning.md +4 -4
  307. package/docs/decisions/ADR-005-subagent-worktrees.md +7 -7
  308. package/docs/decisions/ADR-011-domain-pack-readiness.md +6 -6
  309. package/docs/decisions/ADR-013-discovery-frontmatter-contract.md +3 -3
  310. package/docs/decisions/ADR-015-discovery-manifest-contract.md +3 -3
  311. package/docs/decisions/ADR-017-monorepo-physical-layout.md +10 -10
  312. package/docs/decisions/ADR-018-trust-and-safety-layer.md +6 -6
  313. package/docs/decisions/ADR-019-router-json-dist-location.md +2 -2
  314. package/docs/decisions/ADR-020-global-only-consumer-scope.md +2 -2
  315. package/docs/decisions/ADR-021-deployment-shape.md +3 -3
  316. package/docs/decisions/ADR-022-daily-workspace-decomposition.md +1 -1
  317. package/docs/decisions/ADR-027-changelog-machine-vs-manual.md +2 -2
  318. package/docs/decisions/ADR-028-root-layout.md +7 -7
  319. package/docs/decisions/ADR-029-multi-workspace-deferred.md +2 -2
  320. package/docs/decisions/ADR-rule-kernel-and-router.md +5 -5
  321. package/docs/deploy/connector-setup.md +2 -2
  322. package/docs/deploy/policy-cookbook.md +2 -2
  323. package/docs/deploy/team-deployment-posture.md +20 -0
  324. package/docs/development.md +17 -17
  325. package/docs/distribution/registries.md +32 -0
  326. package/docs/distribution/registry-submissions.md +85 -0
  327. package/docs/distribution/telemetry-schema.md +1 -1
  328. package/docs/getting-started-by-role.md +45 -3
  329. package/docs/getting-started.md +2 -2
  330. package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
  331. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +1 -1
  332. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
  333. package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
  334. package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
  335. package/docs/guidelines/agent-infra/direct-answers-demos.md +1 -1
  336. package/docs/guidelines/agent-infra/first-principles.md +2 -2
  337. package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
  338. package/docs/guidelines/agent-infra/layered-settings.md +56 -2
  339. package/docs/guidelines/agent-infra/mental-models.md +3 -3
  340. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +2 -2
  341. package/docs/guidelines/agent-infra/rule-type-governance.md +1 -1
  342. package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
  343. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +2 -2
  344. package/docs/guidelines/agent-infra/six-hats.md +3 -3
  345. package/docs/guidelines/agent-infra/skill-quality-checklist.md +5 -5
  346. package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
  347. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +1 -1
  348. package/docs/guidelines/augment-portability-patterns.md +4 -4
  349. package/docs/guidelines/cross-role-handoff.md +2 -2
  350. package/docs/guidelines/php/php-coding-patterns.md +1 -1
  351. package/docs/guidelines/prompt-templates.md +6 -6
  352. package/docs/maintainers/dev-mode.md +1 -1
  353. package/docs/mcp.md +1 -1
  354. package/docs/parity/bench.json +3 -3
  355. package/docs/parity/ruflo.md +2 -2
  356. package/docs/profiles.md +11 -11
  357. package/docs/quality.md +11 -11
  358. package/docs/safety.md +3 -3
  359. package/docs/setup/mcp-client-config.md +1 -1
  360. package/docs/setup/mcp-r2-bootstrap.md +1 -1
  361. package/docs/setup/mcp-server-docker.md +3 -3
  362. package/docs/setup/per-ide/windsurf.md +1 -1
  363. package/docs/skills-catalog.md +8 -7
  364. package/docs/troubleshooting.md +1 -1
  365. package/docs/walkthroughs/daily-workspace-a11y.md +87 -0
  366. package/llms.txt +7 -6
  367. package/package.json +1 -1
  368. package/scripts/__pycache__/validate_frontmatter.cpython-312.pyc +0 -0
  369. package/scripts/_archive/README.md +2 -2
  370. package/scripts/_archive/_backfill_skill_domains.py +3 -3
  371. package/scripts/_archive/_bootstrap_tier_frontmatter.py +3 -3
  372. package/scripts/_archive/_p43_bodies.py +10 -10
  373. package/scripts/_archive/{_p43_compress.py → _p43_condense.py} +5 -5
  374. package/scripts/_archive/_p4_migrate.py +7 -7
  375. package/scripts/_archive/_phase2_shim_helper.py +1 -1
  376. package/scripts/_archive/_pilot_council_question.py +5 -5
  377. package/scripts/_cli/explain_last/inputs.py +1 -1
  378. package/scripts/_lib/__pycache__/__init__.cpython-312.pyc +0 -0
  379. package/scripts/_lib/__pycache__/agent_src.cpython-312.pyc +0 -0
  380. package/scripts/_lib/agent_settings.py +195 -1
  381. package/scripts/_lib/agent_src.py +19 -19
  382. package/scripts/_lib/bench_ab_cache.py +162 -0
  383. package/scripts/_lib/bench_ab_scoring.py +209 -0
  384. package/scripts/_lib/{bench_caveman.py → bench_telegraph.py} +21 -21
  385. package/scripts/_lib/{bench_caveman_report.py → bench_telegraph_report.py} +21 -21
  386. package/scripts/_lib/claude_desktop_bundler.py +5 -5
  387. package/scripts/_lib/module_detection.py +223 -0
  388. package/scripts/_lib/scope_guard.sh +162 -0
  389. package/scripts/_phase4_bucket.py +3 -3
  390. package/scripts/_pilot_measure.py +4 -4
  391. package/scripts/_tmp_scan_framework_leakage.py +1 -1
  392. package/scripts/adoption_report.py +195 -0
  393. package/scripts/adoption_snapshot.py +219 -0
  394. package/scripts/adoption_status.py +166 -0
  395. package/scripts/ai-video/lib/parse-blueprint.sh +1 -1
  396. package/scripts/ai_council/advisors.py +5 -5
  397. package/scripts/ai_council/compile_corpus.py +1 -1
  398. package/scripts/ai_council/one_off_archive/2026-05/_one_off_budget_v2_audit.py +3 -3
  399. package/scripts/ai_council/one_off_archive/2026-05/_one_off_context_layer_v1_review.py +2 -2
  400. package/scripts/ai_council/one_off_archive/2026-05/_one_off_inject_quiet_flag.py +1 -1
  401. package/scripts/ai_council/one_off_archive/2026-05/_one_off_measure_v2.sh +1 -1
  402. package/scripts/ai_council/one_off_archive/2026-05/_one_off_measure_verbosity.sh +1 -1
  403. package/scripts/ai_council/one_off_archive/2026-05/_one_off_nondestructive_inline_audit.py +3 -3
  404. package/scripts/ai_council/one_off_archive/2026-05/_one_off_per_task.sh +1 -1
  405. package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase6_trigger_jaccard.py +1 -1
  406. package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase_2a_budget_rebalance.py +6 -6
  407. package/scripts/ai_council/one_off_archive/2026-05/_one_off_rebalancing_audit.py +1 -1
  408. package/scripts/ai_council/one_off_archive/2026-05/_one_off_tier_retrofit.py +6 -6
  409. package/scripts/annotate_discovery.py +13 -13
  410. package/scripts/apply_modules_config.py +290 -0
  411. package/scripts/audit_adr_coverage.py +2 -2
  412. package/scripts/audit_auto_rules.py +2 -2
  413. package/scripts/audit_cloud_compatibility.py +3 -3
  414. package/scripts/audit_command_surface.py +9 -9
  415. package/scripts/audit_likelihood.py +2 -2
  416. package/scripts/audit_user_type_axis.py +2 -2
  417. package/scripts/bench_ab_cache_dispatch.py +68 -0
  418. package/scripts/bench_ab_clone.py +170 -0
  419. package/scripts/bench_ab_diff.py +227 -0
  420. package/scripts/bench_ab_integrity.py +143 -0
  421. package/scripts/bench_ab_run.py +235 -0
  422. package/scripts/bench_ab_task_runner.py +369 -0
  423. package/scripts/bench_ab_tracka_run.py +202 -0
  424. package/scripts/{bench_compress_memory.py → bench_condense_memory.py} +16 -16
  425. package/scripts/bench_run.py +33 -33
  426. package/scripts/bench_runner.py +2 -2
  427. package/scripts/bootstrap.sh +99 -0
  428. package/scripts/build_cloud_bundle.py +6 -6
  429. package/scripts/build_discovery_manifest.py +7 -7
  430. package/scripts/build_linear_digest.py +3 -3
  431. package/scripts/build_rule_trigger_matrix.py +8 -8
  432. package/scripts/chat_history.py +5 -5
  433. package/scripts/check_always_budget.py +11 -5
  434. package/scripts/check_augment_description_cap.py +3 -3
  435. package/scripts/check_cluster_patterns.py +2 -2
  436. package/scripts/check_command_count_messaging.py +3 -3
  437. package/scripts/{check_compression.py → check_condensation.py} +34 -34
  438. package/scripts/{check_compressed_paths.py → check_condensed_paths.py} +8 -8
  439. package/scripts/check_context_paths.py +7 -7
  440. package/scripts/check_council_layout.py +2 -2
  441. package/scripts/check_council_references.py +9 -9
  442. package/scripts/check_iron_law_prominence.py +2 -2
  443. package/scripts/check_kernel_rule_bundle.py +2 -2
  444. package/scripts/check_module_management_neutral.py +149 -0
  445. package/scripts/check_no_roadmap_refs.py +9 -9
  446. package/scripts/check_portability.py +3 -3
  447. package/scripts/check_public_catalog_links.py +4 -4
  448. package/scripts/check_references.py +7 -6
  449. package/scripts/check_release_pr_shape.py +112 -0
  450. package/scripts/check_reply_consistency.py +3 -3
  451. package/scripts/check_safety_floor_untouched.py +1 -1
  452. package/scripts/check_template_pin_drift.py +5 -5
  453. package/scripts/check_token_optimizer_freshness.py +3 -3
  454. package/scripts/ci_status.py +301 -0
  455. package/scripts/ci_time_ratio.py +1 -1
  456. package/scripts/cleanup_other_scope.sh +146 -0
  457. package/scripts/compile_router.py +10 -10
  458. package/scripts/{compress.py → condense.py} +64 -64
  459. package/scripts/condense.sh +18 -0
  460. package/scripts/{compress_memory.py → condense_memory.py} +33 -33
  461. package/scripts/config/presets.py +2 -2
  462. package/scripts/config/profiles.py +1 -1
  463. package/scripts/cost_by_conversation.py +3 -3
  464. package/scripts/cost_summary.py +7 -7
  465. package/scripts/count_token_optimizer_usage.sh +1 -1
  466. package/scripts/gen_discovery_baseline.py +5 -5
  467. package/scripts/generate_index.py +6 -6
  468. package/scripts/generate_ownership_matrix.py +10 -10
  469. package/scripts/generate_pack_manifests.py +1 -1
  470. package/scripts/ghostwriter_fixture_allowlist.txt +1 -1
  471. package/scripts/install +3 -3
  472. package/scripts/install-hooks.sh +6 -6
  473. package/scripts/install.py +273 -45
  474. package/scripts/install.sh +187 -1
  475. package/scripts/inventory_frontmatter.py +2 -2
  476. package/scripts/iron_law_sha.py +3 -3
  477. package/scripts/lint_agents_layout.py +14 -7
  478. package/scripts/lint_agents_md.py +4 -4
  479. package/scripts/lint_archived_skills.py +3 -3
  480. package/scripts/lint_artefact_frontmatter.py +2 -2
  481. package/scripts/lint_bench_ab.py +172 -0
  482. package/scripts/lint_bench_corpus.py +1 -1
  483. package/scripts/lint_command_tiers.py +5 -5
  484. package/scripts/lint_context_spine_usage.py +1 -1
  485. package/scripts/lint_framework_leakage.py +7 -7
  486. package/scripts/lint_framework_leakage_allowlist.json +152 -84
  487. package/scripts/lint_ghostwriter_source.py +3 -3
  488. package/scripts/lint_handoffs.py +1 -1
  489. package/scripts/lint_load_context.py +11 -11
  490. package/scripts/lint_media_policy_linkage.py +5 -5
  491. package/scripts/lint_namespace.py +1 -1
  492. package/scripts/lint_no_new_atomic_commands.py +2 -2
  493. package/scripts/lint_orchestration_dsl.py +1 -1
  494. package/scripts/lint_pack_boundaries.py +2 -2
  495. package/scripts/lint_persona_governance.py +4 -4
  496. package/scripts/lint_role_experiences.py +237 -0
  497. package/scripts/lint_rule_interactions.py +2 -2
  498. package/scripts/lint_rule_tiers.py +1 -1
  499. package/scripts/lint_trust_coherence.py +2 -2
  500. package/scripts/mcp_registry_submit.sh +187 -0
  501. package/scripts/mcp_server/tools.py +1 -1
  502. package/scripts/measure_frugality_savings.py +10 -10
  503. package/scripts/measure_patterns.py +1 -1
  504. package/scripts/measure_projection_bytes.py +5 -5
  505. package/scripts/measure_rule_budget.py +3 -3
  506. package/scripts/measure_skill_reduction.py +1 -1
  507. package/scripts/memory_lookup.py +1 -1
  508. package/scripts/memory_status.py +2 -2
  509. package/scripts/migrate_command_suggestions.py +3 -3
  510. package/scripts/mine_session.py +1 -1
  511. package/scripts/move_artefact.py +3 -3
  512. package/scripts/new_skill.py +2 -2
  513. package/scripts/pack_mcp_content.py +9 -9
  514. package/scripts/plan_physical_move.py +6 -6
  515. package/scripts/print_required_checks.py +196 -0
  516. package/scripts/probe_skill_registration.py +413 -0
  517. package/scripts/propose_modules_config.py +145 -0
  518. package/scripts/prototype_lint_contradictions.py +1 -1
  519. package/scripts/recruit_preflight.sh +152 -0
  520. package/scripts/refine_ticket_detect.py +3 -3
  521. package/scripts/release.py +20 -0
  522. package/scripts/render_benchmark_md.py +308 -0
  523. package/scripts/roadmap_progress_hook.py +1 -1
  524. package/scripts/run_skill_evals.py +2 -2
  525. package/scripts/runtime_registry.py +4 -4
  526. package/scripts/schemas/command.schema.json +4 -4
  527. package/scripts/schemas/rule.schema.json +5 -5
  528. package/scripts/schemas/skill.schema.json +3 -3
  529. package/scripts/schemas/user-type.schema.json +1 -1
  530. package/scripts/score_skill_selection.py +1 -1
  531. package/scripts/skill_collision_clusters.py +2 -2
  532. package/scripts/skill_linter.py +81 -81
  533. package/scripts/skill_overlap.py +5 -5
  534. package/scripts/skill_tools/audit_persona_coverage.py +2 -2
  535. package/scripts/skill_tools/audit_user_type_coverage.py +2 -2
  536. package/scripts/skill_tools/run_block_d_eval.py +1 -1
  537. package/scripts/skill_tools/score_skill_relevance.py +1 -1
  538. package/scripts/skill_tools/suggest_skill_for_task.py +1 -1
  539. package/scripts/skill_trigger_eval.py +3 -3
  540. package/scripts/smoke/kernel.sh +7 -1
  541. package/scripts/smoke/router.sh +5 -5
  542. package/scripts/smoke/skills.sh +1 -1
  543. package/scripts/smoke_quickstart.py +1 -1
  544. package/scripts/snapshot_agent_outputs.py +3 -3
  545. package/scripts/spotcheck_thin_root.py +1 -1
  546. package/scripts/{caveman_stats.py → telegraph_stats.py} +18 -18
  547. package/scripts/update_counts.py +1 -1
  548. package/scripts/validate_decision_engine.py +1 -1
  549. package/scripts/validate_frontmatter.py +1 -1
  550. package/scripts/validate_safe_paths.py +3 -3
  551. package/scripts/{validate_caveman_carveouts.py → validate_telegraph_carveouts.py} +7 -7
  552. package/scripts/verify_roadmap_closure.py +6 -6
  553. package/templates/consumer-settings/ONBOARDING.md +41 -0
  554. package/.agent-src/commands/install-via-agent.md +0 -129
  555. package/.agent-src/skills/compress-memory/SKILL.md +0 -131
  556. package/dist/ui/assets/index-D-DY1ywI.js +0 -35
  557. package/dist/ui/assets/index-D-DY1ywI.js.map +0 -1
  558. package/dist/ui/assets/index-Dqfhmg-d.css +0 -1
  559. package/docs/adrs/caveman/README.md +0 -9
  560. package/docs/contracts/caveman-telemetry.md +0 -83
  561. package/scripts/compress.sh +0 -18
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env python3
2
+ """Print the expected required-check set for the current branch.
3
+
4
+ Contract: `docs/contracts/branch-protection-policy.md`. Per-PR-shape
5
+ required-check floor — feature PR vs release PR vs docs-only PR. The
6
+ script resolves the PR shape locally so the maintainer can sanity-check
7
+ before pushing, without round-tripping through the GitHub UI.
8
+
9
+ Resolution order:
10
+
11
+ 1. `--branch <name>` flag — explicit override.
12
+ 2. Current git branch — `git rev-parse --abbrev-ref HEAD`.
13
+ 3. Fail with exit 2 (usage error).
14
+
15
+ PR-shape classification:
16
+
17
+ release — branch matches `^release/\\d+\\.\\d+\\.\\d+$` AND
18
+ `check_release_pr_shape.py` reports SHAPE-CLEAN for the
19
+ local diff against `--base` (default `origin/main`).
20
+ docs-only — diff vs base is entirely inside `docs/**` or top-level
21
+ `.md` files (`README.md`, `CHANGELOG.md`,
22
+ `CONTRIBUTING.md`, `AGENTS.md`).
23
+ feature — everything else (default).
24
+
25
+ The script never invokes `gh` and never touches the network — it works
26
+ offline against the local git index so pre-push previews stay fast.
27
+
28
+ Exit codes:
29
+
30
+ 0 — printed the expected required-check set.
31
+ 1 — release-PR shape detector reported OUT-OF-SHAPE; falls back to
32
+ the feature-PR set, which is also printed, plus a warning.
33
+ 2 — usage / environment error.
34
+ """
35
+
36
+ from __future__ import annotations
37
+
38
+ import argparse
39
+ import re
40
+ import subprocess
41
+ import sys
42
+ from pathlib import Path
43
+
44
+ REPO_ROOT = Path(__file__).resolve().parent.parent
45
+ sys.path.insert(0, str(REPO_ROOT / "scripts"))
46
+
47
+ import check_release_pr_shape as shape # noqa: E402
48
+
49
+ RELEASE_BRANCH_RE = re.compile(r"^release/\d+\.\d+\.\d+$")
50
+
51
+ DOCS_ONLY_ALLOWED_TOP = {
52
+ "README.md",
53
+ "CHANGELOG.md",
54
+ "CONTRIBUTING.md",
55
+ "AGENTS.md",
56
+ "LICENSE",
57
+ "llms.txt",
58
+ }
59
+
60
+ FEATURE_CHECKS = (
61
+ "Consistency",
62
+ "Smoke Contracts",
63
+ "Skill Lint",
64
+ "Tests / install-tests",
65
+ "Tests / install-aux-tests",
66
+ "Tests / python-tests",
67
+ "Tests / node-tests",
68
+ "Public Install Smoke / smoke",
69
+ )
70
+
71
+ RELEASE_CHECKS = (
72
+ "Consistency",
73
+ "Smoke Contracts",
74
+ "Migration Dry-Run",
75
+ "Release Validation / release-shape",
76
+ "Release Validation / changelog-entry",
77
+ "Release Validation / version-consistency",
78
+ "Release Guard (post-tag)",
79
+ )
80
+
81
+ DOCS_ONLY_CHECKS = (
82
+ "Consistency",
83
+ "Smoke Contracts",
84
+ )
85
+
86
+
87
+ def _git(*args: str) -> str:
88
+ return subprocess.run(
89
+ ["git", *args], check=True, capture_output=True, text=True
90
+ ).stdout.strip()
91
+
92
+
93
+ def current_branch() -> str:
94
+ return _git("rev-parse", "--abbrev-ref", "HEAD")
95
+
96
+
97
+ def diff_files(base: str) -> list[str]:
98
+ out = subprocess.run(
99
+ ["git", "diff", "--name-only", f"{base}...HEAD"],
100
+ capture_output=True,
101
+ text=True,
102
+ )
103
+ if out.returncode != 0:
104
+ # Base ref unknown locally — fall back to staged + tracked
105
+ # changes vs HEAD so the dry-run still tells the maintainer
106
+ # something useful instead of crashing.
107
+ out = subprocess.run(
108
+ ["git", "diff", "--name-only", "HEAD"],
109
+ check=True,
110
+ capture_output=True,
111
+ text=True,
112
+ )
113
+ return [line for line in out.stdout.splitlines() if line.strip()]
114
+
115
+
116
+ def is_docs_only(files: list[str]) -> bool:
117
+ if not files:
118
+ return False
119
+ for f in files:
120
+ if f in DOCS_ONLY_ALLOWED_TOP:
121
+ continue
122
+ if f.startswith("docs/"):
123
+ continue
124
+ return False
125
+ return True
126
+
127
+
128
+ def classify(branch: str, files: list[str]) -> tuple[str, int]:
129
+ """Return (shape, exit_code)."""
130
+ if RELEASE_BRANCH_RE.match(branch):
131
+ # Release-shape predicate — re-uses the fail-closed allowlist.
132
+ bad = [f for f in files if not shape._matches(f)]
133
+ if bad:
134
+ print(
135
+ "WARNING: branch matches release/X.Y.Z but diff contains "
136
+ f"{len(bad)} out-of-allowlist file(s):",
137
+ file=sys.stderr,
138
+ )
139
+ for f in bad:
140
+ print(f" - {f}", file=sys.stderr)
141
+ print(
142
+ "Falling back to feature-PR required-check set.",
143
+ file=sys.stderr,
144
+ )
145
+ return "feature", 1
146
+ return "release", 0
147
+ if is_docs_only(files):
148
+ return "docs-only", 0
149
+ return "feature", 0
150
+
151
+
152
+ def print_set(shape_label: str, files: list[str]) -> None:
153
+ table = {
154
+ "feature": FEATURE_CHECKS,
155
+ "release": RELEASE_CHECKS,
156
+ "docs-only": DOCS_ONLY_CHECKS,
157
+ }[shape_label]
158
+ print(f"PR shape: {shape_label} ({len(files)} file(s) in diff)")
159
+ print(f"Required checks ({len(table)}):")
160
+ for name in table:
161
+ print(f" - {name}")
162
+ print()
163
+ print(
164
+ "Contract: docs/contracts/branch-protection-policy.md "
165
+ "(per-PR-shape matrix)"
166
+ )
167
+
168
+
169
+ def main(argv: list[str] | None = None) -> int:
170
+ parser = argparse.ArgumentParser(
171
+ description=(
172
+ "Print the expected required-check set for the current branch."
173
+ ),
174
+ )
175
+ parser.add_argument(
176
+ "--branch",
177
+ help="Branch name override (default: current git branch).",
178
+ )
179
+ parser.add_argument(
180
+ "--base",
181
+ default="origin/main",
182
+ help="Base ref for the diff (default: origin/main).",
183
+ )
184
+ args = parser.parse_args(argv)
185
+
186
+ branch = args.branch or current_branch()
187
+ files = diff_files(args.base)
188
+ shape_label, exit_code = classify(branch, files)
189
+ print(f"Branch: {branch}")
190
+ print(f"Base: {args.base}")
191
+ print_set(shape_label, files)
192
+ return exit_code
193
+
194
+
195
+ if __name__ == "__main__":
196
+ sys.exit(main())
@@ -0,0 +1,413 @@
1
+ #!/usr/bin/env python3
2
+ """Tool-agnostic skill-registration probe.
3
+
4
+ Roadmap: road-to-clean-skill-distribution-channels.md § Phase C.
5
+ Contract: docs/contracts/skill-distribution-channels.md.
6
+
7
+ Surfaces every skill registered for any of the six supported AI tools
8
+ across user-global, project-local, and plugin-manifest sources. Flags
9
+ ``DUPLICATE`` (same skill name registered in ≥ 2 sources) and ``DRIFT``
10
+ (same name, different description-hash or version). Both shapes are the
11
+ class of bug that opened road-to-clean-skill-distribution-channels.md
12
+ on 2026-05-25.
13
+
14
+ CLI:
15
+
16
+ python3 scripts/probe_skill_registration.py
17
+ python3 scripts/probe_skill_registration.py --tool=claude --format=json
18
+ python3 scripts/probe_skill_registration.py --strict
19
+
20
+ ``--strict`` flips the exit code: 0 if no DUPLICATE / DRIFT findings,
21
+ non-zero otherwise. Without ``--strict`` the script is informational
22
+ (always exits 0).
23
+ """
24
+ from __future__ import annotations
25
+
26
+ import argparse
27
+ import hashlib
28
+ import json
29
+ import os
30
+ import sys
31
+ from dataclasses import dataclass, field, asdict
32
+ from pathlib import Path
33
+ from typing import Iterable
34
+
35
+ TOOL_IDS = ("claude", "augment", "cursor", "cline", "windsurf", "copilot")
36
+ SCOPE_IDS = ("user", "project")
37
+
38
+
39
+ @dataclass(frozen=True)
40
+ class Registration:
41
+ """One row in the probe table — a single (skill_id, scope, source) tuple."""
42
+ skill_id: str
43
+ tool: str
44
+ scope: str
45
+ source_path: str
46
+ version: str
47
+ description_snippet: str
48
+ description_hash: str
49
+
50
+ def to_dict(self) -> dict[str, str]:
51
+ return asdict(self)
52
+
53
+
54
+ @dataclass
55
+ class ProbeResult:
56
+ registrations: list[Registration] = field(default_factory=list)
57
+ duplicates: dict[str, list[Registration]] = field(default_factory=dict)
58
+ drift: dict[str, list[Registration]] = field(default_factory=dict)
59
+
60
+ def to_dict(self) -> dict[str, object]:
61
+ return {
62
+ "registrations": [r.to_dict() for r in self.registrations],
63
+ "duplicates": {k: [r.to_dict() for r in v] for k, v in self.duplicates.items()},
64
+ "drift": {k: [r.to_dict() for r in v] for k, v in self.drift.items()},
65
+ }
66
+
67
+
68
+ # ---------------------------------------------------------------------------
69
+ # Frontmatter + version helpers
70
+ # ---------------------------------------------------------------------------
71
+
72
+ def _read_frontmatter(skill_md: Path) -> dict[str, str]:
73
+ """Minimal YAML frontmatter extractor — no PyYAML dependency."""
74
+ try:
75
+ text = skill_md.read_text(encoding="utf-8", errors="replace")
76
+ except OSError:
77
+ return {}
78
+ if not text.startswith("---\n") and not text.startswith("---\r\n"):
79
+ return {}
80
+ rest = text.split("---", 2)
81
+ if len(rest) < 3:
82
+ return {}
83
+ body = rest[1]
84
+ out: dict[str, str] = {}
85
+ for line in body.splitlines():
86
+ if ":" not in line or line.lstrip().startswith("#"):
87
+ continue
88
+ key, _, value = line.partition(":")
89
+ out[key.strip()] = value.strip().strip('"').strip("'")
90
+ return out
91
+
92
+
93
+ def _hash_desc(desc: str) -> str:
94
+ return hashlib.sha256(desc.encode("utf-8", "replace")).hexdigest()[:12]
95
+
96
+
97
+ def _snippet(desc: str, n: int = 80) -> str:
98
+ desc = desc.strip()
99
+ return desc if len(desc) <= n else desc[: n - 1] + "…"
100
+
101
+
102
+ def _version_at(root: Path) -> str:
103
+ """Read a 'this install's version' value from package.json / plugin.json."""
104
+ for candidate in (root / "package.json", root / ".augment-plugin" / "plugin.json"):
105
+ if not candidate.is_file():
106
+ continue
107
+ try:
108
+ data = json.loads(candidate.read_text(encoding="utf-8"))
109
+ v = data.get("version")
110
+ if isinstance(v, str) and v:
111
+ return v
112
+ except (OSError, json.JSONDecodeError):
113
+ continue
114
+ return "unknown"
115
+
116
+
117
+ # ---------------------------------------------------------------------------
118
+ # Per-tool readers
119
+ # ---------------------------------------------------------------------------
120
+
121
+ def _iter_skill_md(skills_root: Path) -> Iterable[Path]:
122
+ if not skills_root.is_dir():
123
+ return
124
+ for entry in sorted(skills_root.iterdir()):
125
+ if not entry.is_dir():
126
+ continue
127
+ skill_md = entry / "SKILL.md"
128
+ if skill_md.is_file():
129
+ yield skill_md
130
+
131
+
132
+ def _read_claude(scope: str, root: Path) -> Iterable[Registration]:
133
+ skills = root / ".claude" / "skills"
134
+ for skill_md in _iter_skill_md(skills):
135
+ fm = _read_frontmatter(skill_md)
136
+ name = fm.get("name") or skill_md.parent.name
137
+ desc = fm.get("description", "")
138
+ yield Registration(
139
+ skill_id=name,
140
+ tool="claude",
141
+ scope=scope,
142
+ source_path=str(skill_md),
143
+ version=_version_at(root),
144
+ description_snippet=_snippet(desc),
145
+ description_hash=_hash_desc(desc),
146
+ )
147
+ # Plugin manifest at the same scope. Each entry is a path string into
148
+ # the same .claude/skills/ tree; emit it as a separate "manifest" row so
149
+ # duplicate-detection catches manifest-vs-filesystem double-counting.
150
+ manifest = root / ".claude-plugin" / "marketplace.json"
151
+ if manifest.is_file():
152
+ try:
153
+ data = json.loads(manifest.read_text(encoding="utf-8"))
154
+ plugins = data.get("plugins") or []
155
+ entries: list[str] = []
156
+ for plug in plugins:
157
+ entries.extend(plug.get("skills") or [])
158
+ for entry in entries:
159
+ # The entry is a path string; resolve the name from the path.
160
+ tail = Path(entry).name
161
+ yield Registration(
162
+ skill_id=tail,
163
+ tool="claude",
164
+ scope=f"{scope}-plugin",
165
+ source_path=str(manifest),
166
+ version=_version_at(root),
167
+ description_snippet="(plugin manifest entry)",
168
+ description_hash="manifest",
169
+ )
170
+ except (OSError, json.JSONDecodeError):
171
+ pass
172
+
173
+
174
+ def _read_augment(scope: str, root: Path) -> Iterable[Registration]:
175
+ skills = root / ".augment" / "skills"
176
+ for skill_md in _iter_skill_md(skills):
177
+ fm = _read_frontmatter(skill_md)
178
+ name = fm.get("name") or skill_md.parent.name
179
+ desc = fm.get("description", "")
180
+ yield Registration(
181
+ skill_id=name,
182
+ tool="augment",
183
+ scope=scope,
184
+ source_path=str(skill_md),
185
+ version=_version_at(root),
186
+ description_snippet=_snippet(desc),
187
+ description_hash=_hash_desc(desc),
188
+ )
189
+
190
+
191
+ def _read_cursor(scope: str, root: Path) -> Iterable[Registration]:
192
+ rules = root / ".cursor" / "rules"
193
+ if not rules.is_dir():
194
+ return
195
+ for rule in sorted(rules.glob("*.mdc")):
196
+ fm = _read_frontmatter(rule)
197
+ name = fm.get("name") or rule.stem
198
+ desc = fm.get("description", "")
199
+ yield Registration(
200
+ skill_id=name,
201
+ tool="cursor",
202
+ scope=scope,
203
+ source_path=str(rule),
204
+ version=_version_at(root),
205
+ description_snippet=_snippet(desc),
206
+ description_hash=_hash_desc(desc),
207
+ )
208
+
209
+
210
+ def _read_cline(scope: str, root: Path) -> Iterable[Registration]:
211
+ rules = root / ".clinerules"
212
+ if not rules.is_dir():
213
+ return
214
+ for rule in sorted(rules.glob("*.md")):
215
+ fm = _read_frontmatter(rule)
216
+ name = fm.get("name") or rule.stem
217
+ desc = fm.get("description", "")
218
+ yield Registration(
219
+ skill_id=name,
220
+ tool="cline",
221
+ scope=scope,
222
+ source_path=str(rule),
223
+ version=_version_at(root),
224
+ description_snippet=_snippet(desc),
225
+ description_hash=_hash_desc(desc),
226
+ )
227
+
228
+
229
+ def _read_windsurf(scope: str, root: Path) -> Iterable[Registration]:
230
+ rules = root / ".windsurf" / "rules"
231
+ if not rules.is_dir():
232
+ return
233
+ for rule in sorted(rules.glob("*.md")):
234
+ fm = _read_frontmatter(rule)
235
+ name = fm.get("name") or rule.stem
236
+ desc = fm.get("description", "")
237
+ yield Registration(
238
+ skill_id=name,
239
+ tool="windsurf",
240
+ scope=scope,
241
+ source_path=str(rule),
242
+ version=_version_at(root),
243
+ description_snippet=_snippet(desc),
244
+ description_hash=_hash_desc(desc),
245
+ )
246
+
247
+
248
+ def _read_copilot(scope: str, root: Path) -> Iterable[Registration]:
249
+ # Copilot ships a single file; check both common locations.
250
+ for candidate in (
251
+ root / ".github" / "copilot-instructions.md",
252
+ root / "copilot-instructions.md",
253
+ ):
254
+ if not candidate.is_file():
255
+ continue
256
+ try:
257
+ text = candidate.read_text(encoding="utf-8", errors="replace")
258
+ except OSError:
259
+ continue
260
+ snippet = _snippet(text.split("\n", 1)[0] if text else "")
261
+ yield Registration(
262
+ skill_id="copilot-instructions",
263
+ tool="copilot",
264
+ scope=scope,
265
+ source_path=str(candidate),
266
+ version=_version_at(root),
267
+ description_snippet=snippet,
268
+ description_hash=_hash_desc(text),
269
+ )
270
+
271
+
272
+ TOOL_READERS = {
273
+ "claude": _read_claude,
274
+ "augment": _read_augment,
275
+ "cursor": _read_cursor,
276
+ "cline": _read_cline,
277
+ "windsurf": _read_windsurf,
278
+ "copilot": _read_copilot,
279
+ }
280
+
281
+
282
+ # ---------------------------------------------------------------------------
283
+ # Probe
284
+ # ---------------------------------------------------------------------------
285
+
286
+ def run_probe(
287
+ *,
288
+ tool_filter: str = "all",
289
+ scope_filter: str = "all",
290
+ home: Path | None = None,
291
+ project: Path | None = None,
292
+ ) -> ProbeResult:
293
+ home = home or Path(os.environ.get("HOME", "/tmp"))
294
+ project = project or Path.cwd()
295
+
296
+ scopes: dict[str, Path] = {}
297
+ if scope_filter in ("all", "user"):
298
+ scopes["user"] = home
299
+ if scope_filter in ("all", "project"):
300
+ scopes["project"] = project
301
+
302
+ tools = TOOL_IDS if tool_filter == "all" else (tool_filter,)
303
+
304
+ result = ProbeResult()
305
+ for scope, root in scopes.items():
306
+ for tool in tools:
307
+ reader = TOOL_READERS.get(tool)
308
+ if reader is None:
309
+ continue
310
+ for reg in reader(scope, root):
311
+ result.registrations.append(reg)
312
+
313
+ # Group by (tool, skill_id). Anything with ≥ 2 entries is DUPLICATE.
314
+ # If their description hashes diverge, also flag DRIFT.
315
+ by_key: dict[tuple[str, str], list[Registration]] = {}
316
+ for reg in result.registrations:
317
+ by_key.setdefault((reg.tool, reg.skill_id), []).append(reg)
318
+
319
+ for (tool, skill_id), regs in by_key.items():
320
+ if len(regs) < 2:
321
+ continue
322
+ key = f"{tool}:{skill_id}"
323
+ result.duplicates[key] = regs
324
+ hashes = {r.description_hash for r in regs if r.description_hash != "manifest"}
325
+ versions = {r.version for r in regs if r.version != "unknown"}
326
+ if len(hashes) > 1 or len(versions) > 1:
327
+ result.drift[key] = regs
328
+
329
+ return result
330
+
331
+
332
+ # ---------------------------------------------------------------------------
333
+ # Rendering
334
+ # ---------------------------------------------------------------------------
335
+
336
+ def render_text(result: ProbeResult) -> str:
337
+ lines: list[str] = []
338
+ lines.append("Skill-registration probe")
339
+ lines.append("=" * 64)
340
+ lines.append("")
341
+ if not result.registrations:
342
+ lines.append("(no registrations found)")
343
+ return "\n".join(lines)
344
+
345
+ lines.append(f"{'TOOL':<10} {'SCOPE':<14} {'SKILL':<32} {'VER':<10} SOURCE")
346
+ lines.append("-" * 100)
347
+ for reg in result.registrations:
348
+ lines.append(
349
+ f"{reg.tool:<10} {reg.scope:<14} {reg.skill_id[:32]:<32} {reg.version:<10} {reg.source_path}"
350
+ )
351
+
352
+ if result.duplicates:
353
+ lines.append("")
354
+ lines.append("DUPLICATE — same skill registered in ≥ 2 sources")
355
+ lines.append("-" * 64)
356
+ for key, regs in result.duplicates.items():
357
+ lines.append(f" {key}")
358
+ for r in regs:
359
+ lines.append(f" - [{r.scope}/{r.version}] {r.source_path}")
360
+ if result.drift:
361
+ lines.append("")
362
+ lines.append("DRIFT — same skill registered with DIFFERENT description / version")
363
+ lines.append("-" * 64)
364
+ for key, regs in result.drift.items():
365
+ lines.append(f" {key}")
366
+ for r in regs:
367
+ lines.append(f" - [{r.scope}/{r.version}] hash={r.description_hash} desc={r.description_snippet!r}")
368
+ lines.append(f" source: {r.source_path}")
369
+
370
+ return "\n".join(lines)
371
+
372
+
373
+ def render_json(result: ProbeResult) -> str:
374
+ return json.dumps(result.to_dict(), indent=2)
375
+
376
+
377
+ # ---------------------------------------------------------------------------
378
+ # CLI
379
+ # ---------------------------------------------------------------------------
380
+
381
+ def main(argv: list[str] | None = None) -> int:
382
+ parser = argparse.ArgumentParser(
383
+ prog="probe_skill_registration",
384
+ description="Detect duplicate / drifting skill registrations across AI tools.",
385
+ )
386
+ parser.add_argument("--tool", choices=("all", *TOOL_IDS), default="all")
387
+ parser.add_argument("--scope", choices=("all", *SCOPE_IDS), default="all")
388
+ parser.add_argument("--format", choices=("text", "json"), default="text")
389
+ parser.add_argument(
390
+ "--strict", action="store_true",
391
+ help="Exit non-zero if any DUPLICATE / DRIFT finding is present.",
392
+ )
393
+ parser.add_argument("--home", type=Path, default=None, help="Override the user-global root (testing).")
394
+ parser.add_argument("--project", type=Path, default=None, help="Override the project root (testing).")
395
+ args = parser.parse_args(argv)
396
+
397
+ result = run_probe(
398
+ tool_filter=args.tool,
399
+ scope_filter=args.scope,
400
+ home=args.home,
401
+ project=args.project,
402
+ )
403
+
404
+ out = render_json(result) if args.format == "json" else render_text(result)
405
+ print(out)
406
+
407
+ if args.strict and (result.duplicates or result.drift):
408
+ return 2
409
+ return 0
410
+
411
+
412
+ if __name__ == "__main__":
413
+ sys.exit(main())