@cleocode/core 2026.3.76 → 2026.4.2
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/dist/agents/agent-schema.d.ts.map +1 -1
- package/dist/audit.d.ts +1 -1
- package/dist/audit.d.ts.map +1 -1
- package/dist/bootstrap.d.ts +2 -2
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/caamp/adapter.d.ts +6 -49
- package/dist/caamp/adapter.d.ts.map +1 -1
- package/dist/caamp/index.d.ts +2 -2
- package/dist/caamp/index.d.ts.map +1 -1
- package/dist/code/index.d.ts +10 -0
- package/dist/code/index.d.ts.map +1 -0
- package/dist/code/outline.d.ts +51 -0
- package/dist/code/outline.d.ts.map +1 -0
- package/dist/code/parser.d.ts +32 -0
- package/dist/code/parser.d.ts.map +1 -0
- package/dist/code/search.d.ts +42 -0
- package/dist/code/search.d.ts.map +1 -0
- package/dist/code/unfold.d.ts +44 -0
- package/dist/code/unfold.d.ts.map +1 -0
- package/dist/compliance/protocol-enforcement.d.ts +1 -1
- package/dist/compliance/protocol-rules.d.ts +1 -1
- package/dist/compliance/protocol-types.d.ts +2 -3
- package/dist/compliance/protocol-types.d.ts.map +1 -1
- package/dist/conduit/conduit-client.d.ts +14 -0
- package/dist/conduit/conduit-client.d.ts.map +1 -1
- package/dist/conduit/factory.d.ts +11 -1
- package/dist/conduit/factory.d.ts.map +1 -1
- package/dist/conduit/http-transport.d.ts +17 -5
- package/dist/conduit/http-transport.d.ts.map +1 -1
- package/dist/conduit/index.d.ts +5 -2
- package/dist/conduit/index.d.ts.map +1 -1
- package/dist/conduit/local-transport.d.ts +91 -0
- package/dist/conduit/local-transport.d.ts.map +1 -0
- package/dist/conduit/sse-transport.d.ts +68 -0
- package/dist/conduit/sse-transport.d.ts.map +1 -0
- package/dist/crypto/credentials.d.ts.map +1 -1
- package/dist/error-catalog.d.ts +3 -3
- package/dist/error-catalog.d.ts.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/hooks/handlers/index.d.ts +2 -2
- package/dist/hooks/handlers/index.d.ts.map +1 -1
- package/dist/hooks/handlers/notification-hooks.d.ts +31 -0
- package/dist/hooks/handlers/notification-hooks.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4646 -3476
- package/dist/index.js.map +4 -4
- package/dist/init.d.ts +6 -6
- package/dist/init.d.ts.map +1 -1
- package/dist/injection.d.ts.map +1 -1
- package/dist/internal.d.ts +7 -5
- package/dist/internal.d.ts.map +1 -1
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/tree-sitter-languages.d.ts +29 -0
- package/dist/lib/tree-sitter-languages.d.ts.map +1 -0
- package/dist/logger.d.ts +3 -3
- package/dist/memory/brain-links.d.ts.map +1 -1
- package/dist/memory/brain-maintenance.d.ts +13 -0
- package/dist/memory/brain-maintenance.d.ts.map +1 -1
- package/dist/memory/brain-retrieval.d.ts +1 -1
- package/dist/memory/brain-retrieval.d.ts.map +1 -1
- package/dist/memory/decisions.d.ts.map +1 -1
- package/dist/memory/engine-compat.d.ts +392 -25
- package/dist/memory/engine-compat.d.ts.map +1 -1
- package/dist/memory/index.d.ts +416 -3
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/metrics/token-service.d.ts +3 -3
- package/dist/metrics/token-service.d.ts.map +1 -1
- package/dist/orchestration/hierarchy.d.ts +32 -0
- package/dist/orchestration/hierarchy.d.ts.map +1 -0
- package/dist/orchestration/index.d.ts +1 -0
- package/dist/orchestration/index.d.ts.map +1 -1
- package/dist/paths.d.ts +335 -2
- package/dist/paths.d.ts.map +1 -1
- package/dist/routing/capability-matrix.d.ts +3 -3
- package/dist/routing/capability-matrix.d.ts.map +1 -1
- package/dist/scaffold.d.ts +422 -11
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/security/input-sanitization.d.ts +2 -2
- package/dist/skills/dynamic-skill-generator.d.ts +3 -2
- package/dist/skills/dynamic-skill-generator.d.ts.map +1 -1
- package/dist/skills/routing-table.d.ts +4 -4
- package/dist/skills/routing-table.d.ts.map +1 -1
- package/dist/store/agent-registry-accessor.d.ts +10 -433
- package/dist/store/agent-registry-accessor.d.ts.map +1 -1
- package/dist/store/cross-db-cleanup.d.ts +34 -0
- package/dist/store/cross-db-cleanup.d.ts.map +1 -1
- package/dist/store/provider.d.ts +1 -1
- package/dist/store/signaldock-sqlite.d.ts.map +1 -1
- package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
- package/dist/store/sqlite.d.ts +1 -1
- package/dist/store/task-store.d.ts.map +1 -1
- package/dist/store/tasks-schema.d.ts +4 -228
- package/dist/store/tasks-schema.d.ts.map +1 -1
- package/dist/store/validation-schemas.d.ts +4 -5
- package/dist/store/validation-schemas.d.ts.map +1 -1
- package/dist/system/archive-analytics.d.ts +1 -1
- package/dist/system/health.d.ts +2 -2
- package/dist/system/health.d.ts.map +1 -1
- package/dist/system/runtime.d.ts +2 -1
- package/dist/system/runtime.d.ts.map +1 -1
- package/dist/tasks/list.d.ts +1 -1
- package/dist/tasks/list.d.ts.map +1 -1
- package/dist/tasks/task-ops.d.ts +415 -3
- package/dist/tasks/task-ops.d.ts.map +1 -1
- package/dist/templates/parser.d.ts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/upgrade.d.ts +1 -1
- package/dist/upgrade.d.ts.map +1 -1
- package/dist/validation/operation-gate-validators.d.ts +1 -1
- package/dist/validation/operation-verification-gates.d.ts +3 -3
- package/dist/validation/param-utils.d.ts +6 -5
- package/dist/validation/param-utils.d.ts.map +1 -1
- package/dist/validation/validate-ops.d.ts +1 -1
- package/dist/validation/validate-ops.d.ts.map +1 -1
- package/package.json +19 -7
- package/src/__tests__/caamp-skill-install.test.js +0 -15
- package/src/__tests__/caamp-skill-install.test.js.map +1 -1
- package/src/__tests__/caamp-skill-install.test.ts +0 -16
- package/src/__tests__/injection-mvi-tiers.test.js +7 -7
- package/src/__tests__/injection-mvi-tiers.test.js.map +1 -1
- package/src/__tests__/injection-mvi-tiers.test.ts +55 -103
- package/src/agents/agent-schema.ts +2 -5
- package/src/audit.ts +2 -2
- package/src/bootstrap.ts +5 -39
- package/src/caamp/adapter.ts +3 -219
- package/src/caamp/index.ts +1 -13
- package/src/cant/__tests__/cant-agent-parse.test.d.ts.map +1 -0
- package/src/cant/__tests__/cant-agent-parse.test.js +77 -0
- package/src/cant/__tests__/cant-agent-parse.test.js.map +1 -0
- package/src/code/index.ts +10 -0
- package/src/code/outline.ts +214 -0
- package/src/code/parser.ts +331 -0
- package/src/code/search.ts +173 -0
- package/src/code/unfold.ts +204 -0
- package/src/codebase-map/analyzers/architecture.ts +2 -2
- package/src/compliance/protocol-enforcement.ts +1 -1
- package/src/compliance/protocol-rules.ts +1 -1
- package/src/compliance/protocol-types.ts +2 -3
- package/src/conduit/__tests__/dual-api-e2e.test.d.ts.map +1 -0
- package/src/conduit/__tests__/dual-api-e2e.test.js +178 -0
- package/src/conduit/__tests__/dual-api-e2e.test.js.map +1 -0
- package/src/conduit/__tests__/dual-api-e2e.test.ts +212 -0
- package/src/conduit/__tests__/local-credential-flow.test.d.ts.map +1 -0
- package/src/conduit/__tests__/local-credential-flow.test.js +185 -0
- package/src/conduit/__tests__/local-credential-flow.test.js.map +1 -0
- package/src/conduit/__tests__/local-credential-flow.test.ts +230 -0
- package/src/conduit/__tests__/local-transport.test.d.ts.map +1 -0
- package/src/conduit/__tests__/local-transport.test.js +404 -0
- package/src/conduit/__tests__/local-transport.test.js.map +1 -0
- package/src/conduit/__tests__/local-transport.test.ts +509 -0
- package/src/conduit/__tests__/sse-transport.test.d.ts.map +1 -0
- package/src/conduit/__tests__/sse-transport.test.js +291 -0
- package/src/conduit/__tests__/sse-transport.test.js.map +1 -0
- package/src/conduit/__tests__/sse-transport.test.ts +344 -0
- package/src/conduit/conduit-client.ts +14 -0
- package/src/conduit/factory.ts +29 -8
- package/src/conduit/http-transport.ts +78 -16
- package/src/conduit/index.ts +5 -2
- package/src/conduit/local-transport.ts +309 -0
- package/src/conduit/sse-transport.ts +382 -0
- package/src/crypto/credentials.ts +59 -13
- package/src/error-catalog.ts +3 -3
- package/src/errors.ts +1 -1
- package/src/hooks/__tests__/provider-hooks.test.js +4 -4
- package/src/hooks/__tests__/provider-hooks.test.js.map +1 -1
- package/src/hooks/__tests__/provider-hooks.test.ts +4 -4
- package/src/hooks/handlers/__tests__/hook-automation-e2e.test.js +2 -2
- package/src/hooks/handlers/__tests__/hook-automation-e2e.test.js.map +1 -1
- package/src/hooks/handlers/__tests__/hook-automation-e2e.test.ts +6 -4
- package/src/hooks/handlers/index.ts +2 -6
- package/src/hooks/handlers/notification-hooks.ts +65 -0
- package/src/index.ts +2 -1
- package/src/init.ts +14 -54
- package/src/injection.ts +4 -3
- package/src/internal.ts +7 -5
- package/src/lib/index.ts +8 -0
- package/src/lib/tree-sitter-languages.ts +88 -0
- package/src/logger.ts +5 -5
- package/src/memory/__tests__/brain-links.test.js +13 -0
- package/src/memory/__tests__/brain-links.test.js.map +1 -1
- package/src/memory/__tests__/brain-links.test.ts +14 -0
- package/src/memory/__tests__/brain-retrieval.test.js +9 -0
- package/src/memory/__tests__/brain-retrieval.test.js.map +1 -1
- package/src/memory/__tests__/brain-retrieval.test.ts +10 -0
- package/src/memory/__tests__/session-memory.test.js +16 -0
- package/src/memory/__tests__/session-memory.test.js.map +1 -1
- package/src/memory/__tests__/session-memory.test.ts +17 -0
- package/src/memory/brain-links.ts +17 -0
- package/src/memory/brain-maintenance.ts +33 -1
- package/src/memory/brain-retrieval.ts +19 -3
- package/src/memory/decisions.ts +18 -2
- package/src/memory/engine-compat.ts +392 -25
- package/src/memory/index.ts +417 -4
- package/src/metrics/token-service.ts +4 -4
- package/src/migration/index.ts +1 -1
- package/src/orchestration/hierarchy.ts +202 -0
- package/src/orchestration/index.ts +1 -0
- package/src/paths.ts +340 -5
- package/src/routing/capability-matrix.ts +49 -49
- package/src/scaffold.ts +428 -70
- package/src/security/input-sanitization.ts +4 -4
- package/src/sessions/__tests__/session-grade.integration.test.js +9 -9
- package/src/sessions/__tests__/session-grade.integration.test.ts +9 -9
- package/src/sessions/__tests__/session-grade.test.js +10 -10
- package/src/sessions/__tests__/session-grade.test.js.map +1 -1
- package/src/sessions/__tests__/session-grade.test.ts +10 -10
- package/src/sessions/session-grade.ts +4 -4
- package/src/skills/__tests__/dynamic-skill-generator.test.js +24 -26
- package/src/skills/__tests__/dynamic-skill-generator.test.js.map +1 -1
- package/src/skills/__tests__/dynamic-skill-generator.test.ts +24 -26
- package/src/skills/__tests__/routing-table.test.js +22 -22
- package/src/skills/__tests__/routing-table.test.js.map +1 -1
- package/src/skills/__tests__/routing-table.test.ts +23 -23
- package/src/skills/dynamic-skill-generator.ts +13 -24
- package/src/skills/routing-table.ts +4 -4
- package/src/store/__tests__/data-safety-central.test.js +8 -0
- package/src/store/__tests__/data-safety-central.test.js.map +1 -1
- package/src/store/__tests__/data-safety-central.test.ts +8 -0
- package/src/store/__tests__/safety-accessor.test.js +8 -0
- package/src/store/__tests__/safety-accessor.test.js.map +1 -1
- package/src/store/__tests__/safety-accessor.test.ts +8 -0
- package/src/store/agent-registry-accessor.ts +284 -108
- package/src/store/cross-db-cleanup.ts +175 -1
- package/src/store/provider.ts +2 -2
- package/src/store/signaldock-sqlite.ts +262 -60
- package/src/store/sqlite-data-accessor.ts +3 -0
- package/src/store/sqlite.ts +2 -2
- package/src/store/task-store.ts +8 -1
- package/src/store/tasks-schema.ts +5 -40
- package/src/system/__tests__/health.test.js +2 -2
- package/src/system/__tests__/health.test.js.map +1 -1
- package/src/system/__tests__/health.test.ts +2 -2
- package/src/system/archive-analytics.ts +1 -1
- package/src/system/health.ts +43 -19
- package/src/system/inject-generate.ts +20 -20
- package/src/system/runtime.ts +5 -4
- package/src/tasks/atomicity.ts +1 -1
- package/src/tasks/list.ts +1 -1
- package/src/tasks/task-ops.ts +415 -3
- package/src/templates/parser.ts +1 -1
- package/src/ui/index.ts +4 -4
- package/src/upgrade.ts +3 -14
- package/src/validation/operation-gate-validators.ts +1 -1
- package/src/validation/operation-verification-gates.ts +3 -3
- package/src/validation/param-utils.ts +11 -10
- package/src/validation/validate-ops.ts +6 -6
- package/templates/CLEO-INJECTION.md +38 -110
- package/dist/hooks/handlers/mcp-hooks.d.ts +0 -48
- package/dist/hooks/handlers/mcp-hooks.d.ts.map +0 -1
- package/dist/mcp/index.d.ts +0 -42
- package/dist/mcp/index.d.ts.map +0 -1
- package/src/__tests__/audit-prune.test.d.ts +0 -2
- package/src/__tests__/caamp-skill-install.test.d.ts +0 -14
- package/src/__tests__/cli-mcp-parity.integration.test.d.ts +0 -34
- package/src/__tests__/cli-mcp-parity.integration.test.d.ts.map +0 -1
- package/src/__tests__/cli-mcp-parity.integration.test.js +0 -898
- package/src/__tests__/cli-mcp-parity.integration.test.js.map +0 -1
- package/src/__tests__/cli-parity.test.d.ts +0 -9
- package/src/__tests__/config.test.d.ts +0 -7
- package/src/__tests__/core-parity.test.d.ts +0 -17
- package/src/__tests__/error-catalog.test.d.ts +0 -2
- package/src/__tests__/golden-parity.test.d.ts +0 -12
- package/src/__tests__/hooks.test.d.ts +0 -5
- package/src/__tests__/human-output.test.d.ts +0 -12
- package/src/__tests__/index-api-compat.test.d.ts +0 -2
- package/src/__tests__/init-e2e.test.d.ts +0 -12
- package/src/__tests__/injection-chain.test.d.ts +0 -18
- package/src/__tests__/injection-mvi-tiers.test.d.ts +0 -14
- package/src/__tests__/injection-shared.test.d.ts +0 -10
- package/src/__tests__/lafs-conformance.test.d.ts +0 -18
- package/src/__tests__/logger.test.d.ts +0 -2
- package/src/__tests__/mcp-install-verify.test.d.ts +0 -13
- package/src/__tests__/mcp-install-verify.test.d.ts.map +0 -1
- package/src/__tests__/mcp-install-verify.test.js +0 -177
- package/src/__tests__/mcp-install-verify.test.js.map +0 -1
- package/src/__tests__/mcp-install-verify.test.ts +0 -217
- package/src/__tests__/paths.test.d.ts +0 -7
- package/src/__tests__/project-info.test.d.ts +0 -2
- package/src/__tests__/rcsd-pipeline-e2e.test.d.ts +0 -14
- package/src/__tests__/remote.test.d.ts +0 -6
- package/src/__tests__/scaffold.test.d.ts +0 -6
- package/src/__tests__/schema-management.test.d.ts +0 -5
- package/src/__tests__/schema.test.d.ts +0 -2
- package/src/__tests__/sharing.test.d.ts +0 -6
- package/src/__tests__/snapshot.test.d.ts +0 -6
- package/src/__tests__/upgrade.test.d.ts +0 -7
- package/src/adapters/__tests__/discovery.test.d.ts +0 -6
- package/src/adapters/__tests__/manager.test.d.ts +0 -6
- package/src/agents/__tests__/agent-registry.test.d.ts +0 -12
- package/src/agents/__tests__/capacity.test.d.ts +0 -7
- package/src/agents/__tests__/execution-learning.test.d.ts +0 -14
- package/src/agents/__tests__/health-monitor.test.d.ts +0 -10
- package/src/agents/__tests__/registry.test.d.ts +0 -8
- package/src/agents/__tests__/retry.test.d.ts +0 -7
- package/src/compliance/__tests__/sync.test.d.ts +0 -5
- package/src/hooks/__tests__/provider-hooks.test.d.ts +0 -2
- package/src/hooks/__tests__/registry.test.d.ts +0 -2
- package/src/hooks/handlers/__tests__/error-hooks.test.d.ts +0 -2
- package/src/hooks/handlers/__tests__/file-hooks.test.d.ts +0 -2
- package/src/hooks/handlers/__tests__/hook-automation-e2e.test.d.ts +0 -13
- package/src/hooks/handlers/__tests__/mcp-hooks.test.d.ts +0 -2
- package/src/hooks/handlers/__tests__/mcp-hooks.test.d.ts.map +0 -1
- package/src/hooks/handlers/__tests__/mcp-hooks.test.js +0 -119
- package/src/hooks/handlers/__tests__/mcp-hooks.test.js.map +0 -1
- package/src/hooks/handlers/__tests__/mcp-hooks.test.ts +0 -150
- package/src/hooks/handlers/__tests__/session-hooks.test.d.ts +0 -2
- package/src/hooks/handlers/__tests__/task-hooks.test.d.ts +0 -2
- package/src/hooks/handlers/mcp-hooks.ts +0 -162
- package/src/intelligence/__tests__/adaptive-validation.test.d.ts +0 -11
- package/src/intelligence/__tests__/impact.test.d.ts +0 -16
- package/src/intelligence/__tests__/patterns.test.d.ts +0 -8
- package/src/intelligence/__tests__/prediction.test.d.ts +0 -8
- package/src/lib/__tests__/retry.test.d.ts +0 -7
- package/src/lifecycle/__tests__/chain-store.test.d.ts +0 -10
- package/src/lifecycle/__tests__/consolidate-rcasd.test.d.ts +0 -7
- package/src/lifecycle/__tests__/default-chain.test.d.ts +0 -7
- package/src/lifecycle/__tests__/frontmatter.test.d.ts +0 -7
- package/src/lifecycle/__tests__/lifecycle.test.d.ts +0 -7
- package/src/lifecycle/__tests__/pipeline.integration.test.d.ts +0 -19
- package/src/lifecycle/__tests__/rcasd-paths.test.d.ts +0 -7
- package/src/lifecycle/__tests__/resume-schema-contract.test.d.ts +0 -16
- package/src/lifecycle/__tests__/stage-record-provenance.integration.test.d.ts +0 -7
- package/src/lifecycle/__tests__/tessera-engine.test.d.ts +0 -10
- package/src/mcp/index.ts +0 -163
- package/src/memory/__tests__/auto-extract.test.d.ts +0 -7
- package/src/memory/__tests__/brain-automation.test.d.ts +0 -11
- package/src/memory/__tests__/brain-embedding.test.d.ts +0 -2
- package/src/memory/__tests__/brain-links.test.d.ts +0 -8
- package/src/memory/__tests__/brain-migration.test.d.ts +0 -8
- package/src/memory/__tests__/brain-retrieval.test.d.ts +0 -10
- package/src/memory/__tests__/brain-search.test.d.ts +0 -8
- package/src/memory/__tests__/claude-mem-migration.test.d.ts +0 -12
- package/src/memory/__tests__/decisions.test.d.ts +0 -8
- package/src/memory/__tests__/engine-compat.test.d.ts +0 -12
- package/src/memory/__tests__/memory-bridge.test.d.ts +0 -10
- package/src/memory/__tests__/pipeline-manifest-sqlite.test.d.ts +0 -13
- package/src/memory/__tests__/session-memory.test.d.ts +0 -9
- package/src/metrics/__tests__/model-provider-registry.test.d.ts +0 -2
- package/src/metrics/__tests__/provider-detection.test.d.ts +0 -2
- package/src/migration/__tests__/checksum.test.d.ts +0 -8
- package/src/migration/__tests__/logger.test.d.ts +0 -5
- package/src/migration/__tests__/migration-failure.integration.test.d.ts +0 -15
- package/src/migration/__tests__/migration.test.d.ts +0 -13
- package/src/migration/__tests__/state.test.d.ts +0 -8
- package/src/migration/__tests__/validate.test.d.ts +0 -8
- package/src/nexus/__tests__/deps.test.d.ts +0 -7
- package/src/nexus/__tests__/nexus-e2e.test.d.ts +0 -12
- package/src/nexus/__tests__/permissions.test.d.ts +0 -7
- package/src/nexus/__tests__/query.test.d.ts +0 -7
- package/src/nexus/__tests__/reconcile.test.d.ts +0 -7
- package/src/nexus/__tests__/registry.test.d.ts +0 -7
- package/src/nexus/__tests__/transfer.test.d.ts +0 -8
- package/src/observability/__tests__/index.test.d.ts +0 -7
- package/src/observability/__tests__/log-filter.test.d.ts +0 -7
- package/src/observability/__tests__/log-parser.test.d.ts +0 -7
- package/src/observability/__tests__/log-reader.test.d.ts +0 -7
- package/src/orchestration/__tests__/autonomous-spec.test.d.ts +0 -9
- package/src/orchestration/__tests__/orchestration.test.d.ts +0 -7
- package/src/orchestration/__tests__/protocol-validators.test.d.ts +0 -9
- package/src/phases/__tests__/deps.test.d.ts +0 -7
- package/src/phases/__tests__/phases.test.d.ts +0 -7
- package/src/release/__tests__/artifacts.test.d.ts +0 -7
- package/src/release/__tests__/cancel-release.test.d.ts +0 -10
- package/src/release/__tests__/changelog-writer.test.d.ts +0 -6
- package/src/release/__tests__/push-policy.test.d.ts +0 -14
- package/src/release/__tests__/release.test.d.ts +0 -11
- package/src/sequence/__tests__/allocate.test.d.ts +0 -6
- package/src/sessions/__tests__/briefing-blocked.test.d.ts +0 -6
- package/src/sessions/__tests__/briefing.test.d.ts +0 -11
- package/src/sessions/__tests__/handoff-integration.test.d.ts +0 -8
- package/src/sessions/__tests__/handoff.test.d.ts +0 -11
- package/src/sessions/__tests__/index.test.d.ts +0 -2
- package/src/sessions/__tests__/session-cleanup.test.d.ts +0 -7
- package/src/sessions/__tests__/session-edge-cases.test.d.ts +0 -9
- package/src/sessions/__tests__/session-find.test.d.ts +0 -9
- package/src/sessions/__tests__/session-grade.integration.test.d.ts +0 -11
- package/src/sessions/__tests__/session-grade.test.d.ts +0 -6
- package/src/sessions/__tests__/session-memory-bridge.test.d.ts +0 -2
- package/src/sessions/__tests__/sessions.test.d.ts +0 -7
- package/src/skills/__tests__/discovery.test.d.ts +0 -6
- package/src/skills/__tests__/dispatch.test.d.ts +0 -6
- package/src/skills/__tests__/dynamic-skill-generator.test.d.ts +0 -2
- package/src/skills/__tests__/manifests.test.d.ts +0 -6
- package/src/skills/__tests__/precedence.test.d.ts +0 -6
- package/src/skills/__tests__/routing-table.test.d.ts +0 -2
- package/src/skills/__tests__/skill-paths.test.d.ts +0 -7
- package/src/skills/__tests__/test-utility.test.d.ts +0 -7
- package/src/skills/__tests__/token.test.d.ts +0 -6
- package/src/skills/__tests__/validation.test.d.ts +0 -6
- package/src/skills/__tests__/version.test.d.ts +0 -5
- package/src/skills/injection/__tests__/subagent.test.d.ts +0 -2
- package/src/skills/orchestrator/__tests__/spawn-tier.test.d.ts +0 -2
- package/src/spawn/__tests__/adapter-registry.test.d.ts +0 -2
- package/src/stats/__tests__/stats.test.d.ts +0 -7
- package/src/sticky/__tests__/purge.test.d.ts +0 -9
- package/src/store/__tests__/atomic.test.d.ts +0 -7
- package/src/store/__tests__/backup.test.d.ts +0 -7
- package/src/store/__tests__/brain-accessor-pageindex.test.d.ts +0 -12
- package/src/store/__tests__/brain-accessor.test.d.ts +0 -10
- package/src/store/__tests__/brain-pageindex.test.d.ts +0 -11
- package/src/store/__tests__/brain-schema.test.d.ts +0 -11
- package/src/store/__tests__/brain-vec.test.d.ts +0 -11
- package/src/store/__tests__/collision-detection.test.d.ts +0 -11
- package/src/store/__tests__/data-safety-central.test.d.ts +0 -20
- package/src/store/__tests__/db-helpers.test.d.ts +0 -7
- package/src/store/__tests__/e2e-safety-integration.test.d.ts +0 -13
- package/src/store/__tests__/git-checkpoint.test.d.ts +0 -7
- package/src/store/__tests__/idempotent-migration.test.d.ts +0 -5
- package/src/store/__tests__/import-logging.test.d.ts +0 -7
- package/src/store/__tests__/import-sort.test.d.ts +0 -7
- package/src/store/__tests__/json.test.d.ts +0 -7
- package/src/store/__tests__/lifecycle-schema-parity.test.d.ts +0 -2
- package/src/store/__tests__/migration-integration.test.d.ts +0 -15
- package/src/store/__tests__/migration-retry.test.d.ts +0 -10
- package/src/store/__tests__/migration-safety.test.d.ts +0 -21
- package/src/store/__tests__/migration-sqlite.test.d.ts +0 -11
- package/src/store/__tests__/performance-safety.test.d.ts +0 -17
- package/src/store/__tests__/project-detect.test.d.ts +0 -6
- package/src/store/__tests__/project-registry.test.d.ts +0 -7
- package/src/store/__tests__/provider.test.d.ts +0 -9
- package/src/store/__tests__/relations.test.d.ts +0 -9
- package/src/store/__tests__/safety-accessor.test.d.ts +0 -18
- package/src/store/__tests__/sequence-validation.test.d.ts +0 -11
- package/src/store/__tests__/session-store.test.d.ts +0 -11
- package/src/store/__tests__/sqlite-backup.test.d.ts +0 -14
- package/src/store/__tests__/sqlite.test.d.ts +0 -11
- package/src/store/__tests__/task-store.test.d.ts +0 -11
- package/src/store/__tests__/test-db-helper.d.ts +0 -61
- package/src/store/__tests__/write-verification.test.d.ts +0 -11
- package/src/system/__tests__/cleanup.test.d.ts +0 -2
- package/src/system/__tests__/health.test.d.ts +0 -2
- package/src/task-work/__tests__/start-deps.test.d.ts +0 -6
- package/src/tasks/__tests__/add.test.d.ts +0 -7
- package/src/tasks/__tests__/archive.test.d.ts +0 -7
- package/src/tasks/__tests__/assignee.test.d.ts +0 -14
- package/src/tasks/__tests__/atomicity.test.d.ts +0 -6
- package/src/tasks/__tests__/cancel-ops.test.d.ts +0 -7
- package/src/tasks/__tests__/complete-unblocks.test.d.ts +0 -6
- package/src/tasks/__tests__/complete.test.d.ts +0 -7
- package/src/tasks/__tests__/delete.test.d.ts +0 -7
- package/src/tasks/__tests__/dependency-check.test.d.ts +0 -7
- package/src/tasks/__tests__/deps-ready.test.d.ts +0 -6
- package/src/tasks/__tests__/epic-enforcement.test.d.ts +0 -15
- package/src/tasks/__tests__/find.test.d.ts +0 -7
- package/src/tasks/__tests__/graph-ops.test.d.ts +0 -7
- package/src/tasks/__tests__/hierarchy-policy.test.d.ts +0 -6
- package/src/tasks/__tests__/hierarchy.test.d.ts +0 -7
- package/src/tasks/__tests__/id-generator.test.d.ts +0 -2
- package/src/tasks/__tests__/labels.test.d.ts +0 -7
- package/src/tasks/__tests__/list.test.d.ts +0 -7
- package/src/tasks/__tests__/minimal-test.test.d.ts +0 -2
- package/src/tasks/__tests__/phase-tracking.test.d.ts +0 -7
- package/src/tasks/__tests__/pipeline-stage.test.d.ts +0 -14
- package/src/tasks/__tests__/plan-priority.test.d.ts +0 -10
- package/src/tasks/__tests__/priority-normalization.test.d.ts +0 -7
- package/src/tasks/__tests__/relates.test.d.ts +0 -9
- package/src/tasks/__tests__/show-deps.test.d.ts +0 -6
- package/src/tasks/__tests__/show.test.d.ts +0 -7
- package/src/tasks/__tests__/staleness.test.d.ts +0 -7
- package/src/tasks/__tests__/task-ops-depends.test.d.ts +0 -6
- package/src/tasks/__tests__/update.test.d.ts +0 -7
- package/src/validation/__tests__/chain-validation.test.d.ts +0 -7
- package/src/validation/__tests__/compliance.test.d.ts +0 -7
- package/src/validation/__tests__/docs-sync.test.d.ts +0 -7
- package/src/validation/__tests__/doctor-gitignore.test.d.ts +0 -7
- package/src/validation/__tests__/doctor-injection.test.d.ts +0 -11
- package/src/validation/__tests__/doctor.test.d.ts +0 -7
- package/src/validation/__tests__/engine.test.d.ts +0 -7
- package/src/validation/__tests__/manifest.test.d.ts +0 -7
- package/src/validation/__tests__/protocol-common.test.d.ts +0 -7
- package/src/validation/__tests__/verification.test.d.ts +0 -7
|
@@ -1,898 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI/MCP Parity Integration Tests
|
|
3
|
-
*
|
|
4
|
-
* Verifies that the CLI and MCP paths produce identical results for shared
|
|
5
|
-
* operations. Both CLI and MCP ultimately route through the same domain
|
|
6
|
-
* handlers (TasksHandler, SessionHandler, etc.), which delegate to the same
|
|
7
|
-
* src/core/ functions.
|
|
8
|
-
*
|
|
9
|
-
* Test strategy:
|
|
10
|
-
* 1. Direct domain handler parity — call handler.query()/handler.mutate()
|
|
11
|
-
* and dispatchRaw() for the same operation; assert identical data.
|
|
12
|
-
* 2. CLI dispatch path — call dispatchRaw() and verify it reaches the same
|
|
13
|
-
* handler as MCP would via createDomainHandlers().
|
|
14
|
-
* 3. Cross-adapter data identity — same mock engine function is called with
|
|
15
|
-
* identical args from both CLI and MCP code paths.
|
|
16
|
-
* 4. MCP gateway normalization gap — document that handleMcpToolCall passes
|
|
17
|
-
* 'cleo_query' as gateway but the registry expects 'query' (a real gap).
|
|
18
|
-
*
|
|
19
|
-
* Architecture under test:
|
|
20
|
-
* CLI: dispatchRaw('query', domain, op, params)
|
|
21
|
-
* → getCliDispatcher() → Dispatcher (sanitizer mw)
|
|
22
|
-
* → TasksHandler.query(op, params)
|
|
23
|
-
* → task-engine fn → core/tasks/*
|
|
24
|
-
*
|
|
25
|
-
* MCP: handleMcpToolCall('cleo_query', domain, op, params)
|
|
26
|
-
* → getMcpDispatcher() → Dispatcher (sanitizer+rl+gates+protocol+audit mw)
|
|
27
|
-
* → same TasksHandler.query(op, params) [same handler instance via createDomainHandlers()]
|
|
28
|
-
* → same task-engine fn → same core/tasks/*
|
|
29
|
-
*
|
|
30
|
-
* @task T4796
|
|
31
|
-
* @epic T4654
|
|
32
|
-
*/
|
|
33
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
34
|
-
// ===========================================================================
|
|
35
|
-
// Mocks — all engine functions and MCP-only middleware
|
|
36
|
-
// ===========================================================================
|
|
37
|
-
// --- task-engine mocks ---
|
|
38
|
-
vi.mock('../../dispatch/engines/task-engine.js', () => ({
|
|
39
|
-
taskShow: vi.fn(),
|
|
40
|
-
taskList: vi.fn(),
|
|
41
|
-
taskFind: vi.fn(),
|
|
42
|
-
taskExists: vi.fn(),
|
|
43
|
-
taskCreate: vi.fn(),
|
|
44
|
-
taskUpdate: vi.fn(),
|
|
45
|
-
taskComplete: vi.fn(),
|
|
46
|
-
taskDelete: vi.fn(),
|
|
47
|
-
taskArchive: vi.fn(),
|
|
48
|
-
taskNext: vi.fn(),
|
|
49
|
-
taskBlockers: vi.fn(),
|
|
50
|
-
taskTree: vi.fn(),
|
|
51
|
-
taskRelates: vi.fn(),
|
|
52
|
-
taskRelatesAdd: vi.fn(),
|
|
53
|
-
taskAnalyze: vi.fn(),
|
|
54
|
-
taskRestore: vi.fn(),
|
|
55
|
-
taskReorder: vi.fn(),
|
|
56
|
-
taskReparent: vi.fn(),
|
|
57
|
-
taskPromote: vi.fn(),
|
|
58
|
-
taskReopen: vi.fn(),
|
|
59
|
-
taskComplexityEstimate: vi.fn(),
|
|
60
|
-
taskDepends: vi.fn(),
|
|
61
|
-
}));
|
|
62
|
-
// --- session-engine mocks (hosts taskStart/taskStop/taskCurrentGet) ---
|
|
63
|
-
vi.mock('../../dispatch/engines/session-engine.js', () => ({
|
|
64
|
-
sessionStatus: vi.fn(),
|
|
65
|
-
sessionList: vi.fn(),
|
|
66
|
-
sessionShow: vi.fn(),
|
|
67
|
-
sessionStart: vi.fn(),
|
|
68
|
-
sessionEnd: vi.fn(),
|
|
69
|
-
sessionResume: vi.fn(),
|
|
70
|
-
sessionSuspend: vi.fn(),
|
|
71
|
-
sessionGc: vi.fn(),
|
|
72
|
-
sessionHistory: vi.fn(),
|
|
73
|
-
sessionRecordDecision: vi.fn(),
|
|
74
|
-
sessionDecisionLog: vi.fn(),
|
|
75
|
-
sessionContextDrift: vi.fn(),
|
|
76
|
-
sessionRecordAssumption: vi.fn(),
|
|
77
|
-
taskCurrentGet: vi.fn(),
|
|
78
|
-
taskStart: vi.fn(),
|
|
79
|
-
taskStop: vi.fn(),
|
|
80
|
-
}));
|
|
81
|
-
// --- system-engine mocks ---
|
|
82
|
-
vi.mock('../../dispatch/engines/system-engine.js', () => ({
|
|
83
|
-
systemDash: vi.fn(),
|
|
84
|
-
systemStats: vi.fn(),
|
|
85
|
-
systemLog: vi.fn(),
|
|
86
|
-
systemContext: vi.fn(),
|
|
87
|
-
systemSequence: vi.fn(),
|
|
88
|
-
systemHealth: vi.fn(),
|
|
89
|
-
systemInjectGenerate: vi.fn(),
|
|
90
|
-
systemBackup: vi.fn(),
|
|
91
|
-
systemRestore: vi.fn(),
|
|
92
|
-
systemMigrate: vi.fn(),
|
|
93
|
-
systemCleanup: vi.fn(),
|
|
94
|
-
systemSync: vi.fn(),
|
|
95
|
-
systemSafestop: vi.fn(),
|
|
96
|
-
}));
|
|
97
|
-
// --- lifecycle-engine mocks ---
|
|
98
|
-
vi.mock('../../dispatch/engines/lifecycle-engine.js', () => ({
|
|
99
|
-
lifecycleStatus: vi.fn(),
|
|
100
|
-
lifecycleHistory: vi.fn(),
|
|
101
|
-
lifecycleGates: vi.fn(),
|
|
102
|
-
lifecyclePrerequisites: vi.fn(),
|
|
103
|
-
lifecycleCheck: vi.fn(),
|
|
104
|
-
lifecycleProgress: vi.fn(),
|
|
105
|
-
lifecycleSkip: vi.fn(),
|
|
106
|
-
lifecycleReset: vi.fn(),
|
|
107
|
-
lifecycleGatePass: vi.fn(),
|
|
108
|
-
lifecycleGateFail: vi.fn(),
|
|
109
|
-
LIFECYCLE_STAGES: [
|
|
110
|
-
'research',
|
|
111
|
-
'consensus',
|
|
112
|
-
'architecture_decision',
|
|
113
|
-
'specification',
|
|
114
|
-
'decomposition',
|
|
115
|
-
'implementation',
|
|
116
|
-
'validation',
|
|
117
|
-
'testing',
|
|
118
|
-
'release',
|
|
119
|
-
'contribution',
|
|
120
|
-
],
|
|
121
|
-
}));
|
|
122
|
-
// --- orchestrate-engine mocks ---
|
|
123
|
-
vi.mock('../../dispatch/engines/orchestrate-engine.js', () => ({
|
|
124
|
-
orchestrateStatus: vi.fn(),
|
|
125
|
-
orchestrateAnalyze: vi.fn(),
|
|
126
|
-
orchestrateReady: vi.fn(),
|
|
127
|
-
orchestrateNext: vi.fn(),
|
|
128
|
-
orchestrateWaves: vi.fn(),
|
|
129
|
-
orchestrateContext: vi.fn(),
|
|
130
|
-
orchestrateValidate: vi.fn(),
|
|
131
|
-
orchestrateSpawn: vi.fn(),
|
|
132
|
-
orchestrateStartup: vi.fn(),
|
|
133
|
-
orchestrateBootstrap: vi.fn(),
|
|
134
|
-
orchestrateCriticalPath: vi.fn(),
|
|
135
|
-
orchestrateUnblockOpportunities: vi.fn(),
|
|
136
|
-
orchestrateParallelStart: vi.fn(),
|
|
137
|
-
orchestrateParallelEnd: vi.fn(),
|
|
138
|
-
orchestrateCheck: vi.fn(),
|
|
139
|
-
orchestrateSkillInject: vi.fn(),
|
|
140
|
-
}));
|
|
141
|
-
// --- validate-engine mocks ---
|
|
142
|
-
vi.mock('../../dispatch/engines/validate-engine.js', () => ({
|
|
143
|
-
validateSchemaOp: vi.fn(),
|
|
144
|
-
validateTask: vi.fn(),
|
|
145
|
-
validateProtocol: vi.fn(),
|
|
146
|
-
validateManifest: vi.fn(),
|
|
147
|
-
validateOutput: vi.fn(),
|
|
148
|
-
validateComplianceSummary: vi.fn(),
|
|
149
|
-
validateComplianceViolations: vi.fn(),
|
|
150
|
-
validateComplianceRecord: vi.fn(),
|
|
151
|
-
validateTestStatus: vi.fn(),
|
|
152
|
-
validateTestCoverage: vi.fn(),
|
|
153
|
-
validateCoherenceCheck: vi.fn(),
|
|
154
|
-
validateTestRun: vi.fn(),
|
|
155
|
-
validateBatchValidate: vi.fn(),
|
|
156
|
-
}));
|
|
157
|
-
// --- release-engine mocks ---
|
|
158
|
-
vi.mock('../../dispatch/engines/release-engine.js', () => ({
|
|
159
|
-
releasePrepare: vi.fn(),
|
|
160
|
-
releaseChangelog: vi.fn(),
|
|
161
|
-
releaseList: vi.fn(),
|
|
162
|
-
releaseShow: vi.fn(),
|
|
163
|
-
releaseCommit: vi.fn(),
|
|
164
|
-
releaseTag: vi.fn(),
|
|
165
|
-
releaseGatesRun: vi.fn(),
|
|
166
|
-
releaseRollback: vi.fn(),
|
|
167
|
-
releasePush: vi.fn(),
|
|
168
|
-
}));
|
|
169
|
-
// --- memory engine mock (brain.db backed after T5241 cutover) ---
|
|
170
|
-
vi.mock('../../core/memory/engine-compat.js', () => ({
|
|
171
|
-
memoryShow: vi.fn(),
|
|
172
|
-
memoryFind: vi.fn(),
|
|
173
|
-
memoryTimeline: vi.fn(),
|
|
174
|
-
memoryFetch: vi.fn(),
|
|
175
|
-
memoryObserve: vi.fn(),
|
|
176
|
-
memoryBrainStats: vi.fn(),
|
|
177
|
-
memoryDecisionFind: vi.fn(),
|
|
178
|
-
memoryDecisionStore: vi.fn(),
|
|
179
|
-
memoryPatternFind: vi.fn(),
|
|
180
|
-
memoryPatternStats: vi.fn(),
|
|
181
|
-
memoryPatternStore: vi.fn(),
|
|
182
|
-
memoryLearningFind: vi.fn(),
|
|
183
|
-
memoryLearningStats: vi.fn(),
|
|
184
|
-
memoryLearningStore: vi.fn(),
|
|
185
|
-
}));
|
|
186
|
-
// --- pipeline manifest mock (moved from memory domain in T5241) ---
|
|
187
|
-
vi.mock('../../core/memory/pipeline-manifest-sqlite.js', () => ({
|
|
188
|
-
pipelineManifestShow: vi.fn(),
|
|
189
|
-
pipelineManifestList: vi.fn(),
|
|
190
|
-
pipelineManifestFind: vi.fn(),
|
|
191
|
-
pipelineManifestPending: vi.fn(),
|
|
192
|
-
pipelineManifestStats: vi.fn(),
|
|
193
|
-
pipelineManifestRead: vi.fn(),
|
|
194
|
-
pipelineManifestAppend: vi.fn(),
|
|
195
|
-
pipelineManifestArchive: vi.fn(),
|
|
196
|
-
pipelineManifestLink: vi.fn(),
|
|
197
|
-
pipelineManifestContradictions: vi.fn(),
|
|
198
|
-
pipelineManifestSuperseded: vi.fn(),
|
|
199
|
-
pipelineManifestCompact: vi.fn(),
|
|
200
|
-
pipelineManifestValidate: vi.fn(),
|
|
201
|
-
readManifestEntries: vi.fn(),
|
|
202
|
-
filterEntries: vi.fn(),
|
|
203
|
-
}));
|
|
204
|
-
// --- dispatch/lib/engine (config + init) ---
|
|
205
|
-
vi.mock('../../dispatch/lib/engine.js', () => {
|
|
206
|
-
return {
|
|
207
|
-
// Tasks
|
|
208
|
-
taskShow: vi.fn(),
|
|
209
|
-
taskList: vi.fn(),
|
|
210
|
-
taskFind: vi.fn(),
|
|
211
|
-
taskCreate: vi.fn(),
|
|
212
|
-
taskComplete: vi.fn(),
|
|
213
|
-
taskUpdate: vi.fn(),
|
|
214
|
-
taskDelete: vi.fn(),
|
|
215
|
-
taskCurrentGet: vi.fn(),
|
|
216
|
-
taskStart: vi.fn(),
|
|
217
|
-
taskStop: vi.fn(),
|
|
218
|
-
// Session
|
|
219
|
-
sessionStatus: vi.fn(),
|
|
220
|
-
sessionList: vi.fn(),
|
|
221
|
-
sessionStart: vi.fn(),
|
|
222
|
-
sessionContextInject: vi.fn(),
|
|
223
|
-
configGet: vi.fn(),
|
|
224
|
-
configSet: vi.fn(),
|
|
225
|
-
getVersion: vi.fn(() => ({ success: true, data: { version: '1.0.0' } })),
|
|
226
|
-
initProject: vi.fn(),
|
|
227
|
-
isAutoInitEnabled: vi.fn(() => false),
|
|
228
|
-
ensureInitialized: vi.fn(() => ({ success: true, data: { initialized: true } })),
|
|
229
|
-
};
|
|
230
|
-
});
|
|
231
|
-
// --- template-parser mocks ---
|
|
232
|
-
vi.mock('../../dispatch/engines/template-parser.js', () => ({
|
|
233
|
-
parseIssueTemplates: vi.fn(),
|
|
234
|
-
getTemplateForSubcommand: vi.fn(),
|
|
235
|
-
generateTemplateConfig: vi.fn(),
|
|
236
|
-
validateLabels: vi.fn(),
|
|
237
|
-
}));
|
|
238
|
-
// --- paths ---
|
|
239
|
-
vi.mock('../../core/paths.js', () => ({
|
|
240
|
-
getProjectRoot: vi.fn(() => '/mock/project'),
|
|
241
|
-
}));
|
|
242
|
-
// --- MCP-only middleware (passthrough stubs to avoid blocking tests) ---
|
|
243
|
-
vi.mock('../../dispatch/middleware/rate-limiter.js', () => ({
|
|
244
|
-
createRateLimiter: vi.fn(() => async (_req, next) => next()),
|
|
245
|
-
}));
|
|
246
|
-
vi.mock('../../dispatch/middleware/verification-gates.js', () => ({
|
|
247
|
-
createVerificationGates: vi.fn(() => async (_req, next) => next()),
|
|
248
|
-
}));
|
|
249
|
-
vi.mock('../../dispatch/middleware/protocol-enforcement.js', () => ({
|
|
250
|
-
createProtocolEnforcement: vi.fn(() => async (_req, next) => next()),
|
|
251
|
-
}));
|
|
252
|
-
vi.mock('../../dispatch/middleware/audit.js', () => ({
|
|
253
|
-
createAudit: vi.fn(() => async (_req, next) => next()),
|
|
254
|
-
}));
|
|
255
|
-
// --- MCP rate-limiter config dependency ---
|
|
256
|
-
vi.mock('../../mcp/lib/rate-limiter.js', () => ({
|
|
257
|
-
RateLimiter: vi.fn(),
|
|
258
|
-
createRateLimiter: vi.fn(),
|
|
259
|
-
}));
|
|
260
|
-
// --- security (sanitizer) ---
|
|
261
|
-
vi.mock('../../dispatch/lib/security.js', () => ({
|
|
262
|
-
sanitizeParams: vi.fn((p) => p),
|
|
263
|
-
}));
|
|
264
|
-
vi.mock('../../mcp/lib/security.js', () => ({
|
|
265
|
-
sanitizeParams: vi.fn((p) => p),
|
|
266
|
-
}));
|
|
267
|
-
// ===========================================================================
|
|
268
|
-
// Imports (AFTER all vi.mock() calls)
|
|
269
|
-
// ===========================================================================
|
|
270
|
-
import { dispatchRaw, resetCliDispatcher } from '../../dispatch/adapters/cli.js';
|
|
271
|
-
import { handleMcpToolCall, resetMcpDispatcher } from '../../dispatch/adapters/mcp.js';
|
|
272
|
-
import { SessionHandler } from '../../dispatch/domains/session.js';
|
|
273
|
-
import { TasksHandler } from '../../dispatch/domains/tasks.js';
|
|
274
|
-
import { sessionList, sessionStart, sessionStatus, taskComplete, taskCreate, taskCurrentGet, taskDelete, taskFind, taskList, taskShow, taskStart, taskStop, taskUpdate, } from '../../dispatch/lib/engine.js';
|
|
275
|
-
// ===========================================================================
|
|
276
|
-
// Helpers
|
|
277
|
-
// ===========================================================================
|
|
278
|
-
/**
|
|
279
|
-
* Strip _meta from a DispatchResponse for data-only comparison.
|
|
280
|
-
* _meta legitimately differs between CLI (source:'cli') and MCP (source:'mcp').
|
|
281
|
-
*/
|
|
282
|
-
function stripMeta(response) {
|
|
283
|
-
const { _meta: _ignored, ...rest } = response;
|
|
284
|
-
return rest;
|
|
285
|
-
}
|
|
286
|
-
// ===========================================================================
|
|
287
|
-
// Setup
|
|
288
|
-
// ===========================================================================
|
|
289
|
-
beforeEach(() => {
|
|
290
|
-
vi.clearAllMocks();
|
|
291
|
-
// Reset dispatcher singletons so each test gets a fresh dispatcher instance
|
|
292
|
-
resetCliDispatcher();
|
|
293
|
-
resetMcpDispatcher();
|
|
294
|
-
});
|
|
295
|
-
// ===========================================================================
|
|
296
|
-
// Section 1: Direct Domain Handler Parity
|
|
297
|
-
//
|
|
298
|
-
// Calls the domain handler directly (simulating what both CLI dispatch and MCP
|
|
299
|
-
// dispatch ultimately do) and verifies identical data for each operation.
|
|
300
|
-
// ===========================================================================
|
|
301
|
-
describe('Section 1: Direct domain handler parity (T4796)', () => {
|
|
302
|
-
let tasksHandler;
|
|
303
|
-
beforeEach(() => {
|
|
304
|
-
tasksHandler = new TasksHandler();
|
|
305
|
-
});
|
|
306
|
-
// -------------------------------------------------------------------------
|
|
307
|
-
// tasks.show
|
|
308
|
-
// -------------------------------------------------------------------------
|
|
309
|
-
describe('tasks.show', () => {
|
|
310
|
-
const TASK_DATA = {
|
|
311
|
-
task: {
|
|
312
|
-
id: 'T001',
|
|
313
|
-
title: 'Alpha task',
|
|
314
|
-
status: 'pending',
|
|
315
|
-
priority: 'high',
|
|
316
|
-
},
|
|
317
|
-
};
|
|
318
|
-
beforeEach(() => {
|
|
319
|
-
vi.mocked(taskShow).mockResolvedValue({ success: true, data: TASK_DATA });
|
|
320
|
-
});
|
|
321
|
-
it('handler.query("show") and dispatchRaw produce identical data', async () => {
|
|
322
|
-
const handlerResult = await tasksHandler.query('show', { taskId: 'T001' });
|
|
323
|
-
const cliResult = await dispatchRaw('query', 'tasks', 'show', {
|
|
324
|
-
taskId: 'T001',
|
|
325
|
-
});
|
|
326
|
-
expect(handlerResult.success).toBe(true);
|
|
327
|
-
expect(cliResult.success).toBe(true);
|
|
328
|
-
// Both produce the same data payload
|
|
329
|
-
expect(handlerResult.data).toEqual(TASK_DATA);
|
|
330
|
-
expect(cliResult.data).toEqual(TASK_DATA);
|
|
331
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
332
|
-
});
|
|
333
|
-
it('handler.query("show") and dispatchRaw both fail for missing taskId', async () => {
|
|
334
|
-
const handlerResult = await tasksHandler.query('show', {});
|
|
335
|
-
const cliResult = await dispatchRaw('query', 'tasks', 'show', {});
|
|
336
|
-
expect(handlerResult.success).toBe(false);
|
|
337
|
-
expect(cliResult.success).toBe(false);
|
|
338
|
-
// Both return E_INVALID_INPUT
|
|
339
|
-
expect(handlerResult.error?.code).toBe('E_INVALID_INPUT');
|
|
340
|
-
expect(cliResult.error?.code).toBe('E_INVALID_INPUT');
|
|
341
|
-
});
|
|
342
|
-
it('taskShow engine called with identical args from handler and dispatchRaw', async () => {
|
|
343
|
-
await tasksHandler.query('show', { taskId: 'T001' });
|
|
344
|
-
await dispatchRaw('query', 'tasks', 'show', { taskId: 'T001' });
|
|
345
|
-
expect(taskShow).toHaveBeenCalledTimes(2);
|
|
346
|
-
// Both calls pass the same projectRoot and taskId
|
|
347
|
-
expect(vi.mocked(taskShow).mock.calls[0]).toEqual(vi.mocked(taskShow).mock.calls[1]);
|
|
348
|
-
});
|
|
349
|
-
});
|
|
350
|
-
// -------------------------------------------------------------------------
|
|
351
|
-
// tasks.list
|
|
352
|
-
// -------------------------------------------------------------------------
|
|
353
|
-
describe('tasks.list', () => {
|
|
354
|
-
const LIST_DATA = {
|
|
355
|
-
tasks: [
|
|
356
|
-
{ id: 'T001', title: 'Alpha', status: 'pending', priority: 'medium' },
|
|
357
|
-
{ id: 'T002', title: 'Beta', status: 'active', priority: 'high' },
|
|
358
|
-
],
|
|
359
|
-
total: 2,
|
|
360
|
-
filtered: 2,
|
|
361
|
-
};
|
|
362
|
-
const LIST_PAGE = { mode: 'none' };
|
|
363
|
-
beforeEach(() => {
|
|
364
|
-
vi.mocked(taskList).mockResolvedValue({ success: true, data: LIST_DATA, page: LIST_PAGE });
|
|
365
|
-
});
|
|
366
|
-
it('handler.query("list") and dispatchRaw produce identical data (no filters)', async () => {
|
|
367
|
-
const handlerResult = await tasksHandler.query('list', {});
|
|
368
|
-
const cliResult = await dispatchRaw('query', 'tasks', 'list', {});
|
|
369
|
-
expect(handlerResult.success).toBe(true);
|
|
370
|
-
expect(cliResult.success).toBe(true);
|
|
371
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
372
|
-
expect(handlerResult.page).toEqual(cliResult.page);
|
|
373
|
-
expect(cliResult.data).toEqual(LIST_DATA);
|
|
374
|
-
expect(cliResult.page).toEqual(LIST_PAGE);
|
|
375
|
-
});
|
|
376
|
-
it('handler.query("list") and dispatchRaw produce identical data with status filter', async () => {
|
|
377
|
-
const filteredData = {
|
|
378
|
-
tasks: [{ id: 'T001', title: 'Alpha', status: 'pending' }],
|
|
379
|
-
total: 1,
|
|
380
|
-
filtered: 1,
|
|
381
|
-
};
|
|
382
|
-
vi.mocked(taskList).mockResolvedValue({ success: true, data: filteredData, page: LIST_PAGE });
|
|
383
|
-
const handlerResult = await tasksHandler.query('list', { status: 'pending' });
|
|
384
|
-
const cliResult = await dispatchRaw('query', 'tasks', 'list', {
|
|
385
|
-
status: 'pending',
|
|
386
|
-
});
|
|
387
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
388
|
-
expect(handlerResult.page).toEqual(cliResult.page);
|
|
389
|
-
expect(cliResult.data).toEqual(filteredData);
|
|
390
|
-
});
|
|
391
|
-
it('taskList engine called with identical args from handler and dispatchRaw', async () => {
|
|
392
|
-
await tasksHandler.query('list', { parent: 'T010', limit: 5 });
|
|
393
|
-
await dispatchRaw('query', 'tasks', 'list', { parent: 'T010', limit: 5 });
|
|
394
|
-
expect(taskList).toHaveBeenCalledTimes(2);
|
|
395
|
-
expect(vi.mocked(taskList).mock.calls[0]).toEqual(vi.mocked(taskList).mock.calls[1]);
|
|
396
|
-
});
|
|
397
|
-
});
|
|
398
|
-
// -------------------------------------------------------------------------
|
|
399
|
-
// tasks.find
|
|
400
|
-
// -------------------------------------------------------------------------
|
|
401
|
-
describe('tasks.find', () => {
|
|
402
|
-
const FIND_DATA = {
|
|
403
|
-
results: [{ id: 'T001', title: 'Alpha task', status: 'pending' }],
|
|
404
|
-
total: 1,
|
|
405
|
-
};
|
|
406
|
-
beforeEach(() => {
|
|
407
|
-
vi.mocked(taskFind).mockResolvedValue({ success: true, data: FIND_DATA });
|
|
408
|
-
});
|
|
409
|
-
it('handler.query("find") and dispatchRaw produce identical data', async () => {
|
|
410
|
-
const handlerResult = await tasksHandler.query('find', { query: 'alpha' });
|
|
411
|
-
const cliResult = await dispatchRaw('query', 'tasks', 'find', {
|
|
412
|
-
query: 'alpha',
|
|
413
|
-
});
|
|
414
|
-
expect(handlerResult.success).toBe(true);
|
|
415
|
-
expect(cliResult.success).toBe(true);
|
|
416
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
417
|
-
});
|
|
418
|
-
it('taskFind engine called with identical args from handler and dispatchRaw', async () => {
|
|
419
|
-
const params = { query: 'test', limit: 10 };
|
|
420
|
-
await tasksHandler.query('find', params);
|
|
421
|
-
await dispatchRaw('query', 'tasks', 'find', params);
|
|
422
|
-
expect(taskFind).toHaveBeenCalledTimes(2);
|
|
423
|
-
expect(vi.mocked(taskFind).mock.calls[0]).toEqual(vi.mocked(taskFind).mock.calls[1]);
|
|
424
|
-
});
|
|
425
|
-
});
|
|
426
|
-
// -------------------------------------------------------------------------
|
|
427
|
-
// tasks.add (mutate)
|
|
428
|
-
// -------------------------------------------------------------------------
|
|
429
|
-
describe('tasks.add', () => {
|
|
430
|
-
const CREATED_DATA = {
|
|
431
|
-
task: {
|
|
432
|
-
id: 'T100',
|
|
433
|
-
title: 'New task',
|
|
434
|
-
description: 'Created for parity test',
|
|
435
|
-
status: 'pending',
|
|
436
|
-
},
|
|
437
|
-
};
|
|
438
|
-
beforeEach(() => {
|
|
439
|
-
vi.mocked(taskCreate).mockResolvedValue({
|
|
440
|
-
success: true,
|
|
441
|
-
data: CREATED_DATA,
|
|
442
|
-
});
|
|
443
|
-
});
|
|
444
|
-
it('handler.mutate("add") and dispatchRaw produce identical data', async () => {
|
|
445
|
-
const params = { title: 'New task', description: 'Created for parity test' };
|
|
446
|
-
const handlerResult = await tasksHandler.mutate('add', params);
|
|
447
|
-
const cliResult = await dispatchRaw('mutate', 'tasks', 'add', params);
|
|
448
|
-
expect(handlerResult.success).toBe(true);
|
|
449
|
-
expect(cliResult.success).toBe(true);
|
|
450
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
451
|
-
expect(cliResult.data).toEqual(CREATED_DATA);
|
|
452
|
-
});
|
|
453
|
-
it('handler.mutate("add") and dispatchRaw both fail with E_INVALID_INPUT when title missing', async () => {
|
|
454
|
-
const handlerResult = await tasksHandler.mutate('add', {
|
|
455
|
-
description: 'No title',
|
|
456
|
-
});
|
|
457
|
-
const cliResult = await dispatchRaw('mutate', 'tasks', 'add', {
|
|
458
|
-
description: 'No title',
|
|
459
|
-
});
|
|
460
|
-
expect(handlerResult.success).toBe(false);
|
|
461
|
-
expect(cliResult.success).toBe(false);
|
|
462
|
-
expect(handlerResult.error?.code).toBe('E_INVALID_INPUT');
|
|
463
|
-
expect(cliResult.error?.code).toBe('E_INVALID_INPUT');
|
|
464
|
-
});
|
|
465
|
-
it('taskCreate engine called with identical args from handler and dispatchRaw', async () => {
|
|
466
|
-
const params = { title: 'New task', description: 'Parity test task' };
|
|
467
|
-
await tasksHandler.mutate('add', params);
|
|
468
|
-
await dispatchRaw('mutate', 'tasks', 'add', params);
|
|
469
|
-
expect(taskCreate).toHaveBeenCalledTimes(2);
|
|
470
|
-
expect(vi.mocked(taskCreate).mock.calls[0]).toEqual(vi.mocked(taskCreate).mock.calls[1]);
|
|
471
|
-
});
|
|
472
|
-
});
|
|
473
|
-
// -------------------------------------------------------------------------
|
|
474
|
-
// tasks.complete (mutate)
|
|
475
|
-
// -------------------------------------------------------------------------
|
|
476
|
-
describe('tasks.complete', () => {
|
|
477
|
-
const COMPLETE_DATA = {
|
|
478
|
-
taskId: 'T001',
|
|
479
|
-
completed: true,
|
|
480
|
-
completedAt: '2026-02-25T12:00:00Z',
|
|
481
|
-
};
|
|
482
|
-
beforeEach(() => {
|
|
483
|
-
vi.mocked(taskComplete).mockResolvedValue({
|
|
484
|
-
success: true,
|
|
485
|
-
data: COMPLETE_DATA,
|
|
486
|
-
});
|
|
487
|
-
});
|
|
488
|
-
it('handler.mutate("complete") and dispatchRaw produce identical data', async () => {
|
|
489
|
-
const handlerResult = await tasksHandler.mutate('complete', { taskId: 'T001' });
|
|
490
|
-
const cliResult = await dispatchRaw('mutate', 'tasks', 'complete', {
|
|
491
|
-
taskId: 'T001',
|
|
492
|
-
});
|
|
493
|
-
expect(handlerResult.success).toBe(true);
|
|
494
|
-
expect(cliResult.success).toBe(true);
|
|
495
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
496
|
-
expect(cliResult.data).toEqual(COMPLETE_DATA);
|
|
497
|
-
});
|
|
498
|
-
it('handler.mutate("complete") and dispatchRaw both fail with E_INVALID_INPUT when taskId missing', async () => {
|
|
499
|
-
const handlerResult = await tasksHandler.mutate('complete', {});
|
|
500
|
-
const cliResult = await dispatchRaw('mutate', 'tasks', 'complete', {});
|
|
501
|
-
expect(handlerResult.success).toBe(false);
|
|
502
|
-
expect(cliResult.success).toBe(false);
|
|
503
|
-
expect(handlerResult.error?.code).toBe('E_INVALID_INPUT');
|
|
504
|
-
expect(cliResult.error?.code).toBe('E_INVALID_INPUT');
|
|
505
|
-
});
|
|
506
|
-
it('taskComplete engine called with identical args from handler and dispatchRaw', async () => {
|
|
507
|
-
await tasksHandler.mutate('complete', { taskId: 'T001', notes: 'Done' });
|
|
508
|
-
await dispatchRaw('mutate', 'tasks', 'complete', { taskId: 'T001', notes: 'Done' });
|
|
509
|
-
expect(taskComplete).toHaveBeenCalledTimes(2);
|
|
510
|
-
expect(vi.mocked(taskComplete).mock.calls[0]).toEqual(vi.mocked(taskComplete).mock.calls[1]);
|
|
511
|
-
});
|
|
512
|
-
});
|
|
513
|
-
// -------------------------------------------------------------------------
|
|
514
|
-
// tasks.update (mutate)
|
|
515
|
-
// -------------------------------------------------------------------------
|
|
516
|
-
describe('tasks.update', () => {
|
|
517
|
-
const UPDATED_DATA = {
|
|
518
|
-
task: {
|
|
519
|
-
id: 'T001',
|
|
520
|
-
title: 'Updated title',
|
|
521
|
-
status: 'active',
|
|
522
|
-
},
|
|
523
|
-
};
|
|
524
|
-
beforeEach(() => {
|
|
525
|
-
vi.mocked(taskUpdate).mockResolvedValue({
|
|
526
|
-
success: true,
|
|
527
|
-
data: UPDATED_DATA,
|
|
528
|
-
});
|
|
529
|
-
});
|
|
530
|
-
it('handler.mutate("update") and dispatchRaw produce identical data', async () => {
|
|
531
|
-
const params = { taskId: 'T001', title: 'Updated title', status: 'active' };
|
|
532
|
-
const handlerResult = await tasksHandler.mutate('update', params);
|
|
533
|
-
const cliResult = await dispatchRaw('mutate', 'tasks', 'update', params);
|
|
534
|
-
expect(handlerResult.success).toBe(true);
|
|
535
|
-
expect(cliResult.success).toBe(true);
|
|
536
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
537
|
-
});
|
|
538
|
-
it('taskUpdate engine called with identical args from handler and dispatchRaw', async () => {
|
|
539
|
-
const params = { taskId: 'T001', status: 'done' };
|
|
540
|
-
await tasksHandler.mutate('update', params);
|
|
541
|
-
await dispatchRaw('mutate', 'tasks', 'update', params);
|
|
542
|
-
expect(taskUpdate).toHaveBeenCalledTimes(2);
|
|
543
|
-
expect(vi.mocked(taskUpdate).mock.calls[0]).toEqual(vi.mocked(taskUpdate).mock.calls[1]);
|
|
544
|
-
});
|
|
545
|
-
});
|
|
546
|
-
// -------------------------------------------------------------------------
|
|
547
|
-
// tasks.delete (mutate)
|
|
548
|
-
// -------------------------------------------------------------------------
|
|
549
|
-
describe('tasks.delete', () => {
|
|
550
|
-
const DELETE_DATA = { taskId: 'T001', deleted: true };
|
|
551
|
-
beforeEach(() => {
|
|
552
|
-
vi.mocked(taskDelete).mockResolvedValue({
|
|
553
|
-
success: true,
|
|
554
|
-
data: DELETE_DATA,
|
|
555
|
-
});
|
|
556
|
-
});
|
|
557
|
-
it('handler.mutate("delete") and dispatchRaw produce identical data', async () => {
|
|
558
|
-
const handlerResult = await tasksHandler.mutate('delete', { taskId: 'T001' });
|
|
559
|
-
const cliResult = await dispatchRaw('mutate', 'tasks', 'delete', {
|
|
560
|
-
taskId: 'T001',
|
|
561
|
-
});
|
|
562
|
-
expect(handlerResult.success).toBe(true);
|
|
563
|
-
expect(cliResult.success).toBe(true);
|
|
564
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
565
|
-
expect(cliResult.data).toEqual(DELETE_DATA);
|
|
566
|
-
});
|
|
567
|
-
it('handler.mutate("delete") and dispatchRaw both fail with E_INVALID_INPUT when taskId missing', async () => {
|
|
568
|
-
const handlerResult = await tasksHandler.mutate('delete', {});
|
|
569
|
-
const cliResult = await dispatchRaw('mutate', 'tasks', 'delete', {});
|
|
570
|
-
expect(handlerResult.success).toBe(false);
|
|
571
|
-
expect(cliResult.success).toBe(false);
|
|
572
|
-
expect(handlerResult.error?.code).toBe('E_INVALID_INPUT');
|
|
573
|
-
expect(cliResult.error?.code).toBe('E_INVALID_INPUT');
|
|
574
|
-
});
|
|
575
|
-
});
|
|
576
|
-
});
|
|
577
|
-
// ===========================================================================
|
|
578
|
-
// Section 2: Session domain parity (T4796)
|
|
579
|
-
// ===========================================================================
|
|
580
|
-
describe('Section 2: Session domain parity (T4796)', () => {
|
|
581
|
-
let sessionHandler;
|
|
582
|
-
beforeEach(() => {
|
|
583
|
-
sessionHandler = new SessionHandler();
|
|
584
|
-
});
|
|
585
|
-
// -------------------------------------------------------------------------
|
|
586
|
-
// session.status
|
|
587
|
-
// -------------------------------------------------------------------------
|
|
588
|
-
describe('session.status', () => {
|
|
589
|
-
const STATUS_DATA = {
|
|
590
|
-
hasActiveSession: false,
|
|
591
|
-
currentSession: null,
|
|
592
|
-
};
|
|
593
|
-
beforeEach(() => {
|
|
594
|
-
vi.mocked(sessionStatus).mockResolvedValue({
|
|
595
|
-
success: true,
|
|
596
|
-
data: STATUS_DATA,
|
|
597
|
-
});
|
|
598
|
-
});
|
|
599
|
-
it('handler.query("status") and dispatchRaw produce identical data', async () => {
|
|
600
|
-
const handlerResult = await sessionHandler.query('status', {});
|
|
601
|
-
const cliResult = await dispatchRaw('query', 'session', 'status', {});
|
|
602
|
-
expect(handlerResult.success).toBe(true);
|
|
603
|
-
expect(cliResult.success).toBe(true);
|
|
604
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
605
|
-
expect(cliResult.data).toEqual(STATUS_DATA);
|
|
606
|
-
});
|
|
607
|
-
it('sessionStatus engine called with identical args from handler and dispatchRaw', async () => {
|
|
608
|
-
await sessionHandler.query('status', {});
|
|
609
|
-
await dispatchRaw('query', 'session', 'status', {});
|
|
610
|
-
expect(sessionStatus).toHaveBeenCalledTimes(2);
|
|
611
|
-
expect(vi.mocked(sessionStatus).mock.calls[0]).toEqual(vi.mocked(sessionStatus).mock.calls[1]);
|
|
612
|
-
});
|
|
613
|
-
});
|
|
614
|
-
// -------------------------------------------------------------------------
|
|
615
|
-
// session.list
|
|
616
|
-
// -------------------------------------------------------------------------
|
|
617
|
-
describe('session.list', () => {
|
|
618
|
-
const LIST_DATA = {
|
|
619
|
-
sessions: [
|
|
620
|
-
{ id: 'session_abc', status: 'active', name: 'Sprint 1' },
|
|
621
|
-
{ id: 'session_def', status: 'ended', name: 'Sprint 0' },
|
|
622
|
-
],
|
|
623
|
-
total: 2,
|
|
624
|
-
filtered: 2,
|
|
625
|
-
_meta: { truncated: false, total: 2 },
|
|
626
|
-
};
|
|
627
|
-
const LIST_PAGE = { mode: 'offset', limit: 10, offset: 0, hasMore: false, total: 2 };
|
|
628
|
-
beforeEach(() => {
|
|
629
|
-
vi.mocked(sessionList).mockResolvedValue({
|
|
630
|
-
success: true,
|
|
631
|
-
data: LIST_DATA,
|
|
632
|
-
page: LIST_PAGE,
|
|
633
|
-
});
|
|
634
|
-
});
|
|
635
|
-
it('handler.query("list") and dispatchRaw produce identical data', async () => {
|
|
636
|
-
const handlerResult = await sessionHandler.query('list', {});
|
|
637
|
-
const cliResult = await dispatchRaw('query', 'session', 'list', {});
|
|
638
|
-
expect(handlerResult.success).toBe(true);
|
|
639
|
-
expect(cliResult.success).toBe(true);
|
|
640
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
641
|
-
expect(handlerResult.page).toEqual(cliResult.page);
|
|
642
|
-
expect(cliResult.data).toEqual(LIST_DATA);
|
|
643
|
-
expect(cliResult.page).toEqual(LIST_PAGE);
|
|
644
|
-
});
|
|
645
|
-
});
|
|
646
|
-
// -------------------------------------------------------------------------
|
|
647
|
-
// session.start (mutate)
|
|
648
|
-
// -------------------------------------------------------------------------
|
|
649
|
-
describe('session.start', () => {
|
|
650
|
-
// Note: SessionHandler.mutate('start') enriches the response by adding
|
|
651
|
-
// sessionId: session.id for easy top-level extraction. This is part of the
|
|
652
|
-
// handler contract, so both paths (direct handler + dispatchRaw) produce this.
|
|
653
|
-
const START_DATA = {
|
|
654
|
-
id: 'session_xyz',
|
|
655
|
-
status: 'active',
|
|
656
|
-
scope: { rootTaskId: 'T010' },
|
|
657
|
-
};
|
|
658
|
-
const ENRICHED_START_DATA = {
|
|
659
|
-
...START_DATA,
|
|
660
|
-
sessionId: 'session_xyz',
|
|
661
|
-
};
|
|
662
|
-
beforeEach(() => {
|
|
663
|
-
vi.mocked(sessionStart).mockResolvedValue({
|
|
664
|
-
success: true,
|
|
665
|
-
data: START_DATA,
|
|
666
|
-
});
|
|
667
|
-
});
|
|
668
|
-
it('handler.mutate("start") and dispatchRaw produce identical data', async () => {
|
|
669
|
-
const params = { scope: 'epic:T010', name: 'Test Session', autoStart: true };
|
|
670
|
-
const handlerResult = await sessionHandler.mutate('start', params);
|
|
671
|
-
const cliResult = await dispatchRaw('mutate', 'session', 'start', params);
|
|
672
|
-
expect(handlerResult.success).toBe(true);
|
|
673
|
-
expect(cliResult.success).toBe(true);
|
|
674
|
-
// Both paths (direct handler + dispatchRaw) produce the same enriched data
|
|
675
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
676
|
-
// The handler enriches the data with sessionId
|
|
677
|
-
expect(cliResult.data).toEqual(ENRICHED_START_DATA);
|
|
678
|
-
});
|
|
679
|
-
});
|
|
680
|
-
});
|
|
681
|
-
// ===========================================================================
|
|
682
|
-
// Section 3: tasks.start/stop/current — focus operations (T4796)
|
|
683
|
-
// ===========================================================================
|
|
684
|
-
describe('Section 3: Focus operations parity (tasks.start/stop/current) (T4796)', () => {
|
|
685
|
-
let tasksHandler;
|
|
686
|
-
beforeEach(() => {
|
|
687
|
-
tasksHandler = new TasksHandler();
|
|
688
|
-
});
|
|
689
|
-
describe('tasks.start', () => {
|
|
690
|
-
const START_DATA = { taskId: 'T001', started: true };
|
|
691
|
-
beforeEach(() => {
|
|
692
|
-
vi.mocked(taskStart).mockResolvedValue({ success: true, data: START_DATA });
|
|
693
|
-
});
|
|
694
|
-
it('handler.mutate("start") and dispatchRaw produce identical data', async () => {
|
|
695
|
-
const handlerResult = await tasksHandler.mutate('start', { taskId: 'T001' });
|
|
696
|
-
const cliResult = await dispatchRaw('mutate', 'tasks', 'start', {
|
|
697
|
-
taskId: 'T001',
|
|
698
|
-
});
|
|
699
|
-
expect(handlerResult.success).toBe(true);
|
|
700
|
-
expect(cliResult.success).toBe(true);
|
|
701
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
702
|
-
expect(cliResult.data).toEqual(START_DATA);
|
|
703
|
-
});
|
|
704
|
-
it('taskStart engine called with identical args from handler and dispatchRaw', async () => {
|
|
705
|
-
await tasksHandler.mutate('start', { taskId: 'T005' });
|
|
706
|
-
await dispatchRaw('mutate', 'tasks', 'start', { taskId: 'T005' });
|
|
707
|
-
expect(taskStart).toHaveBeenCalledTimes(2);
|
|
708
|
-
expect(vi.mocked(taskStart).mock.calls[0]).toEqual(vi.mocked(taskStart).mock.calls[1]);
|
|
709
|
-
});
|
|
710
|
-
});
|
|
711
|
-
describe('tasks.stop', () => {
|
|
712
|
-
const STOP_DATA = { cleared: true };
|
|
713
|
-
beforeEach(() => {
|
|
714
|
-
vi.mocked(taskStop).mockResolvedValue({ success: true, data: STOP_DATA });
|
|
715
|
-
});
|
|
716
|
-
it('handler.mutate("stop") and dispatchRaw produce identical data', async () => {
|
|
717
|
-
const handlerResult = await tasksHandler.mutate('stop', {});
|
|
718
|
-
const cliResult = await dispatchRaw('mutate', 'tasks', 'stop', {});
|
|
719
|
-
expect(handlerResult.success).toBe(true);
|
|
720
|
-
expect(cliResult.success).toBe(true);
|
|
721
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
722
|
-
});
|
|
723
|
-
});
|
|
724
|
-
describe('tasks.current', () => {
|
|
725
|
-
const CURRENT_DATA = { currentTask: 'T001', since: '2026-02-25T00:00:00Z' };
|
|
726
|
-
beforeEach(() => {
|
|
727
|
-
vi.mocked(taskCurrentGet).mockResolvedValue({
|
|
728
|
-
success: true,
|
|
729
|
-
data: CURRENT_DATA,
|
|
730
|
-
});
|
|
731
|
-
});
|
|
732
|
-
it('handler.query("current") and dispatchRaw produce identical data', async () => {
|
|
733
|
-
const handlerResult = await tasksHandler.query('current', {});
|
|
734
|
-
const cliResult = await dispatchRaw('query', 'tasks', 'current', {});
|
|
735
|
-
expect(handlerResult.success).toBe(true);
|
|
736
|
-
expect(cliResult.success).toBe(true);
|
|
737
|
-
expect(handlerResult.data).toEqual(cliResult.data);
|
|
738
|
-
});
|
|
739
|
-
});
|
|
740
|
-
});
|
|
741
|
-
// ===========================================================================
|
|
742
|
-
// Section 4: DispatchResponse shape consistency (T4796)
|
|
743
|
-
// ===========================================================================
|
|
744
|
-
describe('Section 4: DispatchResponse shape consistency (T4796)', () => {
|
|
745
|
-
let tasksHandler;
|
|
746
|
-
beforeEach(() => {
|
|
747
|
-
tasksHandler = new TasksHandler();
|
|
748
|
-
});
|
|
749
|
-
it('_meta has required fields: gateway, domain, operation, timestamp, requestId', async () => {
|
|
750
|
-
vi.mocked(taskShow).mockResolvedValue({
|
|
751
|
-
success: true,
|
|
752
|
-
data: { task: { id: 'T001' } },
|
|
753
|
-
});
|
|
754
|
-
const cliResult = await dispatchRaw('query', 'tasks', 'show', {
|
|
755
|
-
taskId: 'T001',
|
|
756
|
-
});
|
|
757
|
-
expect(cliResult._meta).toBeDefined();
|
|
758
|
-
expect(cliResult._meta.gateway).toBe('query');
|
|
759
|
-
expect(cliResult._meta.domain).toBe('tasks');
|
|
760
|
-
expect(cliResult._meta.operation).toBe('show');
|
|
761
|
-
expect(typeof cliResult._meta.timestamp).toBe('string');
|
|
762
|
-
expect(typeof cliResult._meta.requestId).toBe('string');
|
|
763
|
-
expect(typeof cliResult._meta.duration_ms).toBe('number');
|
|
764
|
-
});
|
|
765
|
-
it('_meta.source is "cli" for dispatchRaw calls', async () => {
|
|
766
|
-
vi.mocked(taskShow).mockResolvedValue({
|
|
767
|
-
success: true,
|
|
768
|
-
data: { task: { id: 'T001' } },
|
|
769
|
-
});
|
|
770
|
-
const cliResult = await dispatchRaw('query', 'tasks', 'show', {
|
|
771
|
-
taskId: 'T001',
|
|
772
|
-
});
|
|
773
|
-
expect(cliResult._meta.source).toBe('cli');
|
|
774
|
-
});
|
|
775
|
-
it('success responses have data field; error responses have error field', async () => {
|
|
776
|
-
vi.mocked(taskShow).mockResolvedValue({
|
|
777
|
-
success: true,
|
|
778
|
-
data: { task: { id: 'T001' } },
|
|
779
|
-
});
|
|
780
|
-
const successResult = await dispatchRaw('query', 'tasks', 'show', {
|
|
781
|
-
taskId: 'T001',
|
|
782
|
-
});
|
|
783
|
-
expect(successResult.success).toBe(true);
|
|
784
|
-
expect(successResult.data).toBeDefined();
|
|
785
|
-
expect(successResult.error).toBeUndefined();
|
|
786
|
-
const errorResult = await dispatchRaw('query', 'tasks', 'show', {});
|
|
787
|
-
expect(errorResult.success).toBe(false);
|
|
788
|
-
expect(errorResult.error).toBeDefined();
|
|
789
|
-
expect(typeof errorResult.error?.code).toBe('string');
|
|
790
|
-
expect(typeof errorResult.error?.message).toBe('string');
|
|
791
|
-
});
|
|
792
|
-
it('error codes are E_ prefixed strings', async () => {
|
|
793
|
-
// Missing taskId → E_INVALID_INPUT
|
|
794
|
-
const result1 = await dispatchRaw('query', 'tasks', 'show', {});
|
|
795
|
-
expect(result1.error?.code).toMatch(/^E_/);
|
|
796
|
-
// Unknown operation → E_INVALID_OPERATION
|
|
797
|
-
const result2 = await dispatchRaw('query', 'tasks', 'nonexistent', {});
|
|
798
|
-
expect(result2.error?.code).toBe('E_INVALID_OPERATION');
|
|
799
|
-
});
|
|
800
|
-
it('domain handler and dispatchRaw produce identical error shape for same failure', async () => {
|
|
801
|
-
const handlerResult = await tasksHandler.query('show', {});
|
|
802
|
-
const cliResult = await dispatchRaw('query', 'tasks', 'show', {});
|
|
803
|
-
// Both return error with same code and message
|
|
804
|
-
expect(handlerResult.error?.code).toBe('E_INVALID_INPUT');
|
|
805
|
-
expect(cliResult.error?.code).toBe('E_INVALID_INPUT');
|
|
806
|
-
expect(handlerResult.error?.message).toBe(cliResult.error?.message);
|
|
807
|
-
});
|
|
808
|
-
});
|
|
809
|
-
// ===========================================================================
|
|
810
|
-
// Section 5: Documented parity gaps (T4796)
|
|
811
|
-
//
|
|
812
|
-
// These tests document known architectural gaps between CLI and MCP paths.
|
|
813
|
-
// They verify the current behavior and are intended to fail once the gap
|
|
814
|
-
// is fixed (at which point the test assertions should be updated).
|
|
815
|
-
// ===========================================================================
|
|
816
|
-
describe('Section 5: Documented parity gaps (T4796)', () => {
|
|
817
|
-
/**
|
|
818
|
-
* GAP 1: MCP gateway normalization
|
|
819
|
-
*
|
|
820
|
-
* handleMcpToolCall() passes 'cleo_query' as the gateway field to the
|
|
821
|
-
* Dispatcher, but the registry only indexes operations by 'query'/'mutate'.
|
|
822
|
-
* This causes ALL handleMcpToolCall() calls to fail with E_INVALID_OPERATION
|
|
823
|
-
* because the registry lookup in dispatcher.ts line 38:
|
|
824
|
-
* resolve(request.gateway, domain, operation)
|
|
825
|
-
* receives 'cleo_query' instead of 'query'.
|
|
826
|
-
*
|
|
827
|
-
* Fix: handleMcpToolCall() should normalize gateway before dispatching:
|
|
828
|
-
* const normalizedGateway = gateway === 'cleo_query' ? 'query' : 'mutate';
|
|
829
|
-
*/
|
|
830
|
-
it('GAP RESOLVED: handleMcpToolCall now normalizes cleo_query to query', async () => {
|
|
831
|
-
vi.mocked(taskShow).mockResolvedValue({
|
|
832
|
-
success: true,
|
|
833
|
-
data: { task: { id: 'T001' } },
|
|
834
|
-
});
|
|
835
|
-
const mcpResponse = await handleMcpToolCall('cleo_query', 'tasks', 'show', { taskId: 'T001' });
|
|
836
|
-
// GAP has been resolved: cleo_query is now normalized to query.
|
|
837
|
-
// The request succeeds because the registry lookup now works.
|
|
838
|
-
expect(mcpResponse.success).toBe(true);
|
|
839
|
-
});
|
|
840
|
-
/**
|
|
841
|
-
* GAP 2: Dispatcher routes cleo_query to handler.mutate() instead of handler.query()
|
|
842
|
-
*
|
|
843
|
-
* In dispatcher.ts line 88:
|
|
844
|
-
* if (request.gateway === 'query') { handler.query(...) } else { handler.mutate(...) }
|
|
845
|
-
*
|
|
846
|
-
* Since MCP requests arrive with gateway='cleo_query', they fall through to
|
|
847
|
-
* handler.mutate() even for read operations. This compounds the registry gap.
|
|
848
|
-
*
|
|
849
|
-
* This gap is blocked by GAP 1 (registry failure happens first), but once
|
|
850
|
-
* GAP 1 is fixed, this must also be fixed.
|
|
851
|
-
*
|
|
852
|
-
* Fix: Normalize 'cleo_query' → 'query' before the terminal handler check.
|
|
853
|
-
*/
|
|
854
|
-
it('GAP: Dispatcher routes cleo_query to mutate handler (wrong path for read ops)', async () => {
|
|
855
|
-
// This gap is masked by GAP 1, but we verify the expected correct behavior
|
|
856
|
-
// via dispatchRaw (which uses 'query' gateway correctly):
|
|
857
|
-
vi.mocked(taskShow).mockResolvedValue({
|
|
858
|
-
success: true,
|
|
859
|
-
data: { task: { id: 'T001' } },
|
|
860
|
-
});
|
|
861
|
-
const cliResult = await dispatchRaw('query', 'tasks', 'show', {
|
|
862
|
-
taskId: 'T001',
|
|
863
|
-
});
|
|
864
|
-
// CLI correctly routes to handler.query()
|
|
865
|
-
expect(cliResult.success).toBe(true);
|
|
866
|
-
expect(cliResult.data).toEqual({ task: { id: 'T001' } });
|
|
867
|
-
// taskShow (a query engine fn) was called once (via CLI query path)
|
|
868
|
-
expect(taskShow).toHaveBeenCalledTimes(1);
|
|
869
|
-
});
|
|
870
|
-
/**
|
|
871
|
-
* CORRECT PATH: CLI dispatchRaw produces valid results for all tested operations.
|
|
872
|
-
* The full CLI → Dispatcher → Handler → Engine → Core path works correctly.
|
|
873
|
-
*/
|
|
874
|
-
it('CLI path (dispatchRaw) works correctly end-to-end for task operations', async () => {
|
|
875
|
-
vi.mocked(taskShow).mockResolvedValue({
|
|
876
|
-
success: true,
|
|
877
|
-
data: { task: { id: 'T001', title: 'Test task' } },
|
|
878
|
-
});
|
|
879
|
-
vi.mocked(taskList).mockResolvedValue({
|
|
880
|
-
success: true,
|
|
881
|
-
data: { tasks: [], total: 0 },
|
|
882
|
-
});
|
|
883
|
-
vi.mocked(taskCreate).mockResolvedValue({
|
|
884
|
-
success: true,
|
|
885
|
-
data: { task: { id: 'T100', title: 'New task' } },
|
|
886
|
-
});
|
|
887
|
-
const showResult = await dispatchRaw('query', 'tasks', 'show', { taskId: 'T001' });
|
|
888
|
-
const listResult = await dispatchRaw('query', 'tasks', 'list', {});
|
|
889
|
-
const addResult = await dispatchRaw('mutate', 'tasks', 'add', { title: 'New task' });
|
|
890
|
-
expect(showResult.success).toBe(true);
|
|
891
|
-
expect(listResult.success).toBe(true);
|
|
892
|
-
expect(addResult.success).toBe(true);
|
|
893
|
-
expect(taskShow).toHaveBeenCalledTimes(1);
|
|
894
|
-
expect(taskList).toHaveBeenCalledTimes(1);
|
|
895
|
-
expect(taskCreate).toHaveBeenCalledTimes(1);
|
|
896
|
-
});
|
|
897
|
-
});
|
|
898
|
-
//# sourceMappingURL=cli-mcp-parity.integration.test.js.map
|