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