@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,341 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Engineering Memory validator.
|
|
4
|
+
|
|
5
|
+
Validates YAML files under `agents/memory/<type>/**/*.yml` against the
|
|
6
|
+
schema documented in `guidelines/agent-infra/engineering-memory-data-format`.
|
|
7
|
+
|
|
8
|
+
Checks:
|
|
9
|
+
* Required shared frontmatter: id, status, confidence, source, owner,
|
|
10
|
+
last_validated, review_after_days.
|
|
11
|
+
* Duplicate `id` within the same type.
|
|
12
|
+
* Basic redaction: obvious secrets, private URLs with credentials,
|
|
13
|
+
IP addresses tied to internal ranges.
|
|
14
|
+
* Staleness: entries where (today - last_validated) > review_after_days
|
|
15
|
+
are reported (informational, never hard fail).
|
|
16
|
+
|
|
17
|
+
* Append-only (--append-only): inspects `git diff` against a ref to
|
|
18
|
+
ensure intake JSONL files (`agents/memory/intake/*.jsonl`) only gained
|
|
19
|
+
lines at EOF. In-place edits, deletions, or reorderings fail the check.
|
|
20
|
+
See `road-to-memory-merge-safety.md` Phase 0.
|
|
21
|
+
|
|
22
|
+
Exit codes: 0 = clean, 1 = violations, 2 = PyYAML missing, 3 = internal error.
|
|
23
|
+
|
|
24
|
+
Usage:
|
|
25
|
+
python3 scripts/check_memory.py # validate templates + agents/memory
|
|
26
|
+
python3 scripts/check_memory.py --path agents/memory
|
|
27
|
+
python3 scripts/check_memory.py --format json
|
|
28
|
+
python3 scripts/check_memory.py --append-only # CI: diff vs origin/main
|
|
29
|
+
python3 scripts/check_memory.py --append-only --base HEAD~1
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import argparse
|
|
35
|
+
import datetime as _dt
|
|
36
|
+
import json
|
|
37
|
+
import re
|
|
38
|
+
import subprocess
|
|
39
|
+
import sys
|
|
40
|
+
from dataclasses import dataclass, asdict
|
|
41
|
+
from pathlib import Path
|
|
42
|
+
from typing import List, Literal, Optional, Tuple
|
|
43
|
+
|
|
44
|
+
Severity = Literal["error", "warning", "info"]
|
|
45
|
+
|
|
46
|
+
REQUIRED_KEYS = {
|
|
47
|
+
"id", "status", "confidence", "source",
|
|
48
|
+
"owner", "last_validated", "review_after_days",
|
|
49
|
+
}
|
|
50
|
+
VALID_STATUS = {"active", "deprecated", "archived"}
|
|
51
|
+
VALID_CONFIDENCE = {"low", "medium", "high"}
|
|
52
|
+
KNOWN_TYPES = {
|
|
53
|
+
"domain-invariants", "architecture-decisions",
|
|
54
|
+
"incident-learnings", "product-rules",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Redaction heuristics — plain-regex, deliberately conservative.
|
|
58
|
+
# False positives are fixed by quoting the line differently; false
|
|
59
|
+
# negatives are a curator responsibility.
|
|
60
|
+
REDACTION_PATTERNS = [
|
|
61
|
+
# Key=value secret with a clear credential-word prefix. The value must
|
|
62
|
+
# be a single token (no spaces, no "/" — skips filepaths and URLs).
|
|
63
|
+
(re.compile(r"(?i)\b(api[_-]?key|auth[_-]?token|access[_-]?token|bearer|"
|
|
64
|
+
r"secret|password|passwd|private[_-]?key)\b\s*[:=]\s*"
|
|
65
|
+
r"[A-Za-z0-9+/=_\-]{8,}(?![/.\w])"),
|
|
66
|
+
"inline credential"),
|
|
67
|
+
(re.compile(r"https?://[^\s\"'/]*:[^\s\"'/]*@"), "url with credentials"),
|
|
68
|
+
(re.compile(r"\b10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b"), "internal ipv4 range"),
|
|
69
|
+
(re.compile(r"\b192\.168\.\d{1,3}\.\d{1,3}\b"), "internal ipv4 range"),
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass
|
|
74
|
+
class Finding:
|
|
75
|
+
file: str
|
|
76
|
+
line: int
|
|
77
|
+
severity: Severity
|
|
78
|
+
message: str
|
|
79
|
+
entry_id: str = ""
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _load_yaml(path: Path):
|
|
83
|
+
try:
|
|
84
|
+
import yaml
|
|
85
|
+
except ImportError:
|
|
86
|
+
print(
|
|
87
|
+
"error: PyYAML not installed. Run `pip install pyyaml` to use check_memory.",
|
|
88
|
+
file=sys.stderr,
|
|
89
|
+
)
|
|
90
|
+
sys.exit(2)
|
|
91
|
+
with path.open(encoding="utf-8") as fh:
|
|
92
|
+
return yaml.safe_load(fh)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _memory_type(path: Path) -> str:
|
|
96
|
+
# Supports `memory/<type>.yml`, `memory/<type>/<hash>.yml`, and
|
|
97
|
+
# `memory/<type>.example.yml` template filenames.
|
|
98
|
+
parts = path.parts
|
|
99
|
+
if "memory" not in parts:
|
|
100
|
+
return path.stem
|
|
101
|
+
idx = parts.index("memory")
|
|
102
|
+
nxt = parts[idx + 1] if idx + 1 < len(parts) else ""
|
|
103
|
+
stem = Path(nxt).stem
|
|
104
|
+
# Strip `.example` suffix used in template files.
|
|
105
|
+
return stem[:-len(".example")] if stem.endswith(".example") else stem
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _validate_entry(entry: dict, path: Path, seen_ids: set, findings: List[Finding]):
|
|
109
|
+
eid = entry.get("id", "")
|
|
110
|
+
missing = REQUIRED_KEYS - set(entry.keys())
|
|
111
|
+
for key in sorted(missing):
|
|
112
|
+
findings.append(Finding(str(path), 0, "error", f"missing required field: {key}", eid))
|
|
113
|
+
if entry.get("status") and entry["status"] not in VALID_STATUS:
|
|
114
|
+
findings.append(Finding(str(path), 0, "error",
|
|
115
|
+
f"invalid status '{entry['status']}'", eid))
|
|
116
|
+
if entry.get("confidence") and entry["confidence"] not in VALID_CONFIDENCE:
|
|
117
|
+
findings.append(Finding(str(path), 0, "error",
|
|
118
|
+
f"invalid confidence '{entry['confidence']}'", eid))
|
|
119
|
+
sources = entry.get("source") or []
|
|
120
|
+
if not isinstance(sources, list) or len(sources) < 1:
|
|
121
|
+
findings.append(Finding(str(path), 0, "error",
|
|
122
|
+
"source must be a list with ≥1 entry", eid))
|
|
123
|
+
if eid and eid in seen_ids:
|
|
124
|
+
findings.append(Finding(str(path), 0, "error", f"duplicate id '{eid}'", eid))
|
|
125
|
+
seen_ids.add(eid)
|
|
126
|
+
# Staleness.
|
|
127
|
+
lv = entry.get("last_validated")
|
|
128
|
+
days = entry.get("review_after_days")
|
|
129
|
+
if isinstance(lv, _dt.date) and isinstance(days, int):
|
|
130
|
+
age = (_dt.date.today() - lv).days
|
|
131
|
+
if age > days and entry.get("status") == "active":
|
|
132
|
+
findings.append(Finding(str(path), 0, "info",
|
|
133
|
+
f"stale: last_validated {age} days ago (limit {days})", eid))
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _check_redaction(path: Path, findings: List[Finding]):
|
|
137
|
+
for line_no, line in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1):
|
|
138
|
+
# Skip comments — redaction warnings in example/commentary lines are noise.
|
|
139
|
+
if line.lstrip().startswith("#"):
|
|
140
|
+
continue
|
|
141
|
+
for pattern, label in REDACTION_PATTERNS:
|
|
142
|
+
if pattern.search(line):
|
|
143
|
+
findings.append(Finding(str(path), line_no, "error",
|
|
144
|
+
f"possible leak: {label}"))
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _validate_file(path: Path, findings: List[Finding]):
|
|
148
|
+
mtype = _memory_type(path)
|
|
149
|
+
if mtype not in KNOWN_TYPES:
|
|
150
|
+
findings.append(Finding(str(path), 0, "warning",
|
|
151
|
+
f"unknown memory type '{mtype}'"))
|
|
152
|
+
_check_redaction(path, findings)
|
|
153
|
+
try:
|
|
154
|
+
data = _load_yaml(path) or {}
|
|
155
|
+
except Exception as exc: # yaml.YAMLError or anything else
|
|
156
|
+
findings.append(Finding(str(path), 0, "error",
|
|
157
|
+
f"YAML parse error: {exc.__class__.__name__}"))
|
|
158
|
+
return
|
|
159
|
+
if not isinstance(data, dict) or "entries" not in data:
|
|
160
|
+
findings.append(Finding(str(path), 0, "error",
|
|
161
|
+
"missing top-level 'entries' key"))
|
|
162
|
+
return
|
|
163
|
+
seen_ids: set = set()
|
|
164
|
+
for entry in data.get("entries") or []:
|
|
165
|
+
if isinstance(entry, dict):
|
|
166
|
+
_validate_entry(entry, path, seen_ids, findings)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
INTAKE_GLOB = "agents/memory/intake/*.jsonl"
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _git(cmd: List[str]) -> Tuple[int, str]:
|
|
173
|
+
try:
|
|
174
|
+
out = subprocess.run(cmd, capture_output=True, text=True, check=False)
|
|
175
|
+
return out.returncode, (out.stdout or "") + (out.stderr or "")
|
|
176
|
+
except FileNotFoundError:
|
|
177
|
+
return 127, "git not found"
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _resolve_base(explicit: Optional[str]) -> Optional[str]:
|
|
181
|
+
# CI: GITHUB_BASE_REF is set on PRs → origin/<base>.
|
|
182
|
+
import os
|
|
183
|
+
if explicit:
|
|
184
|
+
return explicit
|
|
185
|
+
base_ref = os.environ.get("GITHUB_BASE_REF")
|
|
186
|
+
if base_ref:
|
|
187
|
+
return f"origin/{base_ref}"
|
|
188
|
+
# Local fallback: origin/main if it exists.
|
|
189
|
+
rc, _ = _git(["git", "rev-parse", "--verify", "origin/main"])
|
|
190
|
+
if rc == 0:
|
|
191
|
+
return "origin/main"
|
|
192
|
+
return None
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _check_append_only(base: Optional[str], findings: List[Finding]) -> None:
|
|
196
|
+
"""Verify that every intake JSONL file only grew at EOF vs `base`.
|
|
197
|
+
|
|
198
|
+
A safe change adds lines at the end. Any hunk that removes or modifies
|
|
199
|
+
an existing line is a violation — it breaks the `merge=union` contract
|
|
200
|
+
and can cause silent conflict resolution errors.
|
|
201
|
+
"""
|
|
202
|
+
ref = _resolve_base(base)
|
|
203
|
+
if ref is None:
|
|
204
|
+
findings.append(Finding(INTAKE_GLOB, 0, "warning",
|
|
205
|
+
"append-only: no base ref resolved (set --base or GITHUB_BASE_REF)"))
|
|
206
|
+
return
|
|
207
|
+
rc, diff = _git(["git", "diff", "--unified=0", "--no-color",
|
|
208
|
+
ref, "--", "agents/memory/intake/"])
|
|
209
|
+
if rc != 0:
|
|
210
|
+
findings.append(Finding(INTAKE_GLOB, 0, "warning",
|
|
211
|
+
f"append-only: git diff failed vs {ref}"))
|
|
212
|
+
return
|
|
213
|
+
if not diff.strip():
|
|
214
|
+
return # nothing changed, nothing to check
|
|
215
|
+
current_file = ""
|
|
216
|
+
old_path = ""
|
|
217
|
+
for line in diff.splitlines():
|
|
218
|
+
if line.startswith("diff --git"):
|
|
219
|
+
parts = line.split()
|
|
220
|
+
current_file = parts[-1][2:] if len(parts) >= 4 else ""
|
|
221
|
+
old_path = ""
|
|
222
|
+
elif line.startswith("--- "):
|
|
223
|
+
old_path = line[4:].strip()
|
|
224
|
+
elif line.startswith("@@"):
|
|
225
|
+
# Hunk header: @@ -oldStart,oldCount +newStart,newCount @@
|
|
226
|
+
m = re.match(r"^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@", line)
|
|
227
|
+
if not m:
|
|
228
|
+
continue
|
|
229
|
+
old_start = int(m.group(1))
|
|
230
|
+
old_count = int(m.group(2) or "1")
|
|
231
|
+
# Any hunk that removes >0 lines from the old file = in-place edit.
|
|
232
|
+
if old_count > 0 and old_path != "/dev/null":
|
|
233
|
+
findings.append(Finding(current_file or INTAKE_GLOB, old_start, "error",
|
|
234
|
+
f"append-only violation: {old_count} existing "
|
|
235
|
+
f"line(s) removed or modified (ref={ref})"))
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def _shadow_report(fmt: str) -> int:
|
|
239
|
+
"""Report per-type shadow counts from the conflict rule.
|
|
240
|
+
|
|
241
|
+
Ships today as scaffolding: without a wired operational backend the
|
|
242
|
+
counts are all zero (there is nothing on the operational side to
|
|
243
|
+
suppress). Once agent-memory is present locally, re-running this
|
|
244
|
+
command will surface real shadows under the same shape — so the
|
|
245
|
+
downstream consumer (dashboards, weekly cron) never changes.
|
|
246
|
+
"""
|
|
247
|
+
# Inline import so `check_memory.py` stays importable when someone
|
|
248
|
+
# runs it on a tree without scripts/ on sys.path (e.g., packaging).
|
|
249
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
250
|
+
from scripts.memory_lookup import CURATED_TYPES, RetrievalResult, retrieve
|
|
251
|
+
|
|
252
|
+
per_type: dict = {}
|
|
253
|
+
total_shadows = 0
|
|
254
|
+
for mtype in sorted(CURATED_TYPES):
|
|
255
|
+
result = retrieve(types=[mtype], keys=[], limit=1000, with_shadows=True)
|
|
256
|
+
assert isinstance(result, RetrievalResult)
|
|
257
|
+
per_type[mtype] = {
|
|
258
|
+
"hits": len(result.hits),
|
|
259
|
+
"shadows": len(result.shadows),
|
|
260
|
+
}
|
|
261
|
+
total_shadows += len(result.shadows)
|
|
262
|
+
|
|
263
|
+
# Best-effort backend-status probe — avoid a hard dependency on
|
|
264
|
+
# memory_status.py in case it is absent.
|
|
265
|
+
backend = "unknown"
|
|
266
|
+
try:
|
|
267
|
+
from scripts.memory_status import status as _memory_status # type: ignore
|
|
268
|
+
backend = _memory_status().status
|
|
269
|
+
except Exception: # noqa: BLE001
|
|
270
|
+
pass
|
|
271
|
+
|
|
272
|
+
if fmt == "json":
|
|
273
|
+
print(json.dumps({
|
|
274
|
+
"backend": backend,
|
|
275
|
+
"total_shadows": total_shadows,
|
|
276
|
+
"per_type": per_type,
|
|
277
|
+
}, indent=2))
|
|
278
|
+
return 0
|
|
279
|
+
|
|
280
|
+
print(f"Shadow report — backend: {backend}")
|
|
281
|
+
print(f" Total operational entries shadowed: {total_shadows}")
|
|
282
|
+
for mtype, stats in per_type.items():
|
|
283
|
+
print(f" {mtype:25s} hits={stats['hits']:>4} "
|
|
284
|
+
f"shadows={stats['shadows']}")
|
|
285
|
+
if backend == "absent":
|
|
286
|
+
print("\n ℹ️ operational backend absent — shadow counts will "
|
|
287
|
+
"stay zero until @event4u/agent-memory is installed.")
|
|
288
|
+
return 0
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def main() -> int:
|
|
292
|
+
ap = argparse.ArgumentParser(description=__doc__)
|
|
293
|
+
ap.add_argument("--path", default="agents/memory", help="Root path to scan")
|
|
294
|
+
ap.add_argument("--format", choices=["text", "json"], default="text")
|
|
295
|
+
ap.add_argument("--append-only", action="store_true",
|
|
296
|
+
help="Enforce append-only JSONL contract for agents/memory/intake/*.jsonl "
|
|
297
|
+
"via git diff against the base ref")
|
|
298
|
+
ap.add_argument("--base", default=None,
|
|
299
|
+
help="Base ref for --append-only (default: GITHUB_BASE_REF or origin/main)")
|
|
300
|
+
ap.add_argument("--shadow-report", action="store_true",
|
|
301
|
+
help="Report per-type shadow counts from the repo-vs-operational "
|
|
302
|
+
"conflict rule (observability scaffolding for weekly cron)")
|
|
303
|
+
args = ap.parse_args()
|
|
304
|
+
if args.shadow_report:
|
|
305
|
+
return _shadow_report(args.format)
|
|
306
|
+
root = Path(args.path)
|
|
307
|
+
findings: List[Finding] = []
|
|
308
|
+
if args.append_only:
|
|
309
|
+
_check_append_only(args.base, findings)
|
|
310
|
+
# Append-only mode is standalone by design: it inspects git state, not files
|
|
311
|
+
# on disk, and is meant to run as a fast CI gate. Skip YAML validation.
|
|
312
|
+
return _emit(findings, args.format)
|
|
313
|
+
if not root.exists():
|
|
314
|
+
if args.format == "json":
|
|
315
|
+
print(json.dumps({"findings": [], "note": f"{root} not found"}))
|
|
316
|
+
else:
|
|
317
|
+
print(f"ℹ️ {root} not found — nothing to validate")
|
|
318
|
+
return 0
|
|
319
|
+
for yml in sorted(root.rglob("*.yml")):
|
|
320
|
+
_validate_file(yml, findings)
|
|
321
|
+
return _emit(findings, args.format)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def _emit(findings: List[Finding], fmt: str) -> int:
|
|
325
|
+
errors = [f for f in findings if f.severity == "error"]
|
|
326
|
+
if fmt == "json":
|
|
327
|
+
print(json.dumps({"findings": [asdict(f) for f in findings]}, indent=2))
|
|
328
|
+
else:
|
|
329
|
+
for f in findings:
|
|
330
|
+
icon = {"error": "❌", "warning": "⚠️", "info": "ℹ️"}[f.severity]
|
|
331
|
+
loc = f"{f.file}:{f.line}" if f.line else f.file
|
|
332
|
+
suffix = f" [{f.entry_id}]" if f.entry_id else ""
|
|
333
|
+
print(f" {icon} {loc}{suffix} {f.message}")
|
|
334
|
+
print(f"\nSummary: {len(errors)} error(s), "
|
|
335
|
+
f"{sum(1 for f in findings if f.severity == 'warning')} warning(s), "
|
|
336
|
+
f"{sum(1 for f in findings if f.severity == 'info')} info")
|
|
337
|
+
return 1 if errors else 0
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
if __name__ == "__main__":
|
|
341
|
+
sys.exit(main())
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Gate script for memory promotion (intake → curated).
|
|
3
|
+
|
|
4
|
+
Validates a memory-promotion candidate — either an intake JSONL record
|
|
5
|
+
(identified by `--intake-id`) or a stand-alone proposal YAML — against
|
|
6
|
+
the admission discipline defined in
|
|
7
|
+
`road-to-agent-memory-integration.md` Phase 3.
|
|
8
|
+
|
|
9
|
+
Gate checks (all hard):
|
|
10
|
+
1. Metadata complete — `id`, `entry_type`, `path`, `body` exist
|
|
11
|
+
(intake); or the full curated schema applies (proposal YAML).
|
|
12
|
+
2. `entry_type` is one of the six curated memory types.
|
|
13
|
+
3. The body describes a **pattern**, not a one-off: ≥ 2 distinct
|
|
14
|
+
paths in the intake stream share the same root-cause signature
|
|
15
|
+
OR the submitter supplies `future_decisions:` with ≥ 3 concrete,
|
|
16
|
+
dated, owner-tagged use cases.
|
|
17
|
+
4. Same `(entry_type, path)` has no active curated entry whose rule
|
|
18
|
+
the promotion would contradict (manual check — script prints a
|
|
19
|
+
hint, does not enforce).
|
|
20
|
+
|
|
21
|
+
Exit codes: 0 = pass, 1 = gate failure, 2 = PyYAML missing, 3 = internal error.
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
python3 scripts/check_memory_proposal.py --intake-id sig-abc123
|
|
25
|
+
python3 scripts/check_memory_proposal.py --proposal path/to.yml
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import argparse
|
|
31
|
+
import json
|
|
32
|
+
import sys
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
from typing import Any
|
|
35
|
+
|
|
36
|
+
INTAKE_ROOT = Path("agents/memory/intake")
|
|
37
|
+
VALID_TYPES = {
|
|
38
|
+
"historical-patterns", "incident-learnings", "ownership",
|
|
39
|
+
"domain-invariants", "architecture-decisions", "product-rules",
|
|
40
|
+
}
|
|
41
|
+
REQUIRED_INTAKE = ("id", "entry_type", "path", "body")
|
|
42
|
+
PATTERN_MIN_PATHS = 2
|
|
43
|
+
MIN_FUTURE_DECISIONS = 3
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _load_yaml(path: Path) -> dict:
|
|
47
|
+
try:
|
|
48
|
+
import yaml
|
|
49
|
+
except ImportError:
|
|
50
|
+
print("error: PyYAML not installed. `pip install pyyaml`.",
|
|
51
|
+
file=sys.stderr)
|
|
52
|
+
sys.exit(2)
|
|
53
|
+
with path.open(encoding="utf-8") as fh:
|
|
54
|
+
data = yaml.safe_load(fh)
|
|
55
|
+
if not isinstance(data, dict):
|
|
56
|
+
print(f"error: {path} is not a YAML mapping", file=sys.stderr)
|
|
57
|
+
sys.exit(1)
|
|
58
|
+
return data
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _find_intake(intake_id: str) -> dict | None:
|
|
62
|
+
if not INTAKE_ROOT.is_dir():
|
|
63
|
+
return None
|
|
64
|
+
for jsonl in sorted(INTAKE_ROOT.glob("*.jsonl")):
|
|
65
|
+
with jsonl.open(encoding="utf-8") as fh:
|
|
66
|
+
for line in fh:
|
|
67
|
+
line = line.strip()
|
|
68
|
+
if not line:
|
|
69
|
+
continue
|
|
70
|
+
try:
|
|
71
|
+
obj = json.loads(line)
|
|
72
|
+
except ValueError:
|
|
73
|
+
continue
|
|
74
|
+
if obj.get("id") == intake_id:
|
|
75
|
+
return obj
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _count_sibling_paths(entry_type: str, body: str) -> int:
|
|
80
|
+
"""Count distinct `path` values in intake with the same (type, body)."""
|
|
81
|
+
if not INTAKE_ROOT.is_dir():
|
|
82
|
+
return 0
|
|
83
|
+
seen: set[str] = set()
|
|
84
|
+
for jsonl in INTAKE_ROOT.glob("*.jsonl"):
|
|
85
|
+
with jsonl.open(encoding="utf-8") as fh:
|
|
86
|
+
for line in fh:
|
|
87
|
+
line = line.strip()
|
|
88
|
+
if not line:
|
|
89
|
+
continue
|
|
90
|
+
try:
|
|
91
|
+
obj = json.loads(line)
|
|
92
|
+
except ValueError:
|
|
93
|
+
continue
|
|
94
|
+
if obj.get("entry_type") == entry_type \
|
|
95
|
+
and obj.get("body") == body \
|
|
96
|
+
and isinstance(obj.get("path"), str):
|
|
97
|
+
seen.add(obj["path"])
|
|
98
|
+
return len(seen)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _check_future_decisions(fds: Any) -> list[str]:
|
|
102
|
+
"""Return failure messages for a weak `future_decisions:` block."""
|
|
103
|
+
failures: list[str] = []
|
|
104
|
+
if not isinstance(fds, list):
|
|
105
|
+
return ["future_decisions: missing or not a list"]
|
|
106
|
+
if len(fds) < MIN_FUTURE_DECISIONS:
|
|
107
|
+
failures.append(
|
|
108
|
+
f"future_decisions: needs ≥{MIN_FUTURE_DECISIONS}, got {len(fds)}"
|
|
109
|
+
)
|
|
110
|
+
for i, fd in enumerate(fds, 1):
|
|
111
|
+
if not isinstance(fd, dict):
|
|
112
|
+
failures.append(f"future_decisions[{i}]: must be a mapping")
|
|
113
|
+
continue
|
|
114
|
+
for key in ("decision", "expected_by", "owner"):
|
|
115
|
+
if not fd.get(key):
|
|
116
|
+
failures.append(f"future_decisions[{i}]: missing `{key}`")
|
|
117
|
+
return failures
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def check(record: dict, source: str) -> list[str]:
|
|
121
|
+
failures: list[str] = []
|
|
122
|
+
# 1. required fields
|
|
123
|
+
for key in REQUIRED_INTAKE:
|
|
124
|
+
if key not in record or record[key] in (None, ""):
|
|
125
|
+
failures.append(f"missing field: `{key}`")
|
|
126
|
+
# 2. type value
|
|
127
|
+
if record.get("entry_type") not in VALID_TYPES:
|
|
128
|
+
failures.append(
|
|
129
|
+
f"entry_type `{record.get('entry_type')}` not in {sorted(VALID_TYPES)}"
|
|
130
|
+
)
|
|
131
|
+
# 3. pattern vs one-off
|
|
132
|
+
body = record.get("body")
|
|
133
|
+
etype = record.get("entry_type")
|
|
134
|
+
sibling_paths = _count_sibling_paths(etype, body) if body and etype else 0
|
|
135
|
+
fds = record.get("future_decisions")
|
|
136
|
+
if sibling_paths >= PATTERN_MIN_PATHS:
|
|
137
|
+
pass # strong pattern signal
|
|
138
|
+
else:
|
|
139
|
+
fd_errors = _check_future_decisions(fds)
|
|
140
|
+
if fd_errors:
|
|
141
|
+
failures.append(
|
|
142
|
+
f"weak pattern evidence ({sibling_paths} sibling path(s)) "
|
|
143
|
+
f"and future_decisions insufficient:"
|
|
144
|
+
)
|
|
145
|
+
failures.extend(f" - {e}" for e in fd_errors)
|
|
146
|
+
return failures
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def main() -> int:
|
|
150
|
+
ap = argparse.ArgumentParser(description=__doc__)
|
|
151
|
+
grp = ap.add_mutually_exclusive_group(required=True)
|
|
152
|
+
grp.add_argument("--intake-id", help="Promote an intake record by id")
|
|
153
|
+
grp.add_argument("--proposal", help="Promote a proposal YAML file")
|
|
154
|
+
ap.add_argument("--format", choices=["text", "json"], default="text")
|
|
155
|
+
args = ap.parse_args()
|
|
156
|
+
if args.intake_id:
|
|
157
|
+
record = _find_intake(args.intake_id)
|
|
158
|
+
if record is None:
|
|
159
|
+
print(f"error: no intake entry with id={args.intake_id}",
|
|
160
|
+
file=sys.stderr)
|
|
161
|
+
return 1
|
|
162
|
+
source = f"intake:{args.intake_id}"
|
|
163
|
+
else:
|
|
164
|
+
record = _load_yaml(Path(args.proposal))
|
|
165
|
+
source = args.proposal
|
|
166
|
+
failures = check(record, source)
|
|
167
|
+
if args.format == "json":
|
|
168
|
+
print(json.dumps({"source": source, "failures": failures}, indent=2))
|
|
169
|
+
else:
|
|
170
|
+
if failures:
|
|
171
|
+
print(f"❌ {source} — gate failed:")
|
|
172
|
+
for f in failures:
|
|
173
|
+
print(f" 🔴 {f}")
|
|
174
|
+
else:
|
|
175
|
+
print(f"✅ {source} — gate passed")
|
|
176
|
+
return 1 if failures else 0
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
if __name__ == "__main__":
|
|
180
|
+
sys.exit(main())
|