@vellumai/assistant 0.12.1 → 0.12.2-dev.202609162314.7778bc8

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.
Files changed (872) hide show
  1. package/.env.example +2 -0
  2. package/AGENTS.md +5 -1
  3. package/ARCHITECTURE.md +20 -21
  4. package/Dockerfile +7 -7
  5. package/docs/architecture/integrations.md +7 -0
  6. package/docs/architecture/memory.md +11 -2
  7. package/docs/architecture/turn-actor.md +15 -8
  8. package/docs/credential-execution-service.md +1 -1
  9. package/docs/desktop-browser-cli.md +35 -0
  10. package/docs/guardian-request-flow.md +16 -0
  11. package/node_modules/@vellumai/environments/src/shell.test.ts +21 -0
  12. package/node_modules/@vellumai/environments/src/shell.ts +24 -0
  13. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -2
  14. package/node_modules/@vellumai/slack-text/src/index.ts +13 -8
  15. package/node_modules/@vellumai/slack-text/src/label-resolution-entities.test.ts +95 -0
  16. package/openapi.yaml +579 -111
  17. package/package.json +7 -4
  18. package/scripts/bundled-plugin-packages.ts +154 -0
  19. package/scripts/generate-bundled-plugin-packages.ts +29 -0
  20. package/scripts/postinstall.ts +33 -0
  21. package/scripts/smoke-desktop-browser-cli.ts +280 -0
  22. package/scripts/smoke-desktop-window-theme.ts +186 -0
  23. package/scripts/sync-llm-catalog.ts +3 -0
  24. package/scripts/test.ts +15 -13
  25. package/scripts/voice-ttft-spike.ts +2 -2
  26. package/src/__tests__/agent-loop.test.ts +259 -0
  27. package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
  28. package/src/__tests__/anthropic-provider.test.ts +55 -63
  29. package/src/__tests__/app-compiler.test.ts +6 -0
  30. package/src/__tests__/app-control-tool-schemas.test.ts +5 -2
  31. package/src/__tests__/app-dir-path-guard.test.ts +1 -3
  32. package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
  33. package/src/__tests__/assistant-event-hub-machine-name.test.ts +6 -7
  34. package/src/__tests__/assistant-event-hub.test.ts +44 -0
  35. package/src/__tests__/attachments-store.test.ts +22 -3
  36. package/src/__tests__/channel-approval.test.ts +9 -14
  37. package/src/__tests__/channel-reply-delivery.test.ts +56 -0
  38. package/src/__tests__/computer-use-screenshot-attachments.test.ts +411 -0
  39. package/src/__tests__/computer-use-screenshot-selection.test.ts +50 -0
  40. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
  41. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
  42. package/src/__tests__/computer-use-tools.test.ts +19 -7
  43. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  44. package/src/__tests__/config-schema.test.ts +29 -30
  45. package/src/__tests__/config-sounds-sync.test.ts +23 -0
  46. package/src/__tests__/config-watcher.test.ts +23 -8
  47. package/src/__tests__/connection-model-compat.test.ts +2 -2
  48. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  49. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
  50. package/src/__tests__/conversation-agent-loop.test.ts +257 -6
  51. package/src/__tests__/conversation-attachments.test.ts +106 -0
  52. package/src/__tests__/conversation-error.test.ts +4 -1
  53. package/src/__tests__/conversation-fork-crud.test.ts +191 -0
  54. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  55. package/src/__tests__/conversation-pairing.test.ts +26 -0
  56. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -10
  57. package/src/__tests__/conversation-queue.test.ts +48 -207
  58. package/src/__tests__/conversation-retry-discard.test.ts +54 -1
  59. package/src/__tests__/conversation-runtime-assembly.test.ts +33 -3
  60. package/src/__tests__/conversation-skill-tools.test.ts +27 -0
  61. package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
  62. package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +1 -0
  63. package/src/__tests__/conversation-surfaces-point-at-capability.test.ts +1 -0
  64. package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
  65. package/src/__tests__/conversation-title-service.test.ts +14 -10
  66. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
  67. package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
  68. package/src/__tests__/credential-execution-client.test.ts +70 -53
  69. package/src/__tests__/credential-record-retire.test.ts +171 -1
  70. package/src/__tests__/credential-routes.test.ts +250 -3
  71. package/src/__tests__/credential-security-invariants.test.ts +5 -3
  72. package/src/__tests__/cu-unified-flow.test.ts +14 -4
  73. package/src/__tests__/db-conversation-tool-surface.test.ts +144 -0
  74. package/src/__tests__/document-sync-tags.test.ts +25 -0
  75. package/src/__tests__/drain-kick-guard.test.ts +0 -2
  76. package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
  77. package/src/__tests__/events-tail-route.test.ts +33 -0
  78. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  79. package/src/__tests__/external-plugin-loader.test.ts +52 -0
  80. package/src/__tests__/git-porcelain.test.ts +47 -0
  81. package/src/__tests__/headless-browser-mode.test.ts +48 -0
  82. package/src/__tests__/heartbeat-service.test.ts +56 -40
  83. package/src/__tests__/helpers/set-workspace-mcp.ts +11 -0
  84. package/src/__tests__/history-repair.test.ts +53 -0
  85. package/src/__tests__/host-bash-proxy.test.ts +26 -45
  86. package/src/__tests__/host-browser-proxy.test.ts +6 -17
  87. package/src/__tests__/host-cu-proxy.test.ts +712 -18
  88. package/src/__tests__/host-file-proxy-targeted.test.ts +23 -0
  89. package/src/__tests__/host-file-proxy.test.ts +11 -23
  90. package/src/__tests__/host-transfer-proxy-targeted.test.ts +30 -9
  91. package/src/__tests__/inference-profile-session-handler.test.ts +26 -0
  92. package/src/__tests__/list-all-apps.test.ts +40 -8
  93. package/src/__tests__/list-messages-camera-frame.test.ts +121 -0
  94. package/src/__tests__/list-messages-tool-merge.test.ts +85 -1
  95. package/src/__tests__/llm-catalog-parity.test.ts +51 -3
  96. package/src/__tests__/managed-store.test.ts +121 -0
  97. package/src/__tests__/mcp-auth-routes.test.ts +104 -8
  98. package/src/__tests__/mcp-client-auth.test.ts +54 -0
  99. package/src/__tests__/mcp-config-secret-boundary.test.ts +78 -136
  100. package/src/__tests__/mcp-health-check.test.ts +40 -43
  101. package/src/__tests__/mcp-list-plugin-servers.test.ts +85 -42
  102. package/src/__tests__/mcp-tool-annotations-risk.test.ts +4 -2
  103. package/src/__tests__/message-deleted-hook-dispatch.test.ts +119 -0
  104. package/src/__tests__/messages-after-tiebreaker.test.ts +91 -0
  105. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  106. package/src/__tests__/messaging-send-tool.test.ts +355 -548
  107. package/src/__tests__/model-intents.test.ts +3 -0
  108. package/src/__tests__/notification-vellum-adapter.test.ts +85 -2
  109. package/src/__tests__/oauth-apps-routes.test.ts +1 -0
  110. package/src/__tests__/oauth-commands-routes.test.ts +282 -101
  111. package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
  112. package/src/__tests__/oauth-provider-profiles.test.ts +18 -0
  113. package/src/__tests__/oauth-provider-serializer.test.ts +23 -0
  114. package/src/__tests__/oauth-providers-routes.test.ts +3 -0
  115. package/src/__tests__/openai-provider.test.ts +1 -0
  116. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  117. package/src/__tests__/persist-media-references.test.ts +50 -0
  118. package/src/__tests__/platform-callback-registration.test.ts +8 -16
  119. package/src/__tests__/platform-client-verify-credential.test.ts +2 -0
  120. package/src/__tests__/plugin-import-boundary-guard.test.ts +13 -0
  121. package/src/__tests__/qdrant-manager.test.ts +132 -0
  122. package/src/__tests__/resolve-app.test.ts +135 -0
  123. package/src/__tests__/run-conversation-turn-persistence.test.ts +138 -1
  124. package/src/__tests__/scaffold-managed-skill-tool.test.ts +317 -6
  125. package/src/__tests__/schedule-routes.test.ts +20 -0
  126. package/src/__tests__/scheduler-result-notification.test.ts +23 -4
  127. package/src/__tests__/script-proxy-certs.test.ts +35 -0
  128. package/src/__tests__/secret-routes-acp-guard.test.ts +59 -1
  129. package/src/__tests__/secret-routes-platform-proxy.test.ts +86 -31
  130. package/src/__tests__/secret-routes-scrub.test.ts +22 -27
  131. package/src/__tests__/secure-keys-managed-failover.test.ts +8 -0
  132. package/src/__tests__/secure-keys.test.ts +7 -3
  133. package/src/__tests__/server-tool-pairing.test.ts +107 -0
  134. package/src/__tests__/service-account-token.test.ts +247 -0
  135. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  136. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  137. package/src/__tests__/skills.test.ts +20 -4
  138. package/src/__tests__/source-fingerprint.test.ts +184 -0
  139. package/src/__tests__/subagent-tool-gate-mode.test.ts +239 -3
  140. package/src/__tests__/subagent-tools.test.ts +3 -2
  141. package/src/__tests__/telephony-tts-guard.test.ts +38 -3
  142. package/src/__tests__/terminal-tools.test.ts +8 -0
  143. package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
  144. package/src/__tests__/tool-result-follow-up.test.ts +99 -0
  145. package/src/__tests__/tool-result-metadata-plumbing.test.ts +63 -0
  146. package/src/__tests__/ui-channel-variants.test.ts +1 -56
  147. package/src/__tests__/unicode.test.ts +49 -0
  148. package/src/__tests__/user-plugin-loader.test.ts +21 -0
  149. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +4 -0
  150. package/src/__tests__/watch-retro-tool-availability.test.ts +8 -17
  151. package/src/__tests__/workspace-git-service.test.ts +26 -0
  152. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +336 -0
  153. package/src/acp/__tests__/acp-claude-oauth.test.ts +257 -6
  154. package/src/acp/__tests__/acp-credentials.test.ts +13 -0
  155. package/src/acp/__tests__/agent-process.test.ts +258 -4
  156. package/src/acp/__tests__/auth-required.test.ts +96 -0
  157. package/src/acp/__tests__/claude-token-refresh.test.ts +257 -0
  158. package/src/acp/__tests__/client-handler.test.ts +90 -2
  159. package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
  160. package/src/acp/__tests__/prepare-agent-env.test.ts +60 -1
  161. package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
  162. package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
  163. package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
  164. package/src/acp/__tests__/session-manager.test.ts +895 -4
  165. package/src/acp/acp-claude-oauth.ts +328 -14
  166. package/src/acp/acp-credentials.ts +19 -0
  167. package/src/acp/agent-process.test.ts +4 -1
  168. package/src/acp/agent-process.ts +96 -10
  169. package/src/acp/auth-required.ts +50 -1
  170. package/src/acp/auto-install.test.ts +9 -7
  171. package/src/acp/claude-token-refresh.ts +150 -0
  172. package/src/acp/client-handler.ts +16 -3
  173. package/src/acp/model-config.test.ts +166 -0
  174. package/src/acp/model-config.ts +138 -0
  175. package/src/acp/prepare-agent-env.ts +21 -6
  176. package/src/acp/resolve-agent.test.ts +220 -6
  177. package/src/acp/resolve-agent.ts +88 -23
  178. package/src/acp/session-manager.test.ts +196 -3
  179. package/src/acp/session-manager.ts +441 -18
  180. package/src/acp/session-snapshot.ts +260 -0
  181. package/src/acp/types.ts +50 -5
  182. package/src/agent/loop.ts +38 -12
  183. package/src/agent/tool-result-follow-up.ts +70 -0
  184. package/src/api/attachment-provenance.test.ts +68 -0
  185. package/src/api/computer-use-tool.test.ts +55 -0
  186. package/src/api/computer-use-tool.ts +27 -0
  187. package/src/api/events/acp-session-model-update.test.ts +88 -0
  188. package/src/api/events/acp-session-model-update.ts +46 -0
  189. package/src/api/events/app-files-changed.ts +4 -3
  190. package/src/api/events/assistant-outbound-attachment.ts +3 -0
  191. package/src/api/events/desktop-activity-changed.ts +10 -0
  192. package/src/api/events/notification-intent.ts +2 -0
  193. package/src/api/events/question-request.ts +1 -0
  194. package/src/api/events/user-message-echo.ts +7 -1
  195. package/src/api/index.ts +17 -0
  196. package/src/api/responses/conversation-message.ts +8 -0
  197. package/src/approvals/approval-primitive.ts +5 -2
  198. package/src/approvals/scoped-approval-grants.ts +6 -2
  199. package/src/apps/app-store.ts +7 -6
  200. package/src/apps/resolve-app.ts +81 -0
  201. package/src/apps/source-fingerprint.ts +266 -0
  202. package/src/avatar/identity-avatar.ts +7 -2
  203. package/src/browser/operations.ts +2 -1
  204. package/src/browser/types.ts +7 -0
  205. package/src/browser/virtual-desktop-target.ts +34 -0
  206. package/src/bundler/app-compiler.ts +15 -0
  207. package/src/calls/__tests__/barge-in-guard.test.ts +81 -0
  208. package/src/{__tests__ → calls/__tests__}/call-controller.test.ts +503 -82
  209. package/src/{__tests__ → calls/__tests__}/media-stream-audio-transcode.test.ts +1 -1
  210. package/src/{__tests__ → calls/__tests__}/media-stream-output.test.ts +37 -8
  211. package/src/{__tests__ → calls/__tests__}/media-stream-parser.test.ts +1 -1
  212. package/src/{__tests__ → calls/__tests__}/media-stream-server-integration.test.ts +150 -57
  213. package/src/{__tests__ → calls/__tests__}/media-stream-stt-session.test.ts +5 -5
  214. package/src/{__tests__ → calls/__tests__}/media-turn-detector.test.ts +1 -1
  215. package/src/{live-voice → calls}/__tests__/progress-narration.test.ts +27 -4
  216. package/src/{live-voice → calls}/__tests__/progress-phrases.test.ts +1 -1
  217. package/src/calls/__tests__/voice-control-protocol.test.ts +151 -27
  218. package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
  219. package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
  220. package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
  221. package/src/calls/__tests__/voice-session-bridge.test.ts +140 -3
  222. package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
  223. package/src/calls/barge-in-guard.ts +118 -0
  224. package/src/calls/call-constants.ts +24 -4
  225. package/src/calls/call-controller.ts +499 -199
  226. package/src/calls/call-transport.ts +16 -0
  227. package/src/calls/media-stream-output.ts +32 -0
  228. package/src/calls/media-stream-server.ts +82 -30
  229. package/src/calls/media-stream-stt-session.ts +15 -0
  230. package/src/{live-voice → calls}/progress-narration.ts +17 -4
  231. package/src/calls/resolve-call-tts-provider.ts +33 -2
  232. package/src/calls/tts-call-strategy.ts +9 -5
  233. package/src/calls/types.ts +2 -0
  234. package/src/calls/voice-control-protocol.ts +194 -21
  235. package/src/calls/voice-leg-coordinator.ts +189 -0
  236. package/src/calls/voice-progress-cadence.ts +423 -0
  237. package/src/calls/voice-session-bridge.ts +140 -76
  238. package/src/calls/voice-triage-escalate.ts +178 -59
  239. package/src/cli/commands/__tests__/apps.test.ts +245 -0
  240. package/src/cli/commands/__tests__/bash.test.ts +53 -0
  241. package/src/cli/commands/__tests__/browser.test.ts +84 -3
  242. package/src/cli/commands/__tests__/cli-test-harness.ts +21 -3
  243. package/src/cli/commands/__tests__/plugins.test.ts +85 -0
  244. package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
  245. package/src/cli/commands/__tests__/schedules.test.ts +14 -0
  246. package/src/cli/commands/apps.help.ts +67 -13
  247. package/src/cli/commands/apps.ts +183 -0
  248. package/src/cli/commands/bash.help.ts +9 -13
  249. package/src/cli/commands/bash.ts +7 -25
  250. package/src/cli/commands/browser.help.ts +47 -0
  251. package/src/cli/commands/browser.ts +52 -8
  252. package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
  253. package/src/cli/commands/channels/index.help.ts +70 -2
  254. package/src/cli/commands/channels/index.ts +16 -3
  255. package/src/cli/commands/channels/send.ts +128 -0
  256. package/src/cli/commands/credentials.help.ts +9 -5
  257. package/src/cli/commands/credentials.ts +2 -2
  258. package/src/cli/commands/mcp.help.ts +8 -8
  259. package/src/cli/commands/mcp.ts +1 -1
  260. package/src/cli/commands/oauth/index.help.ts +10 -0
  261. package/src/cli/commands/oauth/providers.ts +12 -0
  262. package/src/cli/commands/oauth/request.test.ts +179 -2
  263. package/src/cli/commands/oauth/request.ts +41 -10
  264. package/src/cli/commands/oauth/status.ts +5 -0
  265. package/src/cli/commands/plugins.ts +73 -23
  266. package/src/cli/commands/roadmap.help.ts +5 -1
  267. package/src/cli/commands/roadmap.ts +1 -1
  268. package/src/cli/commands/schedules.ts +2 -0
  269. package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
  270. package/src/cli/lib/__tests__/install-from-github.test.ts +219 -0
  271. package/src/cli/lib/__tests__/install-from-platform.test.ts +77 -2
  272. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +45 -3
  273. package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +251 -0
  274. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +65 -2
  275. package/src/cli/lib/__tests__/plugin-catalog-platform.test.ts +14 -0
  276. package/src/cli/lib/__tests__/plugin-catalog-resolve.test.ts +27 -1
  277. package/src/cli/lib/__tests__/plugin-details.test.ts +35 -2
  278. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +20 -0
  279. package/src/cli/lib/__tests__/plugins-install-offline.test.ts +43 -0
  280. package/src/cli/lib/__tests__/search-plugins.test.ts +31 -0
  281. package/src/cli/lib/__tests__/uninstall-plugin.test.ts +122 -5
  282. package/src/cli/lib/bundled-marketplace.json +962 -81
  283. package/src/cli/lib/bundled-plugin-packages.json +786 -0
  284. package/src/cli/lib/bundled-plugin-packages.ts +87 -0
  285. package/src/cli/lib/diff-plugin.ts +1 -1
  286. package/src/cli/lib/inspect-plugin.ts +87 -12
  287. package/src/cli/lib/install-from-github.ts +150 -94
  288. package/src/cli/lib/install-from-platform.ts +14 -9
  289. package/src/cli/lib/list-installed-plugins.ts +21 -35
  290. package/src/cli/lib/plugin-catalog-cache.ts +22 -3
  291. package/src/cli/lib/plugin-catalog-local.ts +13 -3
  292. package/src/cli/lib/plugin-catalog-platform.ts +6 -1
  293. package/src/cli/lib/plugin-catalog-resolve.ts +20 -0
  294. package/src/cli/lib/plugin-details.ts +33 -8
  295. package/src/cli/lib/plugin-marketplace.ts +121 -21
  296. package/src/cli/lib/plugin-pin-history.ts +5 -2
  297. package/src/cli/lib/search-plugins.ts +58 -16
  298. package/src/cli/lib/uninstall-plugin.ts +59 -1
  299. package/src/cli/lib/upgrade-plugin.ts +61 -8
  300. package/src/cli/output.ts +18 -4
  301. package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
  302. package/src/config/__tests__/default-provider.test.ts +4 -0
  303. package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
  304. package/src/config/__tests__/platform-identity.test.ts +255 -0
  305. package/src/config/__tests__/platform-rehydration.test.ts +99 -9
  306. package/src/config/__tests__/plugin-resident-skill-discovery.test.ts +21 -0
  307. package/src/config/acp-agent-write.ts +43 -0
  308. package/src/config/acp-defaults.test.ts +13 -3
  309. package/src/config/acp-defaults.ts +23 -6
  310. package/src/config/acp-schema.test.ts +81 -0
  311. package/src/config/acp-schema.ts +30 -2
  312. package/src/config/bundled-skills/acp/SKILL.md +23 -15
  313. package/src/config/bundled-skills/acp/TOOLS.json +7 -3
  314. package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
  315. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  316. package/src/config/bundled-skills/computer-use/SKILL.md +59 -2
  317. package/src/config/bundled-skills/computer-use/TOOLS.json +101 -2
  318. package/src/config/bundled-skills/computer-use/tools/computer-use-sequence.ts +12 -0
  319. package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -1
  320. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -1
  321. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -1
  322. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  323. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  324. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +67 -139
  325. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  326. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -1
  327. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -1
  328. package/src/config/bundled-skills/schedule/SKILL.md +7 -8
  329. package/src/config/bundled-skills/screen-annotation/SKILL.md +10 -3
  330. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +4 -1
  331. package/src/config/bundled-skills/skill-management/SKILL.md +1 -1
  332. package/src/config/bundled-skills/skill-management/TOOLS.json +13 -9
  333. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +5 -2
  334. package/src/config/default-profile-catalog.ts +1 -1
  335. package/src/config/env.ts +2 -2
  336. package/src/config/feature-flag-registry.json +33 -13
  337. package/src/config/loader.ts +11 -17
  338. package/src/config/memory-v3-gate.test.ts +31 -0
  339. package/src/config/memory-v3-gate.ts +20 -16
  340. package/src/config/platform-identity.ts +201 -0
  341. package/src/config/platform-rehydration.ts +11 -27
  342. package/src/config/profile-text-generation.test.ts +51 -0
  343. package/src/config/profile-text-generation.ts +51 -0
  344. package/src/config/schema.ts +2 -2
  345. package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
  346. package/src/config/schemas/__tests__/voice.test.ts +148 -0
  347. package/src/config/schemas/calls.ts +1 -28
  348. package/src/config/schemas/live-voice.ts +1 -173
  349. package/src/config/schemas/llm.ts +7 -2
  350. package/src/config/schemas/mcp.ts +15 -9
  351. package/src/config/schemas/memory-retrospective.ts +10 -0
  352. package/src/config/schemas/monitoring.ts +9 -0
  353. package/src/config/schemas/services.ts +18 -0
  354. package/src/config/schemas/skills.ts +0 -14
  355. package/src/config/schemas/voice.ts +150 -0
  356. package/src/config/skills.ts +13 -21
  357. package/src/credential-execution/ces-runtime.ts +2 -2
  358. package/src/credential-execution/executable-discovery.ts +36 -134
  359. package/src/credential-execution/process-manager.test.ts +37 -42
  360. package/src/credential-execution/process-manager.ts +24 -19
  361. package/src/credential-health/credential-health-service.ts +11 -17
  362. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +47 -0
  363. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -121
  364. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +5 -1
  365. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +133 -0
  366. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +36 -0
  367. package/src/daemon/app-change-notify.ts +45 -0
  368. package/src/daemon/assistant-attachments.ts +20 -12
  369. package/src/daemon/config-watcher.ts +13 -194
  370. package/src/daemon/conversation-agent-loop-handlers.ts +74 -3
  371. package/src/daemon/conversation-agent-loop.ts +12 -0
  372. package/src/daemon/conversation-attachments.ts +93 -12
  373. package/src/daemon/conversation-client-surface.ts +26 -0
  374. package/src/daemon/conversation-error.ts +3 -2
  375. package/src/daemon/conversation-media-retry.ts +2 -1
  376. package/src/daemon/conversation-process.ts +35 -64
  377. package/src/daemon/conversation-runtime-assembly.ts +21 -8
  378. package/src/daemon/conversation-skill-tools.ts +13 -31
  379. package/src/daemon/conversation-store.ts +1 -1
  380. package/src/daemon/conversation-surfaces.ts +21 -10
  381. package/src/daemon/conversation-tool-setup.ts +135 -109
  382. package/src/daemon/conversation-turn-finalize.ts +26 -13
  383. package/src/daemon/conversation.ts +17 -3
  384. package/src/daemon/daemon-control.ts +3 -7
  385. package/src/daemon/dictation-profile-store.ts +2 -1
  386. package/src/daemon/handlers/shared.ts +2 -1
  387. package/src/daemon/handlers/skills.ts +6 -3
  388. package/src/daemon/host-bash-proxy.ts +8 -12
  389. package/src/daemon/host-browser-proxy.ts +15 -1
  390. package/src/daemon/host-cu-proxy.ts +275 -45
  391. package/src/daemon/host-file-proxy.ts +8 -10
  392. package/src/daemon/host-proxy-preactivation.ts +4 -1
  393. package/src/daemon/host-transfer-proxy.ts +14 -18
  394. package/src/daemon/lifecycle.ts +4 -9
  395. package/src/daemon/mcp-reload-service.ts +13 -6
  396. package/src/daemon/message-types/shared.ts +1 -0
  397. package/src/daemon/message-types/sync.ts +2 -0
  398. package/src/daemon/orphan-reaper.ts +4 -3
  399. package/src/daemon/persist-media-references.ts +20 -3
  400. package/src/daemon/providers-setup.ts +5 -1
  401. package/src/daemon/reaction-history-render.ts +2 -1
  402. package/src/daemon/shutdown-handlers.ts +1 -9
  403. package/src/daemon/skill-memory-refresh.ts +64 -0
  404. package/src/daemon/tool-setup-types.ts +6 -0
  405. package/src/daemon/tool-side-effects.ts +7 -18
  406. package/src/daemon/wake-conversation-ops.ts +38 -15
  407. package/src/desktop/__tests__/fake-desktop.ts +123 -0
  408. package/src/desktop/desktop-automation-lease.test.ts +438 -0
  409. package/src/desktop/desktop-automation-lease.ts +355 -0
  410. package/src/desktop/desktop-browser-client.test.ts +413 -0
  411. package/src/desktop/desktop-browser-client.ts +430 -0
  412. package/src/desktop/desktop-browser-cursor.ts +40 -0
  413. package/src/desktop/desktop-browser-endpoint.test.ts +78 -0
  414. package/src/desktop/desktop-browser-endpoint.ts +145 -0
  415. package/src/desktop/desktop-browser-operations.ts +130 -0
  416. package/src/desktop/desktop-chrome-policy.test.ts +79 -0
  417. package/src/desktop/desktop-chrome-policy.ts +47 -0
  418. package/src/desktop/desktop-chrome-session.test.ts +48 -0
  419. package/src/desktop/desktop-chrome-session.ts +87 -0
  420. package/src/desktop/desktop-dependencies.test.ts +131 -0
  421. package/src/desktop/desktop-dependencies.ts +329 -0
  422. package/src/desktop/desktop-display.ts +9 -0
  423. package/src/desktop/desktop-help.ts +16 -0
  424. package/src/desktop/desktop-panel-config.test.ts +135 -0
  425. package/src/desktop/desktop-panel-config.ts +162 -0
  426. package/src/desktop/desktop-session-manager.test.ts +813 -0
  427. package/src/desktop/desktop-session-manager.ts +970 -0
  428. package/src/desktop/desktop-stream-bridge.test.ts +395 -0
  429. package/src/desktop/desktop-stream-bridge.ts +214 -0
  430. package/src/desktop/desktop-wallpaper.test.ts +191 -0
  431. package/src/desktop/desktop-wallpaper.ts +113 -0
  432. package/src/desktop/desktop-window-drag.ts +177 -0
  433. package/src/desktop/desktop-window-manager-config.test.ts +230 -0
  434. package/src/desktop/desktop-window-manager-config.ts +238 -0
  435. package/src/desktop/desktop-window-theme.ts +170 -0
  436. package/src/desktop/virtual-desktop-feature.ts +18 -0
  437. package/src/desktop/virtual-desktop-platform.test.ts +61 -0
  438. package/src/heartbeat/heartbeat-service.ts +21 -3
  439. package/src/home/__tests__/feed-writer.test.ts +22 -0
  440. package/src/home/feed-writer.ts +11 -2
  441. package/src/hooks/types.ts +33 -0
  442. package/src/i18n/AGENTS.md +22 -0
  443. package/src/i18n/__tests__/i18n.test.ts +112 -0
  444. package/src/i18n/index.ts +16 -0
  445. package/src/i18n/locales.ts +93 -0
  446. package/src/i18n/messages.ts +70 -0
  447. package/src/i18n/title.ts +25 -0
  448. package/src/inbound/platform-callback-registration.ts +4 -5
  449. package/src/ipc/__tests__/browser-ipc.test.ts +230 -2
  450. package/src/ipc/__tests__/cancel-on-disconnect.test.ts +54 -0
  451. package/src/ipc/assistant-server.ts +15 -1
  452. package/src/ipc/cli-client.ts +13 -5
  453. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +143 -0
  454. package/src/live-voice/__tests__/live-voice-events.test.ts +9 -7
  455. package/src/live-voice/__tests__/live-voice-look-follow-up.test.ts +374 -0
  456. package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
  457. package/src/live-voice/__tests__/live-voice-progress.test.ts +94 -15
  458. package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +19 -0
  459. package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +238 -0
  460. package/src/live-voice/__tests__/live-voice-vad.test.ts +660 -5
  461. package/src/live-voice/__tests__/protocol.test.ts +95 -0
  462. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
  463. package/src/live-voice/__tests__/session-controls.test.ts +156 -0
  464. package/src/live-voice/live-voice-metrics.ts +9 -0
  465. package/src/live-voice/live-voice-photo.ts +25 -6
  466. package/src/live-voice/live-voice-session.ts +1081 -760
  467. package/src/live-voice/protocol.ts +89 -2
  468. package/src/live-voice/session-controls.ts +197 -0
  469. package/src/mcp/__tests__/credential-target.test.ts +59 -0
  470. package/src/mcp/__tests__/effective-config.test.ts +13 -2
  471. package/src/mcp/__tests__/manager-state.test.ts +128 -0
  472. package/src/mcp/__tests__/manager-tool-caps.test.ts +111 -0
  473. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +20 -6
  474. package/src/mcp/__tests__/mcp-auth-state-target.test.ts +49 -0
  475. package/src/mcp/__tests__/plugin-mcp-oauth-cleanup.test.ts +107 -0
  476. package/src/mcp/__tests__/plugin-mcp-oauth-provider-isolation.test.ts +89 -0
  477. package/src/mcp/__tests__/plugin-server-credential-isolation.test.ts +63 -11
  478. package/src/mcp/__tests__/reload-signal-emission.test.ts +39 -2
  479. package/src/mcp/__tests__/startup.test.ts +30 -7
  480. package/src/mcp/__tests__/tool-caps.test.ts +107 -0
  481. package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
  482. package/src/mcp/client.ts +64 -16
  483. package/src/mcp/credential-target.ts +105 -0
  484. package/src/mcp/effective-config.ts +45 -18
  485. package/src/mcp/manager.ts +201 -81
  486. package/src/mcp/mcp-auth-orchestrator.ts +17 -4
  487. package/src/mcp/mcp-auth-state.ts +38 -6
  488. package/src/mcp/mcp-header-store.ts +29 -45
  489. package/src/mcp/mcp-oauth-provider.ts +101 -33
  490. package/src/mcp/spec-schema.ts +111 -0
  491. package/src/mcp/startup.ts +41 -17
  492. package/src/mcp/tool-caps.ts +176 -0
  493. package/src/mcp/workspace-mcp-config.ts +188 -0
  494. package/src/messaging/provider-message-metadata.ts +3 -3
  495. package/src/messaging/provider.ts +10 -3
  496. package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
  497. package/src/messaging/providers/callback-routing.ts +18 -0
  498. package/src/messaging/providers/channel-transport.ts +56 -0
  499. package/src/messaging/providers/discord/transport.ts +17 -0
  500. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
  501. package/src/messaging/providers/slack/adapter.ts +7 -44
  502. package/src/messaging/providers/slack/transport.ts +16 -0
  503. package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
  504. package/src/messaging/providers/telegram-bot/client.ts +0 -26
  505. package/src/messaging/providers/telegram-bot/transport.ts +20 -0
  506. package/src/messaging/providers/whatsapp/adapter.ts +1 -48
  507. package/src/messaging/providers/whatsapp/transport.ts +18 -0
  508. package/src/monitoring/__tests__/mount-watch.test.ts +236 -0
  509. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
  510. package/src/monitoring/mount-watch.ts +348 -0
  511. package/src/monitoring/plugin-auto-update.ts +6 -0
  512. package/src/monitoring/worker.ts +9 -0
  513. package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
  514. package/src/notifications/__tests__/copy-composer.test.ts +70 -0
  515. package/src/notifications/__tests__/decision-engine.test.ts +175 -0
  516. package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
  517. package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
  518. package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
  519. package/src/notifications/adapters/macos.ts +3 -0
  520. package/src/notifications/assistant-reply-producer.ts +8 -3
  521. package/src/notifications/conversation-pairing.ts +36 -16
  522. package/src/notifications/copy-composer.ts +11 -3
  523. package/src/notifications/decision-engine.ts +43 -8
  524. package/src/notifications/delivered-post-record.ts +11 -1
  525. package/src/notifications/guardian-feed-projection.ts +125 -5
  526. package/src/notifications/home-feed-side-effect.ts +55 -7
  527. package/src/notifications/schedule-result-producer.ts +64 -22
  528. package/src/oauth/AGENTS.md +4 -0
  529. package/src/oauth/__tests__/identity-verifier.test.ts +36 -1
  530. package/src/oauth/__tests__/seed-providers-managed.test.ts +149 -0
  531. package/src/oauth/byo-connection.test.ts +105 -0
  532. package/src/oauth/byo-connection.ts +36 -6
  533. package/src/oauth/connection-resolver.test.ts +100 -0
  534. package/src/oauth/connection-resolver.ts +120 -3
  535. package/src/oauth/identity-verifier.ts +24 -0
  536. package/src/oauth/oauth-store.ts +11 -1
  537. package/src/oauth/provider-serializer.ts +10 -0
  538. package/src/oauth/scope-utils.ts +24 -0
  539. package/src/oauth/seed-providers.ts +367 -27
  540. package/src/onboarding/checkin-event.ts +2 -1
  541. package/src/outbound-proxy/certs.ts +3 -5
  542. package/src/permissions/checker.test.ts +11 -6
  543. package/src/permissions/confirmation-guardian-request.test.ts +16 -0
  544. package/src/permissions/confirmation-guardian-request.ts +2 -3
  545. package/src/permissions/question-prompter.test.ts +31 -0
  546. package/src/permissions/question-prompter.ts +2 -0
  547. package/src/persistence/attachments-store.ts +84 -44
  548. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  549. package/src/persistence/conversation-crud.ts +182 -83
  550. package/src/persistence/conversation-lineage.ts +12 -4
  551. package/src/persistence/conversation-plugin-facade.ts +13 -0
  552. package/src/persistence/conversation-queries.ts +2 -2
  553. package/src/persistence/conversation-title-placeholders.ts +23 -0
  554. package/src/persistence/conversation-title-service.ts +9 -26
  555. package/src/persistence/conversation-tool-surface.ts +86 -0
  556. package/src/persistence/conversation-types.test.ts +32 -0
  557. package/src/persistence/conversation-types.ts +26 -4
  558. package/src/persistence/embeddings/qdrant-manager.ts +163 -18
  559. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  560. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  561. package/src/persistence/message-cursor.ts +78 -0
  562. package/src/persistence/message-reads.ts +30 -0
  563. package/src/persistence/migrations/157-invite-contact-id.ts +18 -6
  564. package/src/persistence/migrations/378-create-conversation-tool-surfaces.test.ts +78 -0
  565. package/src/persistence/migrations/378-create-conversation-tool-surfaces.ts +29 -0
  566. package/src/persistence/migrations/379-oauth-providers-response-ok-field.test.ts +92 -0
  567. package/src/persistence/migrations/379-oauth-providers-response-ok-field.ts +32 -0
  568. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +149 -0
  569. package/src/persistence/schema/conversation-tool-surfaces.ts +22 -0
  570. package/src/persistence/schema/index.ts +1 -0
  571. package/src/persistence/schema/memory-core.ts +5 -0
  572. package/src/persistence/schema/oauth.ts +1 -0
  573. package/src/persistence/steps.ts +15 -3
  574. package/src/platform/client.test.ts +4 -2
  575. package/src/platform/client.ts +2 -10
  576. package/src/plugin-api/constants.ts +2 -0
  577. package/src/plugin-api/conversation-turn.ts +31 -7
  578. package/src/plugin-api/index.ts +10 -1
  579. package/src/plugin-api/plugin-channel-turn-trust.test.ts +133 -0
  580. package/src/plugin-api/plugin-channel-turn-trust.ts +71 -0
  581. package/src/plugin-api/types.ts +2 -0
  582. package/src/plugins/__tests__/installed-plugin-dirs.test.ts +14 -1
  583. package/src/plugins/__tests__/mcp-servers.test.ts +38 -8
  584. package/src/plugins/defaults/index.ts +2 -0
  585. package/src/plugins/defaults/memory/AGENTS.md +14 -2
  586. package/src/plugins/defaults/memory/__tests__/buffer-file.test.ts +365 -0
  587. package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +43 -0
  588. package/src/plugins/defaults/memory/__tests__/fixtures/buffer-appender.ts +17 -0
  589. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +46 -0
  590. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +118 -0
  591. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +83 -0
  592. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +9 -5
  593. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +66 -10
  594. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +20 -0
  595. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +219 -0
  596. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +31 -0
  597. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +63 -0
  598. package/src/plugins/defaults/memory/__tests__/memory-run-evidence.test.ts +161 -0
  599. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +4 -0
  600. package/src/plugins/defaults/memory/buffer-file.ts +354 -0
  601. package/src/plugins/defaults/memory/buffer-format.ts +40 -0
  602. package/src/plugins/defaults/memory/context-search/agent-runner.ts +3 -3
  603. package/src/plugins/defaults/memory/context-search/format.ts +4 -2
  604. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +7 -3
  605. package/src/plugins/defaults/memory/context-search/sources/workspace.ts +4 -2
  606. package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -8
  607. package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -42
  608. package/src/plugins/defaults/memory/hooks/init.ts +10 -0
  609. package/src/plugins/defaults/memory/hooks/message-deleted.ts +21 -0
  610. package/src/plugins/defaults/memory/hooks/shutdown.ts +2 -0
  611. package/src/plugins/defaults/memory/injectors.ts +4 -3
  612. package/src/plugins/defaults/memory/jobs-worker.ts +13 -0
  613. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +34 -60
  614. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +126 -0
  615. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +79 -0
  616. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +28 -0
  617. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +3 -5
  618. package/src/plugins/defaults/memory/memory-retrospective-job.ts +67 -184
  619. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
  620. package/src/plugins/defaults/memory/memory-retrospective-state.ts +312 -71
  621. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +2 -1
  622. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +5 -3
  623. package/src/plugins/defaults/memory/memory-run-evidence.ts +213 -0
  624. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +9 -0
  625. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +1 -1
  626. package/src/plugins/defaults/memory/startup.ts +28 -2
  627. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +407 -99
  628. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +10 -0
  629. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +107 -7
  630. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
  631. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +307 -86
  632. package/src/plugins/defaults/memory/substrate/consolidation-tool-surface.ts +34 -0
  633. package/src/plugins/defaults/memory/substrate/page-index.ts +7 -1
  634. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +89 -49
  635. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  636. package/src/plugins/defaults/memory/substrate/sweep-job.ts +1 -1
  637. package/src/plugins/defaults/memory/tools.ts +1 -1
  638. package/src/plugins/defaults/memory/v1/graph/consolidation.ts +4 -2
  639. package/src/plugins/defaults/memory/v1/graph/extraction.ts +4 -1
  640. package/src/plugins/defaults/memory/v1/graph/retriever.ts +4 -1
  641. package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +5 -0
  642. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +5 -2
  643. package/src/plugins/defaults/memory/v2/reranker.ts +7 -1
  644. package/src/plugins/defaults/memory/v3/__tests__/card.test.ts +24 -0
  645. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +81 -1
  646. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +87 -0
  647. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +125 -0
  648. package/src/plugins/defaults/memory/v3/__tests__/sections.test.ts +26 -0
  649. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +51 -0
  650. package/src/plugins/defaults/memory/v3/card.ts +4 -2
  651. package/src/plugins/defaults/memory/v3/injector.ts +212 -178
  652. package/src/plugins/defaults/memory/v3/orchestrate.ts +86 -22
  653. package/src/plugins/defaults/memory/v3/pool-select.ts +13 -8
  654. package/src/plugins/defaults/memory/v3/sections.ts +10 -3
  655. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +13 -1
  656. package/src/plugins/defaults/memory/worker.ts +6 -0
  657. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +4 -1
  658. package/src/plugins/defaults/tool-result-truncate/terminal.ts +1 -46
  659. package/src/plugins/external-plugin-loader.ts +49 -86
  660. package/src/plugins/installed-plugin-dirs.ts +6 -4
  661. package/src/plugins/mcp-servers.ts +24 -90
  662. package/src/plugins/mtime-cache.ts +2 -1
  663. package/src/plugins/user-loader.ts +2 -1
  664. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  665. package/src/providers/__tests__/retry-callsite.test.ts +41 -0
  666. package/src/providers/__tests__/retry-outbound-sanitize.test.ts +176 -0
  667. package/src/providers/anthropic/client.ts +0 -47
  668. package/src/providers/gemini/client.ts +9 -23
  669. package/src/providers/gemini-thought-signature.test.ts +63 -0
  670. package/src/providers/gemini-thought-signature.ts +44 -0
  671. package/src/providers/inference/__tests__/endpoint-probe.test.ts +87 -3
  672. package/src/providers/inference/adapter-factory.ts +6 -0
  673. package/src/providers/inference/auth.ts +2 -3
  674. package/src/providers/inference/connection-availability.ts +27 -8
  675. package/src/providers/inference/endpoint-probe.ts +36 -12
  676. package/src/providers/inference/resolve-auth.ts +22 -4
  677. package/src/providers/inference/service-account-token.ts +248 -0
  678. package/src/providers/jev/client.test.ts +260 -0
  679. package/src/providers/jev/client.ts +518 -0
  680. package/src/providers/model-catalog.ts +92 -3
  681. package/src/providers/model-intents.ts +10 -5
  682. package/src/providers/openai/__tests__/chat-completions-output-token-limit.test.ts +141 -0
  683. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +146 -18
  684. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +613 -0
  685. package/src/providers/openai/__tests__/google-thought-signature.test.ts +235 -0
  686. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +83 -1
  687. package/src/providers/openai/chat-completions-provider.ts +212 -79
  688. package/src/providers/openai/codex-models.ts +0 -4
  689. package/src/providers/openai/google-thought-signature.ts +320 -0
  690. package/src/providers/openai/responses-provider.ts +9 -2
  691. package/src/providers/opencode/client.test.ts +240 -4
  692. package/src/providers/opencode/client.ts +129 -3
  693. package/src/providers/openrouter/client.ts +20 -0
  694. package/src/providers/outbound-request-sanitize.ts +96 -0
  695. package/src/providers/retry.ts +30 -19
  696. package/src/providers/server-tool-pairing.ts +16 -7
  697. package/src/providers/unparseable-tool-args.ts +5 -1
  698. package/src/runtime/AGENTS.md +9 -3
  699. package/src/runtime/__tests__/agent-wake.test.ts +86 -1
  700. package/src/runtime/__tests__/channel-send.test.ts +443 -0
  701. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +132 -0
  702. package/src/runtime/__tests__/host-observe.test.ts +40 -1
  703. package/src/runtime/__tests__/live-voice-upgrade.test.ts +58 -0
  704. package/src/runtime/__tests__/runtime-ws-test-utils.ts +72 -0
  705. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +59 -0
  706. package/src/runtime/agent-wake.ts +22 -5
  707. package/src/runtime/assistant-event-hub.ts +21 -3
  708. package/src/runtime/auth/same-actor.ts +38 -3
  709. package/src/runtime/channel-send.ts +316 -0
  710. package/src/runtime/guardian-action-service.ts +2 -17
  711. package/src/runtime/guardian-reply-router.ts +1 -8
  712. package/src/runtime/host-observe.ts +11 -1
  713. package/src/runtime/http-server.ts +160 -151
  714. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +89 -0
  715. package/src/runtime/migrations/vbundle-import-policy.ts +33 -11
  716. package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +16 -5
  717. package/src/runtime/routes/__tests__/acp-routes.test.ts +178 -4
  718. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +275 -0
  719. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
  720. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
  721. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
  722. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
  723. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +24 -2
  724. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
  725. package/src/runtime/routes/__tests__/plugins-routes.test.ts +127 -3
  726. package/src/runtime/routes/acp-claude-auth-routes.ts +11 -3
  727. package/src/runtime/routes/acp-routes.test.ts +15 -0
  728. package/src/runtime/routes/acp-routes.ts +84 -165
  729. package/src/runtime/routes/app-management-routes.ts +90 -2
  730. package/src/runtime/routes/app-routes.ts +1 -1
  731. package/src/runtime/routes/browser-context.ts +39 -0
  732. package/src/runtime/routes/browser-routes.ts +16 -47
  733. package/src/runtime/routes/browser-tabs-routes.ts +72 -29
  734. package/src/runtime/routes/channel-route-shared.ts +1 -9
  735. package/src/runtime/routes/channel-send-routes.ts +85 -0
  736. package/src/runtime/routes/conversation-list-routes.ts +14 -3
  737. package/src/runtime/routes/conversation-query-routes.ts +40 -0
  738. package/src/runtime/routes/conversation-routes.ts +45 -7
  739. package/src/runtime/routes/credential-routes.ts +20 -14
  740. package/src/runtime/routes/desktop-setup-routes.test.ts +89 -0
  741. package/src/runtime/routes/desktop-setup-routes.ts +41 -0
  742. package/src/runtime/routes/diagnostics-routes.ts +61 -4
  743. package/src/runtime/routes/events-routes.ts +4 -0
  744. package/src/runtime/routes/guardian-approval-interception.ts +24 -0
  745. package/src/runtime/routes/host-cu-routes.ts +6 -0
  746. package/src/runtime/routes/inbound-message-handler.ts +2 -3
  747. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +1 -1
  748. package/src/runtime/routes/inbound-stages/background-dispatch.ts +7 -4
  749. package/src/runtime/routes/index.ts +4 -2
  750. package/src/runtime/routes/inference-profile-session-handler.ts +11 -1
  751. package/src/runtime/routes/inference-profiles-routes.ts +9 -0
  752. package/src/runtime/routes/log-export-routes.ts +2 -0
  753. package/src/runtime/routes/mcp-auth-routes.ts +141 -137
  754. package/src/runtime/routes/migration-routes.ts +6 -20
  755. package/src/runtime/routes/oauth-commands-routes.ts +98 -45
  756. package/src/runtime/routes/oauth-providers.ts +11 -0
  757. package/src/runtime/routes/oauth-request-hints.test.ts +246 -0
  758. package/src/runtime/routes/oauth-request-hints.ts +149 -0
  759. package/src/runtime/routes/platform-routes.ts +18 -15
  760. package/src/runtime/routes/plugins-routes.ts +83 -50
  761. package/src/runtime/routes/schedule-routes.ts +2 -0
  762. package/src/runtime/routes/secret-routes.ts +99 -119
  763. package/src/runtime/routes/workspace-routes.test.ts +55 -26
  764. package/src/runtime/routes/workspace-routes.ts +46 -63
  765. package/src/runtime/routes/workspace-tree-walk.test.ts +244 -0
  766. package/src/runtime/routes/workspace-tree-walk.ts +240 -0
  767. package/src/runtime/routes/workspace-utils.ts +17 -0
  768. package/src/runtime/services/__tests__/conversation-serializer.test.ts +28 -0
  769. package/src/runtime/services/conversation-serializer.ts +16 -3
  770. package/src/runtime/sync/resource-sync-events.ts +6 -1
  771. package/src/schedule/__tests__/worker-mcp-bootstrap.test.ts +107 -0
  772. package/src/schedule/__tests__/worker-mcp-readiness.test.ts +173 -0
  773. package/src/schedule/__tests__/worker-mcp-tools.test.ts +13 -47
  774. package/src/schedule/run-script.ts +4 -3
  775. package/src/schedule/schedule-store.ts +9 -2
  776. package/src/schedule/scheduler.ts +47 -11
  777. package/src/schedule/tool-surface-readiness.ts +65 -0
  778. package/src/schedule/worker-mcp.ts +85 -0
  779. package/src/schedule/worker.ts +9 -31
  780. package/src/security/__tests__/ces-http-record-backend.test.ts +137 -0
  781. package/src/security/ces-http-record-backend.ts +120 -0
  782. package/src/security/ces-rpc-record-backend.ts +7 -0
  783. package/src/security/secure-keys.ts +60 -48
  784. package/src/security/untrusted-content.ts +3 -1
  785. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +60 -0
  786. package/src/skills/managed-store.ts +153 -31
  787. package/src/skills/workspace-skill-md-signature.ts +50 -0
  788. package/src/subagent/consult-context.ts +12 -25
  789. package/src/tools/__tests__/side-effect-abort-guard.test.ts +1 -0
  790. package/src/tools/acp/list-agents.test.ts +3 -1
  791. package/src/tools/acp/spawn.test.ts +146 -11
  792. package/src/tools/acp/spawn.ts +21 -3
  793. package/src/tools/acp/status.test.ts +349 -0
  794. package/src/tools/acp/status.ts +112 -9
  795. package/src/tools/app-control/skill-proxy-bridge.ts +2 -1
  796. package/src/tools/ask-question/ask-question-tool.test.ts +167 -5
  797. package/src/tools/ask-question/ask-question-tool.ts +119 -23
  798. package/src/tools/browser/browser-execution.ts +52 -15
  799. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +69 -0
  800. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +9 -3
  801. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +1 -0
  802. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +2 -1
  803. package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +5 -0
  804. package/src/tools/browser/cdp-client/extension-cdp-client.ts +3 -2
  805. package/src/tools/browser/network-recorder.ts +2 -1
  806. package/src/tools/capability-offer.test.ts +22 -2
  807. package/src/tools/capability-offer.ts +16 -1
  808. package/src/tools/computer-use/definitions.ts +123 -5
  809. package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
  810. package/src/tools/credentials/metadata-store.ts +100 -0
  811. package/src/tools/filesystem/search.ts +2 -1
  812. package/src/tools/host-filesystem/edit.test.ts +2 -1
  813. package/src/tools/host-filesystem/edit.ts +2 -2
  814. package/src/tools/host-filesystem/read.test.ts +2 -1
  815. package/src/tools/host-filesystem/read.ts +2 -2
  816. package/src/tools/host-filesystem/transfer.test.ts +2 -1
  817. package/src/tools/host-filesystem/transfer.ts +2 -2
  818. package/src/tools/host-filesystem/write.test.ts +2 -1
  819. package/src/tools/host-filesystem/write.ts +2 -2
  820. package/src/tools/host-terminal/host-shell.test.ts +16 -0
  821. package/src/tools/host-terminal/host-shell.ts +16 -26
  822. package/src/tools/network/web-search.ts +6 -1
  823. package/src/tools/policy-context.ts +6 -7
  824. package/src/tools/shared/filesystem/file-ops-service.ts +1 -31
  825. package/src/tools/shared/shell-output.test.ts +10 -0
  826. package/src/tools/shared/shell-output.ts +14 -2
  827. package/src/tools/skills/find-similar-skills.test.ts +214 -2
  828. package/src/tools/skills/find-similar-skills.ts +62 -9
  829. package/src/tools/skills/resolve-execute-invocation.ts +24 -0
  830. package/src/tools/skills/sandbox-runner.ts +13 -2
  831. package/src/tools/skills/scaffold-managed.ts +78 -16
  832. package/src/tools/subagent/spawn.ts +5 -8
  833. package/src/tools/terminal/__tests__/safe-env.test.ts +33 -4
  834. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +43 -0
  835. package/src/tools/terminal/safe-env.ts +35 -24
  836. package/src/tools/terminal/sanitized-bash.ts +118 -0
  837. package/src/tools/terminal/shell-launch.test.ts +162 -0
  838. package/src/tools/terminal/shell.test.ts +29 -0
  839. package/src/tools/terminal/shell.ts +13 -7
  840. package/src/tools/ui-surface/channel-variants.ts +10 -59
  841. package/src/tools/watch/watch-retro-report.ts +0 -8
  842. package/src/types/host-capabilities.ts +5 -3
  843. package/src/util/__tests__/language-subtag.test.ts +23 -1
  844. package/src/util/abort-reasons.ts +12 -1
  845. package/src/util/browser-human-verification.ts +14 -0
  846. package/src/util/ca-bundle.ts +13 -0
  847. package/src/util/host-process.test.ts +17 -1
  848. package/src/util/host-process.ts +24 -0
  849. package/src/util/language-subtag.ts +16 -0
  850. package/src/util/platform.ts +8 -0
  851. package/src/util/plugin-manifest.ts +203 -0
  852. package/src/util/unicode.ts +44 -1
  853. package/src/watch/watch-retro.ts +6 -8
  854. package/src/watch/watch-timeline.ts +2 -2
  855. package/src/workflows/run-manager.ts +2 -1
  856. package/src/workspace/git-porcelain.ts +66 -0
  857. package/src/workspace/git-service.ts +6 -55
  858. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +258 -0
  859. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +78 -0
  860. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +214 -0
  861. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +102 -0
  862. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +199 -0
  863. package/src/workspace/migrations/registry.ts +6 -0
  864. package/src/__tests__/app-source-watcher.test.ts +0 -218
  865. package/src/__tests__/config-watcher-skill-reseed.test.ts +0 -359
  866. package/src/__tests__/speaker-identification.test.ts +0 -56
  867. package/src/calls/speaker-identification.ts +0 -233
  868. package/src/daemon/app-source-watcher.ts +0 -218
  869. package/src/messaging/providers/whatsapp/client.ts +0 -29
  870. package/src/runtime/routes/debug-bash-routes.ts +0 -173
  871. package/src/util/fs-watcher-error.ts +0 -36
  872. /package/src/{live-voice → calls}/progress-phrases.ts +0 -0
