@vellumai/assistant 0.10.2 → 0.10.3-dev.202606252046.9075fd5
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 +20 -0
- package/docs/workspace-tools.md +42 -33
- package/eslint-rules/cli-no-daemon-internals.js +6 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +31 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +44 -0
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +14 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +17 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +28 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +41 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/openapi.yaml +196 -56
- package/package.json +4 -1
- package/scripts/test.sh +36 -15
- package/src/__tests__/actor-token-service.test.ts +36 -14
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +83 -31
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +2 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -0
- package/src/__tests__/approval-cascade.test.ts +2 -0
- package/src/__tests__/assistant-attachments.test.ts +42 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -0
- package/src/__tests__/btw-routes.test.ts +2 -0
- package/src/__tests__/build-persisted-content.test.ts +2 -0
- package/src/__tests__/call-controller.test.ts +19 -0
- package/src/__tests__/channel-approval-routes.test.ts +21 -26
- package/src/__tests__/channel-delivery-store.test.ts +28 -0
- package/src/__tests__/channel-guardian.test.ts +164 -78
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +11 -19
- package/src/__tests__/channel-reply-delivery.test.ts +2 -0
- package/src/__tests__/code-search-tool.test.ts +585 -0
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/compaction-ledger-store.test.ts +128 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +2 -0
- package/src/__tests__/compactor-low-watermark-cut.test.ts +2 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +2 -0
- package/src/__tests__/compactor-summary-call-truncation.test.ts +2 -0
- package/src/__tests__/compactor-web-search-strip.test.ts +2 -0
- package/src/__tests__/config-loader-backfill.test.ts +123 -10
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +31 -29
- package/src/__tests__/consult-deadline.test.ts +60 -0
- package/src/__tests__/contact-store-interaction-info.test.ts +156 -0
- package/src/__tests__/contact-store-user-file.test.ts +7 -10
- package/src/__tests__/contacts-relay-reads.test.ts +19 -24
- package/src/__tests__/contacts-write.test.ts +0 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop.test.ts +134 -0
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +2 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +9 -11
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -0
- package/src/__tests__/conversation-fork-crud.test.ts +354 -24
- package/src/__tests__/conversation-history-web-search.test.ts +2 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +2 -0
- package/src/__tests__/conversation-load-history-stripped.test.ts +2 -0
- package/src/__tests__/conversation-pairing.test.ts +2 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
- package/src/__tests__/conversation-process-callsite.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +91 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +14 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +14 -0
- package/src/__tests__/conversation-slash-queue.test.ts +2 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-speed-override.test.ts +2 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +29 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -0
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
- package/src/__tests__/conversation-usage.test.ts +2 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/db-compaction-events-migration.test.ts +129 -0
- package/src/__tests__/db-migration-rollback.test.ts +205 -171
- package/src/__tests__/db-test-helpers.ts +5 -4
- package/src/__tests__/delete-propagation.test.ts +5 -3
- package/src/__tests__/deterministic-verification-control-plane.test.ts +4 -2
- package/src/__tests__/disk-pressure-guard.test.ts +41 -0
- package/src/__tests__/dm-backfill.test.ts +6 -4
- package/src/__tests__/dm-persistence.test.ts +2 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +7 -6
- package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
- package/src/__tests__/exploration-drift-hook.test.ts +3 -2
- package/src/__tests__/filing-service.test.ts +2 -0
- package/src/__tests__/guardian-binding-drift-heal.test.ts +104 -19
- package/src/__tests__/guardian-dispatch.test.ts +140 -1
- package/src/__tests__/guardian-expiry-notifier.test.ts +282 -0
- package/src/__tests__/guardian-outbound-http.test.ts +13 -0
- package/src/__tests__/guardian-routing-state.test.ts +6 -10
- package/src/__tests__/heartbeat-disk-pressure.test.ts +2 -0
- package/src/__tests__/heartbeat-service.test.ts +2 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +46 -19
- package/src/__tests__/helpers/create-guardian-binding.ts +15 -23
- package/src/__tests__/helpers/mock-logger.ts +1 -0
- package/src/__tests__/helpers/seed-contact-channel.ts +96 -0
- package/src/__tests__/host-app-control-routes.test.ts +24 -30
- package/src/__tests__/host-bash-routes.test.ts +31 -41
- package/src/__tests__/host-browser-routes.test.ts +26 -32
- package/src/__tests__/host-cu-routes-targeted.test.ts +25 -33
- package/src/__tests__/host-file-routes-targeted.test.ts +40 -52
- package/src/__tests__/host-transfer-routes-targeted.test.ts +31 -43
- package/src/__tests__/http-user-message-parity.test.ts +290 -8
- package/src/__tests__/inbound-invite-redemption.test.ts +115 -10
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/invite-redemption-service.test.ts +471 -53
- package/src/__tests__/invite-routes-http.test.ts +34 -0
- package/src/__tests__/invite-service-ipc.test.ts +65 -2
- package/src/__tests__/llm-context-normalization.test.ts +105 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +71 -9
- package/src/__tests__/llm-usage-store.test.ts +25 -0
- package/src/__tests__/mcp-config-secret-boundary.test.ts +392 -0
- package/src/__tests__/mcp-health-check.test.ts +2 -1
- package/src/__tests__/media-stream-server-integration.test.ts +127 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +2 -0
- package/src/__tests__/messaging-send-tool.test.ts +2 -0
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/mtime-cache.test.ts +275 -5
- package/src/__tests__/native-web-search.test.ts +2 -0
- package/src/__tests__/non-member-access-request.test.ts +191 -17
- package/src/__tests__/notification-broadcaster.test.ts +4 -0
- package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
- package/src/__tests__/notification-deep-link.test.ts +6 -0
- package/src/__tests__/notification-guardian-path.test.ts +19 -0
- package/src/__tests__/onboarding-persona-write.test.ts +52 -22
- package/src/__tests__/openai-provider.test.ts +22 -12
- package/src/__tests__/openai-responses-provider.test.ts +12 -2
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
- package/src/__tests__/persist-onboarding-artifacts.test.ts +1 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
- package/src/__tests__/persona-resolver.test.ts +75 -45
- package/src/__tests__/plugin-bootstrap.test.ts +21 -83
- package/src/__tests__/plugin-disabled-state.test.ts +190 -0
- package/src/__tests__/plugin-pipeline.test.ts +96 -0
- package/src/__tests__/plugin-route-contribution.test.ts +6 -19
- package/src/__tests__/plugin-tool-contribution.test.ts +5 -20
- package/src/__tests__/plugin-types.test.ts +2 -4
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/process-message-display-content.test.ts +2 -0
- package/src/__tests__/provider-error-scenarios.test.ts +5 -4
- package/src/__tests__/provider-usage-tracking.test.ts +39 -0
- package/src/__tests__/reaction-intercept-cold-cache-warm.test.ts +135 -0
- package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +158 -0
- package/src/__tests__/reaction-persistence.test.ts +51 -4
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +2 -0
- package/src/__tests__/registry.test.ts +4 -1
- package/src/__tests__/relay-server.test.ts +758 -32
- package/src/__tests__/runtime-attachment-metadata.test.ts +9 -12
- package/src/__tests__/secret-ingress-http.test.ts +14 -0
- package/src/__tests__/send-endpoint-busy.test.ts +30 -8
- package/src/__tests__/settings-routes.test.ts +32 -0
- package/src/__tests__/skills.test.ts +44 -0
- package/src/__tests__/slack-inbound-verification.test.ts +47 -2
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +79 -0
- package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
- package/src/__tests__/stt-hints.test.ts +49 -15
- package/src/__tests__/subagent-detail.test.ts +27 -0
- package/src/__tests__/subagent-disposal.test.ts +65 -0
- package/src/__tests__/subagent-fork-prompt-role.test.ts +195 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +6 -7
- package/src/__tests__/subagent-notify-parent.test.ts +2 -0
- package/src/__tests__/subagent-role-registry.test.ts +24 -6
- package/src/__tests__/subagent-spawn-and-await.test.ts +546 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +2 -0
- package/src/__tests__/subagent-tools.test.ts +398 -1
- package/src/__tests__/suggestion-routes.test.ts +2 -0
- package/src/__tests__/thread-backfill.test.ts +3 -3
- package/src/__tests__/title-generate-hook.test.ts +2 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -0
- package/src/__tests__/tool-executor.test.ts +16 -11
- package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +2 -0
- package/src/__tests__/tool-start-timestamp.test.ts +2 -0
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +37 -51
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +12 -12
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -7
- package/src/__tests__/trusted-contact-multichannel.test.ts +16 -7
- package/src/__tests__/trusted-contact-verification.test.ts +79 -54
- package/src/__tests__/twilio-routes.test.ts +96 -0
- package/src/__tests__/ui-file-upload-surface.test.ts +86 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -0
- package/src/__tests__/voice-guardian-cold-cache-warm.test.ts +137 -0
- package/src/__tests__/voice-invite-redemption.test.ts +216 -20
- package/src/__tests__/web-search-backend-failure.test.ts +2 -0
- package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +3 -3
- package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +208 -0
- package/src/__tests__/workspace-migration-112-remove-advisor-callsite-override.test.ts +170 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +196 -238
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +14 -35
- package/src/__tests__/workspace-tool-loader.test.ts +195 -2
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +35 -47
- package/src/agent/loop-exclusive-tool.test.ts +154 -0
- package/src/agent/loop-native-web-search.test.ts +200 -0
- package/src/agent/loop.ts +164 -1
- package/src/api/constants/sse-replay.ts +41 -0
- package/src/api/events/conversation-notice.ts +26 -0
- package/src/api/index.ts +19 -1
- package/src/api/responses/llm-request-log-entry.ts +29 -0
- package/src/api/responses/subagent-detail.ts +17 -0
- package/src/api/surfaces.ts +39 -3
- package/src/approvals/guardian-channel-delivery.ts +30 -0
- package/src/approvals/guardian-expiry-notifier.ts +148 -0
- package/src/approvals/guardian-request-resolvers.ts +17 -15
- package/src/calls/__tests__/relay-setup-router.test.ts +267 -17
- package/src/calls/call-domain.ts +3 -3
- package/src/calls/guardian-dispatch.ts +14 -9
- package/src/calls/inbound-trust-reader.ts +24 -2
- package/src/calls/media-stream-server.ts +21 -0
- package/src/calls/relay-access-wait.ts +6 -6
- package/src/calls/relay-server.ts +188 -51
- package/src/calls/relay-setup-router.ts +47 -17
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/stt-hints.ts +9 -12
- package/src/calls/twilio-routes.ts +14 -4
- package/src/channels/types.ts +10 -20
- package/src/cli/commands/__tests__/cache.test.ts +8 -1
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
- package/src/cli/commands/cache.ts +194 -181
- package/src/cli/commands/contacts.ts +10 -7
- package/src/cli/commands/db/__tests__/repair.test.ts +6 -5
- package/src/cli/commands/db/status.ts +37 -1
- package/src/cli/commands/mcp.ts +252 -218
- package/src/cli/commands/memory/__tests__/worker.test.ts +432 -0
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/worker.ts +242 -0
- package/src/cli/commands/plugins.ts +125 -13
- package/src/cli/lib/__tests__/install-from-github.test.ts +102 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
- package/src/cli/lib/__tests__/publish-plugin.test.ts +404 -0
- package/src/cli/lib/list-installed-plugins.ts +179 -1
- package/src/cli/lib/publish-plugin.ts +633 -0
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
- package/src/config/__tests__/sync-gated-profiles.test.ts +16 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +27 -17
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +13 -3
- package/src/config/bundled-skills/subagent/SKILL.md +17 -2
- package/src/config/bundled-skills/subagent/TOOLS.json +5 -4
- package/src/config/call-site-defaults.ts +0 -6
- package/src/config/feature-flag-registry.json +5 -13
- package/src/config/llm-resolver.ts +0 -3
- package/src/config/loader.ts +38 -5
- package/src/config/prune-seeded-callsite-defaults.ts +110 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +0 -7
- package/src/config/schemas/heartbeat.ts +2 -5
- package/src/config/schemas/llm.ts +3 -12
- package/src/config/schemas/memory-lifecycle.ts +12 -0
- package/src/config/schemas/memory-v3.ts +7 -0
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/timeouts.ts +8 -0
- package/src/config/seed-inference-profiles.ts +30 -34
- package/src/config/skills.ts +27 -5
- package/src/config/sync-gated-profiles.ts +12 -16
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +128 -0
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
- package/src/contacts/__tests__/member-write-relay.test.ts +226 -0
- package/src/contacts/contact-store.ts +27 -237
- package/src/contacts/contacts-write.ts +18 -55
- package/src/contacts/gateway-channel-read.ts +51 -0
- package/src/contacts/guardian-delivery-reader.ts +223 -0
- package/src/contacts/member-write-relay.ts +183 -0
- package/src/contacts/types.ts +3 -15
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +35 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +0 -44
- package/src/daemon/assistant-attachments.ts +27 -4
- package/src/daemon/conversation-agent-loop.ts +28 -0
- package/src/daemon/conversation-notices.ts +60 -0
- package/src/daemon/conversation-process.ts +35 -16
- package/src/daemon/conversation-surfaces.ts +111 -38
- package/src/daemon/conversation-tool-setup.ts +71 -30
- package/src/daemon/conversation.ts +23 -1
- package/src/daemon/disk-pressure-guard.ts +12 -2
- package/src/daemon/event-loop-watchdog.ts +28 -1
- package/src/daemon/external-plugins-bootstrap.ts +17 -41
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +0 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -2
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +25 -2
- package/src/daemon/handlers/__tests__/config-channels.test.ts +220 -0
- package/src/daemon/handlers/config-a2a.ts +6 -14
- package/src/daemon/handlers/config-channels.ts +67 -26
- package/src/daemon/handlers/conversations.ts +77 -0
- package/src/daemon/lifecycle.ts +16 -0
- package/src/daemon/mcp-reload-service.ts +10 -0
- package/src/daemon/memory-v2-startup.test.ts +72 -0
- package/src/daemon/memory-v2-startup.ts +87 -19
- package/src/daemon/message-types/conversations.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +12 -12
- package/src/daemon/server.ts +0 -4
- package/src/daemon/shutdown-handlers.ts +20 -0
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/heartbeat/heartbeat-service.ts +5 -0
- package/src/home/relationship-state-writer.ts +5 -0
- package/src/hooks/hook-loader.ts +341 -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 +1 -0
- package/src/mcp/client.ts +15 -1
- package/src/mcp/mcp-auth-orchestrator.ts +6 -1
- package/src/mcp/mcp-header-store.ts +134 -0
- package/src/mcp/mcp-oauth-provider.ts +19 -8
- package/src/memory/__tests__/301-create-watchdog-events.test.ts +110 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +8 -0
- package/src/memory/__tests__/prompt-override.test.ts +192 -0
- package/src/memory/__tests__/watchdog-events-store.test.ts +161 -0
- package/src/memory/compaction-ledger-store.ts +107 -0
- package/src/memory/conversation-crud.ts +129 -61
- package/src/memory/db-connection.ts +22 -3
- package/src/memory/db-init.ts +37 -503
- package/src/memory/db-singleton.ts +6 -4
- package/src/memory/jobs-worker.ts +104 -0
- package/src/memory/llm-request-log-store.ts +26 -1
- package/src/memory/llm-usage-store.ts +48 -20
- package/src/memory/memory-retrospective-job.ts +14 -8
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +152 -56
- package/src/memory/migrations/300-add-processing-started-at.ts +30 -0
- package/src/memory/migrations/301-create-watchdog-events.ts +45 -0
- package/src/memory/migrations/302-create-compaction-events.ts +107 -0
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +297 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
- package/src/memory/migrations/run-migrations.ts +106 -10
- package/src/memory/migrations/validate-migration-state.ts +105 -67
- package/src/memory/prompt-override.ts +129 -0
- package/src/memory/schema/contacts.ts +6 -2
- package/src/memory/schema/conversations.ts +37 -0
- package/src/memory/schema/infrastructure.ts +20 -0
- package/src/memory/steps.ts +1294 -0
- package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
- package/src/memory/v2/cli-command-store.ts +75 -38
- package/src/memory/v2/prompts/consolidation.ts +13 -82
- package/src/memory/v2/prompts/router.ts +21 -93
- package/src/memory/v2/skill-store.ts +68 -31
- package/src/memory/watchdog-events-store.ts +87 -0
- package/src/memory/worker-control.ts +204 -0
- package/src/memory/worker-process.ts +89 -0
- package/src/messaging/channel-binding-metadata.ts +31 -0
- package/src/messaging/provider-types.ts +8 -0
- package/src/messaging/providers/slack/binding-metadata.ts +60 -0
- package/src/notifications/__tests__/broadcaster.test.ts +8 -8
- package/src/notifications/__tests__/connected-channels.test.ts +86 -0
- package/src/notifications/__tests__/decision-engine.test.ts +78 -9
- package/src/notifications/__tests__/destination-resolver.test.ts +151 -0
- package/src/notifications/broadcaster.ts +8 -1
- package/src/notifications/decision-engine.ts +15 -7
- package/src/notifications/destination-resolver.ts +53 -25
- package/src/notifications/emit-signal.ts +34 -15
- package/src/onboarding/checkin-event.test.ts +222 -0
- package/src/onboarding/checkin-event.ts +321 -0
- package/src/onboarding/schedule-checkin.ts +190 -0
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +7 -4
- package/src/plugin-api/index.ts +12 -12
- package/src/plugin-api/types.ts +12 -14
- package/src/plugin-api/vision-support.test.ts +28 -4
- package/src/plugin-api/vision-support.ts +66 -31
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/empty-response/hooks/stop.ts +2 -2
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +4 -3
- package/src/plugins/defaults/history-repair/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/history-repair/hooks/stop.ts +2 -2
- package/src/plugins/defaults/history-repair/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +47 -7
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +12 -13
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +14 -22
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +42 -11
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/image-recovery/hooks/stop.ts +2 -2
- package/src/plugins/defaults/index.ts +0 -35
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/max-tokens-continue/hooks/stop.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +33 -3
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +48 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +4 -8
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +43 -15
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +11 -2
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +146 -0
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +77 -13
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +12 -11
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +2 -2
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +2 -2
- package/src/plugins/defaults/title-generate/hooks/stop.ts +2 -2
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +2 -2
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +2 -2
- package/src/plugins/disabled-state.ts +31 -0
- package/src/plugins/external-plugin-loader.ts +2 -2
- package/src/plugins/mtime-cache.ts +186 -330
- package/src/plugins/pipeline.ts +111 -13
- package/src/plugins/registry.ts +59 -16
- package/src/plugins/surface-import.ts +121 -0
- package/src/plugins/types.ts +7 -9
- package/src/prompts/persona-resolver.ts +43 -11
- package/src/providers/anthropic/client.ts +5 -0
- package/src/providers/call-site-routing.ts +45 -0
- package/src/providers/model-catalog.ts +16 -0
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +321 -0
- package/src/providers/openai/api-error-normalization.ts +270 -0
- package/src/providers/openai/chat-completions-provider.ts +37 -83
- package/src/providers/openai/responses-provider.ts +50 -46
- package/src/providers/openrouter/client.ts +5 -0
- package/src/providers/provider-send-message.ts +10 -0
- package/src/providers/ratelimit.ts +10 -0
- package/src/providers/registry.ts +1 -1
- package/src/providers/retry.ts +10 -0
- package/src/providers/types.ts +22 -0
- package/src/providers/usage-tracking.ts +10 -0
- package/src/runtime/__tests__/channel-verification-service.test.ts +133 -0
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +184 -0
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +66 -0
- package/src/runtime/__tests__/local-principal-trust.test.ts +162 -0
- package/src/runtime/__tests__/member-verdict-cache.test.ts +119 -0
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +402 -123
- package/src/runtime/access-request-helper.ts +18 -39
- package/src/runtime/actor-trust-resolver.ts +46 -19
- package/src/runtime/anchored-guardian.test.ts +109 -0
- package/src/runtime/anchored-guardian.ts +86 -0
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/assistant-stream-state.ts +9 -2
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +99 -0
- package/src/runtime/auth/require-bound-guardian.ts +21 -11
- package/src/runtime/channel-verification-service.ts +56 -31
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
- package/src/runtime/guardian-vellum-migration.ts +69 -8
- package/src/runtime/invite-redemption-service.ts +213 -187
- package/src/runtime/local-actor-identity.test.ts +108 -0
- package/src/runtime/local-actor-identity.ts +85 -13
- package/src/runtime/local-principal-trust.ts +52 -0
- package/src/runtime/member-verdict-cache.ts +0 -0
- package/src/runtime/pending-interactions.ts +11 -1
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +56 -5
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/contact-routes.test.ts +305 -0
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +92 -0
- package/src/runtime/routes/__tests__/http-adapter-actor-header.test.ts +129 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +188 -0
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +13 -5
- package/src/runtime/routes/channel-verification-routes.ts +3 -3
- package/src/runtime/routes/contact-routes.ts +48 -57
- package/src/runtime/routes/conversation-cli-routes.ts +4 -5
- package/src/runtime/routes/conversation-list-routes.ts +4 -7
- package/src/runtime/routes/conversation-query-routes.ts +72 -0
- package/src/runtime/routes/conversation-routes.ts +84 -85
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +3 -1
- package/src/runtime/routes/guardian-action-routes.ts +4 -5
- package/src/runtime/routes/host-app-control-routes.ts +5 -4
- package/src/runtime/routes/host-bash-routes.ts +5 -4
- package/src/runtime/routes/host-browser-routes.ts +9 -11
- package/src/runtime/routes/host-cu-routes.ts +5 -4
- package/src/runtime/routes/host-file-routes.ts +5 -4
- package/src/runtime/routes/host-transfer-routes.ts +6 -6
- package/src/runtime/routes/http-adapter.ts +16 -1
- package/src/runtime/routes/identity-routes.ts +3 -2
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +97 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +61 -59
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +13 -5
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +21 -8
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -3
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +19 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/llm-context-normalization.ts +83 -0
- package/src/runtime/routes/mcp-auth-routes.ts +171 -19
- package/src/runtime/routes/migration-rollback-routes.ts +4 -3
- package/src/runtime/routes/migration-routes.ts +4 -1
- package/src/runtime/routes/onboarding-checkin-routes.ts +86 -0
- package/src/runtime/routes/settings-routes.ts +8 -3
- package/src/runtime/routes/subagents-routes.ts +5 -0
- package/src/runtime/routes/surface-action-routes.ts +42 -56
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +13 -58
- package/src/runtime/tool-grant-request-helper.ts +3 -3
- package/src/runtime/trust-verdict-consumer.ts +111 -40
- package/src/runtime/verification-outbound-actions.ts +18 -18
- package/src/signals/user-message.ts +16 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +35 -0
- package/src/{plugins/defaults/advisor/__tests__/transcript.test.ts → subagent/__tests__/consult-transcript.test.ts} +47 -10
- package/src/{plugins/defaults/advisor/steering.ts → subagent/consult-prompt.ts} +22 -32
- package/src/{plugins/defaults/advisor/transcript.ts → subagent/consult-transcript.ts} +18 -8
- package/src/subagent/index.ts +1 -1
- package/src/subagent/manager.ts +254 -33
- package/src/subagent/types.ts +11 -4
- package/src/telemetry/types.ts +34 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
- package/src/telemetry/usage-telemetry-reporter.ts +87 -3
- package/src/tools/ask-question/ask-question-tool.test.ts +29 -0
- package/src/tools/ask-question/ask-question-tool.ts +13 -0
- package/src/tools/executor.ts +4 -4
- package/src/tools/filesystem/search.ts +543 -0
- package/src/tools/registry.ts +38 -0
- package/src/tools/shared/filesystem/path-policy.ts +12 -5
- package/src/tools/subagent/consult-deadline.ts +49 -0
- package/src/tools/subagent/spawn.ts +234 -5
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-defaults.ts +9 -2
- package/src/tools/tool-manifest.ts +3 -0
- package/src/tools/types.ts +131 -25
- package/src/tools/workspace-tools/loader.ts +348 -244
- package/src/util/errors.ts +26 -1
- package/src/util/logger.ts +9 -0
- package/src/util/platform.ts +19 -0
- package/src/util/telemetry-db-path.ts +24 -0
- package/src/workflows/library.test.ts +140 -0
- package/src/workflows/library.ts +82 -28
- package/src/workspace/migrations/017-seed-persona-dirs.ts +3 -34
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +3 -24
- package/src/workspace/migrations/031-drop-user-md.ts +232 -148
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +14 -66
- package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +134 -0
- package/src/workspace/migrations/112-remove-advisor-callsite-override.ts +64 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/workspace-tools-watcher-flag.test.ts +0 -70
- package/src/daemon/workspace-tools-watcher.ts +0 -328
- package/src/memory/migrations/registry.ts +0 -573
- package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +0 -56
- package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +0 -43
- package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +0 -137
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -153
- package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +0 -138
- package/src/plugins/defaults/advisor/advisor-gate.ts +0 -29
- package/src/plugins/defaults/advisor/advisor-state-store.ts +0 -94
- package/src/plugins/defaults/advisor/config.ts +0 -21
- package/src/plugins/defaults/advisor/consult.ts +0 -93
- package/src/plugins/defaults/advisor/hooks/post-model-call.ts +0 -34
- package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +0 -30
- package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +0 -19
- package/src/plugins/defaults/advisor/package.json +0 -14
- package/src/plugins/defaults/advisor/tools/advisor.ts +0 -65
- package/src/providers/openai/__tests__/api-error-detail.test.ts +0 -120
|
@@ -8,16 +8,8 @@ import {
|
|
|
8
8
|
writeFileSync,
|
|
9
9
|
} from "node:fs";
|
|
10
10
|
import { basename, join } from "node:path";
|
|
11
|
+
import { Database } from "bun:sqlite";
|
|
11
12
|
|
|
12
|
-
import { eq } from "drizzle-orm";
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
findGuardianForChannel,
|
|
16
|
-
generateUserFileSlug,
|
|
17
|
-
listGuardianChannels,
|
|
18
|
-
} from "../../contacts/contact-store.js";
|
|
19
|
-
import { getDb } from "../../memory/db-connection.js";
|
|
20
|
-
import { contacts } from "../../memory/schema/contacts.js";
|
|
21
13
|
import { getLogger } from "../../util/logger.js";
|
|
22
14
|
import type { WorkspaceMigration } from "./types.js";
|
|
23
15
|
|
|
@@ -25,11 +17,11 @@ const log = getLogger("workspace-migration-031-drop-user-md");
|
|
|
25
17
|
|
|
26
18
|
// ── Inlined helpers ───────────────────────────────────────────────
|
|
27
19
|
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
20
|
+
// AGENTS.md requires each migration to be self-contained: it may import
|
|
21
|
+
// only `./types.js`, `./utils.js`, the logger, and runtime built-ins.
|
|
22
|
+
// The helpers below (including the guardian DB read and the userFile
|
|
23
|
+
// slug) are inlined so this migration does not regress if the modules
|
|
24
|
+
// they originate from change later.
|
|
33
25
|
|
|
34
26
|
/**
|
|
35
27
|
* Strip lines starting with `_` (comment convention for prompt .md files)
|
|
@@ -123,13 +115,59 @@ function isValidSlug(slug: string): boolean {
|
|
|
123
115
|
return basename(slug) === slug && slug !== "." && slug !== "..";
|
|
124
116
|
}
|
|
125
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Strip LIKE metacharacters so the prefix match runs literally. SQLite has
|
|
120
|
+
* no default LIKE escape character, so strip rather than escape. Inlined
|
|
121
|
+
* from `contacts/contact-store.ts`.
|
|
122
|
+
*/
|
|
123
|
+
function escapeLike(value: string): string {
|
|
124
|
+
return value.replace(/%/g, "").replace(/_/g, "");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Pure slug transform applied to a display name. */
|
|
128
|
+
function computeUserFileBaseSlug(displayName: string): string {
|
|
129
|
+
return (
|
|
130
|
+
displayName
|
|
131
|
+
.toLowerCase()
|
|
132
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
133
|
+
.replace(/^-+|-+$/g, "")
|
|
134
|
+
.slice(0, 100) || "user"
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Generate a collision-free `users/<slug>.md` filename for a display name,
|
|
140
|
+
* inlined verbatim from `contacts/contact-store.ts` to keep this migration
|
|
141
|
+
* self-contained. Produces "alice.md", "alice-2.md", etc.
|
|
142
|
+
*/
|
|
143
|
+
function generateUserFileSlug(db: Database, displayName: string): string {
|
|
144
|
+
const slug = computeUserFileBaseSlug(displayName);
|
|
145
|
+
|
|
146
|
+
const rows = db
|
|
147
|
+
.query<{ user_file: string | null }, [string]>(
|
|
148
|
+
`SELECT user_file FROM contacts WHERE user_file LIKE ?`,
|
|
149
|
+
)
|
|
150
|
+
.all(`${escapeLike(slug)}%`);
|
|
151
|
+
|
|
152
|
+
const taken = new Set(rows.map((r) => r.user_file?.toLowerCase()));
|
|
153
|
+
|
|
154
|
+
const base = `${slug}.md`;
|
|
155
|
+
if (!taken.has(base)) return base;
|
|
156
|
+
|
|
157
|
+
for (let i = 2; ; i++) {
|
|
158
|
+
const candidate = `${slug}-${i}.md`;
|
|
159
|
+
if (!taken.has(candidate)) return candidate;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
126
163
|
/**
|
|
127
164
|
* Delete the legacy `USER.md` at the workspace root after migrating
|
|
128
165
|
* any customized content into `users/<slug>.md`.
|
|
129
166
|
*
|
|
130
|
-
* Handles
|
|
131
|
-
* 1.
|
|
132
|
-
*
|
|
167
|
+
* Handles these relevant states:
|
|
168
|
+
* 1. No local guardian → preserve a customized `USER.md` (the local
|
|
169
|
+
* mirror can be stale, so a customized profile may still belong to a
|
|
170
|
+
* real guardian); delete only the unmodified template/empty file.
|
|
133
171
|
* 2. Pre-017 customized `USER.md`, guardian has no `userFile` →
|
|
134
172
|
* backfill the slug, copy `USER.md` → `users/<slug>.md`, delete `USER.md`.
|
|
135
173
|
* 3. Post-017 state where `users/<slug>.md` already has content →
|
|
@@ -137,6 +175,12 @@ function isValidSlug(slug: string): boolean {
|
|
|
137
175
|
* 4. Missing `users/<slug>.md` after guardian is resolved → seed a bare
|
|
138
176
|
* `GUARDIAN_PERSONA_TEMPLATE` scaffold so downstream readers have a file.
|
|
139
177
|
*/
|
|
178
|
+
interface GuardianRow {
|
|
179
|
+
id: string;
|
|
180
|
+
display_name: string;
|
|
181
|
+
user_file: string | null;
|
|
182
|
+
}
|
|
183
|
+
|
|
140
184
|
export const dropUserMdMigration: WorkspaceMigration = {
|
|
141
185
|
id: "031-drop-user-md",
|
|
142
186
|
description:
|
|
@@ -145,163 +189,203 @@ export const dropUserMdMigration: WorkspaceMigration = {
|
|
|
145
189
|
run(workspaceDir: string): void {
|
|
146
190
|
const userMdPath = join(workspaceDir, "USER.md");
|
|
147
191
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
let
|
|
192
|
+
const dbPath = join(workspaceDir, "data", "db", "assistant.db");
|
|
193
|
+
if (!existsSync(dbPath)) return; // DB not created yet — defer cleanup.
|
|
194
|
+
|
|
195
|
+
let db: Database;
|
|
152
196
|
try {
|
|
153
|
-
|
|
154
|
-
if (vellumGuardian) {
|
|
155
|
-
guardian = {
|
|
156
|
-
id: vellumGuardian.contact.id,
|
|
157
|
-
displayName: vellumGuardian.contact.displayName,
|
|
158
|
-
userFile: vellumGuardian.contact.userFile ?? null,
|
|
159
|
-
};
|
|
160
|
-
} else {
|
|
161
|
-
const anyGuardian = listGuardianChannels();
|
|
162
|
-
if (!anyGuardian) {
|
|
163
|
-
// Fresh install or pre-onboarding. If a stale USER.md somehow
|
|
164
|
-
// remains on disk (e.g. leftover from an older build), best-
|
|
165
|
-
// effort remove it so future first runs are clean.
|
|
166
|
-
if (existsSync(userMdPath)) {
|
|
167
|
-
try {
|
|
168
|
-
unlinkSync(userMdPath);
|
|
169
|
-
log.info(
|
|
170
|
-
{ path: userMdPath },
|
|
171
|
-
"Deleted stale pre-onboarding USER.md with no guardian",
|
|
172
|
-
);
|
|
173
|
-
} catch (err) {
|
|
174
|
-
log.warn(
|
|
175
|
-
{ err, path: userMdPath },
|
|
176
|
-
"Failed to delete pre-onboarding USER.md; leaving in place",
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
guardian = {
|
|
183
|
-
id: anyGuardian.contact.id,
|
|
184
|
-
displayName: anyGuardian.contact.displayName,
|
|
185
|
-
userFile: anyGuardian.contact.userFile ?? null,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
197
|
+
db = new Database(dbPath);
|
|
188
198
|
} catch (err) {
|
|
189
|
-
|
|
190
|
-
// startup after DB init will try again.
|
|
191
|
-
log.warn(
|
|
192
|
-
{ err },
|
|
193
|
-
"Failed to resolve guardian contact; deferring USER.md cleanup",
|
|
194
|
-
);
|
|
199
|
+
log.warn({ err }, "Cannot open assistant DB; deferring USER.md cleanup");
|
|
195
200
|
return;
|
|
196
201
|
}
|
|
197
202
|
|
|
198
|
-
|
|
199
|
-
|
|
203
|
+
try {
|
|
204
|
+
// Resolve the guardian contact from the local DB. Prefer the
|
|
205
|
+
// vellum-channel binding (the canonical native guardian); fall back to
|
|
206
|
+
// whichever guardian has the most recently verified active channel.
|
|
207
|
+
let guardianRow: GuardianRow | null;
|
|
200
208
|
try {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
);
|
|
209
|
+
guardianRow =
|
|
210
|
+
db
|
|
211
|
+
.query<GuardianRow, []>(
|
|
212
|
+
`SELECT c.id AS id, c.display_name AS display_name, c.user_file AS user_file
|
|
213
|
+
FROM contacts c JOIN contact_channels cc ON cc.contact_id = c.id
|
|
214
|
+
WHERE c.role = 'guardian' AND cc.status = 'active'
|
|
215
|
+
ORDER BY (cc.type = 'vellum') DESC, cc.verified_at DESC
|
|
216
|
+
LIMIT 1`,
|
|
217
|
+
)
|
|
218
|
+
.get() ?? null;
|
|
212
219
|
} catch (err) {
|
|
220
|
+
// DB not ready or query failed — leave USER.md alone. The next
|
|
221
|
+
// startup after DB init tries again.
|
|
213
222
|
log.warn(
|
|
214
|
-
{ err
|
|
215
|
-
"Failed to
|
|
223
|
+
{ err },
|
|
224
|
+
"Failed to resolve guardian contact; deferring USER.md cleanup",
|
|
216
225
|
);
|
|
217
226
|
return;
|
|
218
227
|
}
|
|
219
|
-
}
|
|
220
228
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
+
if (!guardianRow) {
|
|
230
|
+
// No local guardian. The mirror can be stale (the gateway mirrors
|
|
231
|
+
// best-effort), so a customized USER.md may still belong to a real
|
|
232
|
+
// guardian — preserve it. Only delete the unmodified template/empty
|
|
233
|
+
// stale file.
|
|
234
|
+
if (existsSync(userMdPath)) {
|
|
235
|
+
let isStaleTemplate = false;
|
|
236
|
+
try {
|
|
237
|
+
isStaleTemplate =
|
|
238
|
+
!statSync(userMdPath).isFile() ||
|
|
239
|
+
isLegacyTemplateContent(readFileSync(userMdPath, "utf-8"));
|
|
240
|
+
} catch (err) {
|
|
241
|
+
log.warn(
|
|
242
|
+
{ err, path: userMdPath },
|
|
243
|
+
"Cannot read USER.md with no guardian; leaving in place",
|
|
244
|
+
);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (!isStaleTemplate) {
|
|
249
|
+
log.info(
|
|
250
|
+
{ path: userMdPath },
|
|
251
|
+
"Preserving customized USER.md with no local guardian",
|
|
252
|
+
);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
229
255
|
|
|
230
|
-
|
|
231
|
-
|
|
256
|
+
try {
|
|
257
|
+
unlinkSync(userMdPath);
|
|
258
|
+
log.info(
|
|
259
|
+
{ path: userMdPath },
|
|
260
|
+
"Deleting stale template USER.md with no guardian",
|
|
261
|
+
);
|
|
262
|
+
} catch (err) {
|
|
263
|
+
log.warn(
|
|
264
|
+
{ err, path: userMdPath },
|
|
265
|
+
"Failed to delete stale USER.md; leaving in place",
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
232
271
|
|
|
233
|
-
|
|
272
|
+
const guardian = {
|
|
273
|
+
id: guardianRow.id,
|
|
274
|
+
displayName: guardianRow.display_name,
|
|
275
|
+
userFile: guardianRow.user_file ?? null,
|
|
276
|
+
};
|
|
234
277
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
278
|
+
// Backfill a userFile slug on the guardian contact if one isn't set.
|
|
279
|
+
if (!guardian.userFile) {
|
|
280
|
+
try {
|
|
281
|
+
const slug = generateUserFileSlug(db, guardian.displayName);
|
|
282
|
+
db.run("UPDATE contacts SET user_file = ? WHERE id = ?", [
|
|
283
|
+
slug,
|
|
284
|
+
guardian.id,
|
|
285
|
+
]);
|
|
286
|
+
guardian.userFile = slug;
|
|
287
|
+
log.info(
|
|
288
|
+
{ contactId: guardian.id, slug },
|
|
289
|
+
"Backfilled missing guardian.userFile",
|
|
290
|
+
);
|
|
291
|
+
} catch (err) {
|
|
292
|
+
log.warn(
|
|
293
|
+
{ err, contactId: guardian.id },
|
|
294
|
+
"Failed to backfill guardian.userFile; deferring USER.md cleanup",
|
|
295
|
+
);
|
|
296
|
+
return;
|
|
244
297
|
}
|
|
245
|
-
} catch (err) {
|
|
246
|
-
log.warn(
|
|
247
|
-
{ err, path: userMdPath },
|
|
248
|
-
"Failed to read USER.md; treating as unreadable",
|
|
249
|
-
);
|
|
250
298
|
}
|
|
251
|
-
}
|
|
252
299
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
// that already populated users/<slug>.md are left untouched.
|
|
256
|
-
if (
|
|
257
|
-
userMdIsCustomized &&
|
|
258
|
-
userMdRaw !== null &&
|
|
259
|
-
destFileIsMissingOrEmpty(destPath)
|
|
260
|
-
) {
|
|
261
|
-
try {
|
|
262
|
-
copyFileSync(userMdPath, destPath);
|
|
263
|
-
log.info(
|
|
264
|
-
{ src: userMdPath, dest: destPath },
|
|
265
|
-
"Copied customized USER.md content into users/<slug>.md",
|
|
266
|
-
);
|
|
267
|
-
} catch (err) {
|
|
300
|
+
const userFile = guardian.userFile;
|
|
301
|
+
if (!userFile || !isValidSlug(userFile)) {
|
|
268
302
|
log.warn(
|
|
269
|
-
{
|
|
270
|
-
"
|
|
303
|
+
{ userFile },
|
|
304
|
+
"Guardian userFile is missing or not a safe basename; deferring USER.md cleanup",
|
|
271
305
|
);
|
|
272
306
|
return;
|
|
273
307
|
}
|
|
274
|
-
}
|
|
275
308
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
)
|
|
309
|
+
const usersDir = join(workspaceDir, "users");
|
|
310
|
+
mkdirSync(usersDir, { recursive: true });
|
|
311
|
+
|
|
312
|
+
const destPath = join(usersDir, userFile);
|
|
313
|
+
|
|
314
|
+
// Read USER.md if it exists and classify its content.
|
|
315
|
+
let userMdRaw: string | null = null;
|
|
316
|
+
let userMdIsCustomized = false;
|
|
317
|
+
if (existsSync(userMdPath)) {
|
|
318
|
+
try {
|
|
319
|
+
// Guard against USER.md being a directory (hostile state).
|
|
320
|
+
if (statSync(userMdPath).isFile()) {
|
|
321
|
+
userMdRaw = readFileSync(userMdPath, "utf-8");
|
|
322
|
+
userMdIsCustomized = !isLegacyTemplateContent(userMdRaw);
|
|
323
|
+
}
|
|
324
|
+
} catch (err) {
|
|
325
|
+
log.warn(
|
|
326
|
+
{ err, path: userMdPath },
|
|
327
|
+
"Failed to read USER.md; treating as unreadable",
|
|
328
|
+
);
|
|
329
|
+
}
|
|
292
330
|
}
|
|
293
|
-
}
|
|
294
331
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
332
|
+
// Copy customized USER.md content into users/<slug>.md when the
|
|
333
|
+
// destination is missing or effectively empty. Post-017 installs
|
|
334
|
+
// that already populated users/<slug>.md are left untouched.
|
|
335
|
+
if (
|
|
336
|
+
userMdIsCustomized &&
|
|
337
|
+
userMdRaw !== null &&
|
|
338
|
+
destFileIsMissingOrEmpty(destPath)
|
|
339
|
+
) {
|
|
340
|
+
try {
|
|
341
|
+
copyFileSync(userMdPath, destPath);
|
|
342
|
+
log.info(
|
|
343
|
+
{ src: userMdPath, dest: destPath },
|
|
344
|
+
"Copied customized USER.md content into users/<slug>.md",
|
|
345
|
+
);
|
|
346
|
+
} catch (err) {
|
|
347
|
+
log.warn(
|
|
348
|
+
{ err, src: userMdPath, dest: destPath },
|
|
349
|
+
"Failed to copy USER.md; deferring USER.md cleanup",
|
|
350
|
+
);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Seed the guardian persona scaffold when the destination file
|
|
356
|
+
// still doesn't exist (e.g. no USER.md and no post-017 content).
|
|
357
|
+
// This keeps parity with `ensureGuardianPersonaFile` for new
|
|
358
|
+
// installs so downstream readers always find a file.
|
|
359
|
+
if (!existsSync(destPath)) {
|
|
360
|
+
try {
|
|
361
|
+
writeFileSync(destPath, GUARDIAN_PERSONA_TEMPLATE, "utf-8");
|
|
362
|
+
log.info(
|
|
363
|
+
{ dest: destPath },
|
|
364
|
+
"Seeded guardian persona scaffold at users/<slug>.md",
|
|
365
|
+
);
|
|
366
|
+
} catch (err) {
|
|
367
|
+
log.warn(
|
|
368
|
+
{ err, dest: destPath },
|
|
369
|
+
"Failed to seed guardian persona scaffold; continuing with USER.md deletion",
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Finally, delete the legacy USER.md if it still exists — template or
|
|
375
|
+
// customized, it has no remaining consumer.
|
|
376
|
+
if (existsSync(userMdPath)) {
|
|
377
|
+
try {
|
|
378
|
+
unlinkSync(userMdPath);
|
|
379
|
+
log.info({ path: userMdPath }, "Deleted legacy workspace USER.md");
|
|
380
|
+
} catch (err) {
|
|
381
|
+
log.warn(
|
|
382
|
+
{ err, path: userMdPath },
|
|
383
|
+
"Failed to delete legacy USER.md",
|
|
384
|
+
);
|
|
385
|
+
}
|
|
304
386
|
}
|
|
387
|
+
} finally {
|
|
388
|
+
db.close();
|
|
305
389
|
}
|
|
306
390
|
},
|
|
307
391
|
|
|
@@ -1,81 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Workspace migration
|
|
2
|
+
* Workspace migration 048: retained no-op.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* This migration previously deleted `<workspace>/hooks/`, treating it as dead
|
|
5
|
+
* state. `<workspace>/hooks/` is now a supported surface: standalone hook files
|
|
6
|
+
* placed there are loaded by the hook loader (see `src/hooks/hook-loader.ts`).
|
|
7
|
+
* Deleting it would destroy user-authored hooks — including on workspaces that
|
|
8
|
+
* mount a preseeded `<workspace>/hooks/` before this migration first runs — so
|
|
9
|
+
* the deletion has been removed.
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
11
|
+
* The migration is kept (rather than removed from the registry) so the applied
|
|
12
|
+
* checkpoint sequence stays stable across already-migrated workspaces. It is a
|
|
13
|
+
* no-op on every workspace, new or old.
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
|
-
import { existsSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
15
|
-
import { join } from "node:path";
|
|
16
|
-
|
|
17
|
-
import { getLogger } from "../../util/logger.js";
|
|
18
16
|
import type { WorkspaceMigration } from "./types.js";
|
|
19
17
|
|
|
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
|
-
|
|
52
18
|
export const removeWorkspaceHooksMigration: WorkspaceMigration = {
|
|
53
19
|
id: "048-remove-workspace-hooks",
|
|
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;
|
|
20
|
+
description: "Retained no-op (workspace/hooks is now a supported surface)",
|
|
60
21
|
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
}
|
|
22
|
+
run(_workspaceDir: string): void {
|
|
23
|
+
// No-op: `<workspace>/hooks/` is a supported surface and must be preserved.
|
|
74
24
|
},
|
|
75
25
|
|
|
76
26
|
down(_workspaceDir: string): void {
|
|
77
|
-
//
|
|
78
|
-
// data the assistant still consumes. Restoring an empty directory would
|
|
79
|
-
// just reintroduce dead state.
|
|
27
|
+
// No-op: forward-only; nothing to reverse.
|
|
80
28
|
},
|
|
81
29
|
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
// Exact system-owned default materializations. These are not user overrides, so
|
|
7
|
+
// matching entries are pruned and resolved through shipped call-site defaults.
|
|
8
|
+
const SEEDED_CALL_SITES: Record<string, Record<string, unknown>> = {
|
|
9
|
+
guardianQuestionCopy: latencySeed(),
|
|
10
|
+
interactionClassifier: latencySeed(),
|
|
11
|
+
skillCategoryInference: latencySeed(),
|
|
12
|
+
inviteInstructionGenerator: latencySeed(),
|
|
13
|
+
notificationDecision: latencySeed(),
|
|
14
|
+
preferenceExtraction: latencySeed(),
|
|
15
|
+
commitMessage: {
|
|
16
|
+
model: "claude-haiku-4-5-20251001",
|
|
17
|
+
maxTokens: 120,
|
|
18
|
+
temperature: 0.2,
|
|
19
|
+
effort: "low",
|
|
20
|
+
thinking: { enabled: false },
|
|
21
|
+
},
|
|
22
|
+
conversationStarters: latencySeed(),
|
|
23
|
+
conversationSummarization: {
|
|
24
|
+
model: "claude-opus-4-7",
|
|
25
|
+
effort: "low",
|
|
26
|
+
thinking: { enabled: false },
|
|
27
|
+
},
|
|
28
|
+
recall: {
|
|
29
|
+
profile: "cost-optimized",
|
|
30
|
+
maxTokens: 4096,
|
|
31
|
+
effort: "low",
|
|
32
|
+
thinking: { enabled: false, streamThinking: false },
|
|
33
|
+
temperature: 0,
|
|
34
|
+
disableCache: true,
|
|
35
|
+
},
|
|
36
|
+
heartbeatAgent: {
|
|
37
|
+
profile: "cost-optimized",
|
|
38
|
+
maxTokens: 2048,
|
|
39
|
+
effort: "low",
|
|
40
|
+
temperature: 0,
|
|
41
|
+
thinking: { enabled: false, streamThinking: false },
|
|
42
|
+
contextWindow: { maxInputTokens: 16000 },
|
|
43
|
+
},
|
|
44
|
+
replySuggestion: {
|
|
45
|
+
model: "claude-haiku-4-5-20251001",
|
|
46
|
+
effort: "low",
|
|
47
|
+
thinking: { enabled: false },
|
|
48
|
+
disableCache: true,
|
|
49
|
+
},
|
|
50
|
+
memoryRouter: {
|
|
51
|
+
profile: "cost-optimized",
|
|
52
|
+
contextWindow: { maxInputTokens: 1_000_000 },
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const pruneSeededCallsiteDefaultsMigration: WorkspaceMigration = {
|
|
57
|
+
id: "111-prune-seeded-callsite-defaults",
|
|
58
|
+
description:
|
|
59
|
+
"Remove seeded LLM call-site default materializations so fresh workspaces show no overrides",
|
|
60
|
+
run(workspaceDir: string): void {
|
|
61
|
+
const configPath = join(workspaceDir, "config.json");
|
|
62
|
+
if (!existsSync(configPath)) return;
|
|
63
|
+
|
|
64
|
+
let config: Record<string, unknown>;
|
|
65
|
+
try {
|
|
66
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
67
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
68
|
+
config = raw as Record<string, unknown>;
|
|
69
|
+
} catch {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const llm = readObject(config.llm);
|
|
74
|
+
if (llm === null) return;
|
|
75
|
+
|
|
76
|
+
const callSites = readObject(llm.callSites);
|
|
77
|
+
if (callSites === null) return;
|
|
78
|
+
|
|
79
|
+
let changed = false;
|
|
80
|
+
for (const [callSite, seed] of Object.entries(SEEDED_CALL_SITES)) {
|
|
81
|
+
if (deepEqual(callSites[callSite], seed)) {
|
|
82
|
+
delete callSites[callSite];
|
|
83
|
+
changed = true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (!changed) return;
|
|
87
|
+
|
|
88
|
+
if (Object.keys(callSites).length === 0) {
|
|
89
|
+
delete llm.callSites;
|
|
90
|
+
} else {
|
|
91
|
+
llm.callSites = callSites;
|
|
92
|
+
}
|
|
93
|
+
config.llm = llm;
|
|
94
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
95
|
+
},
|
|
96
|
+
down(_workspaceDir: string): void {
|
|
97
|
+
// Forward-only: restoring these entries would make defaults appear as
|
|
98
|
+
// user-visible overrides again.
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
function latencySeed(): Record<string, unknown> {
|
|
103
|
+
return {
|
|
104
|
+
model: "claude-haiku-4-5-20251001",
|
|
105
|
+
effort: "low",
|
|
106
|
+
thinking: { enabled: false },
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function readObject(value: unknown): Record<string, unknown> | null {
|
|
111
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
return value as Record<string, unknown>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function deepEqual(a: unknown, b: unknown): boolean {
|
|
118
|
+
if (a === b) return true;
|
|
119
|
+
if (a === null || b === null) return false;
|
|
120
|
+
if (typeof a !== "object" || typeof b !== "object") return false;
|
|
121
|
+
if (Array.isArray(a) || Array.isArray(b)) return false;
|
|
122
|
+
|
|
123
|
+
const aRecord = a as Record<string, unknown>;
|
|
124
|
+
const bRecord = b as Record<string, unknown>;
|
|
125
|
+
const aKeys = Object.keys(aRecord);
|
|
126
|
+
const bKeys = Object.keys(bRecord);
|
|
127
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
128
|
+
|
|
129
|
+
for (const key of aKeys) {
|
|
130
|
+
if (!Object.prototype.hasOwnProperty.call(bRecord, key)) return false;
|
|
131
|
+
if (!deepEqual(aRecord[key], bRecord[key])) return false;
|
|
132
|
+
}
|
|
133
|
+
return true;
|
|
134
|
+
}
|