@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
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host app-control proxy.
|
|
3
|
+
*
|
|
4
|
+
* Proxies app-control actions (start, observe, press, combo, type, click,
|
|
5
|
+
* drag, stop) to the desktop client. Targets a specific application by
|
|
6
|
+
* bundle ID or process name — distinct from the system-wide computer-use
|
|
7
|
+
* proxy ({@link HostCuProxy}).
|
|
8
|
+
*
|
|
9
|
+
* Lifecycle (pending map, timeout, abort SSE, dispose, isAvailable) lives
|
|
10
|
+
* in {@link HostProxyBase}; this class layers app-control-specific state
|
|
11
|
+
* (PNG-hash loop guard) and the result-payload → ToolExecutionResult
|
|
12
|
+
* translation on top.
|
|
13
|
+
*
|
|
14
|
+
* **Session lock.** Only one conversation may hold an active app-control
|
|
15
|
+
* session at a time, and that session is bound to a specific target app.
|
|
16
|
+
* The lock is module-level (`activeAppControlSession`) because the session
|
|
17
|
+
* targets the user's actual desktop application, which is a host-wide
|
|
18
|
+
* resource. It is acquired on a successful `app_control_start` (storing
|
|
19
|
+
* `(conversationId, app)`) and released when the owning proxy's
|
|
20
|
+
* `dispose()` fires.
|
|
21
|
+
*
|
|
22
|
+
* `app_control_start` is the only tool that can acquire the lock — the
|
|
23
|
+
* user's medium-risk approval at start time is the consent boundary. All
|
|
24
|
+
* other tools (observe / press / combo / sequence / type / click / drag)
|
|
25
|
+
* require the calling conversation to own an active session targeting the
|
|
26
|
+
* same `app`; otherwise the call is rejected before any host dispatch.
|
|
27
|
+
* This prevents prompt-injected tool calls from sending raw input to
|
|
28
|
+
* arbitrary apps without the user having approved control of that
|
|
29
|
+
* specific app.
|
|
30
|
+
*
|
|
31
|
+
* **No step cap.** Unlike {@link HostCuProxy} which enforces a per-session
|
|
32
|
+
* step ceiling via `loadConfig().maxStepsPerSession`, app-control sessions
|
|
33
|
+
* are not capped. App-control flows are typically narrower (single-app,
|
|
34
|
+
* shorter horizons) and the loop guard plus user oversight are the
|
|
35
|
+
* intended safeguards.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import { createHash } from "node:crypto";
|
|
39
|
+
|
|
40
|
+
import type { ContentBlock } from "../providers/types.js";
|
|
41
|
+
import type { ToolExecutionResult } from "../tools/types.js";
|
|
42
|
+
import { getLogger } from "../util/logger.js";
|
|
43
|
+
import { HostProxyBase, HostProxyRequestError } from "./host-proxy-base.js";
|
|
44
|
+
import type {
|
|
45
|
+
HostAppControlInput,
|
|
46
|
+
HostAppControlResultPayload,
|
|
47
|
+
} from "./message-types/host-app-control.js";
|
|
48
|
+
|
|
49
|
+
const log = getLogger("host-app-control-proxy");
|
|
50
|
+
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// Constants
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
const REQUEST_TIMEOUT_MS = 60 * 1000;
|
|
56
|
+
// Threshold of 4 means the warning fires on the 5th identical observation:
|
|
57
|
+
// the first observation establishes the baseline (count = 0), each
|
|
58
|
+
// subsequent identical observation increments the counter, so count = 4 is
|
|
59
|
+
// reached on the 5th total observation.
|
|
60
|
+
const STUCK_REPEAT_THRESHOLD = 4;
|
|
61
|
+
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// Module-level session lock
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Active app-control session: the conversation that owns the lock and the
|
|
68
|
+
* `app` it was approved against. Set on a successful `app_control_start`;
|
|
69
|
+
* cleared by the owning proxy's `dispose()`.
|
|
70
|
+
*/
|
|
71
|
+
export interface ActiveAppControlSession {
|
|
72
|
+
conversationId: string;
|
|
73
|
+
/**
|
|
74
|
+
* The exact `app` string the user approved at start time (bundle ID or
|
|
75
|
+
* process name — preserved as-is). Compared case-insensitively against
|
|
76
|
+
* the `app` of subsequent non-start tool calls.
|
|
77
|
+
*/
|
|
78
|
+
app: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Currently active session, or `undefined` when no session is held.
|
|
83
|
+
*
|
|
84
|
+
* Exported for test inspection only. Production code paths must not read
|
|
85
|
+
* or mutate this directly — use the proxy methods.
|
|
86
|
+
*/
|
|
87
|
+
let activeAppControlSession: ActiveAppControlSession | undefined;
|
|
88
|
+
|
|
89
|
+
/** Test-only helper: read current session. */
|
|
90
|
+
export function _getActiveAppControlSession():
|
|
91
|
+
| ActiveAppControlSession
|
|
92
|
+
| undefined {
|
|
93
|
+
return activeAppControlSession;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Test-only helper: clear session between test cases. */
|
|
97
|
+
export function _resetActiveAppControlSession(): void {
|
|
98
|
+
activeAppControlSession = undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Test-only helper: prime the active session without a full `start` round-trip.
|
|
103
|
+
* Useful for tests that exercise non-start tool paths and don't need to
|
|
104
|
+
* verify the start flow itself.
|
|
105
|
+
*/
|
|
106
|
+
export function _setActiveAppControlSession(
|
|
107
|
+
session: ActiveAppControlSession,
|
|
108
|
+
): void {
|
|
109
|
+
activeAppControlSession = session;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Validate a non-start tool call against the active session. Returns a
|
|
114
|
+
* `ToolExecutionResult` (with `isError: true`) when the call should be
|
|
115
|
+
* rejected; returns `null` when the call is authorized to dispatch.
|
|
116
|
+
*
|
|
117
|
+
* `app` matching is case-insensitive (macOS bundle IDs are
|
|
118
|
+
* case-insensitive in practice) but strict on form: `"Safari"` and
|
|
119
|
+
* `"com.apple.Safari"` do not match — the user approved a specific string
|
|
120
|
+
* and substituting a different form requires a new approval.
|
|
121
|
+
*/
|
|
122
|
+
function checkNonStartAuthorization(
|
|
123
|
+
input: HostAppControlInput,
|
|
124
|
+
conversationId: string,
|
|
125
|
+
): ToolExecutionResult | null {
|
|
126
|
+
if (activeAppControlSession == null) {
|
|
127
|
+
return {
|
|
128
|
+
content:
|
|
129
|
+
"No app-control session is active. Call app_control_start to request " +
|
|
130
|
+
"user approval to control the target app, then retry.",
|
|
131
|
+
isError: true,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (activeAppControlSession.conversationId !== conversationId) {
|
|
135
|
+
return {
|
|
136
|
+
content:
|
|
137
|
+
`Another conversation (${activeAppControlSession.conversationId}) currently ` +
|
|
138
|
+
`holds the app-control session. Wait for it to finish, or call ` +
|
|
139
|
+
`app_control_stop from that conversation first.`,
|
|
140
|
+
isError: true,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
// `app` is required on every non-start variant of HostAppControlInput
|
|
144
|
+
// except `stop`, and `stop` short-circuits in conversation-surfaces and
|
|
145
|
+
// does not reach this method in production. A stop reaching here would
|
|
146
|
+
// be a defensive bug — surface it explicitly rather than dispatch.
|
|
147
|
+
const requestedApp = (input as { app?: string }).app;
|
|
148
|
+
if (requestedApp == null) {
|
|
149
|
+
return {
|
|
150
|
+
content:
|
|
151
|
+
"Tool input missing required 'app' field; cannot validate against " +
|
|
152
|
+
"the active app-control session.",
|
|
153
|
+
isError: true,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (
|
|
157
|
+
requestedApp.toLowerCase() !== activeAppControlSession.app.toLowerCase()
|
|
158
|
+
) {
|
|
159
|
+
return {
|
|
160
|
+
content:
|
|
161
|
+
`Active app-control session targets ${activeAppControlSession.app}; ` +
|
|
162
|
+
`cannot send actions to ${requestedApp}. Call app_control_stop and ` +
|
|
163
|
+
`app_control_start to switch apps.`,
|
|
164
|
+
isError: true,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
// HostAppControlProxy
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
export class HostAppControlProxy extends HostProxyBase<
|
|
175
|
+
HostAppControlInput,
|
|
176
|
+
HostAppControlResultPayload
|
|
177
|
+
> {
|
|
178
|
+
/** Conversation that owns this proxy instance. Used by `dispose()` to release the session lock only when this proxy is the holder. */
|
|
179
|
+
private readonly conversationId: string;
|
|
180
|
+
|
|
181
|
+
/** sha256 hex of the most recent observation's `pngBase64`, or undefined. */
|
|
182
|
+
private lastObservationHash?: string;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Number of consecutive observations whose PNG hash matched the previous
|
|
186
|
+
* one. Reset to 0 when a different hash is observed. When this reaches
|
|
187
|
+
* {@link STUCK_REPEAT_THRESHOLD}, results carry a `"stuck"` warning.
|
|
188
|
+
*/
|
|
189
|
+
private observationHashRepeatCount = 0;
|
|
190
|
+
|
|
191
|
+
constructor(conversationId: string) {
|
|
192
|
+
super({
|
|
193
|
+
capabilityName: "host_app_control",
|
|
194
|
+
requestEventName: "host_app_control_request",
|
|
195
|
+
cancelEventName: "host_app_control_cancel",
|
|
196
|
+
resultPendingKind: "host_app_control",
|
|
197
|
+
timeoutMs: REQUEST_TIMEOUT_MS,
|
|
198
|
+
disposedMessage: "Host app-control proxy disposed",
|
|
199
|
+
});
|
|
200
|
+
this.conversationId = conversationId;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
// State accessors (testing / external inspection)
|
|
205
|
+
// ---------------------------------------------------------------------------
|
|
206
|
+
|
|
207
|
+
get observationRepeatCount(): number {
|
|
208
|
+
return this.observationHashRepeatCount;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
// Public request entry point
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Dispatch an app-control tool call to the desktop client. Catches the
|
|
217
|
+
* base's typed lifecycle errors (timeout/aborted/disposed) and returns
|
|
218
|
+
* a `ToolExecutionResult` instead of letting them bubble.
|
|
219
|
+
*/
|
|
220
|
+
async request(
|
|
221
|
+
toolName: string,
|
|
222
|
+
input: HostAppControlInput,
|
|
223
|
+
conversationId: string,
|
|
224
|
+
signal: AbortSignal,
|
|
225
|
+
): Promise<ToolExecutionResult> {
|
|
226
|
+
if (signal.aborted) {
|
|
227
|
+
return { content: "Aborted", isError: true };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Authorization gate. `start` acquires the session lock (the user's
|
|
231
|
+
// medium-risk approval is the consent boundary); all other tools must
|
|
232
|
+
// belong to the active session and target the same `app`. Without this
|
|
233
|
+
// gate, prompt-injected calls would bypass the start-time approval and
|
|
234
|
+
// send raw input to arbitrary apps.
|
|
235
|
+
if (input.tool === "start") {
|
|
236
|
+
if (
|
|
237
|
+
activeAppControlSession != null &&
|
|
238
|
+
activeAppControlSession.conversationId !== conversationId
|
|
239
|
+
) {
|
|
240
|
+
return {
|
|
241
|
+
content:
|
|
242
|
+
`Another conversation (${activeAppControlSession.conversationId}) currently holds the ` +
|
|
243
|
+
`app-control session. Wait for it to finish, or call app_control_stop ` +
|
|
244
|
+
`from that conversation first.`,
|
|
245
|
+
isError: true,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
const sessionError = checkNonStartAuthorization(input, conversationId);
|
|
250
|
+
if (sessionError != null) {
|
|
251
|
+
return sessionError;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
try {
|
|
256
|
+
const payload = await this.dispatchRequest(
|
|
257
|
+
toolName,
|
|
258
|
+
input,
|
|
259
|
+
conversationId,
|
|
260
|
+
signal,
|
|
261
|
+
);
|
|
262
|
+
return this.handleSuccess(input, payload);
|
|
263
|
+
} catch (err) {
|
|
264
|
+
if (err instanceof HostProxyRequestError) {
|
|
265
|
+
if (err.reason === "timeout") {
|
|
266
|
+
log.warn({ toolName }, "Host app-control proxy request timed out");
|
|
267
|
+
return {
|
|
268
|
+
content:
|
|
269
|
+
"Host app-control proxy timed out waiting for client response",
|
|
270
|
+
isError: true,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
if (err.reason === "aborted") {
|
|
274
|
+
return { content: "Aborted", isError: true };
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// `disposed` and any other unexpected errors propagate.
|
|
278
|
+
throw err;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ---------------------------------------------------------------------------
|
|
283
|
+
// Result handling
|
|
284
|
+
// ---------------------------------------------------------------------------
|
|
285
|
+
|
|
286
|
+
private handleSuccess(
|
|
287
|
+
input: HostAppControlInput,
|
|
288
|
+
payload: HostAppControlResultPayload,
|
|
289
|
+
): ToolExecutionResult {
|
|
290
|
+
// Update PNG-hash loop tracking only for the "running" state — other
|
|
291
|
+
// states (missing/minimized) intentionally won't carry a
|
|
292
|
+
// representative window screenshot, so they should not feed the guard.
|
|
293
|
+
let stuck = false;
|
|
294
|
+
if (payload.state === "running" && payload.pngBase64) {
|
|
295
|
+
const hash = createHash("sha256").update(payload.pngBase64).digest("hex");
|
|
296
|
+
if (hash === this.lastObservationHash) {
|
|
297
|
+
this.observationHashRepeatCount++;
|
|
298
|
+
} else {
|
|
299
|
+
this.observationHashRepeatCount = 0;
|
|
300
|
+
}
|
|
301
|
+
this.lastObservationHash = hash;
|
|
302
|
+
if (this.observationHashRepeatCount >= STUCK_REPEAT_THRESHOLD) {
|
|
303
|
+
stuck = true;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Store the exact `app` form for validation against subsequent
|
|
308
|
+
// non-start tool calls.
|
|
309
|
+
if (input.tool === "start" && payload.state === "running") {
|
|
310
|
+
activeAppControlSession = {
|
|
311
|
+
conversationId: this.conversationId,
|
|
312
|
+
app: input.app,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return this.formatResult(payload, stuck);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
private formatResult(
|
|
320
|
+
payload: HostAppControlResultPayload,
|
|
321
|
+
stuck: boolean,
|
|
322
|
+
): ToolExecutionResult {
|
|
323
|
+
const parts: string[] = [];
|
|
324
|
+
|
|
325
|
+
if (stuck) {
|
|
326
|
+
parts.push(
|
|
327
|
+
`WARNING: ${this.observationHashRepeatCount} consecutive observations ` +
|
|
328
|
+
`produced an identical screenshot — the app appears stuck. Try a ` +
|
|
329
|
+
`different action or call app_control_stop and restart.`,
|
|
330
|
+
);
|
|
331
|
+
parts.push("");
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
parts.push(`State: ${payload.state}`);
|
|
335
|
+
|
|
336
|
+
if (payload.windowBounds) {
|
|
337
|
+
const { x, y, width, height } = payload.windowBounds;
|
|
338
|
+
parts.push(`Window bounds: ${width}x${height} at (${x}, ${y})`);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (payload.executionResult) {
|
|
342
|
+
parts.push("");
|
|
343
|
+
parts.push(payload.executionResult);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const isError = payload.executionError != null;
|
|
347
|
+
const errorPrefix = isError
|
|
348
|
+
? `Action failed: ${payload.executionError}`
|
|
349
|
+
: null;
|
|
350
|
+
|
|
351
|
+
const baseContent = parts.join("\n").trim() || `State: ${payload.state}`;
|
|
352
|
+
const content = errorPrefix
|
|
353
|
+
? `${errorPrefix}\n\n${baseContent}`
|
|
354
|
+
: baseContent;
|
|
355
|
+
|
|
356
|
+
const contentBlocks: ContentBlock[] = [];
|
|
357
|
+
if (payload.pngBase64) {
|
|
358
|
+
contentBlocks.push({
|
|
359
|
+
type: "image",
|
|
360
|
+
source: {
|
|
361
|
+
type: "base64",
|
|
362
|
+
media_type: "image/png",
|
|
363
|
+
data: payload.pngBase64,
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
content,
|
|
370
|
+
isError,
|
|
371
|
+
...(contentBlocks.length > 0 ? { contentBlocks } : {}),
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// ---------------------------------------------------------------------------
|
|
376
|
+
// Lifecycle
|
|
377
|
+
// ---------------------------------------------------------------------------
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Reject pending requests via the base, then release the session lock
|
|
381
|
+
* if this proxy is the holder. Idempotent: safe to call multiple times.
|
|
382
|
+
*/
|
|
383
|
+
override dispose(): void {
|
|
384
|
+
super.dispose();
|
|
385
|
+
if (activeAppControlSession?.conversationId === this.conversationId) {
|
|
386
|
+
activeAppControlSession = undefined;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
@@ -5,25 +5,19 @@ import {
|
|
|
5
5
|
assistantEventHub,
|
|
6
6
|
broadcastMessage,
|
|
7
7
|
} from "../runtime/assistant-event-hub.js";
|
|
8
|
+
import {
|
|
9
|
+
ambiguousSameUserError,
|
|
10
|
+
enforceSameActorOrErrorResult,
|
|
11
|
+
pickSameUserAutoResolve,
|
|
12
|
+
} from "../runtime/auth/same-actor.js";
|
|
8
13
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
9
14
|
import { formatShellOutput } from "../tools/shared/shell-output.js";
|
|
10
15
|
import type { ToolExecutionResult } from "../tools/types.js";
|
|
11
16
|
import { AssistantError, ErrorCode } from "../util/errors.js";
|
|
12
17
|
import { getLogger } from "../util/logger.js";
|
|
13
|
-
import type { ServerMessage } from "./message-protocol.js";
|
|
14
18
|
|
|
15
19
|
const log = getLogger("host-bash-proxy");
|
|
16
20
|
|
|
17
|
-
interface PendingRequest {
|
|
18
|
-
resolve: (result: ToolExecutionResult) => void;
|
|
19
|
-
reject: (err: Error) => void;
|
|
20
|
-
timer: ReturnType<typeof setTimeout>;
|
|
21
|
-
timeoutSec: number;
|
|
22
|
-
conversationId: string;
|
|
23
|
-
/** Detach the abort listener from the caller's signal. No-op when no signal was passed. */
|
|
24
|
-
detachAbort: () => void;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
21
|
export class HostBashProxy {
|
|
28
22
|
private static _instance: HostBashProxy | null = null;
|
|
29
23
|
|
|
@@ -53,8 +47,6 @@ export class HostBashProxy {
|
|
|
53
47
|
HostBashProxy._instance = null;
|
|
54
48
|
}
|
|
55
49
|
|
|
56
|
-
private pending = new Map<string, PendingRequest>();
|
|
57
|
-
|
|
58
50
|
/**
|
|
59
51
|
* Whether a client with `host_bash` capability is connected.
|
|
60
52
|
*/
|
|
@@ -64,71 +56,105 @@ export class HostBashProxy {
|
|
|
64
56
|
);
|
|
65
57
|
}
|
|
66
58
|
|
|
67
|
-
private send(msg: ServerMessage): void {
|
|
68
|
-
broadcastMessage(msg, undefined, { targetCapability: "host_bash" });
|
|
69
|
-
}
|
|
70
|
-
|
|
71
59
|
request(
|
|
72
60
|
input: {
|
|
73
61
|
command: string;
|
|
74
62
|
working_dir?: string;
|
|
75
63
|
timeout_seconds?: number;
|
|
76
64
|
env?: Record<string, string>;
|
|
65
|
+
targetClientId?: string;
|
|
77
66
|
},
|
|
78
67
|
conversationId: string,
|
|
79
68
|
signal?: AbortSignal,
|
|
69
|
+
// Principal ID of the actor on whose behalf this request is initiated.
|
|
70
|
+
sourceActorPrincipalId?: string,
|
|
80
71
|
): Promise<ToolExecutionResult> {
|
|
81
72
|
if (signal?.aborted) {
|
|
82
73
|
const result = formatShellOutput("", "Aborted", null, false, 0);
|
|
83
74
|
return Promise.resolve(result);
|
|
84
75
|
}
|
|
85
76
|
|
|
77
|
+
let resolvedTargetClientId: string | undefined;
|
|
78
|
+
|
|
79
|
+
if (input.targetClientId) {
|
|
80
|
+
const target = assistantEventHub.getClientById(input.targetClientId);
|
|
81
|
+
if (!target || !target.capabilities.includes("host_bash")) {
|
|
82
|
+
return Promise.resolve({
|
|
83
|
+
content: `Error: client "${input.targetClientId}" is not connected or does not support host_bash. Run \`assistant clients list --capability host_bash\` to see available clients.`,
|
|
84
|
+
isError: true,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
resolvedTargetClientId = input.targetClientId;
|
|
88
|
+
} else {
|
|
89
|
+
// Auto-resolve to the unique same-user client. Reject (rather than
|
|
90
|
+
// broadcast) when multiple same-user clients are connected so that
|
|
91
|
+
// a single targeted-style request cannot fan out across every one
|
|
92
|
+
// of the user's machines. Zero same-user matches falls through to
|
|
93
|
+
// the existing untargeted code path.
|
|
94
|
+
const resolved = pickSameUserAutoResolve({
|
|
95
|
+
hub: assistantEventHub,
|
|
96
|
+
capability: "host_bash",
|
|
97
|
+
sourceActorPrincipalId,
|
|
98
|
+
});
|
|
99
|
+
if (resolved.kind === "ambiguous") {
|
|
100
|
+
return Promise.resolve(ambiguousSameUserError("host_bash"));
|
|
101
|
+
}
|
|
102
|
+
resolvedTargetClientId =
|
|
103
|
+
resolved.kind === "match" ? resolved.clientId : undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Targeted requests must be bound to the same authenticated user as the
|
|
107
|
+
// target client. Fail closed at request time — before pendingInteractions
|
|
108
|
+
// registration and before broadcast — so a same-daemon caller cannot
|
|
109
|
+
// execute on another user's connected client.
|
|
110
|
+
if (resolvedTargetClientId != null) {
|
|
111
|
+
const rejection = enforceSameActorOrErrorResult({
|
|
112
|
+
hub: assistantEventHub,
|
|
113
|
+
sourceActorPrincipalId,
|
|
114
|
+
targetClientId: resolvedTargetClientId,
|
|
115
|
+
op: "host_bash",
|
|
116
|
+
});
|
|
117
|
+
if (rejection) return Promise.resolve(rejection);
|
|
118
|
+
}
|
|
119
|
+
|
|
86
120
|
const requestId = uuid();
|
|
87
121
|
|
|
88
122
|
return new Promise<ToolExecutionResult>((resolve, reject) => {
|
|
89
123
|
const shellMaxTimeoutSec = getConfig().timeouts.shellMaxTimeoutSec;
|
|
90
124
|
const timeoutSec = input.timeout_seconds ?? shellMaxTimeoutSec;
|
|
91
|
-
// Proxy timeout: slightly after client-side timeout, but before executor's outer timeout
|
|
92
125
|
const proxyTimeoutSec = timeoutSec + 3;
|
|
93
126
|
|
|
94
|
-
// Declared up-front so onAbort (defined before detachAbort is assigned)
|
|
95
|
-
// can close over a stable reference once it's wired below.
|
|
96
127
|
let detachAbort: () => void = () => {};
|
|
97
128
|
|
|
98
129
|
const timer = setTimeout(() => {
|
|
99
|
-
this.pending.delete(requestId);
|
|
100
|
-
detachAbort();
|
|
101
130
|
pendingInteractions.resolve(requestId);
|
|
102
131
|
log.warn(
|
|
103
132
|
{ requestId, command: input.command },
|
|
104
133
|
"Host bash proxy request timed out",
|
|
105
134
|
);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
null,
|
|
111
|
-
true,
|
|
112
|
-
timeoutSec,
|
|
113
|
-
),
|
|
114
|
-
);
|
|
135
|
+
const timeoutMessage = resolvedTargetClientId
|
|
136
|
+
? `Host bash proxy timed out waiting for response from client ${resolvedTargetClientId}`
|
|
137
|
+
: "Host bash proxy timed out waiting for client response";
|
|
138
|
+
resolve(formatShellOutput("", timeoutMessage, null, true, timeoutSec));
|
|
115
139
|
}, proxyTimeoutSec * 1000);
|
|
116
140
|
|
|
117
141
|
if (signal) {
|
|
118
142
|
const onAbort = () => {
|
|
119
|
-
if (
|
|
120
|
-
clearTimeout(timer);
|
|
121
|
-
this.pending.delete(requestId);
|
|
122
|
-
detachAbort();
|
|
143
|
+
if (pendingInteractions.get(requestId)) {
|
|
123
144
|
pendingInteractions.resolve(requestId);
|
|
124
145
|
try {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
146
|
+
broadcastMessage(
|
|
147
|
+
{
|
|
148
|
+
type: "host_bash_cancel",
|
|
149
|
+
requestId,
|
|
150
|
+
conversationId,
|
|
151
|
+
targetClientId: resolvedTargetClientId,
|
|
152
|
+
},
|
|
128
153
|
conversationId,
|
|
129
|
-
|
|
154
|
+
{ targetClientId: resolvedTargetClientId },
|
|
155
|
+
);
|
|
130
156
|
} catch {
|
|
131
|
-
// Best-effort cancel notification
|
|
157
|
+
// Best-effort cancel notification
|
|
132
158
|
}
|
|
133
159
|
resolve(formatShellOutput("", "Aborted", null, false, 0));
|
|
134
160
|
}
|
|
@@ -137,31 +163,41 @@ export class HostBashProxy {
|
|
|
137
163
|
detachAbort = () => signal.removeEventListener("abort", onAbort);
|
|
138
164
|
}
|
|
139
165
|
|
|
140
|
-
|
|
141
|
-
resolve,
|
|
142
|
-
reject,
|
|
143
|
-
timer,
|
|
144
|
-
timeoutSec,
|
|
166
|
+
pendingInteractions.register(requestId, {
|
|
145
167
|
conversationId,
|
|
168
|
+
kind: "host_bash",
|
|
169
|
+
rpcResolve: resolve,
|
|
170
|
+
rpcReject: reject,
|
|
171
|
+
timer,
|
|
146
172
|
detachAbort,
|
|
173
|
+
targetClientId: resolvedTargetClientId,
|
|
174
|
+
targetActorPrincipalId:
|
|
175
|
+
resolvedTargetClientId != null
|
|
176
|
+
? assistantEventHub.getActorPrincipalIdForClient(
|
|
177
|
+
resolvedTargetClientId,
|
|
178
|
+
)
|
|
179
|
+
: undefined,
|
|
180
|
+
metadata: { timeoutSec },
|
|
147
181
|
});
|
|
148
182
|
|
|
149
183
|
try {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
184
|
+
broadcastMessage(
|
|
185
|
+
{
|
|
186
|
+
type: "host_bash_request",
|
|
187
|
+
requestId,
|
|
188
|
+
conversationId,
|
|
189
|
+
command: input.command,
|
|
190
|
+
working_dir: input.working_dir,
|
|
191
|
+
timeout_seconds: input.timeout_seconds,
|
|
192
|
+
targetClientId: resolvedTargetClientId,
|
|
193
|
+
...(input.env && Object.keys(input.env).length > 0
|
|
158
194
|
? { env: input.env }
|
|
159
195
|
: {}),
|
|
160
|
-
}
|
|
196
|
+
},
|
|
197
|
+
conversationId,
|
|
198
|
+
{ targetClientId: resolvedTargetClientId },
|
|
199
|
+
);
|
|
161
200
|
} catch (err) {
|
|
162
|
-
clearTimeout(timer);
|
|
163
|
-
this.pending.delete(requestId);
|
|
164
|
-
detachAbort();
|
|
165
201
|
pendingInteractions.resolve(requestId);
|
|
166
202
|
log.warn(
|
|
167
203
|
{ requestId, command: input.command, err },
|
|
@@ -172,7 +208,10 @@ export class HostBashProxy {
|
|
|
172
208
|
});
|
|
173
209
|
}
|
|
174
210
|
|
|
175
|
-
|
|
211
|
+
/**
|
|
212
|
+
* Process a client result and resolve the RPC. Called by route handlers.
|
|
213
|
+
*/
|
|
214
|
+
resolveResult(
|
|
176
215
|
requestId: string,
|
|
177
216
|
response: {
|
|
178
217
|
stdout: string;
|
|
@@ -181,49 +220,45 @@ export class HostBashProxy {
|
|
|
181
220
|
timedOut: boolean;
|
|
182
221
|
},
|
|
183
222
|
): void {
|
|
184
|
-
const
|
|
185
|
-
if (!
|
|
223
|
+
const interaction = pendingInteractions.resolve(requestId);
|
|
224
|
+
if (!interaction?.rpcResolve) {
|
|
186
225
|
log.warn({ requestId }, "No pending host bash request for response");
|
|
187
226
|
return;
|
|
188
227
|
}
|
|
189
|
-
|
|
190
|
-
entry.detachAbort();
|
|
191
|
-
this.pending.delete(requestId);
|
|
228
|
+
const timeoutSec = (interaction.metadata?.timeoutSec as number) ?? 0;
|
|
192
229
|
const result = formatShellOutput(
|
|
193
230
|
response.stdout,
|
|
194
231
|
response.stderr,
|
|
195
232
|
response.exitCode,
|
|
196
233
|
response.timedOut,
|
|
197
|
-
|
|
234
|
+
timeoutSec,
|
|
198
235
|
);
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
hasPendingRequest(requestId: string): boolean {
|
|
203
|
-
return this.pending.has(requestId);
|
|
236
|
+
interaction.rpcResolve(result);
|
|
204
237
|
}
|
|
205
238
|
|
|
206
239
|
dispose(): void {
|
|
207
|
-
for (const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
this.send({
|
|
240
|
+
for (const entry of pendingInteractions.getByKind("host_bash")) {
|
|
241
|
+
pendingInteractions.resolve(entry.requestId);
|
|
242
|
+
try {
|
|
243
|
+
broadcastMessage(
|
|
244
|
+
{
|
|
213
245
|
type: "host_bash_cancel",
|
|
214
|
-
requestId,
|
|
246
|
+
requestId: entry.requestId,
|
|
215
247
|
conversationId: entry.conversationId,
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
248
|
+
targetClientId: entry.targetClientId,
|
|
249
|
+
},
|
|
250
|
+
entry.conversationId,
|
|
251
|
+
{ targetClientId: entry.targetClientId },
|
|
252
|
+
);
|
|
253
|
+
} catch {
|
|
254
|
+
// Best-effort cancel notification — connection may already be closed.
|
|
255
|
+
}
|
|
256
|
+
entry.rpcReject?.(
|
|
221
257
|
new AssistantError(
|
|
222
258
|
"Host bash proxy disposed",
|
|
223
259
|
ErrorCode.INTERNAL_ERROR,
|
|
224
260
|
),
|
|
225
261
|
);
|
|
226
262
|
}
|
|
227
|
-
this.pending.clear();
|
|
228
263
|
}
|
|
229
264
|
}
|