package/.env.example CHANGED
@@ -2,6 +2,8 @@
2
2
  ANTHROPIC_API_KEY=sk-ant-...
3
3
  OPENAI_API_KEY=sk-...
4
4
  GEMINI_API_KEY=...
5
+ # Optional. TypeSafe / Jev System One decision model.
6
+ TYPESAFE_API_KEY=...
5
7
  # Optional for authenticated/proxied Ollama deployments
6
8
  OLLAMA_API_KEY=
7
9
  # Optional override (defaults to http://127.0.0.1:11434/v1)
package/AGENTS.md CHANGED
@@ -16,7 +16,7 @@ When you introduce a new env var that the assistant process needs to read at run
16
16
 
17
17
  **Default to including it.** If the var doesn't contain secrets (e.g. a URL, a feature flag, a path, a mode string), add it. Only omit it if it carries credential material (tokens, passwords, private keys) — those must stay isolated to CES.
18
18
 
19
- `CES_LOCAL_SOCKET` is intentionally included despite the socket exposing credential RPCs: assistant subprocesses are expected to reach CES. Credential protection is rules-based access control inside CES, not socket-path secrecy (see root `AGENTS.md`). `CES_SERVICE_TOKEN` and `CES_CREDENTIAL_URL` are also forwarded: managed children still resolve connections through CES HTTP, and the socket path is not a sufficient substitute yet. See the comment on those keys in `src/tools/terminal/safe-env.ts` before attempting to strip them.
19
+ `CES_BOOTSTRAP_SOCKET_DIR` is forwarded so children can reach CES over IPC. `CES_SERVICE_TOKEN` and `CES_CREDENTIAL_URL` are also forwarded so children can fail over to CES HTTP until that transport is removed. Credential protection is rules-based access control inside CES, not socket-path secrecy (see root `AGENTS.md`).
20
20
 
