@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,336 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""One-shot memory observability report.
|
|
3
|
+
|
|
4
|
+
Shows:
|
|
5
|
+
- Backend status (via `memory_status.status()`)
|
|
6
|
+
- Intake counts per entry type and per month
|
|
7
|
+
- Curated file staleness (files with `last_validated` older than
|
|
8
|
+
`review_after_days` for any entry)
|
|
9
|
+
- Supersede-chain totals
|
|
10
|
+
|
|
11
|
+
Exit code: 0 = report printed (green or otherwise); 2 = PyYAML missing.
|
|
12
|
+
`task memory:status` is the expected entry point, but the script is
|
|
13
|
+
usable standalone.
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
python3 scripts/memory_report.py
|
|
17
|
+
python3 scripts/memory_report.py --format json
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import argparse
|
|
23
|
+
import datetime as dt
|
|
24
|
+
import json
|
|
25
|
+
import sys
|
|
26
|
+
from collections import Counter, defaultdict
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
from typing import Any
|
|
29
|
+
|
|
30
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
31
|
+
import memory_status # noqa: E402
|
|
32
|
+
|
|
33
|
+
MEMORY_ROOT = Path("agents/memory")
|
|
34
|
+
INTAKE_ROOT = MEMORY_ROOT / "intake"
|
|
35
|
+
CURATED_TYPES = (
|
|
36
|
+
"ownership", "historical-patterns", "domain-invariants",
|
|
37
|
+
"architecture-decisions", "incident-learnings", "product-rules",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Role-mode marker grepped from session captures / reports / handoffs.
|
|
41
|
+
# Matches `<!-- role-mode: <slug> | contract: ... -->` on any single line.
|
|
42
|
+
# See guidelines/agent-infra/role-contracts.md "Structured mode markers".
|
|
43
|
+
import re # noqa: E402
|
|
44
|
+
|
|
45
|
+
_MODE_MARKER_PATTERN = re.compile(
|
|
46
|
+
r"<!--\s*role-mode:\s*([a-z0-9][a-z0-9-]*)\s*\|"
|
|
47
|
+
r"\s*contract:[^>]*-->"
|
|
48
|
+
)
|
|
49
|
+
_MODE_SCAN_DIRS = (
|
|
50
|
+
Path("agents/sessions"),
|
|
51
|
+
Path("agents/reports"),
|
|
52
|
+
Path("agents/handoffs"),
|
|
53
|
+
Path("agents/learnings"),
|
|
54
|
+
)
|
|
55
|
+
_KNOWN_MODES = (
|
|
56
|
+
"developer", "reviewer", "tester", "po", "incident", "planner",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _load_yaml(path: Path) -> dict:
|
|
61
|
+
try:
|
|
62
|
+
import yaml
|
|
63
|
+
except ImportError:
|
|
64
|
+
print("error: PyYAML not installed. `pip install pyyaml`.",
|
|
65
|
+
file=sys.stderr)
|
|
66
|
+
sys.exit(2)
|
|
67
|
+
with path.open(encoding="utf-8") as fh:
|
|
68
|
+
return yaml.safe_load(fh) or {}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _iter_curated_entries() -> list[tuple[Path, str, dict]]:
|
|
72
|
+
"""Yield (file, type, entry) across both curated layouts."""
|
|
73
|
+
out: list[tuple[Path, str, dict]] = []
|
|
74
|
+
for mtype in CURATED_TYPES:
|
|
75
|
+
single = MEMORY_ROOT / f"{mtype}.yml"
|
|
76
|
+
if single.is_file():
|
|
77
|
+
data = _load_yaml(single)
|
|
78
|
+
for e in data.get("entries") or []:
|
|
79
|
+
if isinstance(e, dict):
|
|
80
|
+
out.append((single, mtype, e))
|
|
81
|
+
type_dir = MEMORY_ROOT / mtype
|
|
82
|
+
if type_dir.is_dir():
|
|
83
|
+
for yml in sorted(type_dir.rglob("*.yml")):
|
|
84
|
+
data = _load_yaml(yml) or {}
|
|
85
|
+
entries = data.get("entries")
|
|
86
|
+
if isinstance(entries, list):
|
|
87
|
+
for e in entries:
|
|
88
|
+
if isinstance(e, dict):
|
|
89
|
+
out.append((yml, mtype, e))
|
|
90
|
+
elif isinstance(data, dict) and data.get("id"):
|
|
91
|
+
out.append((yml, mtype, data))
|
|
92
|
+
return out
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _intake_stats() -> dict:
|
|
96
|
+
total = 0
|
|
97
|
+
by_type: Counter = Counter()
|
|
98
|
+
by_month: Counter = Counter()
|
|
99
|
+
superseded = 0
|
|
100
|
+
if INTAKE_ROOT.is_dir():
|
|
101
|
+
for jsonl in sorted(INTAKE_ROOT.glob("*.jsonl")):
|
|
102
|
+
month = jsonl.stem.replace("signals-", "")
|
|
103
|
+
with jsonl.open(encoding="utf-8") as fh:
|
|
104
|
+
for line in fh:
|
|
105
|
+
line = line.strip()
|
|
106
|
+
if not line:
|
|
107
|
+
continue
|
|
108
|
+
try:
|
|
109
|
+
obj = json.loads(line)
|
|
110
|
+
except ValueError:
|
|
111
|
+
continue
|
|
112
|
+
if obj.get("type") == "supersede":
|
|
113
|
+
superseded += 1
|
|
114
|
+
continue
|
|
115
|
+
total += 1
|
|
116
|
+
t = obj.get("entry_type")
|
|
117
|
+
if isinstance(t, str):
|
|
118
|
+
by_type[t] += 1
|
|
119
|
+
by_month[month] += 1
|
|
120
|
+
return {
|
|
121
|
+
"total_active": total,
|
|
122
|
+
"superseded": superseded,
|
|
123
|
+
"by_type": dict(by_type),
|
|
124
|
+
"by_month": dict(by_month),
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _staleness_report() -> list[dict]:
|
|
129
|
+
today = dt.date.today()
|
|
130
|
+
stale: list[dict] = []
|
|
131
|
+
for path, mtype, entry in _iter_curated_entries():
|
|
132
|
+
lv = entry.get("last_validated")
|
|
133
|
+
review_after = entry.get("review_after_days")
|
|
134
|
+
if not isinstance(lv, (str, dt.date)) \
|
|
135
|
+
or not isinstance(review_after, int):
|
|
136
|
+
continue
|
|
137
|
+
try:
|
|
138
|
+
last = lv if isinstance(lv, dt.date) \
|
|
139
|
+
else dt.date.fromisoformat(str(lv))
|
|
140
|
+
except ValueError:
|
|
141
|
+
continue
|
|
142
|
+
due = last + dt.timedelta(days=review_after)
|
|
143
|
+
if due < today:
|
|
144
|
+
stale.append({
|
|
145
|
+
"file": str(path),
|
|
146
|
+
"type": mtype,
|
|
147
|
+
"id": entry.get("id", "?"),
|
|
148
|
+
"overdue_days": (today - due).days,
|
|
149
|
+
})
|
|
150
|
+
stale.sort(key=lambda r: r["overdue_days"], reverse=True)
|
|
151
|
+
return stale
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _quarter_of(d: dt.date | str) -> str:
|
|
155
|
+
if isinstance(d, str):
|
|
156
|
+
try:
|
|
157
|
+
d = dt.date.fromisoformat(d[:10])
|
|
158
|
+
except ValueError:
|
|
159
|
+
return "unknown"
|
|
160
|
+
if not isinstance(d, dt.date):
|
|
161
|
+
return "unknown"
|
|
162
|
+
return f"{d.year}Q{(d.month - 1) // 3 + 1}"
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _quarterly_stats() -> dict:
|
|
166
|
+
"""Per-quarter breakdown: accepted curated entries, retired (supersede)
|
|
167
|
+
entries, and the curated-file staleness rate.
|
|
168
|
+
|
|
169
|
+
Feeds the Q2 outcome measurement for `road-to-agent-outcomes.md` /
|
|
170
|
+
`road-to-project-memory.md` Phase 5.
|
|
171
|
+
"""
|
|
172
|
+
accepted: Counter = Counter()
|
|
173
|
+
for _, _, entry in _iter_curated_entries():
|
|
174
|
+
created = entry.get("created") or entry.get("last_validated")
|
|
175
|
+
if created is not None:
|
|
176
|
+
accepted[_quarter_of(created)] += 1
|
|
177
|
+
retired: Counter = Counter()
|
|
178
|
+
if INTAKE_ROOT.is_dir():
|
|
179
|
+
for jsonl in sorted(INTAKE_ROOT.glob("*.jsonl")):
|
|
180
|
+
with jsonl.open(encoding="utf-8") as fh:
|
|
181
|
+
for line in fh:
|
|
182
|
+
line = line.strip()
|
|
183
|
+
if not line:
|
|
184
|
+
continue
|
|
185
|
+
try:
|
|
186
|
+
obj = json.loads(line)
|
|
187
|
+
except ValueError:
|
|
188
|
+
continue
|
|
189
|
+
if obj.get("type") != "supersede":
|
|
190
|
+
continue
|
|
191
|
+
ts = obj.get("ts")
|
|
192
|
+
if isinstance(ts, str):
|
|
193
|
+
retired[_quarter_of(ts)] += 1
|
|
194
|
+
# Staleness rate = overdue / total curated entries (0..1).
|
|
195
|
+
total = sum(1 for _ in _iter_curated_entries())
|
|
196
|
+
overdue = len(_staleness_report())
|
|
197
|
+
rate = (overdue / total) if total else 0.0
|
|
198
|
+
return {
|
|
199
|
+
"accepted_by_quarter": dict(accepted),
|
|
200
|
+
"retired_by_quarter": dict(retired),
|
|
201
|
+
"staleness_rate": round(rate, 3),
|
|
202
|
+
"curated_total": total,
|
|
203
|
+
"curated_overdue": overdue,
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _operational_store_stats(backend_status: str) -> dict | None:
|
|
208
|
+
"""Optional operational-store stats when the backend reports `present`.
|
|
209
|
+
|
|
210
|
+
Detection-only for now: the `agent-memory` CLI adapter is the owner
|
|
211
|
+
of real counts. We surface the status and a clear stub marker so a
|
|
212
|
+
future PR can replace the stub with CLI output without changing the
|
|
213
|
+
report schema shape.
|
|
214
|
+
"""
|
|
215
|
+
if backend_status != "present":
|
|
216
|
+
return None
|
|
217
|
+
return {
|
|
218
|
+
"enabled": True,
|
|
219
|
+
"counts": {"entries": None, "recent_writes": None},
|
|
220
|
+
"note": "full operational-store probing is owned by the "
|
|
221
|
+
"agent-memory CLI adapter; stats stubbed here",
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _role_mode_stats() -> dict:
|
|
226
|
+
"""Count structured mode markers across session/report/handoff dirs.
|
|
227
|
+
|
|
228
|
+
Feeds `road-to-role-modes` Phase 4 (contract-conformance signal)
|
|
229
|
+
and `road-to-curated-self-improvement` Phase 3 (outcome measurement).
|
|
230
|
+
Missing directories are silently skipped — the repo may not have
|
|
231
|
+
session captures yet.
|
|
232
|
+
"""
|
|
233
|
+
counts: Counter[str] = Counter()
|
|
234
|
+
files_scanned = 0
|
|
235
|
+
unknown_modes: set[str] = set()
|
|
236
|
+
for root in _MODE_SCAN_DIRS:
|
|
237
|
+
if not root.exists():
|
|
238
|
+
continue
|
|
239
|
+
for md in root.rglob("*.md"):
|
|
240
|
+
try:
|
|
241
|
+
text = md.read_text(encoding="utf-8", errors="replace")
|
|
242
|
+
except OSError:
|
|
243
|
+
continue
|
|
244
|
+
files_scanned += 1
|
|
245
|
+
for match in _MODE_MARKER_PATTERN.finditer(text):
|
|
246
|
+
slug = match.group(1).lower()
|
|
247
|
+
counts[slug] += 1
|
|
248
|
+
if slug not in _KNOWN_MODES:
|
|
249
|
+
unknown_modes.add(slug)
|
|
250
|
+
total = sum(counts.values())
|
|
251
|
+
return {
|
|
252
|
+
"total_markers": total,
|
|
253
|
+
"files_scanned": files_scanned,
|
|
254
|
+
"by_mode": dict(counts),
|
|
255
|
+
"unknown_modes": sorted(unknown_modes),
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def build_report() -> dict:
|
|
260
|
+
status = memory_status.status()
|
|
261
|
+
return {
|
|
262
|
+
"backend": {
|
|
263
|
+
"status": status.status,
|
|
264
|
+
"backend": status.backend,
|
|
265
|
+
"reason": status.reason,
|
|
266
|
+
"cli_path": status.cli_path,
|
|
267
|
+
},
|
|
268
|
+
"intake": _intake_stats(),
|
|
269
|
+
"staleness": _staleness_report(),
|
|
270
|
+
"quarterly": _quarterly_stats(),
|
|
271
|
+
"role_modes": _role_mode_stats(),
|
|
272
|
+
"operational_store": _operational_store_stats(status.status),
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def _print_text(report: dict) -> None:
|
|
277
|
+
b = report["backend"]
|
|
278
|
+
print(f"Backend: {b['status']} (backend={b['backend']})")
|
|
279
|
+
if b["reason"]:
|
|
280
|
+
print(f" reason: {b['reason']}")
|
|
281
|
+
intake = report["intake"]
|
|
282
|
+
print(f"Intake: {intake['total_active']} active, "
|
|
283
|
+
f"{intake['superseded']} superseded")
|
|
284
|
+
for t, n in sorted(intake["by_type"].items()):
|
|
285
|
+
print(f" - {t}: {n}")
|
|
286
|
+
stale = report["staleness"]
|
|
287
|
+
if not stale:
|
|
288
|
+
print("Staleness: no curated entries past review_after_days")
|
|
289
|
+
else:
|
|
290
|
+
print(f"Staleness: {len(stale)} entrie(s) overdue")
|
|
291
|
+
for row in stale[:5]:
|
|
292
|
+
print(f" - {row['id']} ({row['type']}) "
|
|
293
|
+
f"+{row['overdue_days']}d {row['file']}")
|
|
294
|
+
if len(stale) > 5:
|
|
295
|
+
print(f" (+{len(stale) - 5} more)")
|
|
296
|
+
q = report["quarterly"]
|
|
297
|
+
print(f"Quarterly: staleness-rate={q['staleness_rate']:.1%} "
|
|
298
|
+
f"({q['curated_overdue']}/{q['curated_total']})")
|
|
299
|
+
if q["accepted_by_quarter"]:
|
|
300
|
+
acc = ", ".join(f"{k}:{v}" for k, v in
|
|
301
|
+
sorted(q["accepted_by_quarter"].items()))
|
|
302
|
+
print(f" accepted: {acc}")
|
|
303
|
+
if q["retired_by_quarter"]:
|
|
304
|
+
ret = ", ".join(f"{k}:{v}" for k, v in
|
|
305
|
+
sorted(q["retired_by_quarter"].items()))
|
|
306
|
+
print(f" retired: {ret}")
|
|
307
|
+
rm = report.get("role_modes") or {}
|
|
308
|
+
if rm.get("files_scanned"):
|
|
309
|
+
total = rm.get("total_markers", 0)
|
|
310
|
+
print(f"Role modes: {total} marker(s) in "
|
|
311
|
+
f"{rm['files_scanned']} file(s)")
|
|
312
|
+
if rm.get("by_mode"):
|
|
313
|
+
modes = ", ".join(f"{k}:{v}" for k, v in
|
|
314
|
+
sorted(rm["by_mode"].items()))
|
|
315
|
+
print(f" by mode: {modes}")
|
|
316
|
+
if rm.get("unknown_modes"):
|
|
317
|
+
print(f" unknown: {', '.join(rm['unknown_modes'])} "
|
|
318
|
+
"(not in the six reserved slugs)")
|
|
319
|
+
if report["operational_store"]:
|
|
320
|
+
print("Operational-store: present (stats via agent-memory CLI)")
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def main() -> int:
|
|
324
|
+
ap = argparse.ArgumentParser(description=__doc__)
|
|
325
|
+
ap.add_argument("--format", choices=["text", "json"], default="text")
|
|
326
|
+
args = ap.parse_args()
|
|
327
|
+
report = build_report()
|
|
328
|
+
if args.format == "json":
|
|
329
|
+
print(json.dumps(report, indent=2, default=str))
|
|
330
|
+
else:
|
|
331
|
+
_print_text(report)
|
|
332
|
+
return 0
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
if __name__ == "__main__":
|
|
336
|
+
sys.exit(main())
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Write-side helper: drop an engineering-memory signal.
|
|
3
|
+
|
|
4
|
+
Shared by producers (`/bug-fix`, `/do-and-judge`, `/propose-memory`,
|
|
5
|
+
incident role exit). Routes to the optional `agent-memory` package when
|
|
6
|
+
`memory_status.status() == "present"`; otherwise appends an intake
|
|
7
|
+
line under `agents/memory/intake/signals-YYYY-MM.jsonl` — append-only
|
|
8
|
+
JSONL with `merge=union` (see `road-to-memory-merge-safety.md`).
|
|
9
|
+
|
|
10
|
+
Rate limiting:
|
|
11
|
+
- Per-path, per-type, within a rolling window (default 7 days).
|
|
12
|
+
- Silent skip on duplicate — the producer's caller should not error,
|
|
13
|
+
since over-emission is a correctness bug, not a failure mode.
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
python3 scripts/memory_signal.py \\
|
|
17
|
+
--type historical-patterns \\
|
|
18
|
+
--path "app/Http/Controllers/Billing/Checkout.php" \\
|
|
19
|
+
--body "Null deref when currency is missing — add guard."
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import argparse
|
|
25
|
+
import datetime as dt
|
|
26
|
+
import json
|
|
27
|
+
import os
|
|
28
|
+
import secrets
|
|
29
|
+
import sys
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
from typing import Any
|
|
32
|
+
|
|
33
|
+
INTAKE_ROOT = Path("agents/memory/intake")
|
|
34
|
+
SETTINGS_FILE = Path(".agent-settings.yml")
|
|
35
|
+
VALID_TYPES = {
|
|
36
|
+
"historical-patterns",
|
|
37
|
+
"incident-learnings",
|
|
38
|
+
"ownership",
|
|
39
|
+
"domain-invariants",
|
|
40
|
+
"architecture-decisions",
|
|
41
|
+
"product-rules",
|
|
42
|
+
}
|
|
43
|
+
RATE_LIMIT_WINDOW_DAYS = 7
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _skip_intake_when_present() -> bool:
|
|
47
|
+
"""Read `memory.intake.skip_when_present` from `.agent-settings.yml`.
|
|
48
|
+
|
|
49
|
+
Default: False — intake JSONL is always written as debug trail even
|
|
50
|
+
when the `agent-memory` backend is present (see
|
|
51
|
+
`road-to-memory-merge-safety.md` Phase 3).
|
|
52
|
+
"""
|
|
53
|
+
if not SETTINGS_FILE.is_file():
|
|
54
|
+
return False
|
|
55
|
+
try:
|
|
56
|
+
import yaml # type: ignore
|
|
57
|
+
except ImportError:
|
|
58
|
+
return False
|
|
59
|
+
try:
|
|
60
|
+
data = yaml.safe_load(SETTINGS_FILE.read_text(encoding="utf-8")) or {}
|
|
61
|
+
except Exception:
|
|
62
|
+
return False
|
|
63
|
+
mem = data.get("memory") if isinstance(data, dict) else None
|
|
64
|
+
if not isinstance(mem, dict):
|
|
65
|
+
return False
|
|
66
|
+
intake = mem.get("intake")
|
|
67
|
+
if not isinstance(intake, dict):
|
|
68
|
+
return False
|
|
69
|
+
return bool(intake.get("skip_when_present", False))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _backend_status() -> str:
|
|
73
|
+
"""Return the current backend status: 'present' | 'absent' | 'unknown'."""
|
|
74
|
+
try:
|
|
75
|
+
import memory_status # type: ignore
|
|
76
|
+
return memory_status.status().status
|
|
77
|
+
except Exception:
|
|
78
|
+
return "unknown"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _now_iso() -> str:
|
|
82
|
+
return dt.datetime.now(dt.timezone.utc).isoformat(timespec="seconds")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _new_id() -> str:
|
|
86
|
+
# Short, URL-safe, stable enough for intake ids.
|
|
87
|
+
return f"sig-{secrets.token_hex(6)}"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _monthly_file() -> Path:
|
|
91
|
+
ym = dt.datetime.now(dt.timezone.utc).strftime("%Y-%m")
|
|
92
|
+
return INTAKE_ROOT / f"signals-{ym}.jsonl"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _recently_emitted(entry_type: str, path: str, body: str,
|
|
96
|
+
window_days: int = RATE_LIMIT_WINDOW_DAYS) -> bool:
|
|
97
|
+
"""True if an identical (type, path, body) was written within the window."""
|
|
98
|
+
if not INTAKE_ROOT.is_dir():
|
|
99
|
+
return False
|
|
100
|
+
cutoff = dt.datetime.now(dt.timezone.utc) - dt.timedelta(days=window_days)
|
|
101
|
+
for jsonl in sorted(INTAKE_ROOT.glob("signals-*.jsonl")):
|
|
102
|
+
try:
|
|
103
|
+
with jsonl.open(encoding="utf-8") as fh:
|
|
104
|
+
for line in fh:
|
|
105
|
+
line = line.strip()
|
|
106
|
+
if not line:
|
|
107
|
+
continue
|
|
108
|
+
try:
|
|
109
|
+
obj = json.loads(line)
|
|
110
|
+
except ValueError:
|
|
111
|
+
continue
|
|
112
|
+
if obj.get("entry_type") != entry_type:
|
|
113
|
+
continue
|
|
114
|
+
if obj.get("path") != path:
|
|
115
|
+
continue
|
|
116
|
+
if obj.get("body") != body:
|
|
117
|
+
continue
|
|
118
|
+
ts = obj.get("ts")
|
|
119
|
+
if not isinstance(ts, str):
|
|
120
|
+
continue
|
|
121
|
+
try:
|
|
122
|
+
emitted = dt.datetime.fromisoformat(ts)
|
|
123
|
+
except ValueError:
|
|
124
|
+
continue
|
|
125
|
+
if emitted >= cutoff:
|
|
126
|
+
return True
|
|
127
|
+
except OSError:
|
|
128
|
+
continue
|
|
129
|
+
return False
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def emit(entry_type: str, path: str, body: str,
|
|
133
|
+
extra: dict[str, Any] | None = None,
|
|
134
|
+
origin: str = "agent",
|
|
135
|
+
force: bool = False) -> dict[str, Any] | None:
|
|
136
|
+
"""Append a signal entry. Returns the written record, or None when skipped.
|
|
137
|
+
|
|
138
|
+
On `present` backend, routing to the package is a no-op here today —
|
|
139
|
+
the package adapter is wired in `road-to-agent-memory-integration.md`
|
|
140
|
+
Phase 3. For now, the file path is the single source of truth so
|
|
141
|
+
merge-safety is preserved in every mode.
|
|
142
|
+
"""
|
|
143
|
+
if entry_type not in VALID_TYPES:
|
|
144
|
+
raise ValueError(f"unknown memory type: {entry_type}")
|
|
145
|
+
if not path or not body:
|
|
146
|
+
raise ValueError("path and body are required")
|
|
147
|
+
if not force and _recently_emitted(entry_type, path, body):
|
|
148
|
+
return None
|
|
149
|
+
record: dict[str, Any] = {
|
|
150
|
+
"id": _new_id(),
|
|
151
|
+
"ts": _now_iso(),
|
|
152
|
+
"origin": origin,
|
|
153
|
+
"entry_type": entry_type,
|
|
154
|
+
"path": path,
|
|
155
|
+
"body": body,
|
|
156
|
+
}
|
|
157
|
+
if extra:
|
|
158
|
+
# Reserved keys stay intact; extras only fill unclaimed slots.
|
|
159
|
+
for k, v in extra.items():
|
|
160
|
+
record.setdefault(k, v)
|
|
161
|
+
# Backend routing: when the `agent-memory` package is present AND
|
|
162
|
+
# the consumer opted out of the debug trail, skip the JSONL write.
|
|
163
|
+
# Otherwise the intake file stays the source of truth (and, when a
|
|
164
|
+
# backend is present, a replayable debug trail).
|
|
165
|
+
if _backend_status() == "present" and _skip_intake_when_present():
|
|
166
|
+
record["_backend"] = "package-only"
|
|
167
|
+
return record
|
|
168
|
+
INTAKE_ROOT.mkdir(parents=True, exist_ok=True)
|
|
169
|
+
target = _monthly_file()
|
|
170
|
+
with target.open("a", encoding="utf-8") as fh:
|
|
171
|
+
fh.write(json.dumps(record, ensure_ascii=False) + "\n")
|
|
172
|
+
return record
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def main() -> int:
|
|
176
|
+
ap = argparse.ArgumentParser(description=__doc__)
|
|
177
|
+
ap.add_argument("--type", dest="entry_type", required=True,
|
|
178
|
+
choices=sorted(VALID_TYPES))
|
|
179
|
+
ap.add_argument("--path", required=True,
|
|
180
|
+
help="Affected file/module path (e.g., app/Http/Foo.php)")
|
|
181
|
+
ap.add_argument("--body", required=True, help="One- to few-sentence finding")
|
|
182
|
+
ap.add_argument("--origin", default="agent",
|
|
183
|
+
help="Producer identifier, e.g., bug-fix, do-and-judge")
|
|
184
|
+
ap.add_argument("--extra", default="",
|
|
185
|
+
help="Optional JSON blob of extra keys (symptom, owner, ...)")
|
|
186
|
+
ap.add_argument("--force", action="store_true",
|
|
187
|
+
help="Bypass rate-limit dedupe")
|
|
188
|
+
args = ap.parse_args()
|
|
189
|
+
extra: dict[str, Any] = {}
|
|
190
|
+
if args.extra:
|
|
191
|
+
try:
|
|
192
|
+
extra = json.loads(args.extra)
|
|
193
|
+
if not isinstance(extra, dict):
|
|
194
|
+
raise ValueError
|
|
195
|
+
except ValueError:
|
|
196
|
+
print("error: --extra must be a JSON object", file=sys.stderr)
|
|
197
|
+
return 2
|
|
198
|
+
rec = emit(args.entry_type, args.path, args.body,
|
|
199
|
+
extra=extra, origin=args.origin, force=args.force)
|
|
200
|
+
if rec is None:
|
|
201
|
+
print(f" ℹ️ skipped (already emitted within "
|
|
202
|
+
f"{RATE_LIMIT_WINDOW_DAYS}d): {args.entry_type} @ {args.path}")
|
|
203
|
+
return 0
|
|
204
|
+
print(f" ✅ signal emitted: id={rec['id']} type={rec['entry_type']} "
|
|
205
|
+
f"path={rec['path']}")
|
|
206
|
+
return 0
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
if __name__ == "__main__":
|
|
210
|
+
sys.exit(main())
|