@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,623 @@
1
+ #!/usr/bin/env python3
2
+ """Deterministic detection helper for the refine-ticket skill.
3
+
4
+ Reads the detection-map.yml from
5
+ .agent-src.uncompressed/skills/refine-ticket/ (or the projected copy),
6
+ takes ticket body text, and returns a structured decision — which
7
+ sub-skills should fire, which keywords matched, and an
8
+ orchestration-notes line per sub-skill ready to fold into the skill
9
+ output.
10
+
11
+ This helper makes the skill's Step 2 deterministic and pytest-covered.
12
+ The skill's procedure cites this helper by name; it does not re-derive
13
+ the matching logic.
14
+
15
+ Usage:
16
+ from scripts.refine_ticket_detect import detect, load_map
17
+ decision = detect(ticket_body, load_map())
18
+ """
19
+ from __future__ import annotations
20
+
21
+ import json
22
+ import re
23
+ import subprocess
24
+ from dataclasses import dataclass, field
25
+ from pathlib import Path
26
+
27
+ try:
28
+ import yaml
29
+ except ImportError as exc:
30
+ raise SystemExit(
31
+ "refine_ticket_detect requires pyyaml (pip install pyyaml)"
32
+ ) from exc
33
+
34
+ REPO_ROOT = Path(__file__).resolve().parent.parent
35
+ DEFAULT_MAP = (
36
+ REPO_ROOT
37
+ / ".agent-src.uncompressed"
38
+ / "skills"
39
+ / "refine-ticket"
40
+ / "detection-map.yml"
41
+ )
42
+
43
+ # Composite tokens that contain a sub-skill keyword as a substring but
44
+ # are not themselves triggers (Phase F2). Matched with word boundaries
45
+ # on the lowercased text and substituted before keyword matching so the
46
+ # contained keyword ("password") does not fire on them. Defence in
47
+ # depth: word-boundary matching alone already skips these, the
48
+ # blocklist catches edge cases where a future keyword change or unusual
49
+ # spelling might otherwise re-introduce the false positive.
50
+ BLOCKED_COMPOSITES = (
51
+ "1password",
52
+ "lastpass",
53
+ "bitwarden",
54
+ )
55
+ _BLOCKLIST_RE = re.compile(
56
+ r"\b(?:" + "|".join(re.escape(t) for t in BLOCKED_COMPOSITES) + r")\b",
57
+ flags=re.IGNORECASE,
58
+ )
59
+
60
+ # Ticket-ID pattern (Phase F1). Jira / Linear / Shortcut style —
61
+ # two-to-ten uppercase letters, hyphen, digits. Used to extract the
62
+ # project key (``DEV`` in ``DEV-6182``) from a ticket body.
63
+ _TICKET_KEY_RE = re.compile(r"\b([A-Z]{2,10})-\d+\b")
64
+
65
+
66
+ @dataclass
67
+ class SubSkillDecision:
68
+ skill: str
69
+ fired: bool
70
+ matched_keywords: list[str] = field(default_factory=list)
71
+ matched_regex: list[str] = field(default_factory=list)
72
+ matched_alt_signals: list[str] = field(default_factory=list)
73
+ require_count: int = 1
74
+ notes: str = ""
75
+
76
+ def as_output_line(self) -> str:
77
+ if not self.fired:
78
+ return f"`{self.skill}` — skipped (no trigger match)"
79
+ matches = (
80
+ self.matched_keywords
81
+ + self.matched_regex
82
+ + self.matched_alt_signals
83
+ )
84
+ shown = ", ".join(matches[:5])
85
+ extra = (
86
+ f" (+{len(matches) - 5} more)" if len(matches) > 5 else ""
87
+ )
88
+ return f"`{self.skill}` — fired on: {shown}{extra}"
89
+
90
+
91
+ @dataclass
92
+ class RepoContext:
93
+ """Repo-local signals gathered when cwd is inside a repo clone.
94
+
95
+ Feeds the skill's Top-5 risks with project-specific vocabulary —
96
+ recent branch names (naming-convention signal), recent commit
97
+ subjects (active modules signal), and on-disk `agents/contexts/`
98
+ documents (domain-vocabulary signal).
99
+
100
+ Empty when `repo_aware=False` — the skill still produces the same
101
+ output shape (graceful degrade), but without repo-specific
102
+ citations.
103
+ """
104
+
105
+ recent_branches: list[str] = field(default_factory=list)
106
+ recent_commits: list[str] = field(default_factory=list)
107
+ context_docs: list[str] = field(default_factory=list)
108
+
109
+ def is_empty(self) -> bool:
110
+ return not (
111
+ self.recent_branches or self.recent_commits or self.context_docs
112
+ )
113
+
114
+ def summary_line(self) -> str:
115
+ if self.is_empty():
116
+ return "Repo context — none gathered"
117
+ parts = [
118
+ f"{len(self.recent_branches)} branches",
119
+ f"{len(self.recent_commits)} commits",
120
+ f"{len(self.context_docs)} context docs",
121
+ ]
122
+ return "Repo context — " + ", ".join(parts)
123
+
124
+
125
+ @dataclass
126
+ class ProjectAlignment:
127
+ """Cross-check between the ticket's project key and the current repo.
128
+
129
+ Phase F1 + F7 — emits a one-line advisory in orchestration notes
130
+ whenever the ticket is clearly tagged (``DEV-6182``) AND the cwd
131
+ offers at least one repo identifier (composer/package name,
132
+ historical branch-prefix project key). Stays silent when either
133
+ side is absent so the output is not padded with noise.
134
+ """
135
+
136
+ ticket_project_key: str | None = None
137
+ repo_identifiers: list[str] = field(default_factory=list)
138
+ matched: bool | None = None
139
+
140
+ def has_data(self) -> bool:
141
+ return bool(self.ticket_project_key and self.repo_identifiers)
142
+
143
+ def as_output_line(self) -> str | None:
144
+ if not self.has_data():
145
+ return None
146
+ shown = ", ".join(f"`{r}`" for r in self.repo_identifiers[:3])
147
+ if self.matched:
148
+ return (
149
+ f"Repo project match — ticket `{self.ticket_project_key}` "
150
+ f"aligns with repo identifiers {shown}"
151
+ )
152
+ return (
153
+ f"Repo project mismatch — ticket `{self.ticket_project_key}`, "
154
+ f"repo identifiers {shown} — context may not apply"
155
+ )
156
+
157
+
158
+ @dataclass
159
+ class Decision:
160
+ sub_skills: list[SubSkillDecision]
161
+ repo_aware: bool
162
+ repo_context: RepoContext = field(default_factory=RepoContext)
163
+ alignment: ProjectAlignment = field(default_factory=ProjectAlignment)
164
+
165
+ def orchestration_notes(self) -> list[str]:
166
+ notes = [ss.as_output_line() for ss in self.sub_skills]
167
+ notes.append(
168
+ f"Repo-aware — {'on' if self.repo_aware else 'off'}"
169
+ )
170
+ if self.repo_aware:
171
+ notes.append(self.repo_context.summary_line())
172
+ # Phase F1 + F7 — alignment line is independent of repo_aware;
173
+ # a cross-repo invocation must surface the warning even when
174
+ # repo-aware context gathering is off.
175
+ alignment_line = self.alignment.as_output_line()
176
+ if alignment_line is not None:
177
+ notes.append(alignment_line)
178
+ return notes
179
+
180
+
181
+ def load_map(path: Path | None = None) -> dict:
182
+ path = path or DEFAULT_MAP
183
+ if not path.exists():
184
+ raise FileNotFoundError(f"detection-map not found: {path}")
185
+ with path.open("r", encoding="utf-8") as fh:
186
+ data = yaml.safe_load(fh)
187
+ if data.get("version") != 1:
188
+ raise ValueError(
189
+ f"unsupported detection-map version: {data.get('version')}"
190
+ )
191
+ return data
192
+
193
+
194
+ def _keyword_pattern(keyword: str) -> re.Pattern[str]:
195
+ """Word-boundary regex for a keyword (Phase F2).
196
+
197
+ `\\b` matches at word/non-word transitions — `[A-Za-z0-9_]` vs. any
198
+ other character. Multi-word keywords like ``api key`` and
199
+ hyphenated keywords like ``multi-tenant`` work because the inner
200
+ space / hyphen is a non-word character and the outer boundaries
201
+ still anchor against the surrounding text.
202
+ """
203
+ return re.compile(r"\b" + re.escape(keyword) + r"\b", flags=re.IGNORECASE)
204
+
205
+
206
+ def _mask_blocked_composites(text_lower: str) -> str:
207
+ """Neutralize composite tokens that contain a keyword as substring.
208
+
209
+ Returns ``text_lower`` with each occurrence of a blocked composite
210
+ replaced by a fixed marker of equal length-class (non-word chars)
211
+ so keyword positions after the replacement stay plausible.
212
+ """
213
+ return _BLOCKLIST_RE.sub("__blocked__", text_lower)
214
+
215
+
216
+ _AC_BULLET_RE = re.compile(
217
+ r"^\s*[-*]\s*\[[ xX~\-]\]\s*(\S+)",
218
+ flags=re.MULTILINE,
219
+ )
220
+
221
+
222
+ def _extract_description_body(body: str) -> str:
223
+ """Return the prose between ``## Description`` and the next level-2
224
+ heading, or the whole body when no ``## Description`` heading is
225
+ found. Used by the F3 alt-signal ``min_body_sentences`` check.
226
+ """
227
+ m = re.search(
228
+ r"##\s*Description\s*\n(.+?)(?=\n##\s|\Z)",
229
+ body,
230
+ flags=re.DOTALL | re.IGNORECASE,
231
+ )
232
+ if m:
233
+ return m.group(1).strip()
234
+ return body.strip()
235
+
236
+
237
+ def _split_sentences(text: str) -> list[str]:
238
+ """Naive sentence splitter — punctuation `.!?` followed by whitespace.
239
+
240
+ Good enough for the F3 heuristic; intentionally avoids NLP deps.
241
+ """
242
+ parts = re.split(r"(?<=[.!?])\s+", text.strip())
243
+ return [p for p in parts if p.strip() and len(p.strip()) > 2]
244
+
245
+
246
+ def _extract_ac_first_words(body: str) -> list[str]:
247
+ """First token of every AC bullet, lowercased and alpha-only.
248
+
249
+ Used by the F3 alt-signal ``min_distinct_ac_first_words`` check —
250
+ a crude proxy for "distinct verbs in AC" without lemmatization.
251
+ """
252
+ words: list[str] = []
253
+ for raw in _AC_BULLET_RE.findall(body):
254
+ cleaned = re.sub(r"[^A-Za-z]", "", raw).lower()
255
+ if cleaned:
256
+ words.append(cleaned)
257
+ return words
258
+
259
+
260
+ def _evaluate_alt_signals(body: str, spec: dict) -> list[str]:
261
+ """Compute Phase F3 alternative signals for a sub-skill.
262
+
263
+ Returns a list of human-readable reasons (empty when no threshold
264
+ is met). Reasons are folded into `matched_alt_signals` so the
265
+ orchestration-notes line explains *why* the sub-skill fired.
266
+ """
267
+ alt = spec.get("alternative_signals")
268
+ if not isinstance(alt, dict) or not alt:
269
+ return []
270
+ reasons: list[str] = []
271
+
272
+ min_sent = alt.get("min_body_sentences")
273
+ if isinstance(min_sent, int) and min_sent > 0:
274
+ n = len(_split_sentences(_extract_description_body(body)))
275
+ if n >= min_sent:
276
+ reasons.append(f"body sentences {n}≥{min_sent}")
277
+
278
+ min_ac = alt.get("min_distinct_ac_first_words")
279
+ if isinstance(min_ac, int) and min_ac > 0:
280
+ distinct = len(set(_extract_ac_first_words(body)))
281
+ if distinct >= min_ac:
282
+ reasons.append(f"ac first-words {distinct}≥{min_ac}")
283
+
284
+ return reasons
285
+
286
+
287
+ def _match_sub_skill(
288
+ text_lower: str, text_original: str, skill_name: str, spec: dict
289
+ ) -> SubSkillDecision:
290
+ keywords = [kw.lower() for kw in spec.get("keywords", [])]
291
+ require = int(spec.get("require_count", 1))
292
+ masked = _mask_blocked_composites(text_lower)
293
+ matched_kw = sorted({
294
+ kw for kw in keywords if _keyword_pattern(kw).search(masked)
295
+ })
296
+ matched_rx: list[str] = []
297
+ for pattern in spec.get("regex", []) or []:
298
+ if re.search(pattern, text_original):
299
+ matched_rx.append(pattern)
300
+ distinct = len(matched_kw) + len(matched_rx)
301
+ matched_alt = _evaluate_alt_signals(text_original, spec)
302
+ fired = distinct >= require or bool(matched_alt)
303
+ return SubSkillDecision(
304
+ skill=skill_name,
305
+ fired=fired,
306
+ matched_keywords=matched_kw,
307
+ matched_regex=matched_rx,
308
+ matched_alt_signals=matched_alt,
309
+ require_count=require,
310
+ notes=(spec.get("notes") or "").strip(),
311
+ )
312
+
313
+
314
+ def _detect_repo_aware(
315
+ cwd: Path | None, spec: dict | None
316
+ ) -> bool:
317
+ if not spec or cwd is None:
318
+ return False
319
+ signals = spec.get("signals", [])
320
+ require = int(spec.get("require_count", 1))
321
+ hits = 0
322
+ for sig in signals:
323
+ target = cwd / sig["path"]
324
+ if sig.get("type") == "dir" and target.is_dir():
325
+ hits += 1
326
+ elif sig.get("type") == "file" and target.is_file():
327
+ hits += 1
328
+ return hits >= require
329
+
330
+
331
+ def _run_git(cwd: Path, args: list[str]) -> str:
332
+ try:
333
+ result = subprocess.run(
334
+ ["git", *args],
335
+ cwd=str(cwd),
336
+ capture_output=True,
337
+ text=True,
338
+ timeout=5,
339
+ check=False,
340
+ )
341
+ except (FileNotFoundError, subprocess.TimeoutExpired):
342
+ return ""
343
+ if result.returncode != 0:
344
+ return ""
345
+ return result.stdout
346
+
347
+
348
+ def gather_repo_context(
349
+ cwd: Path,
350
+ branch_limit: int = 20,
351
+ commit_limit: int = 30,
352
+ ) -> RepoContext:
353
+ """Collect naming-convention signals from the enclosing repo.
354
+
355
+ Safe outside a repo — returns an empty `RepoContext`. Safe when
356
+ `git` is unavailable (timeout / not installed) — returns partial
357
+ data without raising.
358
+ """
359
+ if not (cwd / ".git").is_dir():
360
+ return RepoContext()
361
+
362
+ branches_raw = _run_git(
363
+ cwd,
364
+ [
365
+ "for-each-ref",
366
+ "--count",
367
+ str(branch_limit),
368
+ "--sort=-committerdate",
369
+ "--format=%(refname:short)",
370
+ "refs/heads/",
371
+ ],
372
+ )
373
+ branches = [b.strip() for b in branches_raw.splitlines() if b.strip()]
374
+
375
+ commits_raw = _run_git(
376
+ cwd, ["log", f"-{commit_limit}", "--pretty=format:%s"]
377
+ )
378
+ commits = [c.strip() for c in commits_raw.splitlines() if c.strip()]
379
+
380
+ context_docs: list[str] = []
381
+ contexts_dir = cwd / "agents" / "contexts"
382
+ if contexts_dir.is_dir():
383
+ context_docs = sorted(
384
+ p.name for p in contexts_dir.glob("*.md") if p.is_file()
385
+ )
386
+
387
+ return RepoContext(
388
+ recent_branches=branches,
389
+ recent_commits=commits,
390
+ context_docs=context_docs,
391
+ )
392
+
393
+
394
+ def _extract_ticket_project_key(body: str) -> str | None:
395
+ """Extract the dominant Jira / Linear / Shortcut project key (Phase F1).
396
+
397
+ Picks the most frequent ``[A-Z]{2,10}`` prefix across all ticket IDs
398
+ found in the body. Ties resolve to the first occurrence order.
399
+ Returns ``None`` when no ticket IDs are present.
400
+ """
401
+ from collections import Counter
402
+
403
+ matches = _TICKET_KEY_RE.findall(body)
404
+ if not matches:
405
+ return None
406
+ counts = Counter(matches)
407
+ top_count = counts.most_common(1)[0][1]
408
+ for key in matches:
409
+ if counts[key] == top_count:
410
+ return key
411
+ return None
412
+
413
+
414
+ def _gather_repo_identifiers(cwd: Path) -> list[str]:
415
+ """Collect project-identifier tokens from the enclosing repo (Phase F1).
416
+
417
+ Sources, in order:
418
+ 1. ``composer.json`` ``name`` field (``vendor/package``).
419
+ 2. ``package.json`` ``name`` field (``@scope/package``).
420
+ 3. Historical branch prefixes that look like Jira project keys.
421
+
422
+ Silent when a source is unreadable or absent. De-duplicates
423
+ case-insensitively while preserving first-seen order.
424
+ """
425
+ ids: list[str] = []
426
+
427
+ for fname in ("composer.json", "package.json"):
428
+ fpath = cwd / fname
429
+ if not fpath.is_file():
430
+ continue
431
+ try:
432
+ data = json.loads(fpath.read_text(encoding="utf-8"))
433
+ except (OSError, ValueError):
434
+ continue
435
+ name = data.get("name") if isinstance(data, dict) else None
436
+ if isinstance(name, str) and name:
437
+ for part in re.split(r"[/@]", name):
438
+ part = part.strip()
439
+ if part:
440
+ ids.append(part)
441
+
442
+ branches_raw = _run_git(
443
+ cwd,
444
+ [
445
+ "for-each-ref",
446
+ "--count", "50",
447
+ "--sort=-committerdate",
448
+ "--format=%(refname:short)",
449
+ "refs/heads/",
450
+ ],
451
+ )
452
+ for branch in branches_raw.splitlines():
453
+ for prefix in _TICKET_KEY_RE.findall(branch):
454
+ ids.append(prefix)
455
+
456
+ seen: set[str] = set()
457
+ deduped: list[str] = []
458
+ for x in ids:
459
+ key = x.lower()
460
+ if key in seen:
461
+ continue
462
+ seen.add(key)
463
+ deduped.append(x)
464
+ return deduped
465
+
466
+
467
+ def _match_project(ticket_key: str, repo_ids: list[str]) -> bool:
468
+ """Heuristic project match — case-insensitive substring either way.
469
+
470
+ ``DEV`` matches ``devtools`` (repo id contains ticket key) and vice
471
+ versa (``DEVOPS`` ticket key matches ``dev`` repo id). Strict
472
+ equality is a subset of this rule.
473
+ """
474
+ tk = ticket_key.lower()
475
+ for rid in repo_ids:
476
+ rlow = rid.lower()
477
+ if tk == rlow or tk in rlow or rlow in tk:
478
+ return True
479
+ return False
480
+
481
+
482
+ def _compute_alignment(
483
+ ticket_body: str, cwd: Path | None
484
+ ) -> ProjectAlignment:
485
+ if cwd is None:
486
+ return ProjectAlignment()
487
+ ticket_key = _extract_ticket_project_key(ticket_body)
488
+ if ticket_key is None:
489
+ return ProjectAlignment()
490
+ repo_ids = _gather_repo_identifiers(cwd)
491
+ if not repo_ids:
492
+ return ProjectAlignment(ticket_project_key=ticket_key)
493
+ return ProjectAlignment(
494
+ ticket_project_key=ticket_key,
495
+ repo_identifiers=repo_ids,
496
+ matched=_match_project(ticket_key, repo_ids),
497
+ )
498
+
499
+
500
+ # ---- Phase F4 — parent context folding -------------------------------------
501
+
502
+ _PARENT_AUTO_FETCH_TYPES = frozenset({"story", "sub-task", "subtask"})
503
+
504
+
505
+ def issuetype_needs_parent(issuetype: str | None) -> bool:
506
+ """Decide whether the F4 auto-fetch rule applies to this issuetype.
507
+
508
+ Story / Sub-task (Jira) and their Linear / Shortcut equivalents
509
+ inherit AC context from a parent epic most of the time. Task / Bug
510
+ / Epic themselves do not, unless a ``parent`` link field is
511
+ already populated — that branch is the agent's responsibility and
512
+ is not encoded here. Comparison is case-insensitive and tolerant
513
+ of ``Sub-task`` vs ``Subtask`` spellings.
514
+ """
515
+ if not issuetype:
516
+ return False
517
+ return issuetype.strip().lower() in _PARENT_AUTO_FETCH_TYPES
518
+
519
+
520
+ def fold_parent_context(
521
+ ticket_body: str,
522
+ parent_body: str,
523
+ parent_key: str,
524
+ ) -> str:
525
+ """Prepend a canonical ``## Parent context`` block to the ticket body.
526
+
527
+ The folded block is what the deterministic detection helper sees,
528
+ so parent-level keywords correctly raise sub-skill triggers and
529
+ the skill's ``Open questions`` section can cite parent AC lines
530
+ verbatim. Idempotent — folding twice with the same parent does
531
+ not duplicate the block.
532
+ """
533
+ header = f"## Parent context — {parent_key}"
534
+ if header in ticket_body:
535
+ return ticket_body
536
+ parent_block = parent_body.strip() or "_(parent body empty)_"
537
+ folded = (
538
+ f"{header}\n\n"
539
+ f"{parent_block}\n\n"
540
+ f"---\n\n"
541
+ f"{ticket_body.lstrip()}"
542
+ )
543
+ return folded
544
+
545
+
546
+ # ---- Phase F6 — close-prompt write-permission probe ------------------------
547
+
548
+ CLOSE_PROMPT_FULL = (
549
+ "> Next action for this ticket:\n"
550
+ ">\n"
551
+ "> 1. Comment on Jira — I'll post the refined version as a comment"
552
+ " (original untouched)\n"
553
+ "> 2. Replace description — I'll overwrite the Jira description;"
554
+ " original saved in a comment\n"
555
+ "> 3. Nothing — I'll handle it myself / leave the ticket as is"
556
+ )
557
+
558
+ CLOSE_PROMPT_READ_ONLY = (
559
+ "> Next action for this ticket:\n"
560
+ ">\n"
561
+ "> 1. Copy-paste — no write access to this project"
562
+ )
563
+
564
+
565
+ def render_close_prompt(write_access: bool | None) -> str:
566
+ """Return the numbered close-prompt block for the skill output.
567
+
568
+ - ``True`` — full three-option prompt (comment / replace / nothing).
569
+ - ``False`` — single-option prompt (copy-paste only); options 1 and
570
+ 2 are hidden up front instead of degrading after the user picks.
571
+ - ``None`` — probe itself failed (network, auth, missing tool).
572
+ Fall back to the full prompt; the skill degrades on selection
573
+ per the v1 behaviour.
574
+ """
575
+ if write_access is False:
576
+ return CLOSE_PROMPT_READ_ONLY
577
+ return CLOSE_PROMPT_FULL
578
+
579
+
580
+ def detect(
581
+ ticket_body: str,
582
+ detection_map: dict,
583
+ cwd: Path | None = None,
584
+ ) -> Decision:
585
+ text_lower = ticket_body.lower()
586
+ decisions: list[SubSkillDecision] = []
587
+ for skill_name, spec in detection_map.get("sub_skills", {}).items():
588
+ decisions.append(
589
+ _match_sub_skill(text_lower, ticket_body, skill_name, spec)
590
+ )
591
+ repo_aware = _detect_repo_aware(cwd, detection_map.get("repo_aware"))
592
+ repo_context = (
593
+ gather_repo_context(cwd) if repo_aware and cwd else RepoContext()
594
+ )
595
+ alignment = _compute_alignment(ticket_body, cwd)
596
+ return Decision(
597
+ sub_skills=decisions,
598
+ repo_aware=repo_aware,
599
+ repo_context=repo_context,
600
+ alignment=alignment,
601
+ )
602
+
603
+
604
+ def main() -> None:
605
+ import argparse
606
+ import sys
607
+
608
+ parser = argparse.ArgumentParser(description=__doc__)
609
+ parser.add_argument(
610
+ "path", nargs="?", help="Path to a ticket body .md file; - for stdin"
611
+ )
612
+ args = parser.parse_args()
613
+ if not args.path or args.path == "-":
614
+ body = sys.stdin.read()
615
+ else:
616
+ body = Path(args.path).read_text(encoding="utf-8")
617
+ decision = detect(body, load_map(), cwd=Path.cwd())
618
+ for line in decision.orchestration_notes():
619
+ print(line)
620
+
621
+
622
+ if __name__ == "__main__":
623
+ main()
@@ -0,0 +1,7 @@
1
+ # Pinned requirements for the live trigger-eval runner.
2
+ #
3
+ # Installed into .venv/ by scripts/setup_eval_venv.sh. Not used by CI,
4
+ # not used by any other script in this repo. If the SDK ever needs to
5
+ # be upgraded, bump the version here and rerun the setup script.
6
+
7
+ anthropic==0.96.0