21
21
  ## Daemon startup philosophy
22
22
 
@@ -87,6 +87,10 @@ The module-level dependency-injection pattern (`registerFooDeps()`) used by some
87
87
 
88
88
  Telemetry event types are defined by a platform-generated wire contract (`src/telemetry/telemetry-wire.generated.ts`) that `src/telemetry/types.ts` layers over, with pre-flush validation against it. Adding a new event type starts platform-side, not here. The mechanics, the drift guards, and the cross-repo ordering are documented next to the code they govern: see [`src/telemetry/AGENTS.md`](src/telemetry/AGENTS.md).
89
89
 
90
+ ## Daemon i18n
91
+
92
+ User-facing copy the daemon generates as a hardcoded constant goes through `src/i18n/`. Persist the message key. Resolve with `t(key, locale)` at the HTTP/CLI/channel edge. Never persist a translated string, and never match stored display strings back to keys. See [`src/i18n/AGENTS.md`](src/i18n/AGENTS.md).
93
+
90
94
  ## Code comments
91
95
 
92
96
  When writing or updating comments, **do not reference code that has been removed.** Comments should describe the current state of the codebase, not narrate its history. Avoid phrases like "no longer does X", "previously used Y", or "was removed in PR Z" — future readers should not need to understand past implementations to understand the current code.
