@accelerationguy/accel 1.0.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.md +19 -0
- package/LICENSE +33 -0
- package/README.md +275 -0
- package/bin/install.js +661 -0
- package/docs/getting-started.md +164 -0
- package/docs/module-guide.md +139 -0
- package/modules/drive/LICENSE +21 -0
- package/modules/drive/PAUL-VS-GSD.md +171 -0
- package/modules/drive/README.md +555 -0
- package/modules/drive/assets/terminal.svg +67 -0
- package/modules/drive/bin/install.js +210 -0
- package/modules/drive/integration.js +76 -0
- package/modules/drive/package.json +38 -0
- package/modules/drive/src/commands/add-phase.md +36 -0
- package/modules/drive/src/commands/apply.md +83 -0
- package/modules/drive/src/commands/assumptions.md +37 -0
- package/modules/drive/src/commands/audit.md +57 -0
- package/modules/drive/src/commands/complete-milestone.md +36 -0
- package/modules/drive/src/commands/config.md +175 -0
- package/modules/drive/src/commands/consider-issues.md +41 -0
- package/modules/drive/src/commands/discover.md +48 -0
- package/modules/drive/src/commands/discuss-milestone.md +33 -0
- package/modules/drive/src/commands/discuss.md +34 -0
- package/modules/drive/src/commands/flows.md +73 -0
- package/modules/drive/src/commands/handoff.md +201 -0
- package/modules/drive/src/commands/help.md +525 -0
- package/modules/drive/src/commands/init.md +54 -0
- package/modules/drive/src/commands/map-codebase.md +34 -0
- package/modules/drive/src/commands/milestone.md +34 -0
- package/modules/drive/src/commands/pause.md +44 -0
- package/modules/drive/src/commands/plan-fix.md +216 -0
- package/modules/drive/src/commands/plan.md +36 -0
- package/modules/drive/src/commands/progress.md +138 -0
- package/modules/drive/src/commands/register.md +29 -0
- package/modules/drive/src/commands/remove-phase.md +37 -0
- package/modules/drive/src/commands/research-phase.md +209 -0
- package/modules/drive/src/commands/research.md +47 -0
- package/modules/drive/src/commands/resume.md +49 -0
- package/modules/drive/src/commands/status.md +78 -0
- package/modules/drive/src/commands/unify.md +87 -0
- package/modules/drive/src/commands/verify.md +60 -0
- package/modules/drive/src/references/checkpoints.md +234 -0
- package/modules/drive/src/references/context-management.md +219 -0
- package/modules/drive/src/references/git-strategy.md +206 -0
- package/modules/drive/src/references/loop-phases.md +254 -0
- package/modules/drive/src/references/plan-format.md +263 -0
- package/modules/drive/src/references/quality-principles.md +152 -0
- package/modules/drive/src/references/research-quality-control.md +247 -0
- package/modules/drive/src/references/sonarqube-integration.md +244 -0
- package/modules/drive/src/references/specialized-workflow-integration.md +186 -0
- package/modules/drive/src/references/subagent-criteria.md +179 -0
- package/modules/drive/src/references/tdd.md +219 -0
- package/modules/drive/src/references/work-units.md +161 -0
- package/modules/drive/src/rules/commands.md +108 -0
- package/modules/drive/src/rules/references.md +107 -0
- package/modules/drive/src/rules/style.md +123 -0
- package/modules/drive/src/rules/templates.md +51 -0
- package/modules/drive/src/rules/workflows.md +133 -0
- package/modules/drive/src/templates/CONTEXT.md +88 -0
- package/modules/drive/src/templates/DEBUG.md +164 -0
- package/modules/drive/src/templates/DISCOVERY.md +148 -0
- package/modules/drive/src/templates/HANDOFF.md +77 -0
- package/modules/drive/src/templates/ISSUES.md +93 -0
- package/modules/drive/src/templates/MILESTONES.md +167 -0
- package/modules/drive/src/templates/PLAN.md +328 -0
- package/modules/drive/src/templates/PROJECT.md +219 -0
- package/modules/drive/src/templates/RESEARCH.md +130 -0
- package/modules/drive/src/templates/ROADMAP.md +328 -0
- package/modules/drive/src/templates/SPECIAL-FLOWS.md +70 -0
- package/modules/drive/src/templates/STATE.md +210 -0
- package/modules/drive/src/templates/SUMMARY.md +221 -0
- package/modules/drive/src/templates/UAT-ISSUES.md +139 -0
- package/modules/drive/src/templates/codebase/architecture.md +259 -0
- package/modules/drive/src/templates/codebase/concerns.md +329 -0
- package/modules/drive/src/templates/codebase/conventions.md +311 -0
- package/modules/drive/src/templates/codebase/integrations.md +284 -0
- package/modules/drive/src/templates/codebase/stack.md +190 -0
- package/modules/drive/src/templates/codebase/structure.md +287 -0
- package/modules/drive/src/templates/codebase/testing.md +484 -0
- package/modules/drive/src/templates/config.md +181 -0
- package/modules/drive/src/templates/milestone-archive.md +236 -0
- package/modules/drive/src/templates/milestone-context.md +190 -0
- package/modules/drive/src/templates/paul-json.md +147 -0
- package/modules/drive/src/vector-config/PAUL +26 -0
- package/modules/drive/src/vector-config/PAUL.manifest +11 -0
- package/modules/drive/src/workflows/apply-phase.md +393 -0
- package/modules/drive/src/workflows/audit-plan.md +344 -0
- package/modules/drive/src/workflows/complete-milestone.md +479 -0
- package/modules/drive/src/workflows/configure-special-flows.md +283 -0
- package/modules/drive/src/workflows/consider-issues.md +172 -0
- package/modules/drive/src/workflows/create-milestone.md +268 -0
- package/modules/drive/src/workflows/debug.md +292 -0
- package/modules/drive/src/workflows/discovery.md +187 -0
- package/modules/drive/src/workflows/discuss-milestone.md +245 -0
- package/modules/drive/src/workflows/discuss-phase.md +231 -0
- package/modules/drive/src/workflows/init-project.md +698 -0
- package/modules/drive/src/workflows/map-codebase.md +459 -0
- package/modules/drive/src/workflows/pause-work.md +259 -0
- package/modules/drive/src/workflows/phase-assumptions.md +181 -0
- package/modules/drive/src/workflows/plan-phase.md +385 -0
- package/modules/drive/src/workflows/quality-gate.md +263 -0
- package/modules/drive/src/workflows/register-manifest.md +107 -0
- package/modules/drive/src/workflows/research.md +241 -0
- package/modules/drive/src/workflows/resume-project.md +200 -0
- package/modules/drive/src/workflows/roadmap-management.md +334 -0
- package/modules/drive/src/workflows/transition-phase.md +368 -0
- package/modules/drive/src/workflows/unify-phase.md +290 -0
- package/modules/drive/src/workflows/verify-work.md +241 -0
- package/modules/forge/README.md +281 -0
- package/modules/forge/bin/install.js +200 -0
- package/modules/forge/package.json +32 -0
- package/modules/forge/skillsmith/rules/checklists-rules.md +42 -0
- package/modules/forge/skillsmith/rules/context-rules.md +43 -0
- package/modules/forge/skillsmith/rules/entry-point-rules.md +44 -0
- package/modules/forge/skillsmith/rules/frameworks-rules.md +43 -0
- package/modules/forge/skillsmith/rules/tasks-rules.md +52 -0
- package/modules/forge/skillsmith/rules/templates-rules.md +43 -0
- package/modules/forge/skillsmith/skillsmith.md +82 -0
- package/modules/forge/skillsmith/tasks/audit.md +277 -0
- package/modules/forge/skillsmith/tasks/discover.md +145 -0
- package/modules/forge/skillsmith/tasks/distill.md +276 -0
- package/modules/forge/skillsmith/tasks/scaffold.md +349 -0
- package/modules/forge/specs/checklists.md +193 -0
- package/modules/forge/specs/context.md +223 -0
- package/modules/forge/specs/entry-point.md +320 -0
- package/modules/forge/specs/frameworks.md +228 -0
- package/modules/forge/specs/rules.md +245 -0
- package/modules/forge/specs/tasks.md +344 -0
- package/modules/forge/specs/templates.md +335 -0
- package/modules/forge/terminal.svg +70 -0
- package/modules/ignition/README.md +245 -0
- package/modules/ignition/bin/install.js +184 -0
- package/modules/ignition/checklists/planning-quality.md +55 -0
- package/modules/ignition/data/application/config.md +21 -0
- package/modules/ignition/data/application/guide.md +51 -0
- package/modules/ignition/data/application/skill-loadout.md +11 -0
- package/modules/ignition/data/campaign/config.md +18 -0
- package/modules/ignition/data/campaign/guide.md +36 -0
- package/modules/ignition/data/campaign/skill-loadout.md +10 -0
- package/modules/ignition/data/client/config.md +18 -0
- package/modules/ignition/data/client/guide.md +36 -0
- package/modules/ignition/data/client/skill-loadout.md +11 -0
- package/modules/ignition/data/utility/config.md +18 -0
- package/modules/ignition/data/utility/guide.md +31 -0
- package/modules/ignition/data/utility/skill-loadout.md +8 -0
- package/modules/ignition/data/workflow/config.md +19 -0
- package/modules/ignition/data/workflow/guide.md +41 -0
- package/modules/ignition/data/workflow/skill-loadout.md +10 -0
- package/modules/ignition/integration.js +54 -0
- package/modules/ignition/package.json +35 -0
- package/modules/ignition/seed.md +81 -0
- package/modules/ignition/tasks/add-type.md +164 -0
- package/modules/ignition/tasks/graduate.md +182 -0
- package/modules/ignition/tasks/ideate.md +221 -0
- package/modules/ignition/tasks/launch.md +137 -0
- package/modules/ignition/tasks/status.md +71 -0
- package/modules/ignition/templates/planning-application.md +193 -0
- package/modules/ignition/templates/planning-campaign.md +138 -0
- package/modules/ignition/templates/planning-client.md +149 -0
- package/modules/ignition/templates/planning-utility.md +112 -0
- package/modules/ignition/templates/planning-workflow.md +125 -0
- package/modules/ignition/terminal.svg +74 -0
- package/modules/mission-control/CONTEXT-CONTINUITY-SPEC.md +293 -0
- package/modules/mission-control/CONTEXT-ENGINEERING-GUIDE.md +282 -0
- package/modules/mission-control/README.md +91 -0
- package/modules/mission-control/assets/terminal.svg +80 -0
- package/modules/mission-control/examples/entities.example.json +133 -0
- package/modules/mission-control/examples/projects.example.json +318 -0
- package/modules/mission-control/examples/state.example.json +183 -0
- package/modules/mission-control/examples/vector.example.json +245 -0
- package/modules/mission-control/mission-control/checklists/install-verification.md +46 -0
- package/modules/mission-control/mission-control/frameworks/framework-registry.md +83 -0
- package/modules/mission-control/mission-control/mission-control.md +83 -0
- package/modules/mission-control/mission-control/tasks/insights.md +73 -0
- package/modules/mission-control/mission-control/tasks/install.md +194 -0
- package/modules/mission-control/mission-control/tasks/status.md +125 -0
- package/modules/mission-control/schemas/entities.schema.json +89 -0
- package/modules/mission-control/schemas/projects.schema.json +221 -0
- package/modules/mission-control/schemas/state.schema.json +108 -0
- package/modules/mission-control/schemas/vector.schema.json +200 -0
- package/modules/momentum/README.md +678 -0
- package/modules/momentum/bin/install.js +563 -0
- package/modules/momentum/integration.js +131 -0
- package/modules/momentum/package.json +42 -0
- package/modules/momentum/schemas/entities.schema.json +89 -0
- package/modules/momentum/schemas/projects.schema.json +221 -0
- package/modules/momentum/schemas/state.schema.json +108 -0
- package/modules/momentum/src/commands/audit-claude-md.md +31 -0
- package/modules/momentum/src/commands/audit.md +33 -0
- package/modules/momentum/src/commands/groom.md +35 -0
- package/modules/momentum/src/commands/history.md +27 -0
- package/modules/momentum/src/commands/pulse.md +33 -0
- package/modules/momentum/src/commands/scaffold.md +33 -0
- package/modules/momentum/src/commands/status.md +28 -0
- package/modules/momentum/src/commands/surface-convert.md +35 -0
- package/modules/momentum/src/commands/surface-create.md +34 -0
- package/modules/momentum/src/commands/surface-list.md +27 -0
- package/modules/momentum/src/commands/vector-hygiene.md +33 -0
- package/modules/momentum/src/framework/context/momentum-principles.md +71 -0
- package/modules/momentum/src/framework/frameworks/audit-strategies.md +53 -0
- package/modules/momentum/src/framework/frameworks/satellite-registration.md +44 -0
- package/modules/momentum/src/framework/tasks/audit-claude-md.md +68 -0
- package/modules/momentum/src/framework/tasks/audit.md +64 -0
- package/modules/momentum/src/framework/tasks/groom.md +164 -0
- package/modules/momentum/src/framework/tasks/history.md +34 -0
- package/modules/momentum/src/framework/tasks/pulse.md +83 -0
- package/modules/momentum/src/framework/tasks/scaffold.md +202 -0
- package/modules/momentum/src/framework/tasks/status.md +35 -0
- package/modules/momentum/src/framework/tasks/surface-convert.md +143 -0
- package/modules/momentum/src/framework/tasks/surface-create.md +184 -0
- package/modules/momentum/src/framework/tasks/surface-list.md +42 -0
- package/modules/momentum/src/framework/tasks/vector-hygiene.md +160 -0
- package/modules/momentum/src/framework/templates/workspace-json.md +96 -0
- package/modules/momentum/src/hooks/_template.py +129 -0
- package/modules/momentum/src/hooks/active-hook.py +178 -0
- package/modules/momentum/src/hooks/backlog-hook.py +115 -0
- package/modules/momentum/src/hooks/mission-control-insights.py +169 -0
- package/modules/momentum/src/hooks/momentum-pulse-check.py +351 -0
- package/modules/momentum/src/hooks/operator.py +53 -0
- package/modules/momentum/src/hooks/psmm-injector.py +67 -0
- package/modules/momentum/src/hooks/satellite-detection.py +248 -0
- package/modules/momentum/src/packages/momentum-mcp/index.js +119 -0
- package/modules/momentum/src/packages/momentum-mcp/package.json +10 -0
- package/modules/momentum/src/packages/momentum-mcp/tools/entities.js +226 -0
- package/modules/momentum/src/packages/momentum-mcp/tools/operator.js +106 -0
- package/modules/momentum/src/packages/momentum-mcp/tools/projects.js +322 -0
- package/modules/momentum/src/packages/momentum-mcp/tools/psmm.js +206 -0
- package/modules/momentum/src/packages/momentum-mcp/tools/state.js +199 -0
- package/modules/momentum/src/packages/momentum-mcp/tools/surfaces.js +404 -0
- package/modules/momentum/src/skill/momentum.md +111 -0
- package/modules/momentum/src/tasks/groom.md +164 -0
- package/modules/momentum/src/templates/operator.json +66 -0
- package/modules/momentum/src/templates/workspace.json +111 -0
- package/modules/momentum/terminal.svg +77 -0
- package/modules/radar/README.md +1552 -0
- package/modules/radar/commands/audit.md +233 -0
- package/modules/radar/commands/guardrails.md +194 -0
- package/modules/radar/commands/init.md +207 -0
- package/modules/radar/commands/playbook.md +176 -0
- package/modules/radar/commands/remediate.md +156 -0
- package/modules/radar/commands/report.md +172 -0
- package/modules/radar/commands/resume.md +176 -0
- package/modules/radar/commands/status.md +148 -0
- package/modules/radar/commands/transform.md +205 -0
- package/modules/radar/commands/validate.md +177 -0
- package/modules/radar/docs/ARCHITECTURE.md +336 -0
- package/modules/radar/docs/GETTING-STARTED.md +287 -0
- package/modules/radar/docs/standards/agents.md +197 -0
- package/modules/radar/docs/standards/commands.md +250 -0
- package/modules/radar/docs/standards/domains.md +191 -0
- package/modules/radar/docs/standards/personas.md +211 -0
- package/modules/radar/docs/standards/rules.md +218 -0
- package/modules/radar/docs/standards/runtime.md +445 -0
- package/modules/radar/docs/standards/schemas.md +269 -0
- package/modules/radar/docs/standards/tools.md +273 -0
- package/modules/radar/docs/standards/workflows.md +254 -0
- package/modules/radar/docs/terminal.svg +72 -0
- package/modules/radar/docs/validation/convention-compliance-report.md +183 -0
- package/modules/radar/docs/validation/cross-reference-report.md +195 -0
- package/modules/radar/docs/validation/validation-summary.md +118 -0
- package/modules/radar/docs/validation/version-manifest.yaml +363 -0
- package/modules/radar/install.sh +711 -0
- package/modules/radar/integration.js +53 -0
- package/modules/radar/src/core/agents/architect.md +25 -0
- package/modules/radar/src/core/agents/compliance-officer.md +25 -0
- package/modules/radar/src/core/agents/data-engineer.md +25 -0
- package/modules/radar/src/core/agents/devils-advocate.md +22 -0
- package/modules/radar/src/core/agents/performance-engineer.md +25 -0
- package/modules/radar/src/core/agents/principal-engineer.md +23 -0
- package/modules/radar/src/core/agents/reality-gap-analyst.md +22 -0
- package/modules/radar/src/core/agents/security-engineer.md +25 -0
- package/modules/radar/src/core/agents/senior-app-engineer.md +25 -0
- package/modules/radar/src/core/agents/sre.md +25 -0
- package/modules/radar/src/core/agents/staff-engineer.md +23 -0
- package/modules/radar/src/core/agents/test-engineer.md +25 -0
- package/modules/radar/src/core/personas/architect.md +111 -0
- package/modules/radar/src/core/personas/compliance-officer.md +104 -0
- package/modules/radar/src/core/personas/data-engineer.md +113 -0
- package/modules/radar/src/core/personas/devils-advocate.md +105 -0
- package/modules/radar/src/core/personas/performance-engineer.md +119 -0
- package/modules/radar/src/core/personas/principal-engineer.md +119 -0
- package/modules/radar/src/core/personas/reality-gap-analyst.md +111 -0
- package/modules/radar/src/core/personas/security-engineer.md +108 -0
- package/modules/radar/src/core/personas/senior-app-engineer.md +111 -0
- package/modules/radar/src/core/personas/sre.md +117 -0
- package/modules/radar/src/core/personas/staff-engineer.md +109 -0
- package/modules/radar/src/core/personas/test-engineer.md +109 -0
- package/modules/radar/src/core/workflows/disagreement-resolution.md +183 -0
- package/modules/radar/src/core/workflows/phase-0-context.md +148 -0
- package/modules/radar/src/core/workflows/phase-1-reconnaissance.md +169 -0
- package/modules/radar/src/core/workflows/phase-2-domain-audits.md +190 -0
- package/modules/radar/src/core/workflows/phase-3-cross-domain.md +177 -0
- package/modules/radar/src/core/workflows/phase-4-adversarial-review.md +165 -0
- package/modules/radar/src/core/workflows/phase-5-report.md +189 -0
- package/modules/radar/src/core/workflows/phase-checkpoint.md +222 -0
- package/modules/radar/src/core/workflows/session-handoff.md +152 -0
- package/modules/radar/src/domains/00-context.md +201 -0
- package/modules/radar/src/domains/01-architecture.md +248 -0
- package/modules/radar/src/domains/02-data.md +224 -0
- package/modules/radar/src/domains/03-correctness.md +230 -0
- package/modules/radar/src/domains/04-security.md +274 -0
- package/modules/radar/src/domains/05-compliance.md +228 -0
- package/modules/radar/src/domains/06-testing.md +228 -0
- package/modules/radar/src/domains/07-reliability.md +246 -0
- package/modules/radar/src/domains/08-performance.md +247 -0
- package/modules/radar/src/domains/09-maintainability.md +271 -0
- package/modules/radar/src/domains/10-operability.md +250 -0
- package/modules/radar/src/domains/11-change-risk.md +246 -0
- package/modules/radar/src/domains/12-team-risk.md +221 -0
- package/modules/radar/src/domains/13-risk-synthesis.md +202 -0
- package/modules/radar/src/rules/agent-boundaries.md +78 -0
- package/modules/radar/src/rules/disagreement-protocol.md +76 -0
- package/modules/radar/src/rules/epistemic-hygiene.md +78 -0
- package/modules/radar/src/schemas/confidence.md +185 -0
- package/modules/radar/src/schemas/disagreement.md +238 -0
- package/modules/radar/src/schemas/finding.md +287 -0
- package/modules/radar/src/schemas/report-section.md +150 -0
- package/modules/radar/src/schemas/signal.md +108 -0
- package/modules/radar/src/tools/checkov.md +463 -0
- package/modules/radar/src/tools/git-history.md +581 -0
- package/modules/radar/src/tools/gitleaks.md +447 -0
- package/modules/radar/src/tools/grype.md +611 -0
- package/modules/radar/src/tools/semgrep.md +378 -0
- package/modules/radar/src/tools/sonarqube.md +550 -0
- package/modules/radar/src/tools/syft.md +539 -0
- package/modules/radar/src/tools/trivy.md +439 -0
- package/modules/radar/src/transform/agents/change-risk-modeler.md +24 -0
- package/modules/radar/src/transform/agents/execution-validator.md +24 -0
- package/modules/radar/src/transform/agents/guardrail-generator.md +24 -0
- package/modules/radar/src/transform/agents/pedagogy-agent.md +24 -0
- package/modules/radar/src/transform/agents/remediation-architect.md +24 -0
- package/modules/radar/src/transform/personas/change-risk-modeler.md +95 -0
- package/modules/radar/src/transform/personas/execution-validator.md +95 -0
- package/modules/radar/src/transform/personas/guardrail-generator.md +103 -0
- package/modules/radar/src/transform/personas/pedagogy-agent.md +105 -0
- package/modules/radar/src/transform/personas/remediation-architect.md +95 -0
- package/modules/radar/src/transform/rules/change-risk-rules.md +87 -0
- package/modules/radar/src/transform/rules/safety-governance.md +87 -0
- package/modules/radar/src/transform/schemas/change-risk.md +139 -0
- package/modules/radar/src/transform/schemas/intervention-level.md +207 -0
- package/modules/radar/src/transform/schemas/playbook.md +205 -0
- package/modules/radar/src/transform/schemas/verification-plan.md +134 -0
- package/modules/radar/src/transform/workflows/phase-6-remediation.md +148 -0
- package/modules/radar/src/transform/workflows/phase-7-risk-validation.md +161 -0
- package/modules/radar/src/transform/workflows/phase-8-execution-planning.md +159 -0
- package/modules/radar/src/transform/workflows/transform-safety.md +158 -0
- package/modules/vector/.vector-template/sessions/.gitkeep +0 -0
- package/modules/vector/.vector-template/vector.json +72 -0
- package/modules/vector/AUDIT-CLAUDEMD.md +154 -0
- package/modules/vector/INSTALL.md +185 -0
- package/modules/vector/LICENSE +21 -0
- package/modules/vector/README.md +409 -0
- package/modules/vector/VECTOR-BLOCK.md +57 -0
- package/modules/vector/assets/terminal.svg +68 -0
- package/modules/vector/bin/install.js +455 -0
- package/modules/vector/bin/migrate-v1-to-v2.sh +492 -0
- package/modules/vector/commands/help.md +46 -0
- package/modules/vector/hooks/vector-hook.py +775 -0
- package/modules/vector/mcp/index.js +118 -0
- package/modules/vector/mcp/package.json +10 -0
- package/modules/vector/mcp/tools/decisions.js +269 -0
- package/modules/vector/mcp/tools/domains.js +361 -0
- package/modules/vector/mcp/tools/staging.js +252 -0
- package/modules/vector/mcp/tools/vector-json.js +647 -0
- package/modules/vector/package.json +38 -0
- package/modules/vector/schemas/vector.schema.json +237 -0
- package/package.json +39 -0
- package/shared/branding/branding.js +70 -0
- package/shared/config/defaults.json +59 -0
- package/shared/events/README.md +175 -0
- package/shared/events/event-bus.js +134 -0
- package/shared/events/event_bus.py +255 -0
- package/shared/events/integrations.js +161 -0
- package/shared/events/schemas/audit-complete.schema.json +21 -0
- package/shared/events/schemas/phase-progress.schema.json +23 -0
- package/shared/events/schemas/plan-created.schema.json +21 -0
|
@@ -0,0 +1,775 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# VECTOR_HOOK_VERSION=2.0.0
|
|
3
|
+
"""
|
|
4
|
+
Vector - Context Augmentation & Reinforcement Layer
|
|
5
|
+
Smart Injector Hook (v2 — JSON-based)
|
|
6
|
+
|
|
7
|
+
Reads from .vector/vector.json instead of manifest + domain files.
|
|
8
|
+
All other behavior identical to v1 (vector-hook-v1.py).
|
|
9
|
+
|
|
10
|
+
Drop-in replacement: swap hook path in settings.json when ready.
|
|
11
|
+
Legacy vector-hook-v1.py reads manifest + domain files (unchanged).
|
|
12
|
+
|
|
13
|
+
What gets injected:
|
|
14
|
+
1. Context bracket rules (FRESH/MODERATE/DEPLETED) — from vector.json config
|
|
15
|
+
2. GLOBAL domain rules (always_on)
|
|
16
|
+
3. Matched domain rules (keyword matching)
|
|
17
|
+
4. Domain decisions (per-domain)
|
|
18
|
+
5. Star commands — from vector.json config
|
|
19
|
+
"""
|
|
20
|
+
import json
|
|
21
|
+
import sys
|
|
22
|
+
import re
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from datetime import datetime, timedelta
|
|
25
|
+
from typing import Optional
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
VECTOR_FOLDER = '.vector'
|
|
29
|
+
VECTOR_JSON = 'vector.json'
|
|
30
|
+
SESSIONS_FOLDER = 'sessions'
|
|
31
|
+
MAX_CONTEXT = 1000000
|
|
32
|
+
STALE_SESSION_HOURS = 24
|
|
33
|
+
DEBUG = False
|
|
34
|
+
|
|
35
|
+
ENABLE_CONTEXT_DEDUP = True
|
|
36
|
+
FORCE_EMIT_EVERY_N = 5
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def debug_log(msg: str):
|
|
40
|
+
if DEBUG:
|
|
41
|
+
print(f"[Vector-v2] {msg}", file=sys.stderr)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def compute_context_signature(
|
|
45
|
+
bracket: str,
|
|
46
|
+
devmode: bool,
|
|
47
|
+
always_on_domains: list,
|
|
48
|
+
matched_domains: list,
|
|
49
|
+
command_names: list
|
|
50
|
+
) -> str:
|
|
51
|
+
parts = [
|
|
52
|
+
"b:{}".format(bracket),
|
|
53
|
+
"d:{}".format(devmode),
|
|
54
|
+
"a:{}".format(','.join(sorted(always_on_domains))),
|
|
55
|
+
"m:{}".format(','.join(sorted(matched_domains))),
|
|
56
|
+
"c:{}".format(','.join(sorted(command_names)))
|
|
57
|
+
]
|
|
58
|
+
return "|".join(parts)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# =============================================================================
|
|
62
|
+
# SESSION MANAGEMENT
|
|
63
|
+
# =============================================================================
|
|
64
|
+
|
|
65
|
+
def get_sessions_path(vector_path: Path) -> Path:
|
|
66
|
+
sessions_path = vector_path / SESSIONS_FOLDER
|
|
67
|
+
sessions_path.mkdir(parents=True, exist_ok=True)
|
|
68
|
+
return sessions_path
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def load_session_config(vector_path: Path, session_id: str) -> Optional[dict]:
|
|
72
|
+
if not session_id:
|
|
73
|
+
return None
|
|
74
|
+
sessions_path = get_sessions_path(vector_path)
|
|
75
|
+
session_file = sessions_path / f"{session_id}.json"
|
|
76
|
+
if not session_file.exists():
|
|
77
|
+
return None
|
|
78
|
+
try:
|
|
79
|
+
with open(session_file, 'r') as f:
|
|
80
|
+
return json.load(f)
|
|
81
|
+
except (json.JSONDecodeError, IOError):
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def save_session_config(vector_path: Path, session_config: dict) -> bool:
|
|
86
|
+
session_id = session_config.get('uuid')
|
|
87
|
+
if not session_id:
|
|
88
|
+
return False
|
|
89
|
+
sessions_path = get_sessions_path(vector_path)
|
|
90
|
+
session_file = sessions_path / f"{session_id}.json"
|
|
91
|
+
try:
|
|
92
|
+
with open(session_file, 'w') as f:
|
|
93
|
+
json.dump(session_config, f, indent=2)
|
|
94
|
+
return True
|
|
95
|
+
except IOError:
|
|
96
|
+
return False
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def create_session_config(session_id: str, cwd: str, vector_data: dict) -> dict:
|
|
100
|
+
now = datetime.now().isoformat()
|
|
101
|
+
label = Path(cwd).name or "unknown"
|
|
102
|
+
overrides = {"DEVMODE": None}
|
|
103
|
+
for domain_name in vector_data.get('domains', {}).keys():
|
|
104
|
+
overrides[f"{domain_name}_STATE"] = None
|
|
105
|
+
return {
|
|
106
|
+
"uuid": session_id,
|
|
107
|
+
"started": now,
|
|
108
|
+
"cwd": cwd,
|
|
109
|
+
"label": label,
|
|
110
|
+
"title": None,
|
|
111
|
+
"prompt_count": 0,
|
|
112
|
+
"last_activity": now,
|
|
113
|
+
"overrides": overrides,
|
|
114
|
+
"last_context_signature": None
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def update_session_activity(vector_path: Path, session_id: str) -> None:
|
|
119
|
+
session_config = load_session_config(vector_path, session_id)
|
|
120
|
+
if session_config:
|
|
121
|
+
session_config['last_activity'] = datetime.now().isoformat()
|
|
122
|
+
save_session_config(vector_path, session_config)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def cleanup_stale_sessions(vector_path: Path) -> list:
|
|
126
|
+
cleaned = []
|
|
127
|
+
sessions_path = get_sessions_path(vector_path)
|
|
128
|
+
threshold = datetime.now() - timedelta(hours=STALE_SESSION_HOURS)
|
|
129
|
+
for session_file in sessions_path.glob("*.json"):
|
|
130
|
+
try:
|
|
131
|
+
with open(session_file, 'r') as f:
|
|
132
|
+
config = json.load(f)
|
|
133
|
+
last_activity = config.get('last_activity', config.get('started', ''))
|
|
134
|
+
if last_activity:
|
|
135
|
+
last_dt = datetime.fromisoformat(last_activity)
|
|
136
|
+
if last_dt < threshold:
|
|
137
|
+
session_file.unlink()
|
|
138
|
+
cleaned.append(config.get('uuid', session_file.stem))
|
|
139
|
+
except Exception:
|
|
140
|
+
pass
|
|
141
|
+
return cleaned
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def merge_config_with_session(
|
|
145
|
+
domains: dict,
|
|
146
|
+
global_exclude: list,
|
|
147
|
+
devmode: bool,
|
|
148
|
+
session_config: Optional[dict]
|
|
149
|
+
) -> tuple:
|
|
150
|
+
if not session_config:
|
|
151
|
+
return domains, global_exclude, devmode
|
|
152
|
+
overrides = session_config.get('overrides', {})
|
|
153
|
+
if overrides.get('DEVMODE') is not None:
|
|
154
|
+
devmode = overrides['DEVMODE']
|
|
155
|
+
for domain_name in list(domains.keys()):
|
|
156
|
+
key = f"{domain_name}_STATE"
|
|
157
|
+
if overrides.get(key) is not None:
|
|
158
|
+
domains[domain_name]['state'] = overrides[key]
|
|
159
|
+
return domains, global_exclude, devmode
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def get_or_create_session(vector_path: Path, session_id: str, cwd: str, vector_data: dict) -> Optional[dict]:
|
|
163
|
+
if not session_id:
|
|
164
|
+
return None
|
|
165
|
+
session_config = load_session_config(vector_path, session_id)
|
|
166
|
+
if session_config is None:
|
|
167
|
+
session_config = create_session_config(session_id, cwd, vector_data)
|
|
168
|
+
cleanup_stale_sessions(vector_path)
|
|
169
|
+
session_config['prompt_count'] = session_config.get('prompt_count', 0) + 1
|
|
170
|
+
session_config['last_activity'] = datetime.now().isoformat()
|
|
171
|
+
save_session_config(vector_path, session_config)
|
|
172
|
+
return session_config
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# =============================================================================
|
|
176
|
+
# CONTEXT PERCENTAGE & BRACKETS
|
|
177
|
+
# =============================================================================
|
|
178
|
+
|
|
179
|
+
def get_context_percentage(input_data: dict) -> Optional[float]:
|
|
180
|
+
try:
|
|
181
|
+
tokens_remaining = input_data.get('context', {}).get('tokensRemaining')
|
|
182
|
+
tokens_used = input_data.get('context', {}).get('tokensUsed')
|
|
183
|
+
if tokens_remaining is not None and tokens_used is not None:
|
|
184
|
+
total = tokens_remaining + tokens_used
|
|
185
|
+
if total > 0:
|
|
186
|
+
return (tokens_remaining / total) * 100
|
|
187
|
+
turn = input_data.get('context', {}).get('conversationTurnNumber', 1)
|
|
188
|
+
if turn and turn > 1:
|
|
189
|
+
estimated_used = turn * 3000
|
|
190
|
+
remaining = MAX_CONTEXT - estimated_used
|
|
191
|
+
if remaining > 0:
|
|
192
|
+
return (remaining / MAX_CONTEXT) * 100
|
|
193
|
+
except Exception:
|
|
194
|
+
pass
|
|
195
|
+
return None
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def get_active_bracket(context_remaining: Optional[float]) -> str:
|
|
199
|
+
if context_remaining is None:
|
|
200
|
+
return "FRESH"
|
|
201
|
+
if context_remaining >= 70:
|
|
202
|
+
return "FRESH"
|
|
203
|
+
elif context_remaining >= 40:
|
|
204
|
+
return "MODERATE"
|
|
205
|
+
elif context_remaining >= 15:
|
|
206
|
+
return "DEPLETED"
|
|
207
|
+
else:
|
|
208
|
+
return "CRITICAL"
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# =============================================================================
|
|
212
|
+
# V2: JSON-BASED DATA LOADING
|
|
213
|
+
# =============================================================================
|
|
214
|
+
|
|
215
|
+
def find_all_vector_scopes(cwd: str) -> list:
|
|
216
|
+
"""Find all .vector/ directories with vector.json by walking up directory tree."""
|
|
217
|
+
scopes = []
|
|
218
|
+
search_path = Path(cwd)
|
|
219
|
+
for i in range(10):
|
|
220
|
+
candidate = search_path / VECTOR_FOLDER
|
|
221
|
+
vector_json_path = candidate / VECTOR_JSON
|
|
222
|
+
if candidate.exists() and vector_json_path.exists():
|
|
223
|
+
label = "project" if i == 0 else "scope-{}".format(search_path.name)
|
|
224
|
+
scopes.append((candidate, label))
|
|
225
|
+
debug_log("Found .vector/ scope at {} ({})".format(candidate, label))
|
|
226
|
+
if search_path.parent == search_path:
|
|
227
|
+
break
|
|
228
|
+
search_path = search_path.parent
|
|
229
|
+
return scopes
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def load_vector_json(vector_path: Path) -> Optional[dict]:
|
|
233
|
+
"""Load vector.json from a .vector/ directory. Returns None if not found."""
|
|
234
|
+
vector_json_path = vector_path / VECTOR_JSON
|
|
235
|
+
if not vector_json_path.exists():
|
|
236
|
+
return None
|
|
237
|
+
try:
|
|
238
|
+
with open(vector_json_path, 'r') as f:
|
|
239
|
+
return json.load(f)
|
|
240
|
+
except (json.JSONDecodeError, IOError):
|
|
241
|
+
return None
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def vector_json_to_domains(vector_data: dict) -> dict:
|
|
245
|
+
"""
|
|
246
|
+
Convert vector.json domains to the internal domains dict format
|
|
247
|
+
that match_domains_to_prompt() expects.
|
|
248
|
+
"""
|
|
249
|
+
domains = {}
|
|
250
|
+
for name, domain_data in vector_data.get('domains', {}).items():
|
|
251
|
+
state_str = domain_data.get('state', 'inactive')
|
|
252
|
+
domains[name] = {
|
|
253
|
+
'state': state_str in ('active', True, 'true'),
|
|
254
|
+
'always_on': domain_data.get('always_on', False),
|
|
255
|
+
'recall': ', '.join(domain_data.get('recall', [])),
|
|
256
|
+
'recall_list': [kw.lower() for kw in domain_data.get('recall', [])],
|
|
257
|
+
'exclude_list': [kw.lower() for kw in domain_data.get('exclude', [])],
|
|
258
|
+
}
|
|
259
|
+
return domains
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def get_domain_rules_from_json(vector_data: dict, domain_name: str) -> list:
|
|
263
|
+
"""Extract rule texts from vector.json for a given domain."""
|
|
264
|
+
domain = vector_data.get('domains', {}).get(domain_name, {})
|
|
265
|
+
return [r.get('text', '') for r in domain.get('rules', []) if r.get('text')]
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def get_domain_decisions_from_json(vector_data: dict, domain_name: str) -> list:
|
|
269
|
+
"""Extract decisions from vector.json for a given domain."""
|
|
270
|
+
domain = vector_data.get('domains', {}).get(domain_name, {})
|
|
271
|
+
return [d for d in domain.get('decisions', []) if d.get('status', 'active') == 'active']
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def get_all_decisions_summary(vector_data: dict) -> str:
|
|
275
|
+
"""
|
|
276
|
+
Generate standalone <decisions> summary across ALL domains.
|
|
277
|
+
Replaces the former get-decisions-summary.py hook.
|
|
278
|
+
"""
|
|
279
|
+
if not vector_data:
|
|
280
|
+
return ''
|
|
281
|
+
|
|
282
|
+
domain_summaries = []
|
|
283
|
+
total_active = 0
|
|
284
|
+
total_archived = 0
|
|
285
|
+
|
|
286
|
+
for dname, ddata in vector_data.get('domains', {}).items():
|
|
287
|
+
decisions = ddata.get('decisions', [])
|
|
288
|
+
active = len([d for d in decisions if d.get('status', 'active') == 'active'])
|
|
289
|
+
archived = len([d for d in decisions if d.get('status') == 'archived'])
|
|
290
|
+
if active > 0:
|
|
291
|
+
domain_summaries.append(f"{dname.lower()} ({active})")
|
|
292
|
+
total_active += active
|
|
293
|
+
total_archived += archived
|
|
294
|
+
|
|
295
|
+
if not domain_summaries and total_active == 0:
|
|
296
|
+
return '<decisions>No decisions logged yet. Use vector_log_decision tool to start.</decisions>'
|
|
297
|
+
|
|
298
|
+
lines = [
|
|
299
|
+
'<decisions>',
|
|
300
|
+
'Domains: {}'.format(', '.join(domain_summaries)),
|
|
301
|
+
'Total: {} active, {} archived'.format(total_active, total_archived),
|
|
302
|
+
'Tools: vector_search_decisions(keyword), vector_get_decisions(domain), vector_log_decision(domain, decision, rationale, recall)',
|
|
303
|
+
'</decisions>',
|
|
304
|
+
]
|
|
305
|
+
return '\n'.join(lines)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def merge_vector_scopes(scopes: list) -> tuple:
|
|
309
|
+
"""
|
|
310
|
+
Merge multiple .vector/ scopes from vector.json files.
|
|
311
|
+
Returns (vector_data, vector_path, domains, global_exclude, devmode)
|
|
312
|
+
All data comes from vector.json — no flat file fallbacks.
|
|
313
|
+
"""
|
|
314
|
+
if not scopes:
|
|
315
|
+
return None, None, {}, [], False
|
|
316
|
+
|
|
317
|
+
merged_vector_data = {"config": {}, "domains": {}, "staging": []}
|
|
318
|
+
merged_global_exclude = []
|
|
319
|
+
merged_devmode = False
|
|
320
|
+
merged_context_brackets = {}
|
|
321
|
+
merged_commands = {}
|
|
322
|
+
|
|
323
|
+
for vector_path, _ in reversed(scopes):
|
|
324
|
+
vector_data = load_vector_json(vector_path)
|
|
325
|
+
if vector_data:
|
|
326
|
+
config = vector_data.get('config', {})
|
|
327
|
+
if config.get('devmode') is not None:
|
|
328
|
+
merged_devmode = config['devmode']
|
|
329
|
+
if config.get('global_exclude'):
|
|
330
|
+
merged_global_exclude = config['global_exclude']
|
|
331
|
+
|
|
332
|
+
# Merge context brackets (more-specific overrides)
|
|
333
|
+
for bracket_name, bracket_config in config.get('context_brackets', {}).items():
|
|
334
|
+
merged_context_brackets[bracket_name] = bracket_config
|
|
335
|
+
|
|
336
|
+
# Merge star commands (more-specific overrides)
|
|
337
|
+
for cmd_name, cmd_rules in config.get('commands', {}).items():
|
|
338
|
+
merged_commands[cmd_name] = cmd_rules
|
|
339
|
+
|
|
340
|
+
for dname, dconfig in vector_data.get('domains', {}).items():
|
|
341
|
+
merged_vector_data['domains'][dname] = dconfig
|
|
342
|
+
|
|
343
|
+
merged_vector_data['staging'].extend(vector_data.get('staging', []))
|
|
344
|
+
|
|
345
|
+
merged_vector_data['config'] = {
|
|
346
|
+
'devmode': merged_devmode,
|
|
347
|
+
'post_compact_gate': True,
|
|
348
|
+
'global_exclude': merged_global_exclude,
|
|
349
|
+
'context_brackets': merged_context_brackets,
|
|
350
|
+
'commands': merged_commands
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
merged_domains = vector_json_to_domains(merged_vector_data)
|
|
354
|
+
|
|
355
|
+
primary_vector_path = scopes[0][0]
|
|
356
|
+
return merged_vector_data, primary_vector_path, merged_domains, merged_global_exclude, merged_devmode
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
# =============================================================================
|
|
360
|
+
# STAR COMMANDS (detection only — rules come from vector.json)
|
|
361
|
+
# =============================================================================
|
|
362
|
+
|
|
363
|
+
def detect_star_commands(user_prompt: str) -> list:
|
|
364
|
+
matches = re.findall(r'\*(\w+)', user_prompt)
|
|
365
|
+
return [m.upper() for m in matches] if matches else []
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
# =============================================================================
|
|
369
|
+
# MATCHING & EXCLUSIONS
|
|
370
|
+
# =============================================================================
|
|
371
|
+
|
|
372
|
+
def check_exclusions(prompt_lower: str, exclude_list: list) -> list:
|
|
373
|
+
matched_exclusions = []
|
|
374
|
+
for keyword in exclude_list:
|
|
375
|
+
pattern = re.escape(keyword)
|
|
376
|
+
if re.search(pattern, prompt_lower):
|
|
377
|
+
matched_exclusions.append(keyword)
|
|
378
|
+
return matched_exclusions
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def match_domains_to_prompt(
|
|
382
|
+
domains: dict,
|
|
383
|
+
user_prompt: str,
|
|
384
|
+
global_exclude: list
|
|
385
|
+
) -> tuple:
|
|
386
|
+
matched = {}
|
|
387
|
+
excluded = {}
|
|
388
|
+
prompt_lower = user_prompt.lower()
|
|
389
|
+
global_excluded = check_exclusions(prompt_lower, global_exclude)
|
|
390
|
+
if global_excluded:
|
|
391
|
+
return matched, excluded, global_excluded
|
|
392
|
+
for domain, config in domains.items():
|
|
393
|
+
if not config.get('state', False) or config.get('always_on', False):
|
|
394
|
+
continue
|
|
395
|
+
recall_list = config.get('recall_list', [])
|
|
396
|
+
if not recall_list:
|
|
397
|
+
continue
|
|
398
|
+
exclude_list = config.get('exclude_list', [])
|
|
399
|
+
if exclude_list:
|
|
400
|
+
domain_exclusions = check_exclusions(prompt_lower, exclude_list)
|
|
401
|
+
if domain_exclusions:
|
|
402
|
+
excluded[domain] = domain_exclusions
|
|
403
|
+
continue
|
|
404
|
+
domain_matches = []
|
|
405
|
+
for keyword in recall_list:
|
|
406
|
+
pattern = re.escape(keyword)
|
|
407
|
+
if re.search(pattern, prompt_lower):
|
|
408
|
+
domain_matches.append(keyword)
|
|
409
|
+
if domain_matches:
|
|
410
|
+
matched[domain] = domain_matches
|
|
411
|
+
return matched, excluded, global_excluded
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
# =============================================================================
|
|
415
|
+
# OUTPUT FORMATTING
|
|
416
|
+
# =============================================================================
|
|
417
|
+
|
|
418
|
+
def format_output(
|
|
419
|
+
domains: dict,
|
|
420
|
+
always_on_rules: dict,
|
|
421
|
+
matched_rules: dict,
|
|
422
|
+
matched_keywords: dict,
|
|
423
|
+
excluded_domains: dict,
|
|
424
|
+
global_excluded: list,
|
|
425
|
+
devmode: bool,
|
|
426
|
+
bracket: str = "FRESH",
|
|
427
|
+
context_remaining: Optional[float] = None,
|
|
428
|
+
bracket_rules: Optional[list] = None,
|
|
429
|
+
command_rules: Optional[dict] = None,
|
|
430
|
+
global_disabled: bool = False,
|
|
431
|
+
domains_with_rules: Optional[set] = None,
|
|
432
|
+
context_enabled: bool = True,
|
|
433
|
+
domain_decisions: Optional[dict] = None
|
|
434
|
+
) -> str:
|
|
435
|
+
output = "\n<vector-rules>\n"
|
|
436
|
+
|
|
437
|
+
if context_enabled:
|
|
438
|
+
if context_remaining is not None:
|
|
439
|
+
is_critical = bracket == "CRITICAL"
|
|
440
|
+
if is_critical:
|
|
441
|
+
output += f"⚠️ CONTEXT CRITICAL: {context_remaining:.0f}% remaining ⚠️\n"
|
|
442
|
+
output += "Recommend: compact session OR spawn fresh agent for remaining work\n\n"
|
|
443
|
+
output += f"CONTEXT BRACKET: [{bracket}] ({context_remaining:.0f}% remaining)\n"
|
|
444
|
+
else:
|
|
445
|
+
output += f"CONTEXT BRACKET: [{bracket}] (fresh session)\n"
|
|
446
|
+
if bracket_rules:
|
|
447
|
+
output += f"\n[{bracket}] CONTEXT RULES:\n"
|
|
448
|
+
for i, rule in enumerate(bracket_rules, 1):
|
|
449
|
+
output += f" {i}. {rule}\n"
|
|
450
|
+
output += "\n"
|
|
451
|
+
|
|
452
|
+
if command_rules:
|
|
453
|
+
output += "🎯 ACTIVE COMMANDS 🎯\n"
|
|
454
|
+
output += "="*60 + "\n"
|
|
455
|
+
output += "EXPLICIT COMMAND INVOCATION - EXECUTE THESE INSTRUCTIONS:\n\n"
|
|
456
|
+
for cmd, rules in command_rules.items():
|
|
457
|
+
output += f"[*{cmd.lower()}] COMMAND:\n"
|
|
458
|
+
for i, rule in enumerate(rules):
|
|
459
|
+
output += f" {i}. {rule}\n"
|
|
460
|
+
output += "\n"
|
|
461
|
+
output += "="*60 + "\n\n"
|
|
462
|
+
|
|
463
|
+
if devmode:
|
|
464
|
+
output += "⚠️ DEVMODE=true ⚠️\n"
|
|
465
|
+
output += "="*60 + "\n"
|
|
466
|
+
output += "MANDATORY: Append a DEVMODE block at the end of EVERY response.\n"
|
|
467
|
+
output += "NEVER skip it. NEVER forget it. NEVER omit it for any reason.\n"
|
|
468
|
+
output += "NEVER fabricate data in the block — only report what you actually received.\n"
|
|
469
|
+
output += "NEVER invent rule numbers, citation counts, or applied counts.\n"
|
|
470
|
+
output += "NEVER write a DEVMODE block from memory — always derive it from THIS prompt's context.\n\n"
|
|
471
|
+
output += "This is a signal dashboard the user reads to tune their context systems.\n\n"
|
|
472
|
+
output += "How to fill each field:\n"
|
|
473
|
+
output += "- Vector: If you received <vector-rules> THIS prompt → list domain names + rule count from the injection.\n"
|
|
474
|
+
output += " If you received <vector-status dedup=\"true\"> → write 'dedup (prompt N)' using the prompt number from the tag.\n"
|
|
475
|
+
output += "- Rules: Total = count of rules in the last <vector-rules> injection. applied = how many you consciously followed in THIS response. 0 is fine and expected.\n"
|
|
476
|
+
output += "- Decisions: Total = count from <decisions> tag. applied = how many influenced THIS response. Usually 0.\n"
|
|
477
|
+
output += "- Signals: List every hook tag you received THIS prompt (e.g. pulse, active, backlog, calendar, time, machine, context, vector-rules, vector-status, decisions, psmm). Only list tags actually present.\n"
|
|
478
|
+
output += "- Applied: Which of those signals actually shaped your response content. 'none' is the honest default.\n"
|
|
479
|
+
output += "- Tools: Which Claude Code tools you called in THIS response. 'none' if you made no tool calls.\n"
|
|
480
|
+
output += "- Gaps: If you noticed missing context or something that should have been injected but wasn't. Usually 'none'.\n\n"
|
|
481
|
+
output += "Format EXACTLY (keep under 8 lines, no rationale, no prose):\n"
|
|
482
|
+
output += "---\n```\n"
|
|
483
|
+
output += "🔧 Vector DEVMODE\n"
|
|
484
|
+
output += "Vector: [see rules above]\n"
|
|
485
|
+
output += "Rules: [total] | applied: [count, or 0]\n"
|
|
486
|
+
output += "Decisions: [total] | applied: [count, or 0]\n"
|
|
487
|
+
output += "Signals: [tags received this prompt]\n"
|
|
488
|
+
output += "Applied: [which signals shaped response, or 'none']\n"
|
|
489
|
+
output += "Tools: [tools used, or 'none']\n"
|
|
490
|
+
output += "Gaps: [one-line, or 'none']\n"
|
|
491
|
+
output += "```\n---\n"
|
|
492
|
+
output += "="*60 + "\n\n"
|
|
493
|
+
else:
|
|
494
|
+
output += "🚫 DEVMODE=false 🚫\n"
|
|
495
|
+
output += "User has DISABLED debug output. Do NOT append any Vector DEVMODE\n"
|
|
496
|
+
output += "debug section to your responses. Respond normally without debug blocks.\n\n"
|
|
497
|
+
|
|
498
|
+
if global_disabled:
|
|
499
|
+
output += "⛔ GLOBAL RULES DISABLED ⛔\n"
|
|
500
|
+
output += "="*60 + "\n"
|
|
501
|
+
output += "CRITICAL: User has INTENTIONALLY disabled GLOBAL domain rules.\n"
|
|
502
|
+
output += "Do NOT apply any previously-seen GLOBAL rules from conversation memory.\n"
|
|
503
|
+
output += "This is an explicit override - await future activation to resume.\n"
|
|
504
|
+
output += "="*60 + "\n\n"
|
|
505
|
+
|
|
506
|
+
output += "LOADED DOMAINS:\n"
|
|
507
|
+
for domain in always_on_rules:
|
|
508
|
+
output += f" [{domain}] always_on ({len(always_on_rules[domain])} rules)\n"
|
|
509
|
+
for domain in matched_rules:
|
|
510
|
+
keywords = matched_keywords.get(domain, [])
|
|
511
|
+
output += f" [{domain}] matched: {', '.join(keywords)} ({len(matched_rules[domain])} rules)\n"
|
|
512
|
+
if not always_on_rules and not matched_rules:
|
|
513
|
+
output += " (none)\n"
|
|
514
|
+
|
|
515
|
+
if global_excluded:
|
|
516
|
+
output += f"\nGLOBAL EXCLUSION ACTIVE: {', '.join(global_excluded)}\n"
|
|
517
|
+
output += " (All domain matching skipped)\n"
|
|
518
|
+
if excluded_domains:
|
|
519
|
+
output += "\nEXCLUDED DOMAINS:\n"
|
|
520
|
+
for domain, exclusions in excluded_domains.items():
|
|
521
|
+
output += f" [{domain}] excluded by: {', '.join(exclusions)}\n"
|
|
522
|
+
|
|
523
|
+
for domain, rules in always_on_rules.items():
|
|
524
|
+
output += f"\n[{domain}] RULES:\n"
|
|
525
|
+
for i, rule in enumerate(rules):
|
|
526
|
+
output += f" {i}. {rule}\n"
|
|
527
|
+
if domain_decisions and domain in domain_decisions:
|
|
528
|
+
decisions = domain_decisions[domain]
|
|
529
|
+
output += f"\n[{domain}] DECISIONS ({len(decisions)}):\n"
|
|
530
|
+
for d in decisions:
|
|
531
|
+
output += " - {} ({}): {}\n".format(
|
|
532
|
+
d.get('decision', ''), d.get('date', ''), d.get('rationale', ''))
|
|
533
|
+
|
|
534
|
+
for domain, rules in matched_rules.items():
|
|
535
|
+
output += f"\n[{domain}] RULES:\n"
|
|
536
|
+
for i, rule in enumerate(rules):
|
|
537
|
+
output += f" {i}. {rule}\n"
|
|
538
|
+
if domain_decisions and domain in domain_decisions:
|
|
539
|
+
decisions = domain_decisions[domain]
|
|
540
|
+
output += f"\n[{domain}] DECISIONS ({len(decisions)}):\n"
|
|
541
|
+
for d in decisions:
|
|
542
|
+
output += " - {} ({}): {}\n".format(
|
|
543
|
+
d.get('decision', ''), d.get('date', ''), d.get('rationale', ''))
|
|
544
|
+
|
|
545
|
+
unloaded = []
|
|
546
|
+
for domain, config in domains.items():
|
|
547
|
+
if config.get('state', False) and not config.get('always_on', False):
|
|
548
|
+
if domain not in matched_rules and domain not in excluded_domains:
|
|
549
|
+
if domains_with_rules is None or domain in domains_with_rules:
|
|
550
|
+
recall = config.get('recall', '')
|
|
551
|
+
unloaded.append(f"{domain} ({recall})")
|
|
552
|
+
if unloaded:
|
|
553
|
+
output += "\nAVAILABLE (not loaded):\n"
|
|
554
|
+
for item in unloaded:
|
|
555
|
+
output += f" {item}\n"
|
|
556
|
+
output += "Use drl_get_domain_rules(domain) to load manually if needed.\n"
|
|
557
|
+
|
|
558
|
+
output += "</vector-rules>\n"
|
|
559
|
+
return output
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
# =============================================================================
|
|
563
|
+
# MAIN (v2 — reads vector.json instead of manifest + domain files)
|
|
564
|
+
# =============================================================================
|
|
565
|
+
|
|
566
|
+
def main():
|
|
567
|
+
try:
|
|
568
|
+
input_data = json.load(sys.stdin)
|
|
569
|
+
except json.JSONDecodeError as e:
|
|
570
|
+
print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
|
|
571
|
+
sys.exit(1)
|
|
572
|
+
|
|
573
|
+
cwd = input_data.get('cwd', str(Path.home()))
|
|
574
|
+
session_id = input_data.get('sessionId', '') or input_data.get('session_id', '')
|
|
575
|
+
user_prompt = (
|
|
576
|
+
input_data.get('prompt', '') or
|
|
577
|
+
input_data.get('userInput', '') or
|
|
578
|
+
input_data.get('message', '') or
|
|
579
|
+
input_data.get('input', '')
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
# Find all .vector/ scopes
|
|
583
|
+
scopes = find_all_vector_scopes(cwd)
|
|
584
|
+
if not scopes:
|
|
585
|
+
sys.exit(0)
|
|
586
|
+
|
|
587
|
+
# Merge scopes — vector.json based (all data from JSON, no flat files)
|
|
588
|
+
vector_data, vector_path, domains, global_exclude, devmode = merge_vector_scopes(scopes)
|
|
589
|
+
|
|
590
|
+
if not domains or vector_path is None:
|
|
591
|
+
sys.exit(0)
|
|
592
|
+
|
|
593
|
+
# Session management
|
|
594
|
+
session_config = get_or_create_session(vector_path, session_id, cwd, vector_data or {})
|
|
595
|
+
|
|
596
|
+
# Merge with session overrides
|
|
597
|
+
domains, global_exclude, devmode = merge_config_with_session(
|
|
598
|
+
domains, global_exclude, devmode, session_config
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
# Context percentage and bracket
|
|
602
|
+
context_remaining = get_context_percentage(input_data)
|
|
603
|
+
bracket = get_active_bracket(context_remaining)
|
|
604
|
+
|
|
605
|
+
# Context bracket rules from vector.json config
|
|
606
|
+
bracket_rules_list = []
|
|
607
|
+
context_enabled = True
|
|
608
|
+
if session_config:
|
|
609
|
+
overrides = session_config.get('overrides', {})
|
|
610
|
+
if overrides.get('CONTEXT_STATE') is not None:
|
|
611
|
+
context_enabled = overrides['CONTEXT_STATE']
|
|
612
|
+
if vector_data and context_enabled:
|
|
613
|
+
context_brackets = vector_data.get('config', {}).get('context_brackets', {})
|
|
614
|
+
rules_bracket = "DEPLETED" if bracket == "CRITICAL" else bracket
|
|
615
|
+
bracket_config = context_brackets.get(rules_bracket, {})
|
|
616
|
+
if bracket_config.get('enabled', True):
|
|
617
|
+
bracket_rules_list = bracket_config.get('rules', [])
|
|
618
|
+
|
|
619
|
+
# GLOBAL disabled check
|
|
620
|
+
global_disabled = False
|
|
621
|
+
if 'GLOBAL' in domains:
|
|
622
|
+
if not domains['GLOBAL'].get('state', True):
|
|
623
|
+
global_disabled = True
|
|
624
|
+
|
|
625
|
+
# Load ALWAYS_ON domain rules from vector.json
|
|
626
|
+
always_on_rules = {}
|
|
627
|
+
if vector_data:
|
|
628
|
+
for domain, config in domains.items():
|
|
629
|
+
is_always_on = config.get('always_on', False) or domain == 'GLOBAL'
|
|
630
|
+
if is_always_on and config.get('state', True):
|
|
631
|
+
rules = get_domain_rules_from_json(vector_data, domain)
|
|
632
|
+
if rules:
|
|
633
|
+
always_on_rules[domain] = rules
|
|
634
|
+
|
|
635
|
+
# Star commands from vector.json config
|
|
636
|
+
command_rules = {}
|
|
637
|
+
if user_prompt and vector_data:
|
|
638
|
+
all_commands = vector_data.get('config', {}).get('commands', {})
|
|
639
|
+
if all_commands:
|
|
640
|
+
star_commands = detect_star_commands(user_prompt)
|
|
641
|
+
for cmd in star_commands:
|
|
642
|
+
if cmd in all_commands:
|
|
643
|
+
command_rules[cmd] = all_commands[cmd]
|
|
644
|
+
|
|
645
|
+
# Match domains to prompt
|
|
646
|
+
matched_keywords = {}
|
|
647
|
+
matched_rules = {}
|
|
648
|
+
excluded_domains = {}
|
|
649
|
+
global_excluded = []
|
|
650
|
+
|
|
651
|
+
if user_prompt:
|
|
652
|
+
matched_keywords, excluded_domains, global_excluded = match_domains_to_prompt(
|
|
653
|
+
domains, user_prompt, global_exclude
|
|
654
|
+
)
|
|
655
|
+
if vector_data:
|
|
656
|
+
for domain in matched_keywords:
|
|
657
|
+
if domain == 'COMMANDS':
|
|
658
|
+
continue
|
|
659
|
+
rules = get_domain_rules_from_json(vector_data, domain)
|
|
660
|
+
if rules:
|
|
661
|
+
matched_rules[domain] = rules
|
|
662
|
+
|
|
663
|
+
matched_keywords.pop('COMMANDS', None)
|
|
664
|
+
|
|
665
|
+
# Load decisions from vector.json
|
|
666
|
+
domain_decisions = {}
|
|
667
|
+
if vector_data:
|
|
668
|
+
for domain in list(always_on_rules.keys()) + list(matched_rules.keys()):
|
|
669
|
+
decisions = get_domain_decisions_from_json(vector_data, domain)
|
|
670
|
+
if decisions:
|
|
671
|
+
domain_decisions[domain] = decisions
|
|
672
|
+
|
|
673
|
+
# Build set of domains that have rules (for AVAILABLE listing)
|
|
674
|
+
domains_with_rules = set()
|
|
675
|
+
if vector_data:
|
|
676
|
+
for dname, ddata in vector_data.get('domains', {}).items():
|
|
677
|
+
if ddata.get('rules'):
|
|
678
|
+
domains_with_rules.add(dname)
|
|
679
|
+
|
|
680
|
+
# Context deduplication
|
|
681
|
+
current_signature = compute_context_signature(
|
|
682
|
+
bracket, devmode,
|
|
683
|
+
list(always_on_rules.keys()),
|
|
684
|
+
list(matched_rules.keys()),
|
|
685
|
+
list(command_rules.keys())
|
|
686
|
+
)
|
|
687
|
+
|
|
688
|
+
prompt_count = session_config.get('prompt_count', 1) if session_config else 1
|
|
689
|
+
last_signature = session_config.get('last_context_signature') if session_config else None
|
|
690
|
+
|
|
691
|
+
should_emit_full = True
|
|
692
|
+
if ENABLE_CONTEXT_DEDUP and session_config:
|
|
693
|
+
signature_changed = (current_signature != last_signature)
|
|
694
|
+
force_emit = (prompt_count % FORCE_EMIT_EVERY_N == 0)
|
|
695
|
+
first_prompt = (prompt_count <= 1)
|
|
696
|
+
if not signature_changed and not force_emit and not first_prompt:
|
|
697
|
+
should_emit_full = False
|
|
698
|
+
else:
|
|
699
|
+
session_config['last_context_signature'] = current_signature
|
|
700
|
+
save_session_config(vector_path, session_config)
|
|
701
|
+
|
|
702
|
+
# Generate decisions summary (always, regardless of dedup)
|
|
703
|
+
decisions_summary = get_all_decisions_summary(vector_data) if vector_data else ''
|
|
704
|
+
|
|
705
|
+
if should_emit_full:
|
|
706
|
+
context = format_output(
|
|
707
|
+
domains,
|
|
708
|
+
always_on_rules,
|
|
709
|
+
matched_rules,
|
|
710
|
+
matched_keywords,
|
|
711
|
+
excluded_domains,
|
|
712
|
+
global_excluded,
|
|
713
|
+
devmode,
|
|
714
|
+
bracket,
|
|
715
|
+
context_remaining,
|
|
716
|
+
bracket_rules_list,
|
|
717
|
+
command_rules,
|
|
718
|
+
global_disabled,
|
|
719
|
+
domains_with_rules,
|
|
720
|
+
context_enabled,
|
|
721
|
+
domain_decisions
|
|
722
|
+
)
|
|
723
|
+
|
|
724
|
+
if decisions_summary:
|
|
725
|
+
context += "\n" + decisions_summary + "\n"
|
|
726
|
+
|
|
727
|
+
output = {
|
|
728
|
+
"hookSpecificOutput": {
|
|
729
|
+
"hookEventName": "UserPromptSubmit",
|
|
730
|
+
"additionalContext": context
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
print(json.dumps(output))
|
|
734
|
+
else:
|
|
735
|
+
loaded = list(always_on_rules.keys()) + list(matched_rules.keys())
|
|
736
|
+
status = "<vector-status dedup=\"true\" prompt=\"{}\" domains=\"{}\">\n".format(
|
|
737
|
+
prompt_count, ','.join(loaded) if loaded else 'GLOBAL'
|
|
738
|
+
)
|
|
739
|
+
status += "Vector rules were NOT injected this prompt (dedup: signature unchanged).\n"
|
|
740
|
+
status += "Prior injection is still in your context window — operate on those rules.\n"
|
|
741
|
+
|
|
742
|
+
if devmode:
|
|
743
|
+
status += "\n"
|
|
744
|
+
status += "DEVMODE=true — MANDATORY DEVMODE BLOCK REQUIRED.\n"
|
|
745
|
+
status += "NEVER skip the DEVMODE block. NEVER fabricate data in it. NEVER write it from memory.\n"
|
|
746
|
+
status += "Derive every field from THIS prompt's context tags.\n"
|
|
747
|
+
status += "Vector line: 'dedup (prompt {})'\n".format(prompt_count)
|
|
748
|
+
status += "Rules: total from last full injection | applied: count that shaped THIS response (0 is fine)\n"
|
|
749
|
+
status += "Decisions: total from <decisions> tag | applied: count (usually 0)\n"
|
|
750
|
+
status += "Signals: list every hook tag received THIS prompt\n"
|
|
751
|
+
status += "Applied: which signals shaped response, or 'none'\n"
|
|
752
|
+
status += "Tools: tools called THIS response, or 'none'\n"
|
|
753
|
+
status += "Gaps: missing context, or 'none'\n"
|
|
754
|
+
status += "Format: ```🔧 Vector DEVMODE``` block, under 8 lines, at END of EVERY response.\n"
|
|
755
|
+
else:
|
|
756
|
+
status += "DEVMODE=false — do NOT append any debug block.\n"
|
|
757
|
+
|
|
758
|
+
status += "</vector-status>\n"
|
|
759
|
+
|
|
760
|
+
if decisions_summary:
|
|
761
|
+
status += "\n" + decisions_summary + "\n"
|
|
762
|
+
|
|
763
|
+
output = {
|
|
764
|
+
"hookSpecificOutput": {
|
|
765
|
+
"hookEventName": "UserPromptSubmit",
|
|
766
|
+
"additionalContext": status
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
print(json.dumps(output))
|
|
770
|
+
|
|
771
|
+
sys.exit(0)
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
if __name__ == "__main__":
|
|
775
|
+
main()
|