@event4u/agent-config 1.9.1

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 (446) hide show
  1. package/.agent-src/README.md +64 -0
  2. package/.agent-src/commands/agent-handoff.md +64 -0
  3. package/.agent-src/commands/agent-status.md +83 -0
  4. package/.agent-src/commands/agents-audit.md +243 -0
  5. package/.agent-src/commands/agents-cleanup.md +169 -0
  6. package/.agent-src/commands/agents-prepare.md +137 -0
  7. package/.agent-src/commands/analyze-reference-repo.md +191 -0
  8. package/.agent-src/commands/bug-fix.md +181 -0
  9. package/.agent-src/commands/bug-investigate.md +175 -0
  10. package/.agent-src/commands/commit.md +121 -0
  11. package/.agent-src/commands/compress.md +177 -0
  12. package/.agent-src/commands/config-agent-settings.md +126 -0
  13. package/.agent-src/commands/context-create.md +167 -0
  14. package/.agent-src/commands/context-refactor.md +170 -0
  15. package/.agent-src/commands/copilot-agents-init.md +150 -0
  16. package/.agent-src/commands/copilot-agents-optimize.md +251 -0
  17. package/.agent-src/commands/create-pr-description.md +112 -0
  18. package/.agent-src/commands/create-pr.md +76 -0
  19. package/.agent-src/commands/do-and-judge.md +114 -0
  20. package/.agent-src/commands/do-in-steps.md +84 -0
  21. package/.agent-src/commands/e2e-heal.md +98 -0
  22. package/.agent-src/commands/e2e-plan.md +85 -0
  23. package/.agent-src/commands/estimate-ticket.md +80 -0
  24. package/.agent-src/commands/feature-dev.md +111 -0
  25. package/.agent-src/commands/feature-explore.md +180 -0
  26. package/.agent-src/commands/feature-plan.md +288 -0
  27. package/.agent-src/commands/feature-refactor.md +181 -0
  28. package/.agent-src/commands/feature-roadmap.md +184 -0
  29. package/.agent-src/commands/fix-ci.md +48 -0
  30. package/.agent-src/commands/fix-portability.md +97 -0
  31. package/.agent-src/commands/fix-pr-bot-comments.md +146 -0
  32. package/.agent-src/commands/fix-pr-comments.md +58 -0
  33. package/.agent-src/commands/fix-pr-developer-comments.md +152 -0
  34. package/.agent-src/commands/fix-references.md +94 -0
  35. package/.agent-src/commands/fix-seeder.md +146 -0
  36. package/.agent-src/commands/implement-ticket.md +133 -0
  37. package/.agent-src/commands/jira-ticket.md +71 -0
  38. package/.agent-src/commands/judge.md +86 -0
  39. package/.agent-src/commands/memory-add.md +130 -0
  40. package/.agent-src/commands/memory-full.md +97 -0
  41. package/.agent-src/commands/memory-promote.md +144 -0
  42. package/.agent-src/commands/mode.md +121 -0
  43. package/.agent-src/commands/module-create.md +132 -0
  44. package/.agent-src/commands/module-explore.md +157 -0
  45. package/.agent-src/commands/optimize-agents.md +139 -0
  46. package/.agent-src/commands/optimize-augmentignore.md +262 -0
  47. package/.agent-src/commands/optimize-rtk-filters.md +120 -0
  48. package/.agent-src/commands/optimize-skills.md +121 -0
  49. package/.agent-src/commands/override-create.md +97 -0
  50. package/.agent-src/commands/override-manage.md +96 -0
  51. package/.agent-src/commands/package-reset.md +154 -0
  52. package/.agent-src/commands/package-test.md +154 -0
  53. package/.agent-src/commands/prepare-for-review.md +91 -0
  54. package/.agent-src/commands/project-analyze.md +300 -0
  55. package/.agent-src/commands/project-health.md +95 -0
  56. package/.agent-src/commands/propose-memory.md +108 -0
  57. package/.agent-src/commands/quality-fix.md +106 -0
  58. package/.agent-src/commands/refine-ticket.md +81 -0
  59. package/.agent-src/commands/review-changes.md +130 -0
  60. package/.agent-src/commands/review-routing.md +111 -0
  61. package/.agent-src/commands/roadmap-create.md +110 -0
  62. package/.agent-src/commands/roadmap-execute.md +68 -0
  63. package/.agent-src/commands/rule-compliance-audit.md +139 -0
  64. package/.agent-src/commands/tests-create.md +73 -0
  65. package/.agent-src/commands/tests-execute.md +58 -0
  66. package/.agent-src/commands/threat-model.md +115 -0
  67. package/.agent-src/commands/update-form-request-messages.md +189 -0
  68. package/.agent-src/commands/upstream-contribute.md +171 -0
  69. package/.agent-src/contexts/augment-infrastructure.md +181 -0
  70. package/.agent-src/contexts/documentation-hierarchy.md +142 -0
  71. package/.agent-src/contexts/model-recommendations.md +142 -0
  72. package/.agent-src/contexts/override-system.md +187 -0
  73. package/.agent-src/contexts/skills-and-commands.md +154 -0
  74. package/.agent-src/contexts/subagent-configuration.md +62 -0
  75. package/.agent-src/guidelines/agent-infra/agent-interaction-and-decision-quality.md +110 -0
  76. package/.agent-src/guidelines/agent-infra/break-glass-usage.md +113 -0
  77. package/.agent-src/guidelines/agent-infra/developer-judgment.md +82 -0
  78. package/.agent-src/guidelines/agent-infra/engineering-memory-data-format.md +117 -0
  79. package/.agent-src/guidelines/agent-infra/layered-settings.md +158 -0
  80. package/.agent-src/guidelines/agent-infra/memory-access.md +121 -0
  81. package/.agent-src/guidelines/agent-infra/naming.md +69 -0
  82. package/.agent-src/guidelines/agent-infra/output-patterns.md +117 -0
  83. package/.agent-src/guidelines/agent-infra/review-routing-data-format.md +144 -0
  84. package/.agent-src/guidelines/agent-infra/role-contracts.md +211 -0
  85. package/.agent-src/guidelines/agent-infra/role-mode-router.md +89 -0
  86. package/.agent-src/guidelines/agent-infra/runtime-layer.md +89 -0
  87. package/.agent-src/guidelines/agent-infra/self-improvement-pipeline.md +135 -0
  88. package/.agent-src/guidelines/agent-infra/size-and-scope.md +189 -0
  89. package/.agent-src/guidelines/agent-infra/tool-integration.md +73 -0
  90. package/.agent-src/guidelines/docs/readme-size-and-splitting.md +153 -0
  91. package/.agent-src/guidelines/e2e/playwright.md +363 -0
  92. package/.agent-src/guidelines/php/api-design.md +115 -0
  93. package/.agent-src/guidelines/php/artisan-commands.md +81 -0
  94. package/.agent-src/guidelines/php/blade-ui.md +78 -0
  95. package/.agent-src/guidelines/php/controllers.md +90 -0
  96. package/.agent-src/guidelines/php/database.md +111 -0
  97. package/.agent-src/guidelines/php/eloquent.md +208 -0
  98. package/.agent-src/guidelines/php/flux.md +80 -0
  99. package/.agent-src/guidelines/php/general.md +191 -0
  100. package/.agent-src/guidelines/php/git.md +96 -0
  101. package/.agent-src/guidelines/php/jobs.md +111 -0
  102. package/.agent-src/guidelines/php/livewire.md +71 -0
  103. package/.agent-src/guidelines/php/logging.md +79 -0
  104. package/.agent-src/guidelines/php/naming.md +89 -0
  105. package/.agent-src/guidelines/php/patterns/dependency-injection.md +57 -0
  106. package/.agent-src/guidelines/php/patterns/dtos.md +199 -0
  107. package/.agent-src/guidelines/php/patterns/events.md +67 -0
  108. package/.agent-src/guidelines/php/patterns/factory.md +53 -0
  109. package/.agent-src/guidelines/php/patterns/pipelines.md +66 -0
  110. package/.agent-src/guidelines/php/patterns/policies.md +66 -0
  111. package/.agent-src/guidelines/php/patterns/repositories.md +122 -0
  112. package/.agent-src/guidelines/php/patterns/service-layer.md +64 -0
  113. package/.agent-src/guidelines/php/patterns/strategy.md +69 -0
  114. package/.agent-src/guidelines/php/patterns.md +28 -0
  115. package/.agent-src/guidelines/php/performance.md +92 -0
  116. package/.agent-src/guidelines/php/resources.md +100 -0
  117. package/.agent-src/guidelines/php/security.md +110 -0
  118. package/.agent-src/guidelines/php/sql.md +97 -0
  119. package/.agent-src/guidelines/php/validations.md +119 -0
  120. package/.agent-src/guidelines/php/websocket.md +100 -0
  121. package/.agent-src/personas/README.md +104 -0
  122. package/.agent-src/personas/ai-agent.md +77 -0
  123. package/.agent-src/personas/critical-challenger.md +73 -0
  124. package/.agent-src/personas/developer.md +73 -0
  125. package/.agent-src/personas/product-owner.md +78 -0
  126. package/.agent-src/personas/qa.md +67 -0
  127. package/.agent-src/personas/senior-engineer.md +77 -0
  128. package/.agent-src/personas/stakeholder.md +78 -0
  129. package/.agent-src/rules/agent-docs.md +61 -0
  130. package/.agent-src/rules/analysis-skill-routing.md +48 -0
  131. package/.agent-src/rules/architecture.md +62 -0
  132. package/.agent-src/rules/artifact-drafting-protocol.md +73 -0
  133. package/.agent-src/rules/ask-when-uncertain.md +52 -0
  134. package/.agent-src/rules/augment-portability.md +38 -0
  135. package/.agent-src/rules/augment-source-of-truth.md +128 -0
  136. package/.agent-src/rules/capture-learnings.md +89 -0
  137. package/.agent-src/rules/cli-output-handling.md +94 -0
  138. package/.agent-src/rules/commit-conventions.md +64 -0
  139. package/.agent-src/rules/context-hygiene.md +90 -0
  140. package/.agent-src/rules/docker-commands.md +55 -0
  141. package/.agent-src/rules/docs-sync.md +79 -0
  142. package/.agent-src/rules/downstream-changes.md +70 -0
  143. package/.agent-src/rules/e2e-testing.md +53 -0
  144. package/.agent-src/rules/guidelines.md +90 -0
  145. package/.agent-src/rules/improve-before-implement.md +94 -0
  146. package/.agent-src/rules/language-and-tone.md +104 -0
  147. package/.agent-src/rules/laravel-translations.md +48 -0
  148. package/.agent-src/rules/markdown-safe-codeblocks.md +18 -0
  149. package/.agent-src/rules/minimal-safe-diff.md +87 -0
  150. package/.agent-src/rules/missing-tool-handling.md +62 -0
  151. package/.agent-src/rules/model-recommendation.md +70 -0
  152. package/.agent-src/rules/package-ci-checks.md +80 -0
  153. package/.agent-src/rules/php-coding.md +63 -0
  154. package/.agent-src/rules/preservation-guard.md +29 -0
  155. package/.agent-src/rules/review-routing-awareness.md +125 -0
  156. package/.agent-src/rules/reviewer-awareness.md +92 -0
  157. package/.agent-src/rules/roadmap-progress-sync.md +56 -0
  158. package/.agent-src/rules/role-mode-adherence.md +54 -0
  159. package/.agent-src/rules/rule-type-governance.md +46 -0
  160. package/.agent-src/rules/runtime-safety.md +42 -0
  161. package/.agent-src/rules/scope-control.md +40 -0
  162. package/.agent-src/rules/security-sensitive-stop.md +77 -0
  163. package/.agent-src/rules/size-enforcement.md +29 -0
  164. package/.agent-src/rules/skill-improvement-trigger.md +58 -0
  165. package/.agent-src/rules/skill-quality.md +110 -0
  166. package/.agent-src/rules/slash-commands.md +30 -0
  167. package/.agent-src/rules/think-before-action.md +91 -0
  168. package/.agent-src/rules/token-efficiency.md +99 -0
  169. package/.agent-src/rules/tool-safety.md +36 -0
  170. package/.agent-src/rules/upstream-proposal.md +76 -0
  171. package/.agent-src/rules/user-interaction.md +79 -0
  172. package/.agent-src/rules/verify-before-complete.md +120 -0
  173. package/.agent-src/scripts/scan-seeder-violations.php +145 -0
  174. package/.agent-src/scripts/update_roadmap_progress.py +244 -0
  175. package/.agent-src/skills/adversarial-review/SKILL.md +149 -0
  176. package/.agent-src/skills/agent-docs-writing/SKILL.md +234 -0
  177. package/.agent-src/skills/analysis-autonomous-mode/SKILL.md +197 -0
  178. package/.agent-src/skills/analysis-skill-router/SKILL.md +134 -0
  179. package/.agent-src/skills/api-design/SKILL.md +104 -0
  180. package/.agent-src/skills/api-endpoint/SKILL.md +185 -0
  181. package/.agent-src/skills/api-testing/SKILL.md +206 -0
  182. package/.agent-src/skills/artisan-commands/SKILL.md +78 -0
  183. package/.agent-src/skills/authz-review/SKILL.md +171 -0
  184. package/.agent-src/skills/aws-infrastructure/SKILL.md +152 -0
  185. package/.agent-src/skills/blade-ui/SKILL.md +75 -0
  186. package/.agent-src/skills/blast-radius-analyzer/SKILL.md +185 -0
  187. package/.agent-src/skills/bug-analyzer/SKILL.md +256 -0
  188. package/.agent-src/skills/check-refs/SKILL.md +72 -0
  189. package/.agent-src/skills/code-refactoring/SKILL.md +200 -0
  190. package/.agent-src/skills/code-review/SKILL.md +214 -0
  191. package/.agent-src/skills/command-routing/SKILL.md +96 -0
  192. package/.agent-src/skills/command-writing/SKILL.md +143 -0
  193. package/.agent-src/skills/composer-packages/SKILL.md +172 -0
  194. package/.agent-src/skills/context-authoring/SKILL.md +157 -0
  195. package/.agent-src/skills/context-document/SKILL.md +153 -0
  196. package/.agent-src/skills/conventional-commits-writing/SKILL.md +70 -0
  197. package/.agent-src/skills/copilot-agents-optimization/SKILL.md +220 -0
  198. package/.agent-src/skills/copilot-config/SKILL.md +203 -0
  199. package/.agent-src/skills/dashboard-design/SKILL.md +116 -0
  200. package/.agent-src/skills/data-flow-mapper/SKILL.md +160 -0
  201. package/.agent-src/skills/database/SKILL.md +91 -0
  202. package/.agent-src/skills/dependency-upgrade/SKILL.md +204 -0
  203. package/.agent-src/skills/description-assist/SKILL.md +169 -0
  204. package/.agent-src/skills/design-review/SKILL.md +228 -0
  205. package/.agent-src/skills/devcontainer/SKILL.md +121 -0
  206. package/.agent-src/skills/developer-like-execution/SKILL.md +276 -0
  207. package/.agent-src/skills/docker/SKILL.md +245 -0
  208. package/.agent-src/skills/dto-creator/SKILL.md +117 -0
  209. package/.agent-src/skills/eloquent/SKILL.md +92 -0
  210. package/.agent-src/skills/eloquent/evals/last-run.json +99 -0
  211. package/.agent-src/skills/eloquent/evals/triggers.json +16 -0
  212. package/.agent-src/skills/estimate-ticket/SKILL.md +186 -0
  213. package/.agent-src/skills/estimate-ticket/evals/output-schema.yml +20 -0
  214. package/.agent-src/skills/estimate-ticket/evals/triggers.json +18 -0
  215. package/.agent-src/skills/fe-design/SKILL.md +223 -0
  216. package/.agent-src/skills/feature-planning/SKILL.md +226 -0
  217. package/.agent-src/skills/file-editor/SKILL.md +129 -0
  218. package/.agent-src/skills/finishing-a-development-branch/SKILL.md +200 -0
  219. package/.agent-src/skills/flux/SKILL.md +64 -0
  220. package/.agent-src/skills/git-workflow/SKILL.md +102 -0
  221. package/.agent-src/skills/github-ci/SKILL.md +122 -0
  222. package/.agent-src/skills/grafana/SKILL.md +168 -0
  223. package/.agent-src/skills/guideline-writing/SKILL.md +147 -0
  224. package/.agent-src/skills/jira-integration/SKILL.md +182 -0
  225. package/.agent-src/skills/jobs-events/SKILL.md +87 -0
  226. package/.agent-src/skills/judge-bug-hunter/SKILL.md +157 -0
  227. package/.agent-src/skills/judge-code-quality/SKILL.md +158 -0
  228. package/.agent-src/skills/judge-security-auditor/SKILL.md +167 -0
  229. package/.agent-src/skills/judge-test-coverage/SKILL.md +154 -0
  230. package/.agent-src/skills/laravel/SKILL.md +195 -0
  231. package/.agent-src/skills/laravel-horizon/SKILL.md +169 -0
  232. package/.agent-src/skills/laravel-mail/SKILL.md +193 -0
  233. package/.agent-src/skills/laravel-middleware/SKILL.md +185 -0
  234. package/.agent-src/skills/laravel-notifications/SKILL.md +168 -0
  235. package/.agent-src/skills/laravel-pennant/SKILL.md +188 -0
  236. package/.agent-src/skills/laravel-pulse/SKILL.md +160 -0
  237. package/.agent-src/skills/laravel-reverb/SKILL.md +205 -0
  238. package/.agent-src/skills/laravel-scheduling/SKILL.md +167 -0
  239. package/.agent-src/skills/laravel-validation/SKILL.md +71 -0
  240. package/.agent-src/skills/learning-to-rule-or-skill/SKILL.md +249 -0
  241. package/.agent-src/skills/lint-skills/SKILL.md +72 -0
  242. package/.agent-src/skills/livewire/SKILL.md +79 -0
  243. package/.agent-src/skills/logging-monitoring/SKILL.md +100 -0
  244. package/.agent-src/skills/mcp/SKILL.md +193 -0
  245. package/.agent-src/skills/merge-conflicts/SKILL.md +158 -0
  246. package/.agent-src/skills/migration-creator/SKILL.md +160 -0
  247. package/.agent-src/skills/module-management/SKILL.md +154 -0
  248. package/.agent-src/skills/multi-tenancy/SKILL.md +129 -0
  249. package/.agent-src/skills/openapi/SKILL.md +154 -0
  250. package/.agent-src/skills/override-management/SKILL.md +186 -0
  251. package/.agent-src/skills/performance/SKILL.md +69 -0
  252. package/.agent-src/skills/performance-analysis/SKILL.md +118 -0
  253. package/.agent-src/skills/pest-testing/SKILL.md +321 -0
  254. package/.agent-src/skills/php-coder/SKILL.md +78 -0
  255. package/.agent-src/skills/php-coder/evals/triggers.json +16 -0
  256. package/.agent-src/skills/php-debugging/SKILL.md +184 -0
  257. package/.agent-src/skills/php-service/SKILL.md +96 -0
  258. package/.agent-src/skills/playwright-testing/SKILL.md +244 -0
  259. package/.agent-src/skills/project-analysis-core/SKILL.md +138 -0
  260. package/.agent-src/skills/project-analysis-hypothesis-driven/SKILL.md +130 -0
  261. package/.agent-src/skills/project-analysis-laravel/SKILL.md +119 -0
  262. package/.agent-src/skills/project-analysis-nextjs/SKILL.md +123 -0
  263. package/.agent-src/skills/project-analysis-node-express/SKILL.md +111 -0
  264. package/.agent-src/skills/project-analysis-react/SKILL.md +119 -0
  265. package/.agent-src/skills/project-analysis-symfony/SKILL.md +111 -0
  266. package/.agent-src/skills/project-analysis-zend-laminas/SKILL.md +108 -0
  267. package/.agent-src/skills/project-analyzer/SKILL.md +341 -0
  268. package/.agent-src/skills/project-docs/SKILL.md +137 -0
  269. package/.agent-src/skills/quality-tools/SKILL.md +411 -0
  270. package/.agent-src/skills/readme-reviewer/SKILL.md +187 -0
  271. package/.agent-src/skills/readme-writing/SKILL.md +142 -0
  272. package/.agent-src/skills/readme-writing-package/SKILL.md +185 -0
  273. package/.agent-src/skills/receiving-code-review/SKILL.md +190 -0
  274. package/.agent-src/skills/refine-ticket/SKILL.md +310 -0
  275. package/.agent-src/skills/refine-ticket/detection-map.yml +124 -0
  276. package/.agent-src/skills/refine-ticket/evals/output-schema.yml +16 -0
  277. package/.agent-src/skills/refine-ticket/evals/triggers.json +16 -0
  278. package/.agent-src/skills/requesting-code-review/SKILL.md +199 -0
  279. package/.agent-src/skills/review-routing/SKILL.md +195 -0
  280. package/.agent-src/skills/roadmap-management/SKILL.md +303 -0
  281. package/.agent-src/skills/rtk-output-filtering/SKILL.md +184 -0
  282. package/.agent-src/skills/rule-writing/SKILL.md +148 -0
  283. package/.agent-src/skills/security/SKILL.md +79 -0
  284. package/.agent-src/skills/security-audit/SKILL.md +123 -0
  285. package/.agent-src/skills/sentry-integration/SKILL.md +170 -0
  286. package/.agent-src/skills/sequential-thinking/SKILL.md +158 -0
  287. package/.agent-src/skills/skill-improvement-pipeline/SKILL.md +155 -0
  288. package/.agent-src/skills/skill-management/SKILL.md +121 -0
  289. package/.agent-src/skills/skill-reviewer/SKILL.md +218 -0
  290. package/.agent-src/skills/skill-writing/SKILL.md +291 -0
  291. package/.agent-src/skills/skill-writing/evals/triggers.json +16 -0
  292. package/.agent-src/skills/sql-writing/SKILL.md +74 -0
  293. package/.agent-src/skills/subagent-orchestration/SKILL.md +190 -0
  294. package/.agent-src/skills/systematic-debugging/SKILL.md +244 -0
  295. package/.agent-src/skills/technical-specification/SKILL.md +185 -0
  296. package/.agent-src/skills/terraform/SKILL.md +137 -0
  297. package/.agent-src/skills/terragrunt/SKILL.md +217 -0
  298. package/.agent-src/skills/test-driven-development/SKILL.md +252 -0
  299. package/.agent-src/skills/test-performance/SKILL.md +172 -0
  300. package/.agent-src/skills/threat-modeling/SKILL.md +189 -0
  301. package/.agent-src/skills/traefik/SKILL.md +319 -0
  302. package/.agent-src/skills/universal-project-analysis/SKILL.md +179 -0
  303. package/.agent-src/skills/upstream-contribute/SKILL.md +255 -0
  304. package/.agent-src/skills/using-git-worktrees/SKILL.md +148 -0
  305. package/.agent-src/skills/validate-feature-fit/SKILL.md +113 -0
  306. package/.agent-src/skills/verify-before-complete/SKILL.md +188 -0
  307. package/.agent-src/skills/websocket/SKILL.md +75 -0
  308. package/.agent-src/templates/AGENTS.md +146 -0
  309. package/.agent-src/templates/agent-settings.md +256 -0
  310. package/.agent-src/templates/agents/.gitattributes.fragment +16 -0
  311. package/.agent-src/templates/agents/agent-project-settings.example.yml +138 -0
  312. package/.agent-src/templates/agents/memory/architecture-decisions.example.yml +95 -0
  313. package/.agent-src/templates/agents/memory/domain-invariants.example.yml +80 -0
  314. package/.agent-src/templates/agents/memory/historical-patterns.example.yml +82 -0
  315. package/.agent-src/templates/agents/memory/incident-learnings.example.yml +113 -0
  316. package/.agent-src/templates/agents/memory/ownership.example.yml +75 -0
  317. package/.agent-src/templates/agents/memory/product-rules.example.yml +87 -0
  318. package/.agent-src/templates/agents/proposal.example.md +143 -0
  319. package/.agent-src/templates/command.md +84 -0
  320. package/.agent-src/templates/contexts/auth-model.md +59 -0
  321. package/.agent-src/templates/contexts/data-sensitivity.md +60 -0
  322. package/.agent-src/templates/contexts/deployment-order.md +72 -0
  323. package/.agent-src/templates/contexts/observability.md +64 -0
  324. package/.agent-src/templates/contexts/tenant-boundaries.md +68 -0
  325. package/.agent-src/templates/contexts.md +116 -0
  326. package/.agent-src/templates/copilot-instructions.md +115 -0
  327. package/.agent-src/templates/features.md +125 -0
  328. package/.agent-src/templates/github-workflows/memory-hygiene.yml +133 -0
  329. package/.agent-src/templates/github-workflows/pr-risk-review.yml +123 -0
  330. package/.agent-src/templates/github-workflows/proposal-drift.yml +118 -0
  331. package/.agent-src/templates/overrides/command.md +24 -0
  332. package/.agent-src/templates/overrides/guideline.md +21 -0
  333. package/.agent-src/templates/overrides/rule.md +19 -0
  334. package/.agent-src/templates/overrides/skill.md +24 -0
  335. package/.agent-src/templates/overrides/template.md +21 -0
  336. package/.agent-src/templates/persona.md +99 -0
  337. package/.agent-src/templates/roadmaps.md +109 -0
  338. package/.agent-src/templates/scripts/README.md +195 -0
  339. package/.agent-src/templates/scripts/check_memory.py +283 -0
  340. package/.agent-src/templates/scripts/check_memory_proposal.py +180 -0
  341. package/.agent-src/templates/scripts/historical-bug-patterns.example.yml +84 -0
  342. package/.agent-src/templates/scripts/implement_ticket/__init__.py +57 -0
  343. package/.agent-src/templates/scripts/implement_ticket/__main__.py +9 -0
  344. package/.agent-src/templates/scripts/implement_ticket/cli.py +171 -0
  345. package/.agent-src/templates/scripts/implement_ticket/delivery_state.py +130 -0
  346. package/.agent-src/templates/scripts/implement_ticket/dispatcher.py +134 -0
  347. package/.agent-src/templates/scripts/implement_ticket/persona_policy.py +85 -0
  348. package/.agent-src/templates/scripts/implement_ticket/steps/__init__.py +49 -0
  349. package/.agent-src/templates/scripts/implement_ticket/steps/analyze.py +98 -0
  350. package/.agent-src/templates/scripts/implement_ticket/steps/implement.py +145 -0
  351. package/.agent-src/templates/scripts/implement_ticket/steps/memory.py +136 -0
  352. package/.agent-src/templates/scripts/implement_ticket/steps/plan.py +175 -0
  353. package/.agent-src/templates/scripts/implement_ticket/steps/refine.py +140 -0
  354. package/.agent-src/templates/scripts/implement_ticket/steps/report.py +195 -0
  355. package/.agent-src/templates/scripts/implement_ticket/steps/test.py +180 -0
  356. package/.agent-src/templates/scripts/implement_ticket/steps/verify.py +170 -0
  357. package/.agent-src/templates/scripts/memory_hash.py +75 -0
  358. package/.agent-src/templates/scripts/memory_lookup.py +216 -0
  359. package/.agent-src/templates/scripts/memory_report.py +184 -0
  360. package/.agent-src/templates/scripts/memory_signal.py +167 -0
  361. package/.agent-src/templates/scripts/memory_status.py +156 -0
  362. package/.agent-src/templates/scripts/ownership-map.example.yml +87 -0
  363. package/.agent-src/templates/scripts/pr-risk-config.example.yml +76 -0
  364. package/.agent-src/templates/scripts/pr_review_routing.py +340 -0
  365. package/.agent-src/templates/scripts/pr_risk_review.py +211 -0
  366. package/.agent-src/templates/skill.md +136 -0
  367. package/.augment-plugin/marketplace.json +32 -0
  368. package/.augment-plugin/plugin.json +21 -0
  369. package/.claude-plugin/marketplace.json +119 -0
  370. package/AGENTS.md +121 -0
  371. package/CHANGELOG.md +279 -0
  372. package/CONTRIBUTING.md +176 -0
  373. package/LICENSE +21 -0
  374. package/README.md +357 -0
  375. package/bin/install.php +38 -0
  376. package/composer.json +29 -0
  377. package/config/agent-settings.template.yml +96 -0
  378. package/config/profiles/balanced.ini +10 -0
  379. package/config/profiles/full.ini +10 -0
  380. package/config/profiles/minimal.ini +10 -0
  381. package/docs/architecture.md +144 -0
  382. package/docs/customization.md +88 -0
  383. package/docs/development.md +171 -0
  384. package/docs/getting-started.md +130 -0
  385. package/docs/github-topics.md +84 -0
  386. package/docs/installation.md +376 -0
  387. package/docs/mcp.md +133 -0
  388. package/docs/quality.md +98 -0
  389. package/docs/skills-catalog.md +136 -0
  390. package/docs/troubleshooting.md +167 -0
  391. package/llms.txt +130 -0
  392. package/package.json +31 -0
  393. package/scripts/audit_skill_descriptions.py +168 -0
  394. package/scripts/check_compression.py +221 -0
  395. package/scripts/check_memory.py +341 -0
  396. package/scripts/check_memory_proposal.py +180 -0
  397. package/scripts/check_portability.py +320 -0
  398. package/scripts/check_proposal.py +269 -0
  399. package/scripts/check_references.py +400 -0
  400. package/scripts/ci_summary.py +131 -0
  401. package/scripts/compress.py +671 -0
  402. package/scripts/compress.sh +18 -0
  403. package/scripts/first-run.sh +109 -0
  404. package/scripts/generate_catalog.py +116 -0
  405. package/scripts/install +151 -0
  406. package/scripts/install-hooks.sh +29 -0
  407. package/scripts/install.py +487 -0
  408. package/scripts/install.sh +637 -0
  409. package/scripts/install_anthropic_key.sh +101 -0
  410. package/scripts/inventory_frontmatter.py +164 -0
  411. package/scripts/lint_marketplace.py +142 -0
  412. package/scripts/lint_regression.py +232 -0
  413. package/scripts/mcp_render.py +159 -0
  414. package/scripts/measure_patterns.py +376 -0
  415. package/scripts/memory_hash.py +75 -0
  416. package/scripts/memory_lookup.py +441 -0
  417. package/scripts/memory_report.py +336 -0
  418. package/scripts/memory_signal.py +210 -0
  419. package/scripts/memory_status.py +195 -0
  420. package/scripts/postinstall.sh +60 -0
  421. package/scripts/readme_linter.py +580 -0
  422. package/scripts/refine_ticket_detect.py +623 -0
  423. package/scripts/requirements-evals.txt +7 -0
  424. package/scripts/runtime_dispatcher.py +265 -0
  425. package/scripts/runtime_handler.py +148 -0
  426. package/scripts/runtime_registry.py +166 -0
  427. package/scripts/schemas/command.schema.json +32 -0
  428. package/scripts/schemas/persona.schema.json +42 -0
  429. package/scripts/schemas/rule.schema.json +28 -0
  430. package/scripts/schemas/skill.schema.json +73 -0
  431. package/scripts/setup.sh +230 -0
  432. package/scripts/setup_eval_venv.sh +58 -0
  433. package/scripts/skill_linter.py +2175 -0
  434. package/scripts/skill_trigger_eval.py +651 -0
  435. package/scripts/tool_registry.py +146 -0
  436. package/scripts/tools/__init__.py +1 -0
  437. package/scripts/tools/adapter_errors.py +63 -0
  438. package/scripts/tools/base_adapter.py +91 -0
  439. package/scripts/tools/github_adapter.py +128 -0
  440. package/scripts/tools/jira_adapter.py +115 -0
  441. package/scripts/update_counts.py +147 -0
  442. package/scripts/validate_frontmatter.py +424 -0
  443. package/templates/consumer-settings/README.md +46 -0
  444. package/templates/consumer-settings/augment-settings.json +12 -0
  445. package/templates/consumer-settings/claude-settings.json +9 -0
  446. package/templates/consumer-settings/copilot-settings.json +14 -0
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env python3
2
+ """Detect the agent-memory backend.
3
+
4
+ Single source of truth for whether skills should use the file fallback
5
+ (`scripts/memory_lookup.py`) or route through the optional
6
+ `@event4u/agent-memory` package.
7
+
8
+ Exit codes / statuses:
9
+
10
+ * `absent` — package not installed or CLI not on PATH
11
+ * `misconfigured` — installed but `health()` fails within the timeout
12
+ * `present` — installed, healthy, usable now
13
+
14
+ Result is cached per process under `os.environ["AGENT_MEMORY_STATUS"]`
15
+ and (optionally) under `.agent-memory/status.cache` per session.
16
+
17
+ Usage:
18
+ python3 scripts/memory_status.py # human-readable line
19
+ python3 scripts/memory_status.py --format json # stable JSON
20
+ from scripts.memory_status import status # Python import
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import argparse
26
+ import json
27
+ import os
28
+ import shutil
29
+ import subprocess
30
+ import sys
31
+ import time
32
+ from dataclasses import dataclass, asdict
33
+ from pathlib import Path
34
+ from typing import Literal
35
+
36
+ Status = Literal["absent", "misconfigured", "present"]
37
+
38
+ _CLI_CANDIDATES = ("agent-memory", "agentmem")
39
+ _HEALTH_TIMEOUT_SECONDS = 2.0
40
+ _CACHE_ENV = "AGENT_MEMORY_STATUS"
41
+ _CACHE_FILE = Path(".agent-memory") / "status.cache"
42
+
43
+
44
+ @dataclass
45
+ class Result:
46
+ status: Status
47
+ backend: str # "file" or "package"
48
+ reason: str # short explanation
49
+ elapsed_ms: int # time spent probing (0 if cached)
50
+ cli_path: str = "" # resolved CLI path, if any
51
+
52
+
53
+ def _find_cli() -> str:
54
+ for name in _CLI_CANDIDATES:
55
+ path = shutil.which(name)
56
+ if path:
57
+ return path
58
+ return ""
59
+
60
+
61
+ def _probe_health(cli_path: str) -> tuple[bool, str]:
62
+ """Returns (healthy, reason)."""
63
+ try:
64
+ out = subprocess.run(
65
+ [cli_path, "health"],
66
+ capture_output=True, text=True,
67
+ timeout=_HEALTH_TIMEOUT_SECONDS,
68
+ )
69
+ except subprocess.TimeoutExpired:
70
+ return False, f"health() timed out after {_HEALTH_TIMEOUT_SECONDS}s"
71
+ except FileNotFoundError:
72
+ return False, "CLI vanished between which() and invoke"
73
+ if out.returncode != 0:
74
+ # First line of combined output, capped, for the reason field.
75
+ msg = (out.stderr or out.stdout or "exit != 0").strip().splitlines()
76
+ head = msg[0][:120] if msg else "exit != 0"
77
+ return False, f"health() returned {out.returncode}: {head}"
78
+ return True, "ok"
79
+
80
+
81
+ def _read_cache() -> Result | None:
82
+ cached = os.environ.get(_CACHE_ENV)
83
+ if cached:
84
+ try:
85
+ data = json.loads(cached)
86
+ return Result(**data)
87
+ except (ValueError, TypeError):
88
+ pass
89
+ if _CACHE_FILE.is_file():
90
+ try:
91
+ data = json.loads(_CACHE_FILE.read_text(encoding="utf-8"))
92
+ return Result(**data)
93
+ except (OSError, ValueError, TypeError):
94
+ pass
95
+ return None
96
+
97
+
98
+ def _write_cache(result: Result) -> None:
99
+ payload = json.dumps(asdict(result))
100
+ os.environ[_CACHE_ENV] = payload
101
+ try:
102
+ _CACHE_FILE.parent.mkdir(parents=True, exist_ok=True)
103
+ _CACHE_FILE.write_text(payload, encoding="utf-8")
104
+ except OSError:
105
+ # Best-effort cache; skills MUST still work without it.
106
+ pass
107
+
108
+
109
+ def status(refresh: bool = False) -> Result:
110
+ """Return the cached or freshly-probed backend status.
111
+
112
+ Always returns in well under ``_HEALTH_TIMEOUT_SECONDS`` seconds on
113
+ cache hit; bounded by the timeout on cache miss. Never raises —
114
+ probe failures degrade to ``absent`` / ``misconfigured`` rather than
115
+ surfacing exceptions.
116
+ """
117
+ if not refresh:
118
+ cached = _read_cache()
119
+ if cached is not None:
120
+ cached.elapsed_ms = 0
121
+ return cached
122
+ t0 = time.monotonic()
123
+ cli = _find_cli()
124
+ if not cli:
125
+ result = Result("absent", "file",
126
+ "agent-memory CLI not on PATH", 0)
127
+ else:
128
+ healthy, reason = _probe_health(cli)
129
+ elapsed = int((time.monotonic() - t0) * 1000)
130
+ if healthy:
131
+ result = Result("present", "package", reason, elapsed, cli)
132
+ else:
133
+ result = Result("misconfigured", "file", reason, elapsed, cli)
134
+ _write_cache(result)
135
+ return result
136
+
137
+
138
+ def main() -> int:
139
+ ap = argparse.ArgumentParser(description=__doc__)
140
+ ap.add_argument("--format", choices=["text", "json"], default="text")
141
+ ap.add_argument("--refresh", action="store_true",
142
+ help="Bypass the session cache and probe fresh")
143
+ args = ap.parse_args()
144
+ r = status(refresh=args.refresh)
145
+ if args.format == "json":
146
+ print(json.dumps(asdict(r)))
147
+ else:
148
+ icon = {"present": "✅", "misconfigured": "⚠️", "absent": "ℹ️"}[r.status]
149
+ print(f" {icon} backend={r.backend} status={r.status} "
150
+ f"elapsed={r.elapsed_ms}ms reason={r.reason}")
151
+ # `absent` is a valid operational state, not a failure.
152
+ return 0
153
+
154
+
155
+ if __name__ == "__main__":
156
+ sys.exit(main())
@@ -0,0 +1,87 @@
1
+ # Ownership map — consumed by scripts/pr_review_routing.py
2
+ #
3
+ # Copy this file to `.github/ownership-map.yml` (preferred) or
4
+ # `agents/ownership-map.yml` and adapt the entries to your stack.
5
+ # Omitting the file entirely is fine — routing falls back to the
6
+ # generic role vocabulary from `reviewer-awareness`.
7
+ #
8
+ # First match wins per file. List narrower globs before broader ones.
9
+
10
+ version: 1
11
+ updated: 2026-04-21 # bump when entries change — stale maps warn after 6 months
12
+
13
+ # Applied when no entry matches a changed file. Optional.
14
+ defaults:
15
+ roles: [backend]
16
+
17
+ entries:
18
+ # --- Laravel ---
19
+ - paths:
20
+ - "app/Billing/**"
21
+ - "app/Services/Payment*.php"
22
+ - "database/migrations/*billing*.php"
23
+ roles: [finance-engineering, security]
24
+ focus: "tax calculation + idempotency"
25
+ risk: "monetary correctness — regressions bill real customers"
26
+
27
+ - paths:
28
+ - "app/Http/Middleware/TenantScope.php"
29
+ - "**/Tenant*.php"
30
+ roles: [platform, security]
31
+ focus: "cross-tenant isolation"
32
+ risk: "data leak across customers"
33
+
34
+ - paths:
35
+ - "app/Http/Controllers/Admin/**"
36
+ - "routes/admin.php"
37
+ roles: [platform, security]
38
+ focus: "admin authorization boundary"
39
+
40
+ - paths:
41
+ - "resources/views/**"
42
+ - "**/*.blade.php"
43
+ roles: [frontend]
44
+ focus: "a11y + responsive layout"
45
+
46
+ # --- Symfony ---
47
+ - paths:
48
+ - "src/Controller/Api/**"
49
+ - "src/Security/**"
50
+ roles: [backend, security]
51
+ focus: "authorization + input validation"
52
+
53
+ # --- Node / Next.js ---
54
+ - paths:
55
+ - "app/api/**"
56
+ - "pages/api/**"
57
+ roles: [backend]
58
+ focus: "public endpoint — rate limit + auth"
59
+
60
+ - paths:
61
+ - "components/**"
62
+ - "app/**/*.tsx"
63
+ roles: [frontend]
64
+ focus: "UX + client-state"
65
+
66
+ # --- Infra ---
67
+ - paths:
68
+ - "**/Dockerfile*"
69
+ - "**/docker-compose*.y*ml"
70
+ - "**/terraform/**"
71
+ - ".github/workflows/**"
72
+ roles: [infra, security]
73
+ focus: "rollout + secrets handling"
74
+
75
+ # --- Data ---
76
+ - paths:
77
+ - "**/migrations/**"
78
+ - "**/*.sql"
79
+ roles: [database, backend]
80
+ focus: "index strategy + rollback realism"
81
+
82
+ # --- Docs ---
83
+ - paths:
84
+ - "docs/**"
85
+ - "**/*.md"
86
+ roles: [domain-owner]
87
+ focus: "accuracy — reviewers confirm behavior matches text"
@@ -0,0 +1,76 @@
1
+ # PR risk config — consumed by scripts/pr_risk_review.py
2
+ #
3
+ # Copy this file to `.github/pr-risk-config.yml` and adapt the patterns to
4
+ # your stack. Omitting the file entirely is fine — the script ships with
5
+ # cross-stack defaults (migrations, lockfiles, auth, workflows).
6
+ #
7
+ # Matching uses `fnmatch` with glob syntax:
8
+ # - `**/foo/**` → any `foo/` anywhere in the tree
9
+ # - `composer.lock` → exact match at repo root
10
+ #
11
+ # Levels:
12
+ # - high → lockfiles, auth, migrations, secrets, CI, infra
13
+ # - medium → queues, routes, controllers, models, manifests
14
+ # - anything not matched → low
15
+ #
16
+ # `ignore` removes paths BEFORE classification (docs, changelog, …).
17
+
18
+ patterns:
19
+ high:
20
+ # --- universal ---
21
+ - "**/.env*"
22
+ - "**/secrets/**"
23
+ - ".github/workflows/**"
24
+
25
+ # --- Laravel / Symfony / generic PHP ---
26
+ - "**/database/migrations/**"
27
+ - "**/app/Policies/**"
28
+ - "**/config/auth.php"
29
+ - "**/config/services.php"
30
+ - "composer.lock"
31
+
32
+ # --- Node / Next.js ---
33
+ - "package-lock.json"
34
+ - "pnpm-lock.yaml"
35
+ - "yarn.lock"
36
+ - "**/middleware.ts"
37
+ - "**/app/api/**"
38
+
39
+ # --- Python / Django / Rails ---
40
+ - "poetry.lock"
41
+ - "Gemfile.lock"
42
+ - "**/migrations/*.py"
43
+ - "**/db/migrate/**"
44
+
45
+ # --- infra ---
46
+ - "**/Dockerfile*"
47
+ - "**/docker-compose*.y*ml"
48
+ - "**/terraform/**"
49
+ - "**/*.tf"
50
+
51
+ medium:
52
+ # --- Laravel ---
53
+ - "**/app/Http/Controllers/**"
54
+ - "**/app/Jobs/**"
55
+ - "**/app/Listeners/**"
56
+ - "**/routes/**"
57
+
58
+ # --- Symfony ---
59
+ - "**/src/Controller/**"
60
+ - "**/src/MessageHandler/**"
61
+
62
+ # --- Node / Next.js ---
63
+ - "**/app/**/route.ts"
64
+ - "**/pages/api/**"
65
+
66
+ # --- manifests (non-lock) ---
67
+ - "composer.json"
68
+ - "package.json"
69
+ - "pyproject.toml"
70
+ - "Gemfile"
71
+
72
+ ignore:
73
+ - "**/*.md"
74
+ - "**/CHANGELOG*"
75
+ - "**/docs/**"
76
+ - "**/*.snap"
@@ -0,0 +1,340 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ PR review-routing classifier.
4
+
5
+ Reads changed files between two git refs, resolves reviewer roles from
6
+ `ownership-map.yml`, and matches the diff against
7
+ `historical-bug-patterns.yml`. Emits a Markdown routing block plus a
8
+ single-word severity level (low / medium / high) for downstream CI steps.
9
+
10
+ This classifier is **informational** — it surfaces who should review and
11
+ what regression tests historical patterns demand. It is not a merge gate.
12
+
13
+ Config file formats — see:
14
+ ownership-map.example.yml
15
+ historical-bug-patterns.example.yml
16
+
17
+ Usage:
18
+ python3 pr_review_routing.py \\
19
+ --base <sha> --head <sha> \\
20
+ --output routing-report.md \\
21
+ --level-file routing-level.txt
22
+
23
+ If --ownership-map / --patterns are omitted, the script searches
24
+ `.github/` first and falls back to `agents/` — matching what the
25
+ review-routing-awareness rule and review-routing skill document.
26
+ Missing data files are not an error; the script emits a generic
27
+ fallback block.
28
+
29
+ Exit codes: 0 = success, 2 = invalid arguments, 3 = git/config error.
30
+ """
31
+
32
+ from __future__ import annotations
33
+
34
+ import argparse
35
+ import re
36
+ import subprocess
37
+ import sys
38
+ from dataclasses import dataclass, field
39
+ from datetime import date, datetime
40
+ from functools import lru_cache
41
+ from pathlib import Path
42
+ from typing import Any
43
+
44
+ try:
45
+ import yaml
46
+ except ImportError:
47
+ print("error: pyyaml not installed (pip install pyyaml)", file=sys.stderr)
48
+ sys.exit(3)
49
+
50
+ LEVELS = ("high", "medium", "low")
51
+ STALE_MONTHS = 6
52
+
53
+
54
+ @dataclass
55
+ class OwnershipHit:
56
+ path: str
57
+ roles: list[str]
58
+ focus: str | None
59
+ risk: str | None
60
+
61
+
62
+ @dataclass
63
+ class PatternHit:
64
+ id: str
65
+ label: str
66
+ severity: str
67
+ required_test: str
68
+ references: list[str] = field(default_factory=list)
69
+ matched_files: list[str] = field(default_factory=list)
70
+
71
+
72
+ @lru_cache(maxsize=512)
73
+ def _compile(pattern: str) -> re.Pattern[str]:
74
+ """Translate a gitignore-ish glob to a regex (same semantics as pr_risk_review.py)."""
75
+ out: list[str] = []
76
+ i, n = 0, len(pattern)
77
+ while i < n:
78
+ c = pattern[i]
79
+ if c == "*":
80
+ if i + 1 < n and pattern[i + 1] == "*":
81
+ if i + 2 < n and pattern[i + 2] == "/":
82
+ out.append("(?:.*/)?")
83
+ i += 3
84
+ continue
85
+ if i > 0 and pattern[i - 1] == "/":
86
+ out[-1] = "(?:/.*)?"
87
+ i += 2
88
+ continue
89
+ out.append(".*")
90
+ i += 2
91
+ continue
92
+ out.append("[^/]*")
93
+ elif c == "?":
94
+ out.append("[^/]")
95
+ elif c in r".^$+{}()[]|\\":
96
+ out.append(re.escape(c))
97
+ else:
98
+ out.append(c)
99
+ i += 1
100
+ return re.compile("^" + "".join(out) + "$")
101
+
102
+
103
+ def _match(path: str, pattern: str) -> bool:
104
+ return bool(_compile(pattern).match(path))
105
+
106
+
107
+ def _load_yaml(path: Path | None) -> dict[str, Any] | None:
108
+ if path is None or not path.exists():
109
+ return None
110
+ try:
111
+ data = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
112
+ except yaml.YAMLError as exc:
113
+ print(f"error: {path} parse failed: {exc}", file=sys.stderr)
114
+ sys.exit(3)
115
+ if data.get("version") != 1:
116
+ print(f"error: {path} missing or unsupported 'version: 1'", file=sys.stderr)
117
+ sys.exit(3)
118
+ return data
119
+
120
+
121
+ def changed_files(base: str, head: str) -> list[str]:
122
+ try:
123
+ out = subprocess.run(
124
+ ["git", "diff", "--name-only", f"{base}...{head}"],
125
+ check=True, capture_output=True, text=True,
126
+ )
127
+ except subprocess.CalledProcessError as exc:
128
+ print(f"error: git diff failed: {exc.stderr}", file=sys.stderr)
129
+ sys.exit(3)
130
+ return [line for line in out.stdout.splitlines() if line.strip()]
131
+
132
+
133
+ def match_ownership(files: list[str], cfg: dict[str, Any] | None) -> tuple[list[OwnershipHit], list[str], bool]:
134
+ """Return per-file hits, fallback roles, and a stale flag."""
135
+ if not cfg:
136
+ return [], [], False
137
+
138
+ entries = cfg.get("entries", []) or []
139
+ defaults = (cfg.get("defaults") or {}).get("roles", []) or []
140
+
141
+ hits: list[OwnershipHit] = []
142
+ for path in files:
143
+ for entry in entries:
144
+ globs = entry.get("paths", []) or []
145
+ if any(_match(path, g) for g in globs):
146
+ hits.append(OwnershipHit(
147
+ path=path,
148
+ roles=list(entry.get("roles", []) or []),
149
+ focus=entry.get("focus"),
150
+ risk=entry.get("risk"),
151
+ ))
152
+ break
153
+
154
+ stale = False
155
+ updated = cfg.get("updated")
156
+ if isinstance(updated, (date, datetime)):
157
+ updated_date = updated.date() if isinstance(updated, datetime) else updated
158
+ months = (date.today().year - updated_date.year) * 12 + (date.today().month - updated_date.month)
159
+ stale = months >= STALE_MONTHS
160
+
161
+ return hits, defaults, stale
162
+
163
+
164
+ def match_patterns(files: list[str], cfg: dict[str, Any] | None) -> list[PatternHit]:
165
+ if not cfg:
166
+ return []
167
+ result: list[PatternHit] = []
168
+ for pattern in cfg.get("patterns", []) or []:
169
+ globs = pattern.get("paths", []) or []
170
+ matched = [f for f in files if any(_match(f, g) for g in globs)]
171
+ if not matched:
172
+ continue
173
+ result.append(PatternHit(
174
+ id=str(pattern.get("id", "unknown")),
175
+ label=str(pattern.get("label", pattern.get("id", "unknown"))),
176
+ severity=str(pattern.get("severity", "medium")),
177
+ required_test=str(pattern.get("required_test", "")),
178
+ references=list(pattern.get("references", []) or []),
179
+ matched_files=matched,
180
+ ))
181
+ return result
182
+
183
+
184
+ def overall_level(patterns: list[PatternHit]) -> str:
185
+ if any(p.severity == "high" for p in patterns):
186
+ return "high"
187
+ if any(p.severity == "medium" for p in patterns):
188
+ return "medium"
189
+ return "low"
190
+
191
+
192
+ def _merge_roles(ownership: list[OwnershipHit], fallback: list[str]) -> list[tuple[str, list[str], list[str]]]:
193
+ """Return [(role, focus_notes, files), …] ordered by hit count then name."""
194
+ by_role: dict[str, tuple[set[str], set[str]]] = {}
195
+ for hit in ownership:
196
+ for role in hit.roles:
197
+ notes, files = by_role.setdefault(role, (set(), set()))
198
+ if hit.focus:
199
+ notes.add(hit.focus)
200
+ files.add(hit.path)
201
+ if not by_role and fallback:
202
+ for role in fallback:
203
+ by_role.setdefault(role, (set(), set()))
204
+ ordered = sorted(by_role.items(), key=lambda kv: (-len(kv[1][1]), kv[0]))
205
+ return [(role, sorted(notes), sorted(files)) for role, (notes, files) in ordered]
206
+
207
+
208
+ def render(
209
+ level: str,
210
+ ownership: list[OwnershipHit],
211
+ fallback: list[str],
212
+ stale: bool,
213
+ patterns: list[PatternHit],
214
+ total: int,
215
+ have_ownership_file: bool,
216
+ have_patterns_file: bool,
217
+ ) -> str:
218
+ emoji = {"high": "🔴", "medium": "🟡", "low": "🟢"}[level]
219
+ lines = [
220
+ f"## {emoji} Review Routing: **{level}**",
221
+ "",
222
+ f"_{total} changed file(s), {len(patterns)} historical pattern(s) matched._",
223
+ "",
224
+ ]
225
+
226
+ roles = _merge_roles(ownership, fallback)
227
+ lines.append("### Suggested reviewers (role-based)")
228
+ if not roles:
229
+ lines.append("- No ownership map and no fallback roles configured.")
230
+ lines.append(" Fall back to generic reviewer selection per `reviewer-awareness`.")
231
+ else:
232
+ labels = ["primary", "secondary"] + [f"additional #{i}" for i in range(1, 20)]
233
+ for (role, notes, files), label in zip(roles, labels):
234
+ focus = " / ".join(notes) if notes else "anchored in diff"
235
+ lines.append(f"- **{label}**: `{role}` — focus: {focus}")
236
+ if files:
237
+ preview = ", ".join(f"`{f}`" for f in files[:3])
238
+ suffix = f" (+{len(files) - 3} more)" if len(files) > 3 else ""
239
+ lines.append(f" - files: {preview}{suffix}")
240
+ lines.append("")
241
+
242
+ if patterns:
243
+ lines.append("### Historical patterns matched")
244
+ order = {"high": 0, "medium": 1, "low": 2}
245
+ for p in sorted(patterns, key=lambda x: order.get(x.severity, 9)):
246
+ bullet = {"high": "🔴", "medium": "🟡", "low": "🟢"}.get(p.severity, "•")
247
+ lines.append(f"- {bullet} **{p.id}** — {p.label}")
248
+ if p.required_test:
249
+ lines.append(f" - required test: {p.required_test}")
250
+ for ref in p.references:
251
+ lines.append(f" - ref: {ref}")
252
+ lines.append("")
253
+
254
+ if stale:
255
+ lines += [
256
+ "> ⚠️ Ownership map last updated > 6 months ago — treat roles as hints.",
257
+ "",
258
+ ]
259
+
260
+ source_bits = []
261
+ if have_ownership_file:
262
+ source_bits.append("ownership-map.yml")
263
+ if have_patterns_file:
264
+ source_bits.append("historical-bug-patterns.yml")
265
+ source = " + ".join(source_bits) if source_bits else "no project data — generic fallback"
266
+ lines.append(f"_Data source: {source}. Routing is informational — merge is not blocked._")
267
+
268
+ return "\n".join(lines) + "\n"
269
+
270
+
271
+ OWNERSHIP_CANDIDATES = (
272
+ Path(".github/ownership-map.yml"),
273
+ Path("agents/ownership-map.yml"),
274
+ )
275
+ PATTERN_CANDIDATES = (
276
+ Path(".github/historical-bug-patterns.yml"),
277
+ Path("agents/historical-bug-patterns.yml"),
278
+ )
279
+
280
+
281
+ def _first_existing(candidates: tuple[Path, ...]) -> Path | None:
282
+ for path in candidates:
283
+ if path.is_file():
284
+ return path
285
+ return None
286
+
287
+
288
+ def main() -> int:
289
+ parser = argparse.ArgumentParser()
290
+ parser.add_argument("--base", required=True)
291
+ parser.add_argument("--head", required=True)
292
+ parser.add_argument(
293
+ "--ownership-map",
294
+ type=Path,
295
+ default=None,
296
+ help=(
297
+ "Path to ownership-map.yml. If omitted, searches "
298
+ ".github/ownership-map.yml then agents/ownership-map.yml."
299
+ ),
300
+ )
301
+ parser.add_argument(
302
+ "--patterns",
303
+ type=Path,
304
+ default=None,
305
+ help=(
306
+ "Path to historical-bug-patterns.yml. If omitted, searches "
307
+ ".github/historical-bug-patterns.yml then "
308
+ "agents/historical-bug-patterns.yml."
309
+ ),
310
+ )
311
+ parser.add_argument("--output", type=Path, required=True)
312
+ parser.add_argument("--level-file", type=Path, required=True)
313
+ args = parser.parse_args()
314
+
315
+ ownership_path = args.ownership_map or _first_existing(OWNERSHIP_CANDIDATES)
316
+ patterns_path = args.patterns or _first_existing(PATTERN_CANDIDATES)
317
+
318
+ ownership_cfg = _load_yaml(ownership_path)
319
+ patterns_cfg = _load_yaml(patterns_path)
320
+
321
+ files = changed_files(args.base, args.head)
322
+ ownership_hits, fallback_roles, stale = match_ownership(files, ownership_cfg)
323
+ pattern_hits = match_patterns(files, patterns_cfg)
324
+ level = overall_level(pattern_hits)
325
+
326
+ args.output.write_text(
327
+ render(
328
+ level, ownership_hits, fallback_roles, stale, pattern_hits,
329
+ total=len(files),
330
+ have_ownership_file=ownership_cfg is not None,
331
+ have_patterns_file=patterns_cfg is not None,
332
+ ),
333
+ encoding="utf-8",
334
+ )
335
+ args.level_file.write_text(level, encoding="utf-8")
336
+ return 0
337
+
338
+
339
+ if __name__ == "__main__":
340
+ sys.exit(main())