package/ARCHITECTURE.md CHANGED
@@ -609,9 +609,11 @@ Every phone call connects over Twilio Media Streams: the voice webhook emits `<C
609
609
 
610
610
  Transcription mode is selected once per session in `media-stream-stt-session.ts`:
611
611
 
612
- - **Streaming** (default): when `calls.voice.telephonyStreaming` is enabled and the `telephony` role resolves a streaming transcriber (`resolveStreamingTranscriber({ role: "telephony" })`), inbound audio is decoded (mu-law → PCM16, resampled 8 kHz → 16 kHz) and fed to the provider's realtime adapter. Replies trigger only on utterance-boundary finals (for Deepgram, `speech_final`/`UtteranceEnd`, never mid-sentence `is_final` segments), and barge-in fires from local energy VAD, never from transcriber partials.
612
+ - **Streaming** (default): when `calls.voice.telephonyStreaming` is enabled and the `telephony` role resolves a streaming transcriber (`resolveStreamingTranscriber({ role: "telephony" })`), inbound audio is decoded (mu-law → PCM16, resampled 8 kHz → 16 kHz) and fed to the provider's realtime adapter. Replies trigger only on utterance-boundary finals (for Deepgram, `speech_final`/`UtteranceEnd`, never mid-sentence `is_final` segments), and barge-in fires from local energy VAD, never from transcriber partials. While something is interruptible (an assistant turn in flight, thinking or speaking, or a completed turn's tail still playing from Twilio's buffer), caller speech arms the shared sustained-speech barge-in guard (`src/calls/barge-in-guard.ts`, the same accounting live voice uses: speech accumulates toward 250 ms, short gaps are tolerated, a run that is mostly silence resets) and every inbound frame feeds it; outside that window the guard is dropped, so the caller's own utterance never carries into a turn that starts before the local VAD ends it. Only a fired guard reaches `CallController.handleBargeIn`, which interrupts a turn in either phase and ignores an idle controller (the playing tail is cleared instead).
613
613
  - **Batch fallback**: otherwise the session segments turns with the energy-based `MediaTurnDetector` and transcribes each completed turn via the same role's batch API. Both halves of a call read the `telephony` role, which is why a role names its consumer rather than a boundary.
614
614
 
615
+ Every phone turn runs the same two-leg triage as live voice through `startVoiceTurn` (`src/calls/voice-session-bridge.ts`): `call-controller.ts` opens on a toolless front-door leg (`routingLeg: "front-door"`, the `voiceFrontDoor` call site) and drives it through the shared `createFrontDoorLegCoordinator` (`src/calls/voice-leg-coordinator.ts`), which reads the stream through the verdict machine and sequences the hand-off (pause narration, abort the leg, resolve and speak the bridge, mark it as the floor holder, start the escalated leg pinned to the conversation's own model, re-arm narration); each driver supplies only a host for how text and the bridge are spoken, how a leg is started or aborted, and (live voice only) the speculative hold and commit. Phone has no partial transcripts, so the hold verdict is never taught and routing is escalate-only. The controller also passes the bridge's turn callbacks (tool activity is recorded as `tool_use_started` / `tool_use_completed` call events, persisted row ids ride the `assistant_spoke` event), `launchedAtMs` for dispatch timing, and a `voiceTelemetry` bag keyed by the call session with a `phone_inbound` / `phone_outbound` entry. Both drivers share the spoken progress narration cadence (`src/calls/voice-progress-cadence.ts`, tuned by `voice.frontModel.progress`): the cadence owns the tool-activity log, the triggers (an ops burst, a long operation completing, a full interval of audible silence with news, the `maxSilenceMs` heartbeat) and the generated or static phrase, while each driver supplies its own view of audible silence (live voice from its TTS queue and playback-tail estimate; the media-stream transport from `isPlaybackIdle()` and a running sum of sent frame durations) and how to speak a phrase.
616
+
615
617
  A credential preflight (`resolveTelephonyCredentialReadiness()` in `src/calls/telephony-credential-preflight.ts`) gates every call: it requires a credentialed, telephony-capable STT provider **and** a media-stream-playable TTS provider (the configured one or a credentialed playable fallback). Inbound calls that fail the preflight receive `<Say>` setup-required copy plus `<Hangup/>` instead of a doomed stream; outbound placement fails before dialing via `preflightVoiceIngress()` with the same user-facing message.
616
618
 
617
619
  Key modules:
@@ -729,9 +731,9 @@ The assistant-side live voice module is intentionally bounded under `src/live-vo
729
731
  | `live-voice-archive.ts` | Audio artifact creation/linking for user utterance and assistant response message IDs |
