@vellumai/assistant 0.7.1 → 0.7.3
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/ARCHITECTURE.md +48 -50
- package/Dockerfile +1 -0
- package/README.md +1 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
- package/bun.lock +26 -26
- package/docs/architecture/memory.md +5 -2
- package/docs/architecture/security.md +20 -0
- package/docs/plugins.md +7 -9
- package/knip.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +52 -5
- package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
- package/node_modules/@vellumai/service-contracts/package.json +2 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
- package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
- package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
- package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
- package/node_modules/@vellumai/twilio-client/package.json +18 -0
- package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
- package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
- package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
- package/openapi.yaml +1020 -40
- package/package.json +6 -3
- package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
- package/src/__tests__/app-bundler.test.ts +170 -1
- package/src/__tests__/app-control-flow.test.ts +384 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
- package/src/__tests__/app-executors.test.ts +30 -43
- package/src/__tests__/approval-routes-http.test.ts +23 -6
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
- package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
- package/src/__tests__/assistant-event-hub.test.ts +157 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -7
- package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
- package/src/__tests__/background-shell-host-bash.test.ts +14 -15
- package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
- package/src/__tests__/btw-routes.test.ts +13 -4
- package/src/__tests__/call-controller.test.ts +49 -1
- package/src/__tests__/call-conversation-messages.test.ts +8 -2
- package/src/__tests__/call-domain.test.ts +0 -2
- package/src/__tests__/call-routes-http.test.ts +0 -2
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
- package/src/__tests__/channel-readiness-service.test.ts +62 -2
- package/src/__tests__/checker.test.ts +3 -4
- package/src/__tests__/config-loader-backfill.test.ts +461 -147
- package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
- package/src/__tests__/config-schema-cmd.test.ts +0 -1
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/config-set-platform-guard.test.ts +48 -4
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +20 -11
- package/src/__tests__/config-watcher.test.ts +142 -71
- package/src/__tests__/context-search-agent-runner.test.ts +61 -3
- package/src/__tests__/context-search-conversations-source.test.ts +0 -24
- package/src/__tests__/context-search-fanout.test.ts +0 -1
- package/src/__tests__/context-search-memory-source.test.ts +3 -7
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +0 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
- package/src/__tests__/conversation-agent-loop.test.ts +454 -5
- package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
- package/src/__tests__/conversation-error.test.ts +150 -3
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-lifecycle.test.ts +36 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
- package/src/__tests__/conversation-process-callsite.test.ts +43 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
- package/src/__tests__/conversation-slash-commands.test.ts +0 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-store.test.ts +0 -18
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +328 -0
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
- package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
- package/src/__tests__/credentials-cli.test.ts +12 -12
- package/src/__tests__/cu-unified-flow.test.ts +351 -23
- package/src/__tests__/daemon-credential-client.test.ts +101 -19
- package/src/__tests__/date-context.test.ts +164 -2
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/disk-pressure-guard.test.ts +262 -0
- package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
- package/src/__tests__/disk-pressure-policy.test.ts +241 -0
- package/src/__tests__/disk-pressure-routes.test.ts +379 -0
- package/src/__tests__/disk-pressure-tools.test.ts +277 -0
- package/src/__tests__/disk-usage.test.ts +150 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/events-client-registration.test.ts +52 -0
- package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
- package/src/__tests__/file-write-tool.test.ts +4 -10
- package/src/__tests__/filing-service.test.ts +3 -4
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
- package/src/__tests__/heartbeat-service.test.ts +968 -2
- package/src/__tests__/helpers/call-route-handler.ts +7 -1
- package/src/__tests__/host-app-control-proxy.test.ts +772 -0
- package/src/__tests__/host-app-control-routes.test.ts +263 -0
- package/src/__tests__/host-bash-proxy.test.ts +439 -47
- package/src/__tests__/host-bash-routes.test.ts +459 -0
- package/src/__tests__/host-browser-proxy.test.ts +24 -22
- package/src/__tests__/host-browser-routes.test.ts +39 -13
- package/src/__tests__/host-cu-proxy.test.ts +248 -52
- package/src/__tests__/host-cu-routes-targeted.test.ts +429 -0
- package/src/__tests__/host-file-edit-tool.test.ts +47 -1
- package/src/__tests__/host-file-proxy-targeted.test.ts +378 -0
- package/src/__tests__/host-file-proxy.test.ts +301 -45
- package/src/__tests__/host-file-read-tool.test.ts +17 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +420 -0
- package/src/__tests__/host-file-write-tool.test.ts +42 -1
- package/src/__tests__/host-proxy-base.test.ts +312 -0
- package/src/__tests__/host-shell-tool.test.ts +22 -4
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +932 -0
- package/src/__tests__/host-transfer-proxy.test.ts +121 -22
- package/src/__tests__/host-transfer-routes-targeted.test.ts +662 -0
- package/src/__tests__/http-user-message-parity.test.ts +108 -1
- package/src/__tests__/identity-intro-cache.test.ts +29 -0
- package/src/__tests__/identity-routes.test.ts +103 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
- package/src/__tests__/injector-chain.test.ts +18 -6
- package/src/__tests__/injector-disk-pressure.test.ts +224 -0
- package/src/__tests__/inline-command-runner.test.ts +0 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
- package/src/__tests__/integration-status.test.ts +85 -5
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
- package/src/__tests__/managed-profile-guard.test.ts +18 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
- package/src/__tests__/mcp-abort-signal.test.ts +130 -0
- package/src/__tests__/mcp-auth-routes.test.ts +197 -0
- package/src/__tests__/mcp-cli.test.ts +338 -2
- package/src/__tests__/memory-admin-recall.test.ts +3 -11
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
- package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
- package/src/__tests__/migration-import-commit-http.test.ts +108 -2
- package/src/__tests__/mock-gateway-ipc.ts +1 -0
- package/src/__tests__/normalize-onboarding.test.ts +180 -0
- package/src/__tests__/oauth-cli.test.ts +0 -2
- package/src/__tests__/oauth-connect-routes.test.ts +316 -0
- package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
- package/src/__tests__/onboarding-persona-write.test.ts +308 -0
- package/src/__tests__/openai-provider.test.ts +45 -8
- package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
- package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
- package/src/__tests__/platform-callback-registration.test.ts +21 -4
- package/src/__tests__/platform.test.ts +2 -1
- package/src/__tests__/playbook-execution.test.ts +0 -43
- package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +214 -25
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
- package/src/__tests__/provider-tool-name.test.ts +23 -0
- package/src/__tests__/public-ingress-urls.test.ts +97 -0
- package/src/__tests__/relay-server.test.ts +15 -4
- package/src/__tests__/require-fresh-approval.test.ts +0 -1
- package/src/__tests__/retry-backoff.test.ts +87 -0
- package/src/__tests__/runtime-events-sse.test.ts +2 -2
- package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
- package/src/__tests__/schedule-retry.test.ts +715 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
- package/src/__tests__/skill-feature-flags.test.ts +43 -41
- package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
- package/src/__tests__/skill-load-inline-command.test.ts +0 -51
- package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
- package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
- package/src/__tests__/slack-channel-config.test.ts +9 -14
- package/src/__tests__/suggestion-routes.test.ts +46 -0
- package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/test-preload.ts +8 -0
- package/src/__tests__/tool-approval-handler.test.ts +3 -4
- package/src/__tests__/tool-audit-listener.test.ts +48 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/twilio-config.test.ts +3 -16
- package/src/__tests__/twilio-routes.test.ts +3 -5
- package/src/__tests__/twilio-validation.test.ts +93 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
- package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
- package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
- package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
- package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
- package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
- package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
- package/src/approvals/guardian-decision-primitive.ts +13 -0
- package/src/approvals/guardian-request-resolvers.ts +16 -17
- package/src/backup/__tests__/paths.test.ts +0 -22
- package/src/backup/__tests__/restore.test.ts +51 -151
- package/src/backup/paths.ts +2 -18
- package/src/backup/restore.ts +107 -231
- package/src/backup/snapshot-lock.ts +2 -27
- package/src/bundler/app-bundler.ts +51 -3
- package/src/bundler/compiler-tools.ts +3 -2
- package/src/calls/call-conversation-messages.ts +46 -10
- package/src/calls/relay-server.ts +4 -44
- package/src/calls/twilio-config.ts +2 -17
- package/src/calls/twilio-rest.ts +33 -105
- package/src/calls/twilio-routes.ts +11 -12
- package/src/channels/types.ts +8 -7
- package/src/cli/commands/__tests__/backup.test.ts +6 -277
- package/src/cli/commands/__tests__/gateway.test.ts +288 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -5
- package/src/cli/commands/backup.ts +6 -331
- package/src/cli/commands/bash.ts +35 -108
- package/src/cli/commands/clients.ts +36 -37
- package/src/cli/commands/contacts.ts +137 -25
- package/src/cli/commands/conversations.ts +2 -5
- package/src/cli/commands/credentials.ts +71 -7
- package/src/cli/commands/domain.ts +66 -15
- package/src/cli/commands/gateway.ts +183 -0
- package/src/cli/commands/keys.ts +9 -6
- package/src/cli/commands/mcp.ts +116 -156
- package/src/cli/commands/memory-v2.ts +303 -7
- package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
- package/src/cli/commands/oauth/connect.ts +127 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -4
- package/src/cli/commands/platform/__tests__/connect.test.ts +7 -3
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -3
- package/src/cli/commands/platform/__tests__/status.test.ts +116 -21
- package/src/cli/commands/platform/disconnect.ts +5 -4
- package/src/cli/commands/platform/index.ts +16 -25
- package/src/cli/commands/status.ts +57 -0
- package/src/cli/lib/daemon-credential-client.ts +110 -28
- package/src/cli/program.ts +6 -2
- package/src/config/assistant-feature-flags.ts +79 -12
- package/src/config/bundled-skills/acp/SKILL.md +6 -0
- package/src/config/bundled-skills/acp/TOOLS.json +1 -22
- package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
- package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
- package/src/config/bundled-skills/app-control/SKILL.md +75 -0
- package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
- package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
- package/src/config/bundled-skills/document/TOOLS.json +0 -8
- package/src/config/bundled-skills/followups/TOOLS.json +0 -12
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
- package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
- package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
- package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +25 -4
- package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
- package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
- package/src/config/bundled-skills/settings/SKILL.md +4 -0
- package/src/config/bundled-skills/settings/TOOLS.json +0 -12
- package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
- package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
- package/src/config/bundled-skills/subagent/SKILL.md +6 -2
- package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
- package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
- package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
- package/src/config/bundled-tool-registry.ts +21 -0
- package/src/config/env-registry.ts +0 -2
- package/src/config/env.ts +19 -20
- package/src/config/feature-flag-registry.json +47 -135
- package/src/config/loader.ts +197 -104
- package/src/config/sanitize-for-transfer.ts +2 -0
- package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +17 -9
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/calls.ts +0 -9
- package/src/config/schemas/channels.ts +0 -5
- package/src/config/schemas/heartbeat.ts +64 -1
- package/src/config/schemas/ingress.ts +10 -6
- package/src/config/schemas/llm.ts +7 -10
- package/src/config/schemas/memory-lifecycle.ts +90 -24
- package/src/config/schemas/memory-v2.ts +121 -13
- package/src/config/schemas/platform.ts +49 -3
- package/src/config/schemas/services.ts +29 -15
- package/src/config/schemas/skills.ts +0 -6
- package/src/config/seed-inference-profiles.ts +230 -33
- package/src/contacts/contact-store.ts +0 -55
- package/src/contacts/contacts-write.ts +0 -27
- package/src/context/window-manager.ts +1 -2
- package/src/credential-execution/feature-gates.ts +10 -10
- package/src/credential-execution/process-manager.ts +12 -41
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +187 -5
- package/src/daemon/assistant-attachments.ts +4 -4
- package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
- package/src/daemon/config-watcher.ts +89 -60
- package/src/daemon/conversation-agent-loop-handlers.ts +27 -3
- package/src/daemon/conversation-agent-loop.ts +202 -61
- package/src/daemon/conversation-error.ts +87 -15
- package/src/daemon/conversation-lifecycle.ts +9 -4
- package/src/daemon/conversation-process.ts +24 -11
- package/src/daemon/conversation-runtime-assembly.ts +28 -2
- package/src/daemon/conversation-store.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +305 -4
- package/src/daemon/conversation-tool-setup.ts +66 -62
- package/src/daemon/conversation.ts +38 -24
- package/src/daemon/date-context.ts +71 -22
- package/src/daemon/disk-pressure-background-gate.ts +73 -0
- package/src/daemon/disk-pressure-guard.ts +343 -0
- package/src/daemon/disk-pressure-policy.ts +163 -0
- package/src/daemon/doordash-steps.ts +1 -1
- package/src/daemon/handlers/shared.ts +4 -2
- package/src/daemon/handlers/skills.ts +3 -4
- package/src/daemon/host-app-control-proxy.ts +389 -0
- package/src/daemon/host-bash-proxy.ts +117 -82
- package/src/daemon/host-browser-proxy.ts +67 -82
- package/src/daemon/host-cu-proxy.ts +127 -86
- package/src/daemon/host-file-proxy.ts +129 -69
- package/src/daemon/host-proxy-base.ts +294 -0
- package/src/daemon/host-proxy-preactivation.ts +82 -0
- package/src/daemon/host-transfer-proxy.ts +338 -129
- package/src/daemon/lifecycle.ts +194 -145
- package/src/daemon/meet-host-supervisor.ts +4 -4
- package/src/daemon/meet-manifest-loader.ts +0 -1
- package/src/daemon/memory-v2-startup.ts +14 -4
- package/src/daemon/message-protocol.ts +6 -8
- package/src/daemon/message-types/contacts.ts +23 -1
- package/src/daemon/message-types/conversations.ts +15 -8
- package/src/daemon/message-types/disk-pressure.ts +9 -0
- package/src/daemon/message-types/host-app-control.ts +150 -0
- package/src/daemon/message-types/host-bash.ts +4 -0
- package/src/daemon/message-types/host-cu.ts +2 -0
- package/src/daemon/message-types/host-file.ts +4 -0
- package/src/daemon/message-types/host-transfer.ts +3 -0
- package/src/daemon/message-types/messages.ts +3 -0
- package/src/daemon/message-types/schedules.ts +8 -3
- package/src/daemon/message-types/skills.ts +2 -2
- package/src/daemon/process-message.ts +18 -1
- package/src/daemon/profiler-run-store.ts +5 -5
- package/src/daemon/shutdown-handlers.ts +0 -3
- package/src/daemon/tool-setup-types.ts +51 -0
- package/src/daemon/tool-side-effects.ts +1 -1
- package/src/documents/document-store.ts +85 -0
- package/src/events/tool-audit-listener.ts +2 -1
- package/src/filing/filing-service.ts +30 -5
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +24 -23
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +252 -0
- package/src/heartbeat/heartbeat-run-store.ts +249 -0
- package/src/heartbeat/heartbeat-service.ts +459 -54
- package/src/home/__tests__/post-connect-feed.test.ts +99 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
- package/src/home/__tests__/suggested-prompts.test.ts +89 -0
- package/src/home/feed-scheduler.ts +18 -0
- package/src/home/post-connect-feed.ts +68 -0
- package/src/home/relationship-state-writer.ts +17 -92
- package/src/home/suggested-prompts.ts +46 -10
- package/src/inbound/platform-callback-registration.ts +8 -15
- package/src/inbound/public-ingress-urls.ts +32 -34
- package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
- package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
- package/src/ipc/assistant-server.ts +70 -3
- package/src/ipc/cli-client.ts +32 -1
- package/src/ipc/gateway-client.ts +37 -3
- package/src/live-voice/live-voice-archive.ts +4 -4
- package/src/live-voice/live-voice-metrics.ts +10 -10
- package/src/live-voice/protocol.ts +5 -7
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
- package/src/mcp/mcp-auth-orchestrator.ts +213 -0
- package/src/mcp/mcp-auth-state.ts +133 -0
- package/src/mcp/mcp-oauth-provider.ts +19 -0
- package/src/media/image-service.ts +1 -7
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
- package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
- package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
- package/src/memory/admin.ts +5 -9
- package/src/memory/anisotropy.test.ts +247 -0
- package/src/memory/anisotropy.ts +443 -0
- package/src/memory/auto-analysis-constants.ts +17 -0
- package/src/memory/auto-analysis-guard.ts +5 -15
- package/src/memory/canonical-guardian-store.ts +7 -7
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
- package/src/memory/context-search/agent-protocol.ts +6 -6
- package/src/memory/context-search/agent-runner.ts +51 -9
- package/src/memory/context-search/sources/conversations.ts +2 -11
- package/src/memory/context-search/sources/memory-v2.ts +22 -9
- package/src/memory/context-search/sources/memory.ts +0 -1
- package/src/memory/context-search/types.ts +0 -1
- package/src/memory/conversation-crud.ts +5 -13
- package/src/memory/conversation-key-store.ts +2 -15
- package/src/memory/db-init.ts +6 -0
- package/src/memory/embedding-backend.ts +9 -21
- package/src/memory/embedding-runtime-manager.ts +119 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +81 -25
- package/src/memory/graph/conversation-graph-memory.ts +43 -78
- package/src/memory/graph/extraction.ts +1 -3
- package/src/memory/graph/graph-search.test.ts +10 -67
- package/src/memory/graph/graph-search.ts +9 -20
- package/src/memory/graph/retriever.test.ts +6 -0
- package/src/memory/graph/retriever.ts +34 -10
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/indexer.ts +54 -45
- package/src/memory/job-handlers/backfill.ts +2 -11
- package/src/memory/job-handlers/cleanup.ts +43 -0
- package/src/memory/job-handlers/embedding.ts +6 -8
- package/src/memory/job-handlers/summarization.ts +2 -7
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
- package/src/memory/jobs/embed-concept-page.ts +28 -2
- package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
- package/src/memory/jobs-store.ts +114 -22
- package/src/memory/jobs-worker.ts +193 -106
- package/src/memory/memory-v2-activation-log-store.ts +33 -15
- package/src/memory/memory-v2-concept-frequency.ts +169 -0
- package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
- package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
- package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-search.test.ts +6 -0
- package/src/memory/pkb/pkb-search.ts +7 -0
- package/src/memory/qdrant-client.ts +49 -32
- package/src/memory/rerank-local.ts +374 -0
- package/src/memory/schema/infrastructure.ts +15 -0
- package/src/memory/search/semantic.ts +13 -67
- package/src/memory/sparse-tokenize.ts +49 -0
- package/src/memory/trace-event-store.ts +1 -17
- package/src/memory/v2/__tests__/activation.test.ts +387 -344
- package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
- package/src/memory/v2/__tests__/injection.test.ts +181 -169
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
- package/src/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/memory/v2/__tests__/sim.test.ts +154 -188
- package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
- package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
- package/src/memory/v2/__tests__/static-context.test.ts +76 -2
- package/src/memory/v2/activation.ts +213 -239
- package/src/memory/v2/consolidation-job.ts +65 -17
- package/src/memory/v2/constants.ts +7 -0
- package/src/memory/v2/injection.ts +123 -103
- package/src/memory/v2/prompts/consolidation.ts +348 -92
- package/src/memory/v2/qdrant.ts +198 -1
- package/src/memory/v2/reranker.ts +177 -0
- package/src/memory/v2/sim.ts +113 -77
- package/src/memory/v2/skill-content.ts +4 -3
- package/src/memory/v2/skill-store.ts +91 -53
- package/src/memory/v2/sparse-bm25.ts +245 -0
- package/src/memory/v2/static-context.ts +28 -5
- package/src/memory/v2/types.ts +10 -10
- package/src/messaging/providers/gmail/types.ts +0 -49
- package/src/messaging/providers/slack/adapter.ts +1 -31
- package/src/messaging/providers/slack/types.ts +0 -32
- package/src/notifications/README.md +10 -10
- package/src/notifications/broadcaster.ts +1 -1
- package/src/notifications/copy-composer.ts +13 -0
- package/src/notifications/guardian-question-mode.ts +5 -5
- package/src/notifications/signal.ts +4 -0
- package/src/oauth/AGENTS.md +3 -1
- package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
- package/src/oauth/connect-orchestrator.ts +6 -0
- package/src/oauth/connection-resolver.test.ts +66 -1
- package/src/oauth/connection-resolver.ts +55 -1
- package/src/oauth/credential-token-resolver.ts +1 -3
- package/src/oauth/manual-token-connection.ts +0 -4
- package/src/oauth/oauth-connect-state.ts +77 -0
- package/src/oauth/seed-providers.ts +58 -1
- package/src/outbound-proxy/index.ts +1 -37
- package/src/outbound-proxy/logging.ts +1 -1
- package/src/outbound-proxy/policy.ts +6 -5
- package/src/outbound-proxy/router.ts +2 -1
- package/src/permissions/approval-policy.test.ts +6 -275
- package/src/permissions/approval-policy.ts +0 -51
- package/src/permissions/checker.test.ts +0 -1
- package/src/permissions/checker.ts +3 -17
- package/src/permissions/gateway-threshold-reader.ts +2 -0
- package/src/permissions/prompter.ts +34 -1
- package/src/permissions/secret-prompter.ts +6 -2
- package/src/plugins/defaults/injectors.ts +35 -2
- package/src/plugins/defaults/memory-retrieval.ts +5 -6
- package/src/plugins/types.ts +7 -0
- package/src/proactive-artifact/aux-message-injector.ts +74 -0
- package/src/proactive-artifact/decision.test.ts +226 -0
- package/src/proactive-artifact/decision.ts +165 -0
- package/src/proactive-artifact/index.ts +7 -0
- package/src/proactive-artifact/job.test.ts +867 -0
- package/src/proactive-artifact/job.ts +352 -0
- package/src/proactive-artifact/message-copy.ts +41 -0
- package/src/proactive-artifact/trigger-state.test.ts +277 -0
- package/src/proactive-artifact/trigger-state.ts +119 -0
- package/src/prompts/bootstrap-cleanup.ts +27 -0
- package/src/prompts/normalize-onboarding.ts +80 -0
- package/src/prompts/persona-resolver.ts +101 -9
- package/src/prompts/system-prompt.ts +23 -24
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/prompts/templates/SOUL.md +13 -1
- package/src/providers/__tests__/retry-callsite.test.ts +222 -1
- package/src/providers/model-intents.ts +7 -0
- package/src/providers/openrouter/client.ts +8 -0
- package/src/providers/retry.ts +50 -0
- package/src/providers/speech-to-text/provider-catalog.ts +7 -8
- package/src/providers/types.ts +1 -0
- package/src/runtime/__tests__/agent-wake.test.ts +456 -3
- package/src/runtime/agent-wake.ts +238 -100
- package/src/runtime/assistant-event-hub.ts +151 -99
- package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
- package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
- package/src/runtime/auth/middleware.ts +0 -96
- package/src/runtime/auth/route-policy.ts +32 -0
- package/src/runtime/auth/same-actor.ts +216 -0
- package/src/runtime/btw-sidechain.ts +2 -3
- package/src/runtime/channel-invite-transport.ts +2 -48
- package/src/runtime/channel-invite-transports/email.ts +1 -1
- package/src/runtime/channel-invite-transports/slack.ts +1 -1
- package/src/runtime/channel-invite-transports/telegram.ts +1 -1
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
- package/src/runtime/channel-invite-types.ts +54 -0
- package/src/runtime/channel-readiness-service.ts +32 -13
- package/src/runtime/channel-retry-sweep.ts +65 -1
- package/src/runtime/guardian-reply-router.ts +10 -0
- package/src/runtime/http-server.ts +3 -329
- package/src/runtime/http-types.ts +0 -5
- package/src/runtime/local-actor-identity.ts +52 -11
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
- package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
- package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
- package/src/runtime/migrations/migration-transport.ts +7 -7
- package/src/runtime/migrations/vbundle-builder.ts +327 -60
- package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
- package/src/runtime/migrations/vbundle-importer.ts +245 -68
- package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
- package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
- package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
- package/src/runtime/migrations/vbundle-validator.ts +114 -0
- package/src/runtime/pending-interactions.ts +43 -9
- package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
- package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -5
- package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
- package/src/runtime/routes/approval-interception-types.ts +13 -0
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
- package/src/runtime/routes/backup-routes.ts +15 -38
- package/src/runtime/routes/btw-routes.ts +14 -37
- package/src/runtime/routes/client-routes.ts +21 -2
- package/src/runtime/routes/contact-prompt-routes.ts +183 -0
- package/src/runtime/routes/contact-routes.ts +0 -25
- package/src/runtime/routes/conversation-query-routes.ts +36 -1
- package/src/runtime/routes/conversation-routes.ts +65 -39
- package/src/runtime/routes/debug-bash-routes.ts +163 -0
- package/src/runtime/routes/disk-pressure-routes.ts +121 -0
- package/src/runtime/routes/document-pdf-renderer.ts +169 -0
- package/src/runtime/routes/documents-routes.ts +32 -75
- package/src/runtime/routes/errors.ts +19 -4
- package/src/runtime/routes/events-routes.ts +38 -0
- package/src/runtime/routes/gateway-log-routes.ts +79 -0
- package/src/runtime/routes/guardian-approval-interception.ts +2 -8
- package/src/runtime/routes/heartbeat-routes.ts +103 -38
- package/src/runtime/routes/host-app-control-routes.ts +134 -0
- package/src/runtime/routes/host-bash-routes.ts +56 -6
- package/src/runtime/routes/host-browser-routes.ts +108 -13
- package/src/runtime/routes/host-cu-routes.ts +66 -9
- package/src/runtime/routes/host-file-routes.ts +54 -5
- package/src/runtime/routes/host-transfer-routes.ts +122 -19
- package/src/runtime/routes/http-adapter.ts +1 -0
- package/src/runtime/routes/identity-intro-cache.ts +30 -0
- package/src/runtime/routes/identity-routes.ts +21 -180
- package/src/runtime/routes/inbound-message-handler.ts +78 -21
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
- package/src/runtime/routes/index.ts +14 -0
- package/src/runtime/routes/mcp-auth-routes.ts +132 -0
- package/src/runtime/routes/memory-item-routes.test.ts +41 -15
- package/src/runtime/routes/memory-item-routes.ts +10 -12
- package/src/runtime/routes/memory-v2-routes.ts +474 -1
- package/src/runtime/routes/migration-routes.ts +96 -0
- package/src/runtime/routes/oauth-connect-routes.ts +153 -0
- package/src/runtime/routes/schedule-routes.ts +7 -0
- package/src/runtime/verification-outbound-actions.ts +4 -4
- package/src/runtime/verification-templates.ts +4 -7
- package/src/schedule/integration-status.ts +66 -2
- package/src/schedule/recurrence-engine.ts +4 -1
- package/src/schedule/retry-backoff.ts +18 -0
- package/src/schedule/retry-policy.ts +82 -0
- package/src/schedule/run-script.ts +37 -5
- package/src/schedule/schedule-recovery.ts +64 -0
- package/src/schedule/schedule-store.ts +106 -2
- package/src/schedule/scheduler-types.ts +25 -0
- package/src/schedule/scheduler.ts +83 -39
- package/src/security/encrypted-store.ts +2 -0
- package/src/security/oauth-callback-registry.ts +8 -0
- package/src/security/secure-keys.ts +55 -0
- package/src/sequence/analytics.ts +5 -5
- package/src/sequence/engine.ts +1 -1
- package/src/skills/catalog-files.ts +2 -8
- package/src/skills/include-graph.ts +5 -5
- package/src/skills/remote-skill-policy.ts +10 -16
- package/src/skills/skill-file-provider.ts +1 -1
- package/src/skills/skill-file-types.ts +13 -0
- package/src/skills/skillssh-audit-types.ts +28 -0
- package/src/skills/skillssh-registry.ts +8 -21
- package/src/subagent/index.ts +1 -7
- package/src/subagent/manager.ts +1 -15
- package/src/tasks/task-runner.ts +0 -1
- package/src/tasks/task-store.ts +0 -3
- package/src/telemetry/types.ts +2 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
- package/src/tools/apps/executors.ts +56 -69
- package/src/tools/background-tool-registry.ts +17 -3
- package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
- package/src/tools/browser/browser-execution.ts +2 -2
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
- package/src/tools/browser/cdp-client/factory.ts +23 -24
- package/src/tools/browser/cdp-client/index.ts +1 -14
- package/src/tools/computer-use/definitions.ts +42 -20
- package/src/tools/executor.ts +2 -0
- package/src/tools/host-filesystem/edit.test.ts +151 -0
- package/src/tools/host-filesystem/edit.ts +68 -0
- package/src/tools/host-filesystem/read.test.ts +129 -0
- package/src/tools/host-filesystem/read.ts +68 -0
- package/src/tools/host-filesystem/transfer.test.ts +127 -2
- package/src/tools/host-filesystem/transfer.ts +78 -3
- package/src/tools/host-filesystem/write.test.ts +134 -0
- package/src/tools/host-filesystem/write.ts +68 -0
- package/src/tools/host-terminal/host-shell.ts +66 -1
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/memory/register.test.ts +12 -9
- package/src/tools/memory/register.ts +1 -2
- package/src/tools/provider-tool-name.ts +28 -0
- package/src/tools/registry.ts +30 -9
- package/src/tools/schedule/create.ts +6 -0
- package/src/tools/schedule/list.ts +2 -0
- package/src/tools/schedule/update.ts +10 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
- package/src/tools/shared/filesystem/path-policy.ts +25 -1
- package/src/tools/skills/load.ts +0 -32
- package/src/tools/terminal/shell.ts +9 -1
- package/src/tools/tool-approval-handler.ts +32 -11
- package/src/tools/types.ts +28 -2
- package/src/tts/provider-catalog.ts +3 -5
- package/src/usage/pricing.ts +1 -1
- package/src/util/disk-usage.ts +138 -0
- package/src/util/platform.ts +21 -11
- package/src/util/process-liveness.ts +26 -0
- package/src/workspace/hatched-date.ts +86 -0
- package/src/workspace/heartbeat-service.ts +19 -0
- package/src/workspace/migrations/003-seed-device-id.ts +1 -1
- package/src/workspace/migrations/006-services-config.ts +8 -5
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
- package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
- package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
- package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
- package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/utils.ts +21 -0
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
- package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
- package/src/__tests__/twilio-rest.test.ts +0 -34
- package/src/backup/__tests__/backup-key.test.ts +0 -152
- package/src/backup/__tests__/backup-worker.test.ts +0 -782
- package/src/backup/__tests__/offsite-writer.test.ts +0 -641
- package/src/backup/__tests__/stream-crypt.test.ts +0 -228
- package/src/backup/backup-key.ts +0 -137
- package/src/backup/backup-worker.ts +0 -472
- package/src/backup/offsite-writer.ts +0 -222
- package/src/backup/stream-crypt.ts +0 -263
- package/src/daemon/message-types/pairing.ts +0 -58
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
- package/src/memory/v2/skill-qdrant.ts +0 -395
- package/src/outbound-proxy/config.ts +0 -20
- package/src/outbound-proxy/health.ts +0 -18
- package/src/outbound-proxy/types.ts +0 -150
- package/src/runtime/capability-tokens.ts +0 -190
- package/src/signals/bash.ts +0 -198
- package/src/signals/mcp-reload.ts +0 -18
|
@@ -12,12 +12,6 @@
|
|
|
12
12
|
* creates a socket-based CesTransport. The CES sidecar manages its own
|
|
13
13
|
* lifecycle; the process manager only manages the transport connection.
|
|
14
14
|
*
|
|
15
|
-
* Feature-flag gate: Managed sidecar mode is controlled by the
|
|
16
|
-
* `ces-managed-sidecar` feature flag (checked via the required
|
|
17
|
-
* AssistantConfig). When the flag is off, the process manager skips
|
|
18
|
-
* managed discovery even in containerized environments, ensuring
|
|
19
|
-
* rollback safety.
|
|
20
|
-
*
|
|
21
15
|
* Managed env contract:
|
|
22
16
|
* - CES_BOOTSTRAP_SOCKET — Path to the bootstrap Unix socket (shared emptyDir)
|
|
23
17
|
* - /assistant-data-ro — Assistant data mounted read-only into the CES sidecar
|
|
@@ -42,7 +36,6 @@ import {
|
|
|
42
36
|
type LocalSourceDiscoverySuccess,
|
|
43
37
|
type ManagedDiscoverySuccess,
|
|
44
38
|
} from "./executable-discovery.js";
|
|
45
|
-
import { isCesManagedSidecarEnabled } from "./feature-gates.js";
|
|
46
39
|
|
|
47
40
|
const log = getLogger("ces-process-manager");
|
|
48
41
|
|
|
@@ -71,10 +64,8 @@ export const CES_PRIVATE_DATA_DIR = "/ces-data";
|
|
|
71
64
|
|
|
72
65
|
export interface CesProcessManagerConfig {
|
|
73
66
|
/**
|
|
74
|
-
* Assistant configuration
|
|
75
|
-
*
|
|
76
|
-
* feature flag via this config. When omitted (e.g. CLI / admin
|
|
77
|
-
* callers), managed mode is allowed unconditionally.
|
|
67
|
+
* Assistant configuration.
|
|
68
|
+
* Reserved for future feature-flag checks or config-driven behavior.
|
|
78
69
|
*/
|
|
79
70
|
assistantConfig?: AssistantConfig;
|
|
80
71
|
}
|
|
@@ -88,10 +79,6 @@ export interface CesProcessManager {
|
|
|
88
79
|
* Start the CES process (local) or connect to the sidecar (managed).
|
|
89
80
|
* Returns a CesTransport ready for use with createCesClient().
|
|
90
81
|
*
|
|
91
|
-
* When the `ces-managed-sidecar` feature flag is off, managed mode
|
|
92
|
-
* is skipped even in containerized environments — the process manager
|
|
93
|
-
* falls back to local discovery.
|
|
94
|
-
*
|
|
95
82
|
* Throws if CES is unavailable.
|
|
96
83
|
*/
|
|
97
84
|
start(): Promise<CesTransport>;
|
|
@@ -118,7 +105,7 @@ export interface CesProcessManager {
|
|
|
118
105
|
// ---------------------------------------------------------------------------
|
|
119
106
|
|
|
120
107
|
export function createCesProcessManager(
|
|
121
|
-
|
|
108
|
+
_config: CesProcessManagerConfig,
|
|
122
109
|
): CesProcessManager {
|
|
123
110
|
let childProcess: Subprocess | null = null;
|
|
124
111
|
let managedSocket: Socket | null = null;
|
|
@@ -131,31 +118,15 @@ export function createCesProcessManager(
|
|
|
131
118
|
throw new Error("CES process manager is already running");
|
|
132
119
|
}
|
|
133
120
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
discoveryResult = await discoverCes();
|
|
144
|
-
if (discoveryResult.mode === "unavailable") {
|
|
145
|
-
// The managed sidecar bootstrap socket is not present — this happens
|
|
146
|
-
// when the flag is enabled by default but the instance pre-dates the
|
|
147
|
-
// socket volume mount (e.g. existing Docker configs without the
|
|
148
|
-
// ces-bootstrap volume). Warn and fall back to local discovery so
|
|
149
|
-
// these deployments don't fail on upgrade.
|
|
150
|
-
log.warn(
|
|
151
|
-
{ reason: discoveryResult.reason },
|
|
152
|
-
"CES managed sidecar bootstrap socket unavailable — falling back to local CES discovery",
|
|
153
|
-
);
|
|
154
|
-
discoveryResult = discoverLocalCes();
|
|
155
|
-
}
|
|
156
|
-
} else {
|
|
157
|
-
log.info(
|
|
158
|
-
"CES managed sidecar feature flag is off — skipping managed discovery, falling back to local",
|
|
121
|
+
discoveryResult = await discoverCes();
|
|
122
|
+
if (discoveryResult.mode === "unavailable") {
|
|
123
|
+
// The managed sidecar bootstrap socket is not present — this happens
|
|
124
|
+
// when the instance pre-dates the socket volume mount (e.g. existing
|
|
125
|
+
// Docker configs without the ces-bootstrap volume). Warn and fall
|
|
126
|
+
// back to local discovery so these deployments don't fail on upgrade.
|
|
127
|
+
log.warn(
|
|
128
|
+
{ reason: discoveryResult.reason },
|
|
129
|
+
"CES managed sidecar bootstrap socket unavailable — falling back to local CES discovery",
|
|
159
130
|
);
|
|
160
131
|
discoveryResult = discoverLocalCes();
|
|
161
132
|
}
|
|
@@ -18,17 +18,45 @@
|
|
|
18
18
|
* first and is authoritative for structural support, so host_bash and
|
|
19
19
|
* host_file_* are filtered out for chrome-extension regardless of the
|
|
20
20
|
* hasNoClient flag.
|
|
21
|
+
*
|
|
22
|
+
* Cross-client exception: tools whose capabilities are in
|
|
23
|
+
* CROSS_CLIENT_EXPOSED_CAPABILITIES (host_bash, host_file) are allowed for
|
|
24
|
+
* non-host-proxy interfaces (e.g. "web") when at least one capable client
|
|
25
|
+
* is connected via the event hub. host_browser is excluded (chrome-extension
|
|
26
|
+
* is its own executor; web turns have no CDP target model).
|
|
21
27
|
*/
|
|
22
28
|
|
|
23
|
-
import { describe, expect, test } from "bun:test";
|
|
29
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
30
|
+
|
|
31
|
+
// ── Module-level mocks ─────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
// Control how many capable clients the hub reports per capability.
|
|
34
|
+
const mockClientCountByCapability = new Map<string, number>();
|
|
24
35
|
|
|
25
|
-
|
|
26
|
-
|
|
36
|
+
mock.module("../../runtime/assistant-event-hub.js", () => ({
|
|
37
|
+
assistantEventHub: {
|
|
38
|
+
listClientsByCapability: (cap: string) => {
|
|
39
|
+
const count = mockClientCountByCapability.get(cap) ?? 0;
|
|
40
|
+
return Array.from({ length: count }, (_, i) => ({
|
|
41
|
+
clientId: `mock-${cap}-client-${i}`,
|
|
42
|
+
capabilities: [cap],
|
|
43
|
+
}));
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
broadcastMessage: () => {},
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
// Dynamic imports after mock.module calls so the stubs take effect
|
|
50
|
+
// before the modules under test are loaded.
|
|
51
|
+
const {
|
|
27
52
|
HOST_TOOL_NAMES,
|
|
28
53
|
HOST_TOOL_TO_CAPABILITY,
|
|
29
54
|
isToolActiveForContext,
|
|
30
|
-
|
|
31
|
-
|
|
55
|
+
} = await import("../conversation-tool-setup.js");
|
|
56
|
+
type SkillProjectionContext =
|
|
57
|
+
import("../conversation-tool-setup.js").SkillProjectionContext;
|
|
58
|
+
type SkillProjectionCache =
|
|
59
|
+
import("../conversation-skill-tools.js").SkillProjectionCache;
|
|
32
60
|
|
|
33
61
|
function makeCtx(
|
|
34
62
|
overrides: Partial<SkillProjectionContext> = {},
|
|
@@ -42,6 +70,10 @@ function makeCtx(
|
|
|
42
70
|
};
|
|
43
71
|
}
|
|
44
72
|
|
|
73
|
+
beforeEach(() => {
|
|
74
|
+
mockClientCountByCapability.clear();
|
|
75
|
+
});
|
|
76
|
+
|
|
45
77
|
describe("isToolActiveForContext — host tool capability gating", () => {
|
|
46
78
|
// macOS transport: SSE-based interactive approval required.
|
|
47
79
|
test("host_bash is active for macOS with a connected client", () => {
|
|
@@ -176,6 +208,156 @@ describe("isToolActiveForContext — host tool capability gating", () => {
|
|
|
176
208
|
});
|
|
177
209
|
});
|
|
178
210
|
|
|
211
|
+
describe("isToolActiveForContext — cross-client exception (Phase 1: host_bash)", () => {
|
|
212
|
+
test("host_bash is active for web transport when a host_bash-capable client is connected", () => {
|
|
213
|
+
// Cross-client path: a web turn should see host_bash when a macOS client
|
|
214
|
+
// with host_bash capability is connected via the event hub.
|
|
215
|
+
mockClientCountByCapability.set("host_bash", 1);
|
|
216
|
+
expect(
|
|
217
|
+
isToolActiveForContext(
|
|
218
|
+
"host_bash",
|
|
219
|
+
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
220
|
+
),
|
|
221
|
+
).toBe(true);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("host_bash is NOT active for web transport when no capable client is connected", () => {
|
|
225
|
+
// No cross-client fallback: hub has no host_bash-capable subscribers.
|
|
226
|
+
mockClientCountByCapability.set("host_bash", 0);
|
|
227
|
+
expect(
|
|
228
|
+
isToolActiveForContext(
|
|
229
|
+
"host_bash",
|
|
230
|
+
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
231
|
+
),
|
|
232
|
+
).toBe(false);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test("host_file_read is NOT active for web transport when only a host_bash client is connected", () => {
|
|
236
|
+
// The cross-client exception is per-capability: a host_bash-capable
|
|
237
|
+
// client in the hub does not satisfy host_file's exposure check, since
|
|
238
|
+
// listClientsByCapability is queried with the tool's actual capability.
|
|
239
|
+
mockClientCountByCapability.set("host_bash", 1);
|
|
240
|
+
expect(
|
|
241
|
+
isToolActiveForContext(
|
|
242
|
+
"host_file_read",
|
|
243
|
+
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
244
|
+
),
|
|
245
|
+
).toBe(false);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test("host_bash for macos transport is unaffected by the cross-client exception", () => {
|
|
249
|
+
// macos natively supports host_bash via host proxy — the supportsHostProxy
|
|
250
|
+
// check passes, so the cross-client branch is never reached.
|
|
251
|
+
mockClientCountByCapability.set("host_bash", 0);
|
|
252
|
+
expect(
|
|
253
|
+
isToolActiveForContext(
|
|
254
|
+
"host_bash",
|
|
255
|
+
makeCtx({ hasNoClient: false, transportInterface: "macos" }),
|
|
256
|
+
),
|
|
257
|
+
).toBe(true);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test("host_bash for macos with no client is still denied (security invariant unaffected)", () => {
|
|
261
|
+
// Even with a capable client in the hub, the macos SSE path takes
|
|
262
|
+
// precedence — it passes the supportsHostProxy check, bypasses the
|
|
263
|
+
// cross-client branch, and reaches the hasNoClient gate.
|
|
264
|
+
mockClientCountByCapability.set("host_bash", 1);
|
|
265
|
+
expect(
|
|
266
|
+
isToolActiveForContext(
|
|
267
|
+
"host_bash",
|
|
268
|
+
makeCtx({ hasNoClient: true, transportInterface: "macos" }),
|
|
269
|
+
),
|
|
270
|
+
).toBe(false);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test("host_bash is NOT active for chrome-extension even when a capable client is connected", () => {
|
|
274
|
+
// Security boundary: chrome-extension only gets host_browser. The
|
|
275
|
+
// cross-client exception explicitly excludes chrome-extension transport
|
|
276
|
+
// regardless of how many host_bash-capable clients are in the hub.
|
|
277
|
+
mockClientCountByCapability.set("host_bash", 1);
|
|
278
|
+
expect(
|
|
279
|
+
isToolActiveForContext(
|
|
280
|
+
"host_bash",
|
|
281
|
+
makeCtx({ hasNoClient: false, transportInterface: "chrome-extension" }),
|
|
282
|
+
),
|
|
283
|
+
).toBe(false);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
test("host_bash is NOT active for web transport when hasNoClient is true (no approval UI)", () => {
|
|
287
|
+
// hasNoClient gate: no interactive approval UI available for this turn.
|
|
288
|
+
// Cross-client exception must not bypass this gate.
|
|
289
|
+
mockClientCountByCapability.set("host_bash", 1);
|
|
290
|
+
expect(
|
|
291
|
+
isToolActiveForContext(
|
|
292
|
+
"host_bash",
|
|
293
|
+
makeCtx({ hasNoClient: true, transportInterface: "web" }),
|
|
294
|
+
),
|
|
295
|
+
).toBe(false);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
describe("isToolActiveForContext — cross-client exposure for host_file_*", () => {
|
|
300
|
+
const HOST_FILE_TOOLS = [
|
|
301
|
+
"host_file_read",
|
|
302
|
+
"host_file_write",
|
|
303
|
+
"host_file_edit",
|
|
304
|
+
"host_file_transfer",
|
|
305
|
+
] as const;
|
|
306
|
+
|
|
307
|
+
for (const tool of HOST_FILE_TOOLS) {
|
|
308
|
+
test(`${tool} is exposed for web transport when a host_file client is connected`, () => {
|
|
309
|
+
mockClientCountByCapability.set("host_file", 1);
|
|
310
|
+
expect(
|
|
311
|
+
isToolActiveForContext(
|
|
312
|
+
tool,
|
|
313
|
+
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
314
|
+
),
|
|
315
|
+
).toBe(true);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
test(`${tool} is NOT exposed for web when no host_file client is connected`, () => {
|
|
319
|
+
mockClientCountByCapability.set("host_file", 0);
|
|
320
|
+
expect(
|
|
321
|
+
isToolActiveForContext(
|
|
322
|
+
tool,
|
|
323
|
+
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
324
|
+
),
|
|
325
|
+
).toBe(false);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test(`${tool} is NOT exposed for chrome-extension (security boundary)`, () => {
|
|
329
|
+
mockClientCountByCapability.set("host_file", 1);
|
|
330
|
+
expect(
|
|
331
|
+
isToolActiveForContext(
|
|
332
|
+
tool,
|
|
333
|
+
makeCtx({ hasNoClient: true, transportInterface: "chrome-extension" }),
|
|
334
|
+
),
|
|
335
|
+
).toBe(false);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
test(`${tool} is NOT exposed when hasNoClient is true (no approval UI)`, () => {
|
|
339
|
+
mockClientCountByCapability.set("host_file", 1);
|
|
340
|
+
expect(
|
|
341
|
+
isToolActiveForContext(
|
|
342
|
+
tool,
|
|
343
|
+
makeCtx({ hasNoClient: true, transportInterface: "web" }),
|
|
344
|
+
),
|
|
345
|
+
).toBe(false);
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
test("listClientsByCapability is queried with the actual capability, not host_bash (regression guard for D5 latent bug)", () => {
|
|
350
|
+
mockClientCountByCapability.set("host_bash", 0);
|
|
351
|
+
mockClientCountByCapability.set("host_file", 1);
|
|
352
|
+
expect(
|
|
353
|
+
isToolActiveForContext(
|
|
354
|
+
"host_file_transfer",
|
|
355
|
+
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
356
|
+
),
|
|
357
|
+
).toBe(true);
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
|
|
179
361
|
describe("HOST_TOOL_NAMES derivation", () => {
|
|
180
362
|
test("HOST_TOOL_NAMES is derived from HOST_TOOL_TO_CAPABILITY", () => {
|
|
181
363
|
// Sanity check: every tool in the names set has a capability mapping.
|
|
@@ -125,7 +125,7 @@ export function classifyKind(mimeType: string): "image" | "video" | "document" {
|
|
|
125
125
|
// Validation / cap enforcement
|
|
126
126
|
// ---------------------------------------------------------------------------
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
interface ValidatedDrafts {
|
|
129
129
|
accepted: AssistantAttachmentDraft[];
|
|
130
130
|
warnings: string[];
|
|
131
131
|
}
|
|
@@ -171,13 +171,13 @@ export interface DirectiveRequest {
|
|
|
171
171
|
mimeType: string | undefined;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
|
|
174
|
+
interface DirectiveParseResult {
|
|
175
175
|
cleanText: string;
|
|
176
176
|
directiveRequests: DirectiveRequest[];
|
|
177
177
|
parseWarnings: string[];
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
|
|
180
|
+
interface DirectiveDisplayDrainResult {
|
|
181
181
|
emitText: string;
|
|
182
182
|
bufferedRemainder: string;
|
|
183
183
|
}
|
|
@@ -362,7 +362,7 @@ export function drainDirectiveDisplayBuffer(
|
|
|
362
362
|
// Sandbox file resolution
|
|
363
363
|
// ---------------------------------------------------------------------------
|
|
364
364
|
|
|
365
|
-
|
|
365
|
+
interface ResolveResult {
|
|
366
366
|
draft: AssistantAttachmentDraft | null;
|
|
367
367
|
warning: string | null;
|
|
368
368
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { getMessages, type MessageRow } from "../memory/conversation-crud.js";
|
|
2
|
+
import { cleanupBootstrapFiles } from "../prompts/bootstrap-cleanup.js";
|
|
3
|
+
import { getLogger } from "../util/logger.js";
|
|
4
|
+
|
|
5
|
+
export const BOOTSTRAP_CLEANUP_USER_TURN_THRESHOLD = 4;
|
|
6
|
+
|
|
7
|
+
const log = getLogger("bootstrap-turn-cleanup");
|
|
8
|
+
|
|
9
|
+
function isWakeUpGreetingMessage(content: string): boolean {
|
|
10
|
+
return content.toLowerCase().includes("wake up, my friend");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function countBootstrapUserTurns(
|
|
14
|
+
messages: Pick<MessageRow, "role" | "content">[],
|
|
15
|
+
): number {
|
|
16
|
+
return messages.filter(
|
|
17
|
+
(message) =>
|
|
18
|
+
message.role === "user" && !isWakeUpGreetingMessage(message.content),
|
|
19
|
+
).length;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function shouldCleanupBootstrapAfterTurn(
|
|
23
|
+
messages: Pick<MessageRow, "role" | "content">[],
|
|
24
|
+
threshold = BOOTSTRAP_CLEANUP_USER_TURN_THRESHOLD,
|
|
25
|
+
): boolean {
|
|
26
|
+
return countBootstrapUserTurns(messages) >= threshold;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function cleanupBootstrapAfterTurnThreshold(
|
|
30
|
+
conversationId: string,
|
|
31
|
+
): boolean {
|
|
32
|
+
let messages: MessageRow[];
|
|
33
|
+
try {
|
|
34
|
+
messages = getMessages(conversationId);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
log.warn({ err, conversationId }, "Failed to inspect bootstrap turn count");
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!shouldCleanupBootstrapAfterTurn(messages)) return false;
|
|
41
|
+
|
|
42
|
+
return cleanupBootstrapFiles(
|
|
43
|
+
`first conversation reached ${BOOTSTRAP_CLEANUP_USER_TURN_THRESHOLD} user turns`,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -8,7 +8,9 @@ import {
|
|
|
8
8
|
type FSWatcher,
|
|
9
9
|
mkdirSync,
|
|
10
10
|
readdirSync,
|
|
11
|
+
unwatchFile,
|
|
11
12
|
watch,
|
|
13
|
+
watchFile,
|
|
12
14
|
} from "node:fs";
|
|
13
15
|
import { join } from "node:path";
|
|
14
16
|
|
|
@@ -17,11 +19,9 @@ import type { MemoryCleanupConfig } from "../config/schemas/memory-lifecycle.js"
|
|
|
17
19
|
import { resetCleanupScheduleThrottle } from "../memory/cleanup-schedule-state.js";
|
|
18
20
|
import { clearEmbeddingBackendCache } from "../memory/embedding-backend.js";
|
|
19
21
|
import { initializeProviders } from "../providers/registry.js";
|
|
20
|
-
import { handleBashSignal } from "../signals/bash.js";
|
|
21
22
|
import { handleCancelSignal } from "../signals/cancel.js";
|
|
22
23
|
import { handleConversationUndoSignal } from "../signals/conversation-undo.js";
|
|
23
24
|
import { handleEmitEventSignal } from "../signals/emit-event.js";
|
|
24
|
-
import { handleMcpReloadSignal } from "../signals/mcp-reload.js";
|
|
25
25
|
import { handleUserMessageSignal } from "../signals/user-message.js";
|
|
26
26
|
import { DebouncerMap } from "../util/debounce.js";
|
|
27
27
|
import { getLogger } from "../util/logger.js";
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
getWorkspaceDir,
|
|
34
34
|
getWorkspaceSkillsDir,
|
|
35
35
|
} from "../util/platform.js";
|
|
36
|
+
import { reloadMcpServers } from "./mcp-reload-service.js";
|
|
36
37
|
|
|
37
38
|
const log = getLogger("config-watcher");
|
|
38
39
|
|
|
@@ -47,19 +48,44 @@ function attachWatcherErrorHandler(watcher: FSWatcher, dir: string): void {
|
|
|
47
48
|
});
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Poll interval for `fs.watchFile()`. Use the stat-polling watcher
|
|
53
|
+
* because Bun's per-file `fs.watch()` doesn't detect renames on Linux
|
|
54
|
+
* (seemingly works on macOS). See https://github.com/oven-sh/bun/issues/15010.
|
|
55
|
+
*/
|
|
56
|
+
const WATCH_FILE_POLL_MS = 2_000;
|
|
57
|
+
|
|
50
58
|
export class ConfigWatcher {
|
|
51
59
|
private watchers: FSWatcher[] = [];
|
|
52
|
-
private
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
protectedKeyPrefix: "__",
|
|
56
|
-
});
|
|
60
|
+
private watchedFiles: Set<string> = new Set();
|
|
61
|
+
private stopped = false;
|
|
62
|
+
private debounceTimers: DebouncerMap;
|
|
57
63
|
private suppressReload = false;
|
|
58
64
|
lastFingerprint = "";
|
|
65
|
+
private lastConfig: ReturnType<typeof getConfig> | null = null;
|
|
59
66
|
private lastRefreshTime = 0;
|
|
60
67
|
|
|
61
68
|
static readonly REFRESH_INTERVAL_MS = 30_000;
|
|
62
69
|
|
|
70
|
+
/**
|
|
71
|
+
* @param pollIntervalMs Per-file stat poll interval (passed to
|
|
72
|
+
* `fs.watchFile`). Default `WATCH_FILE_POLL_MS` (2s); tests pass a
|
|
73
|
+
* smaller value for fast turnaround.
|
|
74
|
+
* @param debounceMs Debounce window applied to any detected file
|
|
75
|
+
* change before invoking its handler. Default 200ms; tests pass a
|
|
76
|
+
* smaller value to avoid sleeping unnecessarily.
|
|
77
|
+
*/
|
|
78
|
+
constructor(
|
|
79
|
+
private readonly pollIntervalMs: number = WATCH_FILE_POLL_MS,
|
|
80
|
+
debounceMs = 200,
|
|
81
|
+
) {
|
|
82
|
+
this.debounceTimers = new DebouncerMap({
|
|
83
|
+
defaultDelayMs: debounceMs,
|
|
84
|
+
maxEntries: 1000,
|
|
85
|
+
protectedKeyPrefix: "__",
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
63
89
|
/** Expose the debounce timers so handlers can schedule debounced work. */
|
|
64
90
|
get timers(): DebouncerMap {
|
|
65
91
|
return this.debounceTimers;
|
|
@@ -88,12 +114,15 @@ export class ConfigWatcher {
|
|
|
88
114
|
|
|
89
115
|
/** Initialize the config fingerprint (call after first config load). */
|
|
90
116
|
initFingerprint(config: ReturnType<typeof getConfig>): void {
|
|
117
|
+
this.lastConfig = config;
|
|
91
118
|
this.lastFingerprint = this.configFingerprint(config);
|
|
92
119
|
}
|
|
93
120
|
|
|
94
121
|
/** Update the fingerprint to match the current config. */
|
|
95
122
|
updateFingerprint(): void {
|
|
96
|
-
|
|
123
|
+
const config = getConfig();
|
|
124
|
+
this.lastConfig = config;
|
|
125
|
+
this.lastFingerprint = this.configFingerprint(config);
|
|
97
126
|
this.lastRefreshTime = Date.now();
|
|
98
127
|
}
|
|
99
128
|
|
|
@@ -103,7 +132,7 @@ export class ConfigWatcher {
|
|
|
103
132
|
* Returns true if config actually changed.
|
|
104
133
|
*/
|
|
105
134
|
async refreshConfigFromSources(): Promise<boolean> {
|
|
106
|
-
const prevCleanup =
|
|
135
|
+
const prevCleanup = this.lastConfig?.memory?.cleanup;
|
|
107
136
|
invalidateConfigCache();
|
|
108
137
|
const config = getConfig();
|
|
109
138
|
const fingerprint = this.configFingerprint(config);
|
|
@@ -120,6 +149,7 @@ export class ConfigWatcher {
|
|
|
120
149
|
}
|
|
121
150
|
const isFirstInit = this.lastFingerprint === "";
|
|
122
151
|
await initializeProviders(config);
|
|
152
|
+
this.lastConfig = config;
|
|
123
153
|
this.lastFingerprint = fingerprint;
|
|
124
154
|
return !isFirstInit;
|
|
125
155
|
}
|
|
@@ -136,22 +166,29 @@ export class ConfigWatcher {
|
|
|
136
166
|
onAvatarChanged?: () => void,
|
|
137
167
|
onConfigChanged?: () => void,
|
|
138
168
|
): void {
|
|
169
|
+
// Reset the stopped flag so a stop()→start() cycle on the same
|
|
170
|
+
// instance resumes hot-reload instead of silently bailing in every
|
|
171
|
+
// watchFile callback. This matters because getConfigWatcher() is a
|
|
172
|
+
// module-level singleton — a daemon restart path that reuses it
|
|
173
|
+
// would otherwise be permanently mute.
|
|
174
|
+
this.stopped = false;
|
|
139
175
|
const workspaceDir = getWorkspaceDir();
|
|
140
176
|
|
|
141
177
|
const workspaceHandlers: Record<string, () => void> = {
|
|
142
178
|
"config.json": async () => {
|
|
143
179
|
if (this.suppressReload) return;
|
|
144
180
|
try {
|
|
145
|
-
const
|
|
146
|
-
const prevMcpFingerprint = JSON.stringify(prevConfig.mcp ?? {});
|
|
181
|
+
const prevMcpFingerprint = JSON.stringify(this.lastConfig?.mcp ?? {});
|
|
147
182
|
const changed = await this.refreshConfigFromSources();
|
|
148
183
|
if (changed) {
|
|
149
184
|
onConversationEvict();
|
|
150
185
|
onConfigChanged?.();
|
|
151
|
-
const newConfig = getConfig();
|
|
186
|
+
const newConfig = this.lastConfig ?? getConfig();
|
|
152
187
|
const newMcpFingerprint = JSON.stringify(newConfig.mcp ?? {});
|
|
153
188
|
if (newMcpFingerprint !== prevMcpFingerprint) {
|
|
154
|
-
|
|
189
|
+
reloadMcpServers().catch((err: unknown) => {
|
|
190
|
+
log.error({ err }, "MCP reload after config change failed");
|
|
191
|
+
});
|
|
155
192
|
}
|
|
156
193
|
}
|
|
157
194
|
} catch (err) {
|
|
@@ -168,37 +205,11 @@ export class ConfigWatcher {
|
|
|
168
205
|
},
|
|
169
206
|
};
|
|
170
207
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
try {
|
|
177
|
-
const watcher = watch(dir, (_eventType, filename) => {
|
|
178
|
-
if (!filename) return;
|
|
179
|
-
const file = String(filename);
|
|
180
|
-
if (!handlers[file]) return;
|
|
181
|
-
this.debounceTimers.schedule(`file:${file}`, () => {
|
|
182
|
-
log.info({ file }, "File changed, reloading");
|
|
183
|
-
handlers[file]();
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
attachWatcherErrorHandler(watcher, dir);
|
|
187
|
-
this.watchers.push(watcher);
|
|
188
|
-
log.info({ dir }, `Watching ${label}`);
|
|
189
|
-
} catch (err) {
|
|
190
|
-
log.warn(
|
|
191
|
-
{ err, dir },
|
|
192
|
-
`Failed to watch ${label}. Hot-reload will be unavailable.`,
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
watchDir(
|
|
198
|
-
workspaceDir,
|
|
199
|
-
workspaceHandlers,
|
|
200
|
-
"workspace directory for config/prompt changes",
|
|
201
|
-
);
|
|
208
|
+
// Per-file watches; don't watch the workspace directory itself because
|
|
209
|
+
// it contains socket files.
|
|
210
|
+
for (const [filename, handler] of Object.entries(workspaceHandlers)) {
|
|
211
|
+
this.watchFile(join(workspaceDir, filename), handler, filename);
|
|
212
|
+
}
|
|
202
213
|
|
|
203
214
|
if (onSoundsConfigChanged) {
|
|
204
215
|
this.startSoundsWatcher(onSoundsConfigChanged);
|
|
@@ -213,13 +224,46 @@ export class ConfigWatcher {
|
|
|
213
224
|
}
|
|
214
225
|
|
|
215
226
|
stop(): void {
|
|
227
|
+
this.stopped = true;
|
|
216
228
|
this.debounceTimers.cancelAll();
|
|
229
|
+
for (const filePath of this.watchedFiles) {
|
|
230
|
+
unwatchFile(filePath);
|
|
231
|
+
}
|
|
232
|
+
this.watchedFiles.clear();
|
|
217
233
|
for (const watcher of this.watchers) {
|
|
218
234
|
watcher.close();
|
|
219
235
|
}
|
|
220
236
|
this.watchers = [];
|
|
221
237
|
}
|
|
222
238
|
|
|
239
|
+
private watchFile(
|
|
240
|
+
filePath: string,
|
|
241
|
+
handler: () => void,
|
|
242
|
+
label: string,
|
|
243
|
+
): void {
|
|
244
|
+
// Match the defensive pattern used by every other startXWatcher in
|
|
245
|
+
// this file: log the failure and continue. Per AGENTS.md, the daemon
|
|
246
|
+
// must never block startup — a watchFile() throw on some platform
|
|
247
|
+
// edge case must not propagate up to DaemonServer.start().
|
|
248
|
+
try {
|
|
249
|
+
watchFile(filePath, { interval: this.pollIntervalMs }, (curr, prev) => {
|
|
250
|
+
if (this.stopped) return;
|
|
251
|
+
if (curr.ino === prev.ino && curr.mtimeMs === prev.mtimeMs) return;
|
|
252
|
+
this.debounceTimers.schedule(`file:${filePath}`, () => {
|
|
253
|
+
log.info({ file: filePath }, "File changed, reloading");
|
|
254
|
+
handler();
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
this.watchedFiles.add(filePath);
|
|
258
|
+
log.info({ file: filePath }, `Watching ${label}`);
|
|
259
|
+
} catch (err) {
|
|
260
|
+
log.warn(
|
|
261
|
+
{ err, file: filePath },
|
|
262
|
+
`Failed to watch ${label}. Hot-reload will be unavailable until restart.`,
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
223
267
|
private startSoundsWatcher(onSoundsConfigChanged: () => void): void {
|
|
224
268
|
const soundsDir = getSoundsDir();
|
|
225
269
|
try {
|
|
@@ -331,7 +375,6 @@ export class ConfigWatcher {
|
|
|
331
375
|
|
|
332
376
|
const exactSignalHandlers: Record<string, () => void | Promise<void>> = {
|
|
333
377
|
cancel: handleCancelSignal,
|
|
334
|
-
"mcp-reload": handleMcpReloadSignal,
|
|
335
378
|
"conversation-undo": handleConversationUndoSignal,
|
|
336
379
|
"emit-event": handleEmitEventSignal,
|
|
337
380
|
};
|
|
@@ -340,7 +383,6 @@ export class ConfigWatcher {
|
|
|
340
383
|
string,
|
|
341
384
|
(filename: string) => void | Promise<void>
|
|
342
385
|
> = {
|
|
343
|
-
"bash.": handleBashSignal,
|
|
344
386
|
"user-message.": handleUserMessageSignal,
|
|
345
387
|
};
|
|
346
388
|
|
|
@@ -485,20 +527,6 @@ export class ConfigWatcher {
|
|
|
485
527
|
}
|
|
486
528
|
}
|
|
487
529
|
|
|
488
|
-
/**
|
|
489
|
-
* Snapshot the current cleanup config so we can compare it against the
|
|
490
|
-
* post-reload value. Tolerant of config-load failures — if the config can't
|
|
491
|
-
* be read (e.g. first-load), returns undefined so the comparison below
|
|
492
|
-
* treats it as "no previous value".
|
|
493
|
-
*/
|
|
494
|
-
function safeGetCleanupConfig(): MemoryCleanupConfig | undefined {
|
|
495
|
-
try {
|
|
496
|
-
return getConfig().memory?.cleanup;
|
|
497
|
-
} catch {
|
|
498
|
-
return undefined;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
530
|
/**
|
|
503
531
|
* Return true if any cleanup field the user can change via the UI differs
|
|
504
532
|
* between the previous and next config snapshots. Used to decide whether to
|
|
@@ -529,6 +557,7 @@ export function cleanupSettingsChanged(
|
|
|
529
557
|
return (
|
|
530
558
|
prev.llmRequestLogRetentionMs !== next.llmRequestLogRetentionMs ||
|
|
531
559
|
prev.conversationRetentionDays !== next.conversationRetentionDays ||
|
|
560
|
+
prev.traceEventRetentionDays !== next.traceEventRetentionDays ||
|
|
532
561
|
prev.enabled !== next.enabled
|
|
533
562
|
);
|
|
534
563
|
}
|