@vellumai/assistant 0.10.2-dev.202606250318.5e7cfb0 → 0.10.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/bun.lock +0 -20
- package/docs/workspace-tools.md +33 -42
- package/eslint-rules/cli-no-daemon-internals.js +0 -6
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +0 -31
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +0 -44
- package/node_modules/@vellumai/gateway-client/src/index.ts +0 -14
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +0 -17
- package/node_modules/@vellumai/service-contracts/package.json +0 -1
- package/node_modules/@vellumai/service-contracts/src/index.ts +0 -1
- package/openapi.yaml +0 -155
- package/package.json +1 -4
- package/scripts/test.sh +15 -36
- package/src/__tests__/actor-token-service.test.ts +14 -36
- package/src/__tests__/agent-loop-override-profile.test.ts +0 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -2
- package/src/__tests__/agent-wake-override-profile.test.ts +0 -2
- package/src/__tests__/annotate-activity-metadata.test.ts +0 -2
- package/src/__tests__/annotate-risk-options.test.ts +0 -2
- package/src/__tests__/approval-cascade.test.ts +0 -2
- package/src/__tests__/assistant-attachments.test.ts +0 -42
- package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
- package/src/__tests__/btw-routes.test.ts +0 -2
- package/src/__tests__/build-persisted-content.test.ts +0 -2
- package/src/__tests__/call-controller.test.ts +0 -19
- package/src/__tests__/channel-guardian.test.ts +58 -94
- package/src/__tests__/channel-reply-delivery.test.ts +0 -2
- package/src/__tests__/compaction-events.test.ts +0 -2
- package/src/__tests__/compaction.benchmark.test.ts +0 -2
- package/src/__tests__/compactor-call-site-logging.test.ts +0 -2
- package/src/__tests__/compactor-low-watermark-cut.test.ts +0 -2
- package/src/__tests__/compactor-preserved-tail-count.test.ts +0 -2
- package/src/__tests__/compactor-summary-call-truncation.test.ts +0 -2
- package/src/__tests__/compactor-web-search-strip.test.ts +0 -2
- package/src/__tests__/config-loader-backfill.test.ts +10 -123
- package/src/__tests__/config-schema.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -31
- package/src/__tests__/contacts-relay-reads.test.ts +15 -13
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop.test.ts +0 -134
- package/src/__tests__/conversation-analysis-routes.test.ts +0 -2
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +0 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -2
- package/src/__tests__/conversation-history-web-search.test.ts +0 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +0 -2
- package/src/__tests__/conversation-load-history-stripped.test.ts +0 -2
- package/src/__tests__/conversation-pairing.test.ts +0 -2
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +0 -2
- package/src/__tests__/conversation-process-callsite.test.ts +0 -2
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -2
- package/src/__tests__/conversation-queue.test.ts +0 -91
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -14
- package/src/__tests__/conversation-routes-slash-commands.test.ts +0 -14
- package/src/__tests__/conversation-slash-queue.test.ts +0 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -2
- package/src/__tests__/conversation-speed-override.test.ts +0 -2
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -29
- package/src/__tests__/conversation-title-service.test.ts +0 -2
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -47
- package/src/__tests__/conversation-usage.test.ts +0 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -2
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/db-migration-rollback.test.ts +171 -205
- package/src/__tests__/db-test-helpers.ts +4 -5
- package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -4
- package/src/__tests__/disk-pressure-guard.test.ts +0 -41
- package/src/__tests__/dm-persistence.test.ts +0 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +5 -10
- package/src/__tests__/events-dev-bypass-actor.test.ts +1 -7
- package/src/__tests__/exploration-drift-hook.test.ts +2 -3
- package/src/__tests__/filing-service.test.ts +0 -2
- package/src/__tests__/guardian-binding-drift-heal.test.ts +10 -75
- package/src/__tests__/guardian-dispatch.test.ts +1 -95
- package/src/__tests__/guardian-outbound-http.test.ts +0 -13
- package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -2
- package/src/__tests__/heartbeat-service.test.ts +0 -2
- package/src/__tests__/helpers/channel-test-adapter.ts +7 -1
- package/src/__tests__/host-app-control-routes.test.ts +30 -24
- package/src/__tests__/host-bash-routes.test.ts +41 -31
- package/src/__tests__/host-browser-routes.test.ts +32 -26
- package/src/__tests__/host-cu-routes-targeted.test.ts +33 -25
- package/src/__tests__/host-file-routes-targeted.test.ts +52 -40
- package/src/__tests__/host-transfer-routes-targeted.test.ts +43 -31
- package/src/__tests__/http-user-message-parity.test.ts +8 -290
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -28
- package/src/__tests__/inbound-slack-persistence.test.ts +0 -2
- package/src/__tests__/invite-redemption-service.test.ts +0 -198
- package/src/__tests__/llm-context-normalization.test.ts +0 -105
- package/src/__tests__/llm-request-log-error-payload.test.ts +9 -71
- package/src/__tests__/llm-usage-store.test.ts +0 -25
- package/src/__tests__/mcp-health-check.test.ts +1 -2
- package/src/__tests__/media-stream-server-integration.test.ts +0 -127
- package/src/__tests__/memory-retrieval-hook.test.ts +0 -2
- package/src/__tests__/messaging-send-tool.test.ts +0 -2
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/mtime-cache.test.ts +5 -146
- package/src/__tests__/native-web-search.test.ts +0 -2
- package/src/__tests__/non-member-access-request.test.ts +17 -189
- package/src/__tests__/notification-broadcaster.test.ts +0 -4
- package/src/__tests__/notification-decision-recipient-context.test.ts +32 -33
- package/src/__tests__/notification-deep-link.test.ts +0 -6
- package/src/__tests__/notification-guardian-path.test.ts +0 -19
- package/src/__tests__/openai-provider.test.ts +12 -22
- package/src/__tests__/openai-responses-provider.test.ts +2 -12
- package/src/__tests__/outbound-slack-persistence.test.ts +0 -2
- package/src/__tests__/pending-interactions-resolved-event.test.ts +4 -7
- package/src/__tests__/persistence-secret-redaction.test.ts +0 -2
- package/src/__tests__/plugin-bootstrap.test.ts +73 -3
- package/src/__tests__/plugin-route-contribution.test.ts +17 -4
- package/src/__tests__/plugin-tool-contribution.test.ts +18 -3
- package/src/__tests__/plugin-types.test.ts +2 -0
- package/src/__tests__/process-message-background-slack.test.ts +0 -2
- package/src/__tests__/process-message-display-content.test.ts +0 -2
- package/src/__tests__/provider-error-scenarios.test.ts +4 -5
- package/src/__tests__/provider-usage-tracking.test.ts +0 -39
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -2
- package/src/__tests__/registry.test.ts +1 -4
- package/src/__tests__/relay-server.test.ts +25 -694
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -0
- package/src/__tests__/secret-ingress-http.test.ts +0 -14
- package/src/__tests__/send-endpoint-busy.test.ts +8 -30
- package/src/__tests__/skills.test.ts +0 -44
- package/src/__tests__/slack-inbound-verification.test.ts +2 -47
- package/src/__tests__/stt-hints.test.ts +13 -44
- package/src/__tests__/subagent-detail.test.ts +0 -27
- package/src/__tests__/subagent-disposal.test.ts +0 -65
- package/src/__tests__/subagent-notify-parent.test.ts +0 -2
- package/src/__tests__/subagent-role-registry.test.ts +2 -7
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +0 -2
- package/src/__tests__/subagent-tools.test.ts +0 -2
- package/src/__tests__/suggestion-routes.test.ts +0 -2
- package/src/__tests__/title-generate-hook.test.ts +0 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -2
- package/src/__tests__/tool-executor.test.ts +11 -16
- package/src/__tests__/tool-preview-lifecycle.test.ts +0 -2
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +0 -2
- package/src/__tests__/tool-start-timestamp.test.ts +0 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
- package/src/__tests__/twilio-routes.test.ts +0 -96
- package/src/__tests__/ui-file-upload-surface.test.ts +0 -86
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/voice-invite-redemption.test.ts +0 -33
- package/src/__tests__/web-search-backend-failure.test.ts +0 -2
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +35 -14
- package/src/__tests__/workspace-tool-loader.test.ts +2 -195
- package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
- package/src/agent/loop.ts +0 -56
- package/src/api/index.ts +1 -19
- package/src/api/responses/llm-request-log-entry.ts +0 -29
- package/src/api/responses/subagent-detail.ts +0 -17
- package/src/api/surfaces.ts +3 -39
- package/src/approvals/guardian-request-resolvers.ts +11 -1
- package/src/calls/__tests__/relay-setup-router.test.ts +4 -262
- package/src/calls/call-domain.ts +3 -3
- package/src/calls/guardian-dispatch.ts +8 -10
- package/src/calls/inbound-trust-reader.ts +1 -17
- package/src/calls/media-stream-server.ts +0 -21
- package/src/calls/relay-server.ts +50 -167
- package/src/calls/relay-setup-router.ts +7 -37
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/stt-hints.ts +12 -9
- package/src/calls/twilio-routes.ts +4 -14
- package/src/channels/types.ts +20 -10
- package/src/cli/commands/__tests__/cache.test.ts +1 -8
- package/src/cli/commands/cache.ts +181 -194
- package/src/cli/commands/db/__tests__/repair.test.ts +5 -6
- package/src/cli/commands/db/status.ts +1 -37
- package/src/cli/commands/mcp.ts +218 -252
- package/src/cli/commands/memory/index.ts +0 -2
- package/src/cli/commands/plugins.ts +3 -75
- package/src/cli/lib/__tests__/install-from-github.test.ts +0 -102
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +1 -160
- package/src/cli/lib/list-installed-plugins.ts +1 -179
- package/src/config/__tests__/sync-gated-profiles.test.ts +3 -11
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +17 -27
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +3 -13
- package/src/config/bundled-skills/subagent/SKILL.md +1 -1
- package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
- package/src/config/feature-flag-registry.json +13 -5
- package/src/config/loader.ts +5 -38
- package/src/config/schemas/__tests__/memory-v3.test.ts +0 -1
- package/src/config/schemas/memory-lifecycle.ts +0 -12
- package/src/config/schemas/memory-v3.ts +0 -7
- package/src/config/schemas/memory.ts +0 -4
- package/src/config/schemas/timeouts.ts +0 -8
- package/src/config/seed-inference-profiles.ts +11 -21
- package/src/config/skills.ts +5 -27
- package/src/config/sync-gated-profiles.ts +13 -12
- package/src/contacts/contacts-write.ts +0 -3
- package/src/daemon/assistant-attachments.ts +4 -27
- package/src/daemon/conversation-agent-loop.ts +0 -28
- package/src/daemon/conversation-process.ts +16 -35
- package/src/daemon/conversation-surfaces.ts +38 -111
- package/src/daemon/conversation-tool-setup.ts +16 -50
- package/src/daemon/conversation.ts +1 -13
- package/src/daemon/disk-pressure-guard.ts +2 -12
- package/src/daemon/event-loop-watchdog.ts +1 -28
- package/src/daemon/external-plugins-bootstrap.ts +34 -4
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -25
- package/src/daemon/handlers/config-a2a.ts +14 -6
- package/src/daemon/handlers/config-channels.ts +22 -78
- package/src/daemon/handlers/conversations.ts +0 -77
- package/src/daemon/lifecycle.ts +0 -4
- package/src/daemon/mcp-reload-service.ts +0 -10
- package/src/daemon/memory-v2-startup.test.ts +0 -72
- package/src/daemon/memory-v2-startup.ts +19 -87
- package/src/daemon/message-types/conversations.ts +0 -2
- package/src/daemon/message-types/surfaces.ts +12 -12
- package/src/daemon/server.ts +4 -0
- package/src/daemon/shutdown-handlers.ts +0 -20
- package/src/daemon/tool-setup-types.ts +0 -9
- package/src/daemon/workspace-tools-watcher.ts +328 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/assistant-server.ts +2 -2
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/client.ts +1 -15
- package/src/mcp/mcp-auth-orchestrator.ts +1 -6
- package/src/mcp/mcp-oauth-provider.ts +8 -19
- package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -8
- package/src/memory/conversation-crud.ts +0 -38
- package/src/memory/db-connection.ts +3 -22
- package/src/memory/db-init.ts +502 -36
- package/src/memory/db-singleton.ts +4 -6
- package/src/memory/jobs-worker.ts +0 -58
- package/src/memory/llm-request-log-store.ts +1 -26
- package/src/memory/llm-usage-store.ts +20 -48
- package/src/memory/memory-retrospective-job.ts +8 -9
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +56 -130
- package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
- package/src/memory/migrations/registry.ts +573 -0
- package/src/memory/migrations/run-migrations.ts +6 -90
- package/src/memory/migrations/validate-migration-state.ts +66 -101
- package/src/memory/schema/conversations.ts +0 -9
- package/src/memory/schema/infrastructure.ts +0 -20
- package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -25
- package/src/memory/v2/__tests__/skill-store.test.ts +0 -80
- package/src/memory/v2/cli-command-store.ts +38 -75
- package/src/memory/v2/prompts/consolidation.ts +82 -13
- package/src/memory/v2/prompts/router.ts +93 -21
- package/src/memory/v2/skill-store.ts +31 -68
- package/src/notifications/__tests__/broadcaster.test.ts +8 -16
- package/src/notifications/__tests__/decision-engine.test.ts +9 -78
- package/src/notifications/broadcaster.ts +1 -8
- package/src/notifications/decision-engine.ts +7 -15
- package/src/notifications/destination-resolver.ts +24 -68
- package/src/notifications/emit-signal.ts +14 -39
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +4 -7
- package/src/plugin-api/index.ts +6 -6
- package/src/plugin-api/types.ts +5 -3
- package/src/plugin-api/vision-support.test.ts +4 -28
- package/src/plugin-api/vision-support.ts +31 -66
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -161
- package/src/plugins/defaults/advisor/consult.ts +6 -110
- package/src/plugins/defaults/advisor/steering.ts +2 -14
- package/src/plugins/defaults/advisor/tools/advisor.ts +5 -32
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +1 -2
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +7 -47
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +11 -10
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +20 -12
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +11 -42
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +3 -33
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +4 -48
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +8 -4
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +15 -43
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +2 -11
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -77
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +11 -12
- package/src/plugins/mtime-cache.ts +291 -76
- package/src/plugins/pipeline.ts +13 -111
- package/src/plugins/types.ts +2 -0
- package/src/providers/anthropic/client.ts +0 -5
- package/src/providers/call-site-routing.ts +0 -4
- package/src/providers/model-catalog.ts +0 -16
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/chat-completions-provider.ts +83 -37
- package/src/providers/openai/responses-provider.ts +46 -50
- package/src/providers/openrouter/client.ts +0 -5
- package/src/providers/provider-send-message.ts +0 -4
- package/src/providers/ratelimit.ts +0 -4
- package/src/providers/retry.ts +0 -4
- package/src/providers/types.ts +0 -9
- package/src/providers/usage-tracking.ts +0 -4
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +3 -335
- package/src/runtime/access-request-helper.ts +39 -19
- package/src/runtime/actor-trust-resolver.ts +2 -2
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/assistant-stream-state.ts +2 -9
- package/src/runtime/auth/require-bound-guardian.ts +11 -21
- package/src/runtime/channel-verification-service.ts +31 -56
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
- package/src/runtime/guardian-vellum-migration.ts +7 -66
- package/src/runtime/invite-redemption-service.ts +187 -198
- package/src/runtime/local-actor-identity.ts +11 -76
- package/src/runtime/pending-interactions.ts +1 -11
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +5 -56
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +0 -187
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -13
- package/src/runtime/routes/channel-verification-routes.ts +3 -3
- package/src/runtime/routes/contact-routes.ts +32 -8
- package/src/runtime/routes/conversation-cli-routes.ts +5 -4
- package/src/runtime/routes/conversation-list-routes.ts +7 -4
- package/src/runtime/routes/conversation-query-routes.ts +0 -72
- package/src/runtime/routes/conversation-routes.ts +85 -84
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +1 -3
- package/src/runtime/routes/guardian-action-routes.ts +5 -4
- package/src/runtime/routes/host-app-control-routes.ts +4 -5
- package/src/runtime/routes/host-bash-routes.ts +4 -5
- package/src/runtime/routes/host-browser-routes.ts +11 -9
- package/src/runtime/routes/host-cu-routes.ts +4 -5
- package/src/runtime/routes/host-file-routes.ts +4 -5
- package/src/runtime/routes/host-transfer-routes.ts +6 -6
- package/src/runtime/routes/http-adapter.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +2 -3
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +5 -97
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +49 -61
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -16
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +8 -21
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +3 -14
- package/src/runtime/routes/index.ts +0 -2
- package/src/runtime/routes/llm-context-normalization.ts +0 -83
- package/src/runtime/routes/mcp-auth-routes.ts +19 -171
- package/src/runtime/routes/migration-rollback-routes.ts +3 -4
- package/src/runtime/routes/migration-routes.ts +1 -4
- package/src/runtime/routes/subagents-routes.ts +0 -5
- package/src/runtime/routes/surface-action-routes.ts +56 -42
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -1
- package/src/runtime/services/conversation-serializer.ts +9 -7
- package/src/runtime/tool-grant-request-helper.ts +3 -3
- package/src/runtime/trust-verdict-consumer.ts +9 -85
- package/src/runtime/verification-outbound-actions.ts +18 -18
- package/src/signals/user-message.ts +0 -16
- package/src/subagent/manager.ts +0 -9
- package/src/subagent/types.ts +3 -3
- package/src/telemetry/types.ts +1 -34
- package/src/telemetry/usage-telemetry-reporter.test.ts +2 -3
- package/src/telemetry/usage-telemetry-reporter.ts +3 -87
- package/src/tools/ask-question/ask-question-tool.test.ts +0 -29
- package/src/tools/ask-question/ask-question-tool.ts +0 -13
- package/src/tools/executor.ts +4 -4
- package/src/tools/registry.ts +0 -18
- package/src/tools/shared/filesystem/path-policy.ts +5 -12
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-defaults.ts +2 -9
- package/src/tools/tool-manifest.ts +0 -3
- package/src/tools/types.ts +2 -17
- package/src/tools/workspace-tools/loader.ts +244 -348
- package/src/util/errors.ts +1 -26
- package/src/util/platform.ts +0 -5
- package/src/workflows/library.test.ts +0 -140
- package/src/workflows/library.ts +28 -82
- package/src/workspace/migrations/017-seed-persona-dirs.ts +34 -3
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +24 -3
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +66 -14
- package/src/workspace/migrations/registry.ts +0 -2
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +0 -91
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +0 -48
- package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +0 -28
- package/node_modules/@vellumai/service-contracts/src/channels.ts +0 -41
- package/src/__tests__/code-search-tool.test.ts +0 -585
- package/src/__tests__/guardian-expiry-notifier.test.ts +0 -282
- package/src/__tests__/mcp-config-secret-boundary.test.ts +0 -390
- package/src/__tests__/plugin-pipeline.test.ts +0 -96
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +0 -102
- package/src/__tests__/steer-on-enqueue-question.test.ts +0 -181
- package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +0 -208
- package/src/agent/loop-exclusive-tool.test.ts +0 -150
- package/src/api/constants/sse-replay.ts +0 -41
- package/src/api/events/conversation-notice.ts +0 -26
- package/src/approvals/guardian-channel-delivery.ts +0 -30
- package/src/approvals/guardian-expiry-notifier.ts +0 -148
- package/src/cli/commands/memory/__tests__/worker.test.ts +0 -302
- package/src/cli/commands/memory/worker.ts +0 -175
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +0 -143
- package/src/config/prune-seeded-callsite-defaults.ts +0 -110
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -129
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +0 -312
- package/src/contacts/__tests__/member-write-relay.test.ts +0 -202
- package/src/contacts/guardian-delivery-reader.ts +0 -223
- package/src/contacts/member-write-relay.ts +0 -189
- package/src/daemon/conversation-notices.ts +0 -60
- package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -225
- package/src/hooks/hook-loader.ts +0 -341
- package/src/mcp/mcp-header-store.ts +0 -134
- package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
- package/src/memory/__tests__/prompt-override.test.ts +0 -192
- package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
- package/src/memory/migrations/300-add-processing-started-at.ts +0 -30
- package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -224
- package/src/memory/prompt-override.ts +0 -129
- package/src/memory/steps.ts +0 -573
- package/src/memory/watchdog-events-store.ts +0 -87
- package/src/memory/worker-control.ts +0 -118
- package/src/memory/worker-process.ts +0 -72
- package/src/notifications/__tests__/connected-channels.test.ts +0 -114
- package/src/notifications/__tests__/destination-resolver.test.ts +0 -256
- package/src/onboarding/checkin-event.test.ts +0 -222
- package/src/onboarding/checkin-event.ts +0 -321
- package/src/onboarding/schedule-checkin.ts +0 -190
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +0 -106
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +0 -60
- package/src/plugins/defaults/advisor/context-pack.ts +0 -288
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
- package/src/plugins/surface-import.ts +0 -121
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +0 -321
- package/src/providers/openai/api-error-normalization.ts +0 -270
- package/src/runtime/__tests__/channel-verification-service.test.ts +0 -133
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +0 -181
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +0 -66
- package/src/runtime/__tests__/local-principal-trust.test.ts +0 -164
- package/src/runtime/anchored-guardian.test.ts +0 -156
- package/src/runtime/anchored-guardian.ts +0 -135
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +0 -99
- package/src/runtime/local-principal-trust.ts +0 -52
- package/src/runtime/routes/__tests__/contact-routes.test.ts +0 -212
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -93
- package/src/runtime/routes/onboarding-checkin-routes.ts +0 -86
- package/src/tools/filesystem/search.ts +0 -543
- package/src/util/telemetry-db-path.ts +0 -24
- package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +0 -134
package/src/util/errors.ts
CHANGED
|
@@ -102,17 +102,6 @@ export class AssistantError extends VellumError {
|
|
|
102
102
|
export class ProviderError extends AssistantError {
|
|
103
103
|
/** Delay (in ms) suggested by the server's Retry-After header, if present. */
|
|
104
104
|
public readonly retryAfterMs?: number;
|
|
105
|
-
/** Upstream provider error metadata, parsed from the raw non-2xx body. */
|
|
106
|
-
public readonly apiErrorCode?: string;
|
|
107
|
-
public readonly apiErrorType?: string;
|
|
108
|
-
public readonly apiErrorParam?: string;
|
|
109
|
-
public readonly requestId?: string;
|
|
110
|
-
/**
|
|
111
|
-
* Verbatim upstream non-2xx body (possibly truncated). Persisted so the
|
|
112
|
-
* inspector's Raw tab can show the actual provider error payload, not just
|
|
113
|
-
* the extracted fields.
|
|
114
|
-
*/
|
|
115
|
-
public readonly rawBody?: string;
|
|
116
105
|
/**
|
|
117
106
|
* Tagged daemon-owned abort reason carried over from the AbortSignal that
|
|
118
107
|
* triggered this error. Untyped here to avoid a daemon→util import cycle;
|
|
@@ -125,25 +114,11 @@ export class ProviderError extends AssistantError {
|
|
|
125
114
|
message: string,
|
|
126
115
|
public readonly provider: string,
|
|
127
116
|
public readonly statusCode?: number,
|
|
128
|
-
options?: {
|
|
129
|
-
cause?: unknown;
|
|
130
|
-
retryAfterMs?: number;
|
|
131
|
-
abortReason?: unknown;
|
|
132
|
-
apiErrorCode?: string;
|
|
133
|
-
apiErrorType?: string;
|
|
134
|
-
apiErrorParam?: string;
|
|
135
|
-
requestId?: string;
|
|
136
|
-
rawBody?: string;
|
|
137
|
-
},
|
|
117
|
+
options?: { cause?: unknown; retryAfterMs?: number; abortReason?: unknown },
|
|
138
118
|
) {
|
|
139
119
|
super(message, ErrorCode.PROVIDER_ERROR, options);
|
|
140
120
|
this.name = "ProviderError";
|
|
141
121
|
this.retryAfterMs = options?.retryAfterMs;
|
|
142
|
-
this.apiErrorCode = options?.apiErrorCode;
|
|
143
|
-
this.apiErrorType = options?.apiErrorType;
|
|
144
|
-
this.apiErrorParam = options?.apiErrorParam;
|
|
145
|
-
this.requestId = options?.requestId;
|
|
146
|
-
this.rawBody = options?.rawBody;
|
|
147
122
|
this.abortReason = options?.abortReason;
|
|
148
123
|
}
|
|
149
124
|
}
|
package/src/util/platform.ts
CHANGED
|
@@ -242,11 +242,6 @@ export function getEmbedWorkerPidPath(): string {
|
|
|
242
242
|
return join(getWorkspaceDir(), "embed-worker.pid");
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
/** Returns the path to the memory-worker PID file ($VELLUM_WORKSPACE_DIR/memory-worker.pid). */
|
|
246
|
-
export function getMemoryWorkerPidPath(): string {
|
|
247
|
-
return join(getWorkspaceDir(), "memory-worker.pid");
|
|
248
|
-
}
|
|
249
|
-
|
|
250
245
|
/**
|
|
251
246
|
* Returns the workspace root for user-facing state.
|
|
252
247
|
*
|
|
@@ -37,13 +37,6 @@ function writeWorkflow(file: string, source: string): void {
|
|
|
37
37
|
writeFileSync(join(dir, file), source, "utf8");
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
/** Write `<workspace>/workflows/<name>/workflow.ts` (directory-style). */
|
|
41
|
-
function writeDirWorkflow(name: string, source: string): void {
|
|
42
|
-
const dir = join(workspaceDir, "workflows", name);
|
|
43
|
-
mkdirSync(dir, { recursive: true });
|
|
44
|
-
writeFileSync(join(dir, "workflow.ts"), source, "utf8");
|
|
45
|
-
}
|
|
46
|
-
|
|
47
40
|
describe("listWorkflows", () => {
|
|
48
41
|
test("returns [] and does not create the dir when none exists", () => {
|
|
49
42
|
expect(listWorkflows()).toEqual([]);
|
|
@@ -91,51 +84,6 @@ describe("listWorkflows", () => {
|
|
|
91
84
|
expect(entries.map((e) => e.name)).toEqual(["real"]);
|
|
92
85
|
});
|
|
93
86
|
|
|
94
|
-
test("includes both flat and directory-style workflows", () => {
|
|
95
|
-
writeWorkflow(
|
|
96
|
-
"flat.workflow.ts",
|
|
97
|
-
`export const meta = { name: "flat-wf", description: "flat" };\nreturn 1;`,
|
|
98
|
-
);
|
|
99
|
-
writeDirWorkflow(
|
|
100
|
-
"dir-wf",
|
|
101
|
-
`export const meta = { name: "dir-wf", description: "dir" };\nreturn 1;`,
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
const entries = listWorkflows().sort((a, b) =>
|
|
105
|
-
a.name.localeCompare(b.name),
|
|
106
|
-
);
|
|
107
|
-
expect(entries.map((e) => e.name)).toEqual(["dir-wf", "flat-wf"]);
|
|
108
|
-
expect(entries[0]!.path).toContain(join("dir-wf", "workflow.ts"));
|
|
109
|
-
expect(entries[1]!.path).toContain("flat.workflow.ts");
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
test("ignores a subdir without a workflow.ts and does not recurse deeper", () => {
|
|
113
|
-
writeWorkflow(
|
|
114
|
-
"real.workflow.ts",
|
|
115
|
-
`export const meta = { name: "real", description: "d" };\nreturn 1;`,
|
|
116
|
-
);
|
|
117
|
-
// Subdir with no entry-point workflow.ts.
|
|
118
|
-
mkdirSync(join(workspaceDir, "workflows", "empty-dir"), {
|
|
119
|
-
recursive: true,
|
|
120
|
-
});
|
|
121
|
-
writeFileSync(
|
|
122
|
-
join(workspaceDir, "workflows", "empty-dir", "notes.ts"),
|
|
123
|
-
`export const meta = { name: "ignored", description: "d" };`,
|
|
124
|
-
"utf8",
|
|
125
|
-
);
|
|
126
|
-
// A nested workflow.ts one level deeper than supported must not be picked up.
|
|
127
|
-
mkdirSync(join(workspaceDir, "workflows", "outer", "inner"), {
|
|
128
|
-
recursive: true,
|
|
129
|
-
});
|
|
130
|
-
writeFileSync(
|
|
131
|
-
join(workspaceDir, "workflows", "outer", "inner", "workflow.ts"),
|
|
132
|
-
`export const meta = { name: "too-deep", description: "d" };`,
|
|
133
|
-
"utf8",
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
expect(listWorkflows().map((e) => e.name)).toEqual(["real"]);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
87
|
test("skips a file whose meta is computed/non-literal (cannot be statically extracted)", () => {
|
|
140
88
|
writeWorkflow(
|
|
141
89
|
"ok.workflow.ts",
|
|
@@ -183,92 +131,4 @@ describe("getWorkflow", () => {
|
|
|
183
131
|
);
|
|
184
132
|
expect(getWorkflow("ghost")).toBeNull();
|
|
185
133
|
});
|
|
186
|
-
|
|
187
|
-
test("resolves a directory-style workflow by meta.name", () => {
|
|
188
|
-
const source = `export const meta = { name: "dir-digest", description: "d" };\nreturn agent("go");`;
|
|
189
|
-
writeDirWorkflow("dir-digest", source);
|
|
190
|
-
|
|
191
|
-
const resolved = getWorkflow("dir-digest");
|
|
192
|
-
expect(resolved).not.toBeNull();
|
|
193
|
-
expect(resolved!.source).toBe(source);
|
|
194
|
-
expect(resolved!.path).toContain(join("dir-digest", "workflow.ts"));
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
test("resolves a directory-style workflow by directory name when meta.name differs", () => {
|
|
198
|
-
// meta.name is "canonical" but the dir (and caller's name) is "by-dir".
|
|
199
|
-
const source = `export const meta = { name: "canonical", description: "d" };\nreturn 1;`;
|
|
200
|
-
writeDirWorkflow("by-dir", source);
|
|
201
|
-
|
|
202
|
-
expect(getWorkflow("by-dir")!.source).toBe(source);
|
|
203
|
-
// The canonical meta.name also resolves.
|
|
204
|
-
expect(getWorkflow("canonical")!.source).toBe(source);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
test("prefers a meta.name match over a base-name match", () => {
|
|
208
|
-
// Asking for "wanted" should hit the file whose meta.name is "wanted",
|
|
209
|
-
// not the file whose base name is "wanted" (whose meta.name differs).
|
|
210
|
-
writeWorkflow(
|
|
211
|
-
"wanted.workflow.ts",
|
|
212
|
-
`export const meta = { name: "other", description: "by base name" };\nreturn 1;`,
|
|
213
|
-
);
|
|
214
|
-
const metaSource = `export const meta = { name: "wanted", description: "by meta name" };\nreturn 1;`;
|
|
215
|
-
writeWorkflow("real.workflow.ts", metaSource);
|
|
216
|
-
|
|
217
|
-
expect(getWorkflow("wanted")!.source).toBe(metaSource);
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
describe("name collisions", () => {
|
|
222
|
-
test("a directory wins over a same-base-name flat file", () => {
|
|
223
|
-
writeWorkflow(
|
|
224
|
-
"foo.workflow.ts",
|
|
225
|
-
`export const meta = { name: "foo", description: "flat" };\nreturn "FLAT";`,
|
|
226
|
-
);
|
|
227
|
-
writeDirWorkflow(
|
|
228
|
-
"foo",
|
|
229
|
-
`export const meta = { name: "foo", description: "dir" };\nreturn "DIR";`,
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
const resolved = getWorkflow("foo")!;
|
|
233
|
-
expect(resolved.source).toContain("DIR");
|
|
234
|
-
expect(resolved.path.endsWith(join("foo", "workflow.ts"))).toBe(true);
|
|
235
|
-
|
|
236
|
-
const foos = listWorkflows().filter((e) => e.name === "foo");
|
|
237
|
-
expect(foos).toHaveLength(1);
|
|
238
|
-
expect(foos[0]!.description).toBe("dir");
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
test("the shadowed flat file's own meta.name no longer resolves", () => {
|
|
242
|
-
writeWorkflow(
|
|
243
|
-
"bar.workflow.ts",
|
|
244
|
-
`export const meta = { name: "flat-name", description: "flat" };\nreturn "FLAT";`,
|
|
245
|
-
);
|
|
246
|
-
writeDirWorkflow(
|
|
247
|
-
"bar",
|
|
248
|
-
`export const meta = { name: "dir-name", description: "dir" };\nreturn "DIR";`,
|
|
249
|
-
);
|
|
250
|
-
|
|
251
|
-
expect(getWorkflow("dir-name")!.source).toContain("DIR");
|
|
252
|
-
expect(getWorkflow("flat-name")).toBeNull();
|
|
253
|
-
// Base-name fallback also lands on the directory.
|
|
254
|
-
expect(getWorkflow("bar")!.source).toContain("DIR");
|
|
255
|
-
expect(listWorkflows().map((e) => e.name)).toEqual(["dir-name"]);
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
test("listWorkflows dedups a duplicate meta.name across different files", () => {
|
|
259
|
-
writeWorkflow(
|
|
260
|
-
"a.workflow.ts",
|
|
261
|
-
`export const meta = { name: "dup", description: "from-a" };\nreturn "A";`,
|
|
262
|
-
);
|
|
263
|
-
writeDirWorkflow(
|
|
264
|
-
"b",
|
|
265
|
-
`export const meta = { name: "dup", description: "from-b" };\nreturn "B";`,
|
|
266
|
-
);
|
|
267
|
-
|
|
268
|
-
// One entry; the directory (yielded first) wins, consistent with getWorkflow.
|
|
269
|
-
const dups = listWorkflows().filter((e) => e.name === "dup");
|
|
270
|
-
expect(dups).toHaveLength(1);
|
|
271
|
-
expect(dups[0]!.description).toBe("from-b");
|
|
272
|
-
expect(getWorkflow("dup")!.source).toContain("B");
|
|
273
|
-
});
|
|
274
134
|
});
|
package/src/workflows/library.ts
CHANGED
|
@@ -2,17 +2,13 @@
|
|
|
2
2
|
* Saved-workflow LIBRARY — named workflows the assistant can invoke by name and
|
|
3
3
|
* the scheduler can trigger.
|
|
4
4
|
*
|
|
5
|
-
* Saved workflows live at `<workspace>/workflows
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* pure-literal extractor that never executes the untrusted source — only the
|
|
13
|
-
* QuickJS sandbox may run it) and the raw source. Resolution to an actual run
|
|
14
|
-
* goes through {@link executeWorkflow} / {@link WorkflowRunManager}, which run
|
|
15
|
-
* the source in the sandbox.
|
|
5
|
+
* Saved workflows live at `<workspace>/workflows/*.workflow.ts`. Each file is a
|
|
6
|
+
* normal workflow script: a leading literal `export const meta = { name,
|
|
7
|
+
* description }` followed by the script body. The library only reads the STATIC
|
|
8
|
+
* `meta` (via {@link extractWorkflowMeta}, a pure-literal extractor that never
|
|
9
|
+
* executes the untrusted source — only the QuickJS sandbox may run it) and the
|
|
10
|
+
* raw source. Resolution to an actual run goes through {@link executeWorkflow} /
|
|
11
|
+
* {@link WorkflowRunManager}, which run the source in the sandbox.
|
|
16
12
|
*
|
|
17
13
|
* The directory is read lazily and is NOT created eagerly: if it does not exist,
|
|
18
14
|
* {@link listWorkflows} returns `[]` and {@link getWorkflow} returns `null`.
|
|
@@ -23,7 +19,7 @@ import { join } from "node:path";
|
|
|
23
19
|
|
|
24
20
|
import { getLogger } from "../util/logger.js";
|
|
25
21
|
import { getWorkspaceDir } from "../util/platform.js";
|
|
26
|
-
import { extractWorkflowMeta
|
|
22
|
+
import { extractWorkflowMeta } from "./engine.js";
|
|
27
23
|
|
|
28
24
|
const log = getLogger("workflow-library");
|
|
29
25
|
|
|
@@ -53,66 +49,31 @@ function workflowsDir(): string {
|
|
|
53
49
|
return join(getWorkspaceDir(), "workflows");
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
/** Filename of the entry-point script inside a directory-style workflow. */
|
|
57
|
-
const DIRECTORY_ENTRY = "workflow.ts";
|
|
58
|
-
|
|
59
52
|
/** The filename (sans `.workflow.ts`) for `<workspace>/workflows/<base>.workflow.ts`. */
|
|
60
53
|
function fileBaseName(file: string): string {
|
|
61
54
|
return file.slice(0, -WORKFLOW_SUFFIX.length);
|
|
62
55
|
}
|
|
63
56
|
|
|
64
|
-
/** A
|
|
57
|
+
/** A `*.workflow.ts` file read off disk, before meta extraction. */
|
|
65
58
|
interface RawWorkflowFile {
|
|
66
|
-
|
|
67
|
-
baseName: string;
|
|
59
|
+
file: string;
|
|
68
60
|
path: string;
|
|
69
61
|
source: string;
|
|
70
62
|
}
|
|
71
63
|
|
|
72
64
|
/**
|
|
73
|
-
* Yield every readable
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* WINS: a flat `<name>.workflow.ts` with the same base name is shadowed (skipped
|
|
77
|
-
* with a warning). Yields nothing if the directory does not exist — it is never
|
|
78
|
-
* created. An unreadable entry is skipped with a logged warning.
|
|
65
|
+
* Yield every readable `*.workflow.ts` file in the workflows directory (each read
|
|
66
|
+
* once). Returns nothing if the directory does not exist — it is never created.
|
|
67
|
+
* An unreadable file is skipped with a logged warning.
|
|
79
68
|
*/
|
|
80
69
|
function* readWorkflowFiles(): Generator<RawWorkflowFile> {
|
|
81
70
|
const dir = workflowsDir();
|
|
82
71
|
if (!existsSync(dir)) return;
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// Directory-style first, so it wins over a same-base-name flat file.
|
|
87
|
-
for (const entry of entries) {
|
|
88
|
-
if (entry.endsWith(WORKFLOW_SUFFIX)) continue;
|
|
89
|
-
const path = join(dir, entry, DIRECTORY_ENTRY);
|
|
90
|
-
if (!existsSync(path)) continue;
|
|
91
|
-
try {
|
|
92
|
-
const source = readFileSync(path, "utf8");
|
|
93
|
-
seen.add(entry);
|
|
94
|
-
yield { baseName: entry, path, source };
|
|
95
|
-
} catch (err) {
|
|
96
|
-
log.warn({ err, path }, "Failed to read saved workflow; skipping");
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Flat files second; skip any shadowed by a directory of the same base name.
|
|
101
|
-
for (const entry of entries) {
|
|
102
|
-
if (!entry.endsWith(WORKFLOW_SUFFIX)) continue;
|
|
103
|
-
const baseName = fileBaseName(entry);
|
|
104
|
-
const path = join(dir, entry);
|
|
105
|
-
if (seen.has(baseName)) {
|
|
106
|
-
log.warn(
|
|
107
|
-
{ path },
|
|
108
|
-
`Flat workflow "${entry}" is shadowed by directory "${baseName}/"; skipping`,
|
|
109
|
-
);
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
72
|
+
for (const file of readdirSync(dir)) {
|
|
73
|
+
if (!file.endsWith(WORKFLOW_SUFFIX)) continue;
|
|
74
|
+
const path = join(dir, file);
|
|
112
75
|
try {
|
|
113
|
-
|
|
114
|
-
seen.add(baseName);
|
|
115
|
-
yield { baseName, path, source };
|
|
76
|
+
yield { file, path, source: readFileSync(path, "utf8") };
|
|
116
77
|
} catch (err) {
|
|
117
78
|
log.warn({ err, path }, "Failed to read saved workflow; skipping");
|
|
118
79
|
}
|
|
@@ -120,57 +81,42 @@ function* readWorkflowFiles(): Generator<RawWorkflowFile> {
|
|
|
120
81
|
}
|
|
121
82
|
|
|
122
83
|
/**
|
|
123
|
-
* List every saved workflow with a statically-extractable `meta
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
* winner). A file whose `meta` cannot be statically extracted is skipped with a
|
|
127
|
-
* warning rather than failing the whole listing.
|
|
84
|
+
* List every saved workflow with a statically-extractable `meta`. A file whose
|
|
85
|
+
* `meta` cannot be statically extracted (computed/missing/malformed) is SKIPPED
|
|
86
|
+
* with a logged warning rather than failing the whole listing.
|
|
128
87
|
*/
|
|
129
88
|
export function listWorkflows(): SavedWorkflowEntry[] {
|
|
130
89
|
const entries: SavedWorkflowEntry[] = [];
|
|
131
|
-
const seenNames = new Set<string>();
|
|
132
90
|
for (const { path, source } of readWorkflowFiles()) {
|
|
133
|
-
let meta: WorkflowMeta;
|
|
134
91
|
try {
|
|
135
|
-
meta = extractWorkflowMeta(source);
|
|
92
|
+
const meta = extractWorkflowMeta(source);
|
|
93
|
+
entries.push({ name: meta.name, description: meta.description, path });
|
|
136
94
|
} catch (err) {
|
|
137
95
|
log.warn(
|
|
138
96
|
{ err, path },
|
|
139
97
|
"Saved workflow has no statically-extractable meta; skipping",
|
|
140
98
|
);
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
if (seenNames.has(meta.name)) {
|
|
144
|
-
log.warn(
|
|
145
|
-
{ path, name: meta.name },
|
|
146
|
-
`Duplicate workflow name "${meta.name}"; skipping shadowed entry`,
|
|
147
|
-
);
|
|
148
|
-
continue;
|
|
149
99
|
}
|
|
150
|
-
seenNames.add(meta.name);
|
|
151
|
-
entries.push({ name: meta.name, description: meta.description, path });
|
|
152
100
|
}
|
|
153
101
|
return entries;
|
|
154
102
|
}
|
|
155
103
|
|
|
156
104
|
/**
|
|
157
|
-
* Resolve a saved workflow by name
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* then falls back to the base name (directory or flat-file). Returns the source
|
|
161
|
-
* + path, or `null` if nothing matches.
|
|
105
|
+
* Resolve a saved workflow by name. Matches against the workflow's `meta.name`
|
|
106
|
+
* first, then falls back to the filename base (`<base>.workflow.ts`). Returns the
|
|
107
|
+
* source + path, or `null` if no saved workflow matches.
|
|
162
108
|
*/
|
|
163
109
|
export function getWorkflow(name: string): SavedWorkflowSource | null {
|
|
164
110
|
let fileMatch: SavedWorkflowSource | null = null;
|
|
165
|
-
for (const {
|
|
111
|
+
for (const { file, path, source } of readWorkflowFiles()) {
|
|
166
112
|
// Prefer a `meta.name` match — it is the canonical identity.
|
|
167
113
|
try {
|
|
168
114
|
if (extractWorkflowMeta(source).name === name) return { source, path };
|
|
169
115
|
} catch {
|
|
170
116
|
// Fall through: a file with non-extractable meta can still match by name.
|
|
171
117
|
}
|
|
172
|
-
// Remember the first base
|
|
173
|
-
if (fileMatch === null &&
|
|
118
|
+
// Remember the first filename-base match as a fallback.
|
|
119
|
+
if (fileMatch === null && fileBaseName(file) === name) {
|
|
174
120
|
fileMatch = { source, path };
|
|
175
121
|
}
|
|
176
122
|
}
|
|
@@ -8,6 +8,11 @@ import {
|
|
|
8
8
|
} from "node:fs";
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
|
|
11
|
+
import { desc, eq } from "drizzle-orm";
|
|
12
|
+
|
|
13
|
+
import { generateUserFileSlug } from "../../contacts/contact-store.js";
|
|
14
|
+
import { getDb } from "../../memory/db-connection.js";
|
|
15
|
+
import { contacts } from "../../memory/schema/contacts.js";
|
|
11
16
|
import type { WorkspaceMigration } from "./types.js";
|
|
12
17
|
|
|
13
18
|
// ── Inlined helpers ───────────────────────────────────────────────
|
|
@@ -117,9 +122,35 @@ export const seedPersonaDirsMigration: WorkspaceMigration = {
|
|
|
117
122
|
// template from disk, since migration 031 deletes that template file.
|
|
118
123
|
if (content === LEGACY_USER_MD_TEMPLATE_STRIPPED) return;
|
|
119
124
|
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
// Determine destination filename based on guardian contact
|
|
126
|
+
let destFilename = "guardian.md";
|
|
127
|
+
try {
|
|
128
|
+
const db = getDb();
|
|
129
|
+
const guardian = db
|
|
130
|
+
.select()
|
|
131
|
+
.from(contacts)
|
|
132
|
+
.where(eq(contacts.role, "guardian"))
|
|
133
|
+
.orderBy(desc(contacts.createdAt))
|
|
134
|
+
.limit(1)
|
|
135
|
+
.get();
|
|
136
|
+
|
|
137
|
+
if (guardian) {
|
|
138
|
+
if (guardian.userFile) {
|
|
139
|
+
destFilename = guardian.userFile;
|
|
140
|
+
} else {
|
|
141
|
+
const slug = generateUserFileSlug(guardian.displayName);
|
|
142
|
+
db.update(contacts)
|
|
143
|
+
.set({ userFile: slug })
|
|
144
|
+
.where(eq(contacts.id, guardian.id))
|
|
145
|
+
.run();
|
|
146
|
+
destFilename = slug;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
} catch {
|
|
150
|
+
// DB might not be initialized yet — fall back to guardian.md
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const destPath = join(workspaceDir, "users", destFilename);
|
|
123
154
|
if (!existsSync(destPath)) {
|
|
124
155
|
copyFileSync(userMdPath, destPath);
|
|
125
156
|
}
|
|
@@ -8,6 +8,10 @@ import {
|
|
|
8
8
|
} from "node:fs";
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
|
|
11
|
+
import { desc, eq } from "drizzle-orm";
|
|
12
|
+
|
|
13
|
+
import { getDb } from "../../memory/db-connection.js";
|
|
14
|
+
import { contacts } from "../../memory/schema/contacts.js";
|
|
11
15
|
import type { WorkspaceMigration } from "./types.js";
|
|
12
16
|
|
|
13
17
|
export const scopeJournalToGuardianMigration: WorkspaceMigration = {
|
|
@@ -36,9 +40,26 @@ export const scopeJournalToGuardianMigration: WorkspaceMigration = {
|
|
|
36
40
|
});
|
|
37
41
|
if (mdFiles.length === 0) return;
|
|
38
42
|
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
// Resolve guardian user slug (same pattern as 017-seed-persona-dirs)
|
|
44
|
+
let slug = "guardian";
|
|
45
|
+
try {
|
|
46
|
+
const db = getDb();
|
|
47
|
+
const guardian = db
|
|
48
|
+
.select()
|
|
49
|
+
.from(contacts)
|
|
50
|
+
.where(eq(contacts.role, "guardian"))
|
|
51
|
+
.orderBy(desc(contacts.createdAt))
|
|
52
|
+
.limit(1)
|
|
53
|
+
.get();
|
|
54
|
+
if (guardian?.userFile) {
|
|
55
|
+
slug = guardian.userFile.replace(/\.md$/, "");
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
// DB not ready — use fallback "guardian"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Create per-user directory and move files (renameSync preserves birthtimes)
|
|
62
|
+
const destDir = join(journalDir, slug);
|
|
42
63
|
mkdirSync(destDir, { recursive: true });
|
|
43
64
|
for (const f of mdFiles) {
|
|
44
65
|
const src = join(journalDir, f);
|
|
@@ -1,29 +1,81 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Workspace migration
|
|
2
|
+
* Workspace migration 046: Remove legacy `workspace/hooks/` directory.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* the deletion has been removed.
|
|
4
|
+
* Migration 022 moved `~/.vellum/hooks/` into `$VELLUM_WORKSPACE_DIR/hooks/`.
|
|
5
|
+
* With the hook system entirely removed, that directory is dead state — it is
|
|
6
|
+
* no longer read or written by the assistant. This migration deletes the
|
|
7
|
+
* directory (and everything under it) so stale hook manifests, config, and
|
|
8
|
+
* executables do not linger in user workspaces.
|
|
10
9
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* no-op on every workspace, new or old.
|
|
10
|
+
* Idempotent: safe to re-run after interruption. A no-op when the directory
|
|
11
|
+
* is already absent.
|
|
14
12
|
*/
|
|
15
13
|
|
|
14
|
+
import { existsSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
|
|
17
|
+
import { getLogger } from "../../util/logger.js";
|
|
16
18
|
import type { WorkspaceMigration } from "./types.js";
|
|
17
19
|
|
|
20
|
+
const log = getLogger("workspace-migration-048-remove-workspace-hooks");
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Count files under `dir` recursively. Best-effort — returns the count we
|
|
24
|
+
* could successfully stat, and silently skips entries that fail (e.g. a
|
|
25
|
+
* symlink whose target is missing, a file removed concurrently). This is
|
|
26
|
+
* only used for log output, so a slightly stale count is acceptable.
|
|
27
|
+
*/
|
|
28
|
+
function countFilesRecursive(dir: string): number {
|
|
29
|
+
let count = 0;
|
|
30
|
+
let entries: string[];
|
|
31
|
+
try {
|
|
32
|
+
entries = readdirSync(dir);
|
|
33
|
+
} catch {
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
for (const entry of entries) {
|
|
37
|
+
const entryPath = join(dir, entry);
|
|
38
|
+
try {
|
|
39
|
+
const s = statSync(entryPath);
|
|
40
|
+
if (s.isDirectory()) {
|
|
41
|
+
count += countFilesRecursive(entryPath);
|
|
42
|
+
} else {
|
|
43
|
+
count += 1;
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
// best-effort
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return count;
|
|
50
|
+
}
|
|
51
|
+
|
|
18
52
|
export const removeWorkspaceHooksMigration: WorkspaceMigration = {
|
|
19
53
|
id: "048-remove-workspace-hooks",
|
|
20
|
-
description:
|
|
54
|
+
description:
|
|
55
|
+
"Remove legacy workspace/hooks/ directory now that the hook system is gone",
|
|
56
|
+
|
|
57
|
+
run(workspaceDir: string): void {
|
|
58
|
+
const hooksDir = join(workspaceDir, "hooks");
|
|
59
|
+
if (!existsSync(hooksDir)) return;
|
|
21
60
|
|
|
22
|
-
|
|
23
|
-
|
|
61
|
+
const fileCount = countFilesRecursive(hooksDir);
|
|
62
|
+
try {
|
|
63
|
+
rmSync(hooksDir, { recursive: true, force: true });
|
|
64
|
+
log.info(
|
|
65
|
+
{ path: hooksDir, fileCount },
|
|
66
|
+
"Removed legacy workspace hooks directory",
|
|
67
|
+
);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
log.warn(
|
|
70
|
+
{ err, path: hooksDir },
|
|
71
|
+
"Failed to remove legacy workspace hooks directory; leaving in place",
|
|
72
|
+
);
|
|
73
|
+
}
|
|
24
74
|
},
|
|
25
75
|
|
|
26
76
|
down(_workspaceDir: string): void {
|
|
27
|
-
//
|
|
77
|
+
// Forward-only: the hook system is gone and the directory contained no
|
|
78
|
+
// data the assistant still consumes. Restoring an empty directory would
|
|
79
|
+
// just reintroduce dead state.
|
|
28
80
|
},
|
|
29
81
|
};
|
|
@@ -108,7 +108,6 @@ import { dropSendDiagnosticsMigration } from "./107-drop-send-diagnostics.js";
|
|
|
108
108
|
import { dropBalancedEconomyProfileMigration } from "./108-drop-balanced-economy-profile.js";
|
|
109
109
|
import { swapQualityProfileToGlm52Migration } from "./109-swap-quality-profile-to-glm-5p2.js";
|
|
110
110
|
import { flipBalancedProfileToTogetherMigration } from "./110-flip-balanced-profile-to-together.js";
|
|
111
|
-
import { pruneSeededCallsiteDefaultsMigration } from "./111-prune-seeded-callsite-defaults.js";
|
|
112
111
|
import { migrateToWorkspaceVolumeMigration } from "./migrate-to-workspace-volume.js";
|
|
113
112
|
import type { WorkspaceMigration } from "./types.js";
|
|
114
113
|
|
|
@@ -228,5 +227,4 @@ export const WORKSPACE_MIGRATIONS: WorkspaceMigration[] = [
|
|
|
228
227
|
dropBalancedEconomyProfileMigration,
|
|
229
228
|
swapQualityProfileToGlm52Migration,
|
|
230
229
|
flipBalancedProfileToTogetherMigration,
|
|
231
|
-
pruneSeededCallsiteDefaultsMigration,
|
|
232
230
|
];
|