@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,320 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Portability checker for agent-config packages.
4
+
5
+ Scans .agent-src/ and .agent-src.uncompressed/ for project-specific references
6
+ that violate package portability (the package must work in ANY project).
7
+
8
+ Allowed: references to packages/libraries (laravel, pest, phpstan, etc.)
9
+ Forbidden: references to specific projects, repos, domains, teams, customers
10
+
11
+ Exit codes: 0 = clean, 1 = violations found, 3 = internal error
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import argparse
17
+ import json
18
+ import re
19
+ import sys
20
+ from dataclasses import dataclass, asdict
21
+ from pathlib import Path
22
+ from typing import List, Literal
23
+
24
+ Severity = Literal["error", "warning"]
25
+
26
+
27
+ @dataclass
28
+ class Violation:
29
+ file: str
30
+ line: int
31
+ match: str
32
+ pattern_name: str
33
+ severity: Severity
34
+ context: str # the full line for review
35
+
36
+
37
+ # ── Auto-detected project identifiers ────────────────────────────────────
38
+ # Instead of hardcoding project names, we auto-detect them from:
39
+ # 1. Git remote URL (org name, repo name)
40
+ # 2. composer.json / package.json (package name)
41
+ # 3. Directory name (workspace root)
42
+ # This makes the checker portable across ANY project.
43
+
44
+
45
+ def _detect_project_identifiers(root: Path) -> set[str]:
46
+ """Auto-detect project-specific identifiers from the project context."""
47
+ identifiers: set[str] = set()
48
+
49
+ # 1. Git remote URL
50
+ try:
51
+ import subprocess
52
+ result = subprocess.run(
53
+ ["git", "remote", "get-url", "origin"],
54
+ capture_output=True, text=True, cwd=root, timeout=5,
55
+ )
56
+ if result.returncode == 0:
57
+ url = result.stdout.strip()
58
+ # Extract from SSH: git@github.com:org/repo.git
59
+ # Extract from HTTPS: https://github.com/org/repo.git
60
+ parts = re.split(r"[:/]", url.replace(".git", ""))
61
+ # Last 2 parts are typically org and repo
62
+ for part in parts[-2:]:
63
+ part = part.strip()
64
+ if part and part not in ("git", "github.com", "gitlab.com", "bitbucket.org", "com"):
65
+ identifiers.add(part)
66
+ # Also add sub-parts split by hyphen (e.g., "event4u-app" → "event4u")
67
+ for sub in part.split("-"):
68
+ if len(sub) >= 3:
69
+ identifiers.add(sub)
70
+ except (FileNotFoundError, subprocess.TimeoutExpired):
71
+ pass
72
+
73
+ # 2. composer.json
74
+ composer = root / "composer.json"
75
+ if composer.exists():
76
+ try:
77
+ data = json.loads(composer.read_text(encoding="utf-8"))
78
+ name = data.get("name", "")
79
+ if "/" in name:
80
+ vendor, pkg = name.split("/", 1)
81
+ identifiers.add(vendor)
82
+ identifiers.add(pkg)
83
+ for sub in pkg.split("-"):
84
+ if len(sub) >= 3:
85
+ identifiers.add(sub)
86
+ except (json.JSONDecodeError, ValueError):
87
+ pass
88
+
89
+ # 3. package.json
90
+ pkgjson = root / "package.json"
91
+ if pkgjson.exists():
92
+ try:
93
+ data = json.loads(pkgjson.read_text(encoding="utf-8"))
94
+ name = data.get("name", "").lstrip("@")
95
+ if "/" in name:
96
+ scope, pkg = name.split("/", 1)
97
+ identifiers.add(scope)
98
+ identifiers.add(pkg)
99
+ elif name:
100
+ identifiers.add(name)
101
+ except (json.JSONDecodeError, ValueError):
102
+ pass
103
+
104
+ # 4. Directory name (parent directories of .agent-src/)
105
+ augment_dir = root / ".agent-src"
106
+ if augment_dir.exists():
107
+ dir_name = root.name
108
+ if len(dir_name) >= 3:
109
+ identifiers.add(dir_name)
110
+ # Also check parent (often the org/group directory)
111
+ parent_name = root.parent.name
112
+ if len(parent_name) >= 3 and parent_name not in ("projects", "src", "code", "repos", "home", "Users"):
113
+ identifiers.add(parent_name)
114
+
115
+ # Filter out generic terms that would cause false positives
116
+ generic = {"app", "api", "web", "src", "lib", "pkg", "core", "main", "test",
117
+ "config", "agent", "tools", "packages", "server", "client", "common"}
118
+ identifiers -= generic
119
+
120
+ return identifiers
121
+
122
+
123
+ def _build_patterns(root: Path) -> tuple[list[tuple[re.Pattern, str, Severity]], list[str]]:
124
+ """Build regex patterns from auto-detected project identifiers."""
125
+ identifiers = _detect_project_identifiers(root)
126
+ patterns: list[tuple[re.Pattern, str, Severity]] = []
127
+ detected: list[str] = sorted(identifiers)
128
+
129
+ for ident in identifiers:
130
+ escaped = re.escape(ident)
131
+ # Word boundary match (case-insensitive)
132
+ patterns.append((re.compile(rf"\b{escaped}\b", re.IGNORECASE), "project-name", "error"))
133
+ # As prefix with separator (db names, container names, env vars)
134
+ patterns.append((re.compile(rf"\b{escaped}[-_]\w+", re.IGNORECASE), "project-derivative", "warning"))
135
+ # Domain patterns (name.tld)
136
+ patterns.append((re.compile(rf"\b{escaped}\.\w{{2,6}}\b", re.IGNORECASE), "project-domain", "error"))
137
+ # GitHub org/user patterns
138
+ patterns.append((re.compile(rf"@{escaped}\b", re.IGNORECASE), "project-org", "error"))
139
+
140
+ return patterns, detected
141
+
142
+ # ── Allowed patterns (NOT violations even if they match above) ──────────
143
+ # Generic Laravel/framework patterns that are NOT project-specific
144
+ ALLOWLIST = [
145
+ r"\.agent-settings\.yml", # config file reference (YAML)
146
+ r"\.agent-settings\b", # legacy reference (key=value, migration window)
147
+ r"agents/overrides/", # override system
148
+ r"app/Modules/", # generic Laravel module pattern
149
+ r"`App\\", # namespace pattern explanation
150
+ r"app/Http/Controllers/", # generic Laravel path pattern
151
+ r"app/Repositories/", # generic pattern in skills/guidelines
152
+ r"\.module-template", # module template
153
+ r"ModuleServiceProvider", # generic module concept
154
+ r"app/Services/MyService", # example placeholder
155
+ r"app/Models/\{", # template placeholder like {Model}
156
+ r"app/Services/\{", # template placeholder like {Service}
157
+ r"agent-config", # refers to the package concept, not a specific project
158
+ r"shared.*package", # "shared package" concept
159
+ r"package repository", # "package repository" concept
160
+ ]
161
+
162
+ # Directories to scan (only package files, not project-specific agents/)
163
+ SCAN_DIRS = [".agent-src", ".agent-src.uncompressed"]
164
+
165
+ # Additional root-level files shipped by the package that must also stay
166
+ # portable. These are read by agents working on the package itself and —
167
+ # for AGENTS.md and copilot-instructions.md — serve as meta docs about
168
+ # the package. They must never leak consumer-project identifiers.
169
+ SCAN_ROOT_FILES = ["AGENTS.md", ".github/copilot-instructions.md"]
170
+
171
+ # Skip these subdirectories (they ARE allowed to be project-specific)
172
+ SKIP_PATTERNS = [
173
+ "agents/", # project-specific by design
174
+ ".agent-settings.yml", # project config (YAML)
175
+ ".agent-settings", # legacy project config (migration window)
176
+ ]
177
+
178
+ # Optional blocklist of identifiers from past/adjacent projects that must
179
+ # never appear anywhere in the shared package, even when the auto-detector
180
+ # would not flag them (e.g. because the repo was renamed or split). The
181
+ # list is loaded from the environment variable AGENT_CONFIG_BLOCKLIST
182
+ # (comma-separated) so the package itself ships without hardcoding any
183
+ # consumer-specific names. Maintainers of a fork with legacy debt can set
184
+ # the variable in their CI to catch regressions.
185
+ def _load_forbidden_identifiers() -> list[str]:
186
+ raw = __import__("os").environ.get("AGENT_CONFIG_BLOCKLIST", "")
187
+ return [part.strip() for part in raw.split(",") if part.strip()]
188
+
189
+
190
+ FORBIDDEN_IDENTIFIERS: list[str] = _load_forbidden_identifiers()
191
+
192
+
193
+ def _compile_patterns(root: Path) -> tuple[list[tuple[re.Pattern, str, Severity]], list[str]]:
194
+ """Build patterns from auto-detected project identifiers."""
195
+ return _build_patterns(root)
196
+
197
+
198
+ def _compile_forbidden_patterns() -> list[tuple[re.Pattern, str, Severity]]:
199
+ """Build regex patterns for hardcoded FORBIDDEN_IDENTIFIERS.
200
+
201
+ These apply to every scanned file regardless of auto-detection. They
202
+ catch leakage from renamed or adjacent projects.
203
+ """
204
+ patterns: list[tuple[re.Pattern, str, Severity]] = []
205
+ for ident in FORBIDDEN_IDENTIFIERS:
206
+ escaped = re.escape(ident)
207
+ patterns.append((re.compile(rf"\b{escaped}\b", re.IGNORECASE), "forbidden-identifier", "error"))
208
+ return patterns
209
+
210
+
211
+ def _compile_allowlist() -> list[re.Pattern]:
212
+ return [re.compile(p) for p in ALLOWLIST]
213
+
214
+
215
+ def check_file(filepath: Path, patterns: list, allowlist: list) -> List[Violation]:
216
+ violations: List[Violation] = []
217
+ try:
218
+ lines = filepath.read_text(encoding="utf-8").splitlines()
219
+ except Exception:
220
+ return violations
221
+
222
+ in_code_block = False
223
+ for i, line in enumerate(lines, 1):
224
+ stripped = line.strip()
225
+
226
+ # Skip YAML frontmatter
227
+ if i <= 10 and stripped == "---":
228
+ continue
229
+
230
+ # Track code blocks
231
+ if stripped.startswith("```"):
232
+ in_code_block = not in_code_block
233
+ continue
234
+ if in_code_block:
235
+ continue
236
+
237
+ # Check allowlist first
238
+ if any(a.search(line) for a in allowlist):
239
+ continue
240
+
241
+ for pattern, name, severity in patterns:
242
+ for m in pattern.finditer(line):
243
+ violations.append(Violation(
244
+ file=str(filepath), line=i, match=m.group(0),
245
+ pattern_name=name, severity=severity, context=stripped,
246
+ ))
247
+
248
+ return violations
249
+
250
+
251
+ def scan_all(root: Path) -> tuple[List[Violation], list[str]]:
252
+ """Scan all package files for portability violations. Returns (violations, detected_identifiers).
253
+
254
+ Scanning has two layers:
255
+ 1. Auto-detected identifiers — applied to `.agent-src/` and
256
+ `.agent-src.uncompressed/` only. The package's own root AGENTS.md and
257
+ copilot-instructions.md are meta docs ABOUT the package, so the
258
+ detector's own hits (e.g. "event4u", "agent-config") are expected.
259
+ 2. Optional FORBIDDEN_IDENTIFIERS from AGENT_CONFIG_BLOCKLIST —
260
+ applied to every scanned file, including the root files. Catches
261
+ leakage from renamed or adjacent projects in downstream forks.
262
+ """
263
+ patterns, detected = _compile_patterns(root)
264
+ forbidden = _compile_forbidden_patterns()
265
+ allowlist = _compile_allowlist()
266
+ violations: List[Violation] = []
267
+
268
+ # Layer 1 + 2: full package content
269
+ for scan_dir in SCAN_DIRS:
270
+ d = root / scan_dir
271
+ if not d.exists():
272
+ continue
273
+ for f in sorted(d.rglob("*.md")):
274
+ violations.extend(check_file(f, patterns + forbidden, allowlist))
275
+
276
+ # Layer 2 only: root files (auto-detected identifiers are expected here)
277
+ for rel in SCAN_ROOT_FILES:
278
+ f = root / rel
279
+ if f.is_file():
280
+ violations.extend(check_file(f, forbidden, allowlist))
281
+
282
+ return violations, detected
283
+
284
+
285
+
286
+ def format_text(violations: List[Violation], detected: list[str]) -> str:
287
+ header = f"Auto-detected identifiers: {', '.join(detected)}\n" if detected else ""
288
+ if not violations:
289
+ return f"{header}✅ No portability violations found."
290
+ lines = [f"{header}❌ Found {len(violations)} portability violation(s):\n"]
291
+ for v in violations:
292
+ icon = "🔴" if v.severity == "error" else "🟡"
293
+ lines.append(f" {icon} {v.file}:{v.line} — [{v.pattern_name}] `{v.match}`")
294
+ lines.append(f" {v.context}")
295
+ return "\n".join(lines)
296
+
297
+
298
+ def main() -> int:
299
+ parser = argparse.ArgumentParser(description="Check agent-config package portability")
300
+ parser.add_argument("--format", choices=["text", "json"], default="text")
301
+ parser.add_argument("--root", type=Path, default=Path("."), help="Repository root")
302
+ args = parser.parse_args()
303
+
304
+ try:
305
+ violations, detected = scan_all(args.root)
306
+ except Exception as e:
307
+ print(f"Internal error: {e}", file=sys.stderr)
308
+ return 3
309
+
310
+ if args.format == "json":
311
+ payload = {"detected": detected, "violations": [asdict(v) for v in violations]}
312
+ print(json.dumps(payload, indent=2))
313
+ else:
314
+ print(format_text(violations, detected))
315
+
316
+ return 1 if violations else 0
317
+
318
+
319
+ if __name__ == "__main__":
320
+ sys.exit(main())
@@ -0,0 +1,269 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Stage-4 gate for curated self-improvement proposals.
4
+
5
+ Validates a proposal doc produced by the pipeline documented in
6
+ `guidelines/agent-infra/self-improvement-pipeline.md`. A proposal is
7
+ only eligible to advance to `stage: gated` if every check here passes.
8
+
9
+ Gate checks (all hard):
10
+ 1. Frontmatter complete — proposal_id, type, scope, stage, author,
11
+ created, last_updated.
12
+ 2. Type / scope / stage values are from the documented vocabulary.
13
+ 3. Evidence block — ≥2 entries under `evidence:`, each with distinct
14
+ `ref` value. At least two distinct hosts/repos/paths.
15
+ 4. No "TODO" / "TBD" / "xxx" markers in the draft body.
16
+ 5. Required sections all present (1..10 per template).
17
+ 6. Success signal — Section 7 has a concrete metric, target, and
18
+ evaluation date.
19
+
20
+ Exit codes: 0 = pass, 1 = gate failure, 2 = PyYAML missing, 3 = internal error.
21
+
22
+ Usage:
23
+ python3 scripts/check_proposal.py agents/proposals/my-proposal.md
24
+ python3 scripts/check_proposal.py --format json path/to.md
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import argparse
30
+ import json
31
+ import re
32
+ import sys
33
+ from dataclasses import dataclass, asdict
34
+ from pathlib import Path
35
+ from typing import List, Literal, Tuple
36
+ from urllib.parse import urlparse
37
+
38
+ Severity = Literal["error", "warning"]
39
+
40
+ REQUIRED_FRONTMATTER = {
41
+ "proposal_id", "type", "scope", "stage",
42
+ "author", "created", "last_updated",
43
+ }
44
+ VALID_TYPES = {"rule", "skill", "command", "guideline"}
45
+ VALID_SCOPES = {"project", "package"}
46
+ VALID_STAGES = {"captured", "classified", "proposed", "gated", "upstream"}
47
+ REQUIRED_SECTIONS: List[Tuple[str, str]] = [
48
+ (r"^##\s+1\.\s+Learning\b", "1. Learning"),
49
+ (r"^##\s+2\.\s+Classification\b", "2. Classification"),
50
+ (r"^##\s+3\.\s+Evidence\b", "3. Evidence"),
51
+ (r"^##\s+4\.\s+Proposed artefact\b", "4. Proposed artefact"),
52
+ (r"^##\s+5\.\s+Quality gate expectations\b", "5. Quality gate expectations"),
53
+ (r"^##\s+6\.\s+Replacement justification\b", "6. Replacement justification"),
54
+ (r"^##\s+7\.\s+Success signal\b", "7. Success signal"),
55
+ (r"^##\s+8\.\s+Risks and alternatives rejected\b", "8. Risks and alternatives rejected"),
56
+ (r"^##\s+9\.\s+Gate verdict\b", "9. Gate verdict"),
57
+ (r"^##\s+10\.\s+Upstream PR\b", "10. Upstream PR"),
58
+ ]
59
+ BAD_MARKERS = re.compile(r"\b(TODO|TBD|FIXME|XXX)\b")
60
+ FRONTMATTER_PATTERN = re.compile(r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
61
+
62
+
63
+ @dataclass
64
+ class Finding:
65
+ severity: Severity
66
+ section: str
67
+ message: str
68
+
69
+
70
+ def _load_frontmatter(text: str) -> dict:
71
+ match = FRONTMATTER_PATTERN.match(text)
72
+ if not match:
73
+ return {}
74
+ try:
75
+ import yaml
76
+ except ImportError:
77
+ print("error: PyYAML not installed. Run `pip install pyyaml`.", file=sys.stderr)
78
+ sys.exit(2)
79
+ return yaml.safe_load(match.group(1)) or {}
80
+
81
+
82
+ def _body_after_frontmatter(text: str) -> str:
83
+ match = FRONTMATTER_PATTERN.match(text)
84
+ return text[match.end():] if match else text
85
+
86
+
87
+ def _check_frontmatter(fm: dict, findings: List[Finding]):
88
+ missing = REQUIRED_FRONTMATTER - set(fm.keys())
89
+ for key in sorted(missing):
90
+ findings.append(Finding("error", "frontmatter", f"missing: {key}"))
91
+ if fm.get("type") and fm["type"] not in VALID_TYPES:
92
+ findings.append(Finding("error", "frontmatter",
93
+ f"invalid type '{fm['type']}'"))
94
+ if fm.get("scope") and fm["scope"] not in VALID_SCOPES:
95
+ findings.append(Finding("error", "frontmatter",
96
+ f"invalid scope '{fm['scope']}'"))
97
+ if fm.get("stage") and fm["stage"] not in VALID_STAGES:
98
+ findings.append(Finding("error", "frontmatter",
99
+ f"invalid stage '{fm['stage']}'"))
100
+
101
+
102
+ def _check_sections(body: str, findings: List[Finding]):
103
+ for pattern, name in REQUIRED_SECTIONS:
104
+ if not re.search(pattern, body, flags=re.MULTILINE):
105
+ findings.append(Finding("error", "sections", f"missing section: {name}"))
106
+
107
+
108
+ def _extract_evidence_refs(body: str) -> List[str]:
109
+ refs: List[str] = []
110
+ ev_match = re.search(r"^##\s+3\.\s+Evidence\b(.+?)(?=^##\s)", body,
111
+ flags=re.DOTALL | re.MULTILINE)
112
+ if not ev_match:
113
+ return refs
114
+ for line in ev_match.group(1).splitlines():
115
+ m = re.match(r"\s*-?\s*ref:\s*(\S+)", line)
116
+ if m:
117
+ refs.append(m.group(1).strip())
118
+ return refs
119
+
120
+
121
+ def _check_evidence(body: str, findings: List[Finding]):
122
+ refs = _extract_evidence_refs(body)
123
+ if len(refs) < 2:
124
+ findings.append(Finding("error", "evidence",
125
+ f"need ≥2 evidence refs, found {len(refs)}"))
126
+ return
127
+ # Independence — two distinct hosts OR two distinct paths.
128
+ hosts = {urlparse(r).netloc or r for r in refs}
129
+ paths = {urlparse(r).path.rsplit("/", 2)[-2:] and urlparse(r).path for r in refs}
130
+ if len(hosts) < 2 and len({tuple(urlparse(r).path.strip("/").split("/")[:2]) for r in refs}) < 2:
131
+ findings.append(Finding("warning", "evidence",
132
+ "evidence refs look similar — verify independence"))
133
+
134
+
135
+ def _strip_html_comments(text: str) -> str:
136
+ return re.sub(r"<!--.*?-->", "", text, flags=re.DOTALL)
137
+
138
+
139
+ def _check_markers(body: str, findings: List[Finding]):
140
+ stripped = _strip_html_comments(body)
141
+ for line_no, line in enumerate(stripped.splitlines(), 1):
142
+ if line.lstrip().startswith("//"):
143
+ continue
144
+ if BAD_MARKERS.search(line):
145
+ findings.append(Finding("error", "markers",
146
+ f"draft placeholder on line {line_no}: {line.strip()[:60]}"))
147
+
148
+
149
+ def _check_success_signal(body: str, findings: List[Finding]):
150
+ m = re.search(r"^##\s+7\.\s+Success signal\b(.+?)(?=^##\s)", body,
151
+ flags=re.DOTALL | re.MULTILINE)
152
+ if not m:
153
+ return
154
+ sect = m.group(1)
155
+ for label in ("Metric:", "Baseline:", "Target:", "Evaluation date:"):
156
+ if label not in sect:
157
+ findings.append(Finding("error", "success-signal",
158
+ f"missing '{label}' entry"))
159
+
160
+
161
+ def _check_originating_project(body: str, fm: dict,
162
+ findings: List[Finding]):
163
+ """Section 10 must name the originating project once stage=upstream.
164
+
165
+ `originating_project` is metadata only — the linter does NOT check
166
+ for specific identifiers. It only ensures the slot is filled so the
167
+ Q2 outcome measurement can group merged proposals by consumer repo.
168
+ """
169
+ if fm.get("stage") != "upstream":
170
+ return
171
+ m = re.search(r"^##\s+10\.\s+Upstream PR\b(.+?)(?:^##\s|\Z)", body,
172
+ flags=re.DOTALL | re.MULTILINE)
173
+ sect = m.group(1) if m else ""
174
+ if "Originating project:" not in sect:
175
+ findings.append(Finding("error", "originating-project",
176
+ "Section 10 must include 'Originating "
177
+ "project: <slug>' when stage=upstream"))
178
+ return
179
+ line = re.search(r"Originating project:\s*(.*)", sect)
180
+ value = (line.group(1).strip() if line else "")
181
+ if not value or value.startswith("<") or value in {"-", "…", "TBD"}:
182
+ findings.append(Finding("error", "originating-project",
183
+ "Originating project slot is empty or "
184
+ "left as template placeholder"))
185
+
186
+
187
+ def _proposal_rate_warning(path: Path, findings: List[Finding],
188
+ limit: int = 6, window_days: int = 90) -> None:
189
+ """Soft cap: warn if the proposals/ directory already holds `limit`
190
+ proposals authored within the last `window_days`.
191
+
192
+ Never a hard block — the Stage-4 gate does not adjudicate volume.
193
+ The goal is to surface a consumer that is over-fitting the package.
194
+ """
195
+ import datetime as dt
196
+ parent = path.parent
197
+ if parent.name != "proposals":
198
+ return
199
+ cutoff = dt.date.today() - dt.timedelta(days=window_days)
200
+ recent = 0
201
+ for md in parent.glob("*.md"):
202
+ if md.resolve() == path.resolve():
203
+ continue
204
+ try:
205
+ text = md.read_text(encoding="utf-8", errors="replace")
206
+ except OSError:
207
+ continue
208
+ fm_m = FRONTMATTER_PATTERN.match(text)
209
+ if not fm_m:
210
+ continue
211
+ created_m = re.search(r"^created:\s*(\S+)", fm_m.group(1),
212
+ flags=re.MULTILINE)
213
+ if not created_m:
214
+ continue
215
+ try:
216
+ created = dt.date.fromisoformat(created_m.group(1).strip())
217
+ except ValueError:
218
+ continue
219
+ if created >= cutoff:
220
+ recent += 1
221
+ if recent >= limit:
222
+ findings.append(Finding(
223
+ "warning", "rate-limit",
224
+ f"{recent} proposals in the last {window_days}d — consider "
225
+ "bundling or pruning; the package is a public good, not a "
226
+ "per-project scratchpad",
227
+ ))
228
+
229
+
230
+ def _run_checks(text: str, path: Path | None = None) -> List[Finding]:
231
+ findings: List[Finding] = []
232
+ fm = _load_frontmatter(text)
233
+ _check_frontmatter(fm, findings)
234
+ body = _body_after_frontmatter(text)
235
+ _check_sections(body, findings)
236
+ _check_evidence(body, findings)
237
+ _check_markers(body, findings)
238
+ _check_success_signal(body, findings)
239
+ _check_originating_project(body, fm, findings)
240
+ if path is not None:
241
+ _proposal_rate_warning(path, findings)
242
+ return findings
243
+
244
+
245
+ def main() -> int:
246
+ ap = argparse.ArgumentParser(description=__doc__)
247
+ ap.add_argument("path", help="Path to the proposal .md file")
248
+ ap.add_argument("--format", choices=["text", "json"], default="text")
249
+ args = ap.parse_args()
250
+ path = Path(args.path)
251
+ if not path.exists():
252
+ print(f"error: {path} not found", file=sys.stderr)
253
+ return 3
254
+ findings = _run_checks(path.read_text(encoding="utf-8"), path=path)
255
+ errors = [f for f in findings if f.severity == "error"]
256
+ if args.format == "json":
257
+ print(json.dumps({"findings": [asdict(f) for f in findings]}, indent=2))
258
+ else:
259
+ for f in findings:
260
+ icon = "❌" if f.severity == "error" else "⚠️"
261
+ print(f" {icon} [{f.section}] {f.message}")
262
+ print(f"\nSummary: {len(errors)} error(s), "
263
+ f"{sum(1 for f in findings if f.severity == 'warning')} warning(s)")
264
+ print(f"Verdict: {'BLOCK' if errors else 'PASS'}")
265
+ return 1 if errors else 0
266
+
267
+
268
+ if __name__ == "__main__":
269
+ sys.exit(main())