730
732
  | `live-voice-metrics.ts` | Per-session and per-turn latency snapshots emitted as `metrics` frames |
731
733
 
732
- Live voice STT uses the same `resolveStreamingTranscriber()` path as conversation streaming. For V1 latency-sensitive behavior, the selected `services.stt.provider` must resolve to a `daemon-streaming` transcriber whose catalog entry has `conversationStreamingMode: "realtime-ws"` and usable credentials. Providers that only support batch or incremental-batch transcription remain valid for other voice surfaces, but do not satisfy live voice's streaming STT requirement.
734
+ Live voice STT uses the same `resolveStreamingTranscriber()` path as conversation streaming, dialed with the provider the `liveVoice` STT role resolves to after managed-speech defaulting (`resolveEffectiveSpeechProviders`, see `config/managed-speech-defaults.ts`). For V1 latency-sensitive behavior, that provider must resolve to a `daemon-streaming` transcriber whose catalog entry has `conversationStreamingMode: "realtime-ws"` and usable credentials. Providers that only support batch or incremental-batch transcription remain valid for other voice surfaces, but do not satisfy live voice's streaming STT requirement.
733
735
 
734
- Live voice TTS uses `streamLiveVoiceTtsAudio()` and the configured `services.tts.provider`. The selected provider must be registered, catalog-compatible, and expose `capabilities.supportsStreaming` plus `synthesizeStream()`. Providers whose catalog entry advertises `supportsStreaming` (currently all four catalog providers: ElevenLabs, Fish Audio, Deepgram, and xAI) satisfy this requirement; a buffered-only provider would remain available for buffered message playback or other supported surfaces, but live voice reports a TTS error instead of silently falling back to buffered playback.
736
+ Live voice TTS uses `streamLiveVoiceTtsAudio()` and the TTS provider that `resolveEffectiveSpeechProviders` settles on (the configured `services.tts.provider`, or the managed `vellum` provider when the configured one has no usable credentials). The selected provider must be registered, catalog-compatible, and expose `capabilities.supportsStreaming` plus `synthesizeStream()`. Providers whose catalog entry advertises `supportsStreaming` (currently all five catalog providers: ElevenLabs, Fish Audio, Deepgram, xAI, and the managed Vellum provider) satisfy this requirement; a buffered-only provider would remain available for buffered message playback or other supported surfaces, but live voice reports a TTS error instead of silently falling back to buffered playback.
735
737
 
