@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
|
@@ -25,19 +25,23 @@ export class ConduitClient implements Conduit {
|
|
|
25
25
|
private credential: AgentCredential;
|
|
26
26
|
private state: ConduitState = 'disconnected';
|
|
27
27
|
|
|
28
|
+
/** Create a ConduitClient backed by the given transport and credential. */
|
|
28
29
|
constructor(transport: Transport, credential: AgentCredential) {
|
|
29
30
|
this.transport = transport;
|
|
30
31
|
this.credential = credential;
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
/** The agent ID from the bound credential. */
|
|
33
35
|
get agentId(): string {
|
|
34
36
|
return this.credential.agentId;
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
/** Current connection state (disconnected → connecting → connected | error). */
|
|
37
40
|
getState(): ConduitState {
|
|
38
41
|
return this.state;
|
|
39
42
|
}
|
|
40
43
|
|
|
44
|
+
/** Connect the underlying transport using the bound credential. */
|
|
41
45
|
async connect(): Promise<void> {
|
|
42
46
|
this.state = 'connecting';
|
|
43
47
|
try {
|
|
@@ -55,6 +59,7 @@ export class ConduitClient implements Conduit {
|
|
|
55
59
|
}
|
|
56
60
|
}
|
|
57
61
|
|
|
62
|
+
/** Send a message to another agent, optionally within a thread. */
|
|
58
63
|
async send(
|
|
59
64
|
to: string,
|
|
60
65
|
content: string,
|
|
@@ -69,6 +74,12 @@ export class ConduitClient implements Conduit {
|
|
|
69
74
|
};
|
|
70
75
|
}
|
|
71
76
|
|
|
77
|
+
/** One-shot poll for new messages. Delegates to the transport's poll method. */
|
|
78
|
+
async poll(options?: { limit?: number; since?: string }): Promise<ConduitMessage[]> {
|
|
79
|
+
return this.transport.poll(options);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Subscribe to incoming messages. Uses real-time transport when available, else polls. */
|
|
72
83
|
onMessage(handler: (message: ConduitMessage) => void): ConduitUnsubscribe {
|
|
73
84
|
// Prefer real-time subscription if transport supports it
|
|
74
85
|
if (this.transport.subscribe) {
|
|
@@ -85,11 +96,13 @@ export class ConduitClient implements Conduit {
|
|
|
85
96
|
return () => clearInterval(interval);
|
|
86
97
|
}
|
|
87
98
|
|
|
99
|
+
/** Send an empty heartbeat to maintain presence on the relay. */
|
|
88
100
|
async heartbeat(): Promise<void> {
|
|
89
101
|
// Send empty heartbeat via transport
|
|
90
102
|
await this.transport.push(this.credential.agentId, '', {});
|
|
91
103
|
}
|
|
92
104
|
|
|
105
|
+
/** Check whether a remote agent is currently online via the cloud API. */
|
|
93
106
|
async isOnline(agentId: string): Promise<boolean> {
|
|
94
107
|
// Delegate to cloud API check — stub for now
|
|
95
108
|
try {
|
|
@@ -107,6 +120,7 @@ export class ConduitClient implements Conduit {
|
|
|
107
120
|
}
|
|
108
121
|
}
|
|
109
122
|
|
|
123
|
+
/** Disconnect the transport and reset state to disconnected. */
|
|
110
124
|
async disconnect(): Promise<void> {
|
|
111
125
|
await this.transport.disconnect();
|
|
112
126
|
this.state = 'disconnected';
|
package/src/conduit/factory.ts
CHANGED
|
@@ -11,17 +11,38 @@
|
|
|
11
11
|
import type { AgentCredential, AgentRegistryAPI, Conduit, Transport } from '@cleocode/contracts';
|
|
12
12
|
import { ConduitClient } from './conduit-client.js';
|
|
13
13
|
import { HttpTransport } from './http-transport.js';
|
|
14
|
+
import { LocalTransport } from './local-transport.js';
|
|
15
|
+
import { SseTransport } from './sse-transport.js';
|
|
14
16
|
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the best available transport for a credential.
|
|
19
|
+
*
|
|
20
|
+
* Cloud-backed agents (apiBaseUrl is a remote URL) use HttpTransport
|
|
21
|
+
* so they can receive messages from the SignalDock cloud relay.
|
|
22
|
+
* LocalTransport is only used when the agent is explicitly local-only
|
|
23
|
+
* (apiBaseUrl is 'local' or absent), since local signaldock.db doesn't
|
|
24
|
+
* sync with the cloud.
|
|
25
|
+
*/
|
|
26
|
+
export function resolveTransport(credential: AgentCredential): Transport {
|
|
27
|
+
const isCloudBacked =
|
|
28
|
+
credential.apiBaseUrl &&
|
|
29
|
+
credential.apiBaseUrl !== 'local' &&
|
|
30
|
+
credential.apiBaseUrl.startsWith('http');
|
|
31
|
+
|
|
32
|
+
// Cloud-backed agents must use network transports to receive cloud messages
|
|
33
|
+
if (isCloudBacked) {
|
|
34
|
+
if (credential.transportConfig.sseEndpoint) {
|
|
35
|
+
return new SseTransport();
|
|
36
|
+
}
|
|
37
|
+
return new HttpTransport();
|
|
21
38
|
}
|
|
22
|
-
|
|
23
|
-
|
|
39
|
+
|
|
40
|
+
// Local-only agents use LocalTransport when signaldock.db is available
|
|
41
|
+
if (LocalTransport.isAvailable()) {
|
|
42
|
+
return new LocalTransport();
|
|
24
43
|
}
|
|
44
|
+
|
|
45
|
+
// Fallback to HTTP
|
|
25
46
|
return new HttpTransport();
|
|
26
47
|
}
|
|
27
48
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HttpTransport — HTTP polling transport
|
|
2
|
+
* HttpTransport — HTTP polling transport with automatic failover.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* (api.
|
|
6
|
-
*
|
|
4
|
+
* Tries the primary API URL (api.signaldock.io) first. If unreachable,
|
|
5
|
+
* falls back to the legacy URL (api.clawmsgr.com). Failover is transparent
|
|
6
|
+
* to callers — they see a single transport that always works if either
|
|
7
|
+
* endpoint is up.
|
|
7
8
|
*
|
|
8
9
|
* @see docs/specs/SIGNALDOCK-UNIFIED-AGENT-REGISTRY.md Section 4.4
|
|
9
10
|
* @task T177
|
|
@@ -15,28 +16,52 @@ import type { ConduitMessage, Transport, TransportConnectConfig } from '@cleocod
|
|
|
15
16
|
interface HttpTransportState {
|
|
16
17
|
agentId: string;
|
|
17
18
|
apiKey: string;
|
|
18
|
-
|
|
19
|
+
primaryUrl: string;
|
|
20
|
+
fallbackUrl: string | null;
|
|
21
|
+
activeUrl: string;
|
|
19
22
|
connected: boolean;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
/** HTTP
|
|
25
|
+
/** HTTP transport with automatic primary/fallback failover. */
|
|
23
26
|
export class HttpTransport implements Transport {
|
|
24
27
|
readonly name = 'http';
|
|
25
28
|
private state: HttpTransportState | null = null;
|
|
26
29
|
|
|
30
|
+
/** Connect to the SignalDock API, probing primary/fallback health when both are configured. */
|
|
27
31
|
async connect(config: TransportConnectConfig): Promise<void> {
|
|
32
|
+
const primaryUrl = config.apiBaseUrl;
|
|
33
|
+
const fallbackUrl = config.apiBaseUrlFallback ?? null;
|
|
34
|
+
|
|
35
|
+
// Only probe health when there's a fallback to choose between
|
|
36
|
+
let activeUrl = primaryUrl;
|
|
37
|
+
if (fallbackUrl) {
|
|
38
|
+
const [primaryResult, fallbackResult] = await Promise.allSettled([
|
|
39
|
+
fetch(`${primaryUrl}/health`, { method: 'GET', signal: AbortSignal.timeout(5000) }),
|
|
40
|
+
fetch(`${fallbackUrl}/health`, { method: 'GET', signal: AbortSignal.timeout(5000) }),
|
|
41
|
+
]);
|
|
42
|
+
const primaryOk = primaryResult.status === 'fulfilled' && primaryResult.value.ok;
|
|
43
|
+
const fallbackOk = fallbackResult.status === 'fulfilled' && fallbackResult.value.ok;
|
|
44
|
+
if (!primaryOk && fallbackOk) {
|
|
45
|
+
activeUrl = fallbackUrl;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
28
49
|
this.state = {
|
|
29
50
|
agentId: config.agentId,
|
|
30
51
|
apiKey: config.apiKey,
|
|
31
|
-
|
|
52
|
+
primaryUrl,
|
|
53
|
+
fallbackUrl,
|
|
54
|
+
activeUrl,
|
|
32
55
|
connected: true,
|
|
33
56
|
};
|
|
34
57
|
}
|
|
35
58
|
|
|
59
|
+
/** Disconnect and clear connection state. */
|
|
36
60
|
async disconnect(): Promise<void> {
|
|
37
61
|
this.state = null;
|
|
38
62
|
}
|
|
39
63
|
|
|
64
|
+
/** Send a message to an agent (direct or within a conversation thread). */
|
|
40
65
|
async push(
|
|
41
66
|
to: string,
|
|
42
67
|
content: string,
|
|
@@ -46,18 +71,18 @@ export class HttpTransport implements Transport {
|
|
|
46
71
|
|
|
47
72
|
const body: Record<string, string> = { content };
|
|
48
73
|
|
|
49
|
-
let
|
|
74
|
+
let path: string;
|
|
50
75
|
if (options?.conversationId) {
|
|
51
|
-
|
|
76
|
+
path = `/conversations/${options.conversationId}/messages`;
|
|
52
77
|
if (options.replyTo) {
|
|
53
78
|
body['replyTo'] = options.replyTo;
|
|
54
79
|
}
|
|
55
80
|
} else {
|
|
56
|
-
|
|
81
|
+
path = '/messages';
|
|
57
82
|
body['toAgentId'] = to;
|
|
58
83
|
}
|
|
59
84
|
|
|
60
|
-
const response = await
|
|
85
|
+
const response = await this.fetchWithFallback(path, {
|
|
61
86
|
method: 'POST',
|
|
62
87
|
headers: this.headers(),
|
|
63
88
|
body: JSON.stringify(body),
|
|
@@ -76,17 +101,17 @@ export class HttpTransport implements Transport {
|
|
|
76
101
|
return { messageId };
|
|
77
102
|
}
|
|
78
103
|
|
|
104
|
+
/** Poll for new messages for this agent. Returns empty array on HTTP error. */
|
|
79
105
|
async poll(options?: { limit?: number; since?: string }): Promise<ConduitMessage[]> {
|
|
80
106
|
this.ensureConnected();
|
|
81
107
|
|
|
82
108
|
const params = new URLSearchParams();
|
|
83
|
-
|
|
109
|
+
// Don't filter by mentioned — the API already scopes by X-Agent-Id header.
|
|
110
|
+
// Using mentioned= misses messages sent TO this agent without @-mentions.
|
|
84
111
|
if (options?.limit) params.set('limit', String(options.limit));
|
|
85
|
-
// H5 fix: pass since param to avoid reprocessing old messages
|
|
86
112
|
if (options?.since) params.set('since', options.since);
|
|
87
113
|
|
|
88
|
-
const
|
|
89
|
-
const response = await fetch(url, {
|
|
114
|
+
const response = await this.fetchWithFallback(`/messages/peek?${params}`, {
|
|
90
115
|
method: 'GET',
|
|
91
116
|
headers: this.headers(),
|
|
92
117
|
});
|
|
@@ -114,16 +139,53 @@ export class HttpTransport implements Transport {
|
|
|
114
139
|
}));
|
|
115
140
|
}
|
|
116
141
|
|
|
142
|
+
/** Acknowledge messages by ID so they are not returned by future polls. */
|
|
117
143
|
async ack(messageIds: string[]): Promise<void> {
|
|
118
144
|
this.ensureConnected();
|
|
119
145
|
|
|
120
|
-
await
|
|
146
|
+
await this.fetchWithFallback('/messages/ack', {
|
|
121
147
|
method: 'POST',
|
|
122
148
|
headers: this.headers(),
|
|
123
149
|
body: JSON.stringify({ messageIds }),
|
|
124
150
|
});
|
|
125
151
|
}
|
|
126
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Fetch with automatic failover. Tries activeUrl first.
|
|
155
|
+
* If it fails and a fallback exists, retries on the other URL
|
|
156
|
+
* and swaps activeUrl for subsequent calls.
|
|
157
|
+
*/
|
|
158
|
+
private async fetchWithFallback(path: string, init: RequestInit): Promise<Response> {
|
|
159
|
+
const timeout = AbortSignal.timeout(10000);
|
|
160
|
+
const signal = init.signal ? AbortSignal.any([init.signal, timeout]) : timeout;
|
|
161
|
+
const url = `${this.state!.activeUrl}${path}`;
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
return await fetch(url, { ...init, signal });
|
|
165
|
+
} catch (primaryErr) {
|
|
166
|
+
const otherUrl =
|
|
167
|
+
this.state!.activeUrl === this.state!.primaryUrl
|
|
168
|
+
? this.state!.fallbackUrl
|
|
169
|
+
: this.state!.primaryUrl;
|
|
170
|
+
|
|
171
|
+
if (!otherUrl) throw primaryErr;
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
const fallbackSignal = init.signal
|
|
175
|
+
? AbortSignal.any([init.signal, AbortSignal.timeout(10000)])
|
|
176
|
+
: AbortSignal.timeout(10000);
|
|
177
|
+
const fallbackResponse = await fetch(`${otherUrl}${path}`, {
|
|
178
|
+
...init,
|
|
179
|
+
signal: fallbackSignal,
|
|
180
|
+
});
|
|
181
|
+
this.state!.activeUrl = otherUrl;
|
|
182
|
+
return fallbackResponse;
|
|
183
|
+
} catch {
|
|
184
|
+
throw primaryErr;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
127
189
|
private headers(): Record<string, string> {
|
|
128
190
|
return {
|
|
129
191
|
'Content-Type': 'application/json',
|
package/src/conduit/index.ts
CHANGED
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
* Conduit — High-level agent messaging for the CLEO ecosystem.
|
|
3
3
|
*
|
|
4
4
|
* Exports the ConduitClient (high-level messaging), HttpTransport
|
|
5
|
-
* (HTTP polling to cloud),
|
|
5
|
+
* (HTTP polling to cloud), LocalTransport (offline SQLite), and
|
|
6
|
+
* createConduit factory.
|
|
6
7
|
*
|
|
7
8
|
* @module conduit
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
export { ConduitClient } from './conduit-client.js';
|
|
11
|
-
export { createConduit } from './factory.js';
|
|
12
|
+
export { createConduit, resolveTransport } from './factory.js';
|
|
12
13
|
export { HttpTransport } from './http-transport.js';
|
|
14
|
+
export { LocalTransport } from './local-transport.js';
|
|
15
|
+
export { SseTransport } from './sse-transport.js';
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LocalTransport — In-process SQLite transport for fully offline agent messaging.
|
|
3
|
+
*
|
|
4
|
+
* Reads and writes messages directly to signaldock.db via node:sqlite.
|
|
5
|
+
* No network calls. Works fully offline. Messages are stored in the
|
|
6
|
+
* same schema that the Rust signaldock-storage crate manages, so both
|
|
7
|
+
* the local CLI and the cloud backend see the same data.
|
|
8
|
+
*
|
|
9
|
+
* Priority: LocalTransport is preferred over HttpTransport when
|
|
10
|
+
* signaldock.db is available (see factory.ts).
|
|
11
|
+
*
|
|
12
|
+
* @see docs/specs/SIGNALDOCK-UNIFIED-AGENT-REGISTRY.md Section 4.4
|
|
13
|
+
* @task T213
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { randomUUID } from 'node:crypto';
|
|
17
|
+
import { existsSync } from 'node:fs';
|
|
18
|
+
import { createRequire } from 'node:module';
|
|
19
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
20
|
+
import type { ConduitMessage, Transport, TransportConnectConfig } from '@cleocode/contracts';
|
|
21
|
+
import { getSignaldockDbPath } from '../store/signaldock-sqlite.js';
|
|
22
|
+
|
|
23
|
+
const _require = createRequire(import.meta.url);
|
|
24
|
+
const { DatabaseSync: DatabaseSyncClass } = _require('node:sqlite') as {
|
|
25
|
+
DatabaseSync: new (...args: ConstructorParameters<typeof DatabaseSync>) => DatabaseSync;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** Internal state for an active local transport connection. */
|
|
29
|
+
interface LocalTransportState {
|
|
30
|
+
agentId: string;
|
|
31
|
+
db: DatabaseSync;
|
|
32
|
+
dbPath: string;
|
|
33
|
+
subscribers: Set<(message: ConduitMessage) => void>;
|
|
34
|
+
pollTimer: ReturnType<typeof setInterval> | null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** In-process SQLite transport for fully offline agent messaging. */
|
|
38
|
+
export class LocalTransport implements Transport {
|
|
39
|
+
readonly name = 'local';
|
|
40
|
+
private state: LocalTransportState | null = null;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Connect to signaldock.db for in-process messaging.
|
|
44
|
+
*
|
|
45
|
+
* Opens the database, sets WAL mode pragmas, and verifies
|
|
46
|
+
* the messages table exists. Throws if signaldock.db is missing
|
|
47
|
+
* or uninitialized (run `cleo init` first).
|
|
48
|
+
*/
|
|
49
|
+
async connect(config: TransportConnectConfig): Promise<void> {
|
|
50
|
+
const dbPath = getSignaldockDbPath();
|
|
51
|
+
|
|
52
|
+
if (!existsSync(dbPath)) {
|
|
53
|
+
throw new Error(`LocalTransport: signaldock.db not found at ${dbPath}. Run: cleo init`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const db = new DatabaseSyncClass(dbPath);
|
|
57
|
+
db.exec('PRAGMA journal_mode = WAL');
|
|
58
|
+
db.exec('PRAGMA busy_timeout = 5000');
|
|
59
|
+
db.exec('PRAGMA foreign_keys = ON');
|
|
60
|
+
|
|
61
|
+
// Verify the messages table exists
|
|
62
|
+
const hasMessages = db
|
|
63
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages'")
|
|
64
|
+
.get() as { name: string } | undefined;
|
|
65
|
+
|
|
66
|
+
if (!hasMessages) {
|
|
67
|
+
db.close();
|
|
68
|
+
throw new Error(
|
|
69
|
+
'LocalTransport: signaldock.db exists but messages table missing. Run: cleo upgrade',
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this.state = {
|
|
74
|
+
agentId: config.agentId,
|
|
75
|
+
db,
|
|
76
|
+
dbPath,
|
|
77
|
+
subscribers: new Set(),
|
|
78
|
+
pollTimer: null,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Close the database connection and stop any subscriber polling. */
|
|
83
|
+
async disconnect(): Promise<void> {
|
|
84
|
+
if (!this.state) return;
|
|
85
|
+
|
|
86
|
+
if (this.state.pollTimer) {
|
|
87
|
+
clearInterval(this.state.pollTimer);
|
|
88
|
+
}
|
|
89
|
+
this.state.subscribers.clear();
|
|
90
|
+
this.state.db.close();
|
|
91
|
+
this.state = null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Store a message in signaldock.db.
|
|
96
|
+
*
|
|
97
|
+
* Inserts into the messages table with status 'pending'.
|
|
98
|
+
* For conversation messages, also links via conversation_participants
|
|
99
|
+
* if not already present.
|
|
100
|
+
*/
|
|
101
|
+
async push(
|
|
102
|
+
to: string,
|
|
103
|
+
content: string,
|
|
104
|
+
options?: { conversationId?: string; replyTo?: string },
|
|
105
|
+
): Promise<{ messageId: string }> {
|
|
106
|
+
this.ensureConnected();
|
|
107
|
+
const { db, agentId } = this.state!;
|
|
108
|
+
const messageId = randomUUID();
|
|
109
|
+
const nowUnix = Math.floor(Date.now() / 1000);
|
|
110
|
+
|
|
111
|
+
if (options?.conversationId) {
|
|
112
|
+
db.prepare(
|
|
113
|
+
`INSERT INTO messages (id, conversation_id, from_agent_id, to_agent_id, content, content_type, status, created_at)
|
|
114
|
+
VALUES (?, ?, ?, ?, ?, 'text', 'pending', ?)`,
|
|
115
|
+
).run(messageId, options.conversationId, agentId, to, content, nowUnix);
|
|
116
|
+
} else {
|
|
117
|
+
// Direct message — create or reuse a DM conversation
|
|
118
|
+
const convId = this.ensureDmConversation(agentId, to);
|
|
119
|
+
db.prepare(
|
|
120
|
+
`INSERT INTO messages (id, conversation_id, from_agent_id, to_agent_id, content, content_type, status, created_at)
|
|
121
|
+
VALUES (?, ?, ?, ?, ?, 'text', 'pending', ?)`,
|
|
122
|
+
).run(messageId, convId, agentId, to, content, nowUnix);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Notify local subscribers
|
|
126
|
+
this.notifySubscribers({
|
|
127
|
+
id: messageId,
|
|
128
|
+
from: agentId,
|
|
129
|
+
content,
|
|
130
|
+
threadId: options?.conversationId,
|
|
131
|
+
timestamp: new Date(nowUnix * 1000).toISOString(),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
return { messageId };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Poll for messages addressed to this agent.
|
|
139
|
+
*
|
|
140
|
+
* Returns messages with status 'pending' where to_agent_id matches
|
|
141
|
+
* the connected agent. Messages are returned oldest-first.
|
|
142
|
+
*/
|
|
143
|
+
async poll(options?: { limit?: number; since?: string }): Promise<ConduitMessage[]> {
|
|
144
|
+
this.ensureConnected();
|
|
145
|
+
const { db, agentId } = this.state!;
|
|
146
|
+
const limit = options?.limit ?? 50;
|
|
147
|
+
|
|
148
|
+
let query: string;
|
|
149
|
+
let params: (string | number)[];
|
|
150
|
+
|
|
151
|
+
if (options?.since) {
|
|
152
|
+
query = `SELECT id, from_agent_id, content, conversation_id, created_at
|
|
153
|
+
FROM messages
|
|
154
|
+
WHERE to_agent_id = ? AND status = 'pending' AND created_at > ?
|
|
155
|
+
ORDER BY created_at ASC
|
|
156
|
+
LIMIT ?`;
|
|
157
|
+
params = [agentId, options.since, limit];
|
|
158
|
+
} else {
|
|
159
|
+
query = `SELECT id, from_agent_id, content, conversation_id, created_at
|
|
160
|
+
FROM messages
|
|
161
|
+
WHERE to_agent_id = ? AND status = 'pending'
|
|
162
|
+
ORDER BY created_at ASC
|
|
163
|
+
LIMIT ?`;
|
|
164
|
+
params = [agentId, limit];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const rows = db.prepare(query).all(...params) as Array<{
|
|
168
|
+
id: string;
|
|
169
|
+
from_agent_id: string;
|
|
170
|
+
content: string;
|
|
171
|
+
conversation_id: string | null;
|
|
172
|
+
created_at: number;
|
|
173
|
+
}>;
|
|
174
|
+
|
|
175
|
+
return rows.map((r) => ({
|
|
176
|
+
id: r.id,
|
|
177
|
+
from: r.from_agent_id,
|
|
178
|
+
content: r.content,
|
|
179
|
+
threadId: r.conversation_id ?? undefined,
|
|
180
|
+
timestamp: new Date(r.created_at * 1000).toISOString(),
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Acknowledge messages by marking them as 'delivered'.
|
|
186
|
+
*
|
|
187
|
+
* Updates the status and delivered_at timestamp for each message ID.
|
|
188
|
+
*/
|
|
189
|
+
async ack(messageIds: string[]): Promise<void> {
|
|
190
|
+
this.ensureConnected();
|
|
191
|
+
if (messageIds.length === 0) return;
|
|
192
|
+
|
|
193
|
+
const { db } = this.state!;
|
|
194
|
+
const nowUnix = Math.floor(Date.now() / 1000);
|
|
195
|
+
|
|
196
|
+
const placeholders = messageIds.map(() => '?').join(', ');
|
|
197
|
+
db.prepare(
|
|
198
|
+
`UPDATE messages SET status = 'delivered', delivered_at = ? WHERE id IN (${placeholders})`,
|
|
199
|
+
).run(nowUnix, ...messageIds);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Subscribe to real-time local messages.
|
|
204
|
+
*
|
|
205
|
+
* Since this is in-process, subscribers are notified synchronously
|
|
206
|
+
* when push() is called. Additionally, a polling interval checks
|
|
207
|
+
* for messages inserted by other processes (e.g., Rust CLI).
|
|
208
|
+
*
|
|
209
|
+
* @returns Unsubscribe function.
|
|
210
|
+
*/
|
|
211
|
+
subscribe(handler: (message: ConduitMessage) => void): () => void {
|
|
212
|
+
this.ensureConnected();
|
|
213
|
+
this.state!.subscribers.add(handler);
|
|
214
|
+
|
|
215
|
+
// Start cross-process polling if not already running
|
|
216
|
+
if (!this.state!.pollTimer && this.state!.subscribers.size === 1) {
|
|
217
|
+
this.state!.pollTimer = setInterval(() => {
|
|
218
|
+
void this.pollAndNotify();
|
|
219
|
+
}, 1000);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return () => {
|
|
223
|
+
this.state?.subscribers.delete(handler);
|
|
224
|
+
if (this.state?.subscribers.size === 0 && this.state.pollTimer) {
|
|
225
|
+
clearInterval(this.state.pollTimer);
|
|
226
|
+
this.state.pollTimer = null;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Check whether signaldock.db is available for local transport.
|
|
233
|
+
*
|
|
234
|
+
* Used by factory.ts to decide whether to use LocalTransport.
|
|
235
|
+
*/
|
|
236
|
+
static isAvailable(cwd?: string): boolean {
|
|
237
|
+
const dbPath = getSignaldockDbPath(cwd);
|
|
238
|
+
return existsSync(dbPath);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** Poll for new messages and notify subscribers (cross-process sync). */
|
|
242
|
+
private async pollAndNotify(): Promise<void> {
|
|
243
|
+
if (!this.state || this.state.subscribers.size === 0) return;
|
|
244
|
+
|
|
245
|
+
const messages = await this.poll({ limit: 20 });
|
|
246
|
+
for (const msg of messages) {
|
|
247
|
+
this.notifySubscribers(msg);
|
|
248
|
+
}
|
|
249
|
+
if (messages.length > 0) {
|
|
250
|
+
await this.ack(messages.map((m) => m.id));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** Notify all active subscribers of a new message. */
|
|
255
|
+
private notifySubscribers(message: ConduitMessage): void {
|
|
256
|
+
if (!this.state) return;
|
|
257
|
+
for (const handler of this.state.subscribers) {
|
|
258
|
+
try {
|
|
259
|
+
handler(message);
|
|
260
|
+
} catch {
|
|
261
|
+
// Subscriber errors must not break the transport
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Ensure a DM conversation exists between two agents.
|
|
268
|
+
*
|
|
269
|
+
* Conversations store participants as a comma-separated TEXT field.
|
|
270
|
+
* We search for existing private conversations containing both agents.
|
|
271
|
+
*
|
|
272
|
+
* @returns The conversation ID.
|
|
273
|
+
*/
|
|
274
|
+
private ensureDmConversation(fromAgentId: string, toAgentId: string): string {
|
|
275
|
+
const { db } = this.state!;
|
|
276
|
+
|
|
277
|
+
// Participants are stored as comma-separated text, sorted alphabetically
|
|
278
|
+
const sortedParticipants = [fromAgentId, toAgentId].sort().join(',');
|
|
279
|
+
|
|
280
|
+
// Check for existing DM conversation with these exact participants
|
|
281
|
+
const existing = db
|
|
282
|
+
.prepare(
|
|
283
|
+
`SELECT id FROM conversations
|
|
284
|
+
WHERE visibility = 'private' AND participants = ?
|
|
285
|
+
LIMIT 1`,
|
|
286
|
+
)
|
|
287
|
+
.get(sortedParticipants) as { id: string } | undefined;
|
|
288
|
+
|
|
289
|
+
if (existing) return existing.id;
|
|
290
|
+
|
|
291
|
+
// Create new DM conversation
|
|
292
|
+
const convId = randomUUID();
|
|
293
|
+
const nowUnix = Math.floor(Date.now() / 1000);
|
|
294
|
+
|
|
295
|
+
db.prepare(
|
|
296
|
+
`INSERT INTO conversations (id, participants, visibility, message_count, created_at, updated_at)
|
|
297
|
+
VALUES (?, ?, 'private', 0, ?, ?)`,
|
|
298
|
+
).run(convId, sortedParticipants, nowUnix, nowUnix);
|
|
299
|
+
|
|
300
|
+
return convId;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Throw if not connected. */
|
|
304
|
+
private ensureConnected(): void {
|
|
305
|
+
if (!this.state) {
|
|
306
|
+
throw new Error('LocalTransport not connected. Call connect() first.');
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|