@vellumai/assistant 0.8.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +11 -0
- package/ARCHITECTURE.md +2 -7
- package/Dockerfile +80 -5
- package/README.md +2 -2
- package/bun.lock +11 -1
- package/docker-entrypoint.sh +21 -0
- package/docker-init-apt-root.sh +94 -0
- package/docker-kata-apt-env.sh +39 -0
- package/docs/plugins.md +88 -47
- package/docs/skills.md +9 -7
- package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
- package/eslint-rules/cli-no-daemon-internals.js +283 -0
- package/eslint.config.mjs +12 -0
- 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/knip.json +2 -1
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
- 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 +4462 -991
- package/package.json +5 -1
- package/scripts/generate-openapi.ts +135 -14
- package/scripts/sync-llm-catalog.ts +165 -0
- package/scripts/sync-web-search-catalog.ts +129 -0
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
- package/src/__tests__/agent-image-optimize.test.ts +11 -3
- package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
- package/src/__tests__/anthropic-provider.test.ts +137 -2
- package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
- package/src/__tests__/app-control-flow.test.ts +7 -0
- package/src/__tests__/app-executors.test.ts +220 -4
- package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
- package/src/__tests__/avatar-identity-sync.test.ts +87 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/call-site-routing-provider.test.ts +172 -45
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
- package/src/__tests__/channel-availability-routes.test.ts +206 -0
- package/src/__tests__/channel-delivery-store.test.ts +289 -1
- package/src/__tests__/channel-policy.test.ts +12 -0
- package/src/__tests__/checker.test.ts +89 -0
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
- package/src/__tests__/clawhub.test.ts +75 -16
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
- package/src/__tests__/compactor-tail-resolution.test.ts +41 -0
- package/src/__tests__/config-loader-backfill.test.ts +526 -102
- package/src/__tests__/config-loader-corrupt.test.ts +68 -0
- package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
- package/src/__tests__/config-schema-cmd.test.ts +63 -29
- package/src/__tests__/config-schema.test.ts +35 -3
- package/src/__tests__/config-set-platform-guard.test.ts +75 -152
- package/src/__tests__/config-set-route.test.ts +278 -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__/config-watcher.test.ts +6 -0
- package/src/__tests__/contacts-tools.test.ts +51 -199
- package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
- package/src/__tests__/context-search-agent-runner.test.ts +22 -138
- package/src/__tests__/context-search-conversations-source.test.ts +159 -18
- package/src/__tests__/context-search-fanout.test.ts +20 -157
- package/src/__tests__/context-search-memory-v2-source.test.ts +3 -4
- package/src/__tests__/context-search-types.test.ts +7 -2
- package/src/__tests__/context-search-workspace-source.test.ts +7 -0
- package/src/__tests__/context-token-estimator.test.ts +1 -0
- 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 +93 -92
- package/src/__tests__/conversation-agent-loop.test.ts +2 -0
- package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
- package/src/__tests__/conversation-error.test.ts +80 -3
- package/src/__tests__/conversation-fork-crud.test.ts +323 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +54 -18
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
- package/src/__tests__/conversation-lifecycle.test.ts +297 -0
- 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-app-control-preactivation.test.ts +100 -1
- package/src/__tests__/conversation-process-callsite.test.ts +25 -2
- 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 +80 -13
- package/src/__tests__/conversation-slash-commands.test.ts +194 -2
- 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-app-control.test.ts +323 -3
- 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 +8 -8
- package/src/__tests__/daemon-credential-client.test.ts +56 -1
- package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
- package/src/__tests__/db-proxy-transaction.test.ts +206 -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 +482 -0
- package/src/__tests__/filing-service.test.ts +163 -3
- package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
- package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +42 -69
- package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
- package/src/__tests__/heartbeat-service.test.ts +50 -233
- 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 +162 -0
- package/src/__tests__/host-app-control-proxy.test.ts +365 -1
- package/src/__tests__/host-app-control-routes.test.ts +247 -1
- package/src/__tests__/host-browser-proxy.test.ts +416 -20
- package/src/__tests__/host-browser-routes.test.ts +325 -33
- package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
- 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 +246 -0
- package/src/__tests__/inference-profile-reaper.test.ts +156 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +410 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +248 -0
- package/src/__tests__/injector-chain.test.ts +10 -8
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
- package/src/__tests__/install-skill-routing.test.ts +157 -39
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +107 -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 +20 -1
- package/src/__tests__/llm-catalog-parity.test.ts +190 -2
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +222 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +100 -0
- package/src/__tests__/llm-resolver.test.ts +46 -0
- package/src/__tests__/llm-usage-store.test.ts +114 -0
- package/src/__tests__/managed-profile-guard.test.ts +145 -14
- package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
- package/src/__tests__/managed-store.test.ts +84 -192
- package/src/__tests__/mcp-auth-routes.test.ts +1 -0
- package/src/__tests__/mcp-cli.test.ts +182 -220
- package/src/__tests__/mcp-health-check.test.ts +56 -27
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
- package/src/__tests__/message-complete-display-id.test.ts +175 -0
- package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
- package/src/__tests__/notification-platform-adapter.test.ts +229 -0
- package/src/__tests__/oauth-cli.test.ts +38 -2009
- package/src/__tests__/oauth-commands-routes.test.ts +863 -0
- package/src/__tests__/oauth-connect-routes.test.ts +174 -11
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
- package/src/__tests__/oauth-providers-routes.test.ts +14 -10
- package/src/__tests__/openai-provider.test.ts +24 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +48 -19
- package/src/__tests__/openai-responses-provider.test.ts +17 -0
- 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} +1 -1
- 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 +41 -38
- 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 +31 -4
- package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +47 -18
- package/src/__tests__/plugin-types.test.ts +15 -23
- package/src/__tests__/process-message-background-slack.test.ts +53 -0
- package/src/__tests__/process-message-display-content.test.ts +421 -0
- package/src/__tests__/profile-entry-status.test.ts +43 -0
- package/src/__tests__/provider-catalog-visibility.test.ts +142 -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} +20 -12
- package/src/__tests__/provider-registry-ollama.test.ts +12 -4
- package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
- package/src/__tests__/relay-server.test.ts +118 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
- package/src/__tests__/schedule-retry.test.ts +56 -4
- package/src/__tests__/schedule-routes.test.ts +151 -0
- package/src/__tests__/schedule-store.test.ts +94 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
- package/src/__tests__/scheduler-recurrence.test.ts +87 -34
- package/src/__tests__/scheduler-reuse-conversation.test.ts +208 -5
- package/src/__tests__/scheduler-wake.test.ts +0 -63
- package/src/__tests__/schema-transforms.test.ts +20 -0
- package/src/__tests__/search-skills-unified.test.ts +0 -5
- package/src/__tests__/secret-allowlist.test.ts +1 -0
- package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +12 -4
- package/src/__tests__/server-history-render.test.ts +43 -0
- package/src/__tests__/shell-credential-ref.test.ts +95 -3
- package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -12
- package/src/__tests__/skill-load-tool.test.ts +29 -93
- 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-call-site-routing.test.ts +78 -16
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/suggestion-routes.test.ts +3 -3
- package/src/__tests__/sync-message-contract.test.ts +63 -0
- package/src/__tests__/system-prompt.test.ts +737 -63
- package/src/__tests__/task-scheduler.test.ts +88 -23
- 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__/update-bulletin-job.test.ts +96 -193
- package/src/__tests__/usage-cli.test.ts +11 -73
- package/src/__tests__/user-plugin-loader.test.ts +143 -5
- package/src/__tests__/vercel-config.test.ts +168 -0
- package/src/__tests__/voice-session-bridge.test.ts +198 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +108 -0
- package/src/__tests__/web-search.test.ts +303 -2
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +170 -0
- package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +241 -0
- package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
- package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
- package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
- package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
- package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
- package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
- package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -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-remove-legacy-skills-index.test.ts +309 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
- package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
- package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
- package/src/acp/__tests__/helpers/which-stub.ts +4 -2
- package/src/acp/resolve-agent.test.ts +25 -0
- package/src/acp/resolve-agent.ts +13 -2
- package/src/acp/session-manager.ts +14 -0
- package/src/agent/image-optimize.ts +13 -5
- package/src/approvals/guardian-request-resolvers.ts +32 -87
- package/src/calls/relay-server.ts +35 -0
- package/src/calls/relay-setup-router.ts +36 -0
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-session-bridge.ts +74 -36
- package/src/channels/config.ts +14 -1
- package/src/channels/types.ts +109 -0
- package/src/cli/AGENTS.md +164 -4
- package/src/cli/__tests__/notifications.test.ts +54 -0
- package/src/cli/__tests__/unknown-command.test.ts +24 -0
- package/src/cli/commands/__tests__/avatar.test.ts +540 -0
- package/src/cli/commands/__tests__/backup.test.ts +236 -776
- package/src/cli/commands/__tests__/cache.test.ts +1 -1
- package/src/cli/commands/__tests__/changelog.test.ts +578 -0
- package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
- package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
- package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
- package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
- package/src/cli/commands/__tests__/email-core.test.ts +579 -0
- package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
- package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
- package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
- package/src/cli/commands/__tests__/schedules.test.ts +491 -0
- package/src/cli/commands/__tests__/skills.test.ts +563 -0
- package/src/cli/commands/__tests__/status.test.ts +249 -0
- package/src/cli/commands/__tests__/stt.test.ts +320 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
- package/src/cli/commands/__tests__/tts.test.ts +321 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
- package/src/cli/commands/attachment.ts +8 -3
- package/src/cli/commands/audit.ts +95 -64
- package/src/cli/commands/auth.ts +61 -58
- package/src/cli/commands/avatar.ts +276 -390
- package/src/cli/commands/backup.ts +409 -505
- package/src/cli/commands/bash.ts +9 -5
- package/src/cli/commands/browser.ts +28 -9
- package/src/cli/commands/cache.ts +9 -4
- package/src/cli/commands/changelog.ts +478 -0
- package/src/cli/commands/channel-verification-sessions.ts +238 -317
- package/src/cli/commands/clients.ts +8 -3
- package/src/cli/commands/completions.ts +9 -9
- package/src/cli/commands/config.ts +102 -72
- package/src/cli/commands/contacts.ts +575 -696
- package/src/cli/commands/conversations-defer.ts +17 -69
- package/src/cli/commands/conversations-import.ts +90 -253
- package/src/cli/commands/conversations.ts +429 -434
- package/src/cli/commands/credential-execution.ts +9 -6
- package/src/cli/commands/credentials.ts +456 -736
- package/src/cli/commands/default-action.ts +10 -53
- package/src/cli/commands/domain.ts +128 -206
- package/src/cli/commands/email.ts +606 -794
- package/src/cli/commands/gateway.ts +8 -1
- package/src/cli/commands/image-generation.ts +157 -205
- package/src/cli/commands/inference-providers.ts +352 -0
- package/src/cli/commands/inference-session.ts +415 -0
- package/src/cli/commands/inference.ts +87 -65
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.ts +103 -287
- package/src/cli/commands/memory-v2.ts +162 -516
- package/src/cli/commands/notifications.ts +342 -304
- package/src/cli/commands/oauth/apps.ts +292 -261
- package/src/cli/commands/oauth/connect.ts +176 -297
- package/src/cli/commands/oauth/disconnect.ts +16 -215
- package/src/cli/commands/oauth/index.ts +49 -45
- package/src/cli/commands/oauth/mode.ts +43 -199
- package/src/cli/commands/oauth/ping.ts +17 -125
- package/src/cli/commands/oauth/providers.ts +732 -921
- package/src/cli/commands/oauth/request.ts +60 -350
- package/src/cli/commands/oauth/shared.ts +11 -121
- package/src/cli/commands/oauth/status.ts +31 -121
- package/src/cli/commands/oauth/token.ts +13 -55
- package/src/cli/commands/pending.ts +19 -10
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
- package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
- package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
- package/src/cli/commands/platform/connect.ts +16 -80
- package/src/cli/commands/platform/disconnect.ts +14 -112
- package/src/cli/commands/platform/index.ts +177 -246
- package/src/cli/commands/plugins.ts +185 -0
- package/src/cli/commands/routes.ts +153 -336
- package/src/cli/commands/schedules.ts +391 -0
- package/src/cli/commands/sequence.ts +316 -360
- package/src/cli/commands/skills.ts +449 -671
- package/src/cli/commands/status.ts +58 -37
- package/src/cli/commands/stt.ts +94 -262
- package/src/cli/commands/task.ts +14 -40
- package/src/cli/commands/telemetry.ts +40 -0
- package/src/cli/commands/trust.ts +8 -3
- package/src/cli/commands/tts.ts +162 -167
- package/src/cli/commands/ui.ts +35 -42
- package/src/cli/commands/usage.ts +188 -126
- package/src/cli/commands/watchers.ts +8 -3
- package/src/cli/commands/webhooks.ts +99 -193
- 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__/register-command.test.ts +85 -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/daemon-credential-client.ts +4 -5
- package/src/cli/lib/install-from-github.ts +304 -0
- package/src/cli/lib/list-installed-plugins.ts +137 -0
- package/src/cli/lib/nested-value.ts +44 -0
- package/src/cli/lib/open-browser.ts +36 -0
- package/src/cli/lib/register-command.ts +19 -0
- package/src/cli/lib/time-ago.ts +34 -0
- package/src/cli/lib/uninstall-plugin.ts +82 -0
- package/src/cli/lib/unknown-command.ts +111 -0
- package/src/cli/program.ts +40 -6
- package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
- package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
- package/src/cli/utils/conversation-id.ts +30 -0
- package/src/cli/utils/parse-duration.ts +41 -0
- package/src/config/acp-defaults.test.ts +5 -1
- package/src/config/acp-defaults.ts +11 -4
- package/src/config/bundled-skills/acp/TOOLS.json +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +23 -21
- package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
- package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
- package/src/config/bundled-skills/contacts/SKILL.md +12 -45
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
- 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/messaging/tools/messaging-archive-by-sender.ts +0 -12
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
- 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 -2
- package/src/config/feature-flag-registry.json +57 -1
- package/src/config/llm-resolver.ts +16 -1
- package/src/config/loader.ts +140 -52
- package/src/config/raw-config-utils.ts +2 -30
- package/src/config/schema.ts +8 -7
- package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
- package/src/config/schemas/call-site-catalog.ts +29 -7
- package/src/config/schemas/channels.ts +8 -0
- package/src/config/schemas/compaction.ts +28 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm-request-logs.ts +81 -0
- package/src/config/schemas/llm.ts +55 -2
- package/src/config/schemas/memory-retrieval.ts +18 -0
- package/src/config/schemas/memory-retrospective.ts +48 -0
- package/src/config/schemas/memory-v2.ts +32 -1
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/services.ts +15 -12
- package/src/config/schemas/tools.ts +14 -0
- package/src/config/seed-inference-profiles.ts +195 -134
- package/src/config/skills.ts +3 -96
- package/src/contacts/contact-store.ts +0 -61
- package/src/context/compactor.ts +1047 -0
- package/src/context/token-estimator.ts +2 -2
- package/src/context/window-manager.ts +197 -1334
- 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 +113 -0
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +183 -4
- package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
- package/src/daemon/approval-generators.ts +26 -30
- package/src/daemon/config-watcher.ts +94 -29
- package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
- package/src/daemon/conversation-agent-loop.ts +293 -103
- package/src/daemon/conversation-error.ts +188 -33
- package/src/daemon/conversation-lifecycle.ts +80 -26
- package/src/daemon/conversation-messaging.ts +25 -6
- package/src/daemon/conversation-process.ts +85 -31
- package/src/daemon/conversation-runtime-assembly.ts +30 -6
- package/src/daemon/conversation-slash.ts +184 -25
- package/src/daemon/conversation-store.ts +24 -10
- package/src/daemon/conversation-surfaces.ts +76 -12
- package/src/daemon/conversation-tool-setup.ts +63 -21
- package/src/daemon/conversation.ts +81 -10
- package/src/daemon/external-plugins-bootstrap.ts +231 -185
- package/src/daemon/first-greeting.ts +22 -2
- package/src/daemon/guardian-action-generators.ts +7 -22
- package/src/daemon/handlers/config-model.ts +13 -130
- package/src/daemon/handlers/config-slack-channel.ts +25 -10
- package/src/daemon/handlers/config-vercel.ts +3 -1
- package/src/daemon/handlers/shared.ts +14 -5
- package/src/daemon/handlers/skills.ts +166 -84
- package/src/daemon/history-repair.ts +61 -7
- package/src/daemon/host-app-control-proxy.ts +129 -29
- package/src/daemon/host-bash-proxy.ts +85 -158
- package/src/daemon/host-browser-proxy.ts +96 -35
- package/src/daemon/host-proxy-base.ts +13 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -1
- package/src/daemon/identity-helpers.ts +19 -0
- package/src/daemon/lifecycle.ts +79 -70
- package/src/daemon/meet-host-supervisor.ts +20 -19
- package/src/daemon/memory-v2-startup.ts +58 -2
- package/src/daemon/message-protocol.ts +7 -0
- package/src/daemon/message-types/bookmarks.ts +18 -0
- package/src/daemon/message-types/conversations.ts +37 -9
- package/src/daemon/message-types/messages.ts +70 -1
- package/src/daemon/message-types/subagents.ts +1 -0
- package/src/daemon/message-types/sync.ts +61 -0
- package/src/daemon/pkb-reminder-builder.test.ts +54 -13
- package/src/daemon/pkb-reminder-builder.ts +21 -7
- package/src/daemon/plugin-source-watcher.ts +146 -0
- package/src/daemon/process-message.ts +77 -26
- package/src/daemon/server.ts +34 -20
- package/src/daemon/shutdown-handlers.ts +0 -2
- package/src/daemon/skill-memory-refresh.ts +29 -0
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/daemon/tool-side-effects.ts +6 -4
- package/src/daemon/wake-target-adapter.ts +11 -0
- package/src/documents/document-store.ts +221 -3
- package/src/embedded/plugin-api.ts +40 -0
- package/src/export/transcript-formatter.ts +61 -2
- package/src/filing/filing-service.ts +79 -53
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +444 -0
- package/src/heartbeat/heartbeat-run-store.ts +3 -1
- package/src/heartbeat/heartbeat-service.ts +189 -127
- package/src/home/__tests__/feed-types.test.ts +99 -127
- package/src/home/__tests__/feed-writer.test.ts +77 -278
- package/src/home/__tests__/post-connect-feed.test.ts +9 -12
- package/src/home/feed-types.ts +41 -73
- package/src/home/feed-writer.ts +25 -156
- package/src/home/post-connect-feed.ts +2 -3
- package/src/index.ts +18 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
- package/src/ipc/__tests__/email-ipc.test.ts +506 -0
- package/src/ipc/__tests__/exit-helper.test.ts +104 -0
- package/src/ipc/__tests__/streaming-client.test.ts +237 -0
- package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
- package/src/ipc/assistant-server.ts +55 -6
- package/src/ipc/cli-client.ts +370 -50
- package/src/ipc/routes/db-proxy-transaction.ts +151 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
- package/src/ipc/skill-routes/events.ts +30 -3
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
- package/src/live-voice/live-voice-session-manager.ts +11 -4
- package/src/live-voice/live-voice-session.ts +14 -6
- package/src/mcp/client.ts +20 -4
- package/src/media/image-credentials.ts +3 -3
- package/src/memory/__tests__/bookmark-crud.test.ts +264 -0
- package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
- package/src/memory/__tests__/conversation-queries.test.ts +263 -0
- package/src/memory/__tests__/conversation-types.test.ts +36 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +318 -0
- package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
- package/src/memory/__tests__/message-content.test.ts +35 -0
- package/src/memory/bookmark-crud.ts +211 -0
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
- package/src/memory/context-search/agent-protocol.ts +5 -1
- package/src/memory/context-search/agent-runner.ts +60 -85
- package/src/memory/context-search/limits.ts +1 -4
- package/src/memory/context-search/search.ts +23 -113
- package/src/memory/context-search/sources/conversations.ts +80 -8
- package/src/memory/context-search/sources/memory-v2.ts +39 -14
- package/src/memory/context-search/sources/memory.ts +7 -0
- package/src/memory/context-search/sources/workspace.ts +17 -10
- package/src/memory/context-search/types.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +11 -0
- package/src/memory/conversation-crud.ts +368 -22
- package/src/memory/conversation-queries.ts +116 -12
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/conversation-types.ts +16 -0
- package/src/memory/db-init.ts +20 -0
- package/src/memory/delivery-crud.ts +152 -5
- package/src/memory/embedding-backend.ts +6 -5
- package/src/memory/embedding-runtime-manager.ts +1 -2
- package/src/memory/external-conversation-store.ts +66 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +66 -9
- package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
- package/src/memory/graph/conversation-graph-memory.ts +92 -5
- package/src/memory/graph/extraction.ts +4 -0
- package/src/memory/graph/graph-memory-state-store.ts +16 -3
- package/src/memory/graph/tool-handlers.ts +17 -7
- package/src/memory/graph/tools.ts +45 -6
- package/src/memory/indexer.ts +51 -29
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +86 -15
- package/src/memory/jobs/embed-concept-page.ts +65 -20
- package/src/memory/jobs-store.ts +51 -1
- package/src/memory/jobs-worker.ts +57 -3
- package/src/memory/llm-request-log-source-clickhouse.ts +324 -0
- package/src/memory/llm-request-log-source-local.ts +26 -0
- package/src/memory/llm-request-log-source.ts +64 -0
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/llm-usage-store.ts +125 -5
- package/src/memory/memory-retrospective-constants.ts +13 -0
- package/src/memory/memory-retrospective-enqueue.ts +114 -0
- package/src/memory/memory-retrospective-job.ts +351 -0
- package/src/memory/memory-retrospective-startup-cleanup.ts +175 -0
- package/src/memory/memory-retrospective-state.ts +162 -0
- package/src/memory/memory-retrospective-trigger-check.ts +91 -0
- package/src/memory/memory-v2-activation-log-store.ts +49 -5
- package/src/memory/memory-v2-concept-frequency.ts +4 -0
- package/src/memory/message-content.ts +38 -1
- package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
- package/src/memory/migrations/229-delete-private-conversations.test.ts +107 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +19 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
- package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
- package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
- package/src/memory/migrations/242-message-bookmarks.ts +38 -0
- package/src/memory/migrations/243-provider-connections.ts +68 -0
- package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
- package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
- package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -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/__tests__/244-provider-connection-status-label.test.ts +84 -0
- package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
- package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
- package/src/memory/migrations/index.ts +13 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/onboarding-events-store.ts +106 -0
- package/src/memory/published-pages-store.ts +16 -0
- package/src/memory/schema/bookmarks.ts +36 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/index.ts +2 -0
- package/src/memory/schema/inference.ts +27 -0
- package/src/memory/schema/infrastructure.ts +12 -0
- package/src/memory/schema/memory-core.ts +9 -0
- package/src/memory/search/semantic.ts +1 -4
- package/src/memory/turn-events-store.ts +127 -2
- package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
- package/src/memory/v2/__tests__/activation.test.ts +11 -12
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
- package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
- package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
- package/src/memory/v2/__tests__/injection.test.ts +726 -18
- package/src/memory/v2/__tests__/migration.test.ts +94 -3
- package/src/memory/v2/__tests__/page-index.test.ts +360 -0
- package/src/memory/v2/__tests__/page-store.test.ts +14 -1
- package/src/memory/v2/__tests__/prompts-router.test.ts +309 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +138 -3
- package/src/memory/v2/__tests__/reranker.test.ts +4 -4
- package/src/memory/v2/__tests__/router.test.ts +531 -0
- package/src/memory/v2/__tests__/sim.test.ts +45 -1
- package/src/memory/v2/__tests__/skill-store.test.ts +445 -11
- package/src/memory/v2/__tests__/static-context.test.ts +7 -22
- package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
- package/src/memory/v2/activation-store.ts +34 -5
- package/src/memory/v2/activation.ts +40 -27
- package/src/memory/v2/backfill-jobs.ts +17 -84
- package/src/memory/v2/consolidation-job.ts +85 -78
- package/src/memory/v2/frontmatter-sweep.ts +91 -0
- package/src/memory/v2/injection.ts +466 -109
- package/src/memory/v2/migration.ts +147 -20
- package/src/memory/v2/page-index.ts +221 -0
- package/src/memory/v2/page-store.ts +3 -0
- package/src/memory/v2/prompts/consolidation.ts +9 -7
- package/src/memory/v2/prompts/router.ts +195 -0
- package/src/memory/v2/prompts/sweep.ts +2 -2
- package/src/memory/v2/qdrant.ts +234 -93
- package/src/memory/v2/reranker.ts +14 -7
- package/src/memory/v2/router.ts +323 -0
- package/src/memory/v2/sim.ts +25 -12
- package/src/memory/v2/skill-store.ts +204 -30
- package/src/memory/v2/static-context.ts +16 -9
- package/src/memory/v2/sweep-job.ts +122 -96
- package/src/memory/v2/types.ts +10 -6
- package/src/memory/validation.ts +13 -0
- 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__/emit-signal-home-feed.test.ts +182 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
- package/src/notifications/__tests__/signal-registry.test.ts +17 -0
- package/src/notifications/adapters/platform.ts +171 -0
- package/src/notifications/conversation-pairing.ts +4 -3
- package/src/notifications/copy-composer.ts +15 -0
- package/src/notifications/decision-engine.ts +2 -1
- package/src/notifications/destination-resolver.ts +21 -0
- package/src/notifications/emit-signal.ts +48 -2
- package/src/notifications/home-feed-side-effect.ts +165 -0
- package/src/notifications/signal.ts +8 -1
- package/src/oauth/connection-resolver.ts +8 -4
- package/src/oauth/platform-connection.ts +6 -2
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/checker.ts +14 -0
- package/src/permissions/ipc-risk-types.ts +3 -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 +46 -0
- package/src/plugin-api/package.json +12 -0
- package/src/plugin-api/types.ts +144 -0
- 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 +55 -6
- 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 +367 -0
- 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 +74 -53
- package/src/plugins/user-loader.ts +85 -43
- package/src/proactive-artifact/aux-message-injector.ts +11 -0
- package/src/proactive-artifact/job.test.ts +49 -9
- package/src/proactive-artifact/job.ts +4 -0
- package/src/proactive-artifact/trigger-state.test.ts +9 -0
- package/src/proactive-artifact/trigger-state.ts +4 -0
- package/src/prompts/__tests__/system-prompt.test.ts +117 -0
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +99 -0
- package/src/prompts/normalize-onboarding.ts +27 -0
- package/src/prompts/sections.ts +302 -0
- package/src/prompts/system-prompt.ts +72 -154
- package/src/prompts/templates/BOOTSTRAP.md +17 -1
- package/src/prompts/templates/system-sections.ts +173 -0
- package/src/prompts/update-bulletin-job.ts +61 -73
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
- package/src/providers/__tests__/inference.test.ts +303 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
- package/src/providers/__tests__/retry-callsite.test.ts +14 -32
- package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
- package/src/providers/anthropic/client.ts +123 -54
- package/src/providers/call-site-routing.ts +94 -16
- package/src/providers/connection-resolution.ts +170 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
- package/src/providers/inference/adapter-factory.ts +210 -0
- package/src/providers/inference/auth.ts +112 -0
- package/src/providers/inference/backfill.ts +196 -0
- package/src/providers/inference/connections.ts +401 -0
- package/src/providers/inference/resolve-auth.ts +73 -0
- package/src/providers/model-catalog.ts +386 -6
- package/src/providers/openai/chat-completions-provider.ts +10 -2
- package/src/providers/openai/responses-provider.ts +4 -2
- package/src/providers/openrouter/client.ts +7 -0
- package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -1
- 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 +36 -0
- package/src/providers/provider-env-vars.ts +17 -7
- package/src/providers/provider-secret-catalog.ts +49 -30
- package/src/providers/provider-send-message.ts +41 -20
- package/src/providers/registry.ts +151 -159
- package/src/providers/retry.ts +65 -11
- package/src/providers/search-provider-catalog.ts +121 -0
- package/src/runtime/AGENTS.md +18 -5
- package/src/runtime/__tests__/agent-wake.test.ts +152 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
- package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
- package/src/runtime/actor-trust-resolver.ts +32 -10
- package/src/runtime/agent-wake.ts +64 -7
- package/src/runtime/assistant-event-hub.ts +3 -85
- package/src/runtime/auth/route-policy.ts +311 -9
- package/src/runtime/auth/same-actor.ts +2 -0
- package/src/runtime/background-job-runner.ts +339 -0
- package/src/runtime/btw-sidechain.ts +3 -0
- package/src/runtime/http-router.ts +36 -1
- package/src/runtime/http-server.ts +31 -5
- package/src/runtime/http-types.ts +21 -0
- package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
- package/src/runtime/middleware/request-logger.ts +62 -1
- package/src/runtime/migrations/origin-mode.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/pre-first-message-gate.ts +83 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +268 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +319 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +280 -4
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +70 -3
- package/src/runtime/routes/acp-routes-list.test.ts +143 -0
- package/src/runtime/routes/acp-routes.ts +12 -8
- package/src/runtime/routes/app-management-routes.ts +228 -3
- package/src/runtime/routes/approval-routes.ts +0 -18
- package/src/runtime/routes/audit-routes.ts +43 -0
- package/src/runtime/routes/auth-routes.ts +72 -0
- package/src/runtime/routes/avatar-routes.ts +273 -20
- package/src/runtime/routes/backup-routes.ts +406 -2
- package/src/runtime/routes/bookmark-routes.ts +156 -0
- package/src/runtime/routes/btw-routes.ts +5 -1
- package/src/runtime/routes/channel-availability-routes.ts +121 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -1
- package/src/runtime/routes/contact-routes.ts +0 -160
- package/src/runtime/routes/conversation-cli-routes.ts +233 -0
- package/src/runtime/routes/conversation-list-routes.ts +3 -20
- package/src/runtime/routes/conversation-management-routes.ts +47 -85
- package/src/runtime/routes/conversation-query-routes.ts +350 -97
- package/src/runtime/routes/conversation-routes.ts +121 -21
- package/src/runtime/routes/conversations-import-routes.ts +229 -0
- package/src/runtime/routes/credential-routes.ts +540 -0
- package/src/runtime/routes/debug-routes.ts +2 -2
- package/src/runtime/routes/document-pdf-renderer.ts +5 -1
- package/src/runtime/routes/documents-routes.ts +25 -86
- package/src/runtime/routes/domain-routes.ts +167 -0
- package/src/runtime/routes/email-routes.ts +603 -0
- package/src/runtime/routes/errors.ts +2 -2
- package/src/runtime/routes/events-routes.ts +192 -0
- package/src/runtime/routes/group-routes.ts +5 -0
- package/src/runtime/routes/home-feed-routes.ts +6 -78
- package/src/runtime/routes/host-app-control-routes.ts +44 -2
- package/src/runtime/routes/host-browser-routes.ts +103 -22
- package/src/runtime/routes/http-adapter.ts +2 -0
- package/src/runtime/routes/identity-routes.ts +5 -0
- package/src/runtime/routes/image-generation-routes.ts +99 -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 +248 -1
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +118 -7
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
- package/src/runtime/routes/index.ts +42 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +285 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +84 -0
- package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +361 -0
- package/src/runtime/routes/inference-send-routes.ts +115 -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 +7 -13
- package/src/runtime/routes/mcp-auth-routes.ts +283 -9
- package/src/runtime/routes/memory-v2-routes.ts +13 -398
- package/src/runtime/routes/notification-routes.ts +3 -1
- package/src/runtime/routes/oauth-apps.ts +112 -7
- package/src/runtime/routes/oauth-commands-routes.ts +1097 -0
- package/src/runtime/routes/oauth-connect-routes.ts +67 -5
- package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
- package/src/runtime/routes/oauth-providers.ts +298 -8
- package/src/runtime/routes/platform-routes.ts +336 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -1
- package/src/runtime/routes/playground/reset-circuit.ts +2 -1
- package/src/runtime/routes/playground/state.ts +2 -1
- package/src/runtime/routes/publish-routes.ts +221 -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 +79 -0
- package/src/runtime/routes/sequence-routes.ts +291 -0
- package/src/runtime/routes/settings-routes.ts +2 -10
- package/src/runtime/routes/skills-routes.ts +31 -1
- package/src/runtime/routes/stt-routes.ts +240 -3
- package/src/runtime/routes/subagents-routes.ts +57 -18
- package/src/runtime/routes/surface-action-routes.ts +43 -7
- package/src/runtime/routes/telemetry-routes.ts +27 -0
- package/src/runtime/routes/tts-routes.ts +93 -1
- package/src/runtime/routes/types.ts +32 -0
- package/src/runtime/routes/user-routes-cli.ts +243 -0
- package/src/runtime/routes/webhook-routes.ts +165 -0
- 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 +117 -0
- package/src/runtime/sync/sync-publisher.test.ts +105 -0
- package/src/runtime/sync/sync-publisher.ts +21 -0
- package/src/schedule/schedule-store.ts +27 -2
- package/src/schedule/scheduler.ts +208 -123
- package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
- package/src/security/__tests__/untrusted-content.test.ts +86 -0
- package/src/security/secret-patterns.ts +3 -0
- package/src/security/untrusted-content.ts +93 -8
- package/src/sequence/engine.ts +38 -40
- 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 +28 -15
- 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/__tests__/browser-execution-acquire.test.ts +206 -0
- package/src/tools/browser/browser-execution.ts +29 -14
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
- package/src/tools/browser/cdp-client/factory.ts +66 -5
- package/src/tools/browser/runtime-check.ts +77 -0
- 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.test.ts +3 -3
- package/src/tools/memory/register.ts +9 -1
- package/src/tools/network/__tests__/web-search.test.ts +156 -0
- package/src/tools/network/web-search.ts +280 -37
- package/src/tools/permission-checker.ts +14 -6
- 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/subagent/spawn.ts +3 -3
- package/src/tools/system/request-permission.ts +2 -2
- package/src/tools/terminal/safe-env.ts +60 -1
- package/src/tools/terminal/shell.ts +44 -0
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/types.ts +72 -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/usage/attribution.ts +3 -2
- package/src/util/errors.ts +17 -0
- package/src/util/platform.ts +10 -0
- package/src/util/pricing.ts +86 -160
- package/src/watcher/__tests__/engine.test.ts +323 -0
- package/src/watcher/constants.ts +7 -0
- package/src/watcher/engine.ts +94 -90
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
- package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +94 -5
- package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +117 -0
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +95 -0
- package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
- package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
- package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
- package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
- package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
- package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
- package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
- package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
- 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/registry.ts +30 -0
- package/src/workspace/migrations/runner.ts +46 -5
- package/src/workspace/migrations/types.ts +17 -3
- package/src/workspace/provider-commit-message-generator.ts +3 -2
- package/examples/plugins/echo/bun.lock +0 -25
- package/src/__tests__/context-search-pkb-source.test.ts +0 -498
- package/src/__tests__/context-window-manager.test.ts +0 -2093
- package/src/__tests__/credentials-cli.test.ts +0 -1225
- package/src/__tests__/memory-admin-recall.test.ts +0 -213
- package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
- package/src/cli/commands/__tests__/email-download.test.ts +0 -260
- package/src/cli/commands/__tests__/email-list.test.ts +0 -216
- package/src/cli/commands/__tests__/email-register.test.ts +0 -186
- package/src/cli/commands/__tests__/email-send.test.ts +0 -416
- package/src/cli/commands/__tests__/email-status.test.ts +0 -185
- package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
- package/src/cli/commands/__tests__/routes.test.ts +0 -562
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
- package/src/cli/commands/autonomy.ts +0 -365
- package/src/cli/commands/memory.ts +0 -424
- package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
- package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
- package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
- package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
- package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
- package/src/cli/lib/daemon-avatar-client.ts +0 -37
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
- package/src/context/__tests__/compact-prompt.test.ts +0 -63
- package/src/context/prompts/compact.md +0 -26
- package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
- package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
- package/src/home/__tests__/emit-feed-event.test.ts +0 -169
- package/src/home/__tests__/feed-population-integration.test.ts +0 -312
- package/src/home/__tests__/feed-scheduler.test.ts +0 -222
- package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
- package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
- package/src/home/__tests__/rollup-producer.test.ts +0 -507
- package/src/home/assistant-feed-authoring.ts +0 -135
- package/src/home/emit-feed-event.ts +0 -169
- package/src/home/feed-scheduler.ts +0 -281
- package/src/home/platform-gmail-digest.ts +0 -163
- package/src/home/rewrite-command-preview.ts +0 -66
- package/src/home/rewrite-feed-title.ts +0 -58
- package/src/home/rollup-producer.ts +0 -426
- package/src/memory/admin.ts +0 -326
- package/src/memory/context-search/sources/pkb.ts +0 -476
- package/src/memory/graph/compaction.ts +0 -299
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
- /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External plugin runtime — `globalThis.__vellumPluginRuntime` bridge.
|
|
3
|
+
*
|
|
4
|
+
* Workspace-local plugins (`<workspaceDir>/plugins/*`) get dynamic-imported by
|
|
5
|
+
* {@link loadUserPlugins}. They need to call `registerPlugin()` from their
|
|
6
|
+
* module body and they typically also want to read secrets, subscribe to
|
|
7
|
+
* runtime events, etc.
|
|
8
|
+
*
|
|
9
|
+
* Importing those symbols by absolute path
|
|
10
|
+
* (`/abs/path/to/assistant/src/plugins/registry.js`) works when the daemon is
|
|
11
|
+
* running from source — both the daemon and the dynamic-imported plugin
|
|
12
|
+
* resolve the same on-disk file and share module identity. It DOES NOT work
|
|
13
|
+
* when the daemon is a `bun --compile` binary: the daemon's modules are baked
|
|
14
|
+
* into the executable, and any absolute-path import re-loads a fresh disk
|
|
15
|
+
* copy. `registerPlugin()` then writes into a disjoint registry instance and
|
|
16
|
+
* the daemon never sees the plugin.
|
|
17
|
+
*
|
|
18
|
+
* The fix is to expose a single, stable handle on `globalThis` that plugins
|
|
19
|
+
* read at module-load time. The daemon's bundled modules attach themselves
|
|
20
|
+
* here once at startup; plugins consume the same instance regardless of how
|
|
21
|
+
* the daemon was built.
|
|
22
|
+
*
|
|
23
|
+
* Plugins use the bridge like this:
|
|
24
|
+
*
|
|
25
|
+
* const runtime = (globalThis as { __vellumPluginRuntime?: ... })
|
|
26
|
+
* .__vellumPluginRuntime;
|
|
27
|
+
* if (!runtime || runtime.version !== 1) throw new Error("...");
|
|
28
|
+
* const { registerPlugin, assistantEventHub, getSecureKeyAsync } = runtime;
|
|
29
|
+
*
|
|
30
|
+
* Type-only imports (`import type { Plugin } from "..."`) remain free to use
|
|
31
|
+
* absolute paths or workspace-local copies — the TypeScript compiler erases
|
|
32
|
+
* them and they have no module-identity effect at runtime.
|
|
33
|
+
*
|
|
34
|
+
* See `assistant/docs/plugins.md` for the full authoring contract and
|
|
35
|
+
* `assistant/examples/plugins/echo/register.ts` for a worked example.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
39
|
+
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
40
|
+
import { registerPlugin } from "./registry.js";
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The handle plugins read from `globalThis.__vellumPluginRuntime`.
|
|
44
|
+
*
|
|
45
|
+
* `version` is the contract version. Plugins should assert against the
|
|
46
|
+
* version they were authored against and refuse to register if they see a
|
|
47
|
+
* different one — bumping it is a breaking change to the plugin surface.
|
|
48
|
+
*
|
|
49
|
+
* The field set is intentionally small: the most-commonly-needed symbols
|
|
50
|
+
* across both static (module-load-time) and dynamic (init-time) plugin
|
|
51
|
+
* lifecycle. Plugins that need richer runtime state can still receive it
|
|
52
|
+
* through {@link PluginInitContext} during `init()`.
|
|
53
|
+
*/
|
|
54
|
+
export interface VellumPluginRuntime {
|
|
55
|
+
readonly version: 1;
|
|
56
|
+
readonly registerPlugin: typeof registerPlugin;
|
|
57
|
+
readonly assistantEventHub: typeof assistantEventHub;
|
|
58
|
+
readonly getSecureKeyAsync: typeof getSecureKeyAsync;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Stable globalThis key. Don't rename — plugins reference it by string. */
|
|
62
|
+
const RUNTIME_GLOBAL_KEY = "__vellumPluginRuntime" as const;
|
|
63
|
+
|
|
64
|
+
interface GlobalWithRuntime {
|
|
65
|
+
[RUNTIME_GLOBAL_KEY]?: VellumPluginRuntime;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Install the plugin runtime bridge on `globalThis`. Idempotent — repeat
|
|
70
|
+
* calls are no-ops, so it's safe to invoke from tests that also touch the
|
|
71
|
+
* lifecycle path.
|
|
72
|
+
*
|
|
73
|
+
* Must be called BEFORE {@link loadUserPlugins} runs, otherwise plugins that
|
|
74
|
+
* touch `globalThis.__vellumPluginRuntime` in their module body will throw.
|
|
75
|
+
*/
|
|
76
|
+
export function installPluginRuntime(): void {
|
|
77
|
+
const g = globalThis as GlobalWithRuntime;
|
|
78
|
+
if (g[RUNTIME_GLOBAL_KEY]) return;
|
|
79
|
+
g[RUNTIME_GLOBAL_KEY] = {
|
|
80
|
+
version: 1,
|
|
81
|
+
registerPlugin,
|
|
82
|
+
assistantEventHub,
|
|
83
|
+
getSecureKeyAsync,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Read the installed runtime. Returns `undefined` if {@link installPluginRuntime}
|
|
89
|
+
* hasn't been called yet — plugins should treat this as a fatal error.
|
|
90
|
+
*
|
|
91
|
+
* Exposed mainly for tests and for the rare in-process consumer that wants
|
|
92
|
+
* to read the bridge from the same module graph that installed it.
|
|
93
|
+
*/
|
|
94
|
+
export function getPluginRuntime(): VellumPluginRuntime | undefined {
|
|
95
|
+
return (globalThis as GlobalWithRuntime)[RUNTIME_GLOBAL_KEY];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Tear down the runtime handle. Test-only — production code never uninstalls
|
|
100
|
+
* because the runtime lifetime is the daemon lifetime.
|
|
101
|
+
*/
|
|
102
|
+
export function uninstallPluginRuntimeForTests(): void {
|
|
103
|
+
delete (globalThis as GlobalWithRuntime)[RUNTIME_GLOBAL_KEY];
|
|
104
|
+
}
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External plugin loader — builds a {@link Plugin} from a directory and
|
|
3
|
+
* registers it with the runtime.
|
|
4
|
+
*
|
|
5
|
+
* The convention this loader walks is currently **experimental**: surface
|
|
6
|
+
* set, manifest fields, and discovery shape may all change before the
|
|
7
|
+
* framework stabilizes. We keep this module's identifiers harness-neutral
|
|
8
|
+
* ("external") so the stable call path through the harness —
|
|
9
|
+
* `loadUserPlugins → loadExternalPlugin → registerPlugin` — does not
|
|
10
|
+
* need to be renamed when the convention shifts.
|
|
11
|
+
*
|
|
12
|
+
* <pluginDir>/
|
|
13
|
+
* package.json ← manifest.name comes from `name`
|
|
14
|
+
* (npm scope stripped);
|
|
15
|
+
* peerDependencies["@vellumai/plugin-api"]
|
|
16
|
+
* semver range is checked against the
|
|
17
|
+
* running assistant version and rejects
|
|
18
|
+
* the plugin if unsatisfied
|
|
19
|
+
* hooks/
|
|
20
|
+
* <name>.ts ← default export → plugin.hooks[<name>]
|
|
21
|
+
* (today the runtime invokes "init" at
|
|
22
|
+
* bootstrap and "shutdown" at teardown;
|
|
23
|
+
* other filenames sit in the map for
|
|
24
|
+
* forward compatibility)
|
|
25
|
+
* tools/
|
|
26
|
+
* *.ts ← each file's default export → plugin.tools[]
|
|
27
|
+
* src/ ← internal helpers, ignored by the loader
|
|
28
|
+
*
|
|
29
|
+
* Per-surface, `.js` is preferred over `.ts` (compiled-binary semantics).
|
|
30
|
+
* Missing surface files are silently omitted (the harness treats absent
|
|
31
|
+
* fields as "this plugin contributes nothing here"). Surface files
|
|
32
|
+
* present without a usable default export are a hard failure: the
|
|
33
|
+
* loader logs with attribution and skips the plugin.
|
|
34
|
+
*
|
|
35
|
+
* This function owns the per-plugin isolation contract: it never throws,
|
|
36
|
+
* times out after `importTimeoutMs`, catches any error from the build or
|
|
37
|
+
* `registerPlugin` call, and logs an attributed entry. Callers can
|
|
38
|
+
* `await loadExternalPlugin(...)` in a loop with no per-iteration guard.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
42
|
+
import { readFile } from "node:fs/promises";
|
|
43
|
+
import { join } from "node:path";
|
|
44
|
+
import { pathToFileURL } from "node:url";
|
|
45
|
+
|
|
46
|
+
import semver from "semver";
|
|
47
|
+
import { z } from "zod";
|
|
48
|
+
|
|
49
|
+
import assistantPkg from "../../package.json" with { type: "json" };
|
|
50
|
+
import { getLogger } from "../util/logger.js";
|
|
51
|
+
import { registerPlugin } from "./registry.js";
|
|
52
|
+
import type {
|
|
53
|
+
Plugin,
|
|
54
|
+
PluginHookFn,
|
|
55
|
+
PluginHooks,
|
|
56
|
+
PluginManifest,
|
|
57
|
+
PluginToolRegistration,
|
|
58
|
+
} from "./types.js";
|
|
59
|
+
|
|
60
|
+
const PLUGIN_API_PEER_DEP = "@vellumai/plugin-api";
|
|
61
|
+
|
|
62
|
+
const log = getLogger("external-plugin-loader");
|
|
63
|
+
|
|
64
|
+
/** Default upper bound on how long a single plugin load may take. */
|
|
65
|
+
const DEFAULT_IMPORT_TIMEOUT_MS = 10_000;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Zod schema for the subset of `package.json` the external loader reads.
|
|
69
|
+
*
|
|
70
|
+
* - `name` is the only required field; everything else is best-effort.
|
|
71
|
+
* - `peerDependencies["@vellumai/plugin-api"]` is the canonical host-compat
|
|
72
|
+
* declaration. If present, the loader checks `semver.satisfies(host, range)`
|
|
73
|
+
* against the running assistant version and rejects the plugin on
|
|
74
|
+
* mismatch. If absent, the plugin loads without a host-compat claim
|
|
75
|
+
* (with a warning).
|
|
76
|
+
* - Unknown fields pass through (`passthrough`) so the loader does not
|
|
77
|
+
* destructively reshape the file when the rest of the npm ecosystem
|
|
78
|
+
* writes to it.
|
|
79
|
+
*/
|
|
80
|
+
const PluginPackageJsonSchema = z
|
|
81
|
+
.object({
|
|
82
|
+
name: z.string().min(1, "package.json `name` must be a non-empty string"),
|
|
83
|
+
version: z.string().optional(),
|
|
84
|
+
peerDependencies: z.record(z.string(), z.string()).optional(),
|
|
85
|
+
})
|
|
86
|
+
.passthrough();
|
|
87
|
+
|
|
88
|
+
type PluginPackageJson = z.infer<typeof PluginPackageJsonSchema>;
|
|
89
|
+
|
|
90
|
+
export interface LoadExternalPluginOptions {
|
|
91
|
+
/**
|
|
92
|
+
* Maximum time to spend building the `Plugin` from disk before bailing.
|
|
93
|
+
* The build runs to completion in the background if it eventually
|
|
94
|
+
* resolves, but the loader has already moved on. Defaults to
|
|
95
|
+
* {@link DEFAULT_IMPORT_TIMEOUT_MS}.
|
|
96
|
+
*/
|
|
97
|
+
readonly importTimeoutMs?: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Strip the npm scope from a package name. `@vellumai/simple-memory` →
|
|
102
|
+
* `simple-memory`; an unscoped name passes through unchanged.
|
|
103
|
+
*/
|
|
104
|
+
function stripScope(name: string): string {
|
|
105
|
+
const match = /^@[^/]+\/(.+)$/.exec(name);
|
|
106
|
+
return match ? match[1]! : name;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Dynamic-import `absolutePath` and return its default export. Throws when
|
|
111
|
+
* the module has no default export — callers attribute the error.
|
|
112
|
+
*/
|
|
113
|
+
async function importDefault<T>(absolutePath: string): Promise<T> {
|
|
114
|
+
const url = pathToFileURL(absolutePath).href;
|
|
115
|
+
const mod = (await import(url)) as { default?: T };
|
|
116
|
+
if (mod.default === undefined) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`module ${absolutePath} has no default export — external plugins must default-export their interface surfaces`,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return mod.default;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
interface SurfaceFile {
|
|
125
|
+
/** Basename without `.js`/`.ts` extension. */
|
|
126
|
+
readonly name: string;
|
|
127
|
+
/** Absolute path on disk. */
|
|
128
|
+
readonly path: string;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* List every `.js`/`.ts` file directly under `dir`, deduplicating `.js`
|
|
133
|
+
* over `.ts` when both are present for the same basename. Returns entries
|
|
134
|
+
* sorted by basename so plugin authors get a deterministic per-plugin
|
|
135
|
+
* registration sequence; cross-plugin order remains the registry's job.
|
|
136
|
+
*
|
|
137
|
+
* Used to walk both `hooks/` and `tools/` — neither surface needs
|
|
138
|
+
* subdirectory recursion today, so this stays flat on purpose.
|
|
139
|
+
*/
|
|
140
|
+
function listSurfaceDir(dir: string): SurfaceFile[] {
|
|
141
|
+
if (!existsSync(dir) || !statSync(dir).isDirectory()) return [];
|
|
142
|
+
const entries = readdirSync(dir);
|
|
143
|
+
const byBase = new Map<string, string>();
|
|
144
|
+
for (const entry of entries) {
|
|
145
|
+
// `.d.ts` declaration files are TypeScript type-only artifacts shipped
|
|
146
|
+
// alongside compiled `.js`. They have no default-exported runtime
|
|
147
|
+
// function and would crash `importDefault`, so the walker filters
|
|
148
|
+
// them out before the `.js`/`.ts` extension check.
|
|
149
|
+
if (entry.endsWith(".d.ts")) continue;
|
|
150
|
+
const base =
|
|
151
|
+
entry.endsWith(".js") || entry.endsWith(".ts")
|
|
152
|
+
? entry.slice(0, -3)
|
|
153
|
+
: null;
|
|
154
|
+
if (base === null) continue;
|
|
155
|
+
const existing = byBase.get(base);
|
|
156
|
+
if (
|
|
157
|
+
existing === undefined ||
|
|
158
|
+
(existing.endsWith(".ts") && entry.endsWith(".js"))
|
|
159
|
+
) {
|
|
160
|
+
byBase.set(base, entry);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return [...byBase.keys()]
|
|
164
|
+
.sort()
|
|
165
|
+
.map((name) => ({ name, path: join(dir, byBase.get(name)!) }));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Walk every file under `<pluginDir>/hooks/` and import each as a
|
|
170
|
+
* lifecycle hook keyed by filename basename. The runtime today invokes
|
|
171
|
+
* `init` at bootstrap and `shutdown` at teardown; other filenames are
|
|
172
|
+
* loaded into the map for forward compatibility with future lifecycle
|
|
173
|
+
* events but stay inert.
|
|
174
|
+
*/
|
|
175
|
+
async function loadHooks(
|
|
176
|
+
pluginDir: string,
|
|
177
|
+
pluginName: string,
|
|
178
|
+
): Promise<PluginHooks | undefined> {
|
|
179
|
+
const files = listSurfaceDir(join(pluginDir, "hooks"));
|
|
180
|
+
if (files.length === 0) return undefined;
|
|
181
|
+
const hooks: PluginHooks = {};
|
|
182
|
+
for (const { name, path } of files) {
|
|
183
|
+
const fn = await importDefault<PluginHookFn>(path);
|
|
184
|
+
if (typeof fn !== "function") {
|
|
185
|
+
throw new Error(
|
|
186
|
+
`external plugin ${pluginName}: hooks/${name} default export must be a function (got ${typeof fn})`,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
hooks[name] = fn;
|
|
190
|
+
}
|
|
191
|
+
return hooks;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Build a `Plugin` object from the directory layout. Internal — the
|
|
196
|
+
* public entry point ({@link loadExternalPlugin}) wraps this in the
|
|
197
|
+
* timeout/try-catch/register triple.
|
|
198
|
+
*/
|
|
199
|
+
async function buildPluginFromDir(pluginDir: string): Promise<Plugin> {
|
|
200
|
+
const pkgPath = join(pluginDir, "package.json");
|
|
201
|
+
let rawPkg: unknown;
|
|
202
|
+
try {
|
|
203
|
+
rawPkg = JSON.parse(await readFile(pkgPath, "utf8"));
|
|
204
|
+
} catch (err) {
|
|
205
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
206
|
+
throw new Error(
|
|
207
|
+
`package.json at ${pluginDir} could not be read or parsed: ${reason}`,
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
const parsed = PluginPackageJsonSchema.safeParse(rawPkg);
|
|
211
|
+
if (!parsed.success) {
|
|
212
|
+
throw new Error(
|
|
213
|
+
`package.json at ${pluginDir} failed schema validation: ${parsed.error.message}`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
const pkg: PluginPackageJson = parsed.data;
|
|
217
|
+
const name = stripScope(pkg.name);
|
|
218
|
+
const version = pkg.version && pkg.version.length > 0 ? pkg.version : "0.0.0";
|
|
219
|
+
|
|
220
|
+
// Host-compat negotiation: plugins declare their plugin-api version
|
|
221
|
+
// range via standard `peerDependencies["@vellumai/plugin-api"]`. We
|
|
222
|
+
// inspect the range and report unparseable / unsatisfied cases via
|
|
223
|
+
// `log.error` but still load the plugin — the plugin-installation
|
|
224
|
+
// flow is in flux and a strict gate here would block experimentation
|
|
225
|
+
// for the customers driving the install UX. Once the install path
|
|
226
|
+
// settles, the two `log.error` branches below should harden into
|
|
227
|
+
// throws so a stale plugin can't silently run against a mismatched
|
|
228
|
+
// host.
|
|
229
|
+
//
|
|
230
|
+
// If the peerDep is absent, the plugin loads without a host-compat
|
|
231
|
+
// claim; we log a warning so the omission is visible at boot.
|
|
232
|
+
const range = pkg.peerDependencies?.[PLUGIN_API_PEER_DEP];
|
|
233
|
+
if (range !== undefined) {
|
|
234
|
+
if (!semver.validRange(range)) {
|
|
235
|
+
log.error(
|
|
236
|
+
{ pluginDir, plugin: name, peerDep: PLUGIN_API_PEER_DEP, range },
|
|
237
|
+
`external plugin ${name}: peerDependencies["${PLUGIN_API_PEER_DEP}"] is not a valid semver range — loading anyway`,
|
|
238
|
+
);
|
|
239
|
+
} else if (
|
|
240
|
+
!semver.satisfies(assistantPkg.version, range, {
|
|
241
|
+
includePrerelease: true,
|
|
242
|
+
})
|
|
243
|
+
) {
|
|
244
|
+
log.error(
|
|
245
|
+
{
|
|
246
|
+
pluginDir,
|
|
247
|
+
plugin: name,
|
|
248
|
+
peerDep: PLUGIN_API_PEER_DEP,
|
|
249
|
+
range,
|
|
250
|
+
assistantVersion: assistantPkg.version,
|
|
251
|
+
},
|
|
252
|
+
`external plugin ${name}: peerDependencies["${PLUGIN_API_PEER_DEP}"] requires "${range}" but assistant is ${assistantPkg.version} — loading anyway`,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
} else {
|
|
256
|
+
log.warn(
|
|
257
|
+
{ pluginDir, plugin: name, peerDep: PLUGIN_API_PEER_DEP },
|
|
258
|
+
"external plugin missing plugin-api peerDependency — loading without host-compat claim",
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const manifest: PluginManifest = { name, version };
|
|
263
|
+
const plugin: Plugin = { manifest };
|
|
264
|
+
|
|
265
|
+
const hooks = await loadHooks(pluginDir, name);
|
|
266
|
+
if (hooks !== undefined) plugin.hooks = hooks;
|
|
267
|
+
|
|
268
|
+
const tools: PluginToolRegistration[] = [];
|
|
269
|
+
for (const { path: toolPath } of listSurfaceDir(join(pluginDir, "tools"))) {
|
|
270
|
+
const tool = await importDefault<PluginToolRegistration>(toolPath);
|
|
271
|
+
if (
|
|
272
|
+
tool === null ||
|
|
273
|
+
typeof tool !== "object" ||
|
|
274
|
+
typeof (tool as { name?: unknown }).name !== "string"
|
|
275
|
+
) {
|
|
276
|
+
throw new Error(
|
|
277
|
+
`external plugin ${name}: ${toolPath} default export must be a Tool object with a string "name"`,
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
tools.push(tool);
|
|
281
|
+
}
|
|
282
|
+
if (tools.length > 0) plugin.tools = tools;
|
|
283
|
+
|
|
284
|
+
return plugin;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Build a {@link Plugin} from `pluginDir` with the same timeout +
|
|
289
|
+
* per-plugin isolation contract as {@link loadExternalPlugin}, but
|
|
290
|
+
* without registering it. The plugin-source watcher consumes this so it
|
|
291
|
+
* can decide between first-time registration (init once, then publish) and
|
|
292
|
+
* hot-reload (replace + skip init) based on what's already in the registry.
|
|
293
|
+
*
|
|
294
|
+
* Returns `undefined` on timeout, build failure, or abandoned surface
|
|
295
|
+
* import. Never throws — failures are logged with directory attribution.
|
|
296
|
+
*/
|
|
297
|
+
export async function buildExternalPlugin(
|
|
298
|
+
pluginDir: string,
|
|
299
|
+
opts: LoadExternalPluginOptions = {},
|
|
300
|
+
): Promise<Plugin | undefined> {
|
|
301
|
+
const timeoutMs = opts.importTimeoutMs ?? DEFAULT_IMPORT_TIMEOUT_MS;
|
|
302
|
+
let timeoutHandle: ReturnType<typeof setTimeout> | undefined;
|
|
303
|
+
try {
|
|
304
|
+
const timeoutSentinel = Symbol("external-plugin-build-timeout");
|
|
305
|
+
const buildPromise = buildPluginFromDir(pluginDir);
|
|
306
|
+
const timeoutPromise = new Promise<typeof timeoutSentinel>((resolve) => {
|
|
307
|
+
timeoutHandle = setTimeout(() => resolve(timeoutSentinel), timeoutMs);
|
|
308
|
+
});
|
|
309
|
+
const result = await Promise.race([buildPromise, timeoutPromise]);
|
|
310
|
+
if (result === timeoutSentinel) {
|
|
311
|
+
// Abandoned build — surface imports may still be running. Attach a
|
|
312
|
+
// terminal `.catch` so a late rejection does not surface as an
|
|
313
|
+
// unhandled-rejection crash. Callers who feed the returned plugin
|
|
314
|
+
// into `registerPlugin` rely on the closed-registration latch
|
|
315
|
+
// (registry.ts) to reject any stale late-arriving registration.
|
|
316
|
+
buildPromise.catch(() => {
|
|
317
|
+
/* swallow — see comment above */
|
|
318
|
+
});
|
|
319
|
+
log.warn(
|
|
320
|
+
{ pluginDir, timeoutMs },
|
|
321
|
+
`Timed out building external plugin ${pluginDir} after ${timeoutMs}ms — skipping`,
|
|
322
|
+
);
|
|
323
|
+
return undefined;
|
|
324
|
+
}
|
|
325
|
+
return result;
|
|
326
|
+
} catch (err) {
|
|
327
|
+
// Per-plugin isolation: one bad external plugin must not crash the
|
|
328
|
+
// daemon. Surface the failure with attribution and move on.
|
|
329
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
330
|
+
log.error(
|
|
331
|
+
{ err, pluginDir },
|
|
332
|
+
`Failed to build external plugin ${pluginDir}: ${message}`,
|
|
333
|
+
);
|
|
334
|
+
return undefined;
|
|
335
|
+
} finally {
|
|
336
|
+
if (timeoutHandle !== undefined) clearTimeout(timeoutHandle);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Load the external plugin at `pluginDir` and register it. Thin wrapper
|
|
342
|
+
* over {@link buildExternalPlugin} that calls `registerPlugin` on the
|
|
343
|
+
* built plugin, preserving the existing `loadUserPlugins` call shape.
|
|
344
|
+
*/
|
|
345
|
+
export async function loadExternalPlugin(
|
|
346
|
+
pluginDir: string,
|
|
347
|
+
opts: LoadExternalPluginOptions = {},
|
|
348
|
+
): Promise<void> {
|
|
349
|
+
const plugin = await buildExternalPlugin(pluginDir, opts);
|
|
350
|
+
if (plugin === undefined) {
|
|
351
|
+
// buildExternalPlugin already logged the failure with attribution.
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
try {
|
|
355
|
+
registerPlugin(plugin);
|
|
356
|
+
log.info(
|
|
357
|
+
{ pluginDir, name: plugin.manifest.name },
|
|
358
|
+
"loaded external plugin",
|
|
359
|
+
);
|
|
360
|
+
} catch (err) {
|
|
361
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
362
|
+
log.error(
|
|
363
|
+
{ err, pluginDir, plugin: plugin.manifest.name },
|
|
364
|
+
`Failed to register external plugin ${pluginDir}: ${message}`,
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External-plugin feature gate.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for whether the experimental external-plugin
|
|
5
|
+
* surface is enabled. The flag gates both the `assistant plugins` CLI
|
|
6
|
+
* command tree and (in future) the declarative external-plugin loader
|
|
7
|
+
* pathway in the daemon.
|
|
8
|
+
*
|
|
9
|
+
* The flag key uses the simple kebab-case format and is declared in
|
|
10
|
+
* `meta/feature-flags/feature-flag-registry.json`.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
14
|
+
import type { AssistantConfig } from "../config/schema.js";
|
|
15
|
+
|
|
16
|
+
/** Gate key for the external-plugin surface. */
|
|
17
|
+
const EXTERNAL_PLUGINS_FLAG_KEY = "external-plugins" as const;
|
|
18
|
+
|
|
19
|
+
/** Whether the external-plugin surface is enabled. */
|
|
20
|
+
export function isExternalPluginsEnabled(config: AssistantConfig): boolean {
|
|
21
|
+
return isAssistantFeatureFlagEnabled(EXTERNAL_PLUGINS_FLAG_KEY, config);
|
|
22
|
+
}
|
package/src/plugins/pipeline.ts
CHANGED
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
|
|
27
27
|
import type { Logger } from "pino";
|
|
28
28
|
|
|
29
|
+
import type { HookName } from "../plugin-api/constants.js";
|
|
29
30
|
import { getLogger } from "../util/logger.js";
|
|
31
|
+
import { getHooksFor } from "./registry.js";
|
|
30
32
|
import {
|
|
31
33
|
type Middleware,
|
|
32
34
|
type PipelineName,
|
|
@@ -314,3 +316,38 @@ export async function runPipeline<A, R>(
|
|
|
314
316
|
logger.info(record, "plugin.pipeline");
|
|
315
317
|
}
|
|
316
318
|
}
|
|
319
|
+
|
|
320
|
+
// ─── Hook runner ────────────────────────────────────────────────────────────
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Execute a hook chain: walk every registered plugin's hook for `name` in
|
|
324
|
+
* registration order, threading `initialCtx` through each. Hooks may either
|
|
325
|
+
* mutate the context in place (returning `void`) or return a new context
|
|
326
|
+
* that replaces the threaded value for subsequent hooks. The final context
|
|
327
|
+
* after the chain settles is returned.
|
|
328
|
+
*
|
|
329
|
+
* `runHook` is the hook-side counterpart to {@link runPipeline}:
|
|
330
|
+
* `runPipeline` composes middleware around a terminal handler for stateful
|
|
331
|
+
* request/response pipelines (memory retrieval, history repair, etc.);
|
|
332
|
+
* `runHook` walks ordered hook functions for declarative chain-style
|
|
333
|
+
* context transformations (`user-prompt-submit` today).
|
|
334
|
+
*
|
|
335
|
+
* @param name The hook identifier — pick one from {@link HOOKS}.
|
|
336
|
+
* @param initialCtx Context the first hook receives.
|
|
337
|
+
* @returns The final context after the chain settles. Same reference as
|
|
338
|
+
* `initialCtx` when no plugin registers `name`, and when every
|
|
339
|
+
* chained hook returns `void` (mutation-in-place style).
|
|
340
|
+
*/
|
|
341
|
+
export async function runHook<TCtx>(
|
|
342
|
+
name: HookName,
|
|
343
|
+
initialCtx: TCtx,
|
|
344
|
+
): Promise<TCtx> {
|
|
345
|
+
let active = initialCtx;
|
|
346
|
+
for (const hook of getHooksFor<TCtx>(name)) {
|
|
347
|
+
const result = await hook(active);
|
|
348
|
+
if (result !== undefined) {
|
|
349
|
+
active = result;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return active;
|
|
353
|
+
}
|