736
738
  The `voiceFrontDoor` prompt skips current-turn legacy and v3 memory retrieval, while prior frozen memory cards and static memory context remain available. The front-door rule escalates rather than guessing when required personal context is absent. The escalated leg runs the ordinary memory pipeline against the latest visible caller prompt before the quality model, with low selector effort. This keeps memory work off the front-door TTFT path without cross-leg speculative state.
737
739
 
@@ -1294,9 +1296,8 @@ graph TB
1294
1296
  RM_DIR["rmSync skill directory"]
1295
1297
  end
1296
1298
 
1297
- subgraph "File Watcher"
1298
- WATCHER["Skills directory watcher<br/>detects changes"]
1299
- EVICT["Session eviction<br/>+ recreation"]
1299
+ subgraph "Capability reseed"
1300
+ RESEED["SKILL.md mtime poll<br/>reseeds capability cards"]
1300
1301
  end
1301
1302
 
1302
1303
  SNIPPET --> EVAL_TOOL
@@ -1309,14 +1310,12 @@ graph TB
1309
1310
  SCAFFOLD --> MANAGED_STORE
1310
1311
  MANAGED_STORE --> SKILL_DIR
1311
1312
 
1312
- SKILL_DIR --> WATCHER
1313
- WATCHER --> EVICT
1314
-
1313
+ SKILL_DIR --> RESEED
1315
1314
  SKILL_DIR --> SKILL_LOAD
1316
1315
  SKILL_LOAD --> SESSION
1317
1316
 
1318
1317
  DELETE --> RM_DIR
