@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,248 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Hook: satellite-detection.py
|
|
4
|
+
Purpose: Scans the workspace recursively for .drive/drive.json files,
|
|
5
|
+
auto-registers new satellites, and syncs drive.json state to
|
|
6
|
+
workspace.json and projects.json.
|
|
7
|
+
Triggers: SessionStart — runs once when Claude Code starts a session.
|
|
8
|
+
Output: <momentum-satellites> block if new satellites registered, silent otherwise.
|
|
9
|
+
|
|
10
|
+
Sync flow (drive.json → workspace.json → projects.json):
|
|
11
|
+
1. Discover drive.json files across workspace
|
|
12
|
+
2. Register new satellites (existing behavior)
|
|
13
|
+
3. Sync drive.json state to workspace.json satellite entries
|
|
14
|
+
4. Cross-check projects.json: update drive field on matching projects
|
|
15
|
+
Respects satellite.sync: false as opt-out for steps 3-4.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import sys
|
|
19
|
+
import json
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
# Workspace root — find .accel/momentum/ relative to this hook's location
|
|
24
|
+
HOOK_DIR = Path(__file__).resolve().parent
|
|
25
|
+
WORKSPACE_ROOT = HOOK_DIR.parent.parent # hooks/ -> .accel/momentum/ -> workspace
|
|
26
|
+
BASE_DIR = WORKSPACE_ROOT / ".accel/momentum"
|
|
27
|
+
MANIFEST_FILE = BASE_DIR / "workspace.json"
|
|
28
|
+
PROJECTS_FILE = BASE_DIR / "data" / "projects.json"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def has_hidden_component(path: Path, workspace_root: Path) -> bool:
|
|
32
|
+
"""
|
|
33
|
+
Return True if any component of path (relative to workspace_root) starts with '.',
|
|
34
|
+
excluding '.drive' itself (which is the expected target directory).
|
|
35
|
+
"""
|
|
36
|
+
try:
|
|
37
|
+
rel = path.relative_to(workspace_root)
|
|
38
|
+
except ValueError:
|
|
39
|
+
return True # Can't relativize — skip it
|
|
40
|
+
return any(part.startswith(".") and part != ".drive" for part in rel.parts)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def find_drive_json_files(workspace_root: Path) -> list[Path]:
|
|
44
|
+
"""
|
|
45
|
+
Recursively scan workspace_root for .drive/drive.json files.
|
|
46
|
+
Skips any path that has a hidden directory component (starts with '.').
|
|
47
|
+
"""
|
|
48
|
+
results = []
|
|
49
|
+
try:
|
|
50
|
+
for drive_json in workspace_root.rglob(".drive/drive.json"):
|
|
51
|
+
if not has_hidden_component(drive_json, workspace_root):
|
|
52
|
+
results.append(drive_json)
|
|
53
|
+
except (OSError, PermissionError):
|
|
54
|
+
pass
|
|
55
|
+
return results
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def should_sync(drive_data: dict) -> bool:
|
|
59
|
+
"""Check if this satellite opts into sync. Default: True."""
|
|
60
|
+
satellite = drive_data.get("satellite", {})
|
|
61
|
+
return satellite.get("sync", True)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def sync_to_workspace(satellites: dict, drive_data: dict, name: str) -> bool:
|
|
65
|
+
"""Sync drive.json state to workspace.json satellite entry. Returns True if changed."""
|
|
66
|
+
if name not in satellites:
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
sat = satellites[name]
|
|
70
|
+
changed = False
|
|
71
|
+
|
|
72
|
+
phase = drive_data.get("phase", {})
|
|
73
|
+
loop = drive_data.get("loop", {})
|
|
74
|
+
handoff = drive_data.get("handoff", {})
|
|
75
|
+
|
|
76
|
+
updates = {
|
|
77
|
+
"phase_name": phase.get("name"),
|
|
78
|
+
"phase_number": phase.get("number"),
|
|
79
|
+
"phase_status": phase.get("status"),
|
|
80
|
+
"loop_position": loop.get("position"),
|
|
81
|
+
"handoff": handoff.get("present", False),
|
|
82
|
+
"last_plan_completed_at": drive_data.get("last_plan_completed_at"),
|
|
83
|
+
"next_action": drive_data.get("next_action"),
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
for key, value in updates.items():
|
|
87
|
+
if sat.get(key) != value:
|
|
88
|
+
sat[key] = value
|
|
89
|
+
changed = True
|
|
90
|
+
|
|
91
|
+
return changed
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def sync_to_projects(drive_data: dict, name: str, projects_data: dict) -> bool:
|
|
95
|
+
"""Sync drive.json state to matching project in projects.json. Returns True if changed."""
|
|
96
|
+
for item in projects_data.get("items", []):
|
|
97
|
+
drive_field = item.get("drive")
|
|
98
|
+
if not drive_field or drive_field.get("satellite_name") != name:
|
|
99
|
+
continue
|
|
100
|
+
|
|
101
|
+
# Found matching project — update drive field
|
|
102
|
+
phase = drive_data.get("phase", {})
|
|
103
|
+
loop = drive_data.get("loop", {})
|
|
104
|
+
handoff = drive_data.get("handoff", {})
|
|
105
|
+
timestamps = drive_data.get("timestamps", {})
|
|
106
|
+
|
|
107
|
+
drive_field["phase"] = phase.get("name")
|
|
108
|
+
drive_field["loop_position"] = loop.get("position")
|
|
109
|
+
drive_field["last_update"] = timestamps.get("updated_at")
|
|
110
|
+
|
|
111
|
+
# Calculate completed phases
|
|
112
|
+
if phase.get("status") == "complete":
|
|
113
|
+
drive_field["completed_phases"] = phase.get("number")
|
|
114
|
+
else:
|
|
115
|
+
drive_field["completed_phases"] = max(0, (phase.get("number", 1) or 1) - 1)
|
|
116
|
+
|
|
117
|
+
# Copy enriched fields
|
|
118
|
+
drive_field["last_plan_completed_at"] = drive_data.get("last_plan_completed_at")
|
|
119
|
+
drive_field["handoff"] = handoff.get("present", False)
|
|
120
|
+
|
|
121
|
+
item["updated_at"] = datetime.now().isoformat()
|
|
122
|
+
return True
|
|
123
|
+
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def main():
|
|
128
|
+
# Skip if Momentum is not installed
|
|
129
|
+
if not BASE_DIR.exists() or not MANIFEST_FILE.exists():
|
|
130
|
+
sys.exit(0)
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
with open(MANIFEST_FILE, "r") as f:
|
|
134
|
+
manifest = json.load(f)
|
|
135
|
+
except (json.JSONDecodeError, OSError):
|
|
136
|
+
sys.exit(0)
|
|
137
|
+
|
|
138
|
+
satellites = manifest.get("satellites", {})
|
|
139
|
+
new_registrations = []
|
|
140
|
+
workspace_changed = False
|
|
141
|
+
projects_changed = False
|
|
142
|
+
|
|
143
|
+
# Load projects.json for cross-check (if it exists)
|
|
144
|
+
projects_data = None
|
|
145
|
+
if PROJECTS_FILE.exists():
|
|
146
|
+
try:
|
|
147
|
+
with open(PROJECTS_FILE, "r") as f:
|
|
148
|
+
projects_data = json.load(f)
|
|
149
|
+
except (json.JSONDecodeError, OSError):
|
|
150
|
+
projects_data = None
|
|
151
|
+
|
|
152
|
+
drive_files = find_drive_json_files(WORKSPACE_ROOT)
|
|
153
|
+
|
|
154
|
+
# Collect drive data for sync pass
|
|
155
|
+
drive_registry = {} # name → drive_data
|
|
156
|
+
|
|
157
|
+
for drive_json_path in drive_files:
|
|
158
|
+
try:
|
|
159
|
+
with open(drive_json_path, "r") as f:
|
|
160
|
+
drive_data = json.load(f)
|
|
161
|
+
except (json.JSONDecodeError, OSError):
|
|
162
|
+
continue # Malformed or unreadable — skip silently
|
|
163
|
+
|
|
164
|
+
name = drive_data.get("name")
|
|
165
|
+
if not name:
|
|
166
|
+
continue # No name field — skip
|
|
167
|
+
|
|
168
|
+
drive_registry[name] = drive_data
|
|
169
|
+
|
|
170
|
+
# Read last_activity from drive.json timestamps (if present)
|
|
171
|
+
last_activity = drive_data.get("timestamps", {}).get("updated_at")
|
|
172
|
+
|
|
173
|
+
if name in satellites:
|
|
174
|
+
# Already registered — refresh last_activity if available
|
|
175
|
+
if last_activity and satellites[name].get("last_activity") != last_activity:
|
|
176
|
+
satellites[name]["last_activity"] = last_activity
|
|
177
|
+
workspace_changed = True
|
|
178
|
+
continue
|
|
179
|
+
|
|
180
|
+
# New satellite — derive relative path
|
|
181
|
+
project_dir = drive_json_path.parent.parent
|
|
182
|
+
try:
|
|
183
|
+
rel_path = str(project_dir.relative_to(WORKSPACE_ROOT))
|
|
184
|
+
except ValueError:
|
|
185
|
+
continue # Can't relativize — skip
|
|
186
|
+
|
|
187
|
+
# Build registration entry
|
|
188
|
+
entry = {
|
|
189
|
+
"path": rel_path,
|
|
190
|
+
"engine": "drive",
|
|
191
|
+
"state": f"{rel_path}/.drive/STATE.md",
|
|
192
|
+
"registered": datetime.now().strftime("%Y-%m-%d"),
|
|
193
|
+
"groom_check": True,
|
|
194
|
+
}
|
|
195
|
+
if last_activity:
|
|
196
|
+
entry["last_activity"] = last_activity
|
|
197
|
+
|
|
198
|
+
satellites[name] = entry
|
|
199
|
+
new_registrations.append(name)
|
|
200
|
+
workspace_changed = True
|
|
201
|
+
|
|
202
|
+
# --- Sync pass: drive.json → workspace.json + projects.json ---
|
|
203
|
+
for name, drive_data in drive_registry.items():
|
|
204
|
+
if not should_sync(drive_data):
|
|
205
|
+
continue # Opt-out — skip sync
|
|
206
|
+
|
|
207
|
+
# Sync to workspace.json
|
|
208
|
+
if sync_to_workspace(satellites, drive_data, name):
|
|
209
|
+
workspace_changed = True
|
|
210
|
+
|
|
211
|
+
# Sync to projects.json
|
|
212
|
+
if projects_data and sync_to_projects(drive_data, name, projects_data):
|
|
213
|
+
projects_changed = True
|
|
214
|
+
|
|
215
|
+
# Write workspace.json if changed
|
|
216
|
+
if workspace_changed:
|
|
217
|
+
try:
|
|
218
|
+
manifest["satellites"] = satellites
|
|
219
|
+
with open(MANIFEST_FILE, "w") as f:
|
|
220
|
+
json.dump(manifest, f, indent=2)
|
|
221
|
+
f.write("\n")
|
|
222
|
+
except OSError:
|
|
223
|
+
pass # Write failed — silent
|
|
224
|
+
|
|
225
|
+
# Write projects.json if changed
|
|
226
|
+
if projects_changed and projects_data:
|
|
227
|
+
try:
|
|
228
|
+
projects_data["last_modified"] = datetime.now().isoformat()
|
|
229
|
+
with open(PROJECTS_FILE, "w") as f:
|
|
230
|
+
json.dump(projects_data, f, indent=2)
|
|
231
|
+
f.write("\n")
|
|
232
|
+
except OSError:
|
|
233
|
+
pass # Write failed — silent
|
|
234
|
+
|
|
235
|
+
# Output only for new registrations
|
|
236
|
+
if new_registrations:
|
|
237
|
+
names_str = ", ".join(new_registrations)
|
|
238
|
+
n = len(new_registrations)
|
|
239
|
+
print(f"<momentum-satellites>\nAuto-registered {n} new satellite(s): {names_str}\n</momentum-satellites>")
|
|
240
|
+
|
|
241
|
+
sys.exit(0)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
if __name__ == "__main__":
|
|
245
|
+
try:
|
|
246
|
+
main()
|
|
247
|
+
except Exception:
|
|
248
|
+
sys.exit(0)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Momentum MCP — Surface CRUD Server
|
|
4
|
+
* Builder's Automated State Engine
|
|
5
|
+
*
|
|
6
|
+
* Generic CRUD operations for any registered data surface.
|
|
7
|
+
* Surfaces are registered in workspace.json and stored as JSON in .accel/momentum/data/.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
11
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
12
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import { fileURLToPath } from 'url';
|
|
15
|
+
|
|
16
|
+
// Tool group imports
|
|
17
|
+
import { TOOLS as surfaceTools, handleTool as handleSurface } from './tools/surfaces.js';
|
|
18
|
+
import { TOOLS as projectTools, handleTool as handleProject } from './tools/projects.js';
|
|
19
|
+
import { TOOLS as stateTools, handleTool as handleState } from './tools/state.js';
|
|
20
|
+
import { TOOLS as entityTools, handleTool as handleEntity } from './tools/entities.js';
|
|
21
|
+
import { TOOLS as operatorTools, handleTool as handleOperator } from './tools/operator.js';
|
|
22
|
+
import { TOOLS as psmmTools, handleTool as handlePsmm } from './tools/psmm.js';
|
|
23
|
+
|
|
24
|
+
// ============================================================
|
|
25
|
+
// CONFIGURATION
|
|
26
|
+
// ============================================================
|
|
27
|
+
|
|
28
|
+
// Resolve workspace from this file's location: momentum-mcp/ → .accel/momentum/ → workspace root
|
|
29
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
30
|
+
const WORKSPACE_PATH = path.resolve(__dirname, '../..');
|
|
31
|
+
|
|
32
|
+
function debugLog(...args) {
|
|
33
|
+
console.error('[Momentum]', new Date().toISOString(), ...args);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ============================================================
|
|
37
|
+
// TOOL REGISTRY
|
|
38
|
+
// ============================================================
|
|
39
|
+
|
|
40
|
+
const ALL_TOOLS = [...surfaceTools, ...projectTools, ...stateTools, ...entityTools, ...operatorTools, ...psmmTools];
|
|
41
|
+
|
|
42
|
+
// Build handler lookup: tool name → handler function
|
|
43
|
+
const TOOL_HANDLERS = {};
|
|
44
|
+
for (const tool of surfaceTools) TOOL_HANDLERS[tool.name] = handleSurface;
|
|
45
|
+
for (const tool of projectTools) TOOL_HANDLERS[tool.name] = handleProject;
|
|
46
|
+
for (const tool of stateTools) TOOL_HANDLERS[tool.name] = handleState;
|
|
47
|
+
for (const tool of entityTools) TOOL_HANDLERS[tool.name] = handleEntity;
|
|
48
|
+
for (const tool of operatorTools) TOOL_HANDLERS[tool.name] = handleOperator;
|
|
49
|
+
for (const tool of psmmTools) TOOL_HANDLERS[tool.name] = handlePsmm;
|
|
50
|
+
|
|
51
|
+
// ============================================================
|
|
52
|
+
// MCP SERVER
|
|
53
|
+
// ============================================================
|
|
54
|
+
|
|
55
|
+
const server = new Server({
|
|
56
|
+
name: "momentum-mcp",
|
|
57
|
+
version: "1.0.0",
|
|
58
|
+
}, {
|
|
59
|
+
capabilities: {
|
|
60
|
+
tools: {},
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
debugLog('Momentum MCP Server initialized');
|
|
65
|
+
debugLog('Workspace:', WORKSPACE_PATH);
|
|
66
|
+
debugLog('Tool groups: surfaces (%d), projects (%d), state (%d), entities (%d), psmm (%d)',
|
|
67
|
+
surfaceTools.length, projectTools.length, stateTools.length, entityTools.length, psmmTools.length);
|
|
68
|
+
debugLog('Total tools:', ALL_TOOLS.length);
|
|
69
|
+
|
|
70
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
71
|
+
debugLog('List tools request');
|
|
72
|
+
return { tools: ALL_TOOLS };
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
76
|
+
const { name, arguments: args } = request.params;
|
|
77
|
+
debugLog('Call tool:', name);
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const handler = TOOL_HANDLERS[name];
|
|
81
|
+
if (!handler) {
|
|
82
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const result = await handler(name, args || {}, WORKSPACE_PATH);
|
|
86
|
+
|
|
87
|
+
if (result === null) {
|
|
88
|
+
throw new Error(`Tool ${name} returned null — handler mismatch`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
93
|
+
isError: false,
|
|
94
|
+
};
|
|
95
|
+
} catch (error) {
|
|
96
|
+
debugLog('Error:', error.message);
|
|
97
|
+
return {
|
|
98
|
+
content: [{ type: "text", text: `Error: ${error.message}` }],
|
|
99
|
+
isError: true,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// ============================================================
|
|
105
|
+
// RUN
|
|
106
|
+
// ============================================================
|
|
107
|
+
|
|
108
|
+
async function runServer() {
|
|
109
|
+
const transport = new StdioServerTransport();
|
|
110
|
+
await server.connect(transport);
|
|
111
|
+
console.error("Momentum MCP Server running on stdio");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
await runServer();
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error("Fatal error:", error);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mission Control Entities — CRUD for entities.json
|
|
3
|
+
* People and organizations with relational links to projects
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
|
|
9
|
+
function debugLog(...args) {
|
|
10
|
+
console.error('[Momentum:entities]', new Date().toISOString(), ...args);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// ============================================================
|
|
14
|
+
// HELPERS
|
|
15
|
+
// ============================================================
|
|
16
|
+
|
|
17
|
+
function getEntitiesPath(workspacePath) {
|
|
18
|
+
return join(workspacePath, '.accel/momentum', 'data', 'entities.json');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function readEntities(workspacePath) {
|
|
22
|
+
const filepath = getEntitiesPath(workspacePath);
|
|
23
|
+
if (!existsSync(filepath)) {
|
|
24
|
+
return { version: 1, last_modified: null, entities: [] };
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(readFileSync(filepath, 'utf-8'));
|
|
28
|
+
} catch (error) {
|
|
29
|
+
debugLog('Error reading entities.json:', error.message);
|
|
30
|
+
return { version: 1, last_modified: null, entities: [] };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function writeEntities(workspacePath, data) {
|
|
35
|
+
const filepath = getEntitiesPath(workspacePath);
|
|
36
|
+
data.last_modified = new Date().toISOString();
|
|
37
|
+
writeFileSync(filepath, JSON.stringify(data, null, 2), 'utf-8');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function generateEntityId(entities) {
|
|
41
|
+
let max = 0;
|
|
42
|
+
for (const entity of entities) {
|
|
43
|
+
const match = (entity.id || '').match(/^ENT-(\d+)$/);
|
|
44
|
+
if (match) {
|
|
45
|
+
const num = parseInt(match[1], 10);
|
|
46
|
+
if (num > max) max = num;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return `ENT-${String(max + 1).padStart(3, '0')}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function formatTimestamp() {
|
|
53
|
+
return new Date().toISOString();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ============================================================
|
|
57
|
+
// TOOL DEFINITIONS
|
|
58
|
+
// ============================================================
|
|
59
|
+
|
|
60
|
+
export const TOOLS = [
|
|
61
|
+
{
|
|
62
|
+
name: "momentum_list_entities",
|
|
63
|
+
description: "List all entities with optional type filter (person/organization).",
|
|
64
|
+
inputSchema: {
|
|
65
|
+
type: "object",
|
|
66
|
+
properties: {
|
|
67
|
+
type: { type: "string", enum: ["person", "organization"], description: "Filter by entity type" }
|
|
68
|
+
},
|
|
69
|
+
required: []
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "momentum_add_entity",
|
|
74
|
+
description: "Add a new person or organization entity. Auto-generates ENT-NNN ID.",
|
|
75
|
+
inputSchema: {
|
|
76
|
+
type: "object",
|
|
77
|
+
properties: {
|
|
78
|
+
name: { type: "string", description: "Display name" },
|
|
79
|
+
type: { type: "string", enum: ["person", "organization"], description: "Entity type" },
|
|
80
|
+
role: { type: "string", description: "Primary role (owner, client, partner, contractor, team member, employer)" }
|
|
81
|
+
},
|
|
82
|
+
required: ["name", "type"]
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "momentum_update_entity",
|
|
87
|
+
description: "Update an entity's fields by ID. Shallow merge — only specified fields updated.",
|
|
88
|
+
inputSchema: {
|
|
89
|
+
type: "object",
|
|
90
|
+
properties: {
|
|
91
|
+
id: { type: "string", description: "Entity ID (e.g., 'ENT-001')" },
|
|
92
|
+
data: { type: "object", description: "Fields to update" }
|
|
93
|
+
},
|
|
94
|
+
required: ["id", "data"]
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "momentum_link_entity",
|
|
99
|
+
description: "Add a relation between an entity and a project item. Avoids duplicate relations.",
|
|
100
|
+
inputSchema: {
|
|
101
|
+
type: "object",
|
|
102
|
+
properties: {
|
|
103
|
+
id: { type: "string", description: "Entity ID (e.g., 'ENT-001')" },
|
|
104
|
+
project_id: { type: "string", description: "Project item ID (e.g., 'PRJ-003')" },
|
|
105
|
+
relationship: { type: "string", description: "Relationship type (stakeholder, client, owner, partner, contractor, assignee)" }
|
|
106
|
+
},
|
|
107
|
+
required: ["id", "project_id", "relationship"]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
// ============================================================
|
|
113
|
+
// TOOL HANDLERS
|
|
114
|
+
// ============================================================
|
|
115
|
+
|
|
116
|
+
function handleListEntities(args, workspacePath) {
|
|
117
|
+
debugLog('Listing entities');
|
|
118
|
+
const data = readEntities(workspacePath);
|
|
119
|
+
let entities = data.entities;
|
|
120
|
+
|
|
121
|
+
if (args.type) {
|
|
122
|
+
entities = entities.filter(e => e.type === args.type);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return { entities, count: entities.length, total: data.entities.length };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function handleAddEntity(args, workspacePath) {
|
|
129
|
+
const { name, type } = args;
|
|
130
|
+
if (!name) throw new Error('Missing required parameter: name');
|
|
131
|
+
if (!type) throw new Error('Missing required parameter: type');
|
|
132
|
+
|
|
133
|
+
const data = readEntities(workspacePath);
|
|
134
|
+
const now = formatTimestamp();
|
|
135
|
+
const id = generateEntityId(data.entities);
|
|
136
|
+
|
|
137
|
+
const entity = {
|
|
138
|
+
id,
|
|
139
|
+
name,
|
|
140
|
+
type,
|
|
141
|
+
role: args.role || null,
|
|
142
|
+
relations: [],
|
|
143
|
+
notes: [],
|
|
144
|
+
created_at: now,
|
|
145
|
+
updated_at: now
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
data.entities.push(entity);
|
|
149
|
+
writeEntities(workspacePath, data);
|
|
150
|
+
|
|
151
|
+
debugLog(`Added ${type} ${id}: ${name}`);
|
|
152
|
+
return entity;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function handleUpdateEntity(args, workspacePath) {
|
|
156
|
+
const { id, data: updateData } = args;
|
|
157
|
+
if (!id) throw new Error('Missing required parameter: id');
|
|
158
|
+
if (!updateData) throw new Error('Missing required parameter: data');
|
|
159
|
+
|
|
160
|
+
const data = readEntities(workspacePath);
|
|
161
|
+
const index = data.entities.findIndex(e => e.id === id);
|
|
162
|
+
if (index === -1) {
|
|
163
|
+
throw new Error(`Entity "${id}" not found. Available: ${data.entities.map(e => e.id).join(', ') || 'none'}`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
data.entities[index] = {
|
|
167
|
+
...data.entities[index],
|
|
168
|
+
...updateData,
|
|
169
|
+
id, // Prevent ID overwrite
|
|
170
|
+
updated_at: formatTimestamp()
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
writeEntities(workspacePath, data);
|
|
174
|
+
|
|
175
|
+
debugLog(`Updated ${id}`);
|
|
176
|
+
return data.entities[index];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function handleLinkEntity(args, workspacePath) {
|
|
180
|
+
const { id, project_id, relationship } = args;
|
|
181
|
+
if (!id) throw new Error('Missing required parameter: id');
|
|
182
|
+
if (!project_id) throw new Error('Missing required parameter: project_id');
|
|
183
|
+
if (!relationship) throw new Error('Missing required parameter: relationship');
|
|
184
|
+
|
|
185
|
+
const data = readEntities(workspacePath);
|
|
186
|
+
const index = data.entities.findIndex(e => e.id === id);
|
|
187
|
+
if (index === -1) {
|
|
188
|
+
throw new Error(`Entity "${id}" not found`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const entity = data.entities[index];
|
|
192
|
+
if (!entity.relations) entity.relations = [];
|
|
193
|
+
|
|
194
|
+
// Check for duplicate
|
|
195
|
+
const exists = entity.relations.some(r => r.project_id === project_id && r.relationship === relationship);
|
|
196
|
+
if (exists) {
|
|
197
|
+
return { already_linked: true, id, project_id, relationship, message: 'Relation already exists' };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
entity.relations.push({ project_id, relationship });
|
|
201
|
+
entity.updated_at = formatTimestamp();
|
|
202
|
+
|
|
203
|
+
writeEntities(workspacePath, data);
|
|
204
|
+
|
|
205
|
+
debugLog(`Linked ${id} → ${project_id} (${relationship})`);
|
|
206
|
+
return { id, project_id, relationship, relations_count: entity.relations.length };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ============================================================
|
|
210
|
+
// HANDLER DISPATCH
|
|
211
|
+
// ============================================================
|
|
212
|
+
|
|
213
|
+
export function handleTool(name, args, workspacePath) {
|
|
214
|
+
switch (name) {
|
|
215
|
+
case 'momentum_list_entities':
|
|
216
|
+
return handleListEntities(args, workspacePath);
|
|
217
|
+
case 'momentum_add_entity':
|
|
218
|
+
return handleAddEntity(args, workspacePath);
|
|
219
|
+
case 'momentum_update_entity':
|
|
220
|
+
return handleUpdateEntity(args, workspacePath);
|
|
221
|
+
case 'momentum_link_entity':
|
|
222
|
+
return handleLinkEntity(args, workspacePath);
|
|
223
|
+
default:
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
}
|