@soleri/core 2.9.0 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agency/agency-manager.d.ts +47 -0
- package/dist/agency/agency-manager.d.ts.map +1 -0
- package/dist/agency/agency-manager.js +281 -0
- package/dist/agency/agency-manager.js.map +1 -0
- package/dist/agency/index.d.ts +3 -0
- package/dist/agency/index.d.ts.map +1 -0
- package/dist/agency/index.js +2 -0
- package/dist/agency/index.js.map +1 -0
- package/dist/agency/types.d.ts +69 -0
- package/dist/agency/types.d.ts.map +1 -0
- package/dist/agency/types.js +5 -0
- package/dist/agency/types.js.map +1 -0
- package/dist/brain/brain.d.ts +0 -1
- package/dist/brain/brain.d.ts.map +1 -1
- package/dist/brain/brain.js +14 -0
- package/dist/brain/brain.js.map +1 -1
- package/dist/brain/intelligence.d.ts +5 -1
- package/dist/brain/intelligence.d.ts.map +1 -1
- package/dist/brain/intelligence.js +83 -0
- package/dist/brain/intelligence.js.map +1 -1
- package/dist/brain/types.d.ts +21 -0
- package/dist/brain/types.d.ts.map +1 -1
- package/dist/chat/agent-loop-types.d.ts +82 -0
- package/dist/chat/agent-loop-types.d.ts.map +1 -0
- package/dist/chat/agent-loop-types.js +8 -0
- package/dist/chat/agent-loop-types.js.map +1 -0
- package/dist/chat/agent-loop.d.ts +19 -0
- package/dist/chat/agent-loop.d.ts.map +1 -0
- package/dist/chat/agent-loop.js +261 -0
- package/dist/chat/agent-loop.js.map +1 -0
- package/dist/chat/auth-manager.d.ts +49 -0
- package/dist/chat/auth-manager.d.ts.map +1 -0
- package/dist/chat/auth-manager.js +152 -0
- package/dist/chat/auth-manager.js.map +1 -0
- package/dist/chat/browser-session.d.ts +86 -0
- package/dist/chat/browser-session.d.ts.map +1 -0
- package/dist/chat/browser-session.js +143 -0
- package/dist/chat/browser-session.js.map +1 -0
- package/dist/chat/cancellation.d.ts +54 -0
- package/dist/chat/cancellation.d.ts.map +1 -0
- package/dist/chat/cancellation.js +80 -0
- package/dist/chat/cancellation.js.map +1 -0
- package/dist/chat/chat-session.d.ts +86 -0
- package/dist/chat/chat-session.d.ts.map +1 -0
- package/dist/chat/chat-session.js +252 -0
- package/dist/chat/chat-session.js.map +1 -0
- package/dist/chat/file-handler.d.ts +63 -0
- package/dist/chat/file-handler.d.ts.map +1 -0
- package/dist/chat/file-handler.js +182 -0
- package/dist/chat/file-handler.js.map +1 -0
- package/dist/chat/fragment-buffer.d.ts +49 -0
- package/dist/chat/fragment-buffer.d.ts.map +1 -0
- package/dist/chat/fragment-buffer.js +130 -0
- package/dist/chat/fragment-buffer.js.map +1 -0
- package/dist/chat/index.d.ts +24 -0
- package/dist/chat/index.d.ts.map +1 -0
- package/dist/chat/index.js +15 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat/mcp-bridge.d.ts +60 -0
- package/dist/chat/mcp-bridge.d.ts.map +1 -0
- package/dist/chat/mcp-bridge.js +111 -0
- package/dist/chat/mcp-bridge.js.map +1 -0
- package/dist/chat/notifications.d.ts +82 -0
- package/dist/chat/notifications.d.ts.map +1 -0
- package/dist/chat/notifications.js +119 -0
- package/dist/chat/notifications.js.map +1 -0
- package/dist/chat/output-compressor.d.ts +30 -0
- package/dist/chat/output-compressor.d.ts.map +1 -0
- package/dist/chat/output-compressor.js +95 -0
- package/dist/chat/output-compressor.js.map +1 -0
- package/dist/chat/queue.d.ts +91 -0
- package/dist/chat/queue.d.ts.map +1 -0
- package/dist/chat/queue.js +146 -0
- package/dist/chat/queue.js.map +1 -0
- package/dist/chat/response-chunker.d.ts +29 -0
- package/dist/chat/response-chunker.d.ts.map +1 -0
- package/dist/chat/response-chunker.js +163 -0
- package/dist/chat/response-chunker.js.map +1 -0
- package/dist/chat/self-update.d.ts +62 -0
- package/dist/chat/self-update.d.ts.map +1 -0
- package/dist/chat/self-update.js +90 -0
- package/dist/chat/self-update.js.map +1 -0
- package/dist/chat/types.d.ts +105 -0
- package/dist/chat/types.d.ts.map +1 -0
- package/dist/chat/types.js +8 -0
- package/dist/chat/types.js.map +1 -0
- package/dist/chat/voice.d.ts +39 -0
- package/dist/chat/voice.d.ts.map +1 -0
- package/dist/chat/voice.js +80 -0
- package/dist/chat/voice.js.map +1 -0
- package/dist/claudemd/compose.d.ts +31 -0
- package/dist/claudemd/compose.d.ts.map +1 -0
- package/dist/claudemd/compose.js +105 -0
- package/dist/claudemd/compose.js.map +1 -0
- package/dist/claudemd/index.d.ts +5 -0
- package/dist/claudemd/index.d.ts.map +1 -0
- package/dist/claudemd/index.js +3 -0
- package/dist/claudemd/index.js.map +1 -0
- package/dist/claudemd/inject.d.ts +31 -0
- package/dist/claudemd/inject.d.ts.map +1 -0
- package/dist/claudemd/inject.js +157 -0
- package/dist/claudemd/inject.js.map +1 -0
- package/dist/claudemd/types.d.ts +41 -0
- package/dist/claudemd/types.d.ts.map +1 -0
- package/dist/claudemd/types.js +5 -0
- package/dist/claudemd/types.js.map +1 -0
- package/dist/context/context-engine.d.ts +31 -0
- package/dist/context/context-engine.d.ts.map +1 -0
- package/dist/context/context-engine.js +245 -0
- package/dist/context/context-engine.js.map +1 -0
- package/dist/context/index.d.ts +3 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +2 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/types.d.ts +54 -0
- package/dist/context/types.d.ts.map +1 -0
- package/dist/context/types.js +5 -0
- package/dist/context/types.js.map +1 -0
- package/dist/enforcement/adapters/claude-code.d.ts +18 -0
- package/dist/enforcement/adapters/claude-code.d.ts.map +1 -0
- package/dist/enforcement/adapters/claude-code.js +106 -0
- package/dist/enforcement/adapters/claude-code.js.map +1 -0
- package/dist/enforcement/adapters/index.d.ts +2 -0
- package/dist/enforcement/adapters/index.d.ts.map +1 -0
- package/dist/enforcement/adapters/index.js +2 -0
- package/dist/enforcement/adapters/index.js.map +1 -0
- package/dist/enforcement/index.d.ts +4 -0
- package/dist/enforcement/index.d.ts.map +1 -0
- package/dist/enforcement/index.js +3 -0
- package/dist/enforcement/index.js.map +1 -0
- package/dist/enforcement/registry.d.ts +23 -0
- package/dist/enforcement/registry.d.ts.map +1 -0
- package/dist/enforcement/registry.js +63 -0
- package/dist/enforcement/registry.js.map +1 -0
- package/dist/enforcement/types.d.ts +51 -0
- package/dist/enforcement/types.d.ts.map +1 -0
- package/dist/enforcement/types.js +8 -0
- package/dist/enforcement/types.js.map +1 -0
- package/dist/facades/facade-factory.d.ts +10 -3
- package/dist/facades/facade-factory.d.ts.map +1 -1
- package/dist/facades/facade-factory.js +94 -5
- package/dist/facades/facade-factory.js.map +1 -1
- package/dist/facades/types.d.ts +15 -1
- package/dist/facades/types.d.ts.map +1 -1
- package/dist/facades/types.js +6 -0
- package/dist/facades/types.js.map +1 -1
- package/dist/health/health-registry.d.ts +40 -0
- package/dist/health/health-registry.d.ts.map +1 -0
- package/dist/health/health-registry.js +134 -0
- package/dist/health/health-registry.js.map +1 -0
- package/dist/health/index.d.ts +5 -0
- package/dist/health/index.d.ts.map +1 -0
- package/dist/health/index.js +3 -0
- package/dist/health/index.js.map +1 -0
- package/dist/health/vault-integrity.d.ts +13 -0
- package/dist/health/vault-integrity.d.ts.map +1 -0
- package/dist/health/vault-integrity.js +49 -0
- package/dist/health/vault-integrity.js.map +1 -0
- package/dist/index.d.ts +67 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -3
- package/dist/index.js.map +1 -1
- package/dist/intake/intake-pipeline.d.ts +0 -7
- package/dist/intake/intake-pipeline.d.ts.map +1 -1
- package/dist/intake/intake-pipeline.js +1 -1
- package/dist/intake/intake-pipeline.js.map +1 -1
- package/dist/intelligence/types.d.ts +1 -0
- package/dist/intelligence/types.d.ts.map +1 -1
- package/dist/migrations/index.d.ts +6 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +5 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/migration-runner.d.ts +51 -0
- package/dist/migrations/migration-runner.d.ts.map +1 -0
- package/dist/migrations/migration-runner.js +141 -0
- package/dist/migrations/migration-runner.js.map +1 -0
- package/dist/packs/index.d.ts +10 -0
- package/dist/packs/index.d.ts.map +1 -0
- package/dist/packs/index.js +8 -0
- package/dist/packs/index.js.map +1 -0
- package/dist/packs/lockfile.d.ts +97 -0
- package/dist/packs/lockfile.d.ts.map +1 -0
- package/dist/packs/lockfile.js +129 -0
- package/dist/packs/lockfile.js.map +1 -0
- package/dist/packs/pack-installer.d.ts +41 -0
- package/dist/packs/pack-installer.d.ts.map +1 -0
- package/dist/packs/pack-installer.js +253 -0
- package/dist/packs/pack-installer.js.map +1 -0
- package/dist/packs/resolver.d.ts +51 -0
- package/dist/packs/resolver.d.ts.map +1 -0
- package/dist/packs/resolver.js +195 -0
- package/dist/packs/resolver.js.map +1 -0
- package/dist/packs/types.d.ts +186 -0
- package/dist/packs/types.d.ts.map +1 -0
- package/dist/packs/types.js +69 -0
- package/dist/packs/types.js.map +1 -0
- package/dist/persistence/postgres-provider.d.ts +42 -7
- package/dist/persistence/postgres-provider.d.ts.map +1 -1
- package/dist/persistence/postgres-provider.js +187 -46
- package/dist/persistence/postgres-provider.js.map +1 -1
- package/dist/planning/gap-analysis.d.ts.map +1 -1
- package/dist/planning/gap-analysis.js +3 -1
- package/dist/planning/gap-analysis.js.map +1 -1
- package/dist/playbooks/index.d.ts +2 -0
- package/dist/playbooks/index.d.ts.map +1 -1
- package/dist/playbooks/index.js +2 -0
- package/dist/playbooks/index.js.map +1 -1
- package/dist/playbooks/playbook-executor.d.ts +100 -0
- package/dist/playbooks/playbook-executor.d.ts.map +1 -0
- package/dist/playbooks/playbook-executor.js +207 -0
- package/dist/playbooks/playbook-executor.js.map +1 -0
- package/dist/plugins/index.d.ts +7 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +7 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/plugin-loader.d.ts +28 -0
- package/dist/plugins/plugin-loader.d.ts.map +1 -0
- package/dist/plugins/plugin-loader.js +150 -0
- package/dist/plugins/plugin-loader.js.map +1 -0
- package/dist/plugins/plugin-registry.d.ts +58 -0
- package/dist/plugins/plugin-registry.d.ts.map +1 -0
- package/dist/plugins/plugin-registry.js +157 -0
- package/dist/plugins/plugin-registry.js.map +1 -0
- package/dist/plugins/types.d.ts +180 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +48 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/runtime/admin-extra-ops.d.ts.map +1 -1
- package/dist/runtime/admin-extra-ops.js +181 -8
- package/dist/runtime/admin-extra-ops.js.map +1 -1
- package/dist/runtime/capture-ops.d.ts.map +1 -1
- package/dist/runtime/capture-ops.js +106 -7
- package/dist/runtime/capture-ops.js.map +1 -1
- package/dist/runtime/deprecation.d.ts +33 -0
- package/dist/runtime/deprecation.d.ts.map +1 -0
- package/dist/runtime/deprecation.js +41 -0
- package/dist/runtime/deprecation.js.map +1 -0
- package/dist/runtime/facades/admin-facade.d.ts.map +1 -1
- package/dist/runtime/facades/admin-facade.js +12 -1
- package/dist/runtime/facades/admin-facade.js.map +1 -1
- package/dist/runtime/facades/agency-facade.d.ts +7 -0
- package/dist/runtime/facades/agency-facade.d.ts.map +1 -0
- package/dist/runtime/facades/agency-facade.js +103 -0
- package/dist/runtime/facades/agency-facade.js.map +1 -0
- package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
- package/dist/runtime/facades/brain-facade.js +58 -0
- package/dist/runtime/facades/brain-facade.js.map +1 -1
- package/dist/runtime/facades/chat-facade.d.ts +7 -0
- package/dist/runtime/facades/chat-facade.d.ts.map +1 -0
- package/dist/runtime/facades/chat-facade.js +808 -0
- package/dist/runtime/facades/chat-facade.js.map +1 -0
- package/dist/runtime/facades/context-facade.d.ts +7 -0
- package/dist/runtime/facades/context-facade.d.ts.map +1 -0
- package/dist/runtime/facades/context-facade.js +45 -0
- package/dist/runtime/facades/context-facade.js.map +1 -0
- package/dist/runtime/facades/index.d.ts.map +1 -1
- package/dist/runtime/facades/index.js +18 -0
- package/dist/runtime/facades/index.js.map +1 -1
- package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
- package/dist/runtime/facades/vault-facade.js +247 -1
- package/dist/runtime/facades/vault-facade.js.map +1 -1
- package/dist/runtime/feature-flags.d.ts +18 -0
- package/dist/runtime/feature-flags.d.ts.map +1 -0
- package/dist/runtime/feature-flags.js +90 -0
- package/dist/runtime/feature-flags.js.map +1 -0
- package/dist/runtime/pack-ops.d.ts +9 -0
- package/dist/runtime/pack-ops.d.ts.map +1 -0
- package/dist/runtime/pack-ops.js +76 -0
- package/dist/runtime/pack-ops.js.map +1 -0
- package/dist/runtime/playbook-ops.d.ts +3 -7
- package/dist/runtime/playbook-ops.d.ts.map +1 -1
- package/dist/runtime/playbook-ops.js +101 -10
- package/dist/runtime/playbook-ops.js.map +1 -1
- package/dist/runtime/plugin-ops.d.ts +9 -0
- package/dist/runtime/plugin-ops.d.ts.map +1 -0
- package/dist/runtime/plugin-ops.js +235 -0
- package/dist/runtime/plugin-ops.js.map +1 -0
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +72 -5
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/telemetry-ops.d.ts +10 -0
- package/dist/runtime/telemetry-ops.d.ts.map +1 -0
- package/dist/runtime/telemetry-ops.js +53 -0
- package/dist/runtime/telemetry-ops.js.map +1 -0
- package/dist/runtime/types.d.ts +35 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/vault-sharing-ops.d.ts +13 -0
- package/dist/runtime/vault-sharing-ops.d.ts.map +1 -0
- package/dist/runtime/vault-sharing-ops.js +345 -0
- package/dist/runtime/vault-sharing-ops.js.map +1 -0
- package/dist/streams/index.d.ts +1 -1
- package/dist/streams/index.d.ts.map +1 -1
- package/dist/streams/index.js +1 -1
- package/dist/streams/index.js.map +1 -1
- package/dist/streams/replayable-stream.d.ts +13 -1
- package/dist/streams/replayable-stream.d.ts.map +1 -1
- package/dist/streams/replayable-stream.js +27 -3
- package/dist/streams/replayable-stream.js.map +1 -1
- package/dist/text/similarity.d.ts +0 -1
- package/dist/text/similarity.d.ts.map +1 -1
- package/dist/text/similarity.js +1 -1
- package/dist/text/similarity.js.map +1 -1
- package/dist/transport/http-server.d.ts +56 -0
- package/dist/transport/http-server.d.ts.map +1 -0
- package/dist/transport/http-server.js +210 -0
- package/dist/transport/http-server.js.map +1 -0
- package/dist/transport/index.d.ts +11 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +10 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/lsp-server.d.ts +140 -0
- package/dist/transport/lsp-server.d.ts.map +1 -0
- package/dist/transport/lsp-server.js +239 -0
- package/dist/transport/lsp-server.js.map +1 -0
- package/dist/transport/rate-limiter.d.ts +35 -0
- package/dist/transport/rate-limiter.d.ts.map +1 -0
- package/dist/transport/rate-limiter.js +72 -0
- package/dist/transport/rate-limiter.js.map +1 -0
- package/dist/transport/session-manager.d.ts +49 -0
- package/dist/transport/session-manager.d.ts.map +1 -0
- package/dist/transport/session-manager.js +83 -0
- package/dist/transport/session-manager.js.map +1 -0
- package/dist/transport/token-auth.d.ts +29 -0
- package/dist/transport/token-auth.d.ts.map +1 -0
- package/dist/transport/token-auth.js +84 -0
- package/dist/transport/token-auth.js.map +1 -0
- package/dist/transport/types.d.ts +61 -0
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/transport/types.js +5 -0
- package/dist/transport/types.js.map +1 -0
- package/dist/transport/ws-server.d.ts +78 -0
- package/dist/transport/ws-server.d.ts.map +1 -0
- package/dist/transport/ws-server.js +342 -0
- package/dist/transport/ws-server.js.map +1 -0
- package/dist/vault/git-vault-sync.d.ts +107 -0
- package/dist/vault/git-vault-sync.d.ts.map +1 -0
- package/dist/vault/git-vault-sync.js +251 -0
- package/dist/vault/git-vault-sync.js.map +1 -0
- package/dist/vault/knowledge-review.d.ts +67 -0
- package/dist/vault/knowledge-review.d.ts.map +1 -0
- package/dist/vault/knowledge-review.js +133 -0
- package/dist/vault/knowledge-review.js.map +1 -0
- package/dist/vault/obsidian-sync.d.ts +94 -0
- package/dist/vault/obsidian-sync.d.ts.map +1 -0
- package/dist/vault/obsidian-sync.js +247 -0
- package/dist/vault/obsidian-sync.js.map +1 -0
- package/dist/vault/scope-detector.d.ts +31 -0
- package/dist/vault/scope-detector.d.ts.map +1 -0
- package/dist/vault/scope-detector.js +182 -0
- package/dist/vault/scope-detector.js.map +1 -0
- package/dist/vault/vault-branching.d.ts +71 -0
- package/dist/vault/vault-branching.d.ts.map +1 -0
- package/dist/vault/vault-branching.js +180 -0
- package/dist/vault/vault-branching.js.map +1 -0
- package/dist/vault/vault-manager.d.ts +89 -0
- package/dist/vault/vault-manager.d.ts.map +1 -0
- package/dist/vault/vault-manager.js +199 -0
- package/dist/vault/vault-manager.js.map +1 -0
- package/dist/vault/vault-types.d.ts +30 -0
- package/dist/vault/vault-types.d.ts.map +1 -0
- package/dist/vault/vault-types.js +10 -0
- package/dist/vault/vault-types.js.map +1 -0
- package/dist/vault/vault.d.ts +10 -0
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +36 -3
- package/dist/vault/vault.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/admin-extra-ops.test.ts +31 -11
- package/src/__tests__/agency-manager.test.ts +374 -0
- package/src/__tests__/agent-loop.test.ts +256 -0
- package/src/__tests__/capture-ops.test.ts +275 -0
- package/src/__tests__/chat-differentiators.test.ts +251 -0
- package/src/__tests__/chat-enhanced.test.ts +390 -0
- package/src/__tests__/chat-transport.test.ts +665 -0
- package/src/__tests__/claudemd.test.ts +282 -0
- package/src/__tests__/context-engine.test.ts +256 -0
- package/src/__tests__/core-ops.test.ts +97 -5
- package/src/__tests__/deprecation.test.ts +78 -0
- package/src/__tests__/enforcement.test.ts +153 -0
- package/src/__tests__/facade-factory.test.ts +271 -0
- package/src/__tests__/feature-flags.test.ts +138 -0
- package/src/__tests__/git-vault-sync.test.ts +230 -0
- package/src/__tests__/health-registry.test.ts +173 -0
- package/src/__tests__/knowledge-review.test.ts +104 -0
- package/src/__tests__/lsp-transport.test.ts +442 -0
- package/src/__tests__/migration-runner.test.ts +170 -0
- package/src/__tests__/normalize.test.ts +10 -0
- package/src/__tests__/obsidian-sync.test.ts +354 -0
- package/src/__tests__/pack-lockfile.test.ts +261 -0
- package/src/__tests__/pack-ops.test.ts +146 -0
- package/src/__tests__/pack-system.test.ts +423 -0
- package/src/__tests__/playbook-executor.test.ts +249 -0
- package/src/__tests__/playbook-ops-execution.test.ts +189 -0
- package/src/__tests__/plugin-ops.test.ts +411 -0
- package/src/__tests__/plugin-system.test.ts +509 -0
- package/src/__tests__/postgres-provider.test.ts +64 -6
- package/src/__tests__/replayable-stream.test.ts +112 -1
- package/src/__tests__/scope-detector.test.ts +121 -0
- package/src/__tests__/session-lifecycle.test.ts +259 -0
- package/src/__tests__/transport.test.ts +758 -0
- package/src/__tests__/vault-branching.test.ts +274 -0
- package/src/__tests__/vault-connect.test.ts +179 -0
- package/src/__tests__/vault-integrity.test.ts +71 -0
- package/src/__tests__/vault-manager.test.ts +238 -0
- package/src/__tests__/vault-scaling.test.ts +281 -0
- package/src/__tests__/vault-sharing.test.ts +270 -0
- package/src/__tests__/ws-transport.test.ts +479 -0
- package/src/agency/agency-manager.ts +326 -0
- package/src/agency/index.ts +13 -0
- package/src/agency/types.ts +88 -0
- package/src/brain/brain.ts +15 -11
- package/src/brain/intelligence.ts +103 -0
- package/src/brain/types.ts +26 -0
- package/src/chat/agent-loop-types.ts +99 -0
- package/src/chat/agent-loop.ts +357 -0
- package/src/chat/auth-manager.ts +171 -0
- package/src/chat/browser-session.ts +188 -0
- package/src/chat/cancellation.ts +99 -0
- package/src/chat/chat-session.ts +283 -0
- package/src/chat/file-handler.ts +230 -0
- package/src/chat/fragment-buffer.ts +160 -0
- package/src/chat/index.ts +72 -0
- package/src/chat/mcp-bridge.ts +135 -0
- package/src/chat/notifications.ts +164 -0
- package/src/chat/output-compressor.ts +116 -0
- package/src/chat/queue.ts +208 -0
- package/src/chat/response-chunker.ts +200 -0
- package/src/chat/self-update.ts +117 -0
- package/src/chat/types.ts +126 -0
- package/src/chat/voice.ts +134 -0
- package/src/claudemd/compose.ts +142 -0
- package/src/claudemd/index.ts +17 -0
- package/src/claudemd/inject.ts +170 -0
- package/src/claudemd/types.ts +45 -0
- package/src/context/context-engine.ts +302 -0
- package/src/context/index.ts +11 -0
- package/src/context/types.ts +69 -0
- package/src/enforcement/adapters/claude-code.ts +135 -0
- package/src/enforcement/adapters/index.ts +1 -0
- package/src/enforcement/index.ts +10 -0
- package/src/enforcement/registry.ts +82 -0
- package/src/enforcement/types.ts +56 -0
- package/src/facades/facade-factory.ts +138 -5
- package/src/facades/types.ts +21 -0
- package/src/health/health-registry.ts +165 -0
- package/src/health/index.ts +11 -0
- package/src/health/vault-integrity.ts +66 -0
- package/src/index.ts +294 -2
- package/src/intake/intake-pipeline.ts +1 -1
- package/src/intelligence/types.ts +1 -0
- package/src/migrations/index.ts +6 -0
- package/src/migrations/migration-runner.ts +185 -0
- package/src/packs/index.ts +20 -0
- package/src/packs/lockfile.ts +180 -0
- package/src/packs/pack-installer.ts +289 -0
- package/src/packs/resolver.ts +237 -0
- package/src/packs/types.ts +125 -0
- package/src/persistence/postgres-provider.ts +211 -58
- package/src/planning/gap-analysis.ts +52 -7
- package/src/playbooks/index.ts +11 -0
- package/src/playbooks/playbook-executor.ts +301 -0
- package/src/plugins/index.ts +19 -0
- package/src/plugins/plugin-loader.ts +183 -0
- package/src/plugins/plugin-registry.ts +187 -0
- package/src/plugins/types.ts +119 -0
- package/src/runtime/admin-extra-ops.ts +193 -8
- package/src/runtime/capture-ops.ts +113 -8
- package/src/runtime/deprecation.ts +58 -0
- package/src/runtime/facades/admin-facade.ts +16 -1
- package/src/runtime/facades/agency-facade.ts +111 -0
- package/src/runtime/facades/brain-facade.ts +60 -0
- package/src/runtime/facades/chat-facade.ts +918 -0
- package/src/runtime/facades/context-facade.ts +55 -0
- package/src/runtime/facades/index.ts +22 -1
- package/src/runtime/facades/vault-facade.ts +261 -1
- package/src/runtime/feature-flags.ts +101 -0
- package/src/runtime/pack-ops.ts +85 -0
- package/src/runtime/playbook-ops.ts +113 -9
- package/src/runtime/plugin-ops.ts +258 -0
- package/src/runtime/runtime.ts +84 -5
- package/src/runtime/telemetry-ops.ts +57 -0
- package/src/runtime/types.ts +35 -0
- package/src/runtime/vault-sharing-ops.ts +372 -0
- package/src/streams/index.ts +1 -1
- package/src/streams/replayable-stream.ts +34 -3
- package/src/text/similarity.ts +1 -1
- package/src/transport/http-server.ts +269 -0
- package/src/transport/index.ts +48 -0
- package/src/transport/lsp-server.ts +401 -0
- package/src/transport/rate-limiter.ts +97 -0
- package/src/transport/session-manager.ts +120 -0
- package/src/transport/token-auth.ts +96 -0
- package/src/transport/types.ts +66 -0
- package/src/transport/ws-server.ts +415 -0
- package/src/vault/git-vault-sync.ts +318 -0
- package/src/vault/knowledge-review.ts +221 -0
- package/src/vault/obsidian-sync.ts +346 -0
- package/src/vault/scope-detector.ts +219 -0
- package/src/vault/vault-branching.ts +264 -0
- package/src/vault/vault-manager.ts +237 -0
- package/src/vault/vault-types.ts +50 -0
- package/src/vault/vault.ts +41 -3
- package/src/governance/index.ts +0 -18
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deprecation utility tests.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, test, expect, beforeEach, vi } from 'vitest';
|
|
6
|
+
import {
|
|
7
|
+
deprecationWarning,
|
|
8
|
+
wrapDeprecated,
|
|
9
|
+
resetDeprecationWarnings,
|
|
10
|
+
} from '../runtime/deprecation.js';
|
|
11
|
+
|
|
12
|
+
describe('deprecation utilities', () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
resetDeprecationWarnings();
|
|
15
|
+
vi.restoreAllMocks();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('logs deprecation warning to console.warn', () => {
|
|
19
|
+
const spy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
20
|
+
deprecationWarning({ name: 'old_op', since: '2.5.0' });
|
|
21
|
+
expect(spy).toHaveBeenCalledOnce();
|
|
22
|
+
expect(spy.mock.calls[0][0]).toContain('old_op');
|
|
23
|
+
expect(spy.mock.calls[0][0]).toContain('deprecated since v2.5.0');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('includes replacement in warning', () => {
|
|
27
|
+
const spy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
28
|
+
deprecationWarning({ name: 'old_op', since: '2.5.0', replacement: 'new_op' });
|
|
29
|
+
expect(spy.mock.calls[0][0]).toContain('new_op');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('includes removeIn in warning', () => {
|
|
33
|
+
const spy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
34
|
+
deprecationWarning({ name: 'old_op', since: '2.5.0', removeIn: '3.0.0' });
|
|
35
|
+
expect(spy.mock.calls[0][0]).toContain('v3.0.0');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('warns only once per op', () => {
|
|
39
|
+
const spy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
40
|
+
deprecationWarning({ name: 'old_op', since: '2.5.0' });
|
|
41
|
+
deprecationWarning({ name: 'old_op', since: '2.5.0' });
|
|
42
|
+
deprecationWarning({ name: 'old_op', since: '2.5.0' });
|
|
43
|
+
expect(spy).toHaveBeenCalledOnce();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('warns separately for different ops', () => {
|
|
47
|
+
const spy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
48
|
+
deprecationWarning({ name: 'op_a', since: '2.5.0' });
|
|
49
|
+
deprecationWarning({ name: 'op_b', since: '2.5.0' });
|
|
50
|
+
expect(spy).toHaveBeenCalledTimes(2);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('resetDeprecationWarnings clears warned set', () => {
|
|
54
|
+
const spy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
55
|
+
deprecationWarning({ name: 'old_op', since: '2.5.0' });
|
|
56
|
+
resetDeprecationWarnings();
|
|
57
|
+
deprecationWarning({ name: 'old_op', since: '2.5.0' });
|
|
58
|
+
expect(spy).toHaveBeenCalledTimes(2);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('wrapDeprecated calls original function and warns', () => {
|
|
62
|
+
const spy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
63
|
+
const original = (x: number) => x * 2;
|
|
64
|
+
const wrapped = wrapDeprecated(original, { name: 'double', since: '2.5.0' });
|
|
65
|
+
const result = wrapped(5);
|
|
66
|
+
expect(result).toBe(10);
|
|
67
|
+
expect(spy).toHaveBeenCalledOnce();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('wrapDeprecated warns only once across calls', () => {
|
|
71
|
+
const spy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
72
|
+
const wrapped = wrapDeprecated((x: number) => x, { name: 'identity', since: '2.5.0' });
|
|
73
|
+
wrapped(1);
|
|
74
|
+
wrapped(2);
|
|
75
|
+
wrapped(3);
|
|
76
|
+
expect(spy).toHaveBeenCalledOnce();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { EnforcementRegistry } from '../enforcement/registry.js';
|
|
3
|
+
import { ClaudeCodeAdapter } from '../enforcement/adapters/claude-code.js';
|
|
4
|
+
import type { EnforcementRule } from '../enforcement/types.js';
|
|
5
|
+
|
|
6
|
+
const makeRule = (overrides: Partial<EnforcementRule> = {}): EnforcementRule => ({
|
|
7
|
+
id: 'test-rule',
|
|
8
|
+
description: 'Test rule',
|
|
9
|
+
trigger: 'pre-tool-use',
|
|
10
|
+
action: 'block',
|
|
11
|
+
message: 'This is blocked',
|
|
12
|
+
...overrides,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe('EnforcementRegistry', () => {
|
|
16
|
+
it('adds and retrieves rules', () => {
|
|
17
|
+
const reg = new EnforcementRegistry();
|
|
18
|
+
reg.addRule(makeRule({ id: 'r1' }));
|
|
19
|
+
reg.addRule(makeRule({ id: 'r2' }));
|
|
20
|
+
expect(reg.getRules()).toHaveLength(2);
|
|
21
|
+
expect(reg.getRule('r1')?.id).toBe('r1');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('replaces rules with same ID', () => {
|
|
25
|
+
const reg = new EnforcementRegistry();
|
|
26
|
+
reg.addRule(makeRule({ id: 'r1', message: 'old' }));
|
|
27
|
+
reg.addRule(makeRule({ id: 'r1', message: 'new' }));
|
|
28
|
+
expect(reg.getRules()).toHaveLength(1);
|
|
29
|
+
expect(reg.getRule('r1')?.message).toBe('new');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('removes rules by ID', () => {
|
|
33
|
+
const reg = new EnforcementRegistry();
|
|
34
|
+
reg.addRule(makeRule({ id: 'r1' }));
|
|
35
|
+
expect(reg.removeRule('r1')).toBe(true);
|
|
36
|
+
expect(reg.removeRule('r1')).toBe(false);
|
|
37
|
+
expect(reg.getRules()).toHaveLength(0);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('filters disabled rules', () => {
|
|
41
|
+
const reg = new EnforcementRegistry();
|
|
42
|
+
reg.addRule(makeRule({ id: 'active' }));
|
|
43
|
+
reg.addRule(makeRule({ id: 'disabled', enabled: false }));
|
|
44
|
+
expect(reg.getEnabledRules()).toHaveLength(1);
|
|
45
|
+
expect(reg.getEnabledRules()[0].id).toBe('active');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('addRules adds multiple', () => {
|
|
49
|
+
const reg = new EnforcementRegistry();
|
|
50
|
+
reg.addRules([makeRule({ id: 'a' }), makeRule({ id: 'b' }), makeRule({ id: 'c' })]);
|
|
51
|
+
expect(reg.getRules()).toHaveLength(3);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('registers and lists adapters', () => {
|
|
55
|
+
const reg = new EnforcementRegistry();
|
|
56
|
+
reg.registerAdapter(new ClaudeCodeAdapter());
|
|
57
|
+
expect(reg.listAdapters()).toEqual(['claude-code']);
|
|
58
|
+
expect(reg.getAdapter('claude-code')).toBeDefined();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('translate returns skipped when no adapter', () => {
|
|
62
|
+
const reg = new EnforcementRegistry();
|
|
63
|
+
reg.addRule(makeRule({ id: 'r1' }));
|
|
64
|
+
const result = reg.translate('unknown-host');
|
|
65
|
+
expect(result.host).toBe('unknown-host');
|
|
66
|
+
expect(result.files).toHaveLength(0);
|
|
67
|
+
expect(result.skipped).toHaveLength(1);
|
|
68
|
+
expect(result.skipped[0].ruleId).toBe('r1');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('translateAll translates for all adapters', () => {
|
|
72
|
+
const reg = new EnforcementRegistry();
|
|
73
|
+
reg.addRule(makeRule());
|
|
74
|
+
reg.registerAdapter(new ClaudeCodeAdapter());
|
|
75
|
+
const results = reg.translateAll();
|
|
76
|
+
expect(results).toHaveLength(1);
|
|
77
|
+
expect(results[0].host).toBe('claude-code');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('ClaudeCodeAdapter', () => {
|
|
82
|
+
const adapter = new ClaudeCodeAdapter();
|
|
83
|
+
|
|
84
|
+
it('supports expected triggers', () => {
|
|
85
|
+
expect(adapter.supports('pre-tool-use')).toBe(true);
|
|
86
|
+
expect(adapter.supports('post-tool-use')).toBe(true);
|
|
87
|
+
expect(adapter.supports('pre-compact')).toBe(true);
|
|
88
|
+
expect(adapter.supports('session-start')).toBe(true);
|
|
89
|
+
expect(adapter.supports('pre-commit')).toBe(true);
|
|
90
|
+
expect(adapter.supports('on-save')).toBe(false);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('translates pre-tool-use with pattern to settings.json hook', () => {
|
|
94
|
+
const result = adapter.translate({
|
|
95
|
+
rules: [makeRule({ id: 'no-console', pattern: 'console\\.log', trigger: 'pre-tool-use' })],
|
|
96
|
+
});
|
|
97
|
+
expect(result.files.length).toBeGreaterThan(0);
|
|
98
|
+
const settingsFile = result.files.find((f) => f.path.includes('settings.json'));
|
|
99
|
+
expect(settingsFile).toBeDefined();
|
|
100
|
+
const parsed = JSON.parse(settingsFile!.content);
|
|
101
|
+
expect(parsed.hooks).toHaveLength(1);
|
|
102
|
+
expect(parsed.hooks[0].event).toBe('PreToolUse');
|
|
103
|
+
expect(parsed.hooks[0].command).toContain('console\\.log');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('translates pre-commit to hookify file', () => {
|
|
107
|
+
const result = adapter.translate({
|
|
108
|
+
rules: [makeRule({ id: 'no-debug', trigger: 'pre-commit', pattern: 'debugger' })],
|
|
109
|
+
});
|
|
110
|
+
const hookFile = result.files.find((f) => f.path.includes('hookify.no-debug'));
|
|
111
|
+
expect(hookFile).toBeDefined();
|
|
112
|
+
expect(hookFile!.content).toContain('name: no-debug');
|
|
113
|
+
expect(hookFile!.content).toContain('debugger');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('skips unsupported triggers', () => {
|
|
117
|
+
const result = adapter.translate({
|
|
118
|
+
rules: [makeRule({ id: 'on-save-rule', trigger: 'on-save' })],
|
|
119
|
+
});
|
|
120
|
+
expect(result.skipped).toHaveLength(1);
|
|
121
|
+
expect(result.skipped[0].ruleId).toBe('on-save-rule');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('generates block command with exit 1', () => {
|
|
125
|
+
const result = adapter.translate({
|
|
126
|
+
rules: [makeRule({ id: 'blocker', action: 'block', pattern: 'bad-thing' })],
|
|
127
|
+
});
|
|
128
|
+
const settings = result.files.find((f) => f.path.includes('settings.json'));
|
|
129
|
+
const parsed = JSON.parse(settings!.content);
|
|
130
|
+
expect(parsed.hooks[0].command).toContain('exit 1');
|
|
131
|
+
expect(parsed.hooks[0].command).toContain('BLOCKED');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('generates warn command without exit 1', () => {
|
|
135
|
+
const result = adapter.translate({
|
|
136
|
+
rules: [makeRule({ id: 'warner', action: 'warn', pattern: 'maybe-bad' })],
|
|
137
|
+
});
|
|
138
|
+
const settings = result.files.find((f) => f.path.includes('settings.json'));
|
|
139
|
+
const parsed = JSON.parse(settings!.content);
|
|
140
|
+
expect(parsed.hooks[0].command).toContain('WARNING');
|
|
141
|
+
expect(parsed.hooks[0].command).not.toContain('exit 1');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('handles rules without patterns', () => {
|
|
145
|
+
const result = adapter.translate({
|
|
146
|
+
rules: [makeRule({ id: 'simple', trigger: 'session-start' })],
|
|
147
|
+
});
|
|
148
|
+
const settings = result.files.find((f) => f.path.includes('settings.json'));
|
|
149
|
+
const parsed = JSON.parse(settings!.content);
|
|
150
|
+
expect(parsed.hooks[0].event).toBe('SessionStart');
|
|
151
|
+
expect(parsed.hooks[0].command).toContain('simple');
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import type { FacadeConfig, AuthPolicy } from '../facades/types.js';
|
|
4
|
+
|
|
5
|
+
import { registerFacade, registerAllFacades } from '../facades/facade-factory.js';
|
|
6
|
+
|
|
7
|
+
function createTestFacade(): FacadeConfig {
|
|
8
|
+
return {
|
|
9
|
+
name: 'test_facade',
|
|
10
|
+
description: 'Test facade',
|
|
11
|
+
ops: [
|
|
12
|
+
{
|
|
13
|
+
name: 'read_op',
|
|
14
|
+
description: 'A read operation',
|
|
15
|
+
auth: 'read',
|
|
16
|
+
handler: async () => ({ status: 'ok' }),
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: 'write_op',
|
|
20
|
+
description: 'A write operation',
|
|
21
|
+
auth: 'write',
|
|
22
|
+
handler: async () => ({ written: true }),
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'admin_op',
|
|
26
|
+
description: 'An admin operation',
|
|
27
|
+
auth: 'admin',
|
|
28
|
+
handler: async () => ({ admin: true }),
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Capture the handler registered with McpServer
|
|
35
|
+
function captureHandler(
|
|
36
|
+
facade: FacadeConfig,
|
|
37
|
+
authPolicy?: () => AuthPolicy,
|
|
38
|
+
): (args: { op: string; params: Record<string, unknown> }) => Promise<{
|
|
39
|
+
content: Array<{ type: string; text: string }>;
|
|
40
|
+
}> {
|
|
41
|
+
let captured:
|
|
42
|
+
| ((args: { op: string; params: Record<string, unknown> }) => Promise<{
|
|
43
|
+
content: Array<{ type: string; text: string }>;
|
|
44
|
+
}>)
|
|
45
|
+
| null = null;
|
|
46
|
+
const mockServer = {
|
|
47
|
+
tool: (_name: string, _desc: string, _schema: unknown, handler: unknown) => {
|
|
48
|
+
captured = handler as typeof captured;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
registerFacade(mockServer as never, facade, authPolicy);
|
|
52
|
+
return captured!;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function callOp(
|
|
56
|
+
handler: ReturnType<typeof captureHandler>,
|
|
57
|
+
op: string,
|
|
58
|
+
): Promise<{ success: boolean; error?: string; data?: unknown }> {
|
|
59
|
+
const result = await handler({ op, params: {} });
|
|
60
|
+
return JSON.parse(result.content[0].text);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
describe('facade-factory auth enforcement', () => {
|
|
64
|
+
it('permissive mode allows all ops regardless of caller level', async () => {
|
|
65
|
+
const handler = captureHandler(createTestFacade(), () => ({
|
|
66
|
+
mode: 'permissive',
|
|
67
|
+
callerLevel: 'read',
|
|
68
|
+
}));
|
|
69
|
+
|
|
70
|
+
const read = await callOp(handler, 'read_op');
|
|
71
|
+
const write = await callOp(handler, 'write_op');
|
|
72
|
+
const admin = await callOp(handler, 'admin_op');
|
|
73
|
+
|
|
74
|
+
expect(read.success).toBe(true);
|
|
75
|
+
expect(write.success).toBe(true);
|
|
76
|
+
expect(admin.success).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('enforce mode blocks ops above caller level', async () => {
|
|
80
|
+
const handler = captureHandler(createTestFacade(), () => ({
|
|
81
|
+
mode: 'enforce',
|
|
82
|
+
callerLevel: 'read',
|
|
83
|
+
}));
|
|
84
|
+
|
|
85
|
+
const read = await callOp(handler, 'read_op');
|
|
86
|
+
const write = await callOp(handler, 'write_op');
|
|
87
|
+
const admin = await callOp(handler, 'admin_op');
|
|
88
|
+
|
|
89
|
+
expect(read.success).toBe(true);
|
|
90
|
+
expect(write.success).toBe(false);
|
|
91
|
+
expect(write.error).toContain('requires write');
|
|
92
|
+
expect(admin.success).toBe(false);
|
|
93
|
+
expect(admin.error).toContain('requires admin');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('enforce mode allows write caller to execute read and write ops', async () => {
|
|
97
|
+
const handler = captureHandler(createTestFacade(), () => ({
|
|
98
|
+
mode: 'enforce',
|
|
99
|
+
callerLevel: 'write',
|
|
100
|
+
}));
|
|
101
|
+
|
|
102
|
+
const read = await callOp(handler, 'read_op');
|
|
103
|
+
const write = await callOp(handler, 'write_op');
|
|
104
|
+
const admin = await callOp(handler, 'admin_op');
|
|
105
|
+
|
|
106
|
+
expect(read.success).toBe(true);
|
|
107
|
+
expect(write.success).toBe(true);
|
|
108
|
+
expect(admin.success).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('enforce mode allows admin caller to execute all ops', async () => {
|
|
112
|
+
const handler = captureHandler(createTestFacade(), () => ({
|
|
113
|
+
mode: 'enforce',
|
|
114
|
+
callerLevel: 'admin',
|
|
115
|
+
}));
|
|
116
|
+
|
|
117
|
+
expect((await callOp(handler, 'read_op')).success).toBe(true);
|
|
118
|
+
expect((await callOp(handler, 'write_op')).success).toBe(true);
|
|
119
|
+
expect((await callOp(handler, 'admin_op')).success).toBe(true);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('warn mode allows ops but logs warning', async () => {
|
|
123
|
+
const handler = captureHandler(createTestFacade(), () => ({
|
|
124
|
+
mode: 'warn',
|
|
125
|
+
callerLevel: 'read',
|
|
126
|
+
}));
|
|
127
|
+
|
|
128
|
+
// Warn mode allows execution even for higher auth levels
|
|
129
|
+
const write = await callOp(handler, 'write_op');
|
|
130
|
+
expect(write.success).toBe(true);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('no auth policy defaults to permissive', async () => {
|
|
134
|
+
const handler = captureHandler(createTestFacade());
|
|
135
|
+
|
|
136
|
+
const admin = await callOp(handler, 'admin_op');
|
|
137
|
+
expect(admin.success).toBe(true);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('per-op overrides take precedence', async () => {
|
|
141
|
+
const handler = captureHandler(createTestFacade(), () => ({
|
|
142
|
+
mode: 'enforce',
|
|
143
|
+
callerLevel: 'write',
|
|
144
|
+
overrides: { read_op: 'admin' }, // escalate read_op to admin
|
|
145
|
+
}));
|
|
146
|
+
|
|
147
|
+
// read_op normally requires 'read' but override says 'admin'
|
|
148
|
+
const read = await callOp(handler, 'read_op');
|
|
149
|
+
expect(read.success).toBe(false);
|
|
150
|
+
expect(read.error).toContain('requires admin');
|
|
151
|
+
|
|
152
|
+
// write_op still works at write level
|
|
153
|
+
const write = await callOp(handler, 'write_op');
|
|
154
|
+
expect(write.success).toBe(true);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('auth policy getter is called per dispatch (mutable)', async () => {
|
|
158
|
+
let mode: AuthPolicy['mode'] = 'permissive';
|
|
159
|
+
const handler = captureHandler(createTestFacade(), () => ({
|
|
160
|
+
mode,
|
|
161
|
+
callerLevel: 'read',
|
|
162
|
+
}));
|
|
163
|
+
|
|
164
|
+
// Permissive — write op works
|
|
165
|
+
expect((await callOp(handler, 'write_op')).success).toBe(true);
|
|
166
|
+
|
|
167
|
+
// Switch to enforce at runtime
|
|
168
|
+
mode = 'enforce';
|
|
169
|
+
expect((await callOp(handler, 'write_op')).success).toBe(false);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('hot ops promotion', () => {
|
|
174
|
+
function createFacadeWithSchema(): FacadeConfig {
|
|
175
|
+
return {
|
|
176
|
+
name: 'test_facade',
|
|
177
|
+
description: 'Test facade',
|
|
178
|
+
ops: [
|
|
179
|
+
{
|
|
180
|
+
name: 'search',
|
|
181
|
+
description: 'Search knowledge',
|
|
182
|
+
auth: 'read',
|
|
183
|
+
hot: true,
|
|
184
|
+
schema: z.object({ query: z.string(), limit: z.number().optional() }),
|
|
185
|
+
handler: async (params) => ({ results: [], query: params.query }),
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: 'delete',
|
|
189
|
+
description: 'Delete entry',
|
|
190
|
+
auth: 'admin',
|
|
191
|
+
handler: async () => ({ deleted: true }),
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
it('registers hot ops as standalone MCP tools', () => {
|
|
198
|
+
const registered: Array<{ name: string; description: string }> = [];
|
|
199
|
+
const mockServer = {
|
|
200
|
+
tool: (name: string, desc: string, _schema: unknown, _handler: unknown) => {
|
|
201
|
+
registered.push({ name, description: desc });
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
registerAllFacades(mockServer as never, [createFacadeWithSchema()], {
|
|
206
|
+
agentId: 'myagent',
|
|
207
|
+
hotOps: ['search'],
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const names = registered.map((r) => r.name);
|
|
211
|
+
// Facade is registered
|
|
212
|
+
expect(names).toContain('test_facade');
|
|
213
|
+
// Hot op is promoted to standalone tool
|
|
214
|
+
expect(names).toContain('myagent_search');
|
|
215
|
+
// Non-hot op is NOT promoted
|
|
216
|
+
expect(names).not.toContain('myagent_delete');
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('hot flag on op definition also triggers promotion', () => {
|
|
220
|
+
const registered: string[] = [];
|
|
221
|
+
const mockServer = {
|
|
222
|
+
tool: (name: string) => {
|
|
223
|
+
registered.push(name);
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
registerAllFacades(mockServer as never, [createFacadeWithSchema()], {
|
|
228
|
+
agentId: 'myagent',
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// op.hot = true on 'search' should promote it even without hotOps list
|
|
232
|
+
expect(registered).toContain('myagent_search');
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('hot ops execute correctly with full schema validation', async () => {
|
|
236
|
+
let capturedHandler: ((params: unknown) => Promise<unknown>) | null = null;
|
|
237
|
+
const mockServer = {
|
|
238
|
+
tool: (name: string, _desc: string, _schema: unknown, handler: unknown) => {
|
|
239
|
+
if (name === 'myagent_search') {
|
|
240
|
+
capturedHandler = handler as typeof capturedHandler;
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
registerAllFacades(mockServer as never, [createFacadeWithSchema()], {
|
|
246
|
+
agentId: 'myagent',
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
expect(capturedHandler).not.toBeNull();
|
|
250
|
+
const result = (await capturedHandler!({ query: 'test', limit: 5 })) as {
|
|
251
|
+
content: Array<{ text: string }>;
|
|
252
|
+
};
|
|
253
|
+
const parsed = JSON.parse(result.content[0].text);
|
|
254
|
+
expect(parsed.success).toBe(true);
|
|
255
|
+
expect(parsed.data.query).toBe('test');
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('no agentId means no hot ops promoted', () => {
|
|
259
|
+
const registered: string[] = [];
|
|
260
|
+
const mockServer = {
|
|
261
|
+
tool: (name: string) => {
|
|
262
|
+
registered.push(name);
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
registerAllFacades(mockServer as never, [createFacadeWithSchema()]);
|
|
267
|
+
|
|
268
|
+
// Only facade, no standalone tools
|
|
269
|
+
expect(registered).toEqual(['test_facade']);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { FeatureFlags } from '../runtime/feature-flags.js';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { mkdtempSync, rmSync, readFileSync } from 'node:fs';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
|
|
7
|
+
describe('FeatureFlags', () => {
|
|
8
|
+
let tempDir: string;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
tempDir = mkdtempSync(join(tmpdir(), 'soleri-flags-'));
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
16
|
+
// Clean up env vars
|
|
17
|
+
for (const key of Object.keys(process.env)) {
|
|
18
|
+
if (key.startsWith('SOLERI_FLAG_')) {
|
|
19
|
+
delete process.env[key];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('initializes with built-in defaults', () => {
|
|
25
|
+
const flags = new FeatureFlags();
|
|
26
|
+
expect(flags.isEnabled('auth-enforcement')).toBe(false);
|
|
27
|
+
expect(flags.isEnabled('hot-reload')).toBe(true);
|
|
28
|
+
expect(flags.isEnabled('search-feedback')).toBe(true);
|
|
29
|
+
expect(flags.isEnabled('telemetry')).toBe(true);
|
|
30
|
+
expect(flags.isEnabled('agency-mode')).toBe(false);
|
|
31
|
+
expect(flags.isEnabled('cognee-sync')).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('returns false for unknown flags', () => {
|
|
35
|
+
const flags = new FeatureFlags();
|
|
36
|
+
expect(flags.isEnabled('nonexistent-flag')).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('set() changes flag value and persists to file', () => {
|
|
40
|
+
const filePath = join(tempDir, 'flags.json');
|
|
41
|
+
const flags = new FeatureFlags(filePath);
|
|
42
|
+
|
|
43
|
+
flags.set('auth-enforcement', true);
|
|
44
|
+
expect(flags.isEnabled('auth-enforcement')).toBe(true);
|
|
45
|
+
|
|
46
|
+
// Verify persisted
|
|
47
|
+
const data = JSON.parse(readFileSync(filePath, 'utf-8'));
|
|
48
|
+
expect(data['auth-enforcement']).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('loads flags from file on construction', () => {
|
|
52
|
+
const filePath = join(tempDir, 'flags.json');
|
|
53
|
+
|
|
54
|
+
// First instance sets a flag
|
|
55
|
+
const flags1 = new FeatureFlags(filePath);
|
|
56
|
+
flags1.set('auth-enforcement', true);
|
|
57
|
+
flags1.set('telemetry', false);
|
|
58
|
+
|
|
59
|
+
// Second instance loads from file
|
|
60
|
+
const flags2 = new FeatureFlags(filePath);
|
|
61
|
+
expect(flags2.isEnabled('auth-enforcement')).toBe(true);
|
|
62
|
+
expect(flags2.isEnabled('telemetry')).toBe(false);
|
|
63
|
+
// Unchanged defaults still work
|
|
64
|
+
expect(flags2.isEnabled('hot-reload')).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('env vars override file and defaults', () => {
|
|
68
|
+
const filePath = join(tempDir, 'flags.json');
|
|
69
|
+
const flags1 = new FeatureFlags(filePath);
|
|
70
|
+
flags1.set('telemetry', true); // file says true
|
|
71
|
+
|
|
72
|
+
process.env.SOLERI_FLAG_TELEMETRY = 'false';
|
|
73
|
+
const flags2 = new FeatureFlags(filePath);
|
|
74
|
+
expect(flags2.isEnabled('telemetry')).toBe(false); // env wins
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('env var format: SOLERI_FLAG_AUTH_ENFORCEMENT=1', () => {
|
|
78
|
+
process.env.SOLERI_FLAG_AUTH_ENFORCEMENT = '1';
|
|
79
|
+
const flags = new FeatureFlags();
|
|
80
|
+
expect(flags.isEnabled('auth-enforcement')).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('env var custom flags work', () => {
|
|
84
|
+
process.env.SOLERI_FLAG_MY_CUSTOM = 'true';
|
|
85
|
+
const flags = new FeatureFlags();
|
|
86
|
+
expect(flags.isEnabled('my-custom')).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('getAll() returns all flags with metadata', () => {
|
|
90
|
+
const flags = new FeatureFlags();
|
|
91
|
+
const all = flags.getAll();
|
|
92
|
+
|
|
93
|
+
expect(all['auth-enforcement']).toEqual({
|
|
94
|
+
enabled: false,
|
|
95
|
+
description: 'Enforce auth levels in facade dispatch',
|
|
96
|
+
source: 'default',
|
|
97
|
+
});
|
|
98
|
+
expect(all['hot-reload']).toEqual({
|
|
99
|
+
enabled: true,
|
|
100
|
+
description: 'Enable hot reload of vault and config',
|
|
101
|
+
source: 'default',
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('getAll() reports env source when env var is set', () => {
|
|
106
|
+
process.env.SOLERI_FLAG_TELEMETRY = 'true';
|
|
107
|
+
const flags = new FeatureFlags();
|
|
108
|
+
const all = flags.getAll();
|
|
109
|
+
expect(all['telemetry'].source).toBe('env');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('set() creates custom flags not in built-in list', () => {
|
|
113
|
+
const flags = new FeatureFlags();
|
|
114
|
+
flags.set('experimental-feature', true);
|
|
115
|
+
expect(flags.isEnabled('experimental-feature')).toBe(true);
|
|
116
|
+
|
|
117
|
+
const all = flags.getAll();
|
|
118
|
+
expect(all['experimental-feature'].description).toBe('Custom flag');
|
|
119
|
+
expect(all['experimental-feature'].source).toBe('runtime');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('handles corrupt flags file gracefully', () => {
|
|
123
|
+
const filePath = join(tempDir, 'flags.json');
|
|
124
|
+
const { writeFileSync } = require('node:fs');
|
|
125
|
+
writeFileSync(filePath, 'not json!!!');
|
|
126
|
+
|
|
127
|
+
// Should not throw — falls back to defaults
|
|
128
|
+
const flags = new FeatureFlags(filePath);
|
|
129
|
+
expect(flags.isEnabled('hot-reload')).toBe(true);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('no file path means in-memory only (no persistence)', () => {
|
|
133
|
+
const flags = new FeatureFlags();
|
|
134
|
+
flags.set('auth-enforcement', true);
|
|
135
|
+
expect(flags.isEnabled('auth-enforcement')).toBe(true);
|
|
136
|
+
// No crash, just works in-memory
|
|
137
|
+
});
|
|
138
|
+
});
|