1319
- RM_DIR --> WATCHER
1318
+ RM_DIR --> RESEED
1320
1319
  ```
1321
1320
 
1322
1321
  **Key design decisions:**
@@ -1324,7 +1323,7 @@ graph TB
1324
1323
  - `evaluate_typescript_code` always forces `sandbox.enabled = true` regardless of global config.
1325
1324
  - Snippet contract: must export `default` or `run` with signature `(input: unknown) => unknown | Promise<unknown>`.
1326
1325
  - Managed-store writes are atomic (tmp file + rename) to prevent partial `SKILL.md` files.
1327
- - After persist or delete, the file watcher triggers conversation eviction; the next turn runs in a fresh conversation. The model's system prompt instructs it to continue normally.
1326
+ - After persist or delete, capability cards reseed from the `SKILL.md` set. The next turn continues in the same conversation.
1328
1327
  - macOS UI shows Inspect and Delete controls for managed skills only (source = "managed").
1329
1328
  - `skill_load` resolves the recursive include graph (via `include-graph.ts`) before emitting output. Missing children are listed as suggested skills without child `<loaded_skill>` markers; cycles still produce `isError: true` with no marker. Valid includes produce an "Included Skills (immediate)" metadata section showing child ID, name, description, and path.
1330
1329
 
@@ -1407,15 +1406,15 @@ skills/<skill-id>/
1407
1406
 
1408
1407
  The following capabilities ship as bundled skills in `assistant/src/config/bundled-skills/`:
1409
1408
 
1410
- | Skill ID | Tools | Purpose |
1411
- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1412
- | `browser` | `browser_navigate`, `browser_snapshot`, `browser_screenshot`, `browser_close`, `browser_click`, `browser_type`, `browser_press_key`, `browser_wait_for`, `browser_extract`, `browser_fill_credential` | Headless browser automation web scraping, form filling, interaction (previously core-registered as `headless-browser`; now skill-provided with default allow rules) |
1413
- | `gmail` | Gmail search, archive, send, etc. | Email management via OAuth2 integration |
1414
- | `computer-use` | `computer_use_observe`, `computer_use_click`, `computer_use_type_text`, `computer_use_key`, `computer_use_scroll`, `computer_use_drag`, `computer_use_wait`, `computer_use_open_app`, `computer_use_run_applescript`, `computer_use_done`, `computer_use_respond` | Computer-use proxy tools preactivated via `preactivatedSkillIds` in desktop sessions. Each tool forwards actions to a compatible connected desktop host via `HostCuProxy`, which handles request/resolve proxying, step counting, loop detection, and observation formatting in the same agent loop. |
1415
- | `weather` | `get-weather` | Fetch current weather data |
1416
- | `app-builder` | `app_create`, `app_delete`, `app_refresh`, `app_generate_icon` | Dynamic app authoring create and manage persistent apps; file editing uses generic file tools plus `app_refresh` (activated via `skill_load app-builder`; `app_open` remains a core proxy tool) |
1417
- | `self-upgrade` | (instruction-only) | Self-improvement workflow |
1418
- | `start-the-day` | (instruction-only) | Morning briefing routine |
1409
+ | Skill ID | Tools | Purpose |
1410
+ | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1411
+ | `browser` | `browser_navigate`, `browser_snapshot`, `browser_screenshot`, `browser_close`, `browser_click`, `browser_type`, `browser_press_key`, `browser_wait_for`, `browser_extract`, `browser_fill_credential` | Headless browser automation: web scraping, form filling, interaction (previously core-registered as `headless-browser`; now skill-provided with default allow rules) |
1412
+ | `gmail` | Gmail search, archive, send, etc. | Email management via OAuth2 integration |
1413
+ | `computer-use` | `computer_use_observe`, `computer_use_click`, `computer_use_type_text`, `computer_use_key`, `computer_use_scroll`, `computer_use_drag`, `computer_use_wait`, `computer_use_open_app`, `computer_use_run_applescript`, `computer_use_sequence`, `computer_use_done`, `computer_use_respond` | Computer-use proxy tools preactivated via `preactivatedSkillIds` in desktop sessions. Each tool forwards actions to a compatible connected desktop host via `HostCuProxy`, which handles request/resolve proxying, step counting, loop detection, and observation formatting in the same agent loop. |
1414
+ | `weather` | `get-weather` | Fetch current weather data |
1415
+ | `app-builder` | `app_create`, `app_delete`, `app_refresh`, `app_generate_icon` | Dynamic app authoring: create and manage persistent apps; file editing uses generic file tools plus `app_refresh` (activated via `skill_load app-builder`; `app_open` remains a core proxy tool) |
1416
+ | `self-upgrade` | (instruction-only) | Self-improvement workflow |
1417
+ | `start-the-day` | (instruction-only) | Morning briefing routine |
1419
1418
 
1420
1419
  ### Activation and Projection Flow
1421
1420
 
@@ -2192,7 +2191,7 @@ The `TtsUseCase` discriminator (`"phone-call"` or `"message-playback"`) lets pro
2192
2191
  - **`native-twilio`** — the text-token path: spoken text is sent via `sendTextToken()`, which the media-stream transport re-synthesizes through daemon TTS. Collapsing this mode into `synthesized-play` is a documented deferred follow-up.
2193
2192
  - **`synthesized-play`** — The assistant synthesises audio via the provider's HTTP API and streams it through the audio store / `sendPlayUrl()` path.
2194
2193
 
2195
- **Phone call integration:** Phone calls run on the media-stream transport, where the daemon synthesises speech via the configured TTS provider and transcodes it to mu-law 8 kHz frames (`media-stream-output.ts`). Each catalog entry declares `mediaStreamPlayback.outputFormat` (`pcm`, `wav`, or `none`); `resolveTelephonyTtsCapability()` (`src/calls/telephony-tts-capability.ts`) combines that field with credential availability into a playable / not-playable verdict, and the call TTS resolver falls back to a credentialed playable provider rather than producing silence.
2194
+ **Phone call integration:** Phone calls run on the media-stream transport, where the daemon synthesises speech via the effective TTS provider (the configured one after managed-speech defaulting, `resolveEffectiveSpeechProviders`, the same substitution live voice makes) and transcodes it to mu-law 8 kHz frames (`media-stream-output.ts`). Each catalog entry declares `mediaStreamPlayback.outputFormat` (`pcm`, `wav`, or `none`); `resolveTelephonyTtsCapability()` (`src/calls/telephony-tts-capability.ts`) combines that field with credential availability into a playable / not-playable verdict, and the call TTS resolver falls back to a credentialed playable provider rather than producing silence.
2196
2195
 
2197
2196
  **Adding a new TTS provider (catalog-first checklist):**
2198
2197
 
package/Dockerfile CHANGED
@@ -130,13 +130,13 @@ RUN bun run scripts/smoke-container-workspace-dependencies.ts
130
130
  # The repo-root .dockerignore decides which skills (and files) ship.
131
131
  COPY skills /app/skills
132
132
 
133
- # Materialize the git-ignored offline plugin manifest from its canonical source.
134
- # `assistant/src/cli/lib/plugin-catalog-local.ts` statically imports this JSON
135
- # (loaded even when platform features are enabled), so it must exist in the image
136
- # the build installs with --ignore-scripts, so the postinstall sync that
137
- # regenerates it in dev never runs here. Mirrors how CI materializes the
138
- # feature-flag registry before building.
139
- COPY plugins/marketplace.json /app/assistant/src/cli/lib/bundled-marketplace.json
133
+ # Materialize the git-ignored offline marketplace and reviewed local packages.
134
+ # The build installs with --ignore-scripts, so the postinstall sync that creates
135
+ # these static imports in development never runs here.
136
+ COPY plugins /app/plugins
137
+ COPY meta/sync-bundled-copies.ts /app/meta/
138
+ RUN cd /app && bun run meta/sync-bundled-copies.ts --plugins-only && \
139
+ bun run assistant/scripts/generate-bundled-plugin-packages.ts
140
140
 
141
141
  # Install assistant CLI launcher backed by the bundled assistant package
142
142
  RUN printf '#!/usr/bin/env sh\nexec bun run /app/assistant/src/index.ts "$@"\n' > /usr/local/bin/assistant && \
@@ -552,6 +552,13 @@ Message content (stored as JSON `ContentBlock[]` in the DB) is flattened for the
552
552
 
553
553
  Attachments are materialized into `conversations/<conversation>/attachments/` as soon as they are linked to a message. During disk-view sync, the JSONL record reuses those filenames directly and only falls back to materializing legacy rows that have not been projected yet. Filename collisions are still resolved by appending a numeric suffix (e.g., `photo-2.png`, `photo-3.png`).
554
554
 
555
+ Computer-use screenshot media is materialized while its tool-result row is
556
+ finalized, so earlier frames remain represented in tool history, JSONL, and
557
+ compaction inputs. The final screenshot-bearing invocation reuses that same
558
+ attachment ID for an additional reply link. A single attachment can therefore
559
+ appear on both a tool-result row and a reply row without creating a second
560
+ attachment-store object.
561
+
555
562
  ### Backfill Migration
556
563
 
557
564
  Existing conversations created before the disk view was introduced are backfilled by workspace migration `009-backfill-conversation-disk-view`, which replays all conversations and their messages through the disk-view sync functions.
@@ -87,8 +87,17 @@ graph LR
87
87
  nesting existed still parse, since an unindented body line that is not itself
88
88
  entry-shaped is read as a continuation.
89
89
  - **Consolidation** (`substrate/consolidation-job.ts`) is a background
90
- agent conversation that files buffer entries into concept pages, rewrites
91
- the aggregate views, and trims the buffer. Scheduling
90
+ agent conversation that files buffer entries into concept pages and
91
+ rewrites the aggregate views. The agent never writes the buffer: the job
92
+ snapshots `buffer.md`, hands the run its pass's entries verbatim in the
93
+ prompt, and after the run removes exactly those entries itself through
94
+ `buffer-file.ts` (the module that also owns the append path, so the two
95
+ writers of the buffer share one protocol). Removal happens only when the
96
+ run's persisted messages hold a page-writing tool call with a non-error
97
+ result, the same evidence bar the retrospective's cursor advance uses; a
98
+ run that wrote nothing, failed, or timed out leaves the buffer intact for
99
+ the next pass. Entries deferred past the per-run cap and entries appended
100
+ while the run was in flight are therefore never lost. Scheduling
92
101
  (`maybeEnqueueGraphMaintenanceJobs` in `jobs-worker.ts`):
93
102
  - interval-based (`memory.v2.consolidation_interval_hours`, default 8h),
94
103
  skipped below `MIN_BUFFER_LINES_FOR_CONSOLIDATION` (10) **unless** the
@@ -60,14 +60,21 @@ and restore the prior value afterwards, each guarding the restore so a turn that
60
60
  started in between is not clobbered. They are supplying the acting actor for
61
61
  their run, and are covered by this contract.
62
62
 
63
- A queued message commits to a run at its drain, not at its enqueue. The drains
64
- (`drainSingleMessage` and `drainBatch` in `conversation-process.ts`) stamp the
65
- queued sender the way `processMessage` stamps its committing actor, and re-scope
66
- the resident history to them, so a turn drained behind another actor's turn
67
- runs as its sender everywhere the resting actor is read, not only in the
68
- per-turn snapshot. A steered drain skips the re-scope: its sender owned the
69
- turn it cut off, and the resident history may carry the in-memory repair of the
70
- abandoned `tool_use`.
63
+ The queue drains are deliberately not in that set. `drainSingleMessage` and
64
+ `drainBatch` carry the queued sender on the per-turn field and into the run,
65
+ and leave the resting slot alone: at the point they stamp, the drain has not
66
+ yet proved it holds the processing lock. Its `isProcessing()` check is a
67
+ time-of-check guard whose documented backstop is the persist that can still
68
+ fail busy, and the requeue on that path restores the queue and the steer flag
69
+ only. A drain that stamped the slot would therefore leave the conversation
70
+ attributed to a sender whose turn never ran.
71
+
72
+ The consequence is that a cross-actor drain runs against history scoped for the
73
+ previous actor, because `ensureActorScopedHistory` reads the slot. That is a
74
+ real defect and it is LUM-3344's, which owns the fix: scope the transcript at
75
+ assembly time from the turn's actor, rather than mutating a shared transcript
76
+ and tracking who it was scoped for. Do not close it by making the drain stamp
77
+ the slot first.
71
78
 
72
79
  `call-controller` keeps its own `trustContext` on its own object and never reads
73
80
  the conversation's. It is outside this contract.
@@ -221,7 +221,7 @@ These invariants are enforced by guard tests and code review:
221
221
  4. **Grants and audit logs are CES-internal**: The assistant cannot read CES grant tables or audit logs directly. CES exposes grant status and audit summaries via RPC responses.
222
222
  5. **No generic authenticated HTTP clients in secure commands**: `curl`, `wget`, `httpie`, interpreters, and shell trampolines are structurally denied as secure command entrypoints. This is checked at manifest validation and re-checked at execution time.
223
223
  6. **Managed CES container runs as non-root**: The CES Docker image runs as `uid 1001` (user `ces`). The CES data volume is owned by this user.
224
- 7. **Single active bootstrap connection**: In managed mode, CES accepts one connection on the bootstrap socket and unlinks the socket path while that connection is live, so no second process can connect concurrently. CES is a long-lived sidecar: when the active session ends (the assistant disconnects or its container restarts), CES re-binds the socket and awaits the assistant's reconnection rather than shutting down. At most one connection is ever active; the sidecar only exits on SIGTERM/SIGINT.
224
+ 7. **Multi-connection bootstrap socket**: In managed mode, CES listens on the bootstrap socket as a concurrent multi-connection server and keeps the path bound. The assistant and its child processes each open their own RPC connection. CES is a long-lived sidecar: it stays up across assistant restarts and only exits on SIGTERM/SIGINT.
225
225
 
226
226
  ## Guarantees by deployment mode
227
227
 
@@ -0,0 +1,35 @@
1
+ # Virtual desktop browser CLI
2
+
3
+ `assistant browser --virtual-desktop` uses the browser CLI's shared operation handlers against the Chrome process owned by `DesktopSessionManager`. It requires a platform-hosted container, the `assistant-desktop` flag, completed automatic desktop installation and an identified guardian conversation. Availability is checked before starting or reusing control and after asynchronous startup; loss of the flag or installation readiness cancels active control. The first eligible browser command waits for the shared installation job, starts Chrome, and executes the original action exactly once. Cancellation and feature revocation stop the pending action while shared installation can finish for other viewers. Browser CLI requests allow ten minutes, with an eight-minute setup wait limit. Eligible web conversations receive browser guidance in the bash tool description, including the configured shell timeout; native clients retain their existing tool description. Opening the picture-in-picture panel also starts setup and shows progress automatically; failed installs retain a retry action. The persistent profile remains `data/desktop-profile`; no data migration or extension installation is required.
4
+
5
+ Automatic browser selection in platform-hosted web conversations uses the streamed Chrome when the desktop flag is enabled and the actor is an identified guardian. The macOS and Windows apps keep their existing browser selection and fallback behavior; they use the streamed desktop only with explicit `--virtual-desktop`. Their shared renderer reports a `web` transport, so selection also reads the active turn's frozen `clientOs`; it does not change transport identity or host capability checks. Explicit `--virtual-desktop`, `--browser-mode`, `--target-client-id` and active-tab requests override the default. Existing personal-browser sessions and tab pins remain on their selected browser. Tab commands use the same streamed-browser default as page commands. `--browser-mode local` selects assistant-side Playwright, not the user's Chrome.
6
+
7
+ The legacy `--desktop` option remains an alias. The deployment flag key `assistant-desktop`, API paths, sync tags and persistent profile path are unchanged for compatibility. The shared `isVirtualDesktopEnabled` gate rejects self-hosted assistants, including local Docker, for setup, streaming and control.
8
+
9
+ ```mermaid
10
+ flowchart LR
11
+ CLI[assistant browser --virtual-desktop] --> IPC[Existing browser IPC routes]
12
+ IPC --> Lease[DesktopAutomationLease conversation and actor lease]
13
+ Lease --> Shared[Shared browser operation handlers]
14
+ Shared --> CDP[Scoped desktop CDP client]
15
+ CDP --> Chrome[Managed Chrome on display :99]
16
+ Chrome --> Stream[Existing desktop stream]
17
+ ```
18
+
19
+ Chrome and its dock launcher share the managed profile and loopback debug port. For Chrome reopened from the dock, the profile singleton lock identifies a candidate PID, validated against the installed executable, profile and loopback debug arguments. Discovery checks `/proc` socket ownership against that browser PID, refuses redirects and validates the returned browser WebSocket endpoint. The connection stays within the container. No CDP endpoint or token is exposed to the renderer.
20
+
21
+ The desktop client bypasses personal-browser discovery, extension reconnect waits and backend fallback. It reuses the existing AX snapshot, DOM element resolution, mouse, keyboard, extraction and credential-fill implementations. Operation-scoped clients borrow the lease's connection; disposing one does not release the lease. `detach`, `close`, turn completion, cancellation, errors and idle expiry release control. Turn completion clears the activity indicator immediately and queues browser cleanup before the next automation session; it leaves Chrome and the current page open for the user. Only `tabs close` closes a Chrome tab.
22
+
23
+ `assistant browser --virtual-desktop screenshot --output /tmp/desktop-page.jpg` captures a color page image through CDP `Page.captureScreenshot`. It excludes the browser toolbar and desktop dock. `snapshot` returns semantic page structure. Agents should use these interfaces and let the manager start the desktop, including when older memory notes describe manual Xvnc, `xdotool` or scratch XWD conversion scripts.
24
+
25
+ Tab IDs are ephemeral numeric aliases for this managed browser's CDP target IDs. They are never personal extension tab IDs. Initial attachment selects an existing HTTP(S) page or opens a blank tab. Use `tabs list` and `tabs select --tab-id <id>` to choose explicitly. Navigation, tab selection, document replacement and release clear the desktop snapshot map. Personal-browser snapshots use a separate namespace.
26
+
27
+ CDP mouse events use page viewport CSS coordinates. Before dispatching them, the client animates a purple arrow overlay to the same point. The overlay is excluded from accessibility and hit testing. It appears in the existing desktop stream and is removed on release. It does not move the OS pointer, appear in browser toolbar UI or visualize every programmatic DOM operation. Native dialogs and other applications are outside the browser CLI; users can interact with them directly in the expanded desktop. The picture-in-picture preview is view-only. Direct user interaction does not pause automation. For logins, the assistant uses saved credentials first and securely collects missing credentials with `assistant credentials prompt`, then fills the login form itself. Every CAPTCHA and bot-detection challenge, including sliders and press-and-hold checks, is handed to the user before the assistant attempts it. When human interaction is needed, the assistant calls `ask_question` with `desktopHelp: { message, doneLabel, skipLabel }` in the user's language. The tool releases held browser input and reserves the desktop before publishing a question with `presentation: "virtual_desktop"`. The live viewer mounts only in the attended Electron window, with browser focus as a fallback on older shells and the web, so conversations release it when focus changes. A busy viewer offers Reconnect if the previous connection has not finished closing. The compact card lives in the scrolling message transcript, with expandable instructions and a preview capped at 384 pixels wide. It hosts the shared live viewer, with Step In opening its full desktop modal and Done or Skip resolving the existing question response. The assistant retains an exclusive human-help reservation while waiting. Done resumes the same conversation's automation lease for its fresh snapshot; Skip, closure, timeout and cancellation release it. The browser idle timer does not expire a pending human-help reservation. The live preview connects after Show live preview or Step In, and reuses an already-open picture-in-picture viewer. Other devices receiving the card do not automatically open a stream. When the request resolves, its interactive viewer closes or returns to the read-only PiP session that was open before the request. Skip does not imply the obstacle was resolved. Older clients show the same request as a normal Done/Skip question, with model-localized labels retained in history. Channels without dynamic UI return guidance to continue in the app rather than waiting on an unusable card.
28
+
29
+ The client records key and mouse presses before dispatch. On release it opens a fresh bounded cleanup connection, attaches to the same live targets, releases uncertain held input and removes overlays. A failed cleanup preserves state and the automation slot for retry. Turn-triggered cancellation retries cleanup automatically until it succeeds or ownership changes. Dispatched actions are never automatically retried. Closed targets need no input cleanup. Browser-process loss disposes the client, and later requests discover the replacement process.
30
+
31
+ `--use-active-tab` and personal browser targeting are rejected with `--virtual-desktop`. Download waiting is unsupported. Browser operations are bounded to two minutes and share the desktop lease's action budget and idle expiry.
32
+
33
+ Validation: focused client tests exercise shared snapshot/click behavior, namespace isolation, stale references, target changes, cancellation and uncertain-input cleanup. Lease tests cover browser ownership, cancellation and cleanup independently of native input. The Linux smoke script exercises real Chrome, the CLI and visible pointer feedback.
34
+
35
+ The desktop header icon pulses in the assistant's avatar accent color while a browser automation lease is active, including between browser commands. It shares the progress indicator's accent and neutral fallback. Reduced-motion clients show a solid accent. Setup status exposes the optional `automationActive` field; `desktop_activity_changed` events refresh it on acquisition and cancellation or release. Installation progress retains its `assistant:self:desktop` sync invalidations. The indicator reads status without starting installation, and reconnects refetch the current lease state.
@@ -72,6 +72,22 @@ it end to end:
72
72
  same way a failed card edit does. The write-vs-resolve race converges
73
73
  from the other side too: the feed writer re-checks canonical status
74
74
  after its append.
75
+ - The receipt is the whole retire mechanism, so everything that must
76
+ stop happening lives in `writeGuardianFeedReceipt`: the terminal
77
+ `guardianRequest.status` withdraws every client affordance, urgency
78
+ drops to `medium` to leave the "Needs attention" treatment, and a
79
+ still-`new` item is marked `seen` (unread means the user has
80
+ something to review, which a resolved request is not). That clear
81
+ runs only on the edge into terminal, so re-running the fan-out
82
+ neither pulls a cleared receipt back into the bell nor undoes a user
83
+ who marked the receipt unread again.
84
+ - Terminal receipts that never passed the edge are cleared once for
85
+ each assistant by `healLegacyGuardianReceiptUnread`, which the sweep calls
86
+ ahead of its gateway read. One-shot rather than recurring: such a row
87
+ and a `new` the user set deliberately are indistinguishable, so a
88
+ completion sentinel in the daemon checkpoint ledger records the
89
+ boundary instead. The transition is re-evaluated inside the writer
90
+ queue and moves only `new`, exactly as the edge does.
75
91
  - The feed writer's bulk-dismiss pass skips pending guardian items
76
92
  (`isPendingGuardianFeedItem`), so "Clear all" can never retire an
77
93
  unresolved request; only its receipt is clearable.
@@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test";
2
2
 
3
3
  import {
4
4
  buildShellInvocation,
5
+ buildShellSpawnFlags,
5
6
  pathListDelimiter,
6
7
  prependUniquePathEntries,
7
8
  } from "./shell.js";
@@ -38,6 +39,26 @@ describe("buildShellInvocation", () => {
38
39
  });
39
40
  });
40
41
 
42
+ describe("buildShellSpawnFlags", () => {
43
+ test("creates a POSIX process group and hides Windows consoles", () => {
44
+ expect(buildShellSpawnFlags("linux")).toEqual({
45
+ detached: true,
46
+ windowsHide: true,
47
+ });
48
+ expect(buildShellSpawnFlags("darwin")).toEqual({
49
+ detached: true,
50
+ windowsHide: true,
51
+ });
52
+ });
53
+
54
+ test("does not detach Windows children that use piped stdio", () => {
55
+ expect(buildShellSpawnFlags("win32")).toEqual({
56
+ detached: false,
57
+ windowsHide: true,
58
+ });
59
+ });
60
+ });
61
+
41
62
  describe("path list handling", () => {
42
63
  test("uses the platform delimiter", () => {
43
64
  expect(pathListDelimiter("win32")).toBe(";");
@@ -5,6 +5,11 @@ export interface ShellInvocation {
5
5
  args: string[];
6
6
  }
7
7
 
8
+ export interface ShellSpawnFlags {
9
+ detached: boolean;
10
+ windowsHide: true;
11
+ }
12
+
8
13
  const WINDOWS_UTF8_PREAMBLE =
9
14
  "try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 } catch {}; " +
10
15
  "$OutputEncoding = [System.Text.Encoding]::UTF8; " +
@@ -43,6 +48,25 @@ export function buildShellInvocation(
43
48
  return { command: "bash", args: ["-c", "--", command] };
44
49
  }
45
50
 
51
+ /**
52
+ * Spawn flags for assistant-owned shell children (sandbox bash, local
53
+ * host_bash fallback, sanitized CLI bash, skill runners, scheduled scripts).
54
+ *
55
+ * POSIX uses a new process group so timeout/abort can SIGKILL the tree via
56
+ * `-pid`. Windows process trees are torn down with `taskkill /T`, which does
57
+ * not need a detached process. Combining `DETACHED_PROCESS`,
58
+ * `CREATE_NO_WINDOW`, and piped stdio on Windows can emit `close` with exit
59
+ * 0 and empty pipes without running the encoded command.
60
+ */
61
+ export function buildShellSpawnFlags(
62
+ hostPlatform: NodeJS.Platform = process.platform,
63
+ ): ShellSpawnFlags {
64
+ return {
65
+ detached: hostPlatform !== "win32",
66
+ windowsHide: true,
67
+ };
68
+ }
69
+
46
70
  export function pathListDelimiter(
47
71
  hostPlatform: NodeJS.Platform = process.platform,
48
72
  ): string {
@@ -83,8 +83,14 @@ export const SourceMetadataSchema = z
83
83
  clientTimezone: z.string().optional(),
84
84
  /** Channel command intent (e.g. Telegram /start). */
85
85
  commandIntent: CommandIntentSchema.optional(),
86
- /** Slack-specific: whether the bot was @-mentioned. */
87
- slackBotMentioned: z.boolean().optional(),
86
+ /**
87
+ * Whether the message addresses the assistant by name, an @-mention on
88
+ * the platforms that have one. Stated by the channel's normalizer only
89
+ * where it proved the answer; absent means "not established". Read to
90
+ * decide whether a reply is expected before any text exists, never to
91
+ * admit or deny: admission is the gate's job, upstream of this.
92
+ */
93
+ botMentioned: z.boolean().optional(),
88
94
  /**
89
95
  * Slack-specific: the `edited.ts` float-string from a `message_changed`
90
96
  * event. Used by the daemon to reject out-of-order edit deliveries whose
@@ -113,7 +113,7 @@ export async function buildSlackUserLabelMap(
113
113
  // that label directly; only queue a lookup when the label is missing,
114
114
  // empty, or ID-shaped. Mirrors the channel builder below.
115
115
  const [, embeddedLabel] = splitSlackLabel(match[0].slice(1, -1));
116
- const sanitizedEmbeddedLabel = sanitizeOptionalLabel(embeddedLabel);
116
+ const sanitizedEmbeddedLabel = sanitizeEmbeddedSlackLabel(embeddedLabel);
117
117
  if (sanitizedEmbeddedLabel && sanitizedEmbeddedLabel !== id) continue;
118
118
  if (seen.has(id)) continue;
119
119
  seen.add(id);
@@ -151,7 +151,7 @@ export async function buildSlackChannelLabelMap(
151
151
  for (const match of text.matchAll(SLACK_CHANNEL_REFERENCE_RE)) {
152
152
  const id = match[1];
153
153
  const [, embeddedLabel] = splitSlackLabel(match[0].slice(1, -1));
154
- const sanitizedEmbeddedLabel = sanitizeOptionalLabel(embeddedLabel);
154
+ const sanitizedEmbeddedLabel = sanitizeEmbeddedSlackLabel(embeddedLabel);
155
155
  if (sanitizedEmbeddedLabel && sanitizedEmbeddedLabel !== id) continue;
156
156
  if (!seen.has(id)) {
157
157
  seen.add(id);
@@ -192,9 +192,7 @@ function renderUserMention(
192
192
  // prefer it over a lookup, mirroring renderChannelReference. The embedded
193
193
  // label is Slack-sourced (part of the token), so entities decode before
194
194
  // sanitization; the caller-resolved label below is not.
195
- const embeddedLabel = sanitizeOptionalLabel(
196
- label === undefined ? undefined : decodeSlackHtmlEntities(label),
197
- );
195
+ const embeddedLabel = sanitizeEmbeddedSlackLabel(label);
198
196
  if (embeddedLabel && embeddedLabel !== id) {
199
197
  return `@${embeddedLabel}`;
200
198
  }
@@ -219,9 +217,7 @@ function renderChannelReference(
219
217
  );
220
218
  // The embedded label is Slack-sourced (part of the token), so entities
221
219
  // decode before sanitization; the caller-resolved label below is not.
222
- const embeddedLabel = sanitizeOptionalLabel(
223
- label === undefined ? undefined : decodeSlackHtmlEntities(label),
224
- );
220
+ const embeddedLabel = sanitizeEmbeddedSlackLabel(label);
225
221
  if (embeddedLabel && embeddedLabel !== channelId) {
226
222
  return `#${embeddedLabel}`;
