@vellumai/assistant 0.6.3 → 0.6.5
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/.prettierignore +5 -0
- package/ARCHITECTURE.md +298 -39
- package/Dockerfile +14 -3
- package/README.md +3 -4
- package/bun.lock +13 -16
- package/docs/architecture/integrations.md +1 -20
- package/docs/architecture/security.md +16 -16
- package/docs/backup-troubleshooting.md +52 -0
- package/docs/browser-use-architecture-phase2.md +174 -0
- package/docs/error-handling.md +111 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +121 -0
- package/knip.json +20 -3
- package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
- package/node_modules/@vellumai/ces-contracts/package.json +5 -4
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
- package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
- package/node_modules/@vellumai/credential-storage/package.json +2 -2
- package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
- package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
- package/node_modules/@vellumai/egress-proxy/package.json +2 -2
- package/openapi.yaml +1094 -72
- package/package.json +9 -8
- package/scripts/generate-openapi.ts +50 -12
- package/scripts/test.sh +73 -18
- package/src/__tests__/agent-image-optimize.test.ts +28 -0
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
- package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
- package/src/__tests__/agent-loop.test.ts +235 -1
- package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
- package/src/__tests__/anthropic-provider.test.ts +434 -12
- package/src/__tests__/approval-cascade.test.ts +31 -10
- package/src/__tests__/approval-routes-http.test.ts +134 -10
- package/src/__tests__/assistant-attachments.test.ts +44 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
- package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
- package/src/__tests__/browser-fill-credential.test.ts +12 -1
- package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
- package/src/__tests__/browser-skill-endstate.test.ts +52 -159
- package/src/__tests__/btw-routes.test.ts +54 -1
- package/src/__tests__/call-controller.test.ts +582 -22
- package/src/__tests__/call-site-routing-provider.test.ts +214 -0
- package/src/__tests__/catalog-cache.test.ts +27 -4
- package/src/__tests__/catalog-files.test.ts +138 -0
- package/src/__tests__/channel-approval-routes.test.ts +4 -4
- package/src/__tests__/channel-invite-transport.test.ts +2 -2
- package/src/__tests__/channel-readiness-routes.test.ts +16 -20
- package/src/__tests__/channel-readiness-service.test.ts +12 -7
- package/src/__tests__/channel-reply-delivery.test.ts +300 -2
- package/src/__tests__/checker.test.ts +576 -502
- package/src/__tests__/clawhub-files.test.ts +347 -0
- package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
- package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
- package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
- package/src/__tests__/compaction.benchmark.test.ts +1 -1
- package/src/__tests__/config-analysis.test.ts +83 -0
- package/src/__tests__/config-loader-backfill.test.ts +174 -0
- package/src/__tests__/config-loader-corrupt.test.ts +183 -0
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
- package/src/__tests__/config-schema-cmd.test.ts +11 -5
- package/src/__tests__/config-schema.test.ts +1458 -198
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +45 -10
- package/src/__tests__/contact-store-user-file.test.ts +511 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-token-estimator.test.ts +191 -1
- package/src/__tests__/context-window-manager.test.ts +618 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +32 -16
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +62 -17
- package/src/__tests__/conversation-agent-loop.test.ts +510 -84
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +165 -9
- package/src/__tests__/conversation-error.test.ts +102 -1
- package/src/__tests__/conversation-history-web-search.test.ts +17 -4
- package/src/__tests__/conversation-init.benchmark.test.ts +42 -1
- package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
- package/src/__tests__/conversation-lifecycle.test.ts +336 -0
- package/src/__tests__/conversation-list-source.test.ts +145 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +32 -16
- package/src/__tests__/conversation-process-callsite.test.ts +306 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +32 -16
- package/src/__tests__/conversation-queue.test.ts +932 -76
- package/src/__tests__/conversation-routes-disk-view.test.ts +299 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +2790 -55
- package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
- package/src/__tests__/conversation-skill-tools.test.ts +12 -143
- package/src/__tests__/conversation-slash-commands.test.ts +33 -0
- package/src/__tests__/conversation-slash-queue.test.ts +120 -34
- package/src/__tests__/conversation-slash-unknown.test.ts +32 -16
- package/src/__tests__/conversation-speed-override.test.ts +30 -11
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -2
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
- package/src/__tests__/conversation-unread-route.test.ts +2 -2
- package/src/__tests__/conversation-usage.test.ts +3 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
- package/src/__tests__/conversation-workspace-injection.test.ts +45 -15
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +46 -16
- package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +8 -3
- package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
- package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
- package/src/__tests__/credential-vault-unit.test.ts +495 -3
- package/src/__tests__/credentials-cli.test.ts +32 -16
- package/src/__tests__/cross-provider-web-search.test.ts +230 -35
- package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
- package/src/__tests__/delete-propagation.test.ts +437 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
- package/src/__tests__/device-id.test.ts +112 -0
- package/src/__tests__/dm-backfill.test.ts +417 -0
- package/src/__tests__/dm-persistence.test.ts +227 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
- package/src/__tests__/edit-propagation.test.ts +280 -0
- package/src/__tests__/email-html-renderer.test.ts +71 -0
- package/src/__tests__/email-invite-adapter.test.ts +36 -32
- package/src/__tests__/emit-event-signal.test.ts +71 -0
- package/src/__tests__/ephemeral-permissions.test.ts +93 -3
- package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
- package/src/__tests__/estimator-calibration.test.ts +213 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +101 -15
- package/src/__tests__/file-write-tool.test.ts +151 -1
- package/src/__tests__/filing-service.test.ts +255 -0
- package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +64 -3
- package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
- package/src/__tests__/guardian-grant-minting.test.ts +8 -0
- package/src/__tests__/headless-browser-interactions.test.ts +44 -1
- package/src/__tests__/headless-browser-mode.test.ts +614 -0
- package/src/__tests__/headless-browser-navigate.test.ts +142 -5
- package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
- package/src/__tests__/heartbeat-service.test.ts +166 -32
- package/src/__tests__/home-state-routes.test.ts +162 -0
- package/src/__tests__/host-bash-proxy.test.ts +0 -5
- package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
- package/src/__tests__/host-cu-proxy.test.ts +0 -5
- package/src/__tests__/host-shell-tool.test.ts +124 -18
- package/src/__tests__/http-user-message-parity.test.ts +29 -1
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/intent-routing.test.ts +1 -40
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/llm-catalog-parity.test.ts +174 -0
- package/src/__tests__/llm-context-normalization.test.ts +609 -0
- package/src/__tests__/llm-context-route-provider.test.ts +86 -5
- package/src/__tests__/llm-resolver.test.ts +214 -0
- package/src/__tests__/llm-schema.test.ts +223 -0
- package/src/__tests__/llm-usage-store.test.ts +363 -0
- package/src/__tests__/managed-proxy-context.test.ts +6 -2
- package/src/__tests__/media-stream-output.test.ts +555 -0
- package/src/__tests__/media-stream-parser.test.ts +374 -0
- package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
- package/src/__tests__/media-stream-stt-session.test.ts +588 -0
- package/src/__tests__/media-turn-detector.test.ts +440 -0
- package/src/__tests__/message-queue.test.ts +125 -0
- package/src/__tests__/messaging-skill-split.test.ts +3 -34
- package/src/__tests__/migration-export-http.test.ts +6 -6
- package/src/__tests__/migration-import-commit-http.test.ts +8 -6
- package/src/__tests__/migration-import-from-url.test.ts +684 -0
- package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +151 -0
- package/src/__tests__/model-intents.test.ts +10 -84
- package/src/__tests__/notification-decision-fallback.test.ts +0 -10
- package/src/__tests__/notification-decision-identity.test.ts +0 -9
- package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
- package/src/__tests__/oauth-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +2 -0
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
- package/src/__tests__/oauth-providers-routes.test.ts +2 -0
- package/src/__tests__/oauth-store.test.ts +95 -7
- package/src/__tests__/oauth2-gateway-transport.test.ts +257 -9
- package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
- package/src/__tests__/onboarding-template-contract.test.ts +6 -13
- package/src/__tests__/openai-provider.test.ts +183 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
- package/src/__tests__/openai-responses-provider.test.ts +1501 -0
- package/src/__tests__/openrouter-provider-only.test.ts +135 -0
- package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
- package/src/__tests__/permission-mode.test.ts +16 -0
- package/src/__tests__/permission-types.test.ts +0 -1
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/pkb-autoinject.test.ts +37 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -1
- package/src/__tests__/platform.test.ts +92 -1
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
- package/src/__tests__/pricing.test.ts +224 -3
- package/src/__tests__/profiler-routes.test.ts +1 -1
- package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
- package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
- package/src/__tests__/provider-error-scenarios.test.ts +135 -6
- package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
- package/src/__tests__/provider-registry-ollama.test.ts +1 -2
- package/src/__tests__/proxy-approval-callback.test.ts +0 -1
- package/src/__tests__/qdrant-manager.test.ts +29 -8
- package/src/__tests__/reaction-persistence.test.ts +560 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
- package/src/__tests__/relationship-state-contract.test.ts +175 -0
- package/src/__tests__/relay-server.test.ts +424 -6
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
- package/src/__tests__/risk-classifier-parity.test.ts +230 -0
- package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
- package/src/__tests__/search-skills-unified.test.ts +118 -0
- package/src/__tests__/secret-ingress-http.test.ts +28 -0
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
- package/src/__tests__/secret-scanner-executor.test.ts +5 -1
- package/src/__tests__/secure-keys.test.ts +107 -0
- package/src/__tests__/send-endpoint-busy.test.ts +34 -2
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +80 -0
- package/src/__tests__/settings-routes.test.ts +201 -0
- package/src/__tests__/shell-parser-property.test.ts +13 -13
- package/src/__tests__/skill-cache-store.test.ts +182 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
- package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
- package/src/__tests__/skills.test.ts +19 -30
- package/src/__tests__/skillssh-files.test.ts +446 -0
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-block-formatting.test.ts +110 -0
- package/src/__tests__/slack-channel-config.test.ts +564 -1
- package/src/__tests__/slack-skill.test.ts +3 -8
- package/src/__tests__/starter-bundle.test.ts +35 -0
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
- package/src/__tests__/suggestion-routes.test.ts +160 -3
- package/src/__tests__/system-prompt.test.ts +126 -53
- package/src/__tests__/task-runner.test.ts +3 -1
- package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +26 -7
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +2 -49
- package/src/__tests__/thread-backfill.test.ts +941 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +10 -6
- package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +88 -113
- package/src/__tests__/tool-result-truncation.test.ts +36 -0
- package/src/__tests__/trust-store.test.ts +442 -103
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
- package/src/__tests__/tts-catalog-parity.test.ts +345 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
- package/src/__tests__/twilio-routes.test.ts +376 -0
- package/src/__tests__/unicode.test.ts +293 -0
- package/src/__tests__/update-bulletin-job.test.ts +389 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
- package/src/__tests__/usage-routes.test.ts +25 -4
- package/src/__tests__/user-reference.test.ts +46 -61
- package/src/__tests__/verification-control-plane-policy.test.ts +5 -22
- package/src/__tests__/voice-config-update.test.ts +403 -0
- package/src/__tests__/voice-quality.test.ts +434 -19
- package/src/__tests__/voice-session-bridge.test.ts +39 -0
- package/src/__tests__/volume-security-guard.test.ts +3 -2
- package/src/__tests__/web-search-history.test.ts +337 -0
- package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
- package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
- package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
- package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
- package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
- package/src/__tests__/workspace-migration-meets.test.ts +244 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
- package/src/__tests__/workspace-policy.test.ts +1 -11
- package/src/acp/client-handler.ts +1 -2
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +251 -19
- package/src/avatar/resvg-lazy.test.ts +136 -0
- package/src/avatar/resvg-lazy.ts +82 -9
- package/src/avatar/traits-png-sync.ts +21 -1
- package/src/backup/__tests__/backup-key.test.ts +152 -0
- package/src/backup/__tests__/backup-worker.test.ts +767 -0
- package/src/backup/__tests__/list-snapshots.test.ts +87 -0
- package/src/backup/__tests__/local-writer.test.ts +218 -0
- package/src/backup/__tests__/offsite-writer.test.ts +641 -0
- package/src/backup/__tests__/paths.test.ts +300 -0
- package/src/backup/__tests__/restore.test.ts +498 -0
- package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
- package/src/backup/__tests__/stream-crypt.test.ts +228 -0
- package/src/backup/backup-key.ts +137 -0
- package/src/backup/backup-worker.ts +459 -0
- package/src/backup/list-snapshots.ts +147 -0
- package/src/backup/local-writer.ts +133 -0
- package/src/backup/offsite-writer.ts +222 -0
- package/src/backup/paths.ts +226 -0
- package/src/backup/restore.ts +322 -0
- package/src/backup/snapshot-lock.ts +431 -0
- package/src/backup/stream-crypt.ts +263 -0
- package/src/browser/__tests__/operations.test.ts +163 -0
- package/src/browser/identifiers.ts +51 -0
- package/src/browser/operations.ts +660 -0
- package/src/browser/types.ts +81 -0
- package/src/bundler/package-resolver.ts +4 -0
- package/src/calls/audio-store.ts +11 -5
- package/src/calls/call-controller.ts +226 -71
- package/src/calls/call-domain.ts +9 -0
- package/src/calls/call-speech-output.ts +190 -0
- package/src/calls/call-transport.ts +77 -0
- package/src/calls/guardian-question-copy.ts +2 -2
- package/src/calls/media-stream-audio-transcode.ts +173 -0
- package/src/calls/media-stream-output.ts +660 -0
- package/src/calls/media-stream-parser.ts +300 -0
- package/src/calls/media-stream-protocol.ts +166 -0
- package/src/calls/media-stream-server.ts +592 -0
- package/src/calls/media-stream-stt-session.ts +460 -0
- package/src/calls/media-turn-detector.ts +230 -0
- package/src/calls/relay-server.ts +90 -75
- package/src/calls/resolve-call-tts-provider.ts +136 -0
- package/src/calls/telephony-stt-routing.ts +145 -0
- package/src/calls/tts-call-strategy.ts +161 -0
- package/src/calls/tts-text-sanitizer.ts +32 -16
- package/src/calls/twilio-routes.ts +281 -17
- package/src/calls/voice-quality.ts +78 -35
- package/src/calls/voice-session-bridge.ts +9 -1
- package/src/channels/types.ts +16 -0
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/__tests__/run-assistant-command.ts +11 -1
- package/src/cli/commands/__tests__/attachment.test.ts +438 -0
- package/src/cli/commands/__tests__/backup.test.ts +1165 -0
- package/src/cli/commands/__tests__/browser.test.ts +554 -0
- package/src/cli/commands/__tests__/cache.test.ts +623 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
- package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
- package/src/cli/commands/__tests__/email-download.test.ts +16 -1
- package/src/cli/commands/__tests__/email-list.test.ts +28 -4
- package/src/cli/commands/__tests__/email-register.test.ts +4 -4
- package/src/cli/commands/__tests__/email-send.test.ts +130 -5
- package/src/cli/commands/__tests__/email-status.test.ts +5 -1
- package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
- package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
- package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
- package/src/cli/commands/__tests__/task.test.ts +913 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
- package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
- package/src/cli/commands/__tests__/ui.test.ts +1215 -0
- package/src/cli/commands/__tests__/watchers.test.ts +716 -0
- package/src/cli/commands/attachment.ts +182 -0
- package/src/cli/commands/backup.ts +993 -0
- package/src/cli/commands/browser.ts +350 -0
- package/src/cli/commands/cache.ts +341 -0
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/config.ts +6 -6
- package/src/cli/commands/conversations-import.ts +347 -0
- package/src/cli/commands/conversations.ts +90 -0
- package/src/cli/commands/credentials.ts +0 -1
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +308 -16
- package/src/cli/commands/image-generation.ts +300 -0
- package/src/cli/commands/inference.ts +200 -0
- package/src/cli/commands/memory.ts +127 -17
- package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
- package/src/cli/commands/oauth/mode.ts +12 -3
- package/src/cli/commands/oauth/providers.ts +15 -0
- package/src/cli/commands/oauth/shared.ts +2 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -10
- package/src/cli/commands/platform/__tests__/connect.test.ts +6 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -2
- package/src/cli/commands/platform/__tests__/status.test.ts +6 -1
- package/src/cli/commands/stt.ts +339 -0
- package/src/cli/commands/task.ts +795 -0
- package/src/cli/commands/trust.ts +50 -19
- package/src/cli/commands/tts.ts +273 -0
- package/src/cli/commands/ui.ts +670 -0
- package/src/cli/commands/watchers.ts +509 -0
- package/src/cli/lib/daemon-credential-client.ts +0 -19
- package/src/cli/program.ts +53 -8
- package/src/cli.ts +0 -37
- package/src/config/__tests__/backup-schema.test.ts +134 -0
- package/src/config/assistant-feature-flags.ts +61 -62
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
- package/src/config/bundled-skills/contacts/SKILL.md +2 -2
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
- package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
- package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
- package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
- package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
- package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
- package/src/config/bundled-skills/messaging/SKILL.md +5 -5
- package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -2
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +28 -18
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
- package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
- package/src/config/bundled-tool-registry.ts +0 -167
- package/src/config/env-registry.ts +24 -0
- package/src/config/env.ts +39 -10
- package/src/config/feature-flag-registry.json +63 -15
- package/src/config/llm-resolver.ts +128 -0
- package/src/config/loader.ts +220 -22
- package/src/config/raw-config-utils.ts +30 -2
- package/src/config/sanitize-for-transfer.ts +35 -0
- package/src/config/schema.ts +65 -51
- package/src/config/schemas/__tests__/stt.test.ts +43 -0
- package/src/config/schemas/analysis.ts +32 -0
- package/src/config/schemas/backup.ts +72 -0
- package/src/config/schemas/calls.ts +1 -30
- package/src/config/schemas/elevenlabs.ts +0 -59
- package/src/config/schemas/filing.ts +49 -14
- package/src/config/schemas/heartbeat.ts +27 -10
- package/src/config/schemas/host-browser.ts +47 -1
- package/src/config/schemas/inference.ts +3 -23
- package/src/config/schemas/llm.ts +318 -0
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/memory-processing.ts +1 -9
- package/src/config/schemas/notifications.ts +4 -11
- package/src/config/schemas/platform.ts +3 -9
- package/src/config/schemas/security.ts +33 -0
- package/src/config/schemas/services.ts +53 -4
- package/src/config/schemas/stt.ts +60 -0
- package/src/config/schemas/tts.ts +283 -0
- package/src/config/schemas/updates.ts +14 -0
- package/src/config/schemas/workspace-git.ts +3 -40
- package/src/config/skills.ts +6 -2
- package/src/config/types.ts +4 -0
- package/src/contacts/contact-store.ts +56 -11
- package/src/contacts/contacts-write.ts +38 -1
- package/src/context/__tests__/compact-prompt.test.ts +45 -0
- package/src/context/__tests__/microcompact.test.ts +805 -0
- package/src/context/estimator-calibration.ts +136 -0
- package/src/context/microcompact.ts +443 -0
- package/src/context/post-turn-tool-result-truncation.ts +3 -2
- package/src/context/prompts/compact.md +12 -0
- package/src/context/token-estimator.ts +61 -3
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +272 -35
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/executable-discovery.ts +23 -2
- package/src/credential-execution/process-manager.test.ts +109 -0
- package/src/credential-execution/process-manager.ts +96 -2
- package/src/credential-health/credential-health-service.ts +366 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
- package/src/daemon/approval-generators.ts +29 -4
- package/src/daemon/assistant-attachments.ts +24 -13
- package/src/daemon/classifier.ts +2 -2
- package/src/daemon/config-watcher.ts +99 -6
- package/src/daemon/context-overflow-reducer.ts +4 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +85 -12
- package/src/daemon/conversation-agent-loop.ts +563 -104
- package/src/daemon/conversation-attachments.ts +2 -6
- package/src/daemon/conversation-error.ts +46 -0
- package/src/daemon/conversation-history.ts +40 -6
- package/src/daemon/conversation-launch.ts +220 -0
- package/src/daemon/conversation-lifecycle.ts +85 -11
- package/src/daemon/conversation-messaging.ts +110 -7
- package/src/daemon/conversation-notifiers.ts +5 -0
- package/src/daemon/conversation-process.ts +591 -23
- package/src/daemon/conversation-queue-manager.ts +27 -0
- package/src/daemon/conversation-runtime-assembly.ts +769 -28
- package/src/daemon/conversation-slash.ts +38 -2
- package/src/daemon/conversation-surfaces.ts +483 -5
- package/src/daemon/conversation-tool-setup.ts +35 -5
- package/src/daemon/conversation-usage.ts +8 -5
- package/src/daemon/conversation.ts +193 -47
- package/src/daemon/external-skills-bootstrap.ts +41 -0
- package/src/daemon/guardian-action-generators.ts +34 -14
- package/src/daemon/handlers/config-model.test.ts +86 -0
- package/src/daemon/handlers/config-model.ts +54 -12
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +13 -3
- package/src/daemon/handlers/shared.ts +51 -1
- package/src/daemon/handlers/skills.ts +323 -79
- package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
- package/src/daemon/host-browser-proxy.ts +2 -1
- package/src/daemon/lifecycle.ts +185 -26
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/conversations.ts +48 -1
- package/src/daemon/message-types/home.ts +40 -0
- package/src/daemon/message-types/meet.ts +143 -0
- package/src/daemon/message-types/messages.ts +23 -1
- package/src/daemon/message-types/schedules.ts +34 -2
- package/src/daemon/message-types/skills.ts +16 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/message-types/trust.ts +0 -2
- package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
- package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
- package/src/daemon/pkb-context-tracker.test.ts +169 -0
- package/src/daemon/pkb-context-tracker.ts +125 -0
- package/src/daemon/pkb-reminder-builder.test.ts +70 -0
- package/src/daemon/pkb-reminder-builder.ts +31 -0
- package/src/daemon/providers-setup.ts +6 -0
- package/src/daemon/server.ts +463 -10
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +9 -9
- package/src/daemon/watch-handler.ts +4 -4
- package/src/daemon/web-search-history.ts +126 -0
- package/src/email/html-renderer.ts +76 -0
- package/src/events/domain-events.ts +0 -1
- package/src/filing/filing-service.ts +9 -10
- package/src/heartbeat/heartbeat-service.ts +156 -22
- package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
- package/src/home/__tests__/emit-feed-event.test.ts +169 -0
- package/src/home/__tests__/feed-scheduler.test.ts +222 -0
- package/src/home/__tests__/feed-types.test.ts +275 -0
- package/src/home/__tests__/feed-writer.test.ts +688 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
- package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
- package/src/home/__tests__/progress-formula.test.ts +213 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
- package/src/home/__tests__/rollup-producer.test.ts +442 -0
- package/src/home/assistant-feed-authoring.ts +128 -0
- package/src/home/emit-feed-event.ts +162 -0
- package/src/home/feed-scheduler.ts +263 -0
- package/src/home/feed-types.ts +235 -0
- package/src/home/feed-writer.ts +469 -0
- package/src/home/platform-gmail-digest.ts +163 -0
- package/src/home/progress-formula.ts +86 -0
- package/src/home/relationship-state-writer.ts +824 -0
- package/src/home/relationship-state.ts +143 -0
- package/src/home/rollup-producer.ts +413 -0
- package/src/home/suggested-prompts.ts +101 -0
- package/src/hooks/runner.ts +7 -0
- package/src/inbound/platform-callback-registration.ts +12 -3
- package/src/inbound/public-ingress-urls.ts +12 -0
- package/src/instrument.ts +1 -1
- package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
- package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
- package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
- package/src/ipc/__tests__/socket-path.test.ts +73 -0
- package/src/ipc/__tests__/task-ipc.test.ts +577 -0
- package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
- package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
- package/src/ipc/cli-client.ts +152 -0
- package/src/ipc/cli-server.ts +252 -0
- package/src/ipc/gateway-client.ts +180 -0
- package/src/ipc/routes/attachment.ts +114 -0
- package/src/ipc/routes/browser-context.ts +61 -0
- package/src/ipc/routes/browser.ts +96 -0
- package/src/ipc/routes/cache.ts +96 -0
- package/src/ipc/routes/index.ts +21 -0
- package/src/ipc/routes/task-queue.ts +226 -0
- package/src/ipc/routes/task.ts +173 -0
- package/src/ipc/routes/ui-request.ts +50 -0
- package/src/ipc/routes/wake-conversation.ts +19 -0
- package/src/ipc/routes/watcher.ts +203 -0
- package/src/ipc/socket-path.ts +100 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
- package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +233 -0
- package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
- package/src/memory/admin.ts +18 -0
- package/src/memory/app-store.ts +1 -1
- package/src/memory/attachments-store.ts +70 -0
- package/src/memory/auto-analysis-enqueue.ts +127 -0
- package/src/memory/auto-analysis-guard.ts +27 -0
- package/src/memory/cleanup-schedule-state.ts +37 -0
- package/src/memory/conversation-analyze-job.ts +74 -0
- package/src/memory/conversation-attention-store.ts +13 -6
- package/src/memory/conversation-crud.ts +199 -0
- package/src/memory/conversation-disk-view.ts +7 -0
- package/src/memory/conversation-group-migration.ts +65 -1
- package/src/memory/conversation-queries.ts +6 -5
- package/src/memory/conversation-title-service.ts +7 -4
- package/src/memory/db-init.ts +8 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/embedding-backend.ts +1 -1
- package/src/memory/graph/compaction.ts +299 -0
- package/src/memory/graph/consolidation.ts +4 -4
- package/src/memory/graph/conversation-graph-memory.ts +104 -29
- package/src/memory/graph/extraction.test.ts +295 -2
- package/src/memory/graph/extraction.ts +181 -51
- package/src/memory/graph/graph-search.test.ts +92 -0
- package/src/memory/graph/graph-search.ts +4 -1
- package/src/memory/graph/narrative.ts +2 -2
- package/src/memory/graph/pattern-scan.ts +2 -2
- package/src/memory/graph/retriever.test.ts +459 -0
- package/src/memory/graph/retriever.ts +257 -66
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- package/src/memory/graph/store.ts +41 -0
- package/src/memory/graph/tool-handlers.ts +27 -0
- package/src/memory/graph/tools.ts +6 -1
- package/src/memory/group-crud.ts +6 -1
- package/src/memory/indexer.ts +95 -16
- package/src/memory/job-handlers/cleanup.ts +11 -8
- package/src/memory/job-handlers/conversation-starters.ts +39 -30
- package/src/memory/job-handlers/summarization.ts +2 -2
- package/src/memory/job-utils.ts +7 -1
- package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
- package/src/memory/jobs/embed-pkb-file.ts +54 -0
- package/src/memory/jobs-store.ts +106 -5
- package/src/memory/jobs-worker.ts +26 -9
- package/src/memory/llm-usage-store.ts +92 -56
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
- package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
- package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-index.test.ts +368 -0
- package/src/memory/pkb/pkb-index.ts +255 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
- package/src/memory/pkb/pkb-reconcile.ts +148 -0
- package/src/memory/pkb/pkb-search.test.ts +438 -0
- package/src/memory/pkb/pkb-search.ts +137 -0
- package/src/memory/pkb/types.ts +53 -0
- package/src/memory/qdrant-client.ts +122 -1
- package/src/memory/qdrant-manager.ts +43 -16
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/oauth.ts +3 -0
- package/src/memory/slack-thread-store.ts +37 -0
- package/src/memory/usage-buckets.ts +396 -0
- package/src/messaging/providers/gmail/adapter.ts +6 -16
- package/src/messaging/providers/gmail/client.ts +79 -6
- package/src/messaging/providers/gmail/types.ts +7 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
- package/src/messaging/providers/slack/adapter.ts +155 -38
- package/src/messaging/providers/slack/backfill.test.ts +257 -0
- package/src/messaging/providers/slack/backfill.ts +101 -0
- package/src/messaging/providers/slack/client.ts +16 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
- package/src/messaging/providers/slack/message-metadata.ts +123 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
- package/src/messaging/providers/slack/render-transcript.ts +443 -0
- package/src/messaging/providers/slack/types.ts +4 -0
- package/src/messaging/style-analyzer.ts +5 -2
- package/src/notifications/README.md +9 -5
- package/src/notifications/decision-engine.ts +6 -12
- package/src/notifications/preference-extractor.ts +2 -6
- package/src/notifications/signal.ts +5 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
- package/src/oauth/byo-connection.test.ts +18 -1
- package/src/oauth/byo-connection.ts +3 -1
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.ts +6 -2
- package/src/oauth/connection.ts +2 -0
- package/src/oauth/oauth-store.ts +10 -0
- package/src/oauth/platform-connection.test.ts +145 -0
- package/src/oauth/platform-connection.ts +62 -31
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/approval-policy.test.ts +948 -0
- package/src/permissions/approval-policy.ts +257 -0
- package/src/permissions/bash-risk-classifier.test.ts +1208 -0
- package/src/permissions/bash-risk-classifier.ts +707 -0
- package/src/permissions/checker.ts +218 -699
- package/src/permissions/command-registry.test.ts +535 -0
- package/src/permissions/command-registry.ts +825 -0
- package/src/permissions/defaults.ts +71 -75
- package/src/permissions/file-risk-classifier.test.ts +535 -0
- package/src/permissions/file-risk-classifier.ts +274 -0
- package/src/permissions/risk-types.ts +205 -0
- package/src/permissions/secret-prompter.ts +53 -2
- package/src/permissions/skill-risk-classifier.test.ts +311 -0
- package/src/permissions/skill-risk-classifier.ts +214 -0
- package/src/permissions/trust-client.ts +52 -25
- package/src/permissions/trust-store-interface.ts +1 -6
- package/src/permissions/trust-store.ts +164 -65
- package/src/permissions/types.ts +23 -14
- package/src/permissions/web-risk-classifier.test.ts +170 -0
- package/src/permissions/web-risk-classifier.ts +89 -0
- package/src/permissions/workspace-policy.ts +1 -13
- package/src/platform/client.test.ts +10 -0
- package/src/platform/client.ts +19 -1
- package/src/platform/sync-identity.ts +129 -0
- package/src/prompts/persona-resolver.ts +127 -3
- package/src/prompts/system-prompt.ts +78 -38
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- package/src/prompts/templates/SOUL.md +5 -3
- package/src/prompts/templates/channels/slack.md +20 -0
- package/src/prompts/update-bulletin-job.ts +190 -0
- package/src/prompts/user-reference.ts +20 -17
- package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
- package/src/providers/__tests__/retry-callsite.test.ts +424 -0
- package/src/providers/anthropic/client.ts +335 -70
- package/src/providers/call-site-routing.ts +71 -0
- package/src/providers/fireworks/client.ts +2 -2
- package/src/providers/gemini/client.ts +74 -3
- package/src/providers/managed-proxy/constants.ts +2 -1
- package/src/providers/model-catalog.ts +502 -28
- package/src/providers/model-intents.ts +8 -8
- package/src/providers/ollama/client.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +530 -0
- package/src/providers/openai/client.ts +25 -440
- package/src/providers/openai/responses-provider.ts +579 -0
- package/src/providers/openrouter/client.ts +168 -4
- package/src/providers/provider-env-vars.ts +56 -0
- package/src/providers/provider-secret-catalog.ts +139 -0
- package/src/providers/provider-send-message.ts +22 -5
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/registry.ts +21 -10
- package/src/providers/retry.ts +185 -39
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +883 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
- package/src/providers/speech-to-text/deepgram.test.ts +332 -0
- package/src/providers/speech-to-text/deepgram.ts +115 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
- package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
- package/src/providers/speech-to-text/google-gemini.ts +101 -0
- package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
- package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
- package/src/providers/speech-to-text/openai-whisper.ts +63 -33
- package/src/providers/speech-to-text/provider-catalog.ts +323 -0
- package/src/providers/speech-to-text/resolve.ts +393 -6
- package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
- package/src/providers/speech-to-text/xai-realtime.ts +796 -0
- package/src/providers/speech-to-text/xai.test.ts +155 -0
- package/src/providers/speech-to-text/xai.ts +97 -0
- package/src/providers/types.ts +102 -3
- package/src/runtime/AGENTS.md +45 -3
- package/src/runtime/__tests__/agent-wake.test.ts +872 -0
- package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
- package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
- package/src/runtime/agent-wake.ts +553 -0
- package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
- package/src/runtime/auth/route-policy.ts +34 -5
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +15 -3
- package/src/runtime/capability-tokens.ts +10 -10
- package/src/runtime/channel-invite-transport.ts +1 -1
- package/src/runtime/channel-invite-transports/email.ts +14 -6
- package/src/runtime/channel-readiness-service.ts +12 -22
- package/src/runtime/channel-reply-delivery.ts +106 -2
- package/src/runtime/chrome-extension-registry.ts +38 -2
- package/src/runtime/decision-token.ts +116 -0
- package/src/runtime/gateway-client.ts +2 -2
- package/src/runtime/http-router.ts +32 -0
- package/src/runtime/http-server.ts +447 -11
- package/src/runtime/http-types.ts +29 -3
- package/src/runtime/interactive-ui.ts +362 -0
- package/src/runtime/invite-instruction-generator.ts +2 -2
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
- package/src/runtime/migrations/gcs-signed-url.ts +162 -0
- package/src/runtime/migrations/migration-transport.ts +1 -0
- package/src/runtime/migrations/migration-wizard.ts +1 -0
- package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
- package/src/runtime/migrations/vbundle-importer.ts +187 -8
- package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
- package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
- package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
- package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
- package/src/runtime/migrations/vbundle-validator.ts +15 -6
- package/src/runtime/pending-interactions.ts +0 -11
- package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +618 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +247 -0
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
- package/src/runtime/routes/app-management-routes.ts +12 -18
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
- package/src/runtime/routes/approval-routes.ts +12 -17
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
- package/src/runtime/routes/attachment-routes.test.ts +9 -3
- package/src/runtime/routes/attachment-routes.ts +216 -17
- package/src/runtime/routes/avatar-routes.ts +20 -4
- package/src/runtime/routes/backup-routes.ts +519 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
- package/src/runtime/routes/btw-routes.ts +9 -10
- package/src/runtime/routes/contact-routes.test.ts +298 -0
- package/src/runtime/routes/contact-routes.ts +132 -5
- package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
- package/src/runtime/routes/conversation-management-routes.ts +133 -0
- package/src/runtime/routes/conversation-routes.ts +487 -160
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/diagnostics-routes.ts +6 -4
- package/src/runtime/routes/events-routes.ts +16 -0
- package/src/runtime/routes/filing-routes.ts +93 -0
- package/src/runtime/routes/guardian-approval-interception.ts +33 -3
- package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
- package/src/runtime/routes/home-feed-routes.ts +452 -0
- package/src/runtime/routes/home-state-routes.ts +138 -0
- package/src/runtime/routes/host-browser-routes.ts +3 -14
- package/src/runtime/routes/identity-intro-cache.ts +7 -3
- package/src/runtime/routes/identity-routes.ts +3 -17
- package/src/runtime/routes/inbound-message-handler.ts +912 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
- package/src/runtime/routes/integrations/slack/channel.ts +36 -6
- package/src/runtime/routes/integrations/slack/share.ts +45 -7
- package/src/runtime/routes/llm-context-normalization.ts +325 -0
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/migration-routes.ts +722 -91
- package/src/runtime/routes/settings-routes.ts +26 -7
- package/src/runtime/routes/skills-routes.ts +76 -7
- package/src/runtime/routes/stt-routes.ts +233 -0
- package/src/runtime/routes/surface-action-routes.ts +41 -2
- package/src/runtime/routes/trust-rules-routes.ts +30 -14
- package/src/runtime/routes/tts-routes.ts +108 -24
- package/src/runtime/routes/usage-routes.ts +30 -2
- package/src/runtime/routes/user-route-dispatcher.ts +50 -5
- package/src/runtime/routes/user-routes.ts +13 -1
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/routes/work-items-routes.ts +11 -3
- package/src/runtime/runtime-mode.ts +33 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +426 -0
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
- package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
- package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
- package/src/runtime/services/analyze-conversation.ts +340 -0
- package/src/runtime/services/analyze-deps-singleton.ts +32 -0
- package/src/runtime/services/auto-analysis-prompt.ts +55 -0
- package/src/runtime/skill-route-registry.ts +71 -0
- package/src/runtime/slack-block-formatting.ts +437 -10
- package/src/schedule/scheduler.ts +58 -0
- package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
- package/src/security/__tests__/untrusted-content.test.ts +109 -0
- package/src/security/oauth2.ts +122 -37
- package/src/security/secure-keys.ts +32 -10
- package/src/security/token-manager.ts +35 -13
- package/src/security/untrusted-content.ts +102 -0
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-cache.ts +26 -7
- package/src/skills/catalog-files.ts +64 -2
- package/src/skills/catalog-install.ts +31 -3
- package/src/skills/category-inference.ts +122 -0
- package/src/skills/clawhub-files.ts +213 -0
- package/src/skills/clawhub.ts +84 -23
- package/src/skills/skill-cache-store.ts +97 -0
- package/src/skills/skill-file-provider.ts +40 -0
- package/src/skills/skillssh-files.ts +395 -0
- package/src/skills/skillssh-registry.ts +4 -4
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +468 -0
- package/src/stt/__tests__/types.test.ts +89 -0
- package/src/stt/daemon-batch-transcriber.ts +228 -0
- package/src/stt/stt-stream-session.ts +506 -0
- package/src/stt/types.ts +334 -0
- package/src/stt/wav-encoder.test.ts +373 -0
- package/src/stt/wav-encoder.ts +175 -0
- package/src/subagent/manager.ts +79 -27
- package/src/tasks/ephemeral-permissions.ts +9 -4
- package/src/telemetry/usage-telemetry-reporter.ts +27 -5
- package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +166 -0
- package/src/tools/browser/browser-execution.ts +1208 -41
- package/src/tools/browser/browser-manager.ts +45 -0
- package/src/tools/browser/browser-mode-constants.ts +12 -0
- package/src/tools/browser/browser-mode.ts +92 -0
- package/src/tools/browser/browser-status-constants.ts +33 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +205 -17
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
- package/src/tools/browser/cdp-client/errors.ts +15 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
- package/src/tools/browser/cdp-client/factory.ts +797 -87
- package/src/tools/browser/cdp-client/index.ts +16 -2
- package/src/tools/browser/cdp-client/types.ts +68 -0
- package/src/tools/credentials/tool-policy.ts +39 -5
- package/src/tools/credentials/vault.ts +41 -7
- package/src/tools/executor.ts +4 -0
- package/src/tools/filesystem/write.ts +52 -0
- package/src/tools/host-terminal/host-shell.ts +45 -5
- package/src/tools/memory/register.test.ts +185 -0
- package/src/tools/memory/register.ts +3 -1
- package/src/tools/network/web-fetch.ts +25 -12
- package/src/tools/network/web-search.ts +20 -2
- package/src/tools/permission-checker.ts +36 -15
- package/src/tools/policy-context.ts +25 -8
- package/src/tools/registry.ts +55 -3
- package/src/tools/shared/shell-output.ts +3 -1
- package/src/tools/side-effects.ts +0 -9
- package/src/tools/skills/execute.ts +2 -2
- package/src/tools/skills/sandbox-runner.ts +6 -2
- package/src/tools/terminal/backends/native.ts +51 -2
- package/src/tools/terminal/safe-env.ts +11 -2
- package/src/tools/terminal/shell.ts +16 -4
- package/src/tools/tool-manifest.ts +6 -0
- package/src/tools/types.ts +29 -3
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tools/verification-control-plane-policy.ts +1 -1
- package/src/tts/__tests__/provider-adapters.test.ts +1061 -0
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
- package/src/tts/__tests__/provider-catalog.test.ts +183 -0
- package/src/tts/__tests__/provider-registry.test.ts +90 -0
- package/src/tts/provider-catalog.ts +219 -0
- package/src/tts/provider-registry.ts +73 -0
- package/src/tts/providers/deepgram-provider.ts +219 -0
- package/src/tts/providers/elevenlabs-provider.ts +211 -0
- package/src/tts/providers/fish-audio-provider.ts +183 -0
- package/src/tts/providers/index.ts +44 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/providers/xai-provider.ts +224 -0
- package/src/tts/synthesize-text.ts +110 -0
- package/src/tts/tts-config-resolver.ts +78 -0
- package/src/tts/types.ts +199 -0
- package/src/types/onboarding-context.ts +7 -0
- package/src/types/tar-stream.d.ts +66 -0
- package/src/util/abort-reasons.ts +58 -0
- package/src/util/device-id.ts +32 -16
- package/src/util/errors.ts +9 -1
- package/src/util/json.ts +17 -0
- package/src/util/platform.ts +56 -12
- package/src/util/pricing.ts +78 -5
- package/src/util/spawn.ts +1 -1
- package/src/util/truncate.ts +4 -2
- package/src/util/unicode.ts +201 -0
- package/src/version.ts +19 -24
- package/src/watcher/engine.ts +24 -1
- package/src/watcher/providers/google-calendar.ts +134 -8
- package/src/watcher/providers/outlook-calendar.ts +42 -2
- package/src/watcher/watcher-store.ts +31 -0
- package/src/workspace/git-service.ts +23 -4
- package/src/workspace/migrations/003-seed-device-id.ts +9 -3
- package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
- package/src/workspace/migrations/029-seed-pkb.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +317 -0
- package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
- package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
- package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
- package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
- package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
- package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
- package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
- package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
- package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
- package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
- package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
- package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/registry.ts +32 -0
- package/src/workspace/provider-commit-message-generator.ts +19 -38
- package/src/workspace/top-level-renderer.ts +13 -1
- package/src/workspace/turn-commit.ts +31 -0
- package/src/__tests__/email-cli.test.ts +0 -297
- package/src/__tests__/email-service-config-fallback.test.ts +0 -102
- package/src/__tests__/outlook-attachments.test.ts +0 -301
- package/src/__tests__/outlook-automation-tools.test.ts +0 -425
- package/src/__tests__/outlook-categories.test.ts +0 -212
- package/src/__tests__/outlook-compose-tools.test.ts +0 -325
- package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
- package/src/__tests__/outlook-follow-up.test.ts +0 -196
- package/src/__tests__/outlook-trash.test.ts +0 -77
- package/src/__tests__/outlook-unsubscribe.test.ts +0 -250
- package/src/__tests__/update-bulletin-format.test.ts +0 -122
- package/src/__tests__/update-bulletin-state.test.ts +0 -135
- package/src/__tests__/update-bulletin.test.ts +0 -277
- package/src/__tests__/update-template-contract.test.ts +0 -29
- package/src/cli/commands/browser-relay.ts +0 -466
- package/src/cli/commands/doctor.ts +0 -341
- package/src/config/bundled-skills/browser/SKILL.md +0 -63
- package/src/config/bundled-skills/browser/TOOLS.json +0 -393
- package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -32
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
- package/src/config/bundled-skills/gmail/SKILL.md +0 -175
- package/src/config/bundled-skills/gmail/TOOLS.json +0 -558
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -149
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -220
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -251
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
- package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
- package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
- package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/google-calendar/types.ts +0 -97
- package/src/config/bundled-skills/outlook/SKILL.md +0 -196
- package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
- package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
- package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
- package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
- package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
- package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
- package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
- package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
- package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
- package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
- package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
- package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
- package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
- package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
- package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
- package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
- package/src/config/bundled-skills/slack/SKILL.md +0 -107
- package/src/config/bundled-skills/tasks/SKILL.md +0 -37
- package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
- package/src/config/bundled-skills/tasks/icon.svg +0 -34
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
- package/src/config/bundled-skills/watcher/SKILL.md +0 -31
- package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
- package/src/email/guardrails.ts +0 -221
- package/src/email/provider.ts +0 -117
- package/src/email/providers/agentmail.ts +0 -361
- package/src/email/providers/index.ts +0 -65
- package/src/email/service.ts +0 -384
- package/src/email/types.ts +0 -126
- package/src/prompts/templates/UPDATES.md +0 -38
- package/src/prompts/templates/USER.md +0 -13
- package/src/prompts/update-bulletin-format.ts +0 -68
- package/src/prompts/update-bulletin-state.ts +0 -58
- package/src/prompts/update-bulletin-template-path.ts +0 -13
- package/src/prompts/update-bulletin.ts +0 -128
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/runtime/routes/browser-cdp-routes.ts +0 -229
- package/src/shared/provider-env-vars.ts +0 -19
- package/src/tools/watcher/create.ts +0 -86
- package/src/tools/watcher/delete.ts +0 -36
- package/src/tools/watcher/digest.ts +0 -54
- package/src/tools/watcher/list.ts +0 -83
- package/src/tools/watcher/update.ts +0 -71
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relationship-state writer.
|
|
3
|
+
*
|
|
4
|
+
* Derives a `RelationshipState` snapshot from the filesystem state of
|
|
5
|
+
* the workspace (the guardian's `users/<slug>.md` persona file — resolved
|
|
6
|
+
* via `persona-resolver` / `contact-store` — for world + priorities facts,
|
|
7
|
+
* with legacy workspace-root `USER.md` as a last-ditch fallback; SOUL.md
|
|
8
|
+
* for voice facts; IDENTITY.md for assistant / hatched metadata) plus
|
|
9
|
+
* the DB-authoritative conversation count (via
|
|
10
|
+
* `conversation-queries.countConversations`, matching the UI's
|
|
11
|
+
* `listConversations` filter — no `background` / `private` / `scheduled`)
|
|
12
|
+
* and the OAuth connection store (for capability tiers), and writes it
|
|
13
|
+
* to `<workspace>/data/relationship-state.json`.
|
|
14
|
+
*
|
|
15
|
+
* Per assistant/CLAUDE.md the daemon must never block or throw at
|
|
16
|
+
* startup — the public entry points here catch every error and log a
|
|
17
|
+
* warning instead. Internal helpers use a narrow `safeRead` wrapper so
|
|
18
|
+
* a missing or unreadable file degrades gracefully to an empty string.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
existsSync,
|
|
23
|
+
mkdirSync,
|
|
24
|
+
readFileSync,
|
|
25
|
+
statSync,
|
|
26
|
+
writeFileSync,
|
|
27
|
+
} from "node:fs";
|
|
28
|
+
import { join } from "node:path";
|
|
29
|
+
|
|
30
|
+
import { countConversations as countConversationsDb } from "../memory/conversation-queries.js";
|
|
31
|
+
import { listConnections } from "../oauth/oauth-store.js";
|
|
32
|
+
import { resolveGuardianPersonaPath } from "../prompts/persona-resolver.js";
|
|
33
|
+
import { buildAssistantEvent } from "../runtime/assistant-event.js";
|
|
34
|
+
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
35
|
+
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
36
|
+
import type { OnboardingContext } from "../types/onboarding-context.js";
|
|
37
|
+
import { getLogger } from "../util/logger.js";
|
|
38
|
+
import {
|
|
39
|
+
getDataDir,
|
|
40
|
+
getWorkspaceDir,
|
|
41
|
+
getWorkspacePromptPath,
|
|
42
|
+
} from "../util/platform.js";
|
|
43
|
+
import { computeProgressPercent, computeTier } from "./progress-formula.js";
|
|
44
|
+
import {
|
|
45
|
+
type Capability,
|
|
46
|
+
DEFAULT_CAPABILITIES,
|
|
47
|
+
type Fact,
|
|
48
|
+
RELATIONSHIP_STATE_VERSION,
|
|
49
|
+
type RelationshipState,
|
|
50
|
+
} from "./relationship-state.js";
|
|
51
|
+
|
|
52
|
+
const log = getLogger("relationship-state-writer");
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Filename for the on-disk snapshot. Lives under the workspace data dir.
|
|
56
|
+
*/
|
|
57
|
+
export const RELATIONSHIP_STATE_FILENAME = "relationship-state.json";
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Filename for the pre-chat onboarding sidecar. Lives under the workspace
|
|
61
|
+
* data dir alongside `relationship-state.json`. Written once by the
|
|
62
|
+
* `POST /v1/messages` handler on first message and read on every
|
|
63
|
+
* `computeRelationshipState()` call so onboarding-sourced facts survive
|
|
64
|
+
* the pure-recomputation write cycle (every turn boundary rebuilds facts
|
|
65
|
+
* from scratch — without the sidecar, onboarding chips would vanish on
|
|
66
|
+
* turn 2).
|
|
67
|
+
*/
|
|
68
|
+
export const ONBOARDING_SIDECAR_FILENAME = "onboarding-context.json";
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Conversation-count threshold at which the "voice-writing" capability
|
|
72
|
+
* flips from `earned` (gated, shown with an `unlockHint`) to `unlocked`.
|
|
73
|
+
*
|
|
74
|
+
* This is a placeholder for Open Question #6 in the TDD. Wrap as a
|
|
75
|
+
* named constant so it's obvious which knob to tune when a deeper
|
|
76
|
+
* heuristic replaces it.
|
|
77
|
+
*/
|
|
78
|
+
const VOICE_WRITING_UNLOCK_CONVERSATIONS = 10;
|
|
79
|
+
|
|
80
|
+
/** Default assistant name when IDENTITY.md cannot be parsed. */
|
|
81
|
+
const DEFAULT_ASSISTANT_NAME = "Vellum";
|
|
82
|
+
|
|
83
|
+
/** Default assistant identifier (multi-assistant reserved for future). */
|
|
84
|
+
const DEFAULT_ASSISTANT_ID = "default";
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Canonical path to the relationship-state snapshot
|
|
88
|
+
* (`<workspace>/data/relationship-state.json`).
|
|
89
|
+
*/
|
|
90
|
+
export function getRelationshipStatePath(): string {
|
|
91
|
+
return join(getDataDir(), RELATIONSHIP_STATE_FILENAME);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Canonical path to the onboarding sidecar
|
|
96
|
+
* (`<workspace>/data/onboarding-context.json`).
|
|
97
|
+
*/
|
|
98
|
+
export function getOnboardingSidecarPath(): string {
|
|
99
|
+
return join(getDataDir(), ONBOARDING_SIDECAR_FILENAME);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Persist the pre-chat onboarding context to the sidecar file. Called
|
|
104
|
+
* once from the first-message path in `handleSendMessage`. Never throws
|
|
105
|
+
* — a failed write degrades to "no onboarding facts on the Home page",
|
|
106
|
+
* which is the same state as a skipped onboarding flow.
|
|
107
|
+
*/
|
|
108
|
+
export function writeOnboardingSidecar(ctx: OnboardingContext): void {
|
|
109
|
+
try {
|
|
110
|
+
mkdirSync(getDataDir(), { recursive: true });
|
|
111
|
+
writeFileSync(
|
|
112
|
+
getOnboardingSidecarPath(),
|
|
113
|
+
JSON.stringify(ctx, null, 2),
|
|
114
|
+
"utf-8",
|
|
115
|
+
);
|
|
116
|
+
log.info(
|
|
117
|
+
{
|
|
118
|
+
path: getOnboardingSidecarPath(),
|
|
119
|
+
tools: ctx.tools.length,
|
|
120
|
+
tasks: ctx.tasks.length,
|
|
121
|
+
},
|
|
122
|
+
"Wrote onboarding-context.json sidecar",
|
|
123
|
+
);
|
|
124
|
+
} catch (err) {
|
|
125
|
+
log.warn({ err }, "Failed to write onboarding-context.json sidecar");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Read and parse the onboarding sidecar, returning null when the file
|
|
131
|
+
* is missing or unreadable. Used by `computeRelationshipState()` to
|
|
132
|
+
* inject onboarding-sourced facts alongside the inferred ones.
|
|
133
|
+
*/
|
|
134
|
+
function readOnboardingSidecar(): OnboardingContext | null {
|
|
135
|
+
try {
|
|
136
|
+
const path = getOnboardingSidecarPath();
|
|
137
|
+
if (!existsSync(path)) return null;
|
|
138
|
+
const parsed = JSON.parse(readFileSync(path, "utf-8")) as OnboardingContext;
|
|
139
|
+
if (!parsed || !Array.isArray(parsed.tools) || !Array.isArray(parsed.tasks))
|
|
140
|
+
return null;
|
|
141
|
+
return parsed;
|
|
142
|
+
} catch (err) {
|
|
143
|
+
log.warn({ err }, "Failed to read onboarding-context.json sidecar");
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Build a fresh `RelationshipState` snapshot from the current workspace.
|
|
150
|
+
* Reads USER.md / SOUL.md / IDENTITY.md, queries the oauth connection
|
|
151
|
+
* store, and counts conversations via the DB-authoritative helper.
|
|
152
|
+
*
|
|
153
|
+
* Side effect: on the very first call when IDENTITY.md cannot provide
|
|
154
|
+
* a hatched date, `resolveFallbackHatchedDate` persists a one-time
|
|
155
|
+
* `data/hatched.json` sidecar so subsequent calls return a monotonic
|
|
156
|
+
* timestamp. All other paths are read-only. Callers that want to
|
|
157
|
+
* persist the full snapshot should use `writeRelationshipState()`.
|
|
158
|
+
*/
|
|
159
|
+
export async function computeRelationshipState(): Promise<RelationshipState> {
|
|
160
|
+
// Persona source-of-truth:
|
|
161
|
+
// 1. The guardian contact's per-user file (`users/<slug>.md`), resolved
|
|
162
|
+
// via `resolveGuardianPersonaPath()` — this is the canonical location
|
|
163
|
+
// after workspace migration 031 and handles slugged userFiles like
|
|
164
|
+
// `users/alice.md` that were invisible to a hardcoded `default.md`
|
|
165
|
+
// lookup.
|
|
166
|
+
// 2. Legacy workspace-root `USER.md` as a last-ditch fallback for very
|
|
167
|
+
// old workspaces that never ran migration 031.
|
|
168
|
+
// 3. Empty string → extraction yields [] and `userName` is undefined.
|
|
169
|
+
// Every step is guarded because the writer must never throw.
|
|
170
|
+
const userMd = resolveGuardianUserContent();
|
|
171
|
+
const soulMd = safeRead(getWorkspacePromptPath("SOUL.md"));
|
|
172
|
+
const identityPath = getWorkspacePromptPath("IDENTITY.md");
|
|
173
|
+
const onboarding = readOnboardingSidecar();
|
|
174
|
+
|
|
175
|
+
const facts = extractFacts({
|
|
176
|
+
userContent: userMd,
|
|
177
|
+
soulContent: soulMd,
|
|
178
|
+
onboarding,
|
|
179
|
+
});
|
|
180
|
+
const conversationCount = countConversations();
|
|
181
|
+
const capabilities = resolveCapabilityTiers({ conversationCount });
|
|
182
|
+
const { assistantName: identityName, hatchedDate } =
|
|
183
|
+
parseIdentity(identityPath);
|
|
184
|
+
const parsedUserName = parseUserName(userMd);
|
|
185
|
+
|
|
186
|
+
// Fall back to onboarding sidecar values when IDENTITY.md / USER.md
|
|
187
|
+
// haven't yielded anything yet. On a brand-new workspace the sidecar
|
|
188
|
+
// is often the only source of these names until the daemon parses the
|
|
189
|
+
// markdown files on a subsequent turn.
|
|
190
|
+
const sidecarAssistantName = onboarding?.assistantName?.trim();
|
|
191
|
+
const assistantName =
|
|
192
|
+
identityName !== DEFAULT_ASSISTANT_NAME || !sidecarAssistantName
|
|
193
|
+
? identityName
|
|
194
|
+
: sidecarAssistantName;
|
|
195
|
+
const userName =
|
|
196
|
+
parsedUserName ?? (onboarding?.userName?.trim() || undefined);
|
|
197
|
+
|
|
198
|
+
const tier = computeTier({ facts, capabilities, conversationCount });
|
|
199
|
+
const progressPercent = computeProgressPercent({
|
|
200
|
+
facts,
|
|
201
|
+
capabilities,
|
|
202
|
+
conversationCount,
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
version: RELATIONSHIP_STATE_VERSION,
|
|
207
|
+
assistantId: DEFAULT_ASSISTANT_ID,
|
|
208
|
+
tier,
|
|
209
|
+
progressPercent,
|
|
210
|
+
facts,
|
|
211
|
+
capabilities,
|
|
212
|
+
conversationCount,
|
|
213
|
+
hatchedDate,
|
|
214
|
+
assistantName,
|
|
215
|
+
userName,
|
|
216
|
+
updatedAt: new Date().toISOString(),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* In-module serialization primitive for `writeRelationshipState`.
|
|
222
|
+
*
|
|
223
|
+
* Multiple conversations can finish a turn simultaneously, each firing
|
|
224
|
+
* `void writeRelationshipState()` from `conversation-agent-loop`.
|
|
225
|
+
* Without coalescing, two compute+write cycles can interleave
|
|
226
|
+
* (compute A → compute B → writeSync A → writeSync B), so the
|
|
227
|
+
* persisted snapshot reflects an older state than the last turn and
|
|
228
|
+
* two SSE events fire that don't match the final on-disk content.
|
|
229
|
+
*
|
|
230
|
+
* We use a "latest wins" pattern:
|
|
231
|
+
* - If no write is in flight, start one.
|
|
232
|
+
* - If a write is in flight, mark dirty and return the in-flight
|
|
233
|
+
* promise. Overlapping callers all resolve off the same tail.
|
|
234
|
+
* - When the in-flight write finishes, if dirty, run again.
|
|
235
|
+
*
|
|
236
|
+
* Guarantees:
|
|
237
|
+
* - At most one compute+write runs at a time.
|
|
238
|
+
* - N overlapping callers during one write produce exactly one
|
|
239
|
+
* tail write, not N.
|
|
240
|
+
* - The final on-disk state always reflects the latest completed
|
|
241
|
+
* compute.
|
|
242
|
+
* - No unbounded queue.
|
|
243
|
+
*/
|
|
244
|
+
let writeInFlight: Promise<void> | null = null;
|
|
245
|
+
let writeDirty = false;
|
|
246
|
+
|
|
247
|
+
async function runWriteRelationshipState(): Promise<void> {
|
|
248
|
+
let writtenState: RelationshipState | undefined;
|
|
249
|
+
try {
|
|
250
|
+
const state = await computeRelationshipState();
|
|
251
|
+
const path = getRelationshipStatePath();
|
|
252
|
+
mkdirSync(getDataDir(), { recursive: true });
|
|
253
|
+
writeFileSync(path, JSON.stringify(state, null, 2), "utf8");
|
|
254
|
+
// Only mark the state as "written" AFTER the sync write has
|
|
255
|
+
// succeeded — any throw from `writeFileSync` short-circuits the
|
|
256
|
+
// SSE emit below so subscribers never see a stale update event
|
|
257
|
+
// that contradicts on-disk state.
|
|
258
|
+
writtenState = state;
|
|
259
|
+
log.info(
|
|
260
|
+
{
|
|
261
|
+
path,
|
|
262
|
+
tier: state.tier,
|
|
263
|
+
progress: state.progressPercent,
|
|
264
|
+
facts: state.facts.length,
|
|
265
|
+
},
|
|
266
|
+
"Wrote relationship-state.json",
|
|
267
|
+
);
|
|
268
|
+
} catch (err) {
|
|
269
|
+
log.warn({ err }, "Failed to write relationship-state.json");
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// SSE fanout lives outside the try/catch so a publish failure does
|
|
273
|
+
// not get mis-logged as a write failure. Still guarded against the
|
|
274
|
+
// publish throwing (e.g. a subscriber rejects) — the writer promise
|
|
275
|
+
// must never reject from this path.
|
|
276
|
+
if (writtenState) {
|
|
277
|
+
publishRelationshipStateUpdated(writtenState.updatedAt);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Compute a fresh snapshot and persist it to `getRelationshipStatePath()`.
|
|
283
|
+
*
|
|
284
|
+
* Never throws — all errors are caught and logged as warnings. Fire-and-
|
|
285
|
+
* forget callers (e.g. the conversation-complete hook) can safely call
|
|
286
|
+
* this without additional try/catch wrapping.
|
|
287
|
+
*
|
|
288
|
+
* Concurrent calls are coalesced (see `writeInFlight` above): at most
|
|
289
|
+
* one compute+write runs at a time, and overlapping calls during an
|
|
290
|
+
* in-flight write all resolve off a single tail write that reflects
|
|
291
|
+
* the latest state.
|
|
292
|
+
*/
|
|
293
|
+
export async function writeRelationshipState(): Promise<void> {
|
|
294
|
+
if (writeInFlight) {
|
|
295
|
+
writeDirty = true;
|
|
296
|
+
return writeInFlight;
|
|
297
|
+
}
|
|
298
|
+
writeInFlight = (async () => {
|
|
299
|
+
try {
|
|
300
|
+
await runWriteRelationshipState();
|
|
301
|
+
while (writeDirty) {
|
|
302
|
+
writeDirty = false;
|
|
303
|
+
await runWriteRelationshipState();
|
|
304
|
+
}
|
|
305
|
+
} finally {
|
|
306
|
+
writeInFlight = null;
|
|
307
|
+
}
|
|
308
|
+
})();
|
|
309
|
+
return writeInFlight;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Publish the `relationship_state_updated` event to the in-process
|
|
314
|
+
* assistant event hub. Called only on the success branch of
|
|
315
|
+
* `writeRelationshipState()` so the event accurately reflects what
|
|
316
|
+
* just landed on disk.
|
|
317
|
+
*/
|
|
318
|
+
function publishRelationshipStateUpdated(updatedAt: string): void {
|
|
319
|
+
assistantEventHub
|
|
320
|
+
.publish(
|
|
321
|
+
buildAssistantEvent(DAEMON_INTERNAL_ASSISTANT_ID, {
|
|
322
|
+
type: "relationship_state_updated",
|
|
323
|
+
updatedAt,
|
|
324
|
+
}),
|
|
325
|
+
)
|
|
326
|
+
.catch((err) => {
|
|
327
|
+
log.warn({ err }, "Failed to publish relationship_state_updated event");
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* One-time backfill for existing / upgraded users.
|
|
333
|
+
*
|
|
334
|
+
* On daemon startup we want existing users to land on a populated
|
|
335
|
+
* `relationship-state.json` instead of an empty Home page. This helper
|
|
336
|
+
* is idempotent: it only writes when the file is missing, so subsequent
|
|
337
|
+
* boots are a cheap `existsSync` check and nothing else. The regular
|
|
338
|
+
* conversation-complete writer path keeps the snapshot fresh after the
|
|
339
|
+
* first write, so there is no need to re-run the backfill.
|
|
340
|
+
*
|
|
341
|
+
* Callers must treat this as fire-and-forget: per `assistant/CLAUDE.md`
|
|
342
|
+
* the daemon must never block startup, so `writeRelationshipState()`
|
|
343
|
+
* already catches every error. Wrapping this call in
|
|
344
|
+
* `void backfillRelationshipStateIfMissing().catch(() => {})` at the
|
|
345
|
+
* startup site provides a second belt-and-suspenders guarantee for any
|
|
346
|
+
* unexpected throw out of `existsSync`.
|
|
347
|
+
*/
|
|
348
|
+
export async function backfillRelationshipStateIfMissing(): Promise<void> {
|
|
349
|
+
const path = getRelationshipStatePath();
|
|
350
|
+
if (existsSync(path)) return; // idempotent — only runs once
|
|
351
|
+
log.info("Backfilling relationship-state.json for existing or upgraded user");
|
|
352
|
+
await writeRelationshipState();
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// ─── Internal helpers ───────────────────────────────────────────────────
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Resolve the raw markdown content of the guardian's user persona file
|
|
359
|
+
* (`users/<slug>.md`). Walks a three-step fallback chain so a transient
|
|
360
|
+
* contact-store failure on a migrated workspace still surfaces real
|
|
361
|
+
* user content:
|
|
362
|
+
*
|
|
363
|
+
* 1. `resolveGuardianPersonaPath()` via contact-store — the canonical
|
|
364
|
+
* per-guardian slugged file (e.g. `users/alice.md`).
|
|
365
|
+
* 2. `users/default.md` — the default-guardian persona file that the
|
|
366
|
+
* workspace migration leaves in place. Catches the window where
|
|
367
|
+
* the resolver throws or returns null but the file-backed content
|
|
368
|
+
* is still available.
|
|
369
|
+
* 3. Workspace-root `USER.md` — legacy fallback for very old
|
|
370
|
+
* workspaces that predate migration 031.
|
|
371
|
+
*
|
|
372
|
+
* Every step is guarded; an empty string is returned only when all
|
|
373
|
+
* three sources are unavailable, so `computeRelationshipState()` never
|
|
374
|
+
* throws from this path.
|
|
375
|
+
*/
|
|
376
|
+
function resolveGuardianUserContent(): string {
|
|
377
|
+
try {
|
|
378
|
+
const guardianPath = resolveGuardianPersonaPath();
|
|
379
|
+
if (guardianPath) {
|
|
380
|
+
const content = safeRead(guardianPath);
|
|
381
|
+
if (content) return content;
|
|
382
|
+
}
|
|
383
|
+
} catch (err) {
|
|
384
|
+
log.warn(
|
|
385
|
+
{ err },
|
|
386
|
+
"Failed to resolve guardian persona path; trying users/default.md",
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Intermediate fallback: the default-guardian persona file that
|
|
391
|
+
// exists on most migrated workspaces even when the contact store is
|
|
392
|
+
// transiently unreachable.
|
|
393
|
+
try {
|
|
394
|
+
const defaultUserPath = join(getWorkspaceDir(), "users", "default.md");
|
|
395
|
+
const defaultContent = safeRead(defaultUserPath);
|
|
396
|
+
if (defaultContent) return defaultContent;
|
|
397
|
+
} catch (err) {
|
|
398
|
+
log.warn({ err }, "Failed to read users/default.md; trying legacy USER.md");
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Legacy fallback: workspace-root USER.md for very old workspaces
|
|
402
|
+
// that predate migration 031.
|
|
403
|
+
const legacyPath = getWorkspacePromptPath("USER.md");
|
|
404
|
+
const legacy = safeRead(legacyPath);
|
|
405
|
+
if (legacy) return legacy;
|
|
406
|
+
|
|
407
|
+
return "";
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Read a file as UTF-8, returning "" on any error.
|
|
412
|
+
*
|
|
413
|
+
* Used for every disk read in this module so a missing or unreadable
|
|
414
|
+
* workspace file degrades gracefully to an empty content string rather
|
|
415
|
+
* than propagating an exception out of a startup path.
|
|
416
|
+
*/
|
|
417
|
+
function safeRead(path: string): string {
|
|
418
|
+
try {
|
|
419
|
+
if (!existsSync(path)) return "";
|
|
420
|
+
return readFileSync(path, "utf-8");
|
|
421
|
+
} catch {
|
|
422
|
+
return "";
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Walk the workspace prompt files and emit a flat list of inferred
|
|
428
|
+
* facts. This is deliberately a simple bullet/heading parser — the TDD
|
|
429
|
+
* explicitly calls out "don't try to be clever" here; the goal is to
|
|
430
|
+
* produce something non-empty for the UI so progress looks alive.
|
|
431
|
+
*
|
|
432
|
+
* Voice facts come from SOUL.md. World and priorities facts come from
|
|
433
|
+
* the guardian's `users/<slug>.md` persona file (resolved via
|
|
434
|
+
* `persona-resolver`), with legacy workspace-root `USER.md` as a
|
|
435
|
+
* fallback for workspaces that predate migration 031.
|
|
436
|
+
*/
|
|
437
|
+
function extractFacts(input: {
|
|
438
|
+
userContent: string;
|
|
439
|
+
soulContent: string;
|
|
440
|
+
onboarding?: OnboardingContext | null;
|
|
441
|
+
}): Fact[] {
|
|
442
|
+
const facts: Fact[] = [];
|
|
443
|
+
let counter = 0;
|
|
444
|
+
const nextId = (prefix: string): string => {
|
|
445
|
+
counter += 1;
|
|
446
|
+
return `${prefix}-${counter}`;
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
// Onboarding-sourced facts come first so they render at the top of
|
|
450
|
+
// the Home page chip list until enough inferred facts accumulate to
|
|
451
|
+
// displace them. Each tool/task/tone line the user picked becomes a
|
|
452
|
+
// dashed-border chip tagged `source: "onboarding"`.
|
|
453
|
+
if (input.onboarding) {
|
|
454
|
+
for (const tool of input.onboarding.tools) {
|
|
455
|
+
const text = tool.trim();
|
|
456
|
+
if (!text) continue;
|
|
457
|
+
facts.push({
|
|
458
|
+
id: nextId("onboarding"),
|
|
459
|
+
category: "world",
|
|
460
|
+
text,
|
|
461
|
+
confidence: "strong",
|
|
462
|
+
source: "onboarding",
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
for (const task of input.onboarding.tasks) {
|
|
466
|
+
const text = task.trim();
|
|
467
|
+
if (!text) continue;
|
|
468
|
+
facts.push({
|
|
469
|
+
id: nextId("onboarding"),
|
|
470
|
+
category: "priorities",
|
|
471
|
+
text,
|
|
472
|
+
confidence: "strong",
|
|
473
|
+
source: "onboarding",
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
const tone = input.onboarding.tone?.trim();
|
|
477
|
+
if (tone) {
|
|
478
|
+
facts.push({
|
|
479
|
+
id: nextId("onboarding"),
|
|
480
|
+
category: "voice",
|
|
481
|
+
text: tone,
|
|
482
|
+
confidence: "strong",
|
|
483
|
+
source: "onboarding",
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Heuristic keyword map for USER.md sections -> fact category. Keys
|
|
489
|
+
// are matched case-insensitively as a prefix of the heading/bullet
|
|
490
|
+
// label. Everything that doesn't match stays a "world" fact.
|
|
491
|
+
const priorityKeywords = [
|
|
492
|
+
"goals",
|
|
493
|
+
"priority",
|
|
494
|
+
"priorities",
|
|
495
|
+
"focus",
|
|
496
|
+
"work role",
|
|
497
|
+
"role",
|
|
498
|
+
"projects",
|
|
499
|
+
"daily tools",
|
|
500
|
+
"tools",
|
|
501
|
+
];
|
|
502
|
+
|
|
503
|
+
for (const line of iterateBulletLines(input.userContent)) {
|
|
504
|
+
const parsed = parseBulletLabelValue(line);
|
|
505
|
+
if (!parsed) continue;
|
|
506
|
+
const { label, value } = parsed;
|
|
507
|
+
if (!value) continue;
|
|
508
|
+
const lower = label.toLowerCase();
|
|
509
|
+
const isPriority = priorityKeywords.some((k) => lower.startsWith(k));
|
|
510
|
+
const category: Fact["category"] = isPriority ? "priorities" : "world";
|
|
511
|
+
facts.push({
|
|
512
|
+
id: nextId("user"),
|
|
513
|
+
category,
|
|
514
|
+
text: `${capitalizeLabel(label)}: ${value}`,
|
|
515
|
+
confidence: "strong",
|
|
516
|
+
source: "inferred",
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
for (const line of iterateBulletLines(input.soulContent)) {
|
|
521
|
+
const parsed = parseBulletLabelValue(line);
|
|
522
|
+
if (!parsed) continue;
|
|
523
|
+
const { label, value } = parsed;
|
|
524
|
+
if (!value) continue;
|
|
525
|
+
facts.push({
|
|
526
|
+
id: nextId("soul"),
|
|
527
|
+
category: "voice",
|
|
528
|
+
text: `${capitalizeLabel(label)}: ${value}`,
|
|
529
|
+
confidence: "strong",
|
|
530
|
+
source: "inferred",
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
return facts;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Yield non-empty bullet lines from a markdown string, skipping comment
|
|
539
|
+
* lines (leading `_`) and indented continuation. Lines returned are the
|
|
540
|
+
* trimmed bullet body, without the leading `-` or `*`.
|
|
541
|
+
*/
|
|
542
|
+
function* iterateBulletLines(content: string): Generator<string> {
|
|
543
|
+
if (!content) return;
|
|
544
|
+
for (const raw of content.split("\n")) {
|
|
545
|
+
const line = raw.trim();
|
|
546
|
+
if (!line) continue;
|
|
547
|
+
if (line.startsWith("_")) continue;
|
|
548
|
+
if (!line.startsWith("- ") && !line.startsWith("* ")) continue;
|
|
549
|
+
const body = line.slice(2).trim();
|
|
550
|
+
if (body.length === 0) continue;
|
|
551
|
+
yield body;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Parse a bullet body of the form `**Label:** value` or `Label: value`
|
|
557
|
+
* into its label and value halves. Returns null when no colon is found.
|
|
558
|
+
*/
|
|
559
|
+
function parseBulletLabelValue(
|
|
560
|
+
body: string,
|
|
561
|
+
): { label: string; value: string } | null {
|
|
562
|
+
const stripped = body.replace(/\*\*/g, "").replace(/__/g, "");
|
|
563
|
+
const idx = stripped.indexOf(":");
|
|
564
|
+
if (idx <= 0) return null;
|
|
565
|
+
const label = stripped.slice(0, idx).trim();
|
|
566
|
+
const value = stripped.slice(idx + 1).trim();
|
|
567
|
+
if (!label) return null;
|
|
568
|
+
return { label, value };
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Lowercase-ify a label but keep the first character uppercased for
|
|
573
|
+
* display: "PREFERRED Name" -> "Preferred name".
|
|
574
|
+
*/
|
|
575
|
+
function capitalizeLabel(label: string): string {
|
|
576
|
+
const trimmed = label.trim();
|
|
577
|
+
if (!trimmed) return trimmed;
|
|
578
|
+
return trimmed.charAt(0).toUpperCase() + trimmed.slice(1).toLowerCase();
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Project `DEFAULT_CAPABILITIES` into a concrete capability list by
|
|
583
|
+
* consulting the OAuth connection store for integration-gated tiers
|
|
584
|
+
* and the conversation count for usage-gated tiers.
|
|
585
|
+
*
|
|
586
|
+
* Failures in the oauth lookup fall back to the "empty set" — every
|
|
587
|
+
* integration appears as `next-up` — so startup paths never throw.
|
|
588
|
+
*/
|
|
589
|
+
function resolveCapabilityTiers(opts: {
|
|
590
|
+
conversationCount: number;
|
|
591
|
+
}): Capability[] {
|
|
592
|
+
const connectedProviders = resolveConnectedProviders();
|
|
593
|
+
|
|
594
|
+
return DEFAULT_CAPABILITIES.map((cap) => {
|
|
595
|
+
switch (cap.id) {
|
|
596
|
+
case "email": {
|
|
597
|
+
// Only Gmail is a real email integration today. Outlook appears in
|
|
598
|
+
// seed-providers.ts as scaffolding but we don't actually ship a
|
|
599
|
+
// Microsoft integration, so we do not advertise email unlock for it.
|
|
600
|
+
const unlocked =
|
|
601
|
+
connectedProviders.has("google") || connectedProviders.has("gmail");
|
|
602
|
+
return { ...cap, tier: unlocked ? "unlocked" : "next-up" };
|
|
603
|
+
}
|
|
604
|
+
case "calendar": {
|
|
605
|
+
// Only Google Calendar is a real calendar integration today.
|
|
606
|
+
const unlocked =
|
|
607
|
+
connectedProviders.has("google") ||
|
|
608
|
+
connectedProviders.has("google-calendar");
|
|
609
|
+
return { ...cap, tier: unlocked ? "unlocked" : "next-up" };
|
|
610
|
+
}
|
|
611
|
+
case "slack": {
|
|
612
|
+
const unlocked = connectedProviders.has("slack");
|
|
613
|
+
return { ...cap, tier: unlocked ? "unlocked" : "next-up" };
|
|
614
|
+
}
|
|
615
|
+
case "voice-writing": {
|
|
616
|
+
const unlocked =
|
|
617
|
+
opts.conversationCount >= VOICE_WRITING_UNLOCK_CONVERSATIONS;
|
|
618
|
+
return { ...cap, tier: unlocked ? "unlocked" : "earned" };
|
|
619
|
+
}
|
|
620
|
+
case "proactive":
|
|
621
|
+
case "autonomous":
|
|
622
|
+
default:
|
|
623
|
+
return { ...cap, tier: "earned" };
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Return the set of provider keys with at least one `active` OAuth
|
|
630
|
+
* connection. Any failure (DB not initialized, schema drift, etc.)
|
|
631
|
+
* returns an empty set so the writer keeps advancing with sane
|
|
632
|
+
* defaults.
|
|
633
|
+
*/
|
|
634
|
+
function resolveConnectedProviders(): Set<string> {
|
|
635
|
+
try {
|
|
636
|
+
const rows = listConnections();
|
|
637
|
+
const set = new Set<string>();
|
|
638
|
+
for (const row of rows) {
|
|
639
|
+
if (row.status === "active") set.add(row.provider);
|
|
640
|
+
}
|
|
641
|
+
return set;
|
|
642
|
+
} catch (err) {
|
|
643
|
+
log.warn(
|
|
644
|
+
{ err },
|
|
645
|
+
"Failed to list OAuth connections; assuming no integrations connected",
|
|
646
|
+
);
|
|
647
|
+
return new Set<string>();
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Count conversations using the DB-authoritative helper from
|
|
653
|
+
* `conversation-queries`. This matches `listConversations()` used by
|
|
654
|
+
* the UI — it filters out `background`, `private`, and `scheduled`
|
|
655
|
+
* conversation types — and is immune to stray filesystem entries like
|
|
656
|
+
* `.DS_Store` or double-counts from workspace migration 009 where
|
|
657
|
+
* legacy + canonical directory forms temporarily co-exist.
|
|
658
|
+
*
|
|
659
|
+
* Returns 0 on any failure (DB not initialized, schema drift, etc.)
|
|
660
|
+
* so the writer still produces a valid snapshot — per module contract
|
|
661
|
+
* this path must never throw.
|
|
662
|
+
*/
|
|
663
|
+
function countConversations(): number {
|
|
664
|
+
try {
|
|
665
|
+
return countConversationsDb();
|
|
666
|
+
} catch (err) {
|
|
667
|
+
log.warn({ err }, "Failed to count conversations from DB; defaulting to 0");
|
|
668
|
+
return 0;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Filename for the hatched-date sidecar, used as a stable fallback
|
|
674
|
+
* when IDENTITY.md is missing / unreadable / has no explicit hatched
|
|
675
|
+
* bullet and file stat is unavailable. Lives under the workspace
|
|
676
|
+
* data dir alongside `relationship-state.json`.
|
|
677
|
+
*/
|
|
678
|
+
const HATCHED_SIDECAR_FILENAME = "hatched.json";
|
|
679
|
+
|
|
680
|
+
function getHatchedSidecarPath(): string {
|
|
681
|
+
return join(getDataDir(), HATCHED_SIDECAR_FILENAME);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Resolve a stable hatched-date fallback timestamp.
|
|
686
|
+
*
|
|
687
|
+
* The Swift client, OpenAPI schema, and UI have no special handling
|
|
688
|
+
* for a Unix-epoch sentinel — they'll render "1/1/1970" to the user.
|
|
689
|
+
* Instead, we use `new Date().toISOString()` the first time a
|
|
690
|
+
* fallback is needed and persist it to a small sidecar file
|
|
691
|
+
* (`data/hatched.json`). Subsequent calls read the sidecar first, so
|
|
692
|
+
* the returned timestamp is monotonic across writes and the
|
|
693
|
+
* `hatchedDate` field never drifts once initialized.
|
|
694
|
+
*
|
|
695
|
+
* Never throws — a sidecar read/write failure still yields a valid
|
|
696
|
+
* (though non-stable) `now` timestamp, which is still far better than
|
|
697
|
+
* the epoch sentinel.
|
|
698
|
+
*/
|
|
699
|
+
function resolveFallbackHatchedDate(): string {
|
|
700
|
+
const path = getHatchedSidecarPath();
|
|
701
|
+
try {
|
|
702
|
+
if (existsSync(path)) {
|
|
703
|
+
const parsed = JSON.parse(readFileSync(path, "utf-8")) as {
|
|
704
|
+
hatchedAt?: string;
|
|
705
|
+
};
|
|
706
|
+
if (parsed.hatchedAt && !isNaN(Date.parse(parsed.hatchedAt))) {
|
|
707
|
+
return parsed.hatchedAt;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
} catch {
|
|
711
|
+
// Fall through to write a fresh sidecar.
|
|
712
|
+
}
|
|
713
|
+
const now = new Date().toISOString();
|
|
714
|
+
try {
|
|
715
|
+
mkdirSync(getDataDir(), { recursive: true });
|
|
716
|
+
writeFileSync(path, JSON.stringify({ hatchedAt: now }, null, 2), "utf-8");
|
|
717
|
+
} catch {
|
|
718
|
+
// If even the sidecar write fails, return `now` anyway — the
|
|
719
|
+
// caller will just get a fresh-looking date on every call. Not
|
|
720
|
+
// ideal, but far better than the epoch sentinel.
|
|
721
|
+
}
|
|
722
|
+
return now;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Pull `assistantName` and `hatchedDate` from IDENTITY.md.
|
|
727
|
+
*
|
|
728
|
+
* IDENTITY.md is a freeform markdown file, so for the name we scan
|
|
729
|
+
* bullet lines for any recognizable `name` label (`Name`,
|
|
730
|
+
* `Assistant Name`, `Preferred Name`, etc.). For the hatched date we
|
|
731
|
+
* prefer any explicit `hatched:` / `birth:` bullet, then fall back to
|
|
732
|
+
* the file's `stat.birthtime` (matching the pattern already
|
|
733
|
+
* established by `identity-routes.ts`), and finally to `stat.mtime`
|
|
734
|
+
* if birthtime is unavailable. We never fall back to `new Date()`
|
|
735
|
+
* directly — `writeRelationshipState()` is called on every turn
|
|
736
|
+
* boundary, so a raw `Date.now()` fallback would cause `hatchedDate`
|
|
737
|
+
* to drift forward on every write. Instead, when nothing else is
|
|
738
|
+
* readable we resolve via `resolveFallbackHatchedDate()` which
|
|
739
|
+
* persists a stable timestamp to a sidecar file on first use.
|
|
740
|
+
*/
|
|
741
|
+
function parseIdentity(identityPath: string): {
|
|
742
|
+
assistantName: string;
|
|
743
|
+
hatchedDate: string;
|
|
744
|
+
} {
|
|
745
|
+
const content = safeRead(identityPath);
|
|
746
|
+
|
|
747
|
+
let assistantName = DEFAULT_ASSISTANT_NAME;
|
|
748
|
+
let explicitHatched: string | undefined;
|
|
749
|
+
|
|
750
|
+
for (const line of iterateBulletLines(content)) {
|
|
751
|
+
const parsed = parseBulletLabelValue(line);
|
|
752
|
+
if (!parsed || !parsed.value) continue;
|
|
753
|
+
const lower = parsed.label.toLowerCase();
|
|
754
|
+
// Accept any label whose lowercased form looks like a "name"
|
|
755
|
+
// label: `Name`, `Assistant Name`, `Preferred Name`, etc.
|
|
756
|
+
// Preserves the "first match wins" precedence so a raw `Name`
|
|
757
|
+
// bullet still takes precedence over later aliases.
|
|
758
|
+
if (
|
|
759
|
+
assistantName === DEFAULT_ASSISTANT_NAME &&
|
|
760
|
+
(lower === "name" ||
|
|
761
|
+
lower === "assistant name" ||
|
|
762
|
+
lower === "preferred name" ||
|
|
763
|
+
lower.startsWith("name"))
|
|
764
|
+
) {
|
|
765
|
+
assistantName = parsed.value;
|
|
766
|
+
}
|
|
767
|
+
if (
|
|
768
|
+
!explicitHatched &&
|
|
769
|
+
(lower.startsWith("hatched") || lower.startsWith("birth"))
|
|
770
|
+
) {
|
|
771
|
+
const parsedDate = new Date(parsed.value);
|
|
772
|
+
if (!isNaN(parsedDate.getTime())) {
|
|
773
|
+
explicitHatched = parsedDate.toISOString();
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
if (explicitHatched) {
|
|
779
|
+
return { assistantName, hatchedDate: explicitHatched };
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// Stable fallback: use the IDENTITY.md file birth time so the
|
|
783
|
+
// relationship start date is monotonic across turns. Matches the
|
|
784
|
+
// approach used by `identity-routes.ts` for the Settings UI.
|
|
785
|
+
try {
|
|
786
|
+
const stats = statSync(identityPath);
|
|
787
|
+
const candidate =
|
|
788
|
+
stats.birthtime.getTime() > 0 ? stats.birthtime : stats.mtime;
|
|
789
|
+
if (candidate.getTime() > 0) {
|
|
790
|
+
return { assistantName, hatchedDate: candidate.toISOString() };
|
|
791
|
+
}
|
|
792
|
+
} catch {
|
|
793
|
+
// File missing or unreadable — fall through to the sidecar.
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// Last-ditch fallback: `resolveFallbackHatchedDate` returns a stable,
|
|
797
|
+
// real timestamp (persisted to `data/hatched.json` on first call) so
|
|
798
|
+
// the wire contract always carries a valid ISO date.
|
|
799
|
+
return { assistantName, hatchedDate: resolveFallbackHatchedDate() };
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* Best-effort user-name extraction from USER.md (or its successor
|
|
804
|
+
* `users/<slug>.md`). Returns undefined when no `name`/`preferred` line
|
|
805
|
+
* is present so the caller can leave `userName` off the wire.
|
|
806
|
+
*/
|
|
807
|
+
function parseUserName(content: string): string | undefined {
|
|
808
|
+
if (!content) return undefined;
|
|
809
|
+
for (const line of iterateBulletLines(content)) {
|
|
810
|
+
const parsed = parseBulletLabelValue(line);
|
|
811
|
+
if (!parsed) continue;
|
|
812
|
+
const lower = parsed.label.toLowerCase();
|
|
813
|
+
if (
|
|
814
|
+
(lower === "user" ||
|
|
815
|
+
lower === "user name" ||
|
|
816
|
+
lower.startsWith("preferred name") ||
|
|
817
|
+
lower.startsWith("name")) &&
|
|
818
|
+
parsed.value
|
|
819
|
+
) {
|
|
820
|
+
return parsed.value;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
return undefined;
|
|
824
|
+
}
|