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