@vellumai/assistant 0.11.3 → 0.11.4-dev.202608190019.b94dbf2
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 +9 -3
- package/ARCHITECTURE.md +32 -10
- package/docs/architecture/memory.md +43 -5
- package/docs/architecture/security.md +96 -152
- package/docs/architecture/turn-actor.md +70 -0
- package/docs/browser-use-architecture-phase2.md +128 -56
- package/docs/flux-turn-detection-spike.md +248 -0
- package/docs/guardian-request-flow.md +35 -0
- package/docs/stt-provider-onboarding.md +3 -1
- package/knip.json +3 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +34 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
- package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/openapi.yaml +289 -113
- package/package.json +1 -1
- package/scripts/voice-ttft-spike.ts +3 -3
- package/scripts/write-plugin-api-shim.ts +10 -0
- package/src/__tests__/app-compiler.test.ts +38 -3
- package/src/__tests__/app-control-flow.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +2 -2
- package/src/__tests__/assistant-feature-flag-guard.test.ts +25 -3
- package/src/__tests__/attachments-store.test.ts +21 -12
- package/src/__tests__/byok-default-profile-ensure.test.ts +17 -0
- package/src/__tests__/call-setup-flow-name-capture.test.ts +0 -1
- package/src/__tests__/call-site-routing-provider.test.ts +1 -1
- package/src/__tests__/channel-availability-routes.test.ts +14 -1
- package/src/__tests__/channel-capabilities-dedupe.test.ts +214 -0
- package/src/__tests__/channel-delivery-store.test.ts +14 -14
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +4 -4
- package/src/__tests__/channel-setup-panel-ack.test.ts +1 -1
- package/src/__tests__/checker.test.ts +20 -314
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
- package/src/__tests__/compaction-events.test.ts +8 -10
- package/src/__tests__/config-loader-backfill.test.ts +3 -3
- package/src/__tests__/config-schema.test.ts +25 -10
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +8 -11
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +8 -11
- package/src/__tests__/conversation-agent-loop.test.ts +32 -21
- package/src/__tests__/conversation-attachments.test.ts +0 -1
- package/src/__tests__/conversation-attention-store.test.ts +63 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +112 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -4
- package/src/__tests__/conversation-fork-crud.test.ts +69 -0
- package/src/__tests__/conversation-fork-referential.test.ts +67 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +24 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +209 -0
- package/src/__tests__/conversation-notifiers-provenance.test.ts +59 -0
- package/src/__tests__/conversation-queue.test.ts +154 -4
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +1 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +9 -9
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +1 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +187 -102
- package/src/__tests__/conversation-runtime-workspace.test.ts +14 -10
- package/src/__tests__/conversation-slash-queue.test.ts +3 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-app-open.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +21 -14
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-state-update.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-table-action.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
- package/src/__tests__/credential-prompt-route.test.ts +7 -10
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +1 -0
- package/src/__tests__/custom-profile-ensure.test.ts +5 -1
- package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +5 -1
- package/src/__tests__/discord-requester-notice-privacy.test.ts +3 -3
- package/src/__tests__/document-append-idempotency.test.ts +233 -0
- package/src/__tests__/document-sync-tags.test.ts +0 -75
- package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
- package/src/__tests__/edit-propagation.test.ts +107 -11
- package/src/__tests__/file-ops-service.test.ts +163 -30
- package/src/__tests__/filesystem-tools.test.ts +23 -24
- package/src/__tests__/gateway-only-guard.test.ts +2 -5
- package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
- package/src/__tests__/helpers/mock-actor-context.ts +49 -0
- package/src/__tests__/helpers/mock-conversation.ts +13 -1
- package/src/__tests__/host-file-read-tool.test.ts +16 -19
- package/src/__tests__/http-user-message-parity.test.ts +1 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +49 -0
- package/src/__tests__/injector-chain.test.ts +63 -41
- package/src/__tests__/injector-disk-pressure.test.ts +11 -23
- package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
- package/src/__tests__/llm-context-resolution.test.ts +73 -1
- package/src/__tests__/llm-schema.test.ts +5 -2
- package/src/__tests__/managed-skill-lifecycle.test.ts +7 -0
- package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
- package/src/__tests__/media-generate-image.test.ts +131 -21
- package/src/__tests__/memory-retrieval-hook.test.ts +100 -7
- package/src/__tests__/messages-read-boundary-guard.test.ts +134 -0
- package/src/__tests__/mtime-cache.test.ts +3 -1
- package/src/__tests__/non-member-access-request.test.ts +0 -20
- package/src/__tests__/outbound-slack-persistence.test.ts +40 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
- package/src/__tests__/plugin-api-store-credential.test.ts +261 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +10 -7
- package/src/__tests__/plugin-disabled-state.test.ts +2 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
- package/src/__tests__/plugin-execution-context.test.ts +73 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +7 -4
- package/src/__tests__/plugin-secret-pattern-contribution.test.ts +1 -1
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +14 -7
- package/src/__tests__/provider-commit-message-generator.test.ts +20 -0
- package/src/__tests__/proxy-approval-callback.test.ts +1 -0
- package/src/__tests__/qdrant-manager.test.ts +14 -1
- package/src/__tests__/reaction-persistence.test.ts +200 -7
- package/src/__tests__/require-fresh-approval.test.ts +0 -4
- package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +460 -105
- package/src/__tests__/run-due-schedules.test.ts +21 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +187 -18
- package/src/__tests__/schedule-routes.test.ts +23 -0
- package/src/__tests__/schedule-store.test.ts +17 -0
- package/src/__tests__/scoped-approval-grants.test.ts +11 -6
- package/src/__tests__/secret-ingress-channel.test.ts +0 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +3 -3
- package/src/__tests__/skills.test.ts +32 -0
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +0 -1
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/subagent-call-site-routing.test.ts +31 -19
- package/src/__tests__/subagent-fork-prompt-role.test.ts +1 -1
- package/src/__tests__/subagent-spawn-and-await.test.ts +18 -17
- package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
- package/src/__tests__/subagent-tools.test.ts +81 -101
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +1 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
- package/src/__tests__/tool-executor.test.ts +68 -39
- package/src/__tests__/turn-events-store.test.ts +43 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +1 -1
- package/src/__tests__/ui-shape-teaching.test.ts +33 -0
- package/src/__tests__/ui-visual-surface.test.ts +1 -1
- package/src/__tests__/ui-voice-picker-surface.test.ts +128 -0
- package/src/__tests__/ui-work-result-surface.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +3 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/visible-app-context.test.ts +16 -9
- package/src/__tests__/voice-config-update.test.ts +40 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +5 -3
- package/src/__tests__/voice-session-bridge.test.ts +85 -29
- package/src/__tests__/worker-entrypoint-guards.test.ts +54 -0
- package/src/__tests__/worker-plugin-surface.test.ts +77 -0
- package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +158 -0
- package/src/__tests__/workspace-migration-143-repair-deprecated-codex-model-id.test.ts +133 -0
- package/src/__tests__/workspace-migration-144-convert-stranded-subscription-openai-profiles.test.ts +316 -0
- package/src/__tests__/workspace-migration-145-collapse-profile-bindings-to-entries.test.ts +325 -0
- package/src/__tests__/workspace-migration-146-repair-retired-fireworks-deepseek-flash-model-id.test.ts +235 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +10 -2
- package/src/acp/__tests__/auth-required.test.ts +161 -0
- package/src/acp/acp-claude-oauth.ts +19 -2
- package/src/acp/agent-process.test.ts +100 -0
- package/src/acp/agent-process.ts +29 -26
- package/src/acp/auth-required.ts +102 -0
- package/src/acp/session-manager.test.ts +119 -0
- package/src/acp/session-manager.ts +76 -3
- package/src/api/events/acp-auth-required.ts +55 -0
- package/src/api/events/host-file.ts +2 -2
- package/src/api/index.ts +7 -0
- package/src/api/surfaces.ts +12 -3
- package/src/apps/app-store.ts +3 -0
- package/src/bundler/package-resolver.ts +2 -30
- package/src/calls/__tests__/voice-session-bridge.test.ts +194 -11
- package/src/calls/__tests__/voice-triage-escalate.test.ts +102 -0
- package/src/calls/call-controller.ts +19 -3
- package/src/calls/call-setup-flow.ts +0 -1
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/calls/voice-session-bridge.ts +115 -41
- package/src/calls/voice-triage-escalate.ts +105 -2
- package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
- package/src/channels/config.ts +13 -0
- package/src/channels/plugin-channel-declarations.ts +108 -0
- package/src/channels/types.ts +30 -0
- package/src/cli/AGENTS.md +5 -2
- package/src/cli/bundled-modules.ts +29 -0
- package/src/cli/commands/credentials.help.ts +2 -2
- package/src/cli/commands/db/repair.ts +4 -8
- package/src/cli/commands/domain.ts +6 -3
- package/src/cli/commands/email.ts +6 -3
- package/src/cli/commands/inference-providers.ts +1 -1
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.help.ts +13 -4
- package/src/cli/commands/mcp.ts +9 -0
- package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
- package/src/cli/commands/memory/__tests__/memory-v3.test.ts +128 -5
- package/src/cli/commands/memory/index.help.ts +84 -28
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/memory-v2.ts +58 -54
- package/src/cli/commands/memory/memory-v3.ts +64 -0
- package/src/cli/commands/memory/memory-validate.ts +18 -0
- package/src/cli/commands/plugins.ts +85 -36
- package/src/cli/commands/schedules.ts +35 -1
- package/src/cli/commands/stt.help.ts +27 -2
- package/src/cli/commands/trust.ts +3 -14
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +39 -0
- package/src/cli/lib/bundled-marketplace.json +14 -1
- package/src/cli/lib/upgrade-plugin.ts +42 -0
- package/src/config/__tests__/balanced-model-experiment.test.ts +278 -0
- package/src/config/__tests__/default-profile-catalog.test.ts +34 -2
- package/src/config/__tests__/default-provider.test.ts +6 -1
- package/src/config/__tests__/profile-materialization.test.ts +75 -19
- package/src/config/assistant-feature-flags.ts +36 -15
- package/src/config/balanced-model-experiment.ts +35 -0
- package/src/config/bundled-skills/acp/SKILL.md +6 -7
- package/src/config/bundled-skills/document-editor/SKILL.md +2 -2
- package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/SKILL.md +5 -4
- package/src/config/bundled-skills/image-studio/TOOLS.json +1 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +101 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.test.ts +65 -0
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +7 -1
- package/src/config/bundled-skills/settings/tools/shared.ts +16 -0
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +9 -3
- package/src/config/bundled-skills/subagent/SKILL.md +17 -12
- package/src/config/bundled-skills/subagent/TOOLS.json +4 -4
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
- package/src/config/call-site-defaults.ts +11 -5
- package/src/config/default-profile-catalog.ts +179 -16
- package/src/config/default-profile-names.ts +4 -1
- package/src/config/default-provider-resolution.ts +4 -0
- package/src/config/feature-flag-registry.json +12 -12
- package/src/config/llm-context-resolution.ts +11 -3
- package/src/config/llm-resolver.ts +28 -1
- package/src/config/profile-materialization.ts +70 -22
- package/src/config/schemas/__tests__/live-voice.test.ts +107 -4
- package/src/config/schemas/call-site-catalog.ts +4 -4
- package/src/config/schemas/live-voice.ts +57 -23
- package/src/config/schemas/llm.ts +59 -32
- package/src/config/schemas/mcp.ts +23 -0
- package/src/config/schemas/plugin-updates.ts +6 -2
- package/src/config/schemas/stt.ts +1 -0
- package/src/config/skills.ts +9 -2
- package/src/context/outbound-sanitize.ts +96 -1
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +82 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +15 -10
- package/src/daemon/conversation-agent-loop.ts +31 -19
- package/src/daemon/conversation-messaging.ts +5 -1
- package/src/daemon/conversation-notifiers.ts +20 -10
- package/src/daemon/conversation-process.ts +20 -6
- package/src/daemon/conversation-runtime-assembly.ts +12 -6
- package/src/daemon/conversation-store.ts +14 -4
- package/src/daemon/conversation-surfaces.ts +75 -26
- package/src/daemon/conversation-tool-setup.ts +3 -6
- package/src/daemon/conversation.ts +154 -51
- package/src/daemon/doordash-steps.ts +2 -2
- package/src/daemon/lifecycle.ts +14 -1
- package/src/daemon/mcp-reload-service.ts +36 -6
- package/src/daemon/process-message.ts +13 -26
- package/src/daemon/providers-setup.ts +6 -3
- package/src/daemon/trust-context-types.ts +29 -0
- package/src/daemon/trust-context.ts +12 -7
- package/src/daemon/wake-conversation-ops.ts +3 -2
- package/src/daemon/windows-compiled-entry.ts +4 -0
- package/src/documents/document-store.ts +143 -240
- package/src/hooks/hook-loader.ts +3 -3
- package/src/hooks/registry.ts +103 -45
- package/src/hooks/types.ts +5 -0
- package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
- package/src/inbound/oauth-callback-url.ts +61 -0
- package/src/ipc/gateway-client.test.ts +1 -1
- package/src/ipc/gateway-client.ts +14 -21
- package/src/ipc/gateway-flag-listener.ts +17 -3
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
- package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +1050 -0
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
- package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +60 -194
- package/src/live-voice/__tests__/live-voice-stt.test.ts +14 -0
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +29 -0
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
- package/src/live-voice/__tests__/live-voice-vad.test.ts +0 -16
- package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
- package/src/live-voice/live-voice-archive.ts +2 -0
- package/src/live-voice/live-voice-manager.ts +16 -3
- package/src/live-voice/live-voice-metrics.ts +57 -32
- package/src/live-voice/live-voice-photo.ts +1 -2
- package/src/live-voice/live-voice-session.ts +598 -323
- package/src/live-voice/progress-narration.ts +277 -0
- package/src/live-voice/protocol.ts +21 -1
- package/src/live-voice/windows-compiled-live-voice.ts +4 -0
- package/src/mcp/__tests__/effective-config.test.ts +238 -0
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +200 -0
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
- package/src/mcp/__tests__/plugin-server-credential-isolation.test.ts +95 -0
- package/src/mcp/client.ts +16 -11
- package/src/mcp/effective-config.ts +113 -0
- package/src/mcp/manager.ts +11 -6
- package/src/mcp/mcp-auth-orchestrator.ts +13 -22
- package/src/mcp/mcp-oauth-provider.ts +205 -240
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +166 -3
- package/src/monitoring/control.ts +1 -0
- package/src/monitoring/db-integrity-sample.ts +4 -5
- package/src/monitoring/plugin-auto-update.ts +128 -24
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/approval-card-data.ts +33 -0
- package/src/notifications/signal.ts +1 -0
- package/src/permissions/AGENTS.md +16 -0
- package/src/permissions/checker.test.ts +75 -122
- package/src/permissions/checker.ts +44 -560
- package/src/permissions/confirmation-guardian-request.test.ts +15 -11
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/prompter.ts +1 -5
- package/src/permissions/question-guardian-request.test.ts +14 -6
- package/src/permissions/question-guardian-request.ts +1 -2
- package/src/persistence/attachments-store.ts +8 -1
- package/src/persistence/bookmark-crud.ts +3 -7
- package/src/persistence/conversation-attention-store.ts +16 -45
- package/src/persistence/conversation-crud.ts +33 -4
- package/src/persistence/conversation-lineage.ts +9 -0
- package/src/persistence/conversation-queries.ts +182 -52
- package/src/persistence/delivery-crud.ts +150 -36
- package/src/persistence/embeddings/qdrant-manager.ts +84 -49
- package/src/persistence/external-conversation-store.ts +32 -4
- package/src/persistence/llm-request-log-store.ts +4 -10
- package/src/persistence/llm-usage-store.ts +8 -3
- package/src/persistence/message-reads.test.ts +197 -0
- package/src/persistence/message-reads.ts +211 -0
- package/src/persistence/migrations/360-add-document-workspace-path.ts +5 -14
- package/src/persistence/migrations/366-chatgpt-subscription-row-identity.test.ts +120 -0
- package/src/persistence/migrations/366-chatgpt-subscription-row-identity.ts +62 -0
- package/src/persistence/real-user-turn-filter.ts +27 -3
- package/src/persistence/schema/documents.ts +4 -4
- package/src/persistence/steps.ts +9 -0
- package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
- package/src/plugin-api/constants.ts +8 -0
- package/src/plugin-api/conversation-turn.ts +195 -5
- package/src/plugin-api/index.ts +38 -6
- package/src/plugin-api/resolve-credential.ts +3 -2
- package/src/plugin-api/store-credential.ts +146 -0
- package/src/plugin-api/vision-support.test.ts +1 -1
- package/src/plugin-api/webhook-url.ts +13 -11
- package/src/plugins/__tests__/mcp-servers.test.ts +371 -0
- package/src/plugins/defaults/main.ts +21 -7
- package/src/plugins/defaults/memory/AGENTS.md +15 -3
- package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +204 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +72 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
- package/src/plugins/defaults/memory/buffer-format.ts +165 -0
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +6 -0
- package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +77 -0
- package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +24 -6
- package/src/plugins/defaults/memory/graph/image-ref-utils.ts +3 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -30
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.test.ts +34 -0
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +17 -24
- package/src/plugins/defaults/memory/hooks/post-compact.ts +1 -4
- package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +53 -5
- package/src/plugins/defaults/memory/indexer.ts +3 -1
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +19 -7
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +4 -4
- package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +281 -0
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
- package/src/plugins/defaults/memory/src/memory-v3-routes.ts +207 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +147 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
- package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
- package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
- package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
- package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
- package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
- package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +195 -58
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +93 -24
- package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
- package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
- package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
- package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
- package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
- package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
- package/src/plugins/defaults/memory/substrate/static-context.ts +160 -33
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +2 -4
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +3 -1
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +18 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +66 -1
- package/src/plugins/defaults/memory/v3/card.ts +9 -9
- package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
- package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
- package/src/plugins/defaults/memory/v3/edge.ts +13 -57
- package/src/plugins/defaults/memory/v3/injector.ts +8 -0
- package/src/plugins/defaults/memory/v3/prune.ts +2 -0
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +2 -0
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +23 -9
- package/src/plugins/defaults/memory/worker-control.ts +1 -0
- package/src/plugins/defaults/memory/worker.ts +6 -3
- package/src/plugins/defaults/worker-entrypoints.ts +3 -0
- package/src/plugins/external-plugin-loader.ts +47 -0
- package/src/plugins/mcp-servers.ts +361 -0
- package/src/plugins/mtime-cache.ts +37 -46
- package/src/plugins/pipeline.ts +14 -7
- package/src/plugins/plugin-execution-context.ts +35 -11
- package/src/plugins/worker-plugin-surface.ts +33 -0
- package/src/prompts/templates/system-sections.ts +0 -7
- package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
- package/src/providers/__tests__/context-overflow-error.test.ts +24 -0
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +214 -2
- package/src/providers/__tests__/preflight-resolved-config.test.ts +57 -0
- package/src/providers/__tests__/retry-callsite.test.ts +25 -2
- package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
- package/src/providers/anthropic/client.ts +332 -241
- package/src/providers/call-site-routing.ts +30 -3
- package/src/providers/connection-resolution.ts +194 -11
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +4 -0
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/inference/auth.ts +6 -0
- package/src/providers/inference/connection-availability.ts +24 -2
- package/src/providers/inference/connections.ts +2 -0
- package/src/providers/model-catalog.ts +3 -3
- package/src/providers/model-intents.ts +28 -8
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +163 -40
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
- package/src/providers/openai/chat-completions-provider.ts +133 -36
- package/src/providers/openai/codex-models.ts +2 -1
- package/src/providers/provider-send-message.ts +32 -3
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +625 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +285 -6
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +679 -0
- package/src/providers/speech-to-text/provider-catalog.ts +99 -8
- package/src/providers/speech-to-text/resolve.ts +25 -2
- package/src/routes/control.ts +1 -0
- package/src/routes/route-host-client.ts +1 -0
- package/src/routes/route-host-protocol.ts +7 -0
- package/src/routes/worker.ts +48 -15
- package/src/runtime/AGENTS.md +16 -17
- package/src/runtime/access-request-helper.ts +9 -12
- package/src/runtime/agent-wake.ts +18 -15
- package/src/runtime/effective-capabilities.test.ts +43 -0
- package/src/runtime/effective-capabilities.ts +27 -0
- package/src/runtime/guardian-reply-router.ts +6 -2
- package/src/runtime/pre-first-message-gate.ts +4 -0
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +12 -4
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +522 -2
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +52 -0
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +61 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +44 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +102 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +132 -35
- package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +215 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +133 -1
- package/src/runtime/routes/channel-availability-routes.ts +32 -14
- package/src/runtime/routes/channel-route-shared.ts +0 -6
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +6 -6
- package/src/runtime/routes/conversation-list-routes.ts +181 -23
- package/src/runtime/routes/conversation-management-routes.ts +17 -12
- package/src/runtime/routes/conversation-query-routes.ts +40 -27
- package/src/runtime/routes/conversation-routes.ts +43 -29
- package/src/runtime/routes/credential-prompt-routes.ts +4 -7
- package/src/runtime/routes/credential-routes.ts +26 -82
- package/src/runtime/routes/default-provider-routes.ts +15 -0
- package/src/runtime/routes/documents-routes.ts +3 -222
- package/src/runtime/routes/inbound-message-handler.ts +21 -45
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -9
- package/src/runtime/routes/inbound-stages/admission-policy.ts +1 -17
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -79
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +12 -7
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -8
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -79
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +2 -3
- package/src/runtime/routes/inference-profiles-routes.ts +20 -11
- package/src/runtime/routes/inference-provider-connection-routes.ts +77 -15
- package/src/runtime/routes/log-export-routes.ts +3 -0
- package/src/runtime/routes/mcp-auth-routes.ts +148 -57
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +2 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +3 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -2
- package/src/runtime/routes/playground/reset-circuit.ts +1 -1
- package/src/runtime/routes/plugins-routes.ts +38 -8
- package/src/runtime/routes/schedule-routes.ts +94 -7
- package/src/runtime/routes/settings-routes.ts +6 -6
- package/src/runtime/routes/stt-routes.ts +31 -25
- package/src/runtime/routes/surface-action-routes.ts +20 -19
- package/src/runtime/routes/surface-conversation-resolver.ts +3 -0
- package/src/runtime/routes/user-route-dispatcher.ts +69 -15
- package/src/runtime/routes/user-route-import.ts +108 -0
- package/src/runtime/routes/user-route-resolution.ts +18 -1
- package/src/runtime/routes/workspace-routes.ts +0 -9
- package/src/runtime/routes/workspace-utils.ts +3 -13
- package/src/runtime/services/conversation-serializer.ts +7 -2
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +68 -5
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +81 -0
- package/src/schedule/plugin-schedule-availability.ts +58 -0
- package/src/schedule/plugin-schedule-declarations.ts +23 -27
- package/src/schedule/plugin-schedule-reconciler.ts +12 -3
- package/src/schedule/schedule-store.ts +5 -1
- package/src/schedule/scheduler.ts +9 -4
- package/src/schedule/worker-control.ts +1 -0
- package/src/schedule/worker.ts +6 -0
- package/src/security/oauth2.ts +6 -22
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
- package/src/stt/__tests__/types.test.ts +94 -0
- package/src/stt/daemon-batch-transcriber.ts +10 -0
- package/src/stt/stt-stream-session.ts +8 -4
- package/src/stt/types.ts +103 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +26 -15
- package/src/subagent/consult-context.ts +11 -11
- package/src/subagent/consult-prompt.ts +26 -35
- package/src/subagent/manager.ts +21 -40
- package/src/subagent/notify.ts +7 -1
- package/src/subagent/types.ts +15 -12
- package/src/tools/__tests__/tool-input-schemas.test.ts +7 -7
- package/src/tools/acp/spawn.test.ts +97 -0
- package/src/tools/acp/spawn.ts +38 -4
- package/src/tools/credentials/ref-parse.ts +35 -0
- package/src/tools/credentials/resolve.ts +4 -10
- package/src/tools/credentials/store.ts +168 -0
- package/src/tools/document/document-tool.ts +12 -3
- package/src/tools/executor.ts +53 -15
- package/src/tools/filesystem/read.ts +27 -10
- package/src/tools/host-filesystem/read.ts +27 -15
- package/src/tools/network/url-safety.ts +9 -16
- package/src/tools/permission-checker.ts +43 -52
- package/src/tools/registry.ts +2 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +63 -35
- package/src/tools/shared/filesystem/legacy-read-args.ts +22 -0
- package/src/tools/shared/filesystem/types.ts +5 -5
- package/src/tools/skills/scaffold-managed.ts +25 -7
- package/src/tools/subagent/spawn.ts +28 -88
- package/src/tools/tool-types.ts +26 -13
- package/src/tools/types.ts +6 -6
- package/src/tools/ui-surface/surface-shape-docs.ts +12 -1
- package/src/tools/workflows/run-workflow.ts +1 -2
- package/src/tts/__tests__/reasoning-tag-filter.test.ts +78 -0
- package/src/tts/reasoning-tag-filter.ts +89 -0
- package/src/util/__tests__/worker-process-command.test.ts +37 -0
- package/src/util/logger.ts +16 -0
- package/src/util/think-tag-stream.ts +95 -0
- package/src/util/worker-process.ts +37 -4
- package/src/windows-compiled-cli.ts +32 -0
- package/src/windows-compiled-entry.ts +4 -0
- package/src/windows-compiled-logger.ts +6 -0
- package/src/windows-compiled-worker-entry.ts +29 -0
- package/src/workspace/byok-default-profile-ensure.ts +76 -24
- package/src/workspace/custom-profile-ensure.ts +4 -24
- package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
- package/src/workspace/migrations/143-repair-deprecated-codex-model-id.ts +134 -0
- package/src/workspace/migrations/144-convert-stranded-subscription-openai-profiles.ts +265 -0
- package/src/workspace/migrations/145-collapse-profile-bindings-to-entries.ts +328 -0
- package/src/workspace/migrations/146-repair-retired-fireworks-deepseek-flash-model-id.ts +195 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +0 -10
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/workspace/provider-commit-message-generator.ts +7 -5
- package/src/__tests__/document-workspace-file.test.ts +0 -467
- package/src/live-voice/__tests__/front-decision.test.ts +0 -645
- package/src/live-voice/front-decision.ts +0 -476
- package/src/permissions/ipc-risk-types.ts +0 -143
- package/src/permissions/risk-types.ts +0 -76
- package/src/subagent/__tests__/consult-transcript.test.ts +0 -184
- package/src/subagent/consult-transcript.ts +0 -90
|
@@ -223,6 +223,35 @@ const STT_ERROR_MAP: Record<SttErrorCategory, () => RouteError> = {
|
|
|
223
223
|
"provider-error": () => new BadGatewayError("STT provider error"),
|
|
224
224
|
};
|
|
225
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Resolve the configured batch transcriber, or fail the request with a 503
|
|
228
|
+
* naming which kind of unavailability this is.
|
|
229
|
+
*
|
|
230
|
+
* A typed {@link SttError} already names the situation and its fix (a
|
|
231
|
+
* configured provider that cannot batch transcribe), so its message is
|
|
232
|
+
* surfaced verbatim. `null` means nothing is configured at all, and any other
|
|
233
|
+
* throw is an unexpected resolver failure.
|
|
234
|
+
*/
|
|
235
|
+
async function resolveBatchTranscriberOrUnavailable(): Promise<BatchTranscriber> {
|
|
236
|
+
let transcriber: BatchTranscriber | null;
|
|
237
|
+
try {
|
|
238
|
+
transcriber = await resolveBatchTranscriber();
|
|
239
|
+
} catch (err) {
|
|
240
|
+
if (err instanceof SttError) {
|
|
241
|
+
throw new ServiceUnavailableError(err.message);
|
|
242
|
+
}
|
|
243
|
+
log.error({ err }, "Failed to resolve STT transcriber");
|
|
244
|
+
throw new ServiceUnavailableError("STT provider is not available");
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (!transcriber) {
|
|
248
|
+
throw new ServiceUnavailableError(
|
|
249
|
+
"No speech-to-text provider is configured",
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
return transcriber;
|
|
253
|
+
}
|
|
254
|
+
|
|
226
255
|
// ---------------------------------------------------------------------------
|
|
227
256
|
// Handlers
|
|
228
257
|
// ---------------------------------------------------------------------------
|
|
@@ -288,19 +317,7 @@ async function handleTranscribe({ body }: RouteHandlerArgs) {
|
|
|
288
317
|
}
|
|
289
318
|
|
|
290
319
|
// -- Resolve transcriber --------------------------------------------------
|
|
291
|
-
|
|
292
|
-
try {
|
|
293
|
-
transcriber = await resolveBatchTranscriber();
|
|
294
|
-
} catch (err) {
|
|
295
|
-
log.error({ err }, "Failed to resolve STT transcriber");
|
|
296
|
-
throw new ServiceUnavailableError("STT provider is not available");
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (!transcriber) {
|
|
300
|
-
throw new ServiceUnavailableError(
|
|
301
|
-
"No speech-to-text provider is configured",
|
|
302
|
-
);
|
|
303
|
-
}
|
|
320
|
+
const transcriber = await resolveBatchTranscriberOrUnavailable();
|
|
304
321
|
|
|
305
322
|
// -- Transcribe with timeout ----------------------------------------------
|
|
306
323
|
const abortController = new AbortController();
|
|
@@ -358,18 +375,7 @@ async function handleTranscribeFile({ body }: RouteHandlerArgs) {
|
|
|
358
375
|
);
|
|
359
376
|
}
|
|
360
377
|
|
|
361
|
-
|
|
362
|
-
try {
|
|
363
|
-
transcriber = await resolveBatchTranscriber();
|
|
364
|
-
} catch (err) {
|
|
365
|
-
log.error({ err }, "Failed to resolve STT transcriber");
|
|
366
|
-
throw new ServiceUnavailableError("STT provider is not available");
|
|
367
|
-
}
|
|
368
|
-
if (!transcriber) {
|
|
369
|
-
throw new ServiceUnavailableError(
|
|
370
|
-
"No speech-to-text provider is configured",
|
|
371
|
-
);
|
|
372
|
-
}
|
|
378
|
+
const transcriber = await resolveBatchTranscriberOrUnavailable();
|
|
373
379
|
|
|
374
380
|
const startTime = Date.now();
|
|
375
381
|
let wavPath: string | null = null;
|
|
@@ -37,26 +37,25 @@ const log = getLogger("surface-action-routes");
|
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Resolve trust context for the actor principal from the gateway guardian
|
|
40
|
-
* binding and
|
|
41
|
-
* nobody, so the mapper yields guardian or
|
|
42
|
-
* dev-bypass principal translation and the
|
|
43
|
-
*
|
|
44
|
-
*
|
|
40
|
+
* binding, and return it for the caller to attribute this action with. A vellum
|
|
41
|
+
* principal is the guardian or nobody, so the mapper yields guardian or
|
|
42
|
+
* unknown. Resolution (including the dev-bypass principal translation and the
|
|
43
|
+
* mutating reset-drift repair) lives in the shared
|
|
44
|
+
* {@link resolveVellumActorTrustContext} so the surface content route's
|
|
45
|
+
* read-only requester scoping cannot drift from it.
|
|
46
|
+
*
|
|
47
|
+
* Resolution only: the requester travels to `handleSurfaceAction` as an
|
|
48
|
+
* argument, and the conversation's slot is stamped there, at the point the
|
|
49
|
+
* click is committed to starting a turn. Stamping here instead would repoint
|
|
50
|
+
* the actor of a turn already in flight, or of a turn that starts between this
|
|
51
|
+
* call and the dispatch.
|
|
45
52
|
*/
|
|
46
|
-
async function
|
|
47
|
-
conversation: {
|
|
48
|
-
setTrustContext?(ctx: TrustContext): void;
|
|
49
|
-
},
|
|
53
|
+
async function resolveRequesterTrustContext(
|
|
50
54
|
actorPrincipalId: string | undefined,
|
|
51
|
-
): Promise<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
conversation.setTrustContext(
|
|
56
|
-
await resolveVellumActorTrustContext(actorPrincipalId, {
|
|
57
|
-
healResetDrift: true,
|
|
58
|
-
}),
|
|
59
|
-
);
|
|
55
|
+
): Promise<TrustContext> {
|
|
56
|
+
return resolveVellumActorTrustContext(actorPrincipalId, {
|
|
57
|
+
healResetDrift: true,
|
|
58
|
+
});
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
// ---------------------------------------------------------------------------
|
|
@@ -154,7 +153,8 @@ async function handleSurfaceAction({
|
|
|
154
153
|
}
|
|
155
154
|
|
|
156
155
|
const actorPrincipalId = headers?.["x-vellum-actor-principal-id"];
|
|
157
|
-
|
|
156
|
+
const requesterTrustContext =
|
|
157
|
+
await resolveRequesterTrustContext(actorPrincipalId);
|
|
158
158
|
|
|
159
159
|
// Translate dev-bypass → real guardian so the surface turn's principal matches
|
|
160
160
|
// the SSE host-proxy client's registered principal; otherwise CU/app-control
|
|
@@ -170,6 +170,7 @@ async function handleSurfaceAction({
|
|
|
170
170
|
actionId,
|
|
171
171
|
data,
|
|
172
172
|
resolvedActorPrincipalId,
|
|
173
|
+
requesterTrustContext,
|
|
173
174
|
);
|
|
174
175
|
const result =
|
|
175
176
|
raw && typeof raw === "object" && "accepted" in raw
|
|
@@ -64,6 +64,9 @@ export async function resolveSurfaceConversation(
|
|
|
64
64
|
const escaped = surfaceId.replace(/[\\%_]/g, "\\$&");
|
|
65
65
|
const row = rawGet<{ conversation_id: string }>(
|
|
66
66
|
"surfaceResolver:resolveConversation",
|
|
67
|
+
// Unfinalized rows cannot match: their content is a { ref } pointer,
|
|
68
|
+
// never inline surface JSON, so the LIKE probes below see finalized
|
|
69
|
+
// content only by shape. No completeness predicate needed.
|
|
67
70
|
`SELECT conversation_id FROM messages
|
|
68
71
|
WHERE content LIKE ? ESCAPE '\\'
|
|
69
72
|
ORDER BY created_at DESC
|
|
@@ -27,13 +27,17 @@
|
|
|
27
27
|
* shows no route depends on it.
|
|
28
28
|
*
|
|
29
29
|
* Modules are lazily loaded on first request and cached by file path +
|
|
30
|
-
* mtime. When a file changes on disk, the next request
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* mtime. When a file changes on disk, the next request evicts the whole
|
|
31
|
+
* source tree that file belongs to (plugin root, or the workspace
|
|
32
|
+
* `routes/` directory) and re-imports the entry. Cache-busting only the
|
|
33
|
+
* entry file would re-bind it to stale helpers still in Bun's registry.
|
|
34
|
+
* A request whose file does not exist 404s. Nothing is registered ahead
|
|
35
|
+
* of time.
|
|
33
36
|
*/
|
|
34
37
|
|
|
35
38
|
import { statSync } from "node:fs";
|
|
36
39
|
|
|
40
|
+
import { runInPluginContext } from "../../plugins/plugin-execution-context.js";
|
|
37
41
|
import { isRouteHostEnabled } from "../../routes/control.js";
|
|
38
42
|
import {
|
|
39
43
|
RouteHostClient,
|
|
@@ -47,6 +51,12 @@ import {
|
|
|
47
51
|
type UserRouteContext,
|
|
48
52
|
} from "./deprecated-route-context.js";
|
|
49
53
|
import {
|
|
54
|
+
evictRouteSourceTree,
|
|
55
|
+
importRouteModule,
|
|
56
|
+
routeSourceRoot,
|
|
57
|
+
} from "./user-route-import.js";
|
|
58
|
+
import {
|
|
59
|
+
pluginNameForRoutePath,
|
|
50
60
|
resolveHandlerFile,
|
|
51
61
|
resolveRouteLocation,
|
|
52
62
|
} from "./user-route-resolution.js";
|
|
@@ -134,7 +144,7 @@ export class UserRouteDispatcher {
|
|
|
134
144
|
? resolveHandlerFile(location.routesDir, location.subPath)
|
|
135
145
|
: null;
|
|
136
146
|
|
|
137
|
-
if (!filePath) {
|
|
147
|
+
if (!location || !filePath) {
|
|
138
148
|
return httpError(
|
|
139
149
|
"NOT_FOUND",
|
|
140
150
|
`No route handler found for /x/${routePath}`,
|
|
@@ -142,11 +152,36 @@ export class UserRouteDispatcher {
|
|
|
142
152
|
);
|
|
143
153
|
}
|
|
144
154
|
|
|
155
|
+
// A plugin's own routes execute as that plugin, so the host APIs a handler
|
|
156
|
+
// reaches scope to it exactly as they do inside its hooks and tools. Both
|
|
157
|
+
// execution paths carry it: in-thread here, and the route host through the
|
|
158
|
+
// invoke params it marks its own execution with.
|
|
159
|
+
const pluginName = pluginNameForRoutePath(routePath);
|
|
160
|
+
|
|
145
161
|
if (isRouteHostEnabled()) {
|
|
146
|
-
return this.dispatchViaHost(filePath, routePath, request);
|
|
162
|
+
return this.dispatchViaHost(filePath, routePath, request, pluginName);
|
|
147
163
|
}
|
|
148
164
|
|
|
149
|
-
|
|
165
|
+
// The context covers module evaluation, not just the handler call. A route
|
|
166
|
+
// module can reach a scoped host API at import time (a top-level `await`),
|
|
167
|
+
// and that import happens once per mtime, so a load left outside the
|
|
168
|
+
// context would take the unscoped branch and never be re-run scoped.
|
|
169
|
+
const serve = () =>
|
|
170
|
+
this.serveInThread(filePath, location.routesDir, routePath, request);
|
|
171
|
+
return pluginName ? runInPluginContext(pluginName, serve) : serve();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Load the handler module and run the method's handler in this thread.
|
|
176
|
+
* Called inside the owning plugin's execution context, when the route has one.
|
|
177
|
+
*/
|
|
178
|
+
private async serveInThread(
|
|
179
|
+
filePath: string,
|
|
180
|
+
routesDir: string,
|
|
181
|
+
routePath: string,
|
|
182
|
+
request: Request,
|
|
183
|
+
): Promise<Response> {
|
|
184
|
+
const mod = await this.loadModule(filePath, routesDir);
|
|
150
185
|
const method = request.method as HttpMethod;
|
|
151
186
|
const handler = mod.handlers[method];
|
|
152
187
|
|
|
@@ -172,6 +207,7 @@ export class UserRouteDispatcher {
|
|
|
172
207
|
filePath: string,
|
|
173
208
|
routePath: string,
|
|
174
209
|
request: Request,
|
|
210
|
+
pluginName: string | undefined,
|
|
175
211
|
): Promise<Response> {
|
|
176
212
|
const mtimeMs = statSync(filePath).mtimeMs;
|
|
177
213
|
|
|
@@ -193,6 +229,7 @@ export class UserRouteDispatcher {
|
|
|
193
229
|
method: request.method,
|
|
194
230
|
url: request.url,
|
|
195
231
|
headers,
|
|
232
|
+
pluginName,
|
|
196
233
|
},
|
|
197
234
|
body,
|
|
198
235
|
);
|
|
@@ -231,11 +268,15 @@ export class UserRouteDispatcher {
|
|
|
231
268
|
/**
|
|
232
269
|
* Load a handler module, using the mtime-based cache when possible.
|
|
233
270
|
*
|
|
234
|
-
* On cache miss or stale mtime,
|
|
235
|
-
*
|
|
236
|
-
*
|
|
271
|
+
* On cache miss or stale mtime, every source file in the handler's tree
|
|
272
|
+
* is evicted first so a new entry cannot import a helper that is still
|
|
273
|
+
* the pre-upgrade module. Then the entry is re-imported with an mtime
|
|
274
|
+
* query parameter.
|
|
237
275
|
*/
|
|
238
|
-
private async loadModule(
|
|
276
|
+
private async loadModule(
|
|
277
|
+
filePath: string,
|
|
278
|
+
routesDir: string,
|
|
279
|
+
): Promise<CachedModule> {
|
|
239
280
|
const stat = statSync(filePath);
|
|
240
281
|
const mtimeMs = stat.mtimeMs;
|
|
241
282
|
|
|
@@ -244,11 +285,11 @@ export class UserRouteDispatcher {
|
|
|
244
285
|
return cached;
|
|
245
286
|
}
|
|
246
287
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
288
|
+
const sourceRoot = routeSourceRoot(routesDir);
|
|
289
|
+
evictRouteSourceTree(sourceRoot);
|
|
290
|
+
this.dropCachedModulesUnder(sourceRoot);
|
|
291
|
+
|
|
292
|
+
const mod = await importRouteModule(filePath);
|
|
252
293
|
|
|
253
294
|
const handlers: Partial<Record<HttpMethod, RouteHandler>> = {};
|
|
254
295
|
for (const method of HTTP_METHODS) {
|
|
@@ -271,6 +312,19 @@ export class UserRouteDispatcher {
|
|
|
271
312
|
return entry;
|
|
272
313
|
}
|
|
273
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Drop every cached handler under `sourceRoot`. Sibling routes must not
|
|
317
|
+
* keep closures over the helpers we just evicted.
|
|
318
|
+
*/
|
|
319
|
+
private dropCachedModulesUnder(sourceRoot: string): void {
|
|
320
|
+
const prefix = sourceRoot.endsWith("/") ? sourceRoot : `${sourceRoot}/`;
|
|
321
|
+
for (const path of this.moduleCache.keys()) {
|
|
322
|
+
if (path === sourceRoot || path.startsWith(prefix)) {
|
|
323
|
+
this.moduleCache.delete(path);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
274
328
|
/**
|
|
275
329
|
* Execute a handler function with a per-request timeout and error boundary.
|
|
276
330
|
*/
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import a user/plugin route module so its helpers match the files on disk.
|
|
3
|
+
*
|
|
4
|
+
* Bun caches every imported helper independently. Cache-busting only the
|
|
5
|
+
* entry file (`import(file?t=mtime)`) re-binds it to whatever helpers are
|
|
6
|
+
* already in the registry. That is how a new route that imports a new export
|
|
7
|
+
* from `src/http.ts` 500s with "Export named 'requireNumber' not found" while
|
|
8
|
+
* `/frame` (still on the old http.ts surface) keeps answering 200.
|
|
9
|
+
*
|
|
10
|
+
* Hooks and tools already treat the whole plugin directory as the reload
|
|
11
|
+
* unit (`plugins/source-fingerprint.ts`). Routes must do the same: when the
|
|
12
|
+
* entry file's mtime moves, evict every source file in that tree before the
|
|
13
|
+
* next import, so the new entry cannot pair with a stale helper.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { statSync } from "node:fs";
|
|
17
|
+
import { dirname, sep } from "node:path";
|
|
18
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
19
|
+
|
|
20
|
+
import { snapshotPluginSource } from "../../plugins/source-fingerprint.js";
|
|
21
|
+
import { evictModule } from "../../plugins/surface-import.js";
|
|
22
|
+
import { getWorkspaceRoutesDir } from "../../util/platform.js";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Directory whose source files must stay mutually consistent with this
|
|
26
|
+
* handler. An installed or default plugin uses the plugin root (so `src/`
|
|
27
|
+
* helpers evict with `routes/`). Workspace routes use the workspace
|
|
28
|
+
* `routes/` directory.
|
|
29
|
+
*/
|
|
30
|
+
export function routeSourceRoot(routesDir: string): string {
|
|
31
|
+
if (routesDir === getWorkspaceRoutesDir()) {
|
|
32
|
+
return routesDir;
|
|
33
|
+
}
|
|
34
|
+
return dirname(routesDir);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Infer the source root from a handler path when the caller has no
|
|
39
|
+
* {@link routeSourceRoot} (the route-host worker only sees `filePath`).
|
|
40
|
+
*/
|
|
41
|
+
export function sourceRootForHandler(filePath: string): string {
|
|
42
|
+
const marker = `${sep}routes${sep}`;
|
|
43
|
+
const idx = filePath.lastIndexOf(marker);
|
|
44
|
+
if (idx !== -1) {
|
|
45
|
+
return filePath.slice(0, idx);
|
|
46
|
+
}
|
|
47
|
+
return dirname(filePath);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Drop every source module under `sourceRoot` from the runtime registry,
|
|
52
|
+
* including query-string aliases (`file.ts?t=mtime`) the dispatcher uses to
|
|
53
|
+
* cache-bust the entry file.
|
|
54
|
+
*/
|
|
55
|
+
export function evictRouteSourceTree(sourceRoot: string): void {
|
|
56
|
+
const { evictionPaths } = snapshotPluginSource(sourceRoot);
|
|
57
|
+
for (const path of evictionPaths) {
|
|
58
|
+
evictModule(path);
|
|
59
|
+
}
|
|
60
|
+
evictRegistryAliases(sourceRoot);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function evictRegistryAliases(sourceRoot: string): void {
|
|
64
|
+
const prefix = sourceRoot.endsWith("/") ? sourceRoot : `${sourceRoot}/`;
|
|
65
|
+
const fileUrlPrefix = pathToFileURL(prefix).href;
|
|
66
|
+
for (const key of Object.keys(require.cache)) {
|
|
67
|
+
if (!keyBelongsToTree(key, sourceRoot, prefix, fileUrlPrefix)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
delete require.cache[key];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function keyBelongsToTree(
|
|
75
|
+
key: string,
|
|
76
|
+
sourceRoot: string,
|
|
77
|
+
prefix: string,
|
|
78
|
+
fileUrlPrefix: string,
|
|
79
|
+
): boolean {
|
|
80
|
+
const bare = key.split("?")[0] ?? key;
|
|
81
|
+
if (bare.includes("/node_modules/") || bare.includes("/node_modules?")) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
if (
|
|
85
|
+
bare === sourceRoot ||
|
|
86
|
+
bare.startsWith(prefix) ||
|
|
87
|
+
bare.startsWith(fileUrlPrefix)
|
|
88
|
+
) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
if (bare.startsWith("file:")) {
|
|
92
|
+
try {
|
|
93
|
+
const asPath = fileURLToPath(bare);
|
|
94
|
+
return asPath === sourceRoot || asPath.startsWith(prefix);
|
|
95
|
+
} catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Dynamic-import a handler, cache-busted by the file's current mtime. */
|
|
103
|
+
export async function importRouteModule(
|
|
104
|
+
filePath: string,
|
|
105
|
+
): Promise<Record<string, unknown>> {
|
|
106
|
+
const mtimeMs = statSync(filePath).mtimeMs;
|
|
107
|
+
return (await import(`${filePath}?t=${mtimeMs}`)) as Record<string, unknown>;
|
|
108
|
+
}
|
|
@@ -66,6 +66,23 @@ export interface RouteLocation {
|
|
|
66
66
|
subPath: string;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* The manifest name of the plugin whose namespace an `/x/` route path falls in,
|
|
71
|
+
* or undefined for a workspace route.
|
|
72
|
+
*
|
|
73
|
+
* The dispatcher marks that plugin as in context for the handler's execution,
|
|
74
|
+
* so host APIs a route handler reaches (`resolveCredential`,
|
|
75
|
+
* `indexDocument`) scope to the owning plugin exactly as they do inside its
|
|
76
|
+
* hooks and tools.
|
|
77
|
+
*/
|
|
78
|
+
export function pluginNameForRoutePath(routePath: string): string | undefined {
|
|
79
|
+
const segments = routePath.split("/");
|
|
80
|
+
if (segments[0] !== PLUGIN_ROUTE_SEGMENT) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
return segments[1] || undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
69
86
|
/**
|
|
70
87
|
* Resolve an `/x/` route path to the base directory + sub-path the handler file
|
|
71
88
|
* is looked up under.
|
|
@@ -87,7 +104,7 @@ export interface RouteLocation {
|
|
|
87
104
|
export function resolveRouteLocation(routePath: string): RouteLocation | null {
|
|
88
105
|
const segments = routePath.split("/");
|
|
89
106
|
if (segments[0] === PLUGIN_ROUTE_SEGMENT) {
|
|
90
|
-
const pluginName =
|
|
107
|
+
const pluginName = pluginNameForRoutePath(routePath);
|
|
91
108
|
if (!pluginName) {
|
|
92
109
|
return null;
|
|
93
110
|
}
|
|
@@ -19,7 +19,6 @@ import { basename, dirname, join } from "node:path";
|
|
|
19
19
|
|
|
20
20
|
import { z } from "zod";
|
|
21
21
|
|
|
22
|
-
import { rebindDocumentsToRenamedPath } from "../../documents/document-store.js";
|
|
23
22
|
import { getWorkspaceDir } from "../../util/platform.js";
|
|
24
23
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
25
24
|
import { publishSoundsConfigUpdated } from "../sync/resource-sync-events.js";
|
|
@@ -35,7 +34,6 @@ import {
|
|
|
35
34
|
isTextMimeType,
|
|
36
35
|
MAX_INLINE_TEXT_SIZE,
|
|
37
36
|
resolveWorkspacePath,
|
|
38
|
-
toWorkspaceRelativePath,
|
|
39
37
|
writeWorkspaceFile,
|
|
40
38
|
} from "./workspace-utils.js";
|
|
41
39
|
|
|
@@ -505,13 +503,6 @@ function handleWorkspaceRename({ body, headers }: RouteHandlerArgs) {
|
|
|
505
503
|
|
|
506
504
|
mkdirSync(dirname(resolvedNew), { recursive: true });
|
|
507
505
|
renameSync(resolvedOld, resolvedNew);
|
|
508
|
-
// File-backed documents key off the canonical relative path, so they follow
|
|
509
|
-
// the file to its new name. The request strings are not canonical, hence the
|
|
510
|
-
// resolved paths.
|
|
511
|
-
rebindDocumentsToRenamedPath({
|
|
512
|
-
oldPath: toWorkspaceRelativePath(resolvedOld),
|
|
513
|
-
newPath: toWorkspaceRelativePath(resolvedNew),
|
|
514
|
-
});
|
|
515
506
|
publishSoundsConfigUpdatedForPaths(
|
|
516
507
|
[oldPath, newPath],
|
|
517
508
|
headers?.["x-vellum-client-id"]?.trim() || undefined,
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
statSync,
|
|
7
7
|
writeFileSync,
|
|
8
8
|
} from "node:fs";
|
|
9
|
-
import { dirname,
|
|
9
|
+
import { dirname, resolve, sep } from "node:path";
|
|
10
10
|
|
|
11
11
|
import { getWorkspaceDir } from "../../util/platform.js";
|
|
12
12
|
import { BadRequestError, ConflictError } from "./errors.js";
|
|
@@ -85,22 +85,12 @@ export function resolveWorkspacePath(
|
|
|
85
85
|
return resolved;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
/**
|
|
89
|
-
* Normalise a workspace path to the canonical relative form used as a stable
|
|
90
|
-
* key for the file — forward slashes, no `.`/`..` segments, no leading slash.
|
|
91
|
-
* `absolutePath` must already have passed {@link resolveWorkspacePath}.
|
|
92
|
-
*/
|
|
93
|
-
export function toWorkspaceRelativePath(absolutePath: string): string {
|
|
94
|
-
return relative(getWorkspaceDir(), absolutePath).split(sep).join("/");
|
|
95
|
-
}
|
|
96
|
-
|
|
97
88
|
/**
|
|
98
89
|
* Write bytes to a workspace-relative path, enforcing the workspace boundary.
|
|
99
90
|
*
|
|
100
91
|
* This is the one write primitive behind every daemon-side workspace file
|
|
101
|
-
* write
|
|
102
|
-
*
|
|
103
|
-
* directory-conflict rules cannot drift apart.
|
|
92
|
+
* write, so the traversal and directory-conflict rules cannot drift apart
|
|
93
|
+
* between callers.
|
|
104
94
|
*
|
|
105
95
|
* Returns the number of bytes written. Throws {@link BadRequestError} when the
|
|
106
96
|
* path escapes the workspace and {@link ConflictError} when it names a
|
|
@@ -244,13 +244,18 @@ export function serializeConversationSummary(params: {
|
|
|
244
244
|
|
|
245
245
|
/**
|
|
246
246
|
* Build a full conversation detail response from a conversation ID.
|
|
247
|
-
* Returns null if the conversation doesn't exist
|
|
247
|
+
* Returns null if the conversation doesn't exist, or if it is a legacy
|
|
248
|
+
* `private` row: every listing hides those by type (see
|
|
249
|
+
* `standardListingVisibilitySql`) and migration cleanup deletes them, and the
|
|
250
|
+
* wire type collapses the value to `standard`, so serving one by id would let
|
|
251
|
+
* a client that only holds a stale id (a persisted last-viewed conversation)
|
|
252
|
+
* resurrect a row it can never see listed.
|
|
248
253
|
*/
|
|
249
254
|
export function buildConversationDetailResponse(
|
|
250
255
|
conversationId: string,
|
|
251
256
|
): { conversation: ReturnType<typeof serializeConversationSummary> } | null {
|
|
252
257
|
const conversation = getConversation(conversationId);
|
|
253
|
-
if (!conversation) {
|
|
258
|
+
if (!conversation || conversation.conversationType === "private") {
|
|
254
259
|
return null;
|
|
255
260
|
}
|
|
256
261
|
|
|
@@ -487,11 +487,39 @@ describe("parsePluginScheduleDeclarations", () => {
|
|
|
487
487
|
expect(after).not.toBe(before);
|
|
488
488
|
});
|
|
489
489
|
|
|
490
|
-
test("changes when
|
|
490
|
+
test("changes when config.json is edited", () => {
|
|
491
|
+
const pluginDir = makePlugin(FULL_DIGEST);
|
|
492
|
+
const before = parsePluginScheduleDeclarations(pluginDir, "p")
|
|
493
|
+
.declarations[0]!.definitionHash;
|
|
494
|
+
writeFileSync(
|
|
495
|
+
join(pluginDir, "schedules", "digest", "config.json"),
|
|
496
|
+
JSON.stringify({ expression: "0 10 * * *" }),
|
|
497
|
+
);
|
|
498
|
+
const after = parsePluginScheduleDeclarations(pluginDir, "p")
|
|
499
|
+
.declarations[0]!.definitionHash;
|
|
500
|
+
expect(after).not.toBe(before);
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
test("changes when the index.sh entrypoint is edited", () => {
|
|
504
|
+
const pluginDir = makePlugin({
|
|
505
|
+
"backup/config.json": JSON.stringify({ expression: "0 3 * * *" }),
|
|
506
|
+
"backup/index.sh": "echo v1\n",
|
|
507
|
+
});
|
|
508
|
+
const parse = () =>
|
|
509
|
+
parsePluginScheduleDeclarations(pluginDir, "p").declarations[0]!
|
|
510
|
+
.definitionHash;
|
|
511
|
+
const before = parse();
|
|
512
|
+
writeFileSync(
|
|
513
|
+
join(pluginDir, "schedules", "backup", "index.sh"),
|
|
514
|
+
"echo v2\n",
|
|
515
|
+
);
|
|
516
|
+
expect(parse()).not.toBe(before);
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
test("ignores every other file under the declaration directory", () => {
|
|
491
520
|
const pluginDir = makePlugin({
|
|
492
521
|
"backup/config.json": JSON.stringify({ expression: "0 3 * * *" }),
|
|
493
522
|
"backup/index.sh": "sh lib/helper.sh\n",
|
|
494
|
-
"backup/lib/helper.sh": "echo v1\n",
|
|
495
523
|
});
|
|
496
524
|
const parse = () =>
|
|
497
525
|
parsePluginScheduleDeclarations(pluginDir, "p").declarations[0]!
|
|
@@ -505,15 +533,50 @@ describe("parsePluginScheduleDeclarations", () => {
|
|
|
505
533
|
"lib",
|
|
506
534
|
"helper.sh",
|
|
507
535
|
);
|
|
536
|
+
mkdirSync(dirname(helperPath), { recursive: true });
|
|
537
|
+
writeFileSync(helperPath, "echo v1\n");
|
|
538
|
+
const statePath = join(
|
|
539
|
+
pluginDir,
|
|
540
|
+
"schedules",
|
|
541
|
+
"backup",
|
|
542
|
+
"data",
|
|
543
|
+
"state.json",
|
|
544
|
+
);
|
|
545
|
+
mkdirSync(dirname(statePath), { recursive: true });
|
|
546
|
+
writeFileSync(statePath, JSON.stringify({ lastRun: 1 }));
|
|
547
|
+
expect(parse()).toBe(original);
|
|
548
|
+
|
|
508
549
|
writeFileSync(helperPath, "echo v2\n");
|
|
509
|
-
|
|
510
|
-
expect(
|
|
550
|
+
writeFileSync(statePath, JSON.stringify({ lastRun: 2 }));
|
|
551
|
+
expect(parse()).toBe(original);
|
|
511
552
|
|
|
512
553
|
renameSync(
|
|
513
554
|
helperPath,
|
|
514
555
|
join(pluginDir, "schedules", "backup", "lib", "helper2.sh"),
|
|
515
556
|
);
|
|
516
|
-
expect(parse()).
|
|
557
|
+
expect(parse()).toBe(original);
|
|
558
|
+
|
|
559
|
+
rmSync(join(pluginDir, "schedules", "backup", "data"), {
|
|
560
|
+
recursive: true,
|
|
561
|
+
force: true,
|
|
562
|
+
});
|
|
563
|
+
expect(parse()).toBe(original);
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
test("hashes a two-file declaration to its known value", () => {
|
|
567
|
+
const pluginDir = makePlugin({
|
|
568
|
+
"backup/config.json": JSON.stringify({ expression: "0 3 * * *" }),
|
|
569
|
+
"backup/index.sh": "echo backup\n",
|
|
570
|
+
});
|
|
571
|
+
// Pinned so stored rows keep their hash across upgrades. It holds only
|
|
572
|
+
// while the hashed paths stay `<name>/config.json` and
|
|
573
|
+
// `<name>/<entrypoint>`, relative to schedules/.
|
|
574
|
+
expect(
|
|
575
|
+
parsePluginScheduleDeclarations(pluginDir, "p").declarations[0]!
|
|
576
|
+
.definitionHash,
|
|
577
|
+
).toBe(
|
|
578
|
+
"0b5722fc45abdd2c46672f275e3bcf548016ee5c0722da5a0588ef45fa7bbcab",
|
|
579
|
+
);
|
|
517
580
|
});
|
|
518
581
|
|
|
519
582
|
test("differs between two schedules with different names but same content", () => {
|