@event4u/agent-config 6.0.0 → 6.1.0
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/.claude-plugin/marketplace.json +5 -5
- package/CHANGELOG.md +167 -440
- package/README.md +3 -3
- package/dist/agent-src/commands/agent-handoff.md +5 -4
- package/dist/agent-src/commands/agent-status.md +1 -0
- package/dist/agent-src/commands/agents/audit.md +1 -0
- package/dist/agent-src/commands/agents/init.md +3 -0
- package/dist/agent-src/commands/agents/optimize.md +1 -0
- package/dist/agent-src/commands/agents/user/accept.md +1 -0
- package/dist/agent-src/commands/agents/user/init.md +1 -0
- package/dist/agent-src/commands/agents/user/review.md +1 -0
- package/dist/agent-src/commands/agents/user/show.md +1 -0
- package/dist/agent-src/commands/agents/user/update.md +1 -0
- package/dist/agent-src/commands/agents/user.md +1 -0
- package/dist/agent-src/commands/agents.md +1 -0
- package/dist/agent-src/commands/analytics/prune.md +3 -2
- package/dist/agent-src/commands/analytics/show.md +3 -2
- package/dist/agent-src/commands/analytics.md +3 -2
- package/dist/agent-src/commands/analyze-reference-repo.md +1 -0
- package/dist/agent-src/commands/bug-fix.md +1 -0
- package/dist/agent-src/commands/bug-investigate.md +1 -0
- package/dist/agent-src/commands/challenge-me/vision.md +3 -2
- package/dist/agent-src/commands/challenge-me/with-docs.md +3 -2
- package/dist/agent-src/commands/challenge-me.md +3 -2
- package/dist/agent-src/commands/chat-history/import.md +9 -9
- package/dist/agent-src/commands/chat-history.md +32 -30
- package/dist/agent-src/commands/check-current-md.md +1 -0
- package/dist/agent-src/commands/commit/in-chunks.md +1 -0
- package/dist/agent-src/commands/commit.md +1 -0
- package/dist/agent-src/commands/condense.md +1 -0
- package/dist/agent-src/commands/context/create.md +1 -0
- package/dist/agent-src/commands/context/refactor.md +1 -0
- package/dist/agent-src/commands/context.md +1 -0
- package/dist/agent-src/commands/cost-report.md +5 -4
- package/dist/agent-src/commands/council/analysis.md +3 -2
- package/dist/agent-src/commands/council/debate.md +5 -4
- package/dist/agent-src/commands/council/default.md +3 -2
- package/dist/agent-src/commands/council/design.md +3 -2
- package/dist/agent-src/commands/council/optimize.md +3 -2
- package/dist/agent-src/commands/council/pr.md +3 -2
- package/dist/agent-src/commands/council.md +4 -3
- package/dist/agent-src/commands/e2e-heal.md +1 -0
- package/dist/agent-src/commands/e2e-plan.md +1 -0
- package/dist/agent-src/commands/estimate-ticket.md +1 -0
- package/dist/agent-src/commands/feature/dev.md +1 -0
- package/dist/agent-src/commands/feature/explore.md +1 -0
- package/dist/agent-src/commands/feature/plan.md +6 -6
- package/dist/agent-src/commands/feature/refactor.md +1 -0
- package/dist/agent-src/commands/feature/roadmap.md +1 -0
- package/dist/agent-src/commands/feature.md +1 -0
- package/dist/agent-src/commands/fix/ci.md +1 -0
- package/dist/agent-src/commands/fix/portability.md +1 -0
- package/dist/agent-src/commands/fix/pr-comments.md +147 -15
- package/dist/agent-src/commands/fix/refs.md +1 -0
- package/dist/agent-src/commands/fix/seeder.md +1 -0
- package/dist/agent-src/commands/fix.md +8 -8
- package/dist/agent-src/commands/ghostwriter/delete.md +1 -0
- package/dist/agent-src/commands/ghostwriter/fetch.md +1 -0
- package/dist/agent-src/commands/ghostwriter/list.md +1 -0
- package/dist/agent-src/commands/ghostwriter/show.md +1 -0
- package/dist/agent-src/commands/ghostwriter/write.md +1 -0
- package/dist/agent-src/commands/ghostwriter.md +1 -0
- package/dist/agent-src/commands/grill-me.md +3 -2
- package/dist/agent-src/commands/image/analyse.md +1 -0
- package/dist/agent-src/commands/image/create.md +1 -0
- package/dist/agent-src/commands/image/verify.md +1 -0
- package/dist/agent-src/commands/image.md +1 -0
- package/dist/agent-src/commands/implement-ticket.md +1 -0
- package/dist/agent-src/commands/jira-ticket.md +1 -0
- package/dist/agent-src/commands/judge/on-diff.md +1 -0
- package/dist/agent-src/commands/judge/solo.md +1 -0
- package/dist/agent-src/commands/judge/steps.md +1 -0
- package/dist/agent-src/commands/judge.md +1 -0
- package/dist/agent-src/commands/knowledge/cross-repo.md +1 -0
- package/dist/agent-src/commands/knowledge/forget.md +1 -0
- package/dist/agent-src/commands/knowledge/ingest.md +1 -0
- package/dist/agent-src/commands/knowledge/list.md +1 -0
- package/dist/agent-src/commands/knowledge.md +1 -0
- package/dist/agent-src/commands/memory/add.md +8 -6
- package/dist/agent-src/commands/memory/learn-low-impact.md +3 -2
- package/dist/agent-src/commands/memory/load.md +7 -7
- package/dist/agent-src/commands/memory/mine-session.md +39 -12
- package/dist/agent-src/commands/memory/promote.md +3 -2
- package/dist/agent-src/commands/memory/propose.md +7 -6
- package/dist/agent-src/commands/memory.md +3 -2
- package/dist/agent-src/commands/mode.md +1 -0
- package/dist/agent-src/commands/module/create.md +1 -0
- package/dist/agent-src/commands/module/explore.md +1 -0
- package/dist/agent-src/commands/module.md +1 -0
- package/dist/agent-src/commands/optimize/agents-dir.md +1 -0
- package/dist/agent-src/commands/optimize/augmentignore.md +1 -0
- package/dist/agent-src/commands/optimize/rtk.md +1 -0
- package/dist/agent-src/commands/optimize/skills.md +1 -0
- package/dist/agent-src/commands/optimize-prompt.md +1 -0
- package/dist/agent-src/commands/optimize.md +1 -0
- package/dist/agent-src/commands/orchestrate.md +1 -0
- package/dist/agent-src/commands/override/create.md +1 -0
- package/dist/agent-src/commands/override/manage.md +1 -0
- package/dist/agent-src/commands/override.md +1 -0
- package/dist/agent-src/commands/package-reset.md +1 -0
- package/dist/agent-src/commands/package-test.md +1 -0
- package/dist/agent-src/commands/post-as/ghostwriter.md +1 -0
- package/dist/agent-src/commands/post-as/me.md +1 -0
- package/dist/agent-src/commands/post-as.md +1 -0
- package/dist/agent-src/commands/pr/create/description-only.md +1 -0
- package/dist/agent-src/commands/pr/create.md +25 -0
- package/dist/agent-src/commands/prediction-pool.md +1 -0
- package/dist/agent-src/commands/prepare-for-review.md +1 -0
- package/dist/agent-src/commands/profile/activate.md +1 -0
- package/dist/agent-src/commands/profile/deactivate.md +1 -0
- package/dist/agent-src/commands/profile/show.md +1 -0
- package/dist/agent-src/commands/profile.md +1 -0
- package/dist/agent-src/commands/project-analyze.md +1 -0
- package/dist/agent-src/commands/project-health.md +1 -0
- package/dist/agent-src/commands/quality-fix.md +1 -0
- package/dist/agent-src/commands/refine-ticket.md +1 -0
- package/dist/agent-src/commands/research/deep.md +1 -0
- package/dist/agent-src/commands/research/report.md +1 -0
- package/dist/agent-src/commands/research.md +1 -0
- package/dist/agent-src/commands/review-changes.md +1 -0
- package/dist/agent-src/commands/review-routing.md +1 -0
- package/dist/agent-src/commands/roadmap/ai-council.md +1 -0
- package/dist/agent-src/commands/roadmap/create.md +1 -0
- package/dist/agent-src/commands/roadmap/process-full.md +1 -0
- package/dist/agent-src/commands/roadmap/process-phase.md +1 -0
- package/dist/agent-src/commands/roadmap/process-step.md +1 -0
- package/dist/agent-src/commands/roadmap.md +1 -0
- package/dist/agent-src/commands/rule-compliance-audit.md +1 -0
- package/dist/agent-src/commands/security-audit-config.md +84 -0
- package/dist/agent-src/commands/set-cost-profile.md +1 -0
- package/dist/agent-src/commands/skill/preview.md +1 -0
- package/dist/agent-src/commands/skill.md +1 -0
- package/dist/agent-src/commands/skills/discover.md +1 -0
- package/dist/agent-src/commands/skills.md +1 -0
- package/dist/agent-src/commands/sync-agent-settings.md +1 -0
- package/dist/agent-src/commands/sync-gitignore/fix.md +1 -0
- package/dist/agent-src/commands/sync-gitignore.md +1 -0
- package/dist/agent-src/commands/tests/create.md +1 -0
- package/dist/agent-src/commands/tests/execute.md +1 -0
- package/dist/agent-src/commands/tests.md +1 -0
- package/dist/agent-src/commands/threat-model.md +1 -0
- package/dist/agent-src/commands/update-form-request-messages.md +1 -0
- package/dist/agent-src/commands/upstream-contribute.md +1 -0
- package/dist/agent-src/commands/video/from-script.md +1 -0
- package/dist/agent-src/commands/video/from-song.md +1 -0
- package/dist/agent-src/commands/video/scene.md +1 -0
- package/dist/agent-src/commands/video/stitch.md +1 -0
- package/dist/agent-src/commands/video/storyboard.md +1 -0
- package/dist/agent-src/commands/video.md +1 -0
- package/dist/agent-src/commands/work.md +1 -0
- package/dist/agent-src/contexts/augment-infrastructure.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +2 -2
- package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +6 -6
- package/dist/agent-src/contexts/contracts/consumer-agents-md-guide.md +2 -2
- package/dist/agent-src/contexts/execution/rdp-gate.md +75 -0
- package/dist/agent-src/contexts/subagent-configuration.md +1 -0
- package/dist/agent-src/personas/advisors/contrarian.md +1 -1
- package/dist/agent-src/personas/advisors/executor.md +1 -1
- package/dist/agent-src/personas/advisors/expansionist.md +1 -1
- package/dist/agent-src/personas/advisors/first-principles.md +1 -1
- package/dist/agent-src/personas/advisors/outsider.md +1 -1
- package/dist/agent-src/rules/autonomous-execution.md +12 -0
- package/dist/agent-src/rules/external-reference-deep-dive.md +1 -1
- package/dist/agent-src/rules/git-history-discipline.md +47 -1
- package/dist/agent-src/rules/improve-before-implement.md +12 -0
- package/dist/agent-src/rules/lethal-trifecta-guard.md +80 -0
- package/dist/agent-src/rules/no-pr-progress-comments.md +3 -4
- package/dist/agent-src/rules/notes-first-reasoning.md +71 -0
- package/dist/agent-src/rules/roadmap-progress-sync.md +48 -31
- package/dist/agent-src/rules/security-sensitive-stop.md +14 -1
- package/dist/agent-src/rules/source-confidentiality.md +97 -0
- package/dist/agent-src/rules/think-before-action.md +9 -1
- package/dist/agent-src/rules/untrusted-input-defense.md +76 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.py +171 -0
- package/dist/agent-src/skills/adversarial-review/SKILL.md +14 -0
- package/dist/agent-src/skills/agent-security-review/SKILL.md +113 -0
- package/dist/agent-src/skills/agent-security-review/evals/triggers.json +51 -0
- package/dist/agent-src/skills/ai-council/SKILL.md +3 -3
- package/dist/agent-src/skills/async-python-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +12 -11
- package/dist/agent-src/skills/command-routing/SKILL.md +1 -1
- package/dist/agent-src/skills/complexity-first-planning/SKILL.md +96 -0
- package/dist/agent-src/skills/complexity-first-planning/evals/triggers.json +16 -0
- package/dist/agent-src/skills/copilot-config/SKILL.md +3 -4
- package/dist/agent-src/skills/defense-in-depth/SKILL.md +1 -1
- package/dist/agent-src/skills/developer-like-execution/SKILL.md +5 -4
- package/dist/agent-src/skills/error-handling-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/feature-planning/SKILL.md +2 -2
- package/dist/agent-src/skills/mcp-builder/SKILL.md +1 -1
- package/dist/agent-src/skills/memory-consolidation/SKILL.md +63 -17
- package/dist/agent-src/skills/prompt-engineering-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/readme-writing-package/SKILL.md +1 -1
- package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +119 -0
- package/dist/agent-src/skills/reasoning-orchestrator/evals/triggers.json +16 -0
- package/dist/agent-src/skills/receiving-code-review/SKILL.md +6 -6
- package/dist/agent-src/skills/refine-prompt/SKILL.md +1 -1
- package/dist/agent-src/skills/refine-ticket/SKILL.md +1 -1
- package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
- package/dist/agent-src/skills/secrets-management/SKILL.md +1 -1
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +10 -3
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +1 -1
- package/dist/agent-src/skills/token-optimizer/SKILL.md +1 -1
- package/dist/agent-src/templates/agents/.gitattributes.fragment +0 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +4 -4
- package/dist/agent-src/templates/scripts/check_memory.py +1 -2
- package/dist/agent-src/templates/scripts/check_memory_proposal.py +1 -1
- package/dist/agent-src/templates/scripts/memory_lookup.py +148 -289
- package/dist/agent-src/templates/scripts/memory_report.py +132 -2
- package/dist/agent-src/templates/scripts/memory_signal.py +7 -9
- package/dist/agent-src/templates/scripts/memory_status.py +25 -206
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/memory.py +6 -6
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/_passthrough.py +3 -3
- package/dist/agent-src/templates/scripts/work_engine/scoring/memory_visibility.py +0 -1
- package/dist/cli/agent-config.js +31 -300
- package/dist/cli/agent-config.js.map +1 -1
- package/dist/cli/commands/commands.js +10 -5
- package/dist/cli/commands/commands.js.map +1 -1
- package/dist/cli/discovery/loadManifest.js.map +1 -1
- package/dist/cli/main.js +309 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +645 -342
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +8 -5
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +149 -37
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +61 -36
- package/dist/mcp/registry-manifest.json +4 -4
- package/dist/router.json +1 -1
- package/dist/server/routes/wizard.js +4 -3
- package/dist/server/routes/wizard.js.map +1 -1
- package/dist/server/schemas/settings.js +18 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/docs/MIGRATION.md +1 -1
- package/docs/adrs/cost/0001-hard-stop-hook.md +5 -5
- package/docs/adrs/memory/0001-consumer-side-snapshot.md +15 -7
- package/docs/adrs/memory/README.md +6 -5
- package/docs/adrs/router/0001-three-tier-routing.md +2 -2
- package/docs/adrs/schema/0001-json-schema-frontmatter.md +2 -2
- package/docs/adrs/smoke/0001-per-tier-smoke-scripts.md +5 -5
- package/docs/adrs/telegraph/0001-default-off-until-bench.md +3 -3
- package/docs/architecture.md +9 -9
- package/docs/archive/CHANGELOG-pre-2.2.0.md +30 -30
- package/docs/archive/CHANGELOG-pre-2.25.0.md +1 -1
- package/docs/archive/CHANGELOG-pre-4.5.0.md +1 -1
- package/docs/archive/CHANGELOG-pre-6.0.0.md +473 -0
- package/docs/benchmark.md +54 -53
- package/docs/benchmarks.md +2 -2
- package/docs/case-studies/{frontend-design-vs-ui-ux-pro-max.md → frontend-design-positioning.md} +4 -4
- package/docs/catalog.md +20 -13
- package/docs/command-flows.md +90 -92
- package/docs/contracts/adr-layout.md +2 -3
- package/docs/contracts/adr-level-6-productization.md +1 -1
- package/docs/contracts/ai-council-config.md +42 -7
- package/docs/contracts/command-clusters.md +1 -1
- package/docs/contracts/cost-enforcement.md +1 -1
- package/docs/contracts/cost-summary-schema.md +1 -1
- package/docs/contracts/daily-workspace.md +1 -0
- package/docs/contracts/discovery-manifest.schema.json +4 -2
- package/docs/contracts/explain-modes.md +1 -1
- package/docs/contracts/implement-ticket-flow.md +6 -7
- package/docs/contracts/mcp-tool-inventory.md +10 -10
- package/docs/contracts/measurement-baseline.md +1 -1
- package/docs/contracts/memory-visibility-v1.md +1 -5
- package/docs/contracts/namespace.md +1 -1
- package/docs/contracts/persona-schema.md +1 -1
- package/docs/contracts/rule-interactions.md +1 -1
- package/docs/contracts/smoke-contracts.md +1 -1
- package/docs/contracts/universal-skills.md +0 -1
- package/docs/contracts/workspace-boundary.md +84 -0
- package/docs/customization.md +3 -3
- package/docs/decisions/ADR-009-event4u-namespace.md +1 -1
- package/docs/decisions/ADR-013-discovery-frontmatter-contract.md +1 -1
- package/docs/decisions/ADR-026-explain-mode-translation.md +1 -1
- package/docs/decisions/ADR-088-no-external-runtime-federation.md +26 -27
- package/docs/decisions/ADR-090-visibility-command-frontmatter-field.md +95 -0
- package/docs/decisions/ADR-091-split-meta-capability-packs.md +113 -0
- package/docs/decisions/ADR-092-defer-command-tier-alias-removal.md +93 -0
- package/docs/decisions/ADR-093-ai-council-config-user-global.md +111 -0
- package/docs/decisions/ADR-094-agent-memory-layer-removal.md +94 -0
- package/docs/decisions/ADR-095-workspace-boundary-contract.md +108 -0
- package/docs/decisions/INDEX.md +6 -0
- package/docs/development.md +5 -7
- package/docs/getting-started.md +4 -4
- package/docs/guidelines/agent-infra/5w2h-analysis.md +1 -1
- package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
- package/docs/guidelines/agent-infra/corpus-grounding-authoring.md +1 -1
- package/docs/guidelines/agent-infra/critical-thinking.md +1 -1
- package/docs/guidelines/agent-infra/engineering-memory-data-format.md +1 -5
- package/docs/guidelines/agent-infra/first-principles.md +1 -1
- package/docs/guidelines/agent-infra/frontier-reasoning-operating-profile.md +164 -0
- package/docs/guidelines/agent-infra/inversion-thinking.md +1 -1
- package/docs/guidelines/agent-infra/ios-simulator-guide.md +9 -14
- package/docs/guidelines/agent-infra/mcp-request-signing.md +19 -22
- package/docs/guidelines/agent-infra/memory-access.md +25 -31
- package/docs/guidelines/agent-infra/mental-models.md +1 -1
- package/docs/guidelines/agent-infra/model-recommendation.md +29 -0
- package/docs/guidelines/agent-infra/scqa-framework.md +3 -3
- package/docs/guidelines/agent-infra/security-lint-containment.md +81 -0
- package/docs/guidelines/agent-infra/six-hats.md +1 -1
- package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
- package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +72 -0
- package/docs/installation.md +1 -1
- package/docs/mcp.md +2 -2
- package/docs/parity/{bench-ruflo.json → bench-external.json} +10 -10
- package/docs/parity/{ruflo.md → external-runtime.md} +9 -9
- package/docs/quality.md +3 -3
- package/docs/safety.md +3 -3
- package/docs/skills-catalog.md +4 -1
- package/llms.txt +3 -0
- package/package.json +1 -1
- package/src/config/agent-settings.template.yml +65 -3
- package/src/config/discovery/packs.yml +29 -0
- package/src/config/discovery/workspaces.yml +3 -1
- package/src/config/gitignore-block.txt +6 -0
- package/src/scripts/__pycache__/validate_frontmatter.cpython-312.pyc +0 -0
- package/src/scripts/_cli/cmd_doctor.py +99 -13
- package/src/scripts/_lib/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/scripts/_lib/__pycache__/agent_src.cpython-312.pyc +0 -0
- package/src/scripts/_lib/bench_ab_scoring_v2.py +227 -0
- package/src/scripts/_lib/global_deploy_inventory.py +39 -9
- package/src/scripts/_lib/link_crypto.py +206 -0
- package/src/scripts/_lib/security_lint.py +228 -0
- package/src/scripts/ai_council/clients.py +2 -2
- package/src/scripts/ai_council/config.py +55 -0
- package/src/scripts/audit_adr_coverage.py +0 -2
- package/src/scripts/audit_command_surface.py +18 -5
- package/src/scripts/audit_mcp_tools.py +2 -2
- package/src/scripts/audit_skill_descriptions.py +2 -2
- package/src/scripts/bench_ab_clone.py +62 -12
- package/src/scripts/bench_ab_task_runner.py +475 -30
- package/src/scripts/bench_ab_v2_run.py +247 -0
- package/src/scripts/bench_ab_v2_stats.py +347 -0
- package/src/scripts/bench_run.py +1 -1
- package/src/scripts/build_discovery_manifest.py +10 -0
- package/src/scripts/check_bite_sized_granularity.py +1 -2
- package/src/scripts/check_memory.py +49 -63
- package/src/scripts/check_memory_proposal.py +1 -1
- package/src/scripts/check_no_external_sources.py +101 -0
- package/src/scripts/check_references.py +2 -0
- package/src/scripts/cost_by_conversation.py +1 -1
- package/src/scripts/council_cli.py +28 -14
- package/src/scripts/external_sources_denylist.json +91 -0
- package/src/scripts/hook_manifest.yaml +14 -6
- package/src/scripts/injection_scan_hook.py +145 -0
- package/src/scripts/install-hooks.sh +11 -0
- package/src/scripts/install.py +88 -13
- package/src/scripts/lint_agent_security.py +112 -0
- package/src/scripts/lint_bench_ab.py +5 -4
- package/src/scripts/lint_command_tiers.py +63 -22
- package/src/scripts/lint_discovery_vocabulary.py +2 -0
- package/src/scripts/lint_empty_roadmaps.py +80 -0
- package/src/scripts/lint_hidden_unicode.py +132 -0
- package/src/scripts/lint_instruction_smuggling.py +107 -0
- package/src/scripts/lint_marketplace.py +1 -1
- package/src/scripts/lint_mcp_config_security.py +124 -0
- package/src/scripts/lint_skill_frontmatter_safety.py +144 -0
- package/src/scripts/lint_workspace_boundary.py +122 -0
- package/src/scripts/mcp_server/consumer_tool_catalog.json +2 -3
- package/src/scripts/mcp_server/tools.py +8 -32
- package/src/scripts/memory_lookup.py +27 -296
- package/src/scripts/memory_report.py +1 -23
- package/src/scripts/memory_signal.py +6 -53
- package/src/scripts/memory_status.py +25 -206
- package/src/scripts/mine_session.py +118 -41
- package/src/scripts/pack_dependency_allowlist.json +2 -2
- package/src/scripts/render_benchmark_md.py +141 -52
- package/src/scripts/schemas/command.schema.json +6 -1
- package/src/scripts/security_audit_config.py +153 -0
- package/dist/agent-src/commands/chat-history/learn.md +0 -184
- package/dist/agent-src/commands/chat-history/show.md +0 -113
- package/dist/agent-src/commands/fix/pr-bot-comments.md +0 -157
- package/dist/agent-src/commands/fix/pr-developer-comments.md +0 -163
- package/dist/agent-src/templates/agents/memory/architecture-decisions.example.yml +0 -95
- package/docs/contracts/agent-memory-contract.md +0 -159
|
@@ -1,28 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
2
|
+
"""File-first memory retrieval.
|
|
3
3
|
|
|
4
4
|
Implements the shared `retrieve(types, keys, limit)` abstraction used
|
|
5
5
|
by skills. Reads YAML under `agents/memory/<type>/` (curated, hand-
|
|
6
6
|
reviewed) and JSONL under `agents/memory/intake/*.jsonl` (agent-written,
|
|
7
|
-
append-only, supersede-chain aware)
|
|
7
|
+
append-only, supersede-chain aware), plus user-ingested `knowledge`
|
|
8
|
+
chunks and opted-in `cross-repo` matches.
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
through the package's semantic CLI. Repo entries always win on
|
|
13
|
-
conflict — see `_apply_conflict_rule`.
|
|
10
|
+
Retrieval is entirely repo-side and file-backed — there is no external
|
|
11
|
+
backend. (The former optional `@event4u/agent-memory` package routing
|
|
12
|
+
was removed; see `docs/decisions/` for the agent-memory removal ADR.)
|
|
14
13
|
|
|
15
14
|
Usage:
|
|
16
15
|
python3 scripts/memory_lookup.py --types domain-invariants,ownership \\
|
|
17
16
|
--key "app/Http/Controllers/Foo" --limit 5
|
|
18
17
|
python3 scripts/memory_lookup.py --types incident-learnings --format json
|
|
19
|
-
python3 scripts/memory_lookup.py --types ownership --key billing --auto
|
|
20
18
|
|
|
21
|
-
from scripts.memory_lookup import retrieve
|
|
22
|
-
hits = retrieve(
|
|
23
|
-
types=["ownership"], keys=["app/Http"], limit=3,
|
|
24
|
-
operational_provider=package_operational_provider(),
|
|
25
|
-
)
|
|
19
|
+
from scripts.memory_lookup import retrieve
|
|
20
|
+
hits = retrieve(types=["ownership"], keys=["app/Http"], limit=3)
|
|
26
21
|
"""
|
|
27
22
|
|
|
28
23
|
from __future__ import annotations
|
|
@@ -30,12 +25,10 @@ from __future__ import annotations
|
|
|
30
25
|
import argparse
|
|
31
26
|
import fnmatch
|
|
32
27
|
import json
|
|
33
|
-
import os
|
|
34
|
-
import subprocess
|
|
35
28
|
import sys
|
|
36
29
|
from dataclasses import dataclass, asdict, field
|
|
37
30
|
from pathlib import Path
|
|
38
|
-
from typing import
|
|
31
|
+
from typing import Iterable, Union
|
|
39
32
|
|
|
40
33
|
MEMORY_ROOT = Path("agents/memory")
|
|
41
34
|
INTAKE_ROOT = MEMORY_ROOT / "intake"
|
|
@@ -45,15 +38,13 @@ CURATED_TYPES = {
|
|
|
45
38
|
"ownership",
|
|
46
39
|
"historical-patterns",
|
|
47
40
|
"domain-invariants",
|
|
48
|
-
"architecture-decisions",
|
|
49
41
|
"incident-learnings",
|
|
50
42
|
"product-rules",
|
|
51
43
|
}
|
|
52
44
|
|
|
53
45
|
# `knowledge` is its own type: user-ingested local documents that live
|
|
54
46
|
# under `agents/memory/knowledge/<ingest-id>/chunks/*.md`. They are
|
|
55
|
-
# repo-side (file-backed) but not "curated" and not intake
|
|
56
|
-
# conflict rule still treats them as repo entries against operational.
|
|
47
|
+
# repo-side (file-backed) but not "curated" and not intake.
|
|
57
48
|
KNOWLEDGE_TYPE = "knowledge"
|
|
58
49
|
|
|
59
50
|
# Cross-repo retrieval (road-to-leaner-core-and-discovery Phase 4). When this
|
|
@@ -70,7 +61,7 @@ CROSS_REPO_TYPE = "cross-repo"
|
|
|
70
61
|
class Hit:
|
|
71
62
|
id: str
|
|
72
63
|
type: str
|
|
73
|
-
source: str # "curated" | "intake" | "
|
|
64
|
+
source: str # "curated" | "intake" | "knowledge" | "cross-repo"
|
|
74
65
|
path: str # file (or logical locator) that produced the hit
|
|
75
66
|
score: float # naive, content-match based [0..1]
|
|
76
67
|
entry: dict = field(default_factory=dict)
|
|
@@ -79,36 +70,13 @@ class Hit:
|
|
|
79
70
|
return asdict(self)
|
|
80
71
|
|
|
81
72
|
|
|
82
|
-
@dataclass
|
|
83
|
-
class Shadow:
|
|
84
|
-
"""An operational entry suppressed by the conflict rule."""
|
|
85
|
-
id: str
|
|
86
|
-
type: str
|
|
87
|
-
reason: str # "same-id" | "repo-deprecated"
|
|
88
|
-
operational_path: str # where the suppressed entry came from
|
|
89
|
-
repo_path: str # repo entry that shadowed it
|
|
90
|
-
|
|
91
|
-
def as_dict(self) -> dict:
|
|
92
|
-
return asdict(self)
|
|
93
|
-
|
|
94
|
-
|
|
95
73
|
@dataclass
|
|
96
74
|
class RetrievalResult:
|
|
97
|
-
"""Full retrieval payload
|
|
75
|
+
"""Full retrieval payload."""
|
|
98
76
|
hits: list
|
|
99
|
-
shadows: list = field(default_factory=list)
|
|
100
77
|
|
|
101
78
|
def as_dict(self) -> dict:
|
|
102
|
-
return {
|
|
103
|
-
"hits": [h.as_dict() for h in self.hits],
|
|
104
|
-
"shadows": [s.as_dict() for s in self.shadows],
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
# An operational provider returns repo-shaped Hit objects with
|
|
109
|
-
# source="operational". Backend adapters (e.g. @event4u/agent-memory)
|
|
110
|
-
# are expected to translate their native payload into this shape.
|
|
111
|
-
OperationalProvider = Callable[[list[str], list[str]], Iterable[Hit]]
|
|
79
|
+
return {"hits": [h.as_dict() for h in self.hits]}
|
|
112
80
|
|
|
113
81
|
|
|
114
82
|
def _load_yaml(path: Path):
|
|
@@ -238,8 +206,7 @@ def _iter_knowledge_entries() -> Iterable[tuple[Path, dict]]:
|
|
|
238
206
|
def _score(entry: dict, keys: list[str]) -> float:
|
|
239
207
|
"""Naive relevance score: max over keys of (glob-match | substring).
|
|
240
208
|
|
|
241
|
-
Good enough for
|
|
242
|
-
The `present` path returns a real score from agent-memory.
|
|
209
|
+
Good enough for best-effort file retrieval.
|
|
243
210
|
"""
|
|
244
211
|
if not keys:
|
|
245
212
|
return 0.1 # any hit beats no hit when there is no key
|
|
@@ -261,170 +228,6 @@ def _score(entry: dict, keys: list[str]) -> float:
|
|
|
261
228
|
return best
|
|
262
229
|
|
|
263
230
|
|
|
264
|
-
def _apply_conflict_rule(
|
|
265
|
-
repo_hits: list[Hit],
|
|
266
|
-
operational_hits: list[Hit],
|
|
267
|
-
) -> tuple[list[Hit], list[Shadow]]:
|
|
268
|
-
"""Enforce REPO WINS / OPERATIONAL AUGMENTS / NEVER CONTRADICTS SILENTLY.
|
|
269
|
-
|
|
270
|
-
Reference: `agents/roadmaps/road-to-memory-self-consumption.md` §
|
|
271
|
-
"Conflict rule: repo vs. operational". The four cases mapped below
|
|
272
|
-
are covered by `tests/test_conflict_rule.py`.
|
|
273
|
-
"""
|
|
274
|
-
# Repo entries index — curated AND intake both count as "repo" for
|
|
275
|
-
# the conflict rule. The operational store is the only non-repo side.
|
|
276
|
-
repo_by_id: dict[str, Hit] = {h.id: h for h in repo_hits if h.id}
|
|
277
|
-
|
|
278
|
-
merged: list[Hit] = list(repo_hits)
|
|
279
|
-
shadows: list[Shadow] = []
|
|
280
|
-
|
|
281
|
-
for op in operational_hits:
|
|
282
|
-
if op.id and op.id in repo_by_id:
|
|
283
|
-
# Case 1+2: same id → repo wins (including when repo is
|
|
284
|
-
# status:deprecated — operational cannot revive a retired
|
|
285
|
-
# entry). Suppress the operational entry and record shadow.
|
|
286
|
-
repo = repo_by_id[op.id]
|
|
287
|
-
reason = (
|
|
288
|
-
"repo-deprecated"
|
|
289
|
-
if repo.entry.get("status") == "deprecated"
|
|
290
|
-
else "same-id"
|
|
291
|
-
)
|
|
292
|
-
shadows.append(Shadow(
|
|
293
|
-
id=op.id,
|
|
294
|
-
type=op.type,
|
|
295
|
-
reason=reason,
|
|
296
|
-
operational_path=op.path,
|
|
297
|
-
repo_path=repo.path,
|
|
298
|
-
))
|
|
299
|
-
continue
|
|
300
|
-
# Case 3 (different ids on same logical key) and Case 4 (repo
|
|
301
|
-
# has no entry) — both simply include the operational hit.
|
|
302
|
-
# Repo entries naturally rank higher because their score is not
|
|
303
|
-
# discounted (see _score / operational scoring in retrieve()).
|
|
304
|
-
merged.append(op)
|
|
305
|
-
|
|
306
|
-
return merged, shadows
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
# ---------------------------------------------------------------------------
|
|
310
|
-
# Package-backed operational provider (the `present` path)
|
|
311
|
-
# ---------------------------------------------------------------------------
|
|
312
|
-
#
|
|
313
|
-
# When `memory_status.status() == "present"` the consumer-facing contract
|
|
314
|
-
# says retrieval should route through `@event4u/agent-memory`. The package
|
|
315
|
-
# CLI is purely **semantic** (`memory retrieve <query> --type T …`); the
|
|
316
|
-
# shared `retrieve(types, keys, …)` API is **key-based**. The hybrid
|
|
317
|
-
# resolution agreed in `docs/contracts/agent-memory-contract.md` synthesises
|
|
318
|
-
# `keys` into a single natural-language query for the package call, while
|
|
319
|
-
# the file fallback continues to do glob/substring matching on the same
|
|
320
|
-
# keys. Both legs land in the same `Hit` shape so the conflict rule can
|
|
321
|
-
# merge them transparently.
|
|
322
|
-
|
|
323
|
-
_CLI_TIMEOUT_SECONDS = 5.0
|
|
324
|
-
_CLI_RETRIEVE_LIMIT_DEFAULT = 20
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
def _synthesize_query(keys: list[str]) -> str:
|
|
328
|
-
"""Turn a list of retrieval keys into one natural-language query.
|
|
329
|
-
|
|
330
|
-
Keys are typically file paths (`app/Http/Controllers/Foo`), feature
|
|
331
|
-
names (`billing`), or short identifiers — joining them with spaces
|
|
332
|
-
gives the package's semantic search enough surface to score against
|
|
333
|
-
without inventing structure. Empty or whitespace-only keys are
|
|
334
|
-
dropped; if nothing remains the caller falls back to the file path.
|
|
335
|
-
"""
|
|
336
|
-
cleaned = [k.strip() for k in keys if isinstance(k, str) and k.strip()]
|
|
337
|
-
return " ".join(cleaned)
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
def _cli_operational_provider(
|
|
341
|
-
types: list[str],
|
|
342
|
-
keys: list[str],
|
|
343
|
-
*,
|
|
344
|
-
cli_path: str = "memory",
|
|
345
|
-
timeout: float = _CLI_TIMEOUT_SECONDS,
|
|
346
|
-
limit: int = _CLI_RETRIEVE_LIMIT_DEFAULT,
|
|
347
|
-
) -> Iterable[Hit]:
|
|
348
|
-
"""Run `memory retrieve` and yield operational `Hit` objects.
|
|
349
|
-
|
|
350
|
-
Pino structured logs from the package go to stderr; stdout is a
|
|
351
|
-
clean v1 retrieval envelope. Any non-zero exit, timeout, or parse
|
|
352
|
-
failure degrades to "no operational hits" — `retrieve()` already
|
|
353
|
-
treats provider exceptions as a soft warning, so the caller still
|
|
354
|
-
gets the file-fallback result.
|
|
355
|
-
"""
|
|
356
|
-
query = _synthesize_query(keys)
|
|
357
|
-
if not query:
|
|
358
|
-
return
|
|
359
|
-
cmd: list[str] = [cli_path, "retrieve", query, "--limit", str(limit)]
|
|
360
|
-
for t in types:
|
|
361
|
-
cmd.extend(["--type", t])
|
|
362
|
-
try:
|
|
363
|
-
out = subprocess.run(
|
|
364
|
-
cmd,
|
|
365
|
-
capture_output=True, text=True, timeout=timeout,
|
|
366
|
-
)
|
|
367
|
-
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
368
|
-
return
|
|
369
|
-
if out.returncode != 0:
|
|
370
|
-
return
|
|
371
|
-
try:
|
|
372
|
-
envelope = json.loads(out.stdout)
|
|
373
|
-
except (ValueError, TypeError):
|
|
374
|
-
return
|
|
375
|
-
entries = envelope.get("entries") if isinstance(envelope, dict) else None
|
|
376
|
-
if not isinstance(entries, list):
|
|
377
|
-
return
|
|
378
|
-
for e in entries:
|
|
379
|
-
if not isinstance(e, dict):
|
|
380
|
-
continue
|
|
381
|
-
eid = e.get("id")
|
|
382
|
-
etype = e.get("type")
|
|
383
|
-
if not isinstance(eid, str) or not isinstance(etype, str):
|
|
384
|
-
continue
|
|
385
|
-
# The package returns `confidence` (0..1) per the v1 envelope;
|
|
386
|
-
# map it onto our internal `score` field so the conflict rule
|
|
387
|
-
# and ranking work uniformly across providers.
|
|
388
|
-
try:
|
|
389
|
-
score = float(e.get("confidence", 0.0))
|
|
390
|
-
except (TypeError, ValueError):
|
|
391
|
-
score = 0.0
|
|
392
|
-
body = e.get("body") if isinstance(e.get("body"), dict) else {}
|
|
393
|
-
yield Hit(
|
|
394
|
-
id=eid,
|
|
395
|
-
type=etype,
|
|
396
|
-
source="operational",
|
|
397
|
-
path=f"agent-memory:{eid}",
|
|
398
|
-
score=score,
|
|
399
|
-
entry=body,
|
|
400
|
-
)
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
def package_operational_provider() -> Optional[OperationalProvider]:
|
|
404
|
-
"""Return a CLI-backed provider when the package is `present`, else None.
|
|
405
|
-
|
|
406
|
-
Callers who want automatic backend routing pass the result directly
|
|
407
|
-
to :func:`retrieve` — `None` is a safe value that yields file-only
|
|
408
|
-
retrieval, so this is the recommended one-liner for skills:
|
|
409
|
-
|
|
410
|
-
retrieve(types, keys, operational_provider=package_operational_provider())
|
|
411
|
-
|
|
412
|
-
The status probe is bounded (≤ 2s, cached per process) — see
|
|
413
|
-
`scripts/memory_status.py`. We import lazily so pure file-fallback
|
|
414
|
-
callers never pay for the probe.
|
|
415
|
-
"""
|
|
416
|
-
# Late import: keeps `memory_lookup` importable even when
|
|
417
|
-
# `memory_status` is missing in stripped consumer installs.
|
|
418
|
-
try:
|
|
419
|
-
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
420
|
-
import memory_status # type: ignore[import-not-found]
|
|
421
|
-
except ImportError:
|
|
422
|
-
return None
|
|
423
|
-
if memory_status.status().status != "present":
|
|
424
|
-
return None
|
|
425
|
-
return _cli_operational_provider
|
|
426
|
-
|
|
427
|
-
|
|
428
231
|
def _cross_repo_hits(keys: list[str], limit: int) -> list[Hit]:
|
|
429
232
|
"""Project cross-repo matches into discounted, tagged Hits.
|
|
430
233
|
|
|
@@ -468,20 +271,13 @@ def retrieve(
|
|
|
468
271
|
types: list[str],
|
|
469
272
|
keys: list[str],
|
|
470
273
|
limit: int = 5,
|
|
471
|
-
|
|
472
|
-
with_shadows: bool = False,
|
|
473
|
-
) -> Union[list[Hit], RetrievalResult]:
|
|
274
|
+
) -> list[Hit]:
|
|
474
275
|
"""Return up to `limit` hits across the requested types, highest score first.
|
|
475
276
|
|
|
476
277
|
Repo entries (curated + intake) are preferred on ties — they are
|
|
477
|
-
hand-reviewed or session-captured against the repo itself.
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
REPO WINS conflict rule; suppressed operational entries surface as
|
|
481
|
-
`shadows` when `with_shadows=True`.
|
|
482
|
-
|
|
483
|
-
The return type stays `list[Hit]` by default for backward
|
|
484
|
-
compatibility with existing skill call sites.
|
|
278
|
+
hand-reviewed or session-captured against the repo itself. Knowledge
|
|
279
|
+
and cross-repo hits are discounted so the project's own truth wins on
|
|
280
|
+
equal relevance.
|
|
485
281
|
"""
|
|
486
282
|
repo_hits: list[Hit] = []
|
|
487
283
|
for mtype in types:
|
|
@@ -527,27 +323,9 @@ def retrieve(
|
|
|
527
323
|
entry=entry,
|
|
528
324
|
))
|
|
529
325
|
|
|
530
|
-
|
|
531
|
-
if
|
|
532
|
-
|
|
533
|
-
for oh in operational_provider(list(types), list(keys)) or []:
|
|
534
|
-
# Discount operational vs curated/intake so repo ranks
|
|
535
|
-
# higher on equal relevance. Providers may already return
|
|
536
|
-
# trust-adjusted scores; we only apply a floor discount.
|
|
537
|
-
oh.score = min(oh.score, 0.85)
|
|
538
|
-
operational_hits.append(oh)
|
|
539
|
-
except Exception as exc: # noqa: BLE001 — providers are external
|
|
540
|
-
print(f"warning: operational_provider raised "
|
|
541
|
-
f"{exc.__class__.__name__}: {exc}", file=sys.stderr)
|
|
542
|
-
|
|
543
|
-
merged, shadows = _apply_conflict_rule(repo_hits, operational_hits)
|
|
544
|
-
merged.sort(key=lambda h: (h.score, h.source == "curated"), reverse=True)
|
|
545
|
-
positives = [h for h in merged if h.score > 0]
|
|
546
|
-
final_hits = (positives or merged)[:limit]
|
|
547
|
-
|
|
548
|
-
if with_shadows:
|
|
549
|
-
return RetrievalResult(hits=final_hits, shadows=shadows)
|
|
550
|
-
return final_hits
|
|
326
|
+
repo_hits.sort(key=lambda h: (h.score, h.source == "curated"), reverse=True)
|
|
327
|
+
positives = [h for h in repo_hits if h.score > 0]
|
|
328
|
+
return (positives or repo_hits)[:limit]
|
|
551
329
|
|
|
552
330
|
|
|
553
331
|
CONTRACT_VERSION = 1
|
|
@@ -561,7 +339,6 @@ def retrieve_v1(
|
|
|
561
339
|
types: list[str],
|
|
562
340
|
keys: list[str],
|
|
563
341
|
limit: int = 20,
|
|
564
|
-
operational_provider: Optional[OperationalProvider] = None,
|
|
565
342
|
) -> dict:
|
|
566
343
|
"""Return a v1 retrieval-contract envelope.
|
|
567
344
|
|
|
@@ -569,49 +346,27 @@ def retrieve_v1(
|
|
|
569
346
|
the shape defined by
|
|
570
347
|
``internal/schemas/retrieval-v1.schema.json``. Unknown types are reported as
|
|
571
348
|
``status: unknown_type`` for that slice only, rather than failing
|
|
572
|
-
the whole call.
|
|
349
|
+
the whole call. All entries are file-backed (``source: "repo"``).
|
|
573
350
|
"""
|
|
574
351
|
known = [t for t in types if t in _KNOWN_TYPES]
|
|
575
352
|
unknown = [t for t in types if t not in _KNOWN_TYPES]
|
|
576
353
|
|
|
577
|
-
|
|
578
|
-
operational_provider=operational_provider,
|
|
579
|
-
with_shadows=True)
|
|
580
|
-
assert isinstance(result, RetrievalResult)
|
|
581
|
-
hits, shadows = result.hits, result.shadows
|
|
582
|
-
shadow_by_id = {s.id: s for s in shadows if s.id}
|
|
354
|
+
hits = retrieve(known, keys, limit=limit)
|
|
583
355
|
|
|
584
356
|
slice_counts: dict[str, int] = {t: 0 for t in known}
|
|
585
357
|
entries: list[dict] = []
|
|
586
358
|
for h in hits:
|
|
587
|
-
source = "operational" if h.source == "operational" else "repo"
|
|
588
359
|
envelope_entry: dict = {
|
|
589
360
|
"id": h.id,
|
|
590
361
|
"type": h.type,
|
|
591
|
-
"source":
|
|
362
|
+
"source": "repo",
|
|
592
363
|
"confidence": round(float(h.score), 4),
|
|
593
364
|
"body": dict(h.entry) if isinstance(h.entry, dict) else {},
|
|
594
|
-
"shadowed_by": None,
|
|
595
365
|
}
|
|
596
366
|
if h.type in slice_counts:
|
|
597
367
|
slice_counts[h.type] += 1
|
|
598
368
|
entries.append(envelope_entry)
|
|
599
369
|
|
|
600
|
-
# Surface shadowed operational entries as additional entries carrying
|
|
601
|
-
# `shadowed_by`. The conformance harness checks that only
|
|
602
|
-
# source="operational" entries ever set this field.
|
|
603
|
-
for sid, s in shadow_by_id.items():
|
|
604
|
-
entries.append({
|
|
605
|
-
"id": sid,
|
|
606
|
-
"type": s.type,
|
|
607
|
-
"source": "operational",
|
|
608
|
-
"confidence": 0.0,
|
|
609
|
-
"body": {},
|
|
610
|
-
"shadowed_by": f"repo:{sid}",
|
|
611
|
-
})
|
|
612
|
-
if s.type in slice_counts:
|
|
613
|
-
slice_counts[s.type] += 1
|
|
614
|
-
|
|
615
370
|
slices: dict[str, dict] = {
|
|
616
371
|
t: {"status": "ok", "count": slice_counts.get(t, 0)}
|
|
617
372
|
for t in known
|
|
@@ -655,35 +410,18 @@ def main() -> int:
|
|
|
655
410
|
ap.add_argument("--envelope", choices=["legacy", "v1"], default="legacy",
|
|
656
411
|
help="Output shape: `legacy` (Hit list) or `v1` "
|
|
657
412
|
"(retrieval contract v1 envelope). `v1` implies JSON output.")
|
|
658
|
-
ap.add_argument("--with-shadows", action="store_true",
|
|
659
|
-
help="Include shadowed-operational entries in the output "
|
|
660
|
-
"(no-op until an operational backend is wired)")
|
|
661
|
-
ap.add_argument("--auto", action="store_true",
|
|
662
|
-
help="Auto-route to the @event4u/agent-memory package "
|
|
663
|
-
"when memory_status.status() == 'present'; "
|
|
664
|
-
"falls through to file-only retrieval otherwise")
|
|
665
413
|
args = ap.parse_args()
|
|
666
414
|
types = [t.strip() for t in args.types.split(",") if t.strip()]
|
|
667
415
|
if not types:
|
|
668
416
|
print("error: --types is required", file=sys.stderr)
|
|
669
417
|
return 2
|
|
670
|
-
op_provider = package_operational_provider() if args.auto else None
|
|
671
418
|
if args.envelope == "v1":
|
|
672
|
-
envelope = retrieve_v1(types, args.key, args.limit
|
|
673
|
-
operational_provider=op_provider)
|
|
419
|
+
envelope = retrieve_v1(types, args.key, args.limit)
|
|
674
420
|
print(json.dumps(envelope, indent=2, default=str))
|
|
675
421
|
return 0
|
|
676
|
-
|
|
677
|
-
operational_provider=op_provider,
|
|
678
|
-
with_shadows=args.with_shadows)
|
|
679
|
-
if args.with_shadows:
|
|
680
|
-
assert isinstance(result, RetrievalResult)
|
|
681
|
-
hits, shadows = result.hits, result.shadows
|
|
682
|
-
else:
|
|
683
|
-
hits, shadows = result, [] # type: ignore[assignment]
|
|
422
|
+
hits = retrieve(types, args.key, args.limit)
|
|
684
423
|
if args.format == "json":
|
|
685
|
-
payload = {"hits": [h.as_dict() for h in hits]
|
|
686
|
-
"shadows": [s.as_dict() for s in shadows]}
|
|
424
|
+
payload = {"hits": [h.as_dict() for h in hits]}
|
|
687
425
|
print(json.dumps(payload, indent=2, default=str))
|
|
688
426
|
else:
|
|
689
427
|
if not hits:
|
|
@@ -691,13 +429,6 @@ def main() -> int:
|
|
|
691
429
|
for h in hits:
|
|
692
430
|
print(f" [{h.source}] {h.type} score={h.score:.2f} "
|
|
693
431
|
f"id={h.id or '-'} path={h.path}")
|
|
694
|
-
if shadows:
|
|
695
|
-
print(f"\n shadows: {len(shadows)} operational entr"
|
|
696
|
-
f"{'y' if len(shadows) == 1 else 'ies'} suppressed by "
|
|
697
|
-
f"the conflict rule")
|
|
698
|
-
for s in shadows:
|
|
699
|
-
print(f" [{s.reason}] {s.type} id={s.id} "
|
|
700
|
-
f"op={s.operational_path} repo={s.repo_path}")
|
|
701
432
|
return 0
|
|
702
433
|
|
|
703
434
|
|
|
@@ -34,7 +34,7 @@ MEMORY_ROOT = Path("agents/memory")
|
|
|
34
34
|
INTAKE_ROOT = MEMORY_ROOT / "intake"
|
|
35
35
|
CURATED_TYPES = (
|
|
36
36
|
"ownership", "historical-patterns", "domain-invariants",
|
|
37
|
-
"
|
|
37
|
+
"incident-learnings", "product-rules",
|
|
38
38
|
)
|
|
39
39
|
|
|
40
40
|
# Role-mode marker grepped from session captures / reports / handoffs.
|
|
@@ -204,24 +204,6 @@ def _quarterly_stats() -> dict:
|
|
|
204
204
|
}
|
|
205
205
|
|
|
206
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
207
|
def _role_mode_stats() -> dict:
|
|
226
208
|
"""Count structured mode markers across session/report/handoff dirs.
|
|
227
209
|
|
|
@@ -263,13 +245,11 @@ def build_report() -> dict:
|
|
|
263
245
|
"status": status.status,
|
|
264
246
|
"backend": status.backend,
|
|
265
247
|
"reason": status.reason,
|
|
266
|
-
"cli_path": status.cli_path,
|
|
267
248
|
},
|
|
268
249
|
"intake": _intake_stats(),
|
|
269
250
|
"staleness": _staleness_report(),
|
|
270
251
|
"quarterly": _quarterly_stats(),
|
|
271
252
|
"role_modes": _role_mode_stats(),
|
|
272
|
-
"operational_store": _operational_store_stats(status.status),
|
|
273
253
|
}
|
|
274
254
|
|
|
275
255
|
|
|
@@ -316,8 +296,6 @@ def _print_text(report: dict) -> None:
|
|
|
316
296
|
if rm.get("unknown_modes"):
|
|
317
297
|
print(f" unknown: {', '.join(rm['unknown_modes'])} "
|
|
318
298
|
"(not in the six reserved slugs)")
|
|
319
|
-
if report["operational_store"]:
|
|
320
|
-
print("Operational-store: present (stats via agent-memory CLI)")
|
|
321
299
|
|
|
322
300
|
|
|
323
301
|
def main() -> int:
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"""Write-side helper: drop an engineering-memory signal.
|
|
3
3
|
|
|
4
4
|
Shared by producers (`/bug-fix`, `/do-and-judge`, `/propose-memory`,
|
|
5
|
-
incident role exit).
|
|
6
|
-
`
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
incident role exit). Appends an intake line under
|
|
6
|
+
`agents/memory/intake/signals-YYYY-MM.jsonl` — append-only JSONL with
|
|
7
|
+
`merge=union` (see `road-to-memory-merge-safety.md`). Memory is entirely
|
|
8
|
+
file-backed (no external backend).
|
|
9
9
|
|
|
10
10
|
Rate limiting:
|
|
11
11
|
- Per-path, per-type, within a rolling window (default 7 days).
|
|
@@ -37,49 +37,11 @@ VALID_TYPES = {
|
|
|
37
37
|
"incident-learnings",
|
|
38
38
|
"ownership",
|
|
39
39
|
"domain-invariants",
|
|
40
|
-
"architecture-decisions",
|
|
41
40
|
"product-rules",
|
|
42
41
|
}
|
|
43
42
|
RATE_LIMIT_WINDOW_DAYS = 7
|
|
44
43
|
|
|
45
44
|
|
|
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
|
-
Centralized loader (road-to-portable-dev-preferences P3): tolerance
|
|
54
|
-
contract handles missing file / malformed YAML / no PyYAML uniformly.
|
|
55
|
-
"""
|
|
56
|
-
try:
|
|
57
|
-
from scripts._lib.agent_settings import load_agent_settings
|
|
58
|
-
except ImportError: # pragma: no cover — script-style invocation
|
|
59
|
-
import sys as _sys
|
|
60
|
-
from pathlib import Path as _Path
|
|
61
|
-
_sys.path.insert(0, str(_Path(__file__).resolve().parent))
|
|
62
|
-
from _lib.agent_settings import load_agent_settings # type: ignore[import-not-found]
|
|
63
|
-
|
|
64
|
-
data = load_agent_settings(project_path=SETTINGS_FILE)
|
|
65
|
-
mem = data.get("memory")
|
|
66
|
-
if not isinstance(mem, dict):
|
|
67
|
-
return False
|
|
68
|
-
intake = mem.get("intake")
|
|
69
|
-
if not isinstance(intake, dict):
|
|
70
|
-
return False
|
|
71
|
-
return bool(intake.get("skip_when_present", False))
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def _backend_status() -> str:
|
|
75
|
-
"""Return the current backend status: 'present' | 'absent' | 'unknown'."""
|
|
76
|
-
try:
|
|
77
|
-
import memory_status # type: ignore
|
|
78
|
-
return memory_status.status().status
|
|
79
|
-
except Exception:
|
|
80
|
-
return "unknown"
|
|
81
|
-
|
|
82
|
-
|
|
83
45
|
def _now_iso() -> str:
|
|
84
46
|
return dt.datetime.now(dt.timezone.utc).isoformat(timespec="seconds")
|
|
85
47
|
|
|
@@ -137,10 +99,8 @@ def emit(entry_type: str, path: str, body: str,
|
|
|
137
99
|
force: bool = False) -> dict[str, Any] | None:
|
|
138
100
|
"""Append a signal entry. Returns the written record, or None when skipped.
|
|
139
101
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
Phase 3. For now, the file path is the single source of truth so
|
|
143
|
-
merge-safety is preserved in every mode.
|
|
102
|
+
The intake JSONL file is the single source of truth — memory is
|
|
103
|
+
entirely file-backed (no external backend).
|
|
144
104
|
"""
|
|
145
105
|
if entry_type not in VALID_TYPES:
|
|
146
106
|
raise ValueError(f"unknown memory type: {entry_type}")
|
|
@@ -160,13 +120,6 @@ def emit(entry_type: str, path: str, body: str,
|
|
|
160
120
|
# Reserved keys stay intact; extras only fill unclaimed slots.
|
|
161
121
|
for k, v in extra.items():
|
|
162
122
|
record.setdefault(k, v)
|
|
163
|
-
# Backend routing: when the `agent-memory` package is present AND
|
|
164
|
-
# the consumer opted out of the debug trail, skip the JSONL write.
|
|
165
|
-
# Otherwise the intake file stays the source of truth (and, when a
|
|
166
|
-
# backend is present, a replayable debug trail).
|
|
167
|
-
if _backend_status() == "present" and _skip_intake_when_present():
|
|
168
|
-
record["_backend"] = "package-only"
|
|
169
|
-
return record
|
|
170
123
|
INTAKE_ROOT.mkdir(parents=True, exist_ok=True)
|
|
171
124
|
target = _monthly_file()
|
|
172
125
|
with target.open("a", encoding="utf-8") as fh:
|