@event4u/agent-config 1.15.0 → 1.17.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 (354) hide show
  1. package/.agent-src/commands/{agents-audit.md → agents/audit.md} +4 -3
  2. package/.agent-src/commands/{agents-cleanup.md → agents/cleanup.md} +12 -6
  3. package/.agent-src/commands/{agents-prepare.md → agents/prepare.md} +4 -3
  4. package/.agent-src/commands/agents.md +46 -0
  5. package/.agent-src/commands/bug-fix.md +1 -1
  6. package/.agent-src/commands/bug-investigate.md +2 -2
  7. package/.agent-src/commands/{chat-history-checkpoint.md → chat-history/checkpoint.md} +5 -5
  8. package/.agent-src/commands/{chat-history-clear.md → chat-history/clear.md} +5 -5
  9. package/.agent-src/commands/{chat-history-resume.md → chat-history/resume.md} +4 -4
  10. package/.agent-src/commands/chat-history/show.md +107 -0
  11. package/.agent-src/commands/chat-history.md +33 -89
  12. package/.agent-src/commands/check-current-md.md +1 -1
  13. package/.agent-src/commands/{commit-in-chunks.md → commit/in-chunks.md} +15 -13
  14. package/.agent-src/commands/commit.md +22 -2
  15. package/.agent-src/commands/{context-create.md → context/create.md} +4 -3
  16. package/.agent-src/commands/{context-refactor.md → context/refactor.md} +4 -3
  17. package/.agent-src/commands/context.md +44 -0
  18. package/.agent-src/commands/{copilot-agents-init.md → copilot-agents/init.md} +4 -3
  19. package/.agent-src/commands/{copilot-agents-optimize.md → copilot-agents/optimize.md} +4 -3
  20. package/.agent-src/commands/copilot-agents.md +44 -0
  21. package/.agent-src/commands/council/default.md +221 -0
  22. package/.agent-src/commands/council/design.md +97 -0
  23. package/.agent-src/commands/council/optimize.md +116 -0
  24. package/.agent-src/commands/council/pr.md +124 -0
  25. package/.agent-src/commands/council.md +54 -0
  26. package/.agent-src/commands/{create-pr-description.md → create-pr/description-only.md} +4 -2
  27. package/.agent-src/commands/create-pr.md +49 -5
  28. package/.agent-src/commands/e2e-heal.md +1 -1
  29. package/.agent-src/commands/e2e-plan.md +1 -1
  30. package/.agent-src/commands/{feature-dev.md → feature/dev.md} +6 -3
  31. package/.agent-src/commands/{feature-explore.md → feature/explore.md} +5 -4
  32. package/.agent-src/commands/{feature-plan.md → feature/plan.md} +32 -5
  33. package/.agent-src/commands/{feature-refactor.md → feature/refactor.md} +4 -3
  34. package/.agent-src/commands/{feature-roadmap.md → feature/roadmap.md} +7 -6
  35. package/.agent-src/commands/feature.md +52 -0
  36. package/.agent-src/commands/{fix-ci.md → fix/ci.md} +4 -3
  37. package/.agent-src/commands/{fix-portability.md → fix/portability.md} +4 -3
  38. package/.agent-src/commands/{fix-pr-bot-comments.md → fix/pr-bots.md} +4 -3
  39. package/.agent-src/commands/{fix-pr-developer-comments.md → fix/pr-developers.md} +4 -3
  40. package/.agent-src/commands/{fix-pr-comments.md → fix/pr.md} +7 -6
  41. package/.agent-src/commands/{fix-references.md → fix/refs.md} +4 -3
  42. package/.agent-src/commands/{fix-seeder.md → fix/seeder.md} +4 -3
  43. package/.agent-src/commands/fix.md +54 -0
  44. package/.agent-src/commands/jira-ticket.md +1 -1
  45. package/.agent-src/commands/{do-and-judge.md → judge/on-diff.md} +7 -6
  46. package/.agent-src/commands/judge/solo.md +90 -0
  47. package/.agent-src/commands/{do-in-steps.md → judge/steps.md} +8 -7
  48. package/.agent-src/commands/judge.md +35 -70
  49. package/.agent-src/commands/{memory-add.md → memory/add.md} +7 -6
  50. package/.agent-src/commands/{memory-full.md → memory/load.md} +6 -5
  51. package/.agent-src/commands/{memory-promote.md → memory/promote.md} +6 -5
  52. package/.agent-src/commands/{propose-memory.md → memory/propose.md} +6 -5
  53. package/.agent-src/commands/memory.md +48 -0
  54. package/.agent-src/commands/mode.md +5 -5
  55. package/.agent-src/commands/{module-create.md → module/create.md} +4 -3
  56. package/.agent-src/commands/{module-explore.md → module/explore.md} +4 -3
  57. package/.agent-src/commands/module.md +44 -0
  58. package/.agent-src/commands/onboard.md +3 -3
  59. package/.agent-src/commands/{optimize-agents.md → optimize/agents.md} +5 -4
  60. package/.agent-src/commands/{optimize-augmentignore.md → optimize/augmentignore.md} +4 -4
  61. package/.agent-src/commands/{optimize-rtk-filters.md → optimize/rtk.md} +4 -3
  62. package/.agent-src/commands/{optimize-skills.md → optimize/skills.md} +5 -4
  63. package/.agent-src/commands/optimize.md +48 -0
  64. package/.agent-src/commands/{override-create.md → override/create.md} +4 -3
  65. package/.agent-src/commands/{override-manage.md → override/manage.md} +4 -3
  66. package/.agent-src/commands/override.md +44 -0
  67. package/.agent-src/commands/review-changes.md +26 -1
  68. package/.agent-src/commands/review-routing.md +1 -1
  69. package/.agent-src/commands/{roadmap-create.md → roadmap/create.md} +33 -5
  70. package/.agent-src/commands/{roadmap-execute.md → roadmap/execute.md} +4 -3
  71. package/.agent-src/commands/roadmap.md +44 -0
  72. package/.agent-src/commands/set-cost-profile.md +3 -3
  73. package/.agent-src/commands/sync-agent-settings.md +2 -2
  74. package/.agent-src/commands/{tests-create.md → tests/create.md} +5 -4
  75. package/.agent-src/commands/{tests-execute.md → tests/execute.md} +4 -3
  76. package/.agent-src/commands/tests.md +44 -0
  77. package/.agent-src/commands/upstream-contribute.md +1 -1
  78. package/.agent-src/contexts/authority/commit-mechanics.md +57 -0
  79. package/.agent-src/contexts/authority/destructive-mechanics.md +66 -0
  80. package/.agent-src/contexts/authority/scope-mechanics.md +87 -0
  81. package/.agent-src/contexts/communication/rules-auto/artifact-engagement-recording-mechanics.md +72 -0
  82. package/.agent-src/contexts/communication/rules-auto/augment-portability-mechanics.md +79 -0
  83. package/.agent-src/contexts/communication/rules-auto/augment-source-of-truth-mechanics.md +98 -0
  84. package/.agent-src/contexts/communication/rules-auto/cli-output-handling-mechanics.md +87 -0
  85. package/.agent-src/contexts/communication/rules-auto/command-suggestion-policy-mechanics.md +62 -0
  86. package/.agent-src/contexts/communication/rules-auto/docs-sync-mechanics.md +78 -0
  87. package/.agent-src/contexts/communication/rules-auto/package-ci-checks-mechanics.md +85 -0
  88. package/.agent-src/contexts/communication/rules-auto/review-routing-awareness-mechanics.md +65 -0
  89. package/.agent-src/contexts/communication/rules-auto/roadmap-progress-sync-mechanics.md +78 -0
  90. package/.agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +62 -0
  91. package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +55 -0
  92. package/.agent-src/contexts/communication/rules-auto/ui-audit-gate-mechanics.md +53 -0
  93. package/.agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +77 -0
  94. package/.agent-src/contexts/execution/autonomy-detection.md +54 -0
  95. package/.agent-src/contexts/execution/autonomy-examples.md +90 -0
  96. package/.agent-src/contexts/execution/autonomy-mechanics.md +29 -0
  97. package/.agent-src/contexts/execution/verification-mechanics.md +80 -0
  98. package/.agent-src/contexts/judges/no-consolidate-rationale.md +102 -0
  99. package/.agent-src/contexts/judges/persona-voice-rubric.md +140 -0
  100. package/.agent-src/personas/README.md +1 -1
  101. package/.agent-src/rules/agent-authority.md +24 -0
  102. package/.agent-src/rules/architecture.md +1 -1
  103. package/.agent-src/rules/artifact-drafting-protocol.md +1 -1
  104. package/.agent-src/rules/artifact-engagement-recording.md +14 -70
  105. package/.agent-src/rules/ask-when-uncertain.md +28 -43
  106. package/.agent-src/rules/augment-portability.md +15 -61
  107. package/.agent-src/rules/augment-source-of-truth.md +27 -93
  108. package/.agent-src/rules/autonomous-execution.md +78 -114
  109. package/.agent-src/rules/capture-learnings.md +1 -1
  110. package/.agent-src/rules/chat-history-cadence.md +3 -3
  111. package/.agent-src/rules/chat-history-ownership.md +3 -3
  112. package/.agent-src/rules/chat-history-visibility.md +3 -3
  113. package/.agent-src/rules/cli-output-handling.md +10 -76
  114. package/.agent-src/rules/command-suggestion-policy.md +93 -0
  115. package/.agent-src/rules/commit-conventions.md +17 -14
  116. package/.agent-src/rules/commit-policy.md +14 -42
  117. package/.agent-src/rules/context-hygiene.md +3 -3
  118. package/.agent-src/rules/direct-answers.md +34 -49
  119. package/.agent-src/rules/docker-commands.md +5 -5
  120. package/.agent-src/rules/docs-sync.md +16 -70
  121. package/.agent-src/rules/e2e-testing.md +1 -1
  122. package/.agent-src/rules/guidelines.md +4 -4
  123. package/.agent-src/rules/improve-before-implement.md +2 -2
  124. package/.agent-src/rules/language-and-tone.md +50 -133
  125. package/.agent-src/rules/minimal-safe-diff.md +3 -3
  126. package/.agent-src/rules/missing-tool-handling.md +28 -22
  127. package/.agent-src/rules/model-recommendation.md +4 -4
  128. package/.agent-src/rules/no-cheap-questions.md +82 -0
  129. package/.agent-src/rules/no-roadmap-references.md +73 -0
  130. package/.agent-src/rules/non-destructive-by-default.md +15 -49
  131. package/.agent-src/rules/onboarding-gate.md +5 -5
  132. package/.agent-src/rules/package-ci-checks.md +21 -61
  133. package/.agent-src/rules/preservation-guard.md +64 -29
  134. package/.agent-src/rules/review-routing-awareness.md +26 -45
  135. package/.agent-src/rules/roadmap-progress-sync.md +28 -96
  136. package/.agent-src/rules/role-mode-adherence.md +2 -2
  137. package/.agent-src/rules/scope-control.md +65 -46
  138. package/.agent-src/rules/security-sensitive-stop.md +9 -9
  139. package/.agent-src/rules/size-enforcement.md +1 -1
  140. package/.agent-src/rules/skill-quality.md +16 -48
  141. package/.agent-src/rules/{slash-commands.md → slash-command-routing-policy.md} +7 -4
  142. package/.agent-src/rules/think-before-action.md +55 -45
  143. package/.agent-src/rules/token-efficiency.md +4 -4
  144. package/.agent-src/rules/tool-safety.md +19 -16
  145. package/.agent-src/rules/{ui-audit-before-build.md → ui-audit-gate.md} +27 -41
  146. package/.agent-src/rules/user-interaction.md +16 -71
  147. package/.agent-src/rules/verify-before-complete.md +12 -67
  148. package/.agent-src/scripts/update_roadmap_progress.py +9 -4
  149. package/.agent-src/skills/ai-council/SKILL.md +335 -0
  150. package/.agent-src/skills/api-endpoint/SKILL.md +2 -2
  151. package/.agent-src/skills/api-testing/SKILL.md +1 -1
  152. package/.agent-src/skills/blade-ui/SKILL.md +1 -1
  153. package/.agent-src/skills/blast-radius-analyzer/SKILL.md +1 -1
  154. package/.agent-src/skills/bug-analyzer/SKILL.md +1 -1
  155. package/.agent-src/skills/check-refs/SKILL.md +59 -40
  156. package/.agent-src/skills/command-routing/SKILL.md +1 -1
  157. package/.agent-src/skills/command-writing/SKILL.md +1 -1
  158. package/.agent-src/skills/conventional-commits-writing/SKILL.md +86 -28
  159. package/.agent-src/skills/copilot-agents-optimization/SKILL.md +7 -7
  160. package/.agent-src/skills/developer-like-execution/SKILL.md +6 -6
  161. package/.agent-src/skills/finishing-a-development-branch/SKILL.md +101 -65
  162. package/.agent-src/skills/flux/SKILL.md +31 -11
  163. package/.agent-src/skills/git-workflow/SKILL.md +1 -1
  164. package/.agent-src/skills/github-ci/SKILL.md +2 -2
  165. package/.agent-src/skills/guideline-writing/SKILL.md +11 -11
  166. package/.agent-src/skills/judge-code-quality/SKILL.md +7 -8
  167. package/.agent-src/skills/judge-security-auditor/SKILL.md +4 -5
  168. package/.agent-src/skills/judge-test-coverage/SKILL.md +3 -4
  169. package/.agent-src/skills/learning-to-rule-or-skill/SKILL.md +4 -4
  170. package/.agent-src/skills/lint-skills/SKILL.md +57 -39
  171. package/.agent-src/skills/livewire/SKILL.md +1 -1
  172. package/.agent-src/skills/md-language-check/SKILL.md +61 -39
  173. package/.agent-src/skills/override-management/SKILL.md +7 -7
  174. package/.agent-src/skills/php-coder/SKILL.md +1 -1
  175. package/.agent-src/skills/playwright-testing/SKILL.md +2 -2
  176. package/.agent-src/skills/quality-tools/SKILL.md +2 -2
  177. package/.agent-src/skills/react-shadcn-ui/SKILL.md +116 -43
  178. package/.agent-src/skills/readme-reviewer/SKILL.md +31 -30
  179. package/.agent-src/skills/readme-writing/SKILL.md +79 -54
  180. package/.agent-src/skills/readme-writing-package/SKILL.md +51 -48
  181. package/.agent-src/skills/receiving-code-review/SKILL.md +53 -48
  182. package/.agent-src/skills/refine-prompt/SKILL.md +0 -1
  183. package/.agent-src/skills/requesting-code-review/SKILL.md +35 -30
  184. package/.agent-src/skills/review-routing/SKILL.md +2 -2
  185. package/.agent-src/skills/rule-writing/SKILL.md +1 -1
  186. package/.agent-src/skills/security/SKILL.md +7 -2
  187. package/.agent-src/skills/security-audit/SKILL.md +7 -3
  188. package/.agent-src/skills/skill-reviewer/SKILL.md +1 -1
  189. package/.agent-src/skills/skill-writing/SKILL.md +3 -3
  190. package/.agent-src/skills/subagent-orchestration/SKILL.md +1 -0
  191. package/.agent-src/skills/systematic-debugging/SKILL.md +69 -61
  192. package/.agent-src/skills/test-driven-development/SKILL.md +59 -57
  193. package/.agent-src/skills/test-performance/SKILL.md +0 -1
  194. package/.agent-src/skills/traefik/SKILL.md +4 -4
  195. package/.agent-src/skills/upstream-contribute/SKILL.md +1 -1
  196. package/.agent-src/skills/validate-feature-fit/SKILL.md +2 -2
  197. package/.agent-src/skills/{verify-before-complete → verify-completion-evidence}/SKILL.md +30 -28
  198. package/.agent-src/templates/agent-settings.md +8 -8
  199. package/.agent-src/templates/contexts/auth-model.md +1 -1
  200. package/.agent-src/templates/scripts/README.md +2 -2
  201. package/.agent-src/templates/scripts/telemetry/aggregator.py +16 -1
  202. package/.agent-src/templates/scripts/telemetry/engagement.py +59 -0
  203. package/.agent-src/templates/scripts/telemetry/report_renderer.py +28 -1
  204. package/.agent-src/templates/scripts/telemetry_record.py +14 -1
  205. package/.claude-plugin/marketplace.json +31 -12
  206. package/AGENTS.md +11 -9
  207. package/CHANGELOG.md +213 -2
  208. package/README.md +43 -44
  209. package/config/agent-settings.template.yml +58 -1
  210. package/config/gitignore-block.txt +3 -0
  211. package/docs/architecture.md +5 -7
  212. package/docs/catalog.md +359 -0
  213. package/docs/contracts/STABILITY.md +46 -1
  214. package/docs/contracts/adr-chat-history-split.md +1 -3
  215. package/docs/contracts/adr-command-suggestion.md +3 -5
  216. package/docs/contracts/adr-implement-ticket-runtime.md +1 -2
  217. package/docs/contracts/adr-product-ui-track.md +5 -8
  218. package/docs/contracts/adr-prompt-driven-execution.md +3 -4
  219. package/docs/contracts/agent-memory-contract.md +8 -13
  220. package/docs/contracts/artifact-engagement-flow.md +7 -10
  221. package/docs/contracts/command-clusters.md +56 -46
  222. package/docs/contracts/command-suggestion-flow.md +4 -6
  223. package/docs/contracts/context-paths.md +99 -0
  224. package/docs/contracts/file-ownership-matrix.json +6722 -0
  225. package/docs/contracts/file-ownership-matrix.md +134 -0
  226. package/docs/contracts/implement-ticket-flow.md +8 -11
  227. package/docs/contracts/linear-ai-rules-inclusion.md +1 -2
  228. package/docs/contracts/linear-ai-three-layers.md +0 -2
  229. package/docs/contracts/load-context-budget-model.md +178 -0
  230. package/docs/contracts/load-context-schema.md +184 -0
  231. package/docs/contracts/rule-interactions.md +0 -1
  232. package/docs/contracts/rule-interactions.yml +96 -0
  233. package/docs/contracts/rule-priority-hierarchy.md +87 -0
  234. package/docs/contracts/ui-track-flow.md +8 -18
  235. package/docs/customization.md +16 -0
  236. package/docs/end-to-end-walkthroughs.md +165 -0
  237. package/docs/getting-started.md +29 -10
  238. package/docs/github-topics.md +12 -3
  239. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +100 -0
  240. package/docs/guidelines/agent-infra/language-and-tone-examples.md +79 -0
  241. package/{.agent-src → docs}/guidelines/docs/readme-size-and-splitting.md +26 -25
  242. package/docs/guidelines/php/git.md +164 -0
  243. package/docs/migrations/commands-1.15.0.md +1 -1
  244. package/docs/showcase.md +9 -4
  245. package/docs/skills-catalog.md +14 -8
  246. package/docs/ui-track-mental-model.md +2 -2
  247. package/llms.txt +13 -7
  248. package/package.json +1 -1
  249. package/scripts/_one_off_phase4_dispatch_latency.py +108 -0
  250. package/scripts/_one_off_phase6_trigger_jaccard.py +92 -0
  251. package/scripts/_phase2_shim_helper.py +109 -0
  252. package/scripts/agent-config +33 -0
  253. package/scripts/ai_council/__init__.py +39 -0
  254. package/scripts/ai_council/_default_prices.py +41 -0
  255. package/scripts/ai_council/_one_off_2a4_acceptance.py +208 -0
  256. package/scripts/ai_council/_one_off_context_layer_v1_estimate.py +67 -0
  257. package/scripts/ai_council/_one_off_context_layer_v1_review.py +292 -0
  258. package/scripts/ai_council/_one_off_followups_review.py +259 -0
  259. package/scripts/ai_council/_one_off_nondestructive_inline_audit.py +209 -0
  260. package/scripts/ai_council/_one_off_phase_2a_budget_rebalance.py +257 -0
  261. package/scripts/ai_council/_one_off_phase_2a_post_revert.py +197 -0
  262. package/scripts/ai_council/_one_off_rebalancing_audit.py +149 -0
  263. package/scripts/ai_council/_one_off_roundtrip.py +106 -0
  264. package/scripts/ai_council/_one_off_rule_hardening_v1.py +251 -0
  265. package/scripts/ai_council/_one_off_structural_open_questions.py +232 -0
  266. package/scripts/ai_council/_one_off_structural_optimization.py +144 -0
  267. package/scripts/ai_council/_one_off_structural_v3_gaps.py +252 -0
  268. package/scripts/ai_council/_one_off_structural_v3_review.py +240 -0
  269. package/scripts/ai_council/budget_guard.py +172 -0
  270. package/scripts/ai_council/bundler.py +261 -0
  271. package/scripts/ai_council/clients.py +381 -0
  272. package/scripts/ai_council/modes.py +127 -0
  273. package/scripts/ai_council/orchestrator.py +350 -0
  274. package/scripts/ai_council/pricing.py +213 -0
  275. package/scripts/ai_council/project_context.py +159 -0
  276. package/scripts/ai_council/prompts.py +232 -0
  277. package/scripts/ai_council/session.py +144 -0
  278. package/scripts/check_always_budget.py +444 -0
  279. package/scripts/check_augmentignore.py +69 -0
  280. package/scripts/check_cluster_patterns.py +159 -0
  281. package/scripts/check_command_count_messaging.py +127 -0
  282. package/scripts/check_context_paths.py +201 -0
  283. package/scripts/check_no_roadmap_refs.py +155 -0
  284. package/scripts/check_phase_coupling.py +148 -0
  285. package/scripts/check_portability.py +57 -0
  286. package/scripts/check_public_catalog_links.py +122 -0
  287. package/scripts/check_references.py +33 -3
  288. package/scripts/check_roadmap_trackable.py +111 -0
  289. package/scripts/check_safety_floor_untouched.py +125 -0
  290. package/scripts/command_suggester/cooldown.py +1 -1
  291. package/scripts/command_suggester/loader.py +4 -1
  292. package/scripts/compress.py +59 -13
  293. package/scripts/generate_index.py +270 -0
  294. package/scripts/generate_ownership_matrix.py +323 -0
  295. package/scripts/hooks/augment-roadmap-progress.sh +57 -0
  296. package/scripts/install.py +49 -28
  297. package/scripts/install_anthropic_key.sh +5 -0
  298. package/scripts/install_openai_key.sh +106 -0
  299. package/scripts/lint_load_context.py +163 -0
  300. package/scripts/lint_no_new_atomic_commands.py +12 -11
  301. package/scripts/requirements-evals.txt +1 -0
  302. package/scripts/roadmap_progress_hook.py +159 -0
  303. package/scripts/schemas/command.schema.json +22 -1
  304. package/scripts/schemas/rule.schema.json +10 -0
  305. package/scripts/skill_linter.py +13 -4
  306. package/scripts/sync_agent_settings.py +26 -3
  307. package/scripts/update_counts.py +16 -4
  308. package/scripts/update_prices.py +124 -0
  309. package/.agent-src/guidelines/php/git.md +0 -96
  310. package/.agent-src/rules/command-suggestion.md +0 -134
  311. /package/{.agent-src → docs}/guidelines/agent-infra/agent-interaction-and-decision-quality.md +0 -0
  312. /package/{.agent-src → docs}/guidelines/agent-infra/break-glass-usage.md +0 -0
  313. /package/{.agent-src → docs}/guidelines/agent-infra/developer-judgment.md +0 -0
  314. /package/{.agent-src → docs}/guidelines/agent-infra/engineering-memory-data-format.md +0 -0
  315. /package/{.agent-src → docs}/guidelines/agent-infra/layered-settings.md +0 -0
  316. /package/{.agent-src → docs}/guidelines/agent-infra/memory-access.md +0 -0
  317. /package/{.agent-src → docs}/guidelines/agent-infra/naming.md +0 -0
  318. /package/{.agent-src → docs}/guidelines/agent-infra/output-patterns.md +0 -0
  319. /package/{.agent-src → docs}/guidelines/agent-infra/review-routing-data-format.md +0 -0
  320. /package/{.agent-src → docs}/guidelines/agent-infra/role-contracts.md +0 -0
  321. /package/{.agent-src → docs}/guidelines/agent-infra/role-mode-router.md +0 -0
  322. /package/{.agent-src → docs}/guidelines/agent-infra/runtime-layer.md +0 -0
  323. /package/{.agent-src → docs}/guidelines/agent-infra/self-improvement-pipeline.md +0 -0
  324. /package/{.agent-src → docs}/guidelines/agent-infra/size-and-scope.md +0 -0
  325. /package/{.agent-src → docs}/guidelines/agent-infra/tool-integration.md +0 -0
  326. /package/{.agent-src → docs}/guidelines/e2e/playwright.md +0 -0
  327. /package/{.agent-src → docs}/guidelines/php/api-design.md +0 -0
  328. /package/{.agent-src → docs}/guidelines/php/artisan-commands.md +0 -0
  329. /package/{.agent-src → docs}/guidelines/php/blade-ui.md +0 -0
  330. /package/{.agent-src → docs}/guidelines/php/controllers.md +0 -0
  331. /package/{.agent-src → docs}/guidelines/php/database.md +0 -0
  332. /package/{.agent-src → docs}/guidelines/php/eloquent.md +0 -0
  333. /package/{.agent-src → docs}/guidelines/php/flux.md +0 -0
  334. /package/{.agent-src → docs}/guidelines/php/general.md +0 -0
  335. /package/{.agent-src → docs}/guidelines/php/jobs.md +0 -0
  336. /package/{.agent-src → docs}/guidelines/php/livewire.md +0 -0
  337. /package/{.agent-src → docs}/guidelines/php/logging.md +0 -0
  338. /package/{.agent-src → docs}/guidelines/php/naming.md +0 -0
  339. /package/{.agent-src → docs}/guidelines/php/patterns/dependency-injection.md +0 -0
  340. /package/{.agent-src → docs}/guidelines/php/patterns/dtos.md +0 -0
  341. /package/{.agent-src → docs}/guidelines/php/patterns/events.md +0 -0
  342. /package/{.agent-src → docs}/guidelines/php/patterns/factory.md +0 -0
  343. /package/{.agent-src → docs}/guidelines/php/patterns/pipelines.md +0 -0
  344. /package/{.agent-src → docs}/guidelines/php/patterns/policies.md +0 -0
  345. /package/{.agent-src → docs}/guidelines/php/patterns/repositories.md +0 -0
  346. /package/{.agent-src → docs}/guidelines/php/patterns/service-layer.md +0 -0
  347. /package/{.agent-src → docs}/guidelines/php/patterns/strategy.md +0 -0
  348. /package/{.agent-src → docs}/guidelines/php/patterns.md +0 -0
  349. /package/{.agent-src → docs}/guidelines/php/performance.md +0 -0
  350. /package/{.agent-src → docs}/guidelines/php/resources.md +0 -0
  351. /package/{.agent-src → docs}/guidelines/php/security.md +0 -0
  352. /package/{.agent-src → docs}/guidelines/php/sql.md +0 -0
  353. /package/{.agent-src → docs}/guidelines/php/validations.md +0 -0
  354. /package/{.agent-src → docs}/guidelines/php/websocket.md +0 -0
