@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,216 @@
1
+ #!/usr/bin/env python3
2
+ """File-based retrieval for the `absent` path.
3
+
4
+ Implements the shared `retrieve(types, keys, limit)` abstraction used
5
+ by skills. Reads YAML under `agents/memory/<type>/` (curated, hand-
6
+ reviewed) and JSONL under `agents/memory/intake/*.jsonl` (agent-written,
7
+ append-only, supersede-chain aware).
8
+
9
+ The returned shape is identical to the `present`-path adapter over the
10
+ `@event4u/agent-memory` API, so skills stay backend-agnostic.
11
+
12
+ Usage:
13
+ python3 scripts/memory_lookup.py --types domain-invariants,ownership \\
14
+ --key "app/Http/Controllers/Foo" --limit 5
15
+ python3 scripts/memory_lookup.py --types incident-learnings --format json
16
+
17
+ from scripts.memory_lookup import retrieve
18
+ hits = retrieve(types=["ownership"], keys=["app/Http"], limit=3)
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import argparse
24
+ import fnmatch
25
+ import json
26
+ import sys
27
+ from dataclasses import dataclass, asdict, field
28
+ from pathlib import Path
29
+ from typing import Any, Iterable
30
+
31
+ MEMORY_ROOT = Path("agents/memory")
32
+ INTAKE_ROOT = MEMORY_ROOT / "intake"
33
+
34
+ CURATED_TYPES = {
35
+ "ownership",
36
+ "historical-patterns",
37
+ "domain-invariants",
38
+ "architecture-decisions",
39
+ "incident-learnings",
40
+ "product-rules",
41
+ }
42
+
43
+
44
+ @dataclass
45
+ class Hit:
46
+ id: str
47
+ type: str
48
+ source: str # "curated" or "intake"
49
+ path: str # file that produced the hit
50
+ score: float # naive, content-match based [0..1]
51
+ entry: dict = field(default_factory=dict)
52
+
53
+ def as_dict(self) -> dict:
54
+ return asdict(self)
55
+
56
+
57
+ def _load_yaml(path: Path):
58
+ try:
59
+ import yaml
60
+ except ImportError:
61
+ print("error: PyYAML not installed. `pip install pyyaml`.",
62
+ file=sys.stderr)
63
+ sys.exit(2)
64
+ with path.open(encoding="utf-8") as fh:
65
+ return yaml.safe_load(fh) or {}
66
+
67
+
68
+ def _iter_curated_entries(mtype: str) -> Iterable[tuple[Path, dict]]:
69
+ """Yield (file, entry) pairs for curated files of `mtype`.
70
+
71
+ Supports both the content-addressed layout (`agents/memory/<type>/
72
+ <hash>.yml` — one entry per file) and the single-file layout
73
+ (`agents/memory/<type>.yml` or `<type>/entries.yml` with an
74
+ ``entries:`` list), so consumers can adopt either.
75
+ """
76
+ type_dir = MEMORY_ROOT / mtype
77
+ single_file = MEMORY_ROOT / f"{mtype}.yml"
78
+ if single_file.is_file():
79
+ data = _load_yaml(single_file)
80
+ for e in data.get("entries") or []:
81
+ if isinstance(e, dict):
82
+ yield single_file, e
83
+ if type_dir.is_dir():
84
+ for yml in sorted(type_dir.rglob("*.yml")):
85
+ data = _load_yaml(yml) or {}
86
+ entries = data.get("entries")
87
+ if isinstance(entries, list):
88
+ for e in entries:
89
+ if isinstance(e, dict):
90
+ yield yml, e
91
+ elif isinstance(data, dict) and data.get("id"):
92
+ # Flat, one-entry-per-file layout (content-addressed).
93
+ yield yml, data
94
+
95
+
96
+ def _iter_intake_entries(mtype: str) -> Iterable[tuple[Path, dict]]:
97
+ """Yield (file, entry) from intake JSONL, applying supersede chains."""
98
+ if not INTAKE_ROOT.is_dir():
99
+ return
100
+ # Resolve supersede chains globally per file: later lines win.
101
+ for jsonl in sorted(INTAKE_ROOT.glob("*.jsonl")):
102
+ by_id: dict[str, dict] = {}
103
+ superseded: set[str] = set()
104
+ with jsonl.open(encoding="utf-8") as fh:
105
+ for line in fh:
106
+ line = line.strip()
107
+ if not line:
108
+ continue
109
+ try:
110
+ obj = json.loads(line)
111
+ except ValueError:
112
+ continue
113
+ if obj.get("type") == "supersede":
114
+ target = obj.get("supersedes")
115
+ if isinstance(target, str):
116
+ superseded.add(target)
117
+ continue
118
+ eid = obj.get("id")
119
+ if isinstance(eid, str):
120
+ by_id[eid] = obj
121
+ for eid, obj in by_id.items():
122
+ if eid in superseded:
123
+ continue
124
+ if mtype and obj.get("entry_type") and obj["entry_type"] != mtype:
125
+ continue
126
+ yield jsonl, obj
127
+
128
+
129
+ def _score(entry: dict, keys: list[str]) -> float:
130
+ """Naive relevance score: max over keys of (glob-match | substring).
131
+
132
+ Good enough for the `absent` path where retrieval is best-effort.
133
+ The `present` path returns a real score from agent-memory.
134
+ """
135
+ if not keys:
136
+ return 0.1 # any hit beats no hit when there is no key
137
+ hay_parts: list[str] = []
138
+ for field_name in ("path", "key", "symptom", "feature", "rule", "body"):
139
+ v = entry.get(field_name)
140
+ if isinstance(v, str):
141
+ hay_parts.append(v)
142
+ elif isinstance(v, list):
143
+ hay_parts.extend(str(x) for x in v)
144
+ hay = " | ".join(hay_parts).lower()
145
+ best = 0.0
146
+ for k in keys:
147
+ kl = k.lower()
148
+ if fnmatch.fnmatch(hay, f"*{kl}*"):
149
+ best = max(best, 0.8)
150
+ elif kl in hay:
151
+ best = max(best, 0.6)
152
+ return best
153
+
154
+
155
+ def retrieve(types: list[str], keys: list[str], limit: int = 5) -> list[Hit]:
156
+ """Return up to `limit` hits across the requested types, highest score first.
157
+
158
+ Curated entries are preferred on ties — they are hand-reviewed.
159
+ The shape (`Hit`) matches the `present` backend adapter so skills
160
+ can treat both sources identically.
161
+ """
162
+ hits: list[Hit] = []
163
+ for mtype in types:
164
+ if mtype not in CURATED_TYPES:
165
+ continue
166
+ for path, entry in _iter_curated_entries(mtype):
167
+ hits.append(Hit(
168
+ id=str(entry.get("id", "")),
169
+ type=mtype,
170
+ source="curated",
171
+ path=str(path),
172
+ score=_score(entry, keys),
173
+ entry=entry,
174
+ ))
175
+ for path, entry in _iter_intake_entries(mtype):
176
+ hits.append(Hit(
177
+ id=str(entry.get("id", "")),
178
+ type=mtype,
179
+ source="intake",
180
+ path=str(path),
181
+ score=_score(entry, keys) * 0.9, # slight discount vs curated
182
+ entry=entry,
183
+ ))
184
+ hits.sort(key=lambda h: (h.score, h.source == "curated"), reverse=True)
185
+ # Drop zero-score hits unless no better option exists.
186
+ positives = [h for h in hits if h.score > 0]
187
+ return (positives or hits)[:limit]
188
+
189
+
190
+ def main() -> int:
191
+ ap = argparse.ArgumentParser(description=__doc__)
192
+ ap.add_argument("--types", default="",
193
+ help="Comma-separated memory types (e.g., ownership,domain-invariants)")
194
+ ap.add_argument("--key", action="append", default=[],
195
+ help="Retrieval key (repeatable)")
196
+ ap.add_argument("--limit", type=int, default=5)
197
+ ap.add_argument("--format", choices=["text", "json"], default="text")
198
+ args = ap.parse_args()
199
+ types = [t.strip() for t in args.types.split(",") if t.strip()]
200
+ if not types:
201
+ print("error: --types is required", file=sys.stderr)
202
+ return 2
203
+ hits = retrieve(types, args.key, args.limit)
204
+ if args.format == "json":
205
+ print(json.dumps([h.as_dict() for h in hits], indent=2, default=str))
206
+ else:
207
+ if not hits:
208
+ print(" (no hits)")
209
+ for h in hits:
210
+ print(f" [{h.source}] {h.type} score={h.score:.2f} "
211
+ f"id={h.id or '-'} path={h.path}")
212
+ return 0
213
+
214
+
215
+ if __name__ == "__main__":
216
+ sys.exit(main())
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env python3
2
+ """One-shot memory observability report.
3
+
4
+ Shows:
5
+ - Backend status (via `memory_status.status()`)
6
+ - Intake counts per entry type and per month
7
+ - Curated file staleness (files with `last_validated` older than
8
+ `review_after_days` for any entry)
9
+ - Supersede-chain totals
10
+
11
+ Exit code: 0 = report printed (green or otherwise); 2 = PyYAML missing.
12
+ `task memory:status` is the expected entry point, but the script is
13
+ usable standalone.
14
+
15
+ Usage:
16
+ python3 scripts/memory_report.py
17
+ python3 scripts/memory_report.py --format json
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import argparse
23
+ import datetime as dt
24
+ import json
25
+ import sys
26
+ from collections import Counter, defaultdict
27
+ from pathlib import Path
28
+ from typing import Any
29
+
30
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
31
+ import memory_status # noqa: E402
32
+
33
+ MEMORY_ROOT = Path("agents/memory")
34
+ INTAKE_ROOT = MEMORY_ROOT / "intake"
35
+ CURATED_TYPES = (
36
+ "ownership", "historical-patterns", "domain-invariants",
37
+ "architecture-decisions", "incident-learnings", "product-rules",
38
+ )
39
+
40
+
41
+ def _load_yaml(path: Path) -> dict:
42
+ try:
43
+ import yaml
44
+ except ImportError:
45
+ print("error: PyYAML not installed. `pip install pyyaml`.",
46
+ file=sys.stderr)
47
+ sys.exit(2)
48
+ with path.open(encoding="utf-8") as fh:
49
+ return yaml.safe_load(fh) or {}
50
+
51
+
52
+ def _iter_curated_entries() -> list[tuple[Path, str, dict]]:
53
+ """Yield (file, type, entry) across both curated layouts."""
54
+ out: list[tuple[Path, str, dict]] = []
55
+ for mtype in CURATED_TYPES:
56
+ single = MEMORY_ROOT / f"{mtype}.yml"
57
+ if single.is_file():
58
+ data = _load_yaml(single)
59
+ for e in data.get("entries") or []:
60
+ if isinstance(e, dict):
61
+ out.append((single, mtype, e))
62
+ type_dir = MEMORY_ROOT / mtype
63
+ if type_dir.is_dir():
64
+ for yml in sorted(type_dir.rglob("*.yml")):
65
+ data = _load_yaml(yml) or {}
66
+ entries = data.get("entries")
67
+ if isinstance(entries, list):
68
+ for e in entries:
69
+ if isinstance(e, dict):
70
+ out.append((yml, mtype, e))
71
+ elif isinstance(data, dict) and data.get("id"):
72
+ out.append((yml, mtype, data))
73
+ return out
74
+
75
+
76
+ def _intake_stats() -> dict:
77
+ total = 0
78
+ by_type: Counter = Counter()
79
+ by_month: Counter = Counter()
80
+ superseded = 0
81
+ if INTAKE_ROOT.is_dir():
82
+ for jsonl in sorted(INTAKE_ROOT.glob("*.jsonl")):
83
+ month = jsonl.stem.replace("signals-", "")
84
+ with jsonl.open(encoding="utf-8") as fh:
85
+ for line in fh:
86
+ line = line.strip()
87
+ if not line:
88
+ continue
89
+ try:
90
+ obj = json.loads(line)
91
+ except ValueError:
92
+ continue
93
+ if obj.get("type") == "supersede":
94
+ superseded += 1
95
+ continue
96
+ total += 1
97
+ t = obj.get("entry_type")
98
+ if isinstance(t, str):
99
+ by_type[t] += 1
100
+ by_month[month] += 1
101
+ return {
102
+ "total_active": total,
103
+ "superseded": superseded,
104
+ "by_type": dict(by_type),
105
+ "by_month": dict(by_month),
106
+ }
107
+
108
+
109
+ def _staleness_report() -> list[dict]:
110
+ today = dt.date.today()
111
+ stale: list[dict] = []
112
+ for path, mtype, entry in _iter_curated_entries():
113
+ lv = entry.get("last_validated")
114
+ review_after = entry.get("review_after_days")
115
+ if not isinstance(lv, (str, dt.date)) \
116
+ or not isinstance(review_after, int):
117
+ continue
118
+ try:
119
+ last = lv if isinstance(lv, dt.date) \
120
+ else dt.date.fromisoformat(str(lv))
121
+ except ValueError:
122
+ continue
123
+ due = last + dt.timedelta(days=review_after)
124
+ if due < today:
125
+ stale.append({
126
+ "file": str(path),
127
+ "type": mtype,
128
+ "id": entry.get("id", "?"),
129
+ "overdue_days": (today - due).days,
130
+ })
131
+ stale.sort(key=lambda r: r["overdue_days"], reverse=True)
132
+ return stale
133
+
134
+
135
+ def build_report() -> dict:
136
+ status = memory_status.status()
137
+ return {
138
+ "backend": {
139
+ "status": status.status,
140
+ "backend": status.backend,
141
+ "reason": status.reason,
142
+ "cli_path": status.cli_path,
143
+ },
144
+ "intake": _intake_stats(),
145
+ "staleness": _staleness_report(),
146
+ }
147
+
148
+
149
+ def _print_text(report: dict) -> None:
150
+ b = report["backend"]
151
+ print(f"Backend: {b['status']} (backend={b['backend']})")
152
+ if b["reason"]:
153
+ print(f" reason: {b['reason']}")
154
+ intake = report["intake"]
155
+ print(f"Intake: {intake['total_active']} active, "
156
+ f"{intake['superseded']} superseded")
157
+ for t, n in sorted(intake["by_type"].items()):
158
+ print(f" - {t}: {n}")
159
+ stale = report["staleness"]
160
+ if not stale:
161
+ print("Staleness: no curated entries past review_after_days")
162
+ else:
163
+ print(f"Staleness: {len(stale)} entrie(s) overdue")
164
+ for row in stale[:5]:
165
+ print(f" - {row['id']} ({row['type']}) "
166
+ f"+{row['overdue_days']}d {row['file']}")
167
+ if len(stale) > 5:
168
+ print(f" (+{len(stale) - 5} more)")
169
+
170
+
171
+ def main() -> int:
172
+ ap = argparse.ArgumentParser(description=__doc__)
173
+ ap.add_argument("--format", choices=["text", "json"], default="text")
174
+ args = ap.parse_args()
175
+ report = build_report()
176
+ if args.format == "json":
177
+ print(json.dumps(report, indent=2, default=str))
178
+ else:
179
+ _print_text(report)
180
+ return 0
181
+
182
+
183
+ if __name__ == "__main__":
184
+ sys.exit(main())
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env python3
2
+ """Write-side helper: drop an engineering-memory signal.
3
+
4
+ Shared by producers (`/bug-fix`, `/do-and-judge`, `/propose-memory`,
5
+ incident role exit). Routes to the optional `agent-memory` package when
6
+ `memory_status.status() == "present"`; otherwise appends an intake
7
+ line under `agents/memory/intake/signals-YYYY-MM.jsonl` — append-only
8
+ JSONL with `merge=union` (see `road-to-memory-merge-safety.md`).
9
+
10
+ Rate limiting:
11
+ - Per-path, per-type, within a rolling window (default 7 days).
12
+ - Silent skip on duplicate — the producer's caller should not error,
13
+ since over-emission is a correctness bug, not a failure mode.
14
+
15
+ Usage:
16
+ python3 scripts/memory_signal.py \\
17
+ --type historical-patterns \\
18
+ --path "app/Http/Controllers/Billing/Checkout.php" \\
19
+ --body "Null deref when currency is missing — add guard."
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import argparse
25
+ import datetime as dt
26
+ import json
27
+ import os
28
+ import secrets
29
+ import sys
30
+ from pathlib import Path
31
+ from typing import Any
32
+
33
+ INTAKE_ROOT = Path("agents/memory/intake")
34
+ VALID_TYPES = {
35
+ "historical-patterns",
36
+ "incident-learnings",
37
+ "ownership",
38
+ "domain-invariants",
39
+ "architecture-decisions",
40
+ "product-rules",
41
+ }
42
+ RATE_LIMIT_WINDOW_DAYS = 7
43
+
44
+
45
+ def _now_iso() -> str:
46
+ return dt.datetime.now(dt.timezone.utc).isoformat(timespec="seconds")
47
+
48
+
49
+ def _new_id() -> str:
50
+ # Short, URL-safe, stable enough for intake ids.
51
+ return f"sig-{secrets.token_hex(6)}"
52
+
53
+
54
+ def _monthly_file() -> Path:
55
+ ym = dt.datetime.now(dt.timezone.utc).strftime("%Y-%m")
56
+ return INTAKE_ROOT / f"signals-{ym}.jsonl"
57
+
58
+
59
+ def _recently_emitted(entry_type: str, path: str, body: str,
60
+ window_days: int = RATE_LIMIT_WINDOW_DAYS) -> bool:
61
+ """True if an identical (type, path, body) was written within the window."""
62
+ if not INTAKE_ROOT.is_dir():
63
+ return False
64
+ cutoff = dt.datetime.now(dt.timezone.utc) - dt.timedelta(days=window_days)
65
+ for jsonl in sorted(INTAKE_ROOT.glob("signals-*.jsonl")):
66
+ try:
67
+ with jsonl.open(encoding="utf-8") as fh:
68
+ for line in fh:
69
+ line = line.strip()
70
+ if not line:
71
+ continue
72
+ try:
73
+ obj = json.loads(line)
74
+ except ValueError:
75
+ continue
76
+ if obj.get("entry_type") != entry_type:
77
+ continue
78
+ if obj.get("path") != path:
79
+ continue
80
+ if obj.get("body") != body:
81
+ continue
82
+ ts = obj.get("ts")
83
+ if not isinstance(ts, str):
84
+ continue
85
+ try:
86
+ emitted = dt.datetime.fromisoformat(ts)
87
+ except ValueError:
88
+ continue
89
+ if emitted >= cutoff:
90
+ return True
91
+ except OSError:
92
+ continue
93
+ return False
94
+
95
+
96
+ def emit(entry_type: str, path: str, body: str,
97
+ extra: dict[str, Any] | None = None,
98
+ origin: str = "agent",
99
+ force: bool = False) -> dict[str, Any] | None:
100
+ """Append a signal entry. Returns the written record, or None when skipped.
101
+
102
+ On `present` backend, routing to the package is a no-op here today —
103
+ the package adapter is wired in `road-to-agent-memory-integration.md`
104
+ Phase 3. For now, the file path is the single source of truth so
105
+ merge-safety is preserved in every mode.
106
+ """
107
+ if entry_type not in VALID_TYPES:
108
+ raise ValueError(f"unknown memory type: {entry_type}")
109
+ if not path or not body:
110
+ raise ValueError("path and body are required")
111
+ if not force and _recently_emitted(entry_type, path, body):
112
+ return None
113
+ record: dict[str, Any] = {
114
+ "id": _new_id(),
115
+ "ts": _now_iso(),
116
+ "origin": origin,
117
+ "entry_type": entry_type,
118
+ "path": path,
119
+ "body": body,
120
+ }
121
+ if extra:
122
+ # Reserved keys stay intact; extras only fill unclaimed slots.
123
+ for k, v in extra.items():
124
+ record.setdefault(k, v)
125
+ INTAKE_ROOT.mkdir(parents=True, exist_ok=True)
126
+ target = _monthly_file()
127
+ with target.open("a", encoding="utf-8") as fh:
128
+ fh.write(json.dumps(record, ensure_ascii=False) + "\n")
129
+ return record
130
+
131
+
132
+ def main() -> int:
133
+ ap = argparse.ArgumentParser(description=__doc__)
134
+ ap.add_argument("--type", dest="entry_type", required=True,
135
+ choices=sorted(VALID_TYPES))
136
+ ap.add_argument("--path", required=True,
137
+ help="Affected file/module path (e.g., app/Http/Foo.php)")
138
+ ap.add_argument("--body", required=True, help="One- to few-sentence finding")
139
+ ap.add_argument("--origin", default="agent",
140
+ help="Producer identifier, e.g., bug-fix, do-and-judge")
141
+ ap.add_argument("--extra", default="",
142
+ help="Optional JSON blob of extra keys (symptom, owner, ...)")
143
+ ap.add_argument("--force", action="store_true",
144
+ help="Bypass rate-limit dedupe")
145
+ args = ap.parse_args()
146
+ extra: dict[str, Any] = {}
147
+ if args.extra:
148
+ try:
149
+ extra = json.loads(args.extra)
150
+ if not isinstance(extra, dict):
151
+ raise ValueError
152
+ except ValueError:
153
+ print("error: --extra must be a JSON object", file=sys.stderr)
154
+ return 2
155
+ rec = emit(args.entry_type, args.path, args.body,
156
+ extra=extra, origin=args.origin, force=args.force)
157
+ if rec is None:
158
+ print(f" ℹ️ skipped (already emitted within "
159
+ f"{RATE_LIMIT_WINDOW_DAYS}d): {args.entry_type} @ {args.path}")
160
+ return 0
161
+ print(f" ✅ signal emitted: id={rec['id']} type={rec['entry_type']} "
162
+ f"path={rec['path']}")
163
+ return 0
164
+
165
+
166
+ if __name__ == "__main__":
167
+ sys.exit(main())