@vellumai/assistant 0.8.1 → 0.8.3
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/ARCHITECTURE.md +13 -19
- package/Dockerfile +75 -1
- package/bun.lock +11 -1
- package/docker-entrypoint.sh +17 -0
- package/docker-init-apt-root.sh +167 -0
- package/docker-kata-apt-env.sh +39 -0
- package/docs/plugins.md +88 -47
- package/docs/skills.md +9 -7
- package/examples/plugins/echo/README.md +27 -27
- package/examples/plugins/echo/package.json +3 -0
- package/examples/plugins/echo/register.ts +31 -31
- package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
- package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
- package/openapi.yaml +642 -5
- package/package.json +3 -1
- package/scripts/generate-openapi.ts +83 -10
- package/scripts/sync-llm-catalog.ts +2 -2
- package/scripts/sync-web-search-catalog.ts +47 -25
- package/src/__tests__/agent-image-optimize.test.ts +11 -3
- package/src/__tests__/agent-loop-exit-reason.test.ts +272 -0
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
- package/src/__tests__/anthropic-provider.test.ts +45 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
- package/src/__tests__/app-executors.test.ts +220 -4
- package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/channel-availability-routes.test.ts +206 -0
- package/src/__tests__/channel-delivery-store.test.ts +289 -1
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
- package/src/__tests__/clawhub.test.ts +75 -16
- package/src/__tests__/compactor-tail-resolution.test.ts +147 -0
- package/src/__tests__/config-get-vision-flag.test.ts +136 -0
- package/src/__tests__/config-loader-backfill.test.ts +115 -18
- package/src/__tests__/config-schema.test.ts +21 -0
- package/src/__tests__/config-set-route.test.ts +80 -0
- package/src/__tests__/config-sounds-sync.test.ts +97 -0
- package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
- package/src/__tests__/context-search-conversations-source.test.ts +117 -2
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +7 -0
- package/src/__tests__/context-token-estimator.test.ts +31 -65
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +92 -92
- package/src/__tests__/conversation-agent-loop.test.ts +59 -1
- package/src/__tests__/conversation-error.test.ts +42 -3
- package/src/__tests__/conversation-fork-crud.test.ts +82 -0
- package/src/__tests__/conversation-inference-profile-route.test.ts +40 -4
- package/src/__tests__/conversation-lifecycle.test.ts +173 -0
- package/src/__tests__/conversation-media-retry.test.ts +19 -8
- package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
- package/src/__tests__/conversation-pairing.test.ts +54 -0
- package/src/__tests__/conversation-process-callsite.test.ts +4 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
- package/src/__tests__/conversation-queue.test.ts +4 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +102 -13
- package/src/__tests__/conversation-slash-queue.test.ts +59 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
- package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
- package/src/__tests__/conversation-sync-tags.test.ts +235 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-security-invariants.test.ts +3 -2
- package/src/__tests__/date-context.test.ts +45 -0
- package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
- package/src/__tests__/disk-pressure-tools.test.ts +1 -0
- package/src/__tests__/dm-backfill.test.ts +121 -10
- package/src/__tests__/document-tool-security.test.ts +258 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/edit-propagation.test.ts +33 -0
- package/src/__tests__/empty-response-pipeline.test.ts +0 -4
- package/src/__tests__/external-plugin-loader.test.ts +151 -55
- package/src/__tests__/filing-service.test.ts +140 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
- package/src/__tests__/heartbeat-service.test.ts +24 -164
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/helpers/tar-fixtures.ts +39 -0
- package/src/__tests__/helpers/wait-for.ts +21 -0
- package/src/__tests__/history-repair-pipeline.test.ts +0 -3
- package/src/__tests__/history-repair.test.ts +73 -0
- package/src/__tests__/host-app-control-proxy.test.ts +507 -10
- package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
- package/src/__tests__/image-credentials.test.ts +1 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +1 -1
- package/src/__tests__/inference-profile-reaper.test.ts +4 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +18 -6
- package/src/__tests__/inference-profile-session-ipc.test.ts +17 -5
- package/src/__tests__/injector-background-turn.test.ts +153 -0
- package/src/__tests__/injector-chain.test.ts +15 -8
- package/src/__tests__/install-skill-routing.test.ts +155 -37
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +99 -3
- package/src/__tests__/list-messages-page-latest.test.ts +55 -0
- package/src/__tests__/llm-call-pipeline.test.ts +0 -3
- package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +58 -13
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +36 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
- package/src/__tests__/llm-resolver.test.ts +255 -2
- package/src/__tests__/llm-usage-store.test.ts +114 -0
- package/src/__tests__/managed-profile-guard.test.ts +41 -29
- package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
- package/src/__tests__/managed-store.test.ts +84 -192
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
- package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
- package/src/__tests__/notification-decision-fallback.test.ts +0 -91
- package/src/__tests__/notification-decision-strategy.test.ts +14 -31
- package/src/__tests__/notification-deep-link.test.ts +15 -0
- package/src/__tests__/notification-guardian-path.test.ts +1 -2
- package/src/__tests__/notification-platform-adapter.test.ts +5 -4
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
- package/src/__tests__/oauth-commands-routes.test.ts +168 -16
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
- package/src/__tests__/openai-provider.test.ts +242 -3
- package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
- package/src/__tests__/openrouter-provider-only.test.ts +51 -3
- package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
- package/src/__tests__/persistence-pipeline.test.ts +0 -2
- package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +7 -2
- package/src/__tests__/platform.test.ts +2 -0
- package/src/__tests__/plugin-api-shim.test.ts +125 -0
- package/src/__tests__/plugin-bootstrap.test.ts +10 -36
- package/src/__tests__/plugin-external-api.test.ts +68 -0
- package/src/__tests__/plugin-registry.test.ts +0 -77
- package/src/__tests__/plugin-route-contribution.test.ts +0 -1
- package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +16 -15
- package/src/__tests__/plugin-types.test.ts +3 -13
- package/src/__tests__/process-message-background-slack.test.ts +8 -1
- package/src/__tests__/process-message-display-content.test.ts +421 -0
- package/src/__tests__/provider-catalog-visibility.test.ts +158 -0
- package/src/__tests__/provider-error-scenarios.test.ts +111 -0
- package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +33 -31
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
- package/src/__tests__/schedule-routes.test.ts +50 -3
- package/src/__tests__/schedule-store.test.ts +94 -0
- package/src/__tests__/scheduler-reuse-conversation.test.ts +54 -7
- package/src/__tests__/schema-transforms.test.ts +20 -0
- package/src/__tests__/search-skills-unified.test.ts +0 -5
- package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +1 -1
- package/src/__tests__/server-history-render.test.ts +43 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -12
- package/src/__tests__/skill-load-tool.test.ts +27 -89
- package/src/__tests__/skill-memory.test.ts +23 -3
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
- package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
- package/src/__tests__/skills-install-extract.test.ts +49 -38
- package/src/__tests__/skills-install-staging.test.ts +159 -0
- package/src/__tests__/skills-uninstall.test.ts +9 -41
- package/src/__tests__/skills.test.ts +51 -58
- package/src/__tests__/slack-channel-config.test.ts +9 -0
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/system-prompt.test.ts +670 -63
- package/src/__tests__/terminal-tools.test.ts +28 -1
- package/src/__tests__/thread-backfill.test.ts +557 -27
- package/src/__tests__/title-generate-pipeline.test.ts +0 -13
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
- package/src/__tests__/tool-error-pipeline.test.ts +0 -3
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +16 -4
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
- package/src/__tests__/turn-events-store.test.ts +256 -0
- package/src/__tests__/twilio-routes.test.ts +4 -0
- package/src/__tests__/user-plugin-loader.test.ts +0 -7
- package/src/__tests__/voice-session-bridge.test.ts +198 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +32 -10
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +115 -3
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +50 -0
- package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
- package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
- package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
- package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
- package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
- package/src/a2a/__tests__/agent-card.test.ts +98 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
- package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
- package/src/a2a/__tests__/task-store.test.ts +246 -0
- package/src/a2a/agent-card.ts +58 -0
- package/src/a2a/feature-gate.ts +8 -0
- package/src/a2a/protocol-constants.ts +21 -0
- package/src/a2a/protocol-errors.ts +50 -0
- package/src/a2a/protocol-types.ts +162 -0
- package/src/a2a/task-store.ts +168 -0
- package/src/acp/resolve-agent.ts +1 -1
- package/src/agent/image-optimize.ts +13 -5
- package/src/agent/loop.ts +167 -18
- package/src/calls/voice-session-bridge.ts +61 -42
- package/src/channels/config.ts +9 -0
- package/src/channels/types.ts +122 -0
- package/src/cli/__tests__/unknown-command.test.ts +24 -0
- package/src/cli/commands/__tests__/changelog.test.ts +304 -319
- package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
- package/src/cli/commands/__tests__/schedules.test.ts +960 -0
- package/src/cli/commands/changelog.ts +106 -42
- package/src/cli/commands/conversations.ts +102 -17
- package/src/cli/commands/default-action.ts +10 -53
- package/src/cli/commands/notifications.ts +388 -346
- package/src/cli/commands/plugins.ts +252 -0
- package/src/cli/commands/schedules.ts +683 -0
- package/src/cli/commands/telemetry.ts +40 -0
- package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
- package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
- package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
- package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
- package/src/cli/lib/cli-colors.ts +12 -0
- package/src/cli/lib/confirm-prompt.ts +79 -0
- package/src/cli/lib/install-from-github.ts +303 -0
- package/src/cli/lib/list-installed-plugins.ts +137 -0
- package/src/cli/lib/search-plugins.ts +163 -0
- package/src/cli/lib/uninstall-plugin.ts +82 -0
- package/src/cli/lib/unknown-command.ts +111 -0
- package/src/cli/program.ts +52 -2
- package/src/config/assistant-feature-flags.ts +24 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +140 -22
- package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
- package/src/config/bundled-skills/document/SKILL.md +23 -3
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
- package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
- package/src/config/bundled-tool-registry.ts +6 -0
- package/src/config/call-site-defaults.ts +105 -0
- package/src/config/feature-flag-registry.json +41 -9
- package/src/config/llm-resolver.ts +52 -1
- package/src/config/loader.ts +64 -38
- package/src/config/schema.ts +9 -10
- package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +3 -3
- package/src/config/schemas/channels.ts +17 -0
- package/src/config/schemas/compaction.ts +28 -0
- package/src/config/schemas/conversations.ts +10 -0
- package/src/config/schemas/heartbeat.ts +23 -0
- package/src/config/schemas/llm-request-logs.ts +31 -7
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-retrieval.ts +18 -0
- package/src/config/schemas/memory-retrospective.ts +1 -1
- package/src/config/schemas/memory-v2.ts +4 -4
- package/src/config/schemas/memory.ts +3 -1
- package/src/config/schemas/tools.ts +14 -0
- package/src/config/seed-inference-profiles.ts +99 -29
- package/src/config/skills.ts +3 -96
- package/src/context/compactor.ts +1107 -0
- package/src/context/token-estimator.ts +34 -36
- package/src/context/window-manager.ts +197 -1520
- package/src/credential-execution/managed-catalog.ts +37 -0
- package/src/credential-health/credential-health-service.ts +280 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +33 -18
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +74 -0
- package/src/daemon/approval-generators.ts +8 -6
- package/src/daemon/config-watcher.ts +94 -31
- package/src/daemon/conversation-agent-loop-handlers.ts +78 -0
- package/src/daemon/conversation-agent-loop.ts +198 -11
- package/src/daemon/conversation-error.ts +171 -37
- package/src/daemon/conversation-lifecycle.ts +53 -40
- package/src/daemon/conversation-messaging.ts +25 -6
- package/src/daemon/conversation-process.ts +49 -12
- package/src/daemon/conversation-runtime-assembly.ts +25 -1
- package/src/daemon/conversation-slash.ts +12 -5
- package/src/daemon/conversation-store.ts +11 -4
- package/src/daemon/conversation-tool-setup.ts +39 -7
- package/src/daemon/conversation.ts +33 -8
- package/src/daemon/date-context.ts +40 -0
- package/src/daemon/external-plugins-bootstrap.ts +217 -181
- package/src/daemon/first-greeting.ts +22 -2
- package/src/daemon/guardian-action-generators.ts +1 -125
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
- package/src/daemon/handlers/config-a2a.ts +289 -0
- package/src/daemon/handlers/config-model.ts +6 -5
- package/src/daemon/handlers/config-slack-channel.ts +15 -3
- package/src/daemon/handlers/conversations.ts +1 -0
- package/src/daemon/handlers/shared.ts +14 -5
- package/src/daemon/handlers/skills.ts +111 -108
- package/src/daemon/history-repair.ts +28 -1
- package/src/daemon/host-app-control-proxy.ts +153 -27
- package/src/daemon/host-proxy-preactivation.ts +85 -18
- package/src/daemon/lifecycle.ts +89 -91
- package/src/daemon/meet-host-supervisor.ts +5 -4
- package/src/daemon/memory-v2-startup.ts +85 -0
- package/src/daemon/message-protocol.ts +1 -0
- package/src/daemon/message-types/conversations.ts +25 -0
- package/src/daemon/message-types/messages.ts +61 -0
- package/src/daemon/message-types/notifications.ts +21 -0
- package/src/daemon/message-types/subagents.ts +1 -0
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/pkb-reminder-builder.test.ts +11 -54
- package/src/daemon/pkb-reminder-builder.ts +5 -20
- package/src/daemon/plugin-source-watcher.ts +146 -0
- package/src/daemon/process-message.ts +24 -3
- package/src/daemon/server.ts +11 -2
- package/src/daemon/skill-memory-refresh.ts +33 -0
- package/src/daemon/wake-target-adapter.ts +2 -0
- package/src/documents/document-store.ts +221 -3
- package/src/embedded/plugin-api.ts +40 -0
- package/src/export/__tests__/transcript-formatter.test.ts +121 -0
- package/src/export/transcript-formatter.ts +54 -20
- package/src/filing/filing-service.ts +39 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +135 -6
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +73 -189
- package/src/home/__tests__/feed-types.test.ts +80 -0
- package/src/home/feed-types.ts +36 -2
- package/src/home/post-connect-feed.ts +1 -0
- package/src/index.ts +18 -1
- package/src/ipc/cli-client.ts +147 -45
- package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
- package/src/mcp/client.ts +20 -4
- package/src/media/image-credentials.ts +3 -3
- package/src/memory/__tests__/bookmark-crud.test.ts +33 -27
- package/src/memory/__tests__/conversation-queries.test.ts +483 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
- package/src/memory/__tests__/memory-retrospective-job.test.ts +87 -4
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +119 -14
- package/src/memory/__tests__/message-content.test.ts +35 -0
- package/src/memory/bookmark-crud.ts +42 -10
- package/src/memory/context-search/sources/conversations.ts +62 -2
- package/src/memory/context-search/sources/workspace.ts +4 -0
- package/src/memory/conversation-crud.ts +63 -19
- package/src/memory/conversation-queries.ts +197 -11
- package/src/memory/conversation-title-service.ts +26 -4
- package/src/memory/db-init.ts +12 -0
- package/src/memory/delivery-crud.ts +152 -5
- package/src/memory/embedding-backend.ts +4 -4
- package/src/memory/external-conversation-store.ts +66 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +150 -12
- package/src/memory/graph/conversation-graph-memory.ts +49 -21
- package/src/memory/graph/tools.ts +9 -40
- package/src/memory/indexer.ts +34 -29
- package/src/memory/invite-store.ts +53 -0
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +73 -0
- package/src/memory/jobs/embed-concept-page.ts +20 -11
- package/src/memory/jobs-worker.ts +6 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +24 -12
- package/src/memory/llm-request-log-source.ts +19 -52
- package/src/memory/llm-request-log-store.ts +92 -1
- package/src/memory/llm-usage-store.ts +125 -5
- package/src/memory/memory-retrospective-enqueue.ts +1 -20
- package/src/memory/memory-retrospective-job.ts +33 -6
- package/src/memory/memory-retrospective-startup-cleanup.ts +72 -5
- package/src/memory/message-content.ts +1 -1
- package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
- package/src/memory/migrations/229-delete-private-conversations.test.ts +38 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +7 -0
- package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
- package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
- package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
- package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
- package/src/memory/migrations/251-a2a-tasks.ts +49 -0
- package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
- package/src/memory/migrations/index.ts +9 -0
- package/src/memory/migrations/registry.ts +16 -0
- package/src/memory/onboarding-events-store.ts +106 -0
- package/src/memory/schema/a2a.ts +15 -0
- package/src/memory/schema/bookmarks.ts +0 -2
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/inference.ts +3 -3
- package/src/memory/schema/infrastructure.ts +13 -0
- package/src/memory/turn-events-store.ts +127 -2
- package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
- package/src/memory/v2/__tests__/activation.test.ts +0 -8
- package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
- package/src/memory/v2/__tests__/injection.test.ts +288 -11
- package/src/memory/v2/__tests__/migration.test.ts +87 -0
- package/src/memory/v2/__tests__/page-index.test.ts +83 -0
- package/src/memory/v2/__tests__/prompts-router.test.ts +58 -6
- package/src/memory/v2/__tests__/qdrant.test.ts +66 -3
- package/src/memory/v2/__tests__/router.test.ts +15 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +387 -8
- package/src/memory/v2/__tests__/static-context.test.ts +12 -1
- package/src/memory/v2/activation-store.ts +14 -16
- package/src/memory/v2/cli-command-content.ts +19 -0
- package/src/memory/v2/cli-command-store.ts +304 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -1
- package/src/memory/v2/injection.ts +81 -26
- package/src/memory/v2/migration.ts +49 -19
- package/src/memory/v2/page-index.ts +63 -8
- package/src/memory/v2/prompts/router.ts +11 -8
- package/src/memory/v2/prompts/sweep.ts +2 -2
- package/src/memory/v2/qdrant.ts +135 -7
- package/src/memory/v2/router.ts +9 -8
- package/src/memory/v2/skill-store.ts +120 -35
- package/src/memory/v2/static-context.ts +4 -4
- package/src/memory/v2/types.ts +23 -0
- package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
- package/src/messaging/providers/a2a/deliver.ts +156 -0
- package/src/messaging/providers/gmail/client.ts +9 -2
- package/src/messaging/providers/index.ts +11 -2
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
- package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
- package/src/messaging/providers/slack/adapter.ts +43 -5
- package/src/messaging/providers/slack/client.ts +27 -0
- package/src/messaging/providers/slack/deep-link.ts +65 -0
- package/src/messaging/providers/slack/download.ts +104 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
- package/src/messaging/providers/slack/message-metadata.ts +27 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
- package/src/messaging/providers/slack/render-transcript.ts +69 -5
- package/src/messaging/providers/slack/types.ts +20 -1
- package/src/notifications/__tests__/broadcaster.test.ts +203 -0
- package/src/notifications/__tests__/decision-engine.test.ts +283 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +430 -7
- package/src/notifications/adapters/macos.ts +12 -2
- package/src/notifications/broadcaster.ts +29 -4
- package/src/notifications/conversation-pairing.ts +2 -1
- package/src/notifications/copy-composer.ts +17 -64
- package/src/notifications/decision-engine.ts +113 -45
- package/src/notifications/deterministic-checks.ts +96 -0
- package/src/notifications/emit-signal.ts +21 -1
- package/src/notifications/home-feed-side-effect.ts +138 -5
- package/src/notifications/signal.ts +3 -5
- package/src/notifications/types.ts +8 -0
- package/src/oauth/connection-resolver.ts +8 -4
- package/src/oauth/platform-connection.test.ts +43 -3
- package/src/oauth/platform-connection.ts +19 -6
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/checker.ts +2 -0
- package/src/permissions/ipc-risk-types.ts +1 -0
- package/src/permissions/question-prompter.test.ts +416 -0
- package/src/permissions/question-prompter.ts +294 -0
- package/src/platform/client.test.ts +1 -1
- package/src/platform/client.ts +1 -1
- package/src/plugin-api/constants.ts +26 -0
- package/src/plugin-api/index.ts +34 -1
- package/src/plugin-api/types.ts +104 -22
- package/src/plugins/defaults/circuit-breaker.ts +0 -5
- package/src/plugins/defaults/compaction.ts +0 -4
- package/src/plugins/defaults/empty-response.ts +0 -2
- package/src/plugins/defaults/history-repair.ts +0 -2
- package/src/plugins/defaults/injectors.ts +74 -22
- package/src/plugins/defaults/llm-call.ts +0 -2
- package/src/plugins/defaults/memory-retrieval.ts +0 -1
- package/src/plugins/defaults/overflow-reduce.ts +0 -1
- package/src/plugins/defaults/persistence.ts +0 -2
- package/src/plugins/defaults/title-generate.ts +0 -5
- package/src/plugins/defaults/token-estimate.ts +0 -2
- package/src/plugins/defaults/tool-error.ts +0 -7
- package/src/plugins/defaults/tool-execute.ts +0 -2
- package/src/plugins/defaults/tool-result-truncate.ts +0 -4
- package/src/plugins/ensure-plugin-api-shim.ts +96 -0
- package/src/plugins/external-api.ts +104 -0
- package/src/plugins/external-plugin-loader.ts +187 -42
- package/src/plugins/feature-gate.ts +22 -0
- package/src/plugins/pipeline.ts +37 -0
- package/src/plugins/registry.ts +48 -80
- package/src/plugins/types.ts +40 -26
- package/src/plugins/user-loader.ts +21 -2
- package/src/proactive-artifact/aux-message-injector.ts +11 -0
- package/src/proactive-artifact/job.test.ts +37 -5
- package/src/prompts/__tests__/system-prompt.test.ts +10 -43
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +95 -0
- package/src/prompts/normalize-onboarding.ts +27 -0
- package/src/prompts/sections.ts +302 -0
- package/src/prompts/system-prompt.ts +63 -174
- package/src/prompts/templates/BOOTSTRAP.md +17 -1
- package/src/prompts/templates/system-sections.ts +164 -0
- package/src/providers/__tests__/inference.test.ts +24 -7
- package/src/providers/anthropic/client.ts +28 -28
- package/src/providers/call-site-routing.ts +24 -6
- package/src/providers/connection-resolution.ts +68 -11
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
- package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
- package/src/providers/inference/adapter-factory.ts +32 -6
- package/src/providers/inference/auth.ts +12 -0
- package/src/providers/inference/backfill.ts +14 -1
- package/src/providers/inference/connections.ts +159 -34
- package/src/providers/inference/resolve-auth.ts +14 -4
- package/src/providers/model-catalog.ts +249 -12
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
- package/src/providers/openai/chat-completions-provider.ts +169 -8
- package/src/providers/openrouter/client.ts +49 -4
- package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -2
- package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
- package/src/providers/provider-availability.ts +17 -2
- package/src/providers/provider-catalog-visibility.ts +38 -0
- package/src/providers/provider-send-message.ts +27 -12
- package/src/providers/registry.ts +52 -15
- package/src/providers/retry.ts +47 -1
- package/src/runtime/__tests__/agent-wake.test.ts +152 -0
- package/src/runtime/agent-wake.ts +103 -15
- package/src/runtime/auth/route-policy.ts +21 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/http-server.ts +7 -16
- package/src/runtime/http-types.ts +19 -47
- package/src/runtime/migrations/origin-mode.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +17 -0
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +172 -23
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
- package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +64 -1
- package/src/runtime/routes/acp-routes-list.test.ts +143 -0
- package/src/runtime/routes/acp-routes.ts +5 -3
- package/src/runtime/routes/auth-routes.ts +1 -1
- package/src/runtime/routes/bookmark-routes.ts +5 -3
- package/src/runtime/routes/btw-routes.ts +5 -1
- package/src/runtime/routes/channel-availability-routes.ts +126 -0
- package/src/runtime/routes/consolidation-routes.ts +100 -0
- package/src/runtime/routes/conversation-cli-routes.ts +44 -3
- package/src/runtime/routes/conversation-list-routes.ts +3 -20
- package/src/runtime/routes/conversation-management-routes.ts +17 -42
- package/src/runtime/routes/conversation-query-routes.ts +99 -35
- package/src/runtime/routes/conversation-routes.ts +97 -11
- package/src/runtime/routes/documents-routes.ts +25 -86
- package/src/runtime/routes/group-routes.ts +5 -0
- package/src/runtime/routes/inbound-conversation.ts +28 -8
- package/src/runtime/routes/inbound-message-handler.ts +236 -41
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +111 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +32 -1
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
- package/src/runtime/routes/index.ts +8 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +17 -44
- package/src/runtime/routes/inference-profile-session-reaper.ts +7 -21
- package/src/runtime/routes/inference-provider-connection-routes.ts +199 -22
- package/src/runtime/routes/integrations/a2a.ts +235 -0
- package/src/runtime/routes/integrations/slack/share.ts +4 -52
- package/src/runtime/routes/integrations/slack/token.ts +43 -0
- package/src/runtime/routes/integrations/twilio.ts +6 -13
- package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
- package/src/runtime/routes/notification-routes.ts +1 -1
- package/src/runtime/routes/oauth-commands-routes.ts +105 -15
- package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
- package/src/runtime/routes/question-routes.ts +259 -0
- package/src/runtime/routes/rename-conversation-routes.ts +2 -33
- package/src/runtime/routes/schedule-routes.ts +4 -7
- package/src/runtime/routes/subagents-routes.ts +98 -18
- package/src/runtime/routes/telemetry-routes.ts +27 -0
- package/src/runtime/routes/tts-routes.ts +27 -2
- package/src/runtime/routes/workspace-routes.test.ts +43 -0
- package/src/runtime/routes/workspace-routes.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +39 -7
- package/src/runtime/sync/resource-sync-events.ts +93 -1
- package/src/schedule/schedule-store.ts +27 -2
- package/src/schedule/scheduler.ts +9 -1
- package/src/security/__tests__/untrusted-content.test.ts +86 -0
- package/src/security/untrusted-content.ts +93 -8
- package/src/skills/catalog-files.ts +1 -1
- package/src/skills/catalog-install.ts +233 -116
- package/src/skills/clawhub.ts +70 -13
- package/src/skills/managed-store.ts +4 -119
- package/src/skills/skillssh-registry.ts +27 -48
- package/src/subagent/manager.ts +17 -7
- package/src/telemetry/types.ts +113 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
- package/src/telemetry/usage-telemetry-reporter.ts +113 -7
- package/src/tools/apps/executors.ts +58 -7
- package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
- package/src/tools/ask-question/ask-question-tool.ts +304 -0
- package/src/tools/browser/browser-execution.ts +15 -11
- package/src/tools/computer-use/definitions.ts +3 -3
- package/src/tools/credentials/vault.ts +1 -1
- package/src/tools/document/document-tool.ts +124 -1
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +5 -2
- package/src/tools/host-filesystem/transfer.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +1 -1
- package/src/tools/memory/register.ts +1 -9
- package/src/tools/permission-checker.ts +1 -1
- package/src/tools/registry.ts +17 -7
- package/src/tools/schedule/create.ts +2 -2
- package/src/tools/schema-transforms.ts +7 -2
- package/src/tools/side-effects.ts +1 -0
- package/src/tools/skills/delete-managed.ts +4 -4
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/scaffold-managed.ts +3 -2
- package/src/tools/subagent/notify-parent.ts +1 -1
- package/src/tools/system/request-permission.ts +2 -2
- package/src/tools/terminal/safe-env.ts +60 -1
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/types.ts +107 -21
- package/src/tools/ui-surface/definitions.ts +6 -5
- package/src/tts/__tests__/provider-adapters.test.ts +76 -2
- package/src/tts/providers/elevenlabs-provider.ts +75 -1
- package/src/types/onboarding-context.ts +2 -0
- package/src/util/errors.ts +17 -0
- package/src/util/platform.ts +10 -0
- package/src/watcher/__tests__/engine.test.ts +22 -0
- package/src/watcher/engine.ts +6 -2
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +80 -15
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +35 -22
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +3 -1
- package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
- package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
- package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
- package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/workspace/migrations/runner.ts +39 -9
- package/src/workspace/migrations/types.ts +4 -0
- package/examples/plugins/echo/bun.lock +0 -25
- package/src/__tests__/context-window-manager.test.ts +0 -2481
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
- package/src/context/__tests__/compact-prompt.test.ts +0 -63
- package/src/context/prompts/compact.md +0 -26
- package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
- package/src/runtime/guardian-action-conversation-turn.ts +0 -99
|
@@ -70,8 +70,6 @@ describe("loadExternalPlugin — manifest", () => {
|
|
|
70
70
|
);
|
|
71
71
|
expect(registered).toBeDefined();
|
|
72
72
|
expect(registered?.manifest.version).toBe("1.2.3");
|
|
73
|
-
// Defaults to pluginRuntime v1 when no `vellum.requires` is set.
|
|
74
|
-
expect(registered?.manifest.requires).toEqual({ pluginRuntime: "v1" });
|
|
75
73
|
});
|
|
76
74
|
|
|
77
75
|
test("strips npm scope from name", async () => {
|
|
@@ -97,56 +95,84 @@ describe("loadExternalPlugin — manifest", () => {
|
|
|
97
95
|
);
|
|
98
96
|
expect(registered?.manifest.version).toBe("0.0.0");
|
|
99
97
|
});
|
|
98
|
+
});
|
|
100
99
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const dir = freshPluginDir("custom-requires");
|
|
100
|
+
describe("loadExternalPlugin — plugin-api peerDependency", () => {
|
|
101
|
+
// Tests anchor against assistantPkg.version (read from the assistant's
|
|
102
|
+
// own package.json) so the matrix below stays correct across version
|
|
103
|
+
// bumps. Constructing a range from the live version + nudging up/down
|
|
104
|
+
// by one keeps the satisfy/un-satisfy cases honest.
|
|
105
|
+
test("loads when peerDependency range satisfies assistant version", async () => {
|
|
106
|
+
const dir = freshPluginDir("compat-ok");
|
|
109
107
|
writePackageJson(dir, {
|
|
110
|
-
name: "
|
|
108
|
+
name: "compat-ok",
|
|
111
109
|
version: "0.1.0",
|
|
112
|
-
|
|
110
|
+
peerDependencies: { "@vellumai/plugin-api": "*" },
|
|
113
111
|
});
|
|
114
112
|
|
|
115
113
|
await loadExternalPlugin(dir);
|
|
116
114
|
|
|
117
|
-
|
|
118
|
-
(p) => p.manifest.name === "custom-requires",
|
|
119
|
-
);
|
|
120
|
-
expect(registered?.manifest.requires).toEqual({ pluginRuntime: "v1" });
|
|
115
|
+
expect(registeredNames()).toContain("compat-ok");
|
|
121
116
|
});
|
|
122
117
|
|
|
123
|
-
test("
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
const dir = freshPluginDir("
|
|
118
|
+
test("loads plugin whose peerDependency range excludes assistant version (logs error)", async () => {
|
|
119
|
+
// The host-compat gate is soft while the installation flow is in
|
|
120
|
+
// flux — an unsatisfied range produces a `log.error` but the
|
|
121
|
+
// plugin still loads. Once installation settles, this case should
|
|
122
|
+
// harden back into a hard reject.
|
|
123
|
+
const dir = freshPluginDir("compat-bad");
|
|
129
124
|
writePackageJson(dir, {
|
|
130
|
-
name: "
|
|
125
|
+
name: "compat-bad",
|
|
131
126
|
version: "0.1.0",
|
|
132
|
-
|
|
127
|
+
// A range that no real assistant version will satisfy.
|
|
128
|
+
peerDependencies: { "@vellumai/plugin-api": ">=999.0.0" },
|
|
133
129
|
});
|
|
134
130
|
|
|
135
131
|
await loadExternalPlugin(dir);
|
|
136
132
|
|
|
137
|
-
expect(registeredNames()).
|
|
133
|
+
expect(registeredNames()).toContain("compat-bad");
|
|
138
134
|
});
|
|
139
135
|
|
|
140
|
-
test("
|
|
141
|
-
|
|
142
|
-
|
|
136
|
+
test("loads plugin whose peerDependency range is unparseable (logs error)", async () => {
|
|
137
|
+
// Same soft-gate rationale as the excluded-range case above.
|
|
138
|
+
const dir = freshPluginDir("compat-bogus");
|
|
139
|
+
writePackageJson(dir, {
|
|
140
|
+
name: "compat-bogus",
|
|
141
|
+
version: "0.1.0",
|
|
142
|
+
peerDependencies: { "@vellumai/plugin-api": "not-a-real-range" },
|
|
143
|
+
});
|
|
143
144
|
|
|
144
145
|
await loadExternalPlugin(dir);
|
|
145
146
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
expect(registeredNames()).toContain("compat-bogus");
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("loads with warning when no peerDependency on plugin-api is declared", async () => {
|
|
151
|
+
// Absent peerDep is non-fatal — the loader logs a warn and proceeds
|
|
152
|
+
// with no host-compat claim. The convention is opt-in while the
|
|
153
|
+
// plugin-api framework is experimental.
|
|
154
|
+
const dir = freshPluginDir("compat-absent");
|
|
155
|
+
writePackageJson(dir, {
|
|
156
|
+
name: "compat-absent",
|
|
157
|
+
version: "0.1.0",
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
await loadExternalPlugin(dir);
|
|
161
|
+
|
|
162
|
+
expect(registeredNames()).toContain("compat-absent");
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("loads with warning when peerDependencies is present but lacks plugin-api key", async () => {
|
|
166
|
+
const dir = freshPluginDir("compat-other-peer");
|
|
167
|
+
writePackageJson(dir, {
|
|
168
|
+
name: "compat-other-peer",
|
|
169
|
+
version: "0.1.0",
|
|
170
|
+
peerDependencies: { react: "^18.0.0" },
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
await loadExternalPlugin(dir);
|
|
174
|
+
|
|
175
|
+
expect(registeredNames()).toContain("compat-other-peer");
|
|
150
176
|
});
|
|
151
177
|
|
|
152
178
|
test("malformed package.json is logged and skipped (registry untouched)", async () => {
|
|
@@ -197,9 +223,9 @@ describe("loadExternalPlugin — hooks", () => {
|
|
|
197
223
|
);
|
|
198
224
|
expect(typeof registered?.hooks?.init).toBe("function");
|
|
199
225
|
await registered?.hooks?.init?.({} as never);
|
|
200
|
-
expect(
|
|
201
|
-
|
|
202
|
-
)
|
|
226
|
+
expect((globalThis as Record<string, unknown>).__externalInitCalled).toBe(
|
|
227
|
+
true,
|
|
228
|
+
);
|
|
203
229
|
delete (globalThis as Record<string, unknown>).__externalInitCalled;
|
|
204
230
|
});
|
|
205
231
|
|
|
@@ -264,9 +290,9 @@ describe("loadExternalPlugin — hooks", () => {
|
|
|
264
290
|
expect(Object.keys(registered?.hooks ?? {})).toEqual(["init"]);
|
|
265
291
|
expect(typeof registered?.hooks?.init).toBe("function");
|
|
266
292
|
await registered?.hooks?.init?.({} as never);
|
|
267
|
-
expect(
|
|
268
|
-
|
|
269
|
-
);
|
|
293
|
+
expect(
|
|
294
|
+
(globalThis as Record<string, unknown>).__externalDtsInitCalled,
|
|
295
|
+
).toBe(true);
|
|
270
296
|
delete (globalThis as Record<string, unknown>).__externalDtsInitCalled;
|
|
271
297
|
});
|
|
272
298
|
|
|
@@ -319,11 +345,9 @@ describe("loadExternalPlugin — tools", () => {
|
|
|
319
345
|
dir,
|
|
320
346
|
"tools/alpha.ts",
|
|
321
347
|
`export default {
|
|
322
|
-
name: "two_tools_alpha",
|
|
323
348
|
description: "alpha",
|
|
324
|
-
category: "plugin",
|
|
325
349
|
defaultRiskLevel: "low" as const,
|
|
326
|
-
|
|
350
|
+
input_schema: { type: "object", properties: {}, required: [] },
|
|
327
351
|
async execute() { return { content: "a", isError: false }; },
|
|
328
352
|
};
|
|
329
353
|
`,
|
|
@@ -332,11 +356,9 @@ describe("loadExternalPlugin — tools", () => {
|
|
|
332
356
|
dir,
|
|
333
357
|
"tools/beta.ts",
|
|
334
358
|
`export default {
|
|
335
|
-
name: "two_tools_beta",
|
|
336
359
|
description: "beta",
|
|
337
|
-
category: "plugin",
|
|
338
360
|
defaultRiskLevel: "low" as const,
|
|
339
|
-
|
|
361
|
+
input_schema: { type: "object", properties: {}, required: [] },
|
|
340
362
|
async execute() { return { content: "b", isError: false }; },
|
|
341
363
|
};
|
|
342
364
|
`,
|
|
@@ -350,7 +372,7 @@ describe("loadExternalPlugin — tools", () => {
|
|
|
350
372
|
const names = (registered?.tools ?? []).map(
|
|
351
373
|
(t) => (t as { name: string }).name,
|
|
352
374
|
);
|
|
353
|
-
expect(names).toEqual(["
|
|
375
|
+
expect(names).toEqual(["alpha", "beta"]);
|
|
354
376
|
});
|
|
355
377
|
|
|
356
378
|
test("plugin.tools is undefined when tools/ is absent", async () => {
|
|
@@ -379,18 +401,95 @@ describe("loadExternalPlugin — tools", () => {
|
|
|
379
401
|
expect(registeredNames()).toHaveLength(0);
|
|
380
402
|
});
|
|
381
403
|
|
|
382
|
-
test("a tool default export missing
|
|
383
|
-
const dir = freshPluginDir("tool-
|
|
384
|
-
writePackageJson(dir, { name: "tool-
|
|
404
|
+
test("a tool default export with missing fields loads with documented defaults", async () => {
|
|
405
|
+
const dir = freshPluginDir("tool-with-defaults");
|
|
406
|
+
writePackageJson(dir, { name: "tool-with-defaults", version: "0.1.0" });
|
|
407
|
+
// The default export is a bare empty object — no description,
|
|
408
|
+
// defaultRiskLevel, input_schema, or execute. The loader must fill
|
|
409
|
+
// each slot with its documented default and still register the plugin.
|
|
410
|
+
writeSurfaceFile(dir, "tools/empty.ts", `export default {};\n`);
|
|
411
|
+
|
|
412
|
+
await loadExternalPlugin(dir);
|
|
413
|
+
|
|
414
|
+
const registered = getRegisteredPlugins().find(
|
|
415
|
+
(p) => p.manifest.name === "tool-with-defaults",
|
|
416
|
+
);
|
|
417
|
+
expect(registered).toBeDefined();
|
|
418
|
+
const tools = (registered?.tools ?? []) as Array<{
|
|
419
|
+
name: string;
|
|
420
|
+
description: string;
|
|
421
|
+
defaultRiskLevel: string;
|
|
422
|
+
input_schema: Record<string, unknown>;
|
|
423
|
+
execute: (
|
|
424
|
+
input: Record<string, unknown>,
|
|
425
|
+
context: unknown,
|
|
426
|
+
) => Promise<{ content: string; isError: boolean }>;
|
|
427
|
+
}>;
|
|
428
|
+
expect(tools).toHaveLength(1);
|
|
429
|
+
const empty = tools[0]!;
|
|
430
|
+
expect(empty.name).toBe("empty");
|
|
431
|
+
expect(empty.description).toBe("");
|
|
432
|
+
expect(empty.defaultRiskLevel).toBe("medium");
|
|
433
|
+
expect(empty.input_schema).toEqual({
|
|
434
|
+
type: "object",
|
|
435
|
+
properties: {},
|
|
436
|
+
additionalProperties: false,
|
|
437
|
+
});
|
|
438
|
+
expect(typeof empty.execute).toBe("function");
|
|
439
|
+
|
|
440
|
+
const result = await empty.execute({}, {} as unknown);
|
|
441
|
+
expect(result.isError).toBe(true);
|
|
442
|
+
expect(result.content).toContain("empty");
|
|
443
|
+
expect(result.content).toContain("no execute implementation");
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
test("a partial tool default export merges author fields with defaults", async () => {
|
|
447
|
+
const dir = freshPluginDir("tool-partial-defaults");
|
|
448
|
+
writePackageJson(dir, {
|
|
449
|
+
name: "tool-partial-defaults",
|
|
450
|
+
version: "0.1.0",
|
|
451
|
+
});
|
|
452
|
+
// Author supplies only description + execute; the loader must default
|
|
453
|
+
// defaultRiskLevel and input_schema while keeping the author's fields.
|
|
385
454
|
writeSurfaceFile(
|
|
386
455
|
dir,
|
|
387
|
-
"tools/
|
|
388
|
-
`export default {
|
|
456
|
+
"tools/partial.ts",
|
|
457
|
+
`export default {
|
|
458
|
+
description: "custom description",
|
|
459
|
+
async execute() {
|
|
460
|
+
return { content: "ran", isError: false };
|
|
461
|
+
},
|
|
462
|
+
};
|
|
463
|
+
`,
|
|
389
464
|
);
|
|
390
465
|
|
|
391
466
|
await loadExternalPlugin(dir);
|
|
392
467
|
|
|
393
|
-
|
|
468
|
+
const registered = getRegisteredPlugins().find(
|
|
469
|
+
(p) => p.manifest.name === "tool-partial-defaults",
|
|
470
|
+
);
|
|
471
|
+
const tool = (registered?.tools ?? [])[0] as
|
|
472
|
+
| {
|
|
473
|
+
description: string;
|
|
474
|
+
defaultRiskLevel: string;
|
|
475
|
+
input_schema: object;
|
|
476
|
+
execute: (
|
|
477
|
+
input: Record<string, unknown>,
|
|
478
|
+
context: unknown,
|
|
479
|
+
) => Promise<{ content: string; isError: boolean }>;
|
|
480
|
+
}
|
|
481
|
+
| undefined;
|
|
482
|
+
expect(tool).toBeDefined();
|
|
483
|
+
expect(tool?.description).toBe("custom description");
|
|
484
|
+
expect(tool?.defaultRiskLevel).toBe("medium");
|
|
485
|
+
expect(tool?.input_schema).toEqual({
|
|
486
|
+
type: "object",
|
|
487
|
+
properties: {},
|
|
488
|
+
additionalProperties: false,
|
|
489
|
+
});
|
|
490
|
+
const result = await tool!.execute({}, {} as unknown);
|
|
491
|
+
expect(result.isError).toBe(false);
|
|
492
|
+
expect(result.content).toBe("ran");
|
|
394
493
|
});
|
|
395
494
|
});
|
|
396
495
|
|
|
@@ -450,9 +549,6 @@ describe("loadExternalPlugin — end-to-end @vellumai/simple-memory", () => {
|
|
|
450
549
|
const toolNames = (registered?.tools ?? [])
|
|
451
550
|
.map((t) => (t as { name: string }).name)
|
|
452
551
|
.sort();
|
|
453
|
-
expect(toolNames).toEqual([
|
|
454
|
-
"simple_memory_recall",
|
|
455
|
-
"simple_memory_remember",
|
|
456
|
-
]);
|
|
552
|
+
expect(toolNames).toEqual(["recall", "remember"]);
|
|
457
553
|
});
|
|
458
554
|
});
|
|
@@ -303,6 +303,146 @@ describe("FilingService", () => {
|
|
|
303
303
|
expect(processMessageCalls).toHaveLength(1);
|
|
304
304
|
});
|
|
305
305
|
|
|
306
|
+
// Helpers for the compaction-retry tests: hold the filing run open by
|
|
307
|
+
// making processMessage return a manually-resolved promise, so `activeRun`
|
|
308
|
+
// stays set and runCompactionOnce() sees the contention path.
|
|
309
|
+
function holdFilingRun(): {
|
|
310
|
+
release: () => void;
|
|
311
|
+
filingCalls: () => number;
|
|
312
|
+
compactionCalls: () => number;
|
|
313
|
+
waitForFilingStarted: () => Promise<void>;
|
|
314
|
+
} {
|
|
315
|
+
let release: (() => void) | undefined;
|
|
316
|
+
let started = false;
|
|
317
|
+
let filingCalls = 0;
|
|
318
|
+
let compactionCalls = 0;
|
|
319
|
+
|
|
320
|
+
setTestProcessMessage((...args: unknown[]) => {
|
|
321
|
+
const callSite = (args[3] as { callSite?: string } | undefined)
|
|
322
|
+
?.callSite;
|
|
323
|
+
if (callSite === "filingAgent") {
|
|
324
|
+
filingCalls += 1;
|
|
325
|
+
started = true;
|
|
326
|
+
return new Promise((resolve) => {
|
|
327
|
+
release = () => resolve({ messageId: "filing-done" });
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
if (callSite === "compactionAgent") {
|
|
331
|
+
compactionCalls += 1;
|
|
332
|
+
}
|
|
333
|
+
return Promise.resolve({ messageId: "mock" });
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
release: () => release?.(),
|
|
338
|
+
filingCalls: () => filingCalls,
|
|
339
|
+
compactionCalls: () => compactionCalls,
|
|
340
|
+
waitForFilingStarted: async () => {
|
|
341
|
+
while (!started) await Promise.resolve();
|
|
342
|
+
},
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
test("schedules a near-term retry when filing run is in-flight", async () => {
|
|
347
|
+
const hold = holdFilingRun();
|
|
348
|
+
// 5s retry override paired with a production-realistic 24h compaction
|
|
349
|
+
// interval — the assertion proves retry << interval.
|
|
350
|
+
const retryMs = 5_000;
|
|
351
|
+
mockConfig.filing.compactionIntervalMs = 24 * 60 * 60 * 1000;
|
|
352
|
+
const service = new FilingService({
|
|
353
|
+
compactionContendedRetryMs: retryMs,
|
|
354
|
+
});
|
|
355
|
+
const filingPromise = service.runOnce();
|
|
356
|
+
await hold.waitForFilingStarted();
|
|
357
|
+
|
|
358
|
+
const beforeRetry = Date.now();
|
|
359
|
+
const ran = await service.runCompactionOnce();
|
|
360
|
+
|
|
361
|
+
expect(ran).toBe(false);
|
|
362
|
+
expect(service.nextCompactionAt).not.toBeNull();
|
|
363
|
+
const nextAt = service.nextCompactionAt!;
|
|
364
|
+
expect(nextAt - beforeRetry).toBeLessThan(
|
|
365
|
+
mockConfig.filing.compactionIntervalMs,
|
|
366
|
+
);
|
|
367
|
+
expect(nextAt - beforeRetry).toBeLessThanOrEqual(retryMs + 100);
|
|
368
|
+
|
|
369
|
+
hold.release();
|
|
370
|
+
await filingPromise;
|
|
371
|
+
await service.stop();
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
test("retry fires after filing run completes", async () => {
|
|
375
|
+
const hold = holdFilingRun();
|
|
376
|
+
const service = new FilingService({ compactionContendedRetryMs: 1 });
|
|
377
|
+
const filingPromise = service.runOnce();
|
|
378
|
+
await hold.waitForFilingStarted();
|
|
379
|
+
|
|
380
|
+
const skipped = await service.runCompactionOnce();
|
|
381
|
+
expect(skipped).toBe(false);
|
|
382
|
+
expect(hold.compactionCalls()).toBe(0);
|
|
383
|
+
|
|
384
|
+
hold.release();
|
|
385
|
+
await filingPromise;
|
|
386
|
+
|
|
387
|
+
const start = Date.now();
|
|
388
|
+
while (hold.compactionCalls() === 0 && Date.now() - start < 1000) {
|
|
389
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
expect(hold.filingCalls()).toBe(1);
|
|
393
|
+
expect(hold.compactionCalls()).toBe(1);
|
|
394
|
+
|
|
395
|
+
await service.stop();
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
test("stop() clears a scheduled compaction retry", async () => {
|
|
399
|
+
const hold = holdFilingRun();
|
|
400
|
+
const service = new FilingService({ compactionContendedRetryMs: 50 });
|
|
401
|
+
const filingPromise = service.runOnce();
|
|
402
|
+
await hold.waitForFilingStarted();
|
|
403
|
+
await service.runCompactionOnce();
|
|
404
|
+
expect(service.nextCompactionAt).not.toBeNull();
|
|
405
|
+
|
|
406
|
+
hold.release();
|
|
407
|
+
await filingPromise;
|
|
408
|
+
await service.stop();
|
|
409
|
+
|
|
410
|
+
// After stop, the retry timer must be cleared and never fire.
|
|
411
|
+
expect(service.nextCompactionAt).toBeNull();
|
|
412
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
413
|
+
expect(hold.compactionCalls()).toBe(0);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
test("stop() prevents retry callback from re-arming a fresh timer", async () => {
|
|
417
|
+
// Race: the retry callback fires while filing is still in-flight and
|
|
418
|
+
// stop() has begun. The callback already cleared compactionRetryTimer,
|
|
419
|
+
// so clearCompactionRetry is a no-op. Without a stopped flag, the
|
|
420
|
+
// callback's runCompactionOnce() hits the activeRun branch and schedules
|
|
421
|
+
// a fresh retry, leaving a live timer after stop() resolves.
|
|
422
|
+
const hold = holdFilingRun();
|
|
423
|
+
const service = new FilingService({ compactionContendedRetryMs: 5 });
|
|
424
|
+
const filingPromise = service.runOnce();
|
|
425
|
+
await hold.waitForFilingStarted();
|
|
426
|
+
await service.runCompactionOnce();
|
|
427
|
+
expect(service.nextCompactionAt).not.toBeNull();
|
|
428
|
+
|
|
429
|
+
// Begin stop without awaiting — it would block on the held filing run.
|
|
430
|
+
// stop() flips `stopped` synchronously before the retry timer fires.
|
|
431
|
+
const stopPromise = service.stop();
|
|
432
|
+
|
|
433
|
+
// Wait past the retry delay. Without the guard, the callback would call
|
|
434
|
+
// runCompactionOnce(), observe activeRun, and re-arm a new retry.
|
|
435
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
436
|
+
expect(service.nextCompactionAt).toBeNull();
|
|
437
|
+
|
|
438
|
+
hold.release();
|
|
439
|
+
await filingPromise;
|
|
440
|
+
await stopPromise;
|
|
441
|
+
|
|
442
|
+
expect(service.nextCompactionAt).toBeNull();
|
|
443
|
+
expect(hold.compactionCalls()).toBe(0);
|
|
444
|
+
});
|
|
445
|
+
|
|
306
446
|
test("respects active hours", async () => {
|
|
307
447
|
mockConfig.filing.activeHoursStart = 9;
|
|
308
448
|
mockConfig.filing.activeHoursEnd = 17;
|
|
@@ -150,13 +150,11 @@ mock.module("../skills/clawhub-files.js", () => ({
|
|
|
150
150
|
|
|
151
151
|
mock.module("../skills/catalog-install.js", () => ({
|
|
152
152
|
installSkillLocally: async () => {},
|
|
153
|
-
upsertSkillsIndex: () => {},
|
|
154
153
|
}));
|
|
155
154
|
|
|
156
155
|
mock.module("../skills/managed-store.js", () => ({
|
|
157
156
|
createManagedSkill: () => ({ created: true }),
|
|
158
157
|
deleteManagedSkill: () => ({ deleted: true }),
|
|
159
|
-
removeSkillsIndexEntry: () => {},
|
|
160
158
|
validateManagedSkillId: () => null,
|
|
161
159
|
}));
|
|
162
160
|
|
|
@@ -188,8 +186,6 @@ import { getSkill } from "../daemon/handlers/skills.js";
|
|
|
188
186
|
// Helpers
|
|
189
187
|
// ---------------------------------------------------------------------------
|
|
190
188
|
|
|
191
|
-
|
|
192
|
-
|
|
193
189
|
// ---------------------------------------------------------------------------
|
|
194
190
|
// Tests
|
|
195
191
|
// ---------------------------------------------------------------------------
|
|
@@ -3,18 +3,13 @@
|
|
|
3
3
|
* `assistant/src/daemon/handlers/skills.ts`.
|
|
4
4
|
*
|
|
5
5
|
* One representative call site (the `installSkill` bundled branch) is
|
|
6
|
-
* exercised
|
|
7
|
-
* `
|
|
8
|
-
* -
|
|
9
|
-
* observed (callOrder picks up "v2")
|
|
10
|
-
* - config off → helper still invoked, but the seed short-circuits
|
|
6
|
+
* exercised; all handler seed sites share the same delegation to
|
|
7
|
+
* `refreshSkillCapabilityMemories`, so a single suite covers behavior. Validates:
|
|
8
|
+
* - handler invokes the centralized refresh helper with the live config.
|
|
11
9
|
*
|
|
12
|
-
* The
|
|
13
|
-
* `
|
|
14
|
-
*
|
|
15
|
-
* gate semantics are covered by `lifecycle-memory-v2-seed.test.ts`; here
|
|
16
|
-
* we only verify that the handler invokes the helper synchronously with
|
|
17
|
-
* the live config.
|
|
10
|
+
* The helper's gate semantics (flag + config + rejection swallowing) are
|
|
11
|
+
* covered by `lifecycle-memory-v2-seed.test.ts`; here we only verify that the
|
|
12
|
+
* handler delegates to the centralized refresh path synchronously.
|
|
18
13
|
*/
|
|
19
14
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
20
15
|
|
|
@@ -22,16 +17,9 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
|
22
17
|
// Programmable test state
|
|
23
18
|
// ---------------------------------------------------------------------------
|
|
24
19
|
|
|
25
|
-
const
|
|
20
|
+
const configState = { v2Enabled: true };
|
|
26
21
|
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
const mockSeedSkillGraphNodes = mock(() => {
|
|
30
|
-
callOrder.push("v1");
|
|
31
|
-
});
|
|
32
|
-
// Body installed in `beforeEach` so each test sees a fresh implementation
|
|
33
|
-
// that closes over the up-to-date `flagsState`.
|
|
34
|
-
const mockMaybeSeedMemoryV2Skills = mock(
|
|
22
|
+
const mockRefreshSkillCapabilityMemories = mock(
|
|
35
23
|
(_config: { memory: { v2: { enabled: boolean } } }) => {},
|
|
36
24
|
);
|
|
37
25
|
|
|
@@ -53,10 +41,6 @@ mock.module("../config/skills.js", () => ({
|
|
|
53
41
|
],
|
|
54
42
|
}));
|
|
55
43
|
|
|
56
|
-
mock.module("../config/assistant-feature-flags.js", () => ({
|
|
57
|
-
isAssistantFeatureFlagEnabled: () => true,
|
|
58
|
-
}));
|
|
59
|
-
|
|
60
44
|
// Stub both `getConfig` and `loadConfig`. `loadConfig` is reached by code
|
|
61
45
|
// paths transitively imported during teardown (e.g. dynamic imports inside
|
|
62
46
|
// `oauth2.ts`); leaving it undefined here would break sibling test files
|
|
@@ -68,13 +52,13 @@ mock.module("../config/loader.js", () => ({
|
|
|
68
52
|
deepMergeOverwrite: (a: unknown) => a,
|
|
69
53
|
mergeDefaultWorkspaceConfig: () => {},
|
|
70
54
|
getConfig: () => ({
|
|
71
|
-
memory: { v2: { enabled:
|
|
55
|
+
memory: { v2: { enabled: configState.v2Enabled } },
|
|
72
56
|
}),
|
|
73
57
|
getConfigReadOnly: () => ({
|
|
74
|
-
memory: { v2: { enabled:
|
|
58
|
+
memory: { v2: { enabled: configState.v2Enabled } },
|
|
75
59
|
}),
|
|
76
60
|
loadConfig: () => ({
|
|
77
|
-
memory: { v2: { enabled:
|
|
61
|
+
memory: { v2: { enabled: configState.v2Enabled } },
|
|
78
62
|
}),
|
|
79
63
|
invalidateConfigCache: () => {},
|
|
80
64
|
loadRawConfig: () => ({}),
|
|
@@ -147,9 +131,11 @@ mock.module("../skills/catalog-cache.js", () => ({
|
|
|
147
131
|
}));
|
|
148
132
|
|
|
149
133
|
mock.module("../skills/catalog-install.js", () => ({
|
|
150
|
-
|
|
151
|
-
|
|
134
|
+
commitStagedSkillInstall: () => {},
|
|
135
|
+
createSkillInstallStagingDir: () => "/tmp/test-skills/.install-staging/test",
|
|
152
136
|
getRepoSkillsDir: () => undefined,
|
|
137
|
+
installSkillDependenciesIfPresent: () => {},
|
|
138
|
+
installSkillLocally: async () => {},
|
|
153
139
|
}));
|
|
154
140
|
|
|
155
141
|
mock.module("../skills/catalog-search.js", () => ({
|
|
@@ -159,23 +145,15 @@ mock.module("../skills/catalog-search.js", () => ({
|
|
|
159
145
|
mock.module("../skills/managed-store.js", () => ({
|
|
160
146
|
createManagedSkill: () => ({ created: true }),
|
|
161
147
|
deleteManagedSkill: () => ({ deleted: true }),
|
|
162
|
-
removeSkillsIndexEntry: () => {},
|
|
163
148
|
validateManagedSkillId: () => null,
|
|
164
149
|
}));
|
|
165
150
|
|
|
166
151
|
mock.module("../memory/graph/capability-seed.js", () => ({
|
|
167
152
|
deleteSkillCapabilityNode: () => {},
|
|
168
|
-
seedSkillGraphNodes: mockSeedSkillGraphNodes,
|
|
169
|
-
seedUninstalledCatalogSkillMemories: async () => {},
|
|
170
|
-
}));
|
|
171
|
-
|
|
172
|
-
mock.module("../memory/v2/skill-store.js", () => ({
|
|
173
|
-
seedV2SkillEntries: mock(async () => {}),
|
|
174
|
-
getSkillCapability: () => null,
|
|
175
153
|
}));
|
|
176
154
|
|
|
177
|
-
mock.module("../daemon/memory-
|
|
178
|
-
|
|
155
|
+
mock.module("../daemon/skill-memory-refresh.js", () => ({
|
|
156
|
+
refreshSkillCapabilityMemories: mockRefreshSkillCapabilityMemories,
|
|
179
157
|
}));
|
|
180
158
|
|
|
181
159
|
mock.module("../util/platform.js", () => ({
|
|
@@ -204,45 +182,48 @@ mock.module("../daemon/config-watcher.js", () => ({
|
|
|
204
182
|
}));
|
|
205
183
|
|
|
206
184
|
// Import after mocking
|
|
207
|
-
const { installSkill } =
|
|
208
|
-
|
|
209
|
-
// ---------------------------------------------------------------------------
|
|
210
|
-
// Helpers
|
|
211
|
-
// ---------------------------------------------------------------------------
|
|
185
|
+
const { installSkill, uninstallSkill } =
|
|
186
|
+
await import("../daemon/handlers/skills.js");
|
|
212
187
|
|
|
213
188
|
// ---------------------------------------------------------------------------
|
|
214
189
|
// Tests
|
|
215
190
|
// ---------------------------------------------------------------------------
|
|
216
191
|
|
|
217
|
-
describe("v2 skill
|
|
192
|
+
describe("v2 skill refresh delegation in skill handlers", () => {
|
|
218
193
|
beforeEach(() => {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
mockSeedSkillGraphNodes.mockClear();
|
|
222
|
-
mockMaybeSeedMemoryV2Skills.mockClear();
|
|
223
|
-
mockMaybeSeedMemoryV2Skills.mockImplementation((config) => {
|
|
224
|
-
if (!config.memory.v2.enabled) return;
|
|
225
|
-
callOrder.push("v2");
|
|
226
|
-
});
|
|
194
|
+
configState.v2Enabled = true;
|
|
195
|
+
mockRefreshSkillCapabilityMemories.mockClear();
|
|
227
196
|
});
|
|
228
197
|
|
|
229
|
-
test("config
|
|
198
|
+
test("enabled config → refresh helper invoked with live config", async () => {
|
|
230
199
|
const result = await installSkill({ slug: "bundled-skill" });
|
|
231
200
|
|
|
232
201
|
expect(result.success).toBe(true);
|
|
233
|
-
expect(
|
|
234
|
-
expect(
|
|
235
|
-
|
|
202
|
+
expect(mockRefreshSkillCapabilityMemories).toHaveBeenCalledTimes(1);
|
|
203
|
+
expect(mockRefreshSkillCapabilityMemories.mock.calls[0]?.[0]).toEqual({
|
|
204
|
+
memory: { v2: { enabled: true } },
|
|
205
|
+
});
|
|
236
206
|
});
|
|
237
207
|
|
|
238
|
-
test("config.memory.v2.enabled off →
|
|
239
|
-
|
|
208
|
+
test("config.memory.v2.enabled off → helper receives disabled config", async () => {
|
|
209
|
+
configState.v2Enabled = false;
|
|
240
210
|
|
|
241
211
|
const result = await installSkill({ slug: "bundled-skill" });
|
|
242
212
|
|
|
243
213
|
expect(result.success).toBe(true);
|
|
244
|
-
expect(
|
|
245
|
-
expect(
|
|
246
|
-
|
|
214
|
+
expect(mockRefreshSkillCapabilityMemories).toHaveBeenCalledTimes(1);
|
|
215
|
+
expect(mockRefreshSkillCapabilityMemories.mock.calls[0]?.[0]).toEqual({
|
|
216
|
+
memory: { v2: { enabled: false } },
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test("uninstall delegates to refresh helper", async () => {
|
|
221
|
+
const result = await uninstallSkill("managed-skill");
|
|
222
|
+
|
|
223
|
+
expect(result.success).toBe(true);
|
|
224
|
+
expect(mockRefreshSkillCapabilityMemories).toHaveBeenCalledTimes(1);
|
|
225
|
+
expect(mockRefreshSkillCapabilityMemories.mock.calls[0]?.[0]).toEqual({
|
|
226
|
+
memory: { v2: { enabled: true } },
|
|
227
|
+
});
|
|
247
228
|
});
|
|
248
229
|
});
|