227
223
  }
@@ -320,6 +316,15 @@ export function sanitizeSlackLabel(
320
316
  return sanitized || undefined;
321
317
  }
322
318
 
319
+ // Slack-sourced labels are decoded before validation in both lookup and render.
320
+ function sanitizeEmbeddedSlackLabel(
321
+ label: string | undefined,
322
+ ): string | undefined {
323
+ return sanitizeOptionalLabel(
324
+ label === undefined ? undefined : decodeSlackHtmlEntities(label),
325
+ );
326
+ }
327
+
323
328
  function sanitizeOptionalLabel(label: string | undefined): string | undefined {
324
329
  return sanitizeSlackLabel(label);
325
330
  }
@@ -0,0 +1,95 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, test } from "bun:test";
3
+ import {
4
+ buildSlackChannelLabelMap,
5
+ buildSlackUserLabelMap,
6
+ renderSlackTextForModel,
7
+ } from "./index.js";
8
+
9
+ describe("Slack embedded-label lookup parity", () => {
10
+ const cases = [
11
+ { id: "U123", prefix: "@", build: buildSlackUserLabelMap, mapKey: "userLabels" },
12
+ {
13
+ id: "C123",
14
+ prefix: "#",
15
+ build: buildSlackChannelLabelMap,
16
+ mapKey: "channelLabels",
17
+ },
18
+ ] as const;
19
+
20
+ for (const { id, prefix, build, mapKey } of cases) {
21
+ for (const label of ["&lt;&gt;", `&lt;${id}&gt;`, "&lt; @# &gt;"]) {
22
+ test(`${prefix} resolves label ${label} after Slack entity decoding`, async () => {
23
+ const text = `<${prefix}${id}|${label}>`;
24
+ const requested: string[] = [];
25
+ const labels = await build([text], async (value) => {
26
+ requested.push(value);
27
+ return "Example Name";
28
+ });
29
+ assert.deepEqual(requested, [id]);
30
+ assert.equal(
31
+ renderSlackTextForModel(text, { [mapKey]: labels }),
32
+ `${prefix}Example Name`,
33
+ );
34
+ });
35
+ }
36
+
37
+ for (const label of ["&lt;Example&gt;", "R&amp;D", "&amp;lt;&amp;gt;"]) {
38
+ test(`${prefix} keeps usable embedded label ${label} without lookup`, async () => {
39
+ const requested: string[] = [];
40
+ const text = `<${prefix}${id}|${label}>`;
41
+ const labels = await build([text], async (value) => {
42
+ requested.push(value);
43
+ return "Wrong Label";
44
+ });
45
+ assert.deepEqual(requested, []);
46
+ assert.deepEqual(labels, {});
47
+ const expected =
48
+ label === "&lt;Example&gt;"
49
+ ? "Example"
50
+ : label === "R&amp;D"
51
+ ? "R&D"
52
+ : "&lt;&gt;";
53
+ assert.equal(
54
+ renderSlackTextForModel(text, { [mapKey]: labels }),
55
+ `${prefix}${expected}`,
56
+ );
57
+ });
58
+ }
59
+
60
+ test(`${prefix} deduplicates required lookups across encoded and bare mentions`, async () => {
61
+ const requested: string[] = [];
62
+ const labels = await build(
63
+ [`<${prefix}${id}|&lt;&gt;>`, `<${prefix}${id}>`],
64
+ async (value) => {
65
+ requested.push(value);
66
+ return "Example";
67
+ },
68
+ );
69
+ assert.deepEqual(requested, [id]);
70
+ assert.deepEqual(labels, { [id]: "Example" });
71
+ });
72
+
73
+ test(`${prefix} does not decode caller-resolved entity text`, async () => {
74
+ const text = `<${prefix}${id}|&lt;&gt;>`;
75
+ const labels = await build([text], async () => "&lt;Example&gt;");
76
+ assert.equal(
77
+ renderSlackTextForModel(text, { [mapKey]: labels }),
78
+ `${prefix}&lt;Example&gt;`,
79
+ );
80
+ });
81
+
82
+ test(`${prefix} preserves unknown fallback after a failed required lookup`, async () => {
83
+ let attempts = 0;
84
+ const text = `<${prefix}${id}|&lt;&gt;>`;
85
+ const labels = await build([text], async () => {
86
+ attempts++;
87
+ throw new Error("unavailable");
88
+ });
89
+ assert.equal(attempts, 1);
90
+ assert.deepEqual(labels, {});
91
+ const expected = prefix === "@" ? "@unknown-user" : "#unknown-channel";
92
+ assert.equal(renderSlackTextForModel(text, { [mapKey]: labels }), expected);
93
+ });
94
+ }
95
+ });