@soleri/core 9.0.3 → 9.2.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/brain/intelligence.d.ts +27 -0
- package/dist/brain/intelligence.d.ts.map +1 -1
- package/dist/brain/intelligence.js +160 -14
- package/dist/brain/intelligence.js.map +1 -1
- package/dist/brain/learning-radar.d.ts +4 -0
- package/dist/brain/learning-radar.d.ts.map +1 -1
- package/dist/brain/learning-radar.js +20 -1
- package/dist/brain/learning-radar.js.map +1 -1
- package/dist/brain/strength-scorer.d.ts +31 -0
- package/dist/brain/strength-scorer.d.ts.map +1 -0
- package/dist/brain/strength-scorer.js +264 -0
- package/dist/brain/strength-scorer.js.map +1 -0
- package/dist/chat/agent-loop.d.ts.map +1 -1
- package/dist/chat/agent-loop.js +2 -0
- package/dist/chat/agent-loop.js.map +1 -1
- package/dist/chat/notifications.d.ts.map +1 -1
- package/dist/chat/notifications.js +2 -0
- package/dist/chat/notifications.js.map +1 -1
- package/dist/claudemd/compose.js +1 -1
- package/dist/claudemd/compose.js.map +1 -1
- package/dist/control/intent-router.d.ts.map +1 -1
- package/dist/control/intent-router.js +12 -4
- package/dist/control/intent-router.js.map +1 -1
- package/dist/curator/contradiction-detector.d.ts +27 -0
- package/dist/curator/contradiction-detector.d.ts.map +1 -0
- package/dist/curator/contradiction-detector.js +62 -0
- package/dist/curator/contradiction-detector.js.map +1 -0
- package/dist/curator/curator.d.ts +3 -4
- package/dist/curator/curator.d.ts.map +1 -1
- package/dist/curator/curator.js +90 -525
- package/dist/curator/curator.js.map +1 -1
- package/dist/curator/duplicate-detector.d.ts +14 -0
- package/dist/curator/duplicate-detector.d.ts.map +1 -0
- package/dist/curator/duplicate-detector.js +77 -0
- package/dist/curator/duplicate-detector.js.map +1 -0
- package/dist/curator/health-audit.d.ts +15 -0
- package/dist/curator/health-audit.d.ts.map +1 -0
- package/dist/curator/health-audit.js +97 -0
- package/dist/curator/health-audit.js.map +1 -0
- package/dist/curator/metadata-enricher.d.ts +17 -0
- package/dist/curator/metadata-enricher.d.ts.map +1 -0
- package/dist/curator/metadata-enricher.js +60 -0
- package/dist/curator/metadata-enricher.js.map +1 -0
- package/dist/curator/schema.d.ts +7 -0
- package/dist/curator/schema.d.ts.map +1 -0
- package/dist/curator/schema.js +62 -0
- package/dist/curator/schema.js.map +1 -0
- package/dist/curator/tag-manager.d.ts +36 -0
- package/dist/curator/tag-manager.d.ts.map +1 -0
- package/dist/curator/tag-manager.js +78 -0
- package/dist/curator/tag-manager.js.map +1 -0
- package/dist/engine/bin/soleri-engine.js +55 -3
- package/dist/engine/bin/soleri-engine.js.map +1 -1
- package/dist/engine/core-ops.d.ts.map +1 -1
- package/dist/engine/core-ops.js +33 -10
- package/dist/engine/core-ops.js.map +1 -1
- package/dist/engine/module-manifest.d.ts.map +1 -1
- package/dist/engine/module-manifest.js +22 -2
- package/dist/engine/module-manifest.js.map +1 -1
- package/dist/engine/register-engine.d.ts.map +1 -1
- package/dist/engine/register-engine.js +26 -2
- package/dist/engine/register-engine.js.map +1 -1
- package/dist/errors/retry.d.ts.map +1 -1
- package/dist/errors/retry.js +2 -0
- package/dist/errors/retry.js.map +1 -1
- package/dist/facades/types.d.ts +1 -1
- package/dist/flows/chain-types.d.ts +18 -18
- package/dist/flows/gate-evaluator.d.ts.map +1 -1
- package/dist/flows/gate-evaluator.js +22 -0
- package/dist/flows/gate-evaluator.js.map +1 -1
- package/dist/flows/types.d.ts +157 -28
- package/dist/flows/types.d.ts.map +1 -1
- package/dist/flows/types.js +4 -0
- package/dist/flows/types.js.map +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/intake/intake-pipeline.d.ts.map +1 -1
- package/dist/intake/intake-pipeline.js +1 -0
- package/dist/intake/intake-pipeline.js.map +1 -1
- package/dist/intake/text-ingester.d.ts.map +1 -1
- package/dist/intake/text-ingester.js +2 -0
- package/dist/intake/text-ingester.js.map +1 -1
- package/dist/llm/key-pool.d.ts +1 -1
- package/dist/llm/key-pool.d.ts.map +1 -1
- package/dist/llm/key-pool.js +3 -4
- package/dist/llm/key-pool.js.map +1 -1
- package/dist/llm/utils.d.ts.map +1 -1
- package/dist/llm/utils.js +2 -0
- package/dist/llm/utils.js.map +1 -1
- package/dist/migrations/migration-runner.test-helpers.d.ts +13 -0
- package/dist/migrations/migration-runner.test-helpers.d.ts.map +1 -0
- package/dist/migrations/migration-runner.test-helpers.js +47 -0
- package/dist/migrations/migration-runner.test-helpers.js.map +1 -0
- package/dist/operator/operator-profile.d.ts +44 -0
- package/dist/operator/operator-profile.d.ts.map +1 -0
- package/dist/operator/operator-profile.js +377 -0
- package/dist/operator/operator-profile.js.map +1 -0
- package/dist/operator/operator-signals.d.ts +45 -0
- package/dist/operator/operator-signals.d.ts.map +1 -0
- package/dist/operator/operator-signals.js +228 -0
- package/dist/operator/operator-signals.js.map +1 -0
- package/dist/operator/operator-types.d.ts +360 -0
- package/dist/operator/operator-types.d.ts.map +1 -0
- package/dist/operator/operator-types.js +24 -0
- package/dist/operator/operator-types.js.map +1 -0
- package/dist/packs/types.d.ts +27 -27
- package/dist/paths.d.ts +40 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +98 -0
- package/dist/paths.js.map +1 -0
- package/dist/persistence/index.d.ts +1 -1
- package/dist/persistence/index.d.ts.map +1 -1
- package/dist/persistence/index.js +1 -1
- package/dist/persistence/index.js.map +1 -1
- package/dist/persistence/sqlite-provider.d.ts +2 -0
- package/dist/persistence/sqlite-provider.d.ts.map +1 -1
- package/dist/persistence/sqlite-provider.js +8 -5
- package/dist/persistence/sqlite-provider.js.map +1 -1
- package/dist/planning/evidence-collector.d.ts +13 -1
- package/dist/planning/evidence-collector.d.ts.map +1 -1
- package/dist/planning/evidence-collector.js +33 -0
- package/dist/planning/evidence-collector.js.map +1 -1
- package/dist/planning/gap-analysis.d.ts +5 -4
- package/dist/planning/gap-analysis.d.ts.map +1 -1
- package/dist/planning/gap-analysis.js +7 -341
- package/dist/planning/gap-analysis.js.map +1 -1
- package/dist/planning/gap-passes.d.ts +19 -0
- package/dist/planning/gap-passes.d.ts.map +1 -0
- package/dist/planning/gap-passes.js +157 -0
- package/dist/planning/gap-passes.js.map +1 -0
- package/dist/planning/gap-patterns.d.ts +29 -0
- package/dist/planning/gap-patterns.d.ts.map +1 -0
- package/dist/planning/gap-patterns.js +129 -0
- package/dist/planning/gap-patterns.js.map +1 -0
- package/dist/planning/gap-types.d.ts +1 -1
- package/dist/planning/gap-types.d.ts.map +1 -1
- package/dist/planning/gap-types.js +1 -0
- package/dist/planning/gap-types.js.map +1 -1
- package/dist/planning/github-projection.d.ts +122 -0
- package/dist/planning/github-projection.d.ts.map +1 -0
- package/dist/planning/github-projection.js +294 -0
- package/dist/planning/github-projection.js.map +1 -0
- package/dist/planning/impact-analyzer.d.ts +26 -0
- package/dist/planning/impact-analyzer.d.ts.map +1 -0
- package/dist/planning/impact-analyzer.js +199 -0
- package/dist/planning/impact-analyzer.js.map +1 -0
- package/dist/planning/plan-lifecycle.d.ts +136 -0
- package/dist/planning/plan-lifecycle.d.ts.map +1 -0
- package/dist/planning/plan-lifecycle.js +296 -0
- package/dist/planning/plan-lifecycle.js.map +1 -0
- package/dist/planning/planner-types.d.ts +202 -0
- package/dist/planning/planner-types.d.ts.map +1 -0
- package/dist/planning/planner-types.js +6 -0
- package/dist/planning/planner-types.js.map +1 -0
- package/dist/planning/planner.d.ts +31 -383
- package/dist/planning/planner.d.ts.map +1 -1
- package/dist/planning/planner.js +154 -878
- package/dist/planning/planner.js.map +1 -1
- package/dist/planning/rationalization-detector.d.ts +32 -0
- package/dist/planning/rationalization-detector.d.ts.map +1 -0
- package/dist/planning/rationalization-detector.js +89 -0
- package/dist/planning/rationalization-detector.js.map +1 -0
- package/dist/planning/reconciliation-engine.d.ts +47 -0
- package/dist/planning/reconciliation-engine.d.ts.map +1 -0
- package/dist/planning/reconciliation-engine.js +128 -0
- package/dist/planning/reconciliation-engine.js.map +1 -0
- package/dist/planning/task-verifier.d.ts +85 -0
- package/dist/planning/task-verifier.d.ts.map +1 -0
- package/dist/planning/task-verifier.js +227 -0
- package/dist/planning/task-verifier.js.map +1 -0
- package/dist/plugins/types.d.ts +4 -4
- package/dist/runtime/admin-ops.d.ts +2 -2
- package/dist/runtime/admin-ops.d.ts.map +1 -1
- package/dist/runtime/admin-ops.js +44 -17
- package/dist/runtime/admin-ops.js.map +1 -1
- package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
- package/dist/runtime/admin-setup-ops.js +21 -46
- package/dist/runtime/admin-setup-ops.js.map +1 -1
- package/dist/runtime/archive-ops.d.ts +10 -0
- package/dist/runtime/archive-ops.d.ts.map +1 -0
- package/dist/runtime/archive-ops.js +310 -0
- package/dist/runtime/archive-ops.js.map +1 -0
- package/dist/runtime/capture-ops.d.ts.map +1 -1
- package/dist/runtime/capture-ops.js +42 -7
- package/dist/runtime/capture-ops.js.map +1 -1
- package/dist/runtime/claude-md-helpers.js +1 -1
- package/dist/runtime/claude-md-helpers.js.map +1 -1
- package/dist/runtime/context-health.d.ts +31 -0
- package/dist/runtime/context-health.d.ts.map +1 -0
- package/dist/runtime/context-health.js +57 -0
- package/dist/runtime/context-health.js.map +1 -0
- package/dist/runtime/facades/archive-facade.d.ts +10 -0
- package/dist/runtime/facades/archive-facade.d.ts.map +1 -0
- package/dist/runtime/facades/archive-facade.js +11 -0
- package/dist/runtime/facades/archive-facade.js.map +1 -0
- package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
- package/dist/runtime/facades/brain-facade.js +2 -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 -1
- package/dist/runtime/facades/chat-facade.js +15 -800
- package/dist/runtime/facades/chat-facade.js.map +1 -1
- package/dist/runtime/facades/chat-service-ops.d.ts +9 -0
- package/dist/runtime/facades/chat-service-ops.d.ts.map +1 -0
- package/dist/runtime/facades/chat-service-ops.js +330 -0
- package/dist/runtime/facades/chat-service-ops.js.map +1 -0
- package/dist/runtime/facades/chat-session-ops.d.ts +8 -0
- package/dist/runtime/facades/chat-session-ops.d.ts.map +1 -0
- package/dist/runtime/facades/chat-session-ops.js +136 -0
- package/dist/runtime/facades/chat-session-ops.js.map +1 -0
- package/dist/runtime/facades/chat-state.d.ts +31 -0
- package/dist/runtime/facades/chat-state.d.ts.map +1 -0
- package/dist/runtime/facades/chat-state.js +32 -0
- package/dist/runtime/facades/chat-state.js.map +1 -0
- package/dist/runtime/facades/chat-transport-ops.d.ts +9 -0
- package/dist/runtime/facades/chat-transport-ops.d.ts.map +1 -0
- package/dist/runtime/facades/chat-transport-ops.js +337 -0
- package/dist/runtime/facades/chat-transport-ops.js.map +1 -0
- package/dist/runtime/facades/control-facade.d.ts.map +1 -1
- package/dist/runtime/facades/control-facade.js +4 -1
- package/dist/runtime/facades/control-facade.js.map +1 -1
- package/dist/runtime/facades/index.d.ts.map +1 -1
- package/dist/runtime/facades/index.js +6 -0
- package/dist/runtime/facades/index.js.map +1 -1
- package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
- package/dist/runtime/facades/memory-facade.js +75 -6
- package/dist/runtime/facades/memory-facade.js.map +1 -1
- package/dist/runtime/facades/operator-facade.d.ts +8 -0
- package/dist/runtime/facades/operator-facade.d.ts.map +1 -0
- package/dist/runtime/facades/operator-facade.js +220 -0
- package/dist/runtime/facades/operator-facade.js.map +1 -0
- package/dist/runtime/facades/orchestrate-facade.js +3 -3
- package/dist/runtime/facades/orchestrate-facade.js.map +1 -1
- package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
- package/dist/runtime/facades/plan-facade.js +39 -6
- package/dist/runtime/facades/plan-facade.js.map +1 -1
- package/dist/runtime/facades/review-facade.d.ts +7 -0
- package/dist/runtime/facades/review-facade.d.ts.map +1 -0
- package/dist/runtime/facades/review-facade.js +8 -0
- package/dist/runtime/facades/review-facade.js.map +1 -0
- package/dist/runtime/facades/sync-facade.d.ts +7 -0
- package/dist/runtime/facades/sync-facade.d.ts.map +1 -0
- package/dist/runtime/facades/sync-facade.js +8 -0
- package/dist/runtime/facades/sync-facade.js.map +1 -0
- package/dist/runtime/facades/vault-facade.d.ts +4 -1
- package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
- package/dist/runtime/facades/vault-facade.js +13 -66
- package/dist/runtime/facades/vault-facade.js.map +1 -1
- package/dist/runtime/github-integration.d.ts +49 -0
- package/dist/runtime/github-integration.d.ts.map +1 -0
- package/dist/runtime/github-integration.js +113 -0
- package/dist/runtime/github-integration.js.map +1 -0
- package/dist/runtime/grading-ops.js +1 -1
- package/dist/runtime/grading-ops.js.map +1 -1
- package/dist/runtime/memory-extra-ops.d.ts.map +1 -1
- package/dist/runtime/memory-extra-ops.js +6 -2
- package/dist/runtime/memory-extra-ops.js.map +1 -1
- package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
- package/dist/runtime/orchestrate-ops.js +367 -40
- package/dist/runtime/orchestrate-ops.js.map +1 -1
- package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
- package/dist/runtime/planning-extra-ops.js +69 -4
- package/dist/runtime/planning-extra-ops.js.map +1 -1
- package/dist/runtime/review-ops.d.ts +10 -0
- package/dist/runtime/review-ops.d.ts.map +1 -0
- package/dist/runtime/review-ops.js +97 -0
- package/dist/runtime/review-ops.js.map +1 -0
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +27 -12
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/session-briefing.d.ts +3 -0
- package/dist/runtime/session-briefing.d.ts.map +1 -1
- package/dist/runtime/session-briefing.js +68 -1
- package/dist/runtime/session-briefing.js.map +1 -1
- package/dist/runtime/sync-ops.d.ts +12 -0
- package/dist/runtime/sync-ops.d.ts.map +1 -0
- package/dist/runtime/sync-ops.js +288 -0
- package/dist/runtime/sync-ops.js.map +1 -0
- package/dist/runtime/types.d.ts +10 -4
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/vault-extra-ops.d.ts +5 -4
- package/dist/runtime/vault-extra-ops.d.ts.map +1 -1
- package/dist/runtime/vault-extra-ops.js +5 -300
- package/dist/runtime/vault-extra-ops.js.map +1 -1
- package/dist/runtime/vault-sharing-ops.d.ts +4 -4
- package/dist/runtime/vault-sharing-ops.d.ts.map +1 -1
- package/dist/runtime/vault-sharing-ops.js +5 -300
- package/dist/runtime/vault-sharing-ops.js.map +1 -1
- package/dist/skills/sync-skills.d.ts +27 -0
- package/dist/skills/sync-skills.d.ts.map +1 -0
- package/dist/skills/sync-skills.js +81 -0
- package/dist/skills/sync-skills.js.map +1 -0
- package/dist/update-check.d.ts +14 -0
- package/dist/update-check.d.ts.map +1 -0
- package/dist/update-check.js +96 -0
- package/dist/update-check.js.map +1 -0
- package/dist/vault/linking.d.ts +10 -12
- package/dist/vault/linking.d.ts.map +1 -1
- package/dist/vault/linking.js +104 -161
- package/dist/vault/linking.js.map +1 -1
- package/dist/vault/vault-entries.d.ts +69 -0
- package/dist/vault/vault-entries.d.ts.map +1 -0
- package/dist/vault/vault-entries.js +257 -0
- package/dist/vault/vault-entries.js.map +1 -0
- package/dist/vault/vault-interfaces.d.ts +153 -0
- package/dist/vault/vault-interfaces.d.ts.map +1 -0
- package/dist/vault/vault-interfaces.js +2 -0
- package/dist/vault/vault-interfaces.js.map +1 -0
- package/dist/vault/vault-maintenance.d.ts +40 -0
- package/dist/vault/vault-maintenance.d.ts.map +1 -0
- package/dist/vault/vault-maintenance.js +142 -0
- package/dist/vault/vault-maintenance.js.map +1 -0
- package/dist/vault/vault-markdown-sync.d.ts +22 -0
- package/dist/vault/vault-markdown-sync.d.ts.map +1 -0
- package/dist/vault/vault-markdown-sync.js +143 -0
- package/dist/vault/vault-markdown-sync.js.map +1 -0
- package/dist/vault/vault-memories.d.ts +61 -0
- package/dist/vault/vault-memories.d.ts.map +1 -0
- package/dist/vault/vault-memories.js +240 -0
- package/dist/vault/vault-memories.js.map +1 -0
- package/dist/vault/vault-schema.d.ts +9 -0
- package/dist/vault/vault-schema.d.ts.map +1 -0
- package/dist/vault/vault-schema.js +179 -0
- package/dist/vault/vault-schema.js.map +1 -0
- package/dist/vault/vault.d.ts +29 -81
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +78 -931
- package/dist/vault/vault.js.map +1 -1
- package/package.json +1 -1
- package/src/agency/agency-manager.test.ts +600 -0
- package/src/agency/default-rules.test.ts +228 -0
- package/src/{__tests__ → brain}/brain-intelligence.test.ts +37 -14
- package/src/{__tests__ → brain}/brain.test.ts +1 -1
- package/src/brain/intelligence.ts +196 -15
- package/src/brain/learning-radar.ts +22 -1
- package/src/{__tests__ → brain}/second-brain-features.test.ts +4 -4
- package/src/{__tests__ → brain}/session-lifecycle.test.ts +2 -2
- package/src/brain/strength-scorer.ts +404 -0
- package/src/capabilities/chain-mapping.test.ts +66 -0
- package/src/capabilities/registry.test.ts +369 -0
- package/src/chat/agent-loop.test.ts +394 -0
- package/src/chat/agent-loop.ts +2 -0
- package/src/{__tests__ → chat}/chat-differentiators.test.ts +3 -3
- package/src/{__tests__ → chat}/chat-enhanced.test.ts +4 -4
- package/src/{__tests__ → chat}/chat-transport.test.ts +6 -6
- package/src/chat/mcp-bridge.test.ts +173 -0
- package/src/chat/notifications.ts +2 -0
- package/src/chat/output-compressor.test.ts +164 -0
- package/src/claudemd/compose.test.ts +178 -0
- package/src/claudemd/compose.ts +1 -1
- package/src/claudemd/inject.test.ts +211 -0
- package/src/context/context-engine.test.ts +461 -0
- package/src/control/identity-manager.test.ts +305 -0
- package/src/control/intent-router.test.ts +360 -0
- package/src/control/intent-router.ts +13 -4
- package/src/curator/classifier.test.ts +104 -0
- package/src/curator/contradiction-detector.test.ts +180 -0
- package/src/curator/contradiction-detector.ts +87 -0
- package/src/{__tests__ → curator}/curator-pipeline-e2e.test.ts +10 -10
- package/src/{__tests__ → curator}/curator.test.ts +77 -1
- package/src/curator/curator.ts +115 -777
- package/src/curator/duplicate-detector.test.ts +183 -0
- package/src/curator/duplicate-detector.ts +103 -0
- package/src/curator/health-audit.ts +126 -0
- package/src/curator/metadata-enricher.ts +84 -0
- package/src/curator/quality-gate.test.ts +135 -0
- package/src/curator/schema.ts +65 -0
- package/src/curator/tag-manager.test.ts +165 -0
- package/src/curator/tag-manager.ts +109 -0
- package/src/domain-packs/inject-rules.test.ts +117 -0
- package/src/domain-packs/knowledge-installer.test.ts +171 -0
- package/src/domain-packs/loader.test.ts +86 -0
- package/src/domain-packs/pack-runtime.test.ts +140 -0
- package/src/domain-packs/skills-installer.test.ts +135 -0
- package/src/domain-packs/token-resolver.test.ts +150 -0
- package/src/domain-packs/types.test.ts +130 -0
- package/src/enforcement/adapters/claude-code.test.ts +216 -0
- package/src/enforcement/registry.test.ts +264 -0
- package/src/engine/bin/soleri-engine.ts +59 -3
- package/src/engine/core-ops.test.ts +254 -0
- package/src/engine/core-ops.ts +35 -10
- package/src/engine/module-manifest.test.ts +124 -0
- package/src/engine/module-manifest.ts +22 -2
- package/src/engine/register-engine.test.ts +230 -0
- package/src/engine/register-engine.ts +26 -2
- package/src/errors/classify.test.ts +199 -0
- package/src/errors/retry.test.ts +156 -0
- package/src/errors/retry.ts +2 -0
- package/src/errors/types.test.ts +108 -0
- package/src/events/event-bus.test.ts +149 -0
- package/src/extensions/middleware.test.ts +234 -0
- package/src/facades/facade-factory.test.ts +424 -0
- package/src/flows/chain-runner.test.ts +273 -0
- package/src/flows/context-router.test.ts +52 -0
- package/src/flows/dispatch-registry.test.ts +128 -0
- package/src/flows/epilogue.test.ts +107 -0
- package/src/flows/executor.test.ts +263 -0
- package/src/flows/gate-evaluator.test.ts +194 -0
- package/src/flows/gate-evaluator.ts +25 -0
- package/src/flows/types.ts +4 -0
- package/src/governance/governance.test.ts +726 -0
- package/src/health/health-registry.test.ts +186 -0
- package/src/health/vault-integrity.test.ts +110 -0
- package/src/index.ts +92 -0
- package/src/intake/content-classifier.test.ts +209 -0
- package/src/intake/dedup-gate.test.ts +131 -0
- package/src/intake/intake-pipeline.test.ts +506 -0
- package/src/intake/intake-pipeline.ts +1 -0
- package/src/intake/text-ingester.test.ts +194 -0
- package/src/intake/text-ingester.ts +2 -0
- package/src/llm/key-pool.test.ts +236 -0
- package/src/llm/key-pool.ts +3 -4
- package/src/llm/llm-client.test.ts +345 -0
- package/src/llm/oauth-discovery.test.ts +180 -0
- package/src/llm/utils.test.ts +327 -0
- package/src/llm/utils.ts +2 -0
- package/src/{__tests__ → logging}/logger.test.ts +41 -62
- package/src/loop/loop-manager.test.ts +519 -0
- package/src/migrations/migration-runner.edge-cases.test.ts +319 -0
- package/src/migrations/migration-runner.test-helpers.ts +64 -0
- package/src/migrations/migration-runner.test.ts +385 -0
- package/src/operator/auto-signal-pipeline.test.ts +207 -0
- package/src/operator/operator-profile-extended.test.ts +320 -0
- package/src/operator/operator-profile.test.ts +314 -0
- package/src/operator/operator-profile.ts +469 -0
- package/src/operator/operator-signals-extended.test.ts +245 -0
- package/src/operator/operator-signals.test.ts +281 -0
- package/src/operator/operator-signals.ts +261 -0
- package/src/operator/operator-types.ts +444 -0
- package/src/operator/prompts/hook-precompact-operator-dispatch.md +94 -0
- package/src/operator/prompts/subagent-soft-signal-extractor.md +125 -0
- package/src/operator/prompts/subagent-synthesis-cognition.md +181 -0
- package/src/operator/prompts/subagent-synthesis-communication.md +140 -0
- package/src/operator/prompts/subagent-synthesis-technical.md +160 -0
- package/src/operator/prompts/subagent-synthesis-trust.md +143 -0
- package/src/{__tests__ → packs}/pack-lockfile.test.ts +3 -3
- package/src/{__tests__ → packs}/pack-system.test.ts +2 -2
- package/src/paths.ts +115 -0
- package/src/persistence/index.ts +1 -1
- package/src/persistence/sqlite-provider.test.ts +540 -0
- package/src/persistence/sqlite-provider.ts +8 -5
- package/src/persona/defaults.test.ts +59 -0
- package/src/persona/loader.test.ts +67 -0
- package/src/persona/prompt-generator.test.ts +127 -0
- package/src/planning/evidence-collector.test.ts +406 -0
- package/src/planning/evidence-collector.ts +50 -0
- package/src/planning/gap-analysis-alternatives.test.ts +169 -0
- package/src/planning/gap-analysis.ts +21 -636
- package/src/planning/gap-passes.test.ts +372 -0
- package/src/planning/gap-passes.ts +298 -0
- package/src/planning/gap-patterns.test.ts +320 -0
- package/src/planning/gap-patterns.ts +234 -0
- package/src/planning/gap-types.ts +4 -1
- package/src/planning/github-projection.test.ts +177 -0
- package/src/planning/github-projection.ts +425 -0
- package/src/planning/impact-analyzer.test.ts +180 -0
- package/src/planning/impact-analyzer.ts +264 -0
- package/src/planning/plan-lifecycle.test.ts +312 -0
- package/src/planning/plan-lifecycle.ts +346 -0
- package/src/planning/planner-types.ts +215 -0
- package/src/{__tests__ → planning}/planner.test.ts +169 -15
- package/src/planning/planner.ts +197 -1228
- package/src/planning/rationalization-detector.test.ts +171 -0
- package/src/planning/rationalization-detector.ts +138 -0
- package/src/planning/reconciliation-engine.test.ts +141 -0
- package/src/planning/reconciliation-engine.ts +162 -0
- package/src/planning/task-verifier.test.ts +235 -0
- package/src/planning/task-verifier.ts +303 -0
- package/src/planning/verification-protocol.test.ts +201 -0
- package/src/playbooks/generic/generic-playbooks.test.ts +438 -0
- package/src/playbooks/index.test.ts +77 -0
- package/src/playbooks/playbook-executor.test.ts +255 -0
- package/src/playbooks/playbook-registry.test.ts +232 -0
- package/src/playbooks/playbook-seeder.test.ts +153 -0
- package/src/plugins/plugin-loader.test.ts +212 -0
- package/src/plugins/plugin-registry.test.ts +272 -0
- package/src/project/project-registry.test.ts +428 -0
- package/src/prompts/parser.test.ts +100 -0
- package/src/prompts/template-manager.test.ts +109 -0
- package/src/{__tests__ → queue}/async-infrastructure.test.ts +3 -3
- package/src/queue/job-queue.test.ts +331 -0
- package/src/queue/pipeline-runner.test.ts +209 -0
- package/src/runtime/admin-extra-ops.test.ts +527 -0
- package/src/runtime/admin-ops.test.ts +257 -0
- package/src/runtime/admin-ops.ts +45 -17
- package/src/runtime/admin-setup-ops.test.ts +328 -0
- package/src/runtime/admin-setup-ops.ts +20 -43
- package/src/runtime/archive-ops.test.ts +269 -0
- package/src/runtime/archive-ops.ts +347 -0
- package/src/runtime/capture-ops.test.ts +433 -0
- package/src/runtime/capture-ops.ts +50 -8
- package/src/runtime/chain-ops.test.ts +149 -0
- package/src/runtime/claude-md-helpers.test.ts +191 -0
- package/src/runtime/claude-md-helpers.ts +1 -1
- package/src/runtime/context-health.test.ts +78 -0
- package/src/runtime/context-health.ts +85 -0
- package/src/runtime/curator-extra-ops.test.ts +202 -0
- package/src/runtime/deprecation.test.ts +98 -0
- package/src/runtime/domain-ops.test.ts +268 -0
- package/src/runtime/facades/admin-facade.test.ts +333 -0
- package/src/runtime/facades/agency-facade.test.ts +278 -0
- package/src/runtime/facades/archive-facade.test.ts +294 -0
- package/src/runtime/facades/archive-facade.ts +14 -0
- package/src/runtime/facades/brain-facade.test.ts +714 -0
- package/src/runtime/facades/brain-facade.ts +2 -0
- package/src/runtime/facades/chat-facade.test.ts +166 -0
- package/src/runtime/facades/chat-facade.ts +15 -906
- package/src/runtime/facades/chat-service-ops.test.ts +276 -0
- package/src/runtime/facades/chat-service-ops.ts +374 -0
- package/src/runtime/facades/chat-session-ops.test.ts +197 -0
- package/src/runtime/facades/chat-session-ops.ts +146 -0
- package/src/runtime/facades/chat-state.ts +60 -0
- package/src/runtime/facades/chat-transport-ops.test.ts +269 -0
- package/src/runtime/facades/chat-transport-ops.ts +380 -0
- package/src/runtime/facades/context-facade.test.ts +108 -0
- package/src/runtime/facades/control-facade.test.ts +436 -0
- package/src/runtime/facades/control-facade.ts +6 -1
- package/src/runtime/facades/curator-facade.test.ts +303 -0
- package/src/runtime/facades/index.ts +6 -0
- package/src/runtime/facades/loop-facade.test.ts +245 -0
- package/src/runtime/facades/memory-facade.test.ts +269 -0
- package/src/runtime/facades/memory-facade.ts +78 -6
- package/src/runtime/facades/operator-facade.test.ts +208 -0
- package/src/runtime/facades/operator-facade.ts +236 -0
- package/src/runtime/facades/orchestrate-facade.test.ts +185 -0
- package/src/runtime/facades/orchestrate-facade.ts +3 -3
- package/src/runtime/facades/plan-facade.test.ts +266 -0
- package/src/runtime/facades/plan-facade.ts +42 -6
- package/src/runtime/facades/review-facade.test.ts +82 -0
- package/src/runtime/facades/review-facade.ts +11 -0
- package/src/runtime/facades/sync-facade.test.ts +113 -0
- package/src/runtime/facades/sync-facade.ts +11 -0
- package/src/runtime/facades/vault-facade.test.ts +631 -0
- package/src/runtime/facades/vault-facade.ts +15 -70
- package/src/runtime/feature-flags.test.ts +140 -0
- package/src/runtime/github-integration.test.ts +89 -0
- package/src/runtime/github-integration.ts +159 -0
- package/src/runtime/grading-ops.test.ts +141 -0
- package/src/runtime/grading-ops.ts +1 -1
- package/src/runtime/intake-ops.test.ts +208 -0
- package/src/runtime/loop-ops.test.ts +238 -0
- package/src/runtime/memory-cross-project-ops.test.ts +177 -0
- package/src/runtime/memory-extra-ops.test.ts +453 -0
- package/src/runtime/memory-extra-ops.ts +6 -2
- package/src/runtime/orchestrate-ops.test.ts +302 -0
- package/src/runtime/orchestrate-ops.ts +435 -46
- package/src/runtime/pack-ops.test.ts +158 -0
- package/src/runtime/planning-extra-ops.test.ts +583 -0
- package/src/runtime/planning-extra-ops.ts +72 -4
- package/src/{__tests__ → runtime}/playbook-ops-execution.test.ts +3 -3
- package/src/runtime/playbook-ops.test.ts +262 -0
- package/src/runtime/plugin-ops.test.ts +201 -0
- package/src/runtime/project-ops.test.ts +235 -0
- package/src/runtime/review-ops.test.ts +142 -0
- package/src/runtime/review-ops.ts +99 -0
- package/src/runtime/runtime.test.ts +363 -0
- package/src/runtime/runtime.ts +39 -12
- package/src/runtime/session-briefing.test.ts +302 -0
- package/src/runtime/session-briefing.ts +80 -1
- package/src/runtime/sync-ops.test.ts +221 -0
- package/src/runtime/sync-ops.ts +325 -0
- package/src/runtime/telemetry-ops.test.ts +132 -0
- package/src/runtime/types.ts +10 -4
- package/src/runtime/vault-extra-ops.test.ts +246 -0
- package/src/runtime/vault-extra-ops.ts +5 -332
- package/src/runtime/vault-linking-ops.test.ts +237 -0
- package/src/runtime/vault-sharing-ops.test.ts +130 -0
- package/src/runtime/vault-sharing-ops.ts +5 -329
- package/src/skills/sync-skills.ts +108 -0
- package/src/streams/normalize.test.ts +95 -0
- package/src/streams/replayable-stream.test.ts +166 -0
- package/src/telemetry/telemetry.test.ts +143 -0
- package/src/transport/http-server.test.ts +394 -0
- package/src/transport/lsp-server.test.ts +458 -0
- package/src/transport/rate-limiter.test.ts +126 -0
- package/src/transport/session-manager.test.ts +133 -0
- package/src/transport/token-auth.test.ts +136 -0
- package/src/transport/ws-server.test.ts +294 -0
- package/src/update-check.ts +111 -0
- package/src/vault/__tests__/vault-characterization.test.ts +168 -0
- package/src/vault/content-hash.test.ts +78 -0
- package/src/vault/git-vault-sync.test.ts +234 -0
- package/src/vault/knowledge-review.test.ts +269 -0
- package/src/vault/linking.test.ts +358 -0
- package/src/vault/linking.ts +149 -183
- package/src/vault/obsidian-sync.test.ts +342 -0
- package/src/vault/playbook.test.ts +152 -0
- package/src/vault/scope-detector.test.ts +187 -0
- package/src/vault/vault-branching.test.ts +250 -0
- package/src/{__tests__ → vault}/vault-connect.test.ts +1 -1
- package/src/vault/vault-entries.ts +282 -0
- package/src/vault/vault-interfaces.ts +56 -0
- package/src/vault/vault-maintenance.ts +205 -0
- package/src/vault/vault-manager.test.ts +206 -0
- package/src/vault/vault-markdown-sync.test.ts +203 -0
- package/src/vault/vault-markdown-sync.ts +160 -0
- package/src/vault/vault-memories.ts +339 -0
- package/src/{__tests__ → vault}/vault-scaling.test.ts +1 -1
- package/src/vault/vault-schema.ts +181 -0
- package/src/{__tests__ → vault}/vault-sharing.test.ts +4 -4
- package/src/{__tests__ → vault}/vault.test.ts +2 -2
- package/src/vault/vault.ts +89 -1171
- package/dist/cognee/client.d.ts +0 -43
- package/dist/cognee/client.d.ts.map +0 -1
- package/dist/cognee/client.js +0 -375
- package/dist/cognee/client.js.map +0 -1
- package/dist/cognee/sync-manager.d.ts +0 -153
- package/dist/cognee/sync-manager.d.ts.map +0 -1
- package/dist/cognee/sync-manager.js +0 -390
- package/dist/cognee/sync-manager.js.map +0 -1
- package/dist/cognee/types.d.ts +0 -62
- package/dist/cognee/types.d.ts.map +0 -1
- package/dist/cognee/types.js +0 -3
- package/dist/cognee/types.js.map +0 -1
- package/dist/governance/index.d.ts +0 -3
- package/dist/governance/index.d.ts.map +0 -1
- package/dist/governance/index.js +0 -2
- package/dist/governance/index.js.map +0 -1
- package/dist/health/doctor-checks.d.ts +0 -15
- package/dist/health/doctor-checks.d.ts.map +0 -1
- package/dist/health/doctor-checks.js +0 -98
- package/dist/health/doctor-checks.js.map +0 -1
- package/dist/persistence/postgres-provider.d.ts +0 -81
- package/dist/persistence/postgres-provider.d.ts.map +0 -1
- package/dist/persistence/postgres-provider.js +0 -256
- package/dist/persistence/postgres-provider.js.map +0 -1
- package/dist/runtime/cognee-sync-ops.d.ts +0 -12
- package/dist/runtime/cognee-sync-ops.d.ts.map +0 -1
- package/dist/runtime/cognee-sync-ops.js +0 -93
- package/dist/runtime/cognee-sync-ops.js.map +0 -1
- package/dist/runtime/core-ops.d.ts +0 -23
- package/dist/runtime/core-ops.d.ts.map +0 -1
- package/dist/runtime/core-ops.js +0 -1296
- package/dist/runtime/core-ops.js.map +0 -1
- package/dist/runtime/facades/cognee-facade.d.ts +0 -8
- package/dist/runtime/facades/cognee-facade.d.ts.map +0 -1
- package/dist/runtime/facades/cognee-facade.js +0 -156
- package/dist/runtime/facades/cognee-facade.js.map +0 -1
- package/src/__tests__/admin-extra-ops.test.ts +0 -484
- package/src/__tests__/admin-ops.test.ts +0 -268
- package/src/__tests__/admin-setup-ops.test.ts +0 -355
- package/src/__tests__/agency-manager.test.ts +0 -374
- package/src/__tests__/agent-loop.test.ts +0 -256
- package/src/__tests__/capture-ops.test.ts +0 -784
- package/src/__tests__/claudemd.test.ts +0 -282
- package/src/__tests__/content-hash.test.ts +0 -60
- package/src/__tests__/context-engine.test.ts +0 -251
- package/src/__tests__/core-ops.test.ts +0 -550
- package/src/__tests__/curator-extra-ops.test.ts +0 -383
- package/src/__tests__/deprecation.test.ts +0 -78
- package/src/__tests__/domain-ops.test.ts +0 -226
- package/src/__tests__/domain-packs.test.ts +0 -421
- package/src/__tests__/enforcement.test.ts +0 -153
- package/src/__tests__/errors.test.ts +0 -388
- package/src/__tests__/extensions.test.ts +0 -233
- package/src/__tests__/facade-factory.test.ts +0 -271
- package/src/__tests__/feature-flags.test.ts +0 -137
- package/src/__tests__/flows.test.ts +0 -604
- package/src/__tests__/git-vault-sync.test.ts +0 -230
- package/src/__tests__/governance.test.ts +0 -522
- package/src/__tests__/grading-ops.test.ts +0 -361
- package/src/__tests__/health-registry.test.ts +0 -173
- package/src/__tests__/identity-manager.test.ts +0 -243
- package/src/__tests__/intake-pipeline.test.ts +0 -162
- package/src/__tests__/intent-router.test.ts +0 -222
- package/src/__tests__/knowledge-review.test.ts +0 -104
- package/src/__tests__/llm-client.test.ts +0 -69
- package/src/__tests__/llm.test.ts +0 -556
- package/src/__tests__/loader.test.ts +0 -176
- package/src/__tests__/loop-ops.test.ts +0 -469
- package/src/__tests__/lsp-transport.test.ts +0 -442
- package/src/__tests__/memory-cross-project-ops.test.ts +0 -248
- package/src/__tests__/memory-extra-ops.test.ts +0 -352
- package/src/__tests__/migration-runner.test.ts +0 -170
- package/src/__tests__/module-manifest-drift.test.ts +0 -59
- package/src/__tests__/normalize.test.ts +0 -85
- package/src/__tests__/obsidian-sync.test.ts +0 -354
- package/src/__tests__/orchestrate-ops.test.ts +0 -289
- package/src/__tests__/pack-ops.test.ts +0 -146
- package/src/__tests__/persistence.test.ts +0 -291
- package/src/__tests__/planning-extra-ops.test.ts +0 -706
- package/src/__tests__/playbook-executor.test.ts +0 -249
- package/src/__tests__/playbook-registry.test.ts +0 -326
- package/src/__tests__/playbook-seeder.test.ts +0 -163
- package/src/__tests__/playbook.test.ts +0 -389
- package/src/__tests__/plugin-ops.test.ts +0 -411
- package/src/__tests__/plugin-system.test.ts +0 -509
- package/src/__tests__/project-ops.test.ts +0 -381
- package/src/__tests__/replayable-stream.test.ts +0 -177
- package/src/__tests__/runtime.test.ts +0 -95
- package/src/__tests__/scope-detector.test.ts +0 -121
- package/src/__tests__/template-manager.test.ts +0 -222
- package/src/__tests__/token-resolver.test.ts +0 -79
- package/src/__tests__/transport.test.ts +0 -758
- package/src/__tests__/vault-branching.test.ts +0 -274
- package/src/__tests__/vault-extra-ops.test.ts +0 -482
- package/src/__tests__/vault-integrity.test.ts +0 -71
- package/src/__tests__/vault-manager.test.ts +0 -238
- package/src/__tests__/ws-transport.test.ts +0 -479
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Colocated tests for register-engine.ts
|
|
3
|
+
*
|
|
4
|
+
* Validates registerEngine() registration mechanics:
|
|
5
|
+
* - Module tool naming convention
|
|
6
|
+
* - Engine module ordering and completeness
|
|
7
|
+
* - Core ops registration
|
|
8
|
+
* - Domain and domain pack registration
|
|
9
|
+
* - Hot ops as standalone tools
|
|
10
|
+
* - Auth policy enforcement
|
|
11
|
+
* - Error handling for unknown ops
|
|
12
|
+
* - Dynamic tool registration (registerTool)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
16
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
17
|
+
import { createAgentRuntime } from '../runtime/runtime.js';
|
|
18
|
+
import { registerEngine, ENGINE_MODULES } from './register-engine.js';
|
|
19
|
+
import { ENGINE_MODULE_MANIFEST } from './module-manifest.js';
|
|
20
|
+
import type { AgentRuntime } from '../runtime/types.js';
|
|
21
|
+
import type { OpDefinition } from '../facades/types.js';
|
|
22
|
+
|
|
23
|
+
let runtime: AgentRuntime;
|
|
24
|
+
|
|
25
|
+
beforeAll(() => {
|
|
26
|
+
runtime = createAgentRuntime({
|
|
27
|
+
agentId: 'reg-test',
|
|
28
|
+
vaultPath: ':memory:',
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
afterAll(() => {
|
|
33
|
+
runtime.close();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
function makeServer(): McpServer {
|
|
37
|
+
return new McpServer({ name: 'test-server', version: '1.0.0' });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe('registerEngine — tool naming', () => {
|
|
41
|
+
it('prefixes all tools with agentId', () => {
|
|
42
|
+
const server = makeServer();
|
|
43
|
+
const result = registerEngine(server, runtime, { agentId: 'mybot' });
|
|
44
|
+
for (const tool of result.tools) {
|
|
45
|
+
expect(tool.startsWith('mybot_')).toBe(true);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('creates {agentId}_{suffix} for each engine module', () => {
|
|
50
|
+
const server = makeServer();
|
|
51
|
+
const result = registerEngine(server, runtime, { agentId: 'alfa' });
|
|
52
|
+
const expectedSuffixes = ENGINE_MODULES.map((m) => m.suffix);
|
|
53
|
+
for (const suffix of expectedSuffixes) {
|
|
54
|
+
expect(result.tools).toContain(`alfa_${suffix}`);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('registerEngine — module completeness', () => {
|
|
60
|
+
it('ENGINE_MODULES matches ENGINE_MODULE_MANIFEST suffixes', () => {
|
|
61
|
+
const moduleSuffixes = ENGINE_MODULES.map((m) => m.suffix);
|
|
62
|
+
const manifestSuffixes = ENGINE_MODULE_MANIFEST.map((m) => m.suffix);
|
|
63
|
+
expect(moduleSuffixes).toEqual(manifestSuffixes);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('ENGINE_MODULES and manifest have same count', () => {
|
|
67
|
+
expect(ENGINE_MODULES.length).toBe(ENGINE_MODULE_MANIFEST.length);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('registers all unconditional modules', () => {
|
|
71
|
+
const server = makeServer();
|
|
72
|
+
const result = registerEngine(server, runtime, { agentId: 'check' });
|
|
73
|
+
const unconditional = ENGINE_MODULES.filter((m) => !m.condition);
|
|
74
|
+
for (const mod of unconditional) {
|
|
75
|
+
expect(result.tools).toContain(`check_${mod.suffix}`);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('registerEngine — module ordering', () => {
|
|
81
|
+
it('registers vault before brain (dependency order)', () => {
|
|
82
|
+
const server = makeServer();
|
|
83
|
+
const result = registerEngine(server, runtime, { agentId: 'ord' });
|
|
84
|
+
const vaultIdx = result.tools.indexOf('ord_vault');
|
|
85
|
+
const brainIdx = result.tools.indexOf('ord_brain');
|
|
86
|
+
expect(vaultIdx).toBeLessThan(brainIdx);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('registers vault as the first engine module tool', () => {
|
|
90
|
+
const server = makeServer();
|
|
91
|
+
const result = registerEngine(server, runtime, { agentId: 'first' });
|
|
92
|
+
expect(result.tools[0]).toBe('first_vault');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('registerEngine — core ops', () => {
|
|
97
|
+
it('registers core facade when coreOps provided', () => {
|
|
98
|
+
const server = makeServer();
|
|
99
|
+
const coreOps: OpDefinition[] = [
|
|
100
|
+
{ name: 'health', description: 'Health check', auth: 'read', handler: async () => ({ ok: true }) },
|
|
101
|
+
];
|
|
102
|
+
const result = registerEngine(server, runtime, { agentId: 'core', coreOps });
|
|
103
|
+
expect(result.tools).toContain('core_core');
|
|
104
|
+
expect(result.totalOps).toBeGreaterThan(ENGINE_MODULES.length); // at least 1 per module + 1 core
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('does not register core facade when coreOps is empty', () => {
|
|
108
|
+
const server = makeServer();
|
|
109
|
+
const result = registerEngine(server, runtime, { agentId: 'nocore', coreOps: [] });
|
|
110
|
+
expect(result.tools).not.toContain('nocore_core');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('does not register core facade when coreOps is undefined', () => {
|
|
114
|
+
const server = makeServer();
|
|
115
|
+
const result = registerEngine(server, runtime, { agentId: 'nocore2' });
|
|
116
|
+
expect(result.tools).not.toContain('nocore2_core');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe('registerEngine — hot ops', () => {
|
|
121
|
+
it('registers hot ops as standalone tools', () => {
|
|
122
|
+
const server = makeServer();
|
|
123
|
+
const result = registerEngine(server, runtime, {
|
|
124
|
+
agentId: 'hot',
|
|
125
|
+
hotOps: ['search_intelligent', 'capture_knowledge'],
|
|
126
|
+
});
|
|
127
|
+
expect(result.tools).toContain('hot_search_intelligent');
|
|
128
|
+
expect(result.tools).toContain('hot_capture_knowledge');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('counts hot ops in totalOps', () => {
|
|
132
|
+
const server = makeServer();
|
|
133
|
+
const baseResult = registerEngine(server, runtime, { agentId: 'base' });
|
|
134
|
+
|
|
135
|
+
const server2 = makeServer();
|
|
136
|
+
const hotResult = registerEngine(server2, runtime, {
|
|
137
|
+
agentId: 'hotcount',
|
|
138
|
+
hotOps: ['search_intelligent'],
|
|
139
|
+
});
|
|
140
|
+
// Hot ops don't add to totalOps (they mirror existing ops)
|
|
141
|
+
// But they do add to tools array
|
|
142
|
+
expect(hotResult.tools.length).toBeGreaterThan(baseResult.tools.length);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('registerEngine — domains', () => {
|
|
147
|
+
it('registers domain facades with correct naming', () => {
|
|
148
|
+
const server = makeServer();
|
|
149
|
+
const result = registerEngine(server, runtime, {
|
|
150
|
+
agentId: 'dom',
|
|
151
|
+
domains: ['testing', 'architecture'],
|
|
152
|
+
});
|
|
153
|
+
expect(result.tools).toContain('dom_testing');
|
|
154
|
+
expect(result.tools).toContain('dom_architecture');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('increments totalOps for domain facade ops', () => {
|
|
158
|
+
const server1 = makeServer();
|
|
159
|
+
const noDomains = registerEngine(server1, runtime, { agentId: 'nod' });
|
|
160
|
+
|
|
161
|
+
const server2 = makeServer();
|
|
162
|
+
const withDomains = registerEngine(server2, runtime, {
|
|
163
|
+
agentId: 'wd',
|
|
164
|
+
domains: ['testing'],
|
|
165
|
+
});
|
|
166
|
+
expect(withDomains.totalOps).toBeGreaterThan(noDomains.totalOps);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('registerEngine — domain packs', () => {
|
|
171
|
+
it('registers domain pack facades with agentId prefix', () => {
|
|
172
|
+
const server = makeServer();
|
|
173
|
+
const packOp: OpDefinition = {
|
|
174
|
+
name: 'custom_search',
|
|
175
|
+
description: 'Custom search',
|
|
176
|
+
auth: 'read',
|
|
177
|
+
handler: async () => [],
|
|
178
|
+
};
|
|
179
|
+
const result = registerEngine(server, runtime, {
|
|
180
|
+
agentId: 'pk',
|
|
181
|
+
domainPacks: [{ name: 'my-pack', facades: [{ name: 'custom', ops: [packOp] }] }],
|
|
182
|
+
});
|
|
183
|
+
expect(result.tools).toContain('pk_custom');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('skips packs without facades', () => {
|
|
187
|
+
const server = makeServer();
|
|
188
|
+
const result = registerEngine(server, runtime, {
|
|
189
|
+
agentId: 'skip',
|
|
190
|
+
domainPacks: [{ name: 'empty-pack' }],
|
|
191
|
+
});
|
|
192
|
+
// Should still register normally without errors
|
|
193
|
+
expect(result.tools.length).toBeGreaterThan(0);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
describe('registerEngine — return value', () => {
|
|
198
|
+
it('returns tools array, totalOps count, and registerTool function', () => {
|
|
199
|
+
const server = makeServer();
|
|
200
|
+
const result = registerEngine(server, runtime, { agentId: 'ret' });
|
|
201
|
+
expect(Array.isArray(result.tools)).toBe(true);
|
|
202
|
+
expect(typeof result.totalOps).toBe('number');
|
|
203
|
+
expect(typeof result.registerTool).toBe('function');
|
|
204
|
+
expect(result.totalOps).toBeGreaterThan(0);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('registerTool adds a new tool at runtime', () => {
|
|
208
|
+
const server = makeServer();
|
|
209
|
+
const result = registerEngine(server, runtime, { agentId: 'dyn' });
|
|
210
|
+
const initialCount = result.tools.length;
|
|
211
|
+
|
|
212
|
+
result.registerTool('dyn_extra', 'Extra tool', [
|
|
213
|
+
{ name: 'ping', description: 'Ping', auth: 'read', handler: async () => 'pong' },
|
|
214
|
+
]);
|
|
215
|
+
|
|
216
|
+
expect(result.tools.length).toBe(initialCount + 1);
|
|
217
|
+
expect(result.tools).toContain('dyn_extra');
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
describe('ENGINE_MODULES descriptions match manifest', () => {
|
|
222
|
+
it('each module description aligns with manifest', () => {
|
|
223
|
+
for (let i = 0; i < ENGINE_MODULES.length; i++) {
|
|
224
|
+
const mod = ENGINE_MODULES[i];
|
|
225
|
+
const manifest = ENGINE_MODULE_MANIFEST[i];
|
|
226
|
+
expect(mod.suffix).toBe(manifest.suffix);
|
|
227
|
+
// Descriptions may diverge slightly but suffix must match
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
});
|
|
@@ -35,6 +35,10 @@ import { createControlFacadeOps } from '../runtime/facades/control-facade.js';
|
|
|
35
35
|
import { createContextFacadeOps } from '../runtime/facades/context-facade.js';
|
|
36
36
|
import { createAgencyFacadeOps } from '../runtime/facades/agency-facade.js';
|
|
37
37
|
import { createChatFacadeOps } from '../runtime/facades/chat-facade.js';
|
|
38
|
+
import { createOperatorFacadeOps } from '../runtime/facades/operator-facade.js';
|
|
39
|
+
import { createArchiveFacadeOps } from '../runtime/facades/archive-facade.js';
|
|
40
|
+
import { createSyncFacadeOps } from '../runtime/facades/sync-facade.js';
|
|
41
|
+
import { createReviewFacadeOps } from '../runtime/facades/review-facade.js';
|
|
38
42
|
import { createDomainFacade } from '../runtime/domain-ops.js';
|
|
39
43
|
|
|
40
44
|
// ─── Types ────────────────────────────────────────────────────────────
|
|
@@ -84,7 +88,7 @@ interface ModuleDef {
|
|
|
84
88
|
export const ENGINE_MODULES: ModuleDef[] = [
|
|
85
89
|
{
|
|
86
90
|
suffix: 'vault',
|
|
87
|
-
description: 'Knowledge management — search, CRUD, import/export, intake,
|
|
91
|
+
description: 'Knowledge management — search, CRUD, import/export, intake, sharing, linking.',
|
|
88
92
|
createOps: createVaultFacadeOps,
|
|
89
93
|
},
|
|
90
94
|
{
|
|
@@ -120,7 +124,7 @@ export const ENGINE_MODULES: ModuleDef[] = [
|
|
|
120
124
|
{
|
|
121
125
|
suffix: 'orchestrate',
|
|
122
126
|
description:
|
|
123
|
-
'Execution orchestration —
|
|
127
|
+
'Execution orchestration — session start, playbooks, plan/execute/complete.',
|
|
124
128
|
createOps: createOrchestrateFacadeOps,
|
|
125
129
|
},
|
|
126
130
|
{
|
|
@@ -143,6 +147,26 @@ export const ENGINE_MODULES: ModuleDef[] = [
|
|
|
143
147
|
description: 'Chat transport — session management, response chunking, authentication.',
|
|
144
148
|
createOps: createChatFacadeOps,
|
|
145
149
|
},
|
|
150
|
+
{
|
|
151
|
+
suffix: 'operator',
|
|
152
|
+
description: 'Operator profile — personality learning, signals, adaptation.',
|
|
153
|
+
createOps: createOperatorFacadeOps,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
suffix: 'archive',
|
|
157
|
+
description: 'Archival, lifecycle, and knowledge maintenance.',
|
|
158
|
+
createOps: createArchiveFacadeOps,
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
suffix: 'sync',
|
|
162
|
+
description: 'Git, Obsidian, and pack sync operations.',
|
|
163
|
+
createOps: createSyncFacadeOps,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
suffix: 'review',
|
|
167
|
+
description: 'Knowledge review workflow.',
|
|
168
|
+
createOps: createReviewFacadeOps,
|
|
169
|
+
},
|
|
146
170
|
];
|
|
147
171
|
|
|
148
172
|
// ─── Core Registration ────────────────────────────────────────────────
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { classifyError } from './classify.js';
|
|
3
|
+
import { SoleriError, SoleriErrorCode } from './types.js';
|
|
4
|
+
|
|
5
|
+
describe('classifyError', () => {
|
|
6
|
+
describe('passthrough', () => {
|
|
7
|
+
it('should return a SoleriError as-is', () => {
|
|
8
|
+
const original = new SoleriError('already classified', SoleriErrorCode.TIMEOUT);
|
|
9
|
+
const result = classifyError(original);
|
|
10
|
+
expect(result).toBe(original);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('HTTP status classification', () => {
|
|
15
|
+
it('should classify 401 as AUTH', () => {
|
|
16
|
+
const result = classifyError({ status: 401, message: 'Unauthorized' });
|
|
17
|
+
expect(result.code).toBe(SoleriErrorCode.AUTH);
|
|
18
|
+
expect(result.context).toEqual({ httpStatus: 401 });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should classify 403 as AUTH', () => {
|
|
22
|
+
const result = classifyError({ status: 403, message: 'Forbidden' });
|
|
23
|
+
expect(result.code).toBe(SoleriErrorCode.AUTH);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should classify 404 as RESOURCE_NOT_FOUND', () => {
|
|
27
|
+
const result = classifyError({ statusCode: 404, message: 'Not found' });
|
|
28
|
+
expect(result.code).toBe(SoleriErrorCode.RESOURCE_NOT_FOUND);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should classify 408 as TIMEOUT', () => {
|
|
32
|
+
const result = classifyError({ status: 408, message: 'Request Timeout' });
|
|
33
|
+
expect(result.code).toBe(SoleriErrorCode.TIMEOUT);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should classify 429 as RATE_LIMIT', () => {
|
|
37
|
+
const result = classifyError({ status: 429, message: 'Too Many Requests' });
|
|
38
|
+
expect(result.code).toBe(SoleriErrorCode.RATE_LIMIT);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should classify 422 as VALIDATION', () => {
|
|
42
|
+
const result = classifyError({ status: 422, message: 'Unprocessable' });
|
|
43
|
+
expect(result.code).toBe(SoleriErrorCode.VALIDATION);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should classify 500 as INTERNAL', () => {
|
|
47
|
+
const result = classifyError({ status: 500, message: 'Server Error' });
|
|
48
|
+
expect(result.code).toBe(SoleriErrorCode.INTERNAL);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should classify 503 as INTERNAL', () => {
|
|
52
|
+
const result = classifyError({ status: 503, message: 'Service Unavailable' });
|
|
53
|
+
expect(result.code).toBe(SoleriErrorCode.INTERNAL);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should prefer statusCode when status is absent', () => {
|
|
57
|
+
const result = classifyError({ statusCode: 429, message: 'throttled' });
|
|
58
|
+
expect(result.code).toBe(SoleriErrorCode.RATE_LIMIT);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('Node.js error code classification', () => {
|
|
63
|
+
it('should classify ECONNREFUSED as NETWORK', () => {
|
|
64
|
+
const err = Object.assign(new Error('connect failed'), { code: 'ECONNREFUSED' });
|
|
65
|
+
const result = classifyError(err);
|
|
66
|
+
expect(result.code).toBe(SoleriErrorCode.NETWORK);
|
|
67
|
+
expect(result.context).toEqual({ errorCode: 'ECONNREFUSED' });
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should classify ENOTFOUND as NETWORK', () => {
|
|
71
|
+
const err = Object.assign(new Error('dns fail'), { code: 'ENOTFOUND' });
|
|
72
|
+
expect(classifyError(err).code).toBe(SoleriErrorCode.NETWORK);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should classify ECONNRESET as NETWORK', () => {
|
|
76
|
+
const err = Object.assign(new Error('reset'), { code: 'ECONNRESET' });
|
|
77
|
+
expect(classifyError(err).code).toBe(SoleriErrorCode.NETWORK);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should classify ETIMEDOUT as TIMEOUT', () => {
|
|
81
|
+
const err = Object.assign(new Error('timed out'), { code: 'ETIMEDOUT' });
|
|
82
|
+
expect(classifyError(err).code).toBe(SoleriErrorCode.TIMEOUT);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should classify ESOCKETTIMEDOUT as TIMEOUT', () => {
|
|
86
|
+
const err = Object.assign(new Error('socket'), { code: 'ESOCKETTIMEDOUT' });
|
|
87
|
+
expect(classifyError(err).code).toBe(SoleriErrorCode.TIMEOUT);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should classify UND_ERR_CONNECT_TIMEOUT as TIMEOUT', () => {
|
|
91
|
+
const err = Object.assign(new Error('undici'), { code: 'UND_ERR_CONNECT_TIMEOUT' });
|
|
92
|
+
expect(classifyError(err).code).toBe(SoleriErrorCode.TIMEOUT);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('message pattern classification', () => {
|
|
97
|
+
it('should classify "overloaded" as LLM_OVERLOAD', () => {
|
|
98
|
+
expect(classifyError(new Error('server is overloaded')).code).toBe(SoleriErrorCode.LLM_OVERLOAD);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should classify "model busy" as LLM_OVERLOAD', () => {
|
|
102
|
+
expect(classifyError(new Error('model is busy')).code).toBe(SoleriErrorCode.LLM_OVERLOAD);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should classify "timeout" message as TIMEOUT', () => {
|
|
106
|
+
expect(classifyError(new Error('operation timed out')).code).toBe(SoleriErrorCode.TIMEOUT);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should classify "sqlite" as VAULT_UNREACHABLE', () => {
|
|
110
|
+
expect(classifyError(new Error('sqlite error')).code).toBe(SoleriErrorCode.VAULT_UNREACHABLE);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should classify "validation" as VALIDATION', () => {
|
|
114
|
+
expect(classifyError(new Error('validation failed')).code).toBe(SoleriErrorCode.VALIDATION);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should classify "missing key" as CONFIG_ERROR', () => {
|
|
118
|
+
expect(classifyError(new Error('missing key FOO')).code).toBe(SoleriErrorCode.CONFIG_ERROR);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should classify "unauthorized" as AUTH', () => {
|
|
122
|
+
expect(classifyError(new Error('unauthorized access')).code).toBe(SoleriErrorCode.AUTH);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should classify "not found" as RESOURCE_NOT_FOUND', () => {
|
|
126
|
+
expect(classifyError(new Error('resource not found')).code).toBe(SoleriErrorCode.RESOURCE_NOT_FOUND);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should classify "rate limit" as RATE_LIMIT', () => {
|
|
130
|
+
expect(classifyError(new Error('rate limit exceeded')).code).toBe(SoleriErrorCode.RATE_LIMIT);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should classify "network" as NETWORK', () => {
|
|
134
|
+
expect(classifyError(new Error('network failure')).code).toBe(SoleriErrorCode.NETWORK);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe('fallback classification', () => {
|
|
139
|
+
it('should default to INTERNAL for unknown errors', () => {
|
|
140
|
+
const result = classifyError(new Error('something weird'));
|
|
141
|
+
expect(result.code).toBe(SoleriErrorCode.INTERNAL);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should handle string thrown values', () => {
|
|
145
|
+
const result = classifyError('a string error');
|
|
146
|
+
expect(result).toBeInstanceOf(SoleriError);
|
|
147
|
+
expect(result.message).toBe('a string error');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should handle number thrown values', () => {
|
|
151
|
+
const result = classifyError(42);
|
|
152
|
+
expect(result).toBeInstanceOf(SoleriError);
|
|
153
|
+
expect(result.message).toBe('42');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should handle null thrown values', () => {
|
|
157
|
+
const result = classifyError(null);
|
|
158
|
+
expect(result).toBeInstanceOf(SoleriError);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should handle undefined thrown values', () => {
|
|
162
|
+
const result = classifyError(undefined);
|
|
163
|
+
expect(result).toBeInstanceOf(SoleriError);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should handle plain objects with no message', () => {
|
|
167
|
+
const result = classifyError({});
|
|
168
|
+
expect(result).toBeInstanceOf(SoleriError);
|
|
169
|
+
expect(result.message).toBe('Unknown error');
|
|
170
|
+
expect(result.code).toBe(SoleriErrorCode.INTERNAL);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
describe('priority order', () => {
|
|
175
|
+
it('should prefer HTTP status over message pattern', () => {
|
|
176
|
+
const result = classifyError({ status: 404, message: 'network error not found' });
|
|
177
|
+
expect(result.code).toBe(SoleriErrorCode.RESOURCE_NOT_FOUND);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should prefer error code over message pattern', () => {
|
|
181
|
+
const err = Object.assign(new Error('timeout in database'), { code: 'ECONNREFUSED' });
|
|
182
|
+
const result = classifyError(err);
|
|
183
|
+
expect(result.code).toBe(SoleriErrorCode.NETWORK);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe('cause preservation', () => {
|
|
188
|
+
it('should preserve original Error as cause', () => {
|
|
189
|
+
const original = new Error('root');
|
|
190
|
+
const result = classifyError(original);
|
|
191
|
+
expect(result.cause).toBe(original);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should not set cause for non-Error values', () => {
|
|
195
|
+
const result = classifyError('string error');
|
|
196
|
+
expect(result.cause).toBeUndefined();
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
});
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { shouldRetry, getRetryDelay, retryWithPreset, RETRY_PRESETS } from './retry.js';
|
|
3
|
+
import { SoleriError, SoleriErrorCode } from './types.js';
|
|
4
|
+
|
|
5
|
+
describe('RETRY_PRESETS', () => {
|
|
6
|
+
it('should define fast, normal, and patient presets', () => {
|
|
7
|
+
expect(RETRY_PRESETS.fast.maxAttempts).toBe(3);
|
|
8
|
+
expect(RETRY_PRESETS.normal.maxAttempts).toBe(10);
|
|
9
|
+
expect(RETRY_PRESETS.patient.maxAttempts).toBe(25);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe('shouldRetry', () => {
|
|
14
|
+
it('should return true for retryable error below max attempts', () => {
|
|
15
|
+
const error = new SoleriError('timeout', SoleriErrorCode.TIMEOUT);
|
|
16
|
+
expect(shouldRetry(error, 1, 'fast')).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should return false for retryable error at max attempts', () => {
|
|
20
|
+
const error = new SoleriError('timeout', SoleriErrorCode.TIMEOUT);
|
|
21
|
+
expect(shouldRetry(error, 3, 'fast')).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should return false for non-retryable error', () => {
|
|
25
|
+
const error = new SoleriError('bad auth', SoleriErrorCode.AUTH);
|
|
26
|
+
expect(shouldRetry(error, 1, 'fast')).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should return false for fixable error', () => {
|
|
30
|
+
const error = new SoleriError('invalid', SoleriErrorCode.VALIDATION);
|
|
31
|
+
expect(shouldRetry(error, 1, 'normal')).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('getRetryDelay', () => {
|
|
36
|
+
it('should return a positive number', () => {
|
|
37
|
+
const delay = getRetryDelay(0, 'fast');
|
|
38
|
+
expect(delay).toBeGreaterThanOrEqual(0);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should increase with attempt number', () => {
|
|
42
|
+
const delays = Array.from({ length: 5 }, (_, i) => {
|
|
43
|
+
// Average over multiple samples to reduce jitter impact
|
|
44
|
+
const samples = Array.from({ length: 100 }, () => getRetryDelay(i, 'normal'));
|
|
45
|
+
return samples.reduce((a, b) => a + b, 0) / samples.length;
|
|
46
|
+
});
|
|
47
|
+
// Each averaged delay should generally be >= the previous
|
|
48
|
+
for (let i = 1; i < delays.length - 1; i++) {
|
|
49
|
+
expect(delays[i]).toBeGreaterThanOrEqual(delays[i - 1] * 0.5);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should not exceed maxIntervalMs plus jitter', () => {
|
|
54
|
+
const config = RETRY_PRESETS.fast;
|
|
55
|
+
const maxWithJitter = config.maxIntervalMs * 1.25;
|
|
56
|
+
for (let i = 0; i < 20; i++) {
|
|
57
|
+
expect(getRetryDelay(10, 'fast')).toBeLessThanOrEqual(maxWithJitter);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should never return a negative value', () => {
|
|
62
|
+
for (let i = 0; i < 50; i++) {
|
|
63
|
+
expect(getRetryDelay(0, 'fast')).toBeGreaterThanOrEqual(0);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('retryWithPreset', () => {
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
vi.useFakeTimers();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
afterEach(() => {
|
|
74
|
+
vi.useRealTimers();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should return ok on first success', async () => {
|
|
78
|
+
const fn = vi.fn().mockResolvedValue('done');
|
|
79
|
+
const resultPromise = retryWithPreset(fn, 'fast');
|
|
80
|
+
const result = await resultPromise;
|
|
81
|
+
expect(result).toEqual({ ok: true, value: 'done' });
|
|
82
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should retry retryable errors and succeed', async () => {
|
|
86
|
+
const fn = vi
|
|
87
|
+
.fn()
|
|
88
|
+
.mockRejectedValueOnce(new Error('network error'))
|
|
89
|
+
.mockResolvedValue('recovered');
|
|
90
|
+
|
|
91
|
+
const resultPromise = retryWithPreset(fn, 'fast');
|
|
92
|
+
// Advance past the sleep delay
|
|
93
|
+
await vi.advanceTimersByTimeAsync(20_000);
|
|
94
|
+
const result = await resultPromise;
|
|
95
|
+
expect(result).toEqual({ ok: true, value: 'recovered' });
|
|
96
|
+
expect(fn).toHaveBeenCalledTimes(2);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should return err immediately for permanent errors', async () => {
|
|
100
|
+
const fn = vi.fn().mockRejectedValue(new SoleriError('denied', SoleriErrorCode.AUTH));
|
|
101
|
+
const result = await retryWithPreset(fn, 'fast');
|
|
102
|
+
expect(result.ok).toBe(false);
|
|
103
|
+
if (!result.ok) {
|
|
104
|
+
expect(result.error.code).toBe(SoleriErrorCode.AUTH);
|
|
105
|
+
}
|
|
106
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should return err after exhausting all attempts', async () => {
|
|
110
|
+
const fn = vi.fn().mockRejectedValue(new SoleriError('down', SoleriErrorCode.NETWORK));
|
|
111
|
+
const resultPromise = retryWithPreset(fn, 'fast');
|
|
112
|
+
// Advance enough time for all retries
|
|
113
|
+
await vi.advanceTimersByTimeAsync(100_000);
|
|
114
|
+
const result = await resultPromise;
|
|
115
|
+
expect(result.ok).toBe(false);
|
|
116
|
+
expect(fn).toHaveBeenCalledTimes(3);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should call onRetry callback on each retry', async () => {
|
|
120
|
+
const onRetry = vi.fn();
|
|
121
|
+
const fn = vi
|
|
122
|
+
.fn()
|
|
123
|
+
.mockRejectedValueOnce(new Error('network fail'))
|
|
124
|
+
.mockResolvedValue('ok');
|
|
125
|
+
|
|
126
|
+
const resultPromise = retryWithPreset(fn, 'fast', { onRetry });
|
|
127
|
+
await vi.advanceTimersByTimeAsync(20_000);
|
|
128
|
+
await resultPromise;
|
|
129
|
+
expect(onRetry).toHaveBeenCalledTimes(1);
|
|
130
|
+
expect(onRetry).toHaveBeenCalledWith(expect.any(SoleriError), 1, expect.any(Number));
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should abort when signal is aborted during sleep', async () => {
|
|
134
|
+
const controller = new AbortController();
|
|
135
|
+
const fn = vi.fn().mockRejectedValue(new Error('network error'));
|
|
136
|
+
|
|
137
|
+
const resultPromise = retryWithPreset(fn, 'fast', { signal: controller.signal });
|
|
138
|
+
// Let the first attempt fail and enter sleep
|
|
139
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
140
|
+
// Abort during sleep
|
|
141
|
+
controller.abort(new Error('cancelled'));
|
|
142
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
143
|
+
const result = await resultPromise;
|
|
144
|
+
expect(result.ok).toBe(false);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should return err for fixable errors without retrying', async () => {
|
|
148
|
+
const fn = vi.fn().mockRejectedValue(new SoleriError('bad', SoleriErrorCode.VALIDATION));
|
|
149
|
+
const result = await retryWithPreset(fn, 'fast');
|
|
150
|
+
expect(result.ok).toBe(false);
|
|
151
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Need to import afterEach at top level
|
|
156
|
+
import { afterEach } from 'vitest';
|
package/src/errors/retry.ts
CHANGED
|
@@ -104,6 +104,7 @@ export async function retryWithPreset<T>(
|
|
|
104
104
|
|
|
105
105
|
for (let attempt = 0; attempt < RETRY_PRESETS[preset].maxAttempts; attempt++) {
|
|
106
106
|
try {
|
|
107
|
+
// oxlint-disable-next-line eslint(no-await-in-loop)
|
|
107
108
|
const value = await fn();
|
|
108
109
|
return ok(value);
|
|
109
110
|
} catch (thrown: unknown) {
|
|
@@ -117,6 +118,7 @@ export async function retryWithPreset<T>(
|
|
|
117
118
|
options?.onRetry?.(lastError, attempt + 1, delay);
|
|
118
119
|
|
|
119
120
|
try {
|
|
121
|
+
// oxlint-disable-next-line eslint(no-await-in-loop)
|
|
120
122
|
await sleep(delay, options?.signal);
|
|
121
123
|
} catch {
|
|
122
124
|
// Aborted during sleep
|