@@ -0,0 +1,270 @@
1
+ #!/usr/bin/env python3
2
+ """Generate `agents/index.md` (internal) and `docs/catalog.md` (public).
3
+
4
+ Scans `.agent-src.uncompressed/{skills,rules,commands}/` plus `docs/guidelines/`
5
+ and renders two artefact tables — one for maintainers, one for consumers.
6
+
7
+ Both files are sync-checked in CI via `--check`; drift = build break.
8
+
9
+ Usage:
10
+ python3 scripts/generate_index.py # write both files
11
+ python3 scripts/generate_index.py --check # exit 1 if drift
12
+ """
13
+ from __future__ import annotations
14
+
15
+ import argparse
16
+ import re
17
+ import sys
18
+ from dataclasses import dataclass
19
+ from pathlib import Path
20
+
21
+ ROOT = Path(__file__).resolve().parent.parent
22
+ SRC = ROOT / ".agent-src.uncompressed"
23
+ GUIDELINES = ROOT / "docs" / "guidelines"
24
+ INDEX_PATH = ROOT / "agents" / "index.md"
25
+ CATALOG_PATH = ROOT / "docs" / "catalog.md"
26
+
27
+ # Internal-only rules — excluded from the public catalog.
28
+ INTERNAL_RULES = {
29
+ "augment-source-of-truth",
30
+ "augment-portability",
31
+ "docs-sync",
32
+ }
33
+
34
+ FRONTMATTER_RE = re.compile(r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
35
+
36
+
37
+ @dataclass(frozen=True)
38
+ class Entry:
39
+ kind: str # skill | rule | command | shim | guideline
40
+ name: str
41
+ description: str
42
+ extra: str # rule type · cluster · sub-folder, etc.
43
+ path: str # repo-relative link target
44
+
45
+
46
+ def _parse_frontmatter(text: str) -> dict[str, str]:
47
+ m = FRONTMATTER_RE.match(text)
48
+ if not m:
49
+ return {}
50
+ out: dict[str, str] = {}
51
+ for line in m.group(1).splitlines():
52
+ if ":" not in line or line.startswith(" "):
53
+ continue
54
+ k, _, v = line.partition(":")
55
+ out[k.strip()] = v.strip().strip('"').strip("'")
56
+ return out
57
+
58
+
59
+ def _truncate(text: str, limit: int = 200) -> str:
60
+ text = text.replace("|", "\\|").replace("\n", " ").strip()
61
+ return text if len(text) <= limit else text[: limit - 1].rstrip() + "…"
62
+
63
+
64
+ def _collect_skills() -> list[Entry]:
65
+ out = []
66
+ for skill_dir in sorted((SRC / "skills").iterdir()):
67
+ skill_md = skill_dir / "SKILL.md"
68
+ if not skill_md.exists():
69
+ continue
70
+ fm = _parse_frontmatter(skill_md.read_text(encoding="utf-8"))
71
+ name = fm.get("name") or skill_dir.name
72
+ out.append(Entry(
73
+ kind="skill",
74
+ name=name,
75
+ description=_truncate(fm.get("description", "")),
76
+ extra="",
77
+ path=f".agent-src.uncompressed/skills/{skill_dir.name}/SKILL.md",
78
+ ))
79
+ return out
80
+
81
+
82
+ def _collect_rules() -> list[Entry]:
83
+ out = []
84
+ for rule_md in sorted((SRC / "rules").glob("*.md")):
85
+ fm = _parse_frontmatter(rule_md.read_text(encoding="utf-8"))
86
+ out.append(Entry(
87
+ kind="rule",
88
+ name=rule_md.stem,
89
+ description=_truncate(fm.get("description", "")),
90
+ extra=fm.get("type", "?"),
91
+ path=f".agent-src.uncompressed/rules/{rule_md.name}",
92
+ ))
93
+ return out
94
+
95
+
96
+ def _collect_commands() -> list[Entry]:
97
+ out = []
98
+ cmd_dir = SRC / "commands"
99
+ for cmd_md in sorted(cmd_dir.rglob("*.md")):
100
+ if cmd_md.name == "AGENTS.md":
101
+ continue
102
+ fm = _parse_frontmatter(cmd_md.read_text(encoding="utf-8"))
103
+ is_shim = bool(fm.get("superseded_by"))
104
+ extra = ""
105
+ if is_shim:
106
+ extra = f"shim → /{fm['superseded_by']}"
107
+ elif fm.get("cluster"):
108
+ extra = f"cluster: {fm['cluster']}"
109
+ rel = cmd_md.relative_to(cmd_dir)
110
+ out.append(Entry(
111
+ kind="shim" if is_shim else "command",
112
+ name=fm.get("name") or cmd_md.stem,
113
+ description=_truncate(fm.get("description", "")),
114
+ extra=extra,
115
+ path=f".agent-src.uncompressed/commands/{rel}",
116
+ ))
117
+ return out
118
+
119
+
120
+ def _collect_guidelines() -> list[Entry]:
121
+ out = []
122
+ if not GUIDELINES.exists():
123
+ return out
124
+ for g_md in sorted(GUIDELINES.rglob("*.md")):
125
+ rel = g_md.relative_to(ROOT)
126
+ category = g_md.parent.name if g_md.parent != GUIDELINES else "(root)"
127
+ out.append(Entry(
128
+ kind="guideline",
129
+ name=g_md.stem,
130
+ description="",
131
+ extra=category,
132
+ path=str(rel),
133
+ ))
134
+ return out
135
+
136
+
137
+ # Path rewriter for the public catalog: link to the shipped surface
138
+ # (`.agent-src/`) instead of the source-of-truth (`.agent-src.uncompressed/`),
139
+ # which is excluded from `package.json#files` and `composer.json` archives.
140
+ def _to_shipped_path(path: str) -> str:
141
+ return path.replace(".agent-src.uncompressed/", ".agent-src/", 1)
142
+
143
+
144
+ def _render_table(
145
+ entries: list[Entry],
146
+ cols: list[str],
147
+ link_prefix: str,
148
+ path_rewrite=None,
149
+ ) -> str:
150
+ rows = ["| " + " | ".join(cols) + " |", "|" + "|".join(["---"] * len(cols)) + "|"]
151
+ for e in entries:
152
+ path = path_rewrite(e.path) if path_rewrite else e.path
153
+ link = f"[`{e.name}`]({link_prefix}{path})"
154
+ row = [e.kind, link, e.extra, e.description]
155
+ rows.append("| " + " | ".join(row) + " |")
156
+ return "\n".join(rows)
157
+
158
+
159
+
160
+ def _render_index(skills, rules, commands, guidelines) -> str:
161
+ total = len(skills) + len(rules) + len(commands) + len(guidelines)
162
+ parts = [
163
+ "# Agent-Config Internal Index",
164
+ "",
165
+ f"Maintainer-facing index of all **{total} artefacts** in this package.",
166
+ "Auto-generated from `.agent-src.uncompressed/` and `docs/guidelines/`.",
167
+ "",
168
+ "> **Regenerate:** `python3 scripts/generate_index.py`",
169
+ "> **Drift check:** `python3 scripts/generate_index.py --check` (runs in `task ci`)",
170
+ "> Do not edit manually.",
171
+ "",
172
+ f"## Skills ({len(skills)})",
173
+ "",
174
+ _render_table(skills, ["kind", "name", "extra", "description"], "../"),
175
+ "",
176
+ f"## Rules ({len(rules)})",
177
+ "",
178
+ _render_table(rules, ["kind", "name", "type", "description"], "../"),
179
+ "",
180
+ f"## Commands ({len(commands)})",
181
+ "",
182
+ _render_table(commands, ["kind", "name", "cluster/shim", "description"], "../"),
183
+ "",
184
+ f"## Guidelines ({len(guidelines)})",
185
+ "",
186
+ _render_table(guidelines, ["kind", "name", "category", "description"], "../"),
187
+ "",
188
+ ]
189
+ return "\n".join(parts)
190
+
191
+
192
+ def _render_catalog(skills, rules, commands, guidelines) -> str:
193
+ public_rules = [r for r in rules if r.name not in INTERNAL_RULES]
194
+ public_commands = [c for c in commands if c.kind == "command"]
195
+ total = len(skills) + len(public_rules) + len(public_commands) + len(guidelines)
196
+ parts = [
197
+ "# agent-config — Public Catalog",
198
+ "",
199
+ f"Consumer-facing catalog of all **{total} public artefacts** shipped by",
200
+ "this package. Internal package-maintenance rules and deprecation shims",
201
+ "are excluded.",
202
+ "",
203
+ "> **Regenerate:** `python3 scripts/generate_index.py`",
204
+ "> Auto-generated — do not edit manually.",
205
+ "",
206
+ f"## Skills ({len(skills)})",
207
+ "",
208
+ _render_table(skills, ["kind", "name", "extra", "description"], "../", _to_shipped_path),
209
+ "",
210
+ f"## Rules ({len(public_rules)})",
211
+ "",
212
+ _render_table(public_rules, ["kind", "name", "type", "description"], "../", _to_shipped_path),
213
+ "",
214
+ f"## Commands ({len(public_commands)})",
215
+ "",
216
+ _render_table(public_commands, ["kind", "name", "cluster", "description"], "../", _to_shipped_path),
217
+ "",
218
+ f"## Guidelines ({len(guidelines)})",
219
+ "",
220
+ _render_table(guidelines, ["kind", "name", "category", "description"], "../", _to_shipped_path),
221
+ "",
222
+ "---",
223
+ "",
224
+ "← [Back to README](../README.md)",
225
+ "",
226
+ ]
227
+ return "\n".join(parts)
228
+
229
+
230
+ def main() -> int:
231
+ parser = argparse.ArgumentParser(description=__doc__)
232
+ parser.add_argument("--check", action="store_true",
233
+ help="Exit 1 if generated content differs from on-disk files.")
234
+ args = parser.parse_args()
235
+
236
+ skills = _collect_skills()
237
+ rules = _collect_rules()
238
+ commands = _collect_commands()
239
+ guidelines = _collect_guidelines()
240
+
241
+ index_text = _render_index(skills, rules, commands, guidelines)
242
+ catalog_text = _render_catalog(skills, rules, commands, guidelines)
243
+
244
+ if args.check:
245
+ drift = []
246
+ if not INDEX_PATH.exists() or INDEX_PATH.read_text(encoding="utf-8") != index_text:
247
+ drift.append(str(INDEX_PATH.relative_to(ROOT)))
248
+ if not CATALOG_PATH.exists() or CATALOG_PATH.read_text(encoding="utf-8") != catalog_text:
249
+ drift.append(str(CATALOG_PATH.relative_to(ROOT)))
250
+ if drift:
251
+ print("❌ Index drift detected — regenerate with:")
252
+ print(" python3 scripts/generate_index.py")
253
+ for d in drift:
254
+ print(f" - {d}")
255
+ return 1
256
+ print("✅ Index files in sync.")
257
+ return 0
258
+
259
+ INDEX_PATH.parent.mkdir(parents=True, exist_ok=True)
260
+ CATALOG_PATH.parent.mkdir(parents=True, exist_ok=True)
261
+ INDEX_PATH.write_text(index_text, encoding="utf-8")
262
+ CATALOG_PATH.write_text(catalog_text, encoding="utf-8")
263
+ print(f"✅ Wrote {INDEX_PATH.relative_to(ROOT)} ({len(skills)} skills, "
264
+ f"{len(rules)} rules, {len(commands)} commands, {len(guidelines)} guidelines)")
265
+ print(f"✅ Wrote {CATALOG_PATH.relative_to(ROOT)} (public subset)")
266
+ return 0
267
+
268
+
269
+ if __name__ == "__main__":
270
+ sys.exit(main())
@@ -0,0 +1,323 @@
1
+ #!/usr/bin/env python3
2
+ """Generate the file-ownership matrix.
3
+
4
+ Produces:
5
+
6
+ * docs/contracts/file-ownership-matrix.json (machine, internal-locked)
7
+ * agents/contexts/structural/file-ownership-matrix.md (human-readable)
8
+
9
+ Walks `.agent-src.uncompressed/{rules,skills,commands,contexts,personas}/`,
10
+ parses frontmatter for `load_context:` / `load_context_eager:`, scans
11
+ markdown bodies for inline links to `.md` files inside the scanned roots,
12
+ and emits READ_ONLY edges plus depth-2 transitive closure of load_context
13
+ chains. Depth-3 chains abort the build (matches the 0.2.4 nesting cap).
14
+
15
+ Contract: docs/contracts/file-ownership-matrix.md
16
+ Roadmap: road-to-structural-optimization.md § 0.1
17
+
18
+ Modes:
19
+ --check Regenerate to memory and diff against committed JSON.
20
+ Exit 0 if identical, 1 if drifted.
21
+ (default) Regenerate JSON + MD in place; exit 0 on success.
22
+
23
+ Exit codes: 0 = ok, 1 = drift (--check), 2 = depth-3 chain, 3 = internal.
24
+ """
25
+ from __future__ import annotations
26
+
27
+ import argparse
28
+ import json
29
+ import re
30
+ import sys
31
+ from dataclasses import dataclass, field
32
+ from pathlib import Path
33
+ from typing import Iterable
34
+
35
+ import yaml
36
+
37
+ ROOT = Path(__file__).resolve().parent.parent
38
+ SRC_ROOT = ROOT / ".agent-src.uncompressed"
39
+
40
+ SCAN_DIRS = ("rules", "skills", "commands", "contexts", "personas")
41
+
42
+ JSON_OUT = ROOT / "docs" / "contracts" / "file-ownership-matrix.json"
43
+ MD_OUT = ROOT / "agents" / "contexts" / "structural" / "file-ownership-matrix.md"
44
+
45
+ LINK_RE = re.compile(r"\]\(([^)]+\.md)(?:#[^)]*)?\)")
46
+
47
+
48
+ @dataclass
49
+ class FileEntry:
50
+ path: str
51
+ kind: str
52
+ rule_type: str | None = None
53
+ load_context: list[str] = field(default_factory=list)
54
+ load_context_eager: list[str] = field(default_factory=list)
55
+
56
+
57
+ @dataclass
58
+ class Edge:
59
+ source: str
60
+ target: str
61
+ type: str
62
+ via: str
63
+ depth: int
64
+
65
+
66
+ def _rel(p: Path) -> str:
67
+ return p.relative_to(ROOT).as_posix()
68
+
69
+
70
+ def _kind_for(rel: str) -> str:
71
+ parts = rel.split("/")
72
+ if len(parts) >= 3 and parts[0] == ".agent-src.uncompressed":
73
+ return parts[1].rstrip("s") if parts[1] != "personas" else "persona"
74
+ return "unknown"
75
+
76
+
77
+ def _parse_frontmatter(p: Path) -> dict:
78
+ text = p.read_text(encoding="utf-8")
79
+ if not text.startswith("---\n"):
80
+ return {}
81
+ end = text.find("\n---\n", 4)
82
+ if end == -1:
83
+ return {}
84
+ try:
85
+ data = yaml.safe_load(text[4:end])
86
+ except yaml.YAMLError:
87
+ return {}
88
+ return data if isinstance(data, dict) else {}
89
+
90
+
91
+ def _collect_files(src_root: Path) -> list[Path]:
92
+ out: list[Path] = []
93
+ for sub in SCAN_DIRS:
94
+ d = src_root / sub
95
+ if d.exists():
96
+ out.extend(sorted(d.rglob("*.md")))
97
+ return out
98
+
99
+
100
+ def _resolve(target: str, src_root: Path) -> Path | None:
101
+ """Resolve a path string (repo-relative or short) into an absolute Path
102
+ under src_root or the repo root. Return None if not under a scanned root."""
103
+ cand = src_root.parent / target if "/" in target else src_root / target
104
+ try:
105
+ rel = cand.resolve().relative_to(src_root.parent)
106
+ except ValueError:
107
+ return None
108
+ parts = rel.parts
109
+ if len(parts) >= 3 and parts[0] == ".agent-src.uncompressed" and parts[1] in SCAN_DIRS:
110
+ return cand if cand.exists() else None
111
+ return None
112
+
113
+
114
+ def build_matrix(src_root: Path) -> tuple[dict[str, FileEntry], list[Edge], list[str]]:
115
+ """Build the file map + edge list. Returns (files, edges, depth3_chains).
116
+
117
+ depth3_chains is non-empty iff the depth invariant is violated; the
118
+ caller must abort with exit code 2.
119
+ """
120
+ files: dict[str, FileEntry] = {}
121
+ for f in _collect_files(src_root):
122
+ rel = f.relative_to(src_root.parent).as_posix()
123
+ fm = _parse_frontmatter(f)
124
+ rtype = fm.get("type")
125
+ if isinstance(rtype, str):
126
+ rtype = rtype.strip('"').strip("'")
127
+ else:
128
+ rtype = None
129
+ lazy = fm.get("load_context") or []
130
+ eager = fm.get("load_context_eager") or []
131
+ if not isinstance(lazy, list):
132
+ lazy = []
133
+ if not isinstance(eager, list):
134
+ eager = []
135
+ files[rel] = FileEntry(
136
+ path=rel,
137
+ kind=_kind_for(rel),
138
+ rule_type=rtype,
139
+ load_context=[str(x) for x in lazy if isinstance(x, str)],
140
+ load_context_eager=[str(x) for x in eager if isinstance(x, str)],
141
+ )
142
+
143
+ edges: list[Edge] = []
144
+ for rel, entry in files.items():
145
+ for tgt in entry.load_context:
146
+ edges.append(Edge(rel, tgt, "READ_ONLY", "load_context", 1))
147
+ for tgt in entry.load_context_eager:
148
+ edges.append(Edge(rel, tgt, "READ_ONLY", "load_context_eager", 1))
149
+
150
+ # Body markdown links — only count edges to files we know about
151
+ for rel, entry in files.items():
152
+ body = (src_root.parent / rel).read_text(encoding="utf-8")
153
+ body = body.split("\n---\n", 1)[-1] if body.startswith("---\n") else body
154
+ seen_targets: set[str] = set()
155
+ for m in LINK_RE.finditer(body):
156
+ href = m.group(1).strip()
157
+ if href.startswith("http"):
158
+ continue
159
+ resolved = _resolve_link(rel, href, src_root)
160
+ if resolved is None or resolved == rel or resolved in seen_targets:
161
+ continue
162
+ if resolved in files:
163
+ seen_targets.add(resolved)
164
+ edges.append(Edge(rel, resolved, "READ_ONLY", "body_link", 1))
165
+
166
+ # Transitive closure on load_context* edges, depth 2; depth 3 aborts.
167
+ lc_edges_by_src: dict[str, list[str]] = {}
168
+ for e in edges:
169
+ if e.via in ("load_context", "load_context_eager"):
170
+ lc_edges_by_src.setdefault(e.source, []).append(e.target)
171
+
172
+ transitive: list[Edge] = []
173
+ depth3: list[str] = []
174
+ for src, lvl1_targets in lc_edges_by_src.items():
175
+ for t1 in lvl1_targets:
176
+ for t2 in lc_edges_by_src.get(t1, []):
177
+ if t2 == src or t2 == t1:
178
+ continue
179
+ transitive.append(Edge(src, t2, "READ_ONLY", "load_context_transitive", 2))
180
+ # depth-3 probe
181
+ for t3 in lc_edges_by_src.get(t2, []):
182
+ if t3 in (src, t1, t2):
183
+ continue
184
+ depth3.append(f"{src} → {t1} → {t2} → {t3}")
185
+
186
+ edges.extend(transitive)
187
+ for rel in files:
188
+ edges.append(Edge(rel, rel, "WRITE", "self", 0))
189
+
190
+ edges.sort(key=lambda e: (e.source, e.target, e.via, e.depth))
191
+ return files, edges, depth3
192
+
193
+
194
+ def _resolve_link(source_rel: str, href: str, src_root: Path) -> str | None:
195
+ """Resolve a markdown link href (relative to source file) to a repo-relative
196
+ path inside a scanned root, or None."""
197
+ if href.startswith(".agent-src.uncompressed/") or href.startswith("agents/"):
198
+ cand = (src_root.parent / href).resolve()
199
+ else:
200
+ base = (src_root.parent / source_rel).parent
201
+ cand = (base / href).resolve()
202
+ try:
203
+ rel = cand.relative_to(src_root.parent).as_posix()
204
+ except ValueError:
205
+ return None
206
+ parts = rel.split("/")
207
+ if len(parts) >= 3 and parts[0] == ".agent-src.uncompressed" and parts[1] in SCAN_DIRS:
208
+ return rel if cand.exists() else None
209
+ return None
210
+
211
+
212
+ def _to_json(files: dict[str, FileEntry], edges: list[Edge]) -> dict:
213
+ return {
214
+ "version": 1,
215
+ "generated_by": "scripts/generate_ownership_matrix.py",
216
+ "source_of_truth": ".agent-src.uncompressed/",
217
+ "files": {
218
+ rel: {
219
+ "kind": e.kind,
220
+ "rule_type": e.rule_type,
221
+ "load_context": e.load_context,
222
+ "load_context_eager": e.load_context_eager,
223
+ }
224
+ for rel, e in sorted(files.items())
225
+ },
226
+ "edges": [
227
+ {
228
+ "source": e.source,
229
+ "target": e.target,
230
+ "type": e.type,
231
+ "via": e.via,
232
+ "depth": e.depth,
233
+ }
234
+ for e in edges
235
+ ],
236
+ }
237
+
238
+
239
+ def _to_markdown(payload: dict) -> str:
240
+ lines: list[str] = [
241
+ "# File-ownership matrix (regenerated)",
242
+ "",
243
+ "> **Do not edit.** Regenerated by `scripts/generate_ownership_matrix.py`.",
244
+ "> Schema: [`docs/contracts/file-ownership-matrix.md`](../../../docs/contracts/file-ownership-matrix.md).",
245
+ "",
246
+ f"- Schema version: `{payload['version']}`",
247
+ f"- Source of truth: `{payload['source_of_truth']}`",
248
+ f"- Files indexed: **{len(payload['files'])}**",
249
+ f"- Edges (incl. self-WRITE): **{len(payload['edges'])}**",
250
+ "",
251
+ "## READ_ONLY edges",
252
+ "",
253
+ "| Source | Target | Via | Depth |",
254
+ "|---|---|---|---:|",
255
+ ]
256
+ ro = [e for e in payload["edges"] if e["type"] == "READ_ONLY"]
257
+ for e in ro:
258
+ lines.append(f"| `{e['source']}` | `{e['target']}` | `{e['via']}` | {e['depth']} |")
259
+ if not ro:
260
+ lines.append("| _(none)_ | | | |")
261
+ lines += [
262
+ "",
263
+ "## Files by kind",
264
+ "",
265
+ "| Kind | Count |",
266
+ "|---|---:|",
267
+ ]
268
+ counts: dict[str, int] = {}
269
+ for f in payload["files"].values():
270
+ counts[f["kind"]] = counts.get(f["kind"], 0) + 1
271
+ for k in sorted(counts):
272
+ lines.append(f"| `{k}` | {counts[k]} |")
273
+ lines.append("")
274
+ return "\n".join(lines)
275
+
276
+
277
+ def _write_outputs(payload: dict, json_out: Path, md_out: Path) -> None:
278
+ json_out.parent.mkdir(parents=True, exist_ok=True)
279
+ md_out.parent.mkdir(parents=True, exist_ok=True)
280
+ json_out.write_text(json.dumps(payload, indent=2, sort_keys=False) + "\n", encoding="utf-8")
281
+ md_out.write_text(_to_markdown(payload) + "\n", encoding="utf-8")
282
+
283
+
284
+ def main(argv: Iterable[str] | None = None) -> int:
285
+ ap = argparse.ArgumentParser(description=__doc__)
286
+ ap.add_argument("--check", action="store_true",
287
+ help="Regenerate to memory and diff against committed JSON.")
288
+ args = ap.parse_args(list(argv) if argv is not None else None)
289
+
290
+ if not SRC_ROOT.is_dir():
291
+ print(f"❌ source dir missing: {SRC_ROOT}", file=sys.stderr)
292
+ return 3
293
+
294
+ files, edges, depth3 = build_matrix(SRC_ROOT)
295
+ if depth3:
296
+ print("❌ load_context depth-3 chain detected (limit is 2):", file=sys.stderr)
297
+ for chain in depth3:
298
+ print(f" 🔴 {chain}", file=sys.stderr)
299
+ return 2
300
+
301
+ payload = _to_json(files, edges)
302
+
303
+ if args.check:
304
+ if not JSON_OUT.exists():
305
+ print(f"❌ {JSON_OUT.relative_to(ROOT)} not committed; run `task generate-ownership-matrix`",
306
+ file=sys.stderr)
307
+ return 1
308
+ committed = json.loads(JSON_OUT.read_text(encoding="utf-8"))
309
+ if committed != payload:
310
+ print("❌ ownership matrix is stale — run `task generate-ownership-matrix` and commit",
311
+ file=sys.stderr)
312
+ return 1
313
+ print(f"✅ ownership matrix in sync ({len(files)} files, {len(edges)} edges)")
314
+ return 0
315
+
316
+ _write_outputs(payload, JSON_OUT, MD_OUT)
317
+ print(f"✅ wrote {JSON_OUT.relative_to(ROOT)} ({len(files)} files, {len(edges)} edges)")
318
+ print(f"✅ wrote {MD_OUT.relative_to(ROOT)}")
319
+ return 0
320
+
321
+
322
+ if __name__ == "__main__":
323
+ sys.exit(main())
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env bash
2
+ # Augment Code lifecycle-hook trampoline for roadmap-progress-sync.
3
+ #
4
+ # Augment requires hook scripts to use the .sh extension and live at
5
+ # either a system path (/etc/augment/...) or user scope
6
+ # (~/.augment/...). This trampoline lives at user scope and dispatches
7
+ # every PostToolUse event to whichever workspace fired it, so a single
8
+ # install covers every project that has ./agent-config available.
9
+ #
10
+ # Behaviour:
11
+ # - Read the JSON event from stdin into a buffer.
12
+ # - Extract workspace_roots[0]; bail silently when missing.
13
+ # - cd into that workspace; bail silently when it is not a directory
14
+ # or does not contain ./agent-config.
15
+ # - Re-pipe the original JSON into
16
+ # ./agent-config roadmap-progress:hook --platform augment
17
+ # so roadmap_progress_hook.py runs the path filter and decides
18
+ # whether to regenerate the dashboard.
19
+ # - Always exit 0 — PostToolUse hooks must never block.
20
+
21
+ set -u
22
+
23
+ EVENT_DATA="$(cat)"
24
+
25
+ # Extract workspace_roots[0] using whichever JSON tool is available.
26
+ WORKSPACE=""
27
+ if command -v jq >/dev/null 2>&1; then
28
+ WORKSPACE="$(printf '%s' "$EVENT_DATA" \
29
+ | jq -r '.workspace_roots[0] // empty' 2>/dev/null)"
30
+ elif command -v python3 >/dev/null 2>&1; then
31
+ WORKSPACE="$(printf '%s' "$EVENT_DATA" | python3 -c '
32
+ import json, sys
33
+ try:
34
+ data = json.load(sys.stdin)
35
+ except Exception:
36
+ sys.exit(0)
37
+ roots = data.get("workspace_roots") or []
38
+ if roots:
39
+ print(roots[0])
40
+ ' 2>/dev/null)"
41
+ fi
42
+
43
+ if [ -z "$WORKSPACE" ] || [ ! -d "$WORKSPACE" ]; then
44
+ exit 0
45
+ fi
46
+
47
+ cd "$WORKSPACE" 2>/dev/null || exit 0
48
+
49
+ if [ ! -x ./agent-config ]; then
50
+ exit 0
51
+ fi
52
+
53
+ printf '%s' "$EVENT_DATA" \
54
+ | ./agent-config roadmap-progress:hook --platform augment \
55
+ >/dev/null 2>&1 || true
56
+
57
+ exit 0