@vellumai/assistant 0.12.1-dev.202609141913.5e16607 → 0.12.1-staging.2

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 (439) hide show
  1. package/AGENTS.md +0 -4
  2. package/ARCHITECTURE.md +12 -11
  3. package/docs/architecture/turn-actor.md +8 -15
  4. package/docs/guardian-request-flow.md +0 -16
  5. package/openapi.yaml +49 -291
  6. package/package.json +1 -1
  7. package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
  8. package/src/__tests__/app-compiler.test.ts +0 -6
  9. package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
  10. package/src/__tests__/app-dir-path-guard.test.ts +3 -1
  11. package/src/__tests__/app-source-watcher.test.ts +218 -0
  12. package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
  13. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
  14. package/src/__tests__/computer-use-tools.test.ts +5 -17
  15. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  16. package/src/__tests__/config-schema.test.ts +29 -28
  17. package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
  18. package/src/__tests__/config-watcher.test.ts +8 -23
  19. package/src/__tests__/connection-model-compat.test.ts +2 -2
  20. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  21. package/src/__tests__/conversation-pairing.test.ts +0 -26
  22. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
  23. package/src/__tests__/conversation-queue.test.ts +207 -48
  24. package/src/__tests__/conversation-retry-discard.test.ts +1 -54
  25. package/src/__tests__/conversation-skill-tools.test.ts +0 -27
  26. package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
  27. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
  28. package/src/__tests__/conversation-title-service.test.ts +10 -14
  29. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
  30. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
  31. package/src/__tests__/credential-record-retire.test.ts +1 -171
  32. package/src/__tests__/credential-routes.test.ts +3 -212
  33. package/src/__tests__/credential-security-invariants.test.ts +2 -4
  34. package/src/__tests__/cu-unified-flow.test.ts +2 -8
  35. package/src/__tests__/document-sync-tags.test.ts +0 -25
  36. package/src/__tests__/drain-kick-guard.test.ts +2 -0
  37. package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
  38. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  39. package/src/__tests__/host-bash-proxy.test.ts +45 -26
  40. package/src/__tests__/host-browser-proxy.test.ts +17 -6
  41. package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
  42. package/src/__tests__/host-file-proxy.test.ts +23 -11
  43. package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
  44. package/src/__tests__/llm-catalog-parity.test.ts +0 -25
  45. package/src/__tests__/mcp-auth-routes.test.ts +9 -6
  46. package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
  47. package/src/__tests__/mcp-health-check.test.ts +11 -8
  48. package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
  49. package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
  50. package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
  51. package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
  52. package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
  53. package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
  54. package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
  55. package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
  56. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  57. package/src/__tests__/messaging-send-tool.test.ts +548 -355
  58. package/src/__tests__/model-intents.test.ts +0 -3
  59. package/src/__tests__/notification-vellum-adapter.test.ts +2 -85
  60. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  61. package/src/__tests__/platform-callback-registration.test.ts +16 -8
  62. package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
  63. package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
  64. package/src/__tests__/script-proxy-certs.test.ts +0 -35
  65. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  66. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  67. package/src/__tests__/speaker-identification.test.ts +56 -0
  68. package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
  69. package/src/__tests__/subagent-tools.test.ts +2 -3
  70. package/src/__tests__/telephony-tts-guard.test.ts +3 -38
  71. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
  72. package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
  73. package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
  74. package/src/__tests__/workspace-git-service.test.ts +0 -26
  75. package/src/acp/__tests__/agent-process.test.ts +4 -258
  76. package/src/acp/__tests__/auth-required.test.ts +0 -96
  77. package/src/acp/__tests__/client-handler.test.ts +2 -90
  78. package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
  79. package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
  80. package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
  81. package/src/acp/__tests__/session-manager.test.ts +4 -895
  82. package/src/acp/agent-process.test.ts +1 -4
  83. package/src/acp/agent-process.ts +9 -94
  84. package/src/acp/auth-required.ts +1 -50
  85. package/src/acp/auto-install.test.ts +7 -9
  86. package/src/acp/client-handler.ts +3 -16
  87. package/src/acp/resolve-agent.test.ts +6 -220
  88. package/src/acp/resolve-agent.ts +23 -88
  89. package/src/acp/session-manager.test.ts +3 -196
  90. package/src/acp/session-manager.ts +18 -441
  91. package/src/acp/types.ts +5 -50
  92. package/src/api/events/app-files-changed.ts +3 -4
  93. package/src/api/events/notification-intent.ts +0 -2
  94. package/src/api/index.ts +0 -6
  95. package/src/apps/app-store.ts +1 -1
  96. package/src/bundler/app-compiler.ts +0 -15
  97. package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
  98. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
  99. package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
  100. package/src/calls/call-constants.ts +4 -24
  101. package/src/calls/call-controller.ts +199 -499
  102. package/src/calls/call-transport.ts +0 -16
  103. package/src/calls/media-stream-output.ts +0 -32
  104. package/src/calls/media-stream-server.ts +30 -82
  105. package/src/calls/media-stream-stt-session.ts +0 -15
  106. package/src/calls/resolve-call-tts-provider.ts +2 -33
  107. package/src/calls/speaker-identification.ts +233 -0
  108. package/src/calls/tts-call-strategy.ts +5 -9
  109. package/src/calls/types.ts +0 -2
  110. package/src/calls/voice-control-protocol.ts +21 -53
  111. package/src/calls/voice-session-bridge.ts +46 -59
  112. package/src/calls/voice-triage-escalate.ts +56 -175
  113. package/src/cli/commands/apps.help.ts +13 -67
  114. package/src/cli/commands/apps.ts +0 -183
  115. package/src/cli/commands/bash.help.ts +13 -8
  116. package/src/cli/commands/bash.ts +25 -7
  117. package/src/cli/commands/channels/index.help.ts +2 -70
  118. package/src/cli/commands/channels/index.ts +3 -16
  119. package/src/cli/commands/credentials.help.ts +2 -6
  120. package/src/cli/commands/credentials.ts +2 -2
  121. package/src/cli/commands/mcp.help.ts +8 -8
  122. package/src/cli/commands/mcp.ts +1 -1
  123. package/src/cli/commands/roadmap.help.ts +1 -5
  124. package/src/cli/commands/roadmap.ts +1 -1
  125. package/src/cli/lib/bundled-marketplace.json +90 -103
  126. package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
  127. package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
  128. package/src/config/__tests__/platform-rehydration.test.ts +9 -99
  129. package/src/config/acp-defaults.test.ts +3 -13
  130. package/src/config/acp-defaults.ts +6 -23
  131. package/src/config/acp-schema.ts +2 -30
  132. package/src/config/bundled-skills/acp/SKILL.md +14 -22
  133. package/src/config/bundled-skills/acp/TOOLS.json +1 -5
  134. package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
  135. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  136. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  137. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  138. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
  139. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  140. package/src/config/bundled-skills/schedule/SKILL.md +4 -3
  141. package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
  142. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
  143. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  144. package/src/config/default-profile-catalog.ts +1 -1
  145. package/src/config/env.ts +2 -2
  146. package/src/config/feature-flag-registry.json +12 -24
  147. package/src/config/loader.ts +0 -1
  148. package/src/config/memory-v3-gate.test.ts +0 -31
  149. package/src/config/memory-v3-gate.ts +16 -20
  150. package/src/config/platform-rehydration.ts +27 -11
  151. package/src/config/schema.ts +2 -2
  152. package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
  153. package/src/config/schemas/calls.ts +28 -1
  154. package/src/config/schemas/live-voice.ts +173 -1
  155. package/src/config/schemas/mcp.ts +1 -1
  156. package/src/config/schemas/memory-retrospective.ts +0 -10
  157. package/src/config/schemas/services.ts +0 -8
  158. package/src/config/schemas/skills.ts +14 -0
  159. package/src/credential-execution/process-manager.test.ts +19 -18
  160. package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
  161. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
  162. package/src/daemon/app-source-watcher.ts +218 -0
  163. package/src/daemon/config-watcher.ts +194 -13
  164. package/src/daemon/conversation-process.ts +64 -35
  165. package/src/daemon/conversation-skill-tools.ts +31 -13
  166. package/src/daemon/conversation-store.ts +1 -1
  167. package/src/daemon/conversation-surfaces.ts +8 -10
  168. package/src/daemon/conversation-tool-setup.ts +43 -37
  169. package/src/daemon/conversation.ts +3 -0
  170. package/src/daemon/host-bash-proxy.ts +12 -8
  171. package/src/daemon/host-browser-proxy.ts +1 -15
  172. package/src/daemon/host-file-proxy.ts +10 -8
  173. package/src/daemon/host-transfer-proxy.ts +18 -14
  174. package/src/daemon/lifecycle.ts +5 -0
  175. package/src/daemon/mcp-reload-service.ts +5 -5
  176. package/src/daemon/message-types/sync.ts +0 -1
  177. package/src/daemon/orphan-reaper.ts +1 -1
  178. package/src/daemon/providers-setup.ts +1 -1
  179. package/src/daemon/shutdown-handlers.ts +9 -1
  180. package/src/daemon/skill-memory-refresh.ts +0 -64
  181. package/src/daemon/tool-side-effects.ts +18 -7
  182. package/src/home/__tests__/feed-writer.test.ts +0 -22
  183. package/src/home/feed-writer.ts +2 -11
  184. package/src/hooks/types.ts +0 -33
  185. package/src/inbound/platform-callback-registration.ts +5 -4
  186. package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
  187. package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
  188. package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
  189. package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
  190. package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
  191. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
  192. package/src/live-voice/live-voice-session.ts +693 -213
  193. package/src/{calls → live-voice}/progress-narration.ts +2 -2
  194. package/src/live-voice/protocol.ts +2 -0
  195. package/src/mcp/__tests__/effective-config.test.ts +2 -2
  196. package/src/mcp/effective-config.ts +3 -3
  197. package/src/mcp/mcp-header-store.ts +45 -29
  198. package/src/mcp/startup.ts +4 -8
  199. package/src/messaging/provider.ts +3 -10
  200. package/src/messaging/providers/callback-routing.ts +0 -18
  201. package/src/messaging/providers/channel-transport.ts +0 -56
  202. package/src/messaging/providers/discord/transport.ts +0 -17
  203. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
  204. package/src/messaging/providers/slack/adapter.ts +44 -7
  205. package/src/messaging/providers/slack/transport.ts +0 -16
  206. package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
  207. package/src/messaging/providers/telegram-bot/client.ts +26 -0
  208. package/src/messaging/providers/telegram-bot/transport.ts +0 -20
  209. package/src/messaging/providers/whatsapp/adapter.ts +48 -1
  210. package/src/messaging/providers/whatsapp/client.ts +29 -0
  211. package/src/messaging/providers/whatsapp/transport.ts +0 -18
  212. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
  213. package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
  214. package/src/notifications/__tests__/guardian-feed-projection.test.ts +2 -158
  215. package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
  216. package/src/notifications/__tests__/schedule-result-producer.test.ts +3 -99
  217. package/src/notifications/adapters/macos.ts +0 -3
  218. package/src/notifications/assistant-reply-producer.ts +3 -8
  219. package/src/notifications/conversation-pairing.ts +16 -36
  220. package/src/notifications/delivered-post-record.ts +1 -11
  221. package/src/notifications/guardian-feed-projection.ts +5 -125
  222. package/src/notifications/home-feed-side-effect.ts +7 -55
  223. package/src/notifications/schedule-result-producer.ts +22 -66
  224. package/src/oauth/__tests__/seed-providers-managed.test.ts +0 -54
  225. package/src/oauth/byo-connection.test.ts +0 -45
  226. package/src/oauth/byo-connection.ts +6 -36
  227. package/src/oauth/connection-resolver.test.ts +0 -73
  228. package/src/oauth/connection-resolver.ts +2 -95
  229. package/src/oauth/seed-providers.ts +0 -165
  230. package/src/outbound-proxy/certs.ts +5 -3
  231. package/src/permissions/checker.test.ts +6 -11
  232. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  233. package/src/persistence/conversation-crud.ts +63 -71
  234. package/src/persistence/conversation-lineage.ts +4 -12
  235. package/src/persistence/conversation-title-service.ts +26 -9
  236. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  237. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  238. package/src/persistence/message-reads.ts +0 -30
  239. package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
  240. package/src/persistence/schema/memory-core.ts +0 -5
  241. package/src/platform/client.test.ts +2 -4
  242. package/src/platform/client.ts +10 -2
  243. package/src/plugin-api/constants.ts +0 -2
  244. package/src/plugin-api/index.ts +0 -1
  245. package/src/plugin-api/types.ts +0 -2
  246. package/src/plugins/defaults/index.ts +0 -2
  247. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
  248. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
  249. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
  250. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
  251. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
  252. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
  253. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
  254. package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
  255. package/src/plugins/defaults/memory/hooks/init.ts +0 -10
  256. package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
  257. package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
  258. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
  259. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
  260. package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
  261. package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
  262. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
  263. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
  264. package/src/plugins/defaults/memory/startup.ts +1 -6
  265. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
  266. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  267. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
  268. package/src/plugins/defaults/memory/worker.ts +0 -6
  269. package/src/plugins/mcp-servers.ts +75 -15
  270. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  271. package/src/providers/gemini/client.ts +23 -9
  272. package/src/providers/inference/auth.ts +3 -2
  273. package/src/providers/inference/connection-availability.ts +8 -27
  274. package/src/providers/inference/resolve-auth.ts +4 -22
  275. package/src/providers/model-catalog.ts +0 -34
  276. package/src/providers/model-intents.ts +5 -10
  277. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
  278. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
  279. package/src/providers/openai/chat-completions-provider.ts +78 -192
  280. package/src/providers/openai/codex-models.ts +4 -0
  281. package/src/runtime/AGENTS.md +0 -2
  282. package/src/runtime/auth/same-actor.ts +3 -38
  283. package/src/runtime/http-server.ts +151 -160
  284. package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
  285. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
  286. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
  287. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
  288. package/src/runtime/routes/acp-routes.test.ts +0 -15
  289. package/src/runtime/routes/acp-routes.ts +9 -72
  290. package/src/runtime/routes/app-management-routes.ts +0 -73
  291. package/src/runtime/routes/app-routes.ts +1 -1
  292. package/src/runtime/routes/conversation-list-routes.ts +3 -14
  293. package/src/runtime/routes/conversation-query-routes.ts +0 -40
  294. package/src/runtime/routes/credential-routes.ts +10 -19
  295. package/src/runtime/routes/debug-bash-routes.ts +173 -0
  296. package/src/runtime/routes/diagnostics-routes.ts +3 -55
  297. package/src/runtime/routes/index.ts +2 -4
  298. package/src/runtime/routes/log-export-routes.ts +0 -2
  299. package/src/runtime/routes/mcp-auth-routes.ts +47 -39
  300. package/src/runtime/routes/migration-routes.ts +20 -6
  301. package/src/runtime/routes/platform-routes.ts +15 -18
  302. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
  303. package/src/runtime/services/conversation-serializer.ts +3 -16
  304. package/src/runtime/sync/resource-sync-events.ts +1 -2
  305. package/src/schedule/worker.ts +1 -1
  306. package/src/security/ces-rpc-record-backend.ts +0 -7
  307. package/src/subagent/consult-context.ts +25 -12
  308. package/src/tools/acp/list-agents.test.ts +1 -3
  309. package/src/tools/acp/spawn.test.ts +11 -146
  310. package/src/tools/acp/spawn.ts +3 -21
  311. package/src/tools/acp/status.ts +3 -40
  312. package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
  313. package/src/tools/capability-offer.test.ts +2 -22
  314. package/src/tools/capability-offer.ts +1 -16
  315. package/src/tools/computer-use/definitions.ts +2 -4
  316. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
  317. package/src/tools/credentials/metadata-store.ts +0 -100
  318. package/src/tools/host-filesystem/edit.test.ts +1 -2
  319. package/src/tools/host-filesystem/edit.ts +2 -2
  320. package/src/tools/host-filesystem/read.test.ts +1 -2
  321. package/src/tools/host-filesystem/read.ts +2 -2
  322. package/src/tools/host-filesystem/transfer.test.ts +1 -2
  323. package/src/tools/host-filesystem/transfer.ts +2 -2
  324. package/src/tools/host-filesystem/write.test.ts +1 -2
  325. package/src/tools/host-filesystem/write.ts +2 -2
  326. package/src/tools/host-terminal/host-shell.test.ts +0 -16
  327. package/src/tools/host-terminal/host-shell.ts +20 -4
  328. package/src/tools/policy-context.ts +7 -6
  329. package/src/tools/subagent/spawn.ts +8 -5
  330. package/src/tools/watch/watch-retro-report.ts +8 -0
  331. package/src/util/__tests__/language-subtag.test.ts +1 -23
  332. package/src/util/fs-watcher-error.ts +36 -0
  333. package/src/util/language-subtag.ts +0 -16
  334. package/src/util/platform.ts +0 -8
  335. package/src/workspace/git-service.ts +54 -5
  336. package/src/workspace/migrations/registry.ts +0 -6
  337. package/scripts/smoke-desktop-window-theme.ts +0 -186
  338. package/src/__tests__/git-porcelain.test.ts +0 -47
  339. package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
  340. package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
  341. package/src/__tests__/resolve-app.test.ts +0 -135
  342. package/src/__tests__/service-account-token.test.ts +0 -247
  343. package/src/__tests__/source-fingerprint.test.ts +0 -184
  344. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
  345. package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
  346. package/src/acp/model-config.test.ts +0 -166
  347. package/src/acp/model-config.ts +0 -138
  348. package/src/api/events/acp-session-model-update.test.ts +0 -88
  349. package/src/api/events/acp-session-model-update.ts +0 -46
  350. package/src/apps/resolve-app.ts +0 -81
  351. package/src/apps/source-fingerprint.ts +0 -266
  352. package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
  353. package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
  354. package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
  355. package/src/calls/barge-in-guard.ts +0 -118
  356. package/src/calls/voice-leg-coordinator.ts +0 -189
  357. package/src/calls/voice-progress-cadence.ts +0 -423
  358. package/src/cli/commands/__tests__/apps.test.ts +0 -245
  359. package/src/cli/commands/__tests__/bash.test.ts +0 -53
  360. package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
  361. package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
  362. package/src/cli/commands/channels/send.ts +0 -128
  363. package/src/config/__tests__/platform-identity.test.ts +0 -255
  364. package/src/config/acp-agent-write.ts +0 -43
  365. package/src/config/acp-schema.test.ts +0 -81
  366. package/src/config/platform-identity.ts +0 -201
  367. package/src/config/schemas/__tests__/voice.test.ts +0 -148
  368. package/src/config/schemas/voice.ts +0 -150
  369. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
  370. package/src/daemon/app-change-notify.ts +0 -45
  371. package/src/desktop/__tests__/fake-desktop.ts +0 -119
  372. package/src/desktop/desktop-chrome-policy.test.ts +0 -71
  373. package/src/desktop/desktop-chrome-policy.ts +0 -42
  374. package/src/desktop/desktop-dependencies.test.ts +0 -102
  375. package/src/desktop/desktop-dependencies.ts +0 -306
  376. package/src/desktop/desktop-feature.test.ts +0 -18
  377. package/src/desktop/desktop-feature.ts +0 -19
  378. package/src/desktop/desktop-panel-config.test.ts +0 -135
  379. package/src/desktop/desktop-panel-config.ts +0 -149
  380. package/src/desktop/desktop-session-manager.test.ts +0 -627
  381. package/src/desktop/desktop-session-manager.ts +0 -814
  382. package/src/desktop/desktop-stream-bridge.test.ts +0 -395
  383. package/src/desktop/desktop-stream-bridge.ts +0 -214
  384. package/src/desktop/desktop-wallpaper.test.ts +0 -191
  385. package/src/desktop/desktop-wallpaper.ts +0 -113
  386. package/src/desktop/desktop-window-theme.ts +0 -170
  387. package/src/i18n/AGENTS.md +0 -22
  388. package/src/i18n/__tests__/i18n.test.ts +0 -108
  389. package/src/i18n/index.ts +0 -16
  390. package/src/i18n/locales.ts +0 -93
  391. package/src/i18n/messages.ts +0 -61
  392. package/src/i18n/title.ts +0 -25
  393. package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
  394. package/src/mcp/spec-schema.ts +0 -111
  395. package/src/mcp/workspace-mcp-config.ts +0 -188
  396. package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
  397. package/src/persistence/conversation-title-placeholders.ts +0 -23
  398. package/src/persistence/message-cursor.ts +0 -78
  399. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
  400. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
  401. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
  402. package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
  403. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
  404. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
  405. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
  406. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
  407. package/src/providers/gemini-thought-signature.test.ts +0 -63
  408. package/src/providers/gemini-thought-signature.ts +0 -44
  409. package/src/providers/inference/service-account-token.ts +0 -248
  410. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
  411. package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
  412. package/src/providers/openai/google-thought-signature.ts +0 -320
  413. package/src/runtime/__tests__/channel-send.test.ts +0 -443
  414. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
  415. package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
  416. package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
  417. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
  418. package/src/runtime/channel-send.ts +0 -316
  419. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
  420. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
  421. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
  422. package/src/runtime/routes/channel-send-routes.ts +0 -85
  423. package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
  424. package/src/runtime/routes/desktop-setup-routes.ts +0 -35
  425. package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
  426. package/src/security/ces-http-record-backend.ts +0 -120
  427. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
  428. package/src/skills/workspace-skill-md-signature.ts +0 -50
  429. package/src/tools/acp/status.test.ts +0 -94
  430. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -57
  431. package/src/tools/terminal/sanitized-bash.ts +0 -105
  432. package/src/util/ca-bundle.ts +0 -13
  433. package/src/workspace/git-porcelain.ts +0 -66
  434. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
  435. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
  436. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
  437. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
  438. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
  439. /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
@@ -1,627 +0,0 @@
1
- import { mkdtempSync, readFileSync, rmSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import { afterAll, describe, expect, test } from "bun:test";
5
-
6
- import { waitFor } from "../__tests__/helpers/wait-for.js";
7
- import { sleep } from "../util/retry.js";
8
- import {
9
- type FakeDesktopOptions,
10
- KILL_GRACE_MS,
11
- LINGER_MS,
12
- newFakeDesktop,
13
- newViewer,
14
- settle,
15
- } from "./__tests__/fake-desktop.js";
16
- import {
17
- DESKTOP_VNC_PORT,
18
- type DesktopChildRole,
19
- } from "./desktop-session-manager.js";
20
-
21
- const BUSY = {
22
- ok: false,
23
- loss: { code: 4013, reason: "Desktop is in use by another viewer" },
24
- } as const;
25
- const SHUTTING_DOWN = {
26
- ok: false,
27
- loss: { code: 1001, reason: "The assistant is shutting down" },
28
- } as const;
29
-
30
- const profileDir = mkdtempSync(join(tmpdir(), "desktop-session-test-"));
31
- const panelConfigDir = mkdtempSync(join(tmpdir(), "desktop-panel-test-"));
32
- afterAll(() => {
33
- rmSync(profileDir, { recursive: true, force: true });
34
- rmSync(panelConfigDir, { recursive: true, force: true });
35
- });
36
-
37
- function newManager(
38
- options: Omit<FakeDesktopOptions, "profileDir" | "panelConfigDir"> = {},
39
- ) {
40
- return newFakeDesktop({ profileDir, panelConfigDir, ...options });
41
- }
42
-
43
- describe("desktop wallpaper lifecycle", () => {
44
- test("applies the rendered wallpaper and refreshes it on reconnect without restarting X", async () => {
45
- let current = Buffer.from("first wallpaper");
46
- const h = newManager({
47
- renderWallpaper: async () => current,
48
- exitOnTerm: true,
49
- });
50
- await h.manager.ensureDesktopRunning();
51
- await settle();
52
- const path = join(panelConfigDir, "wallpaper.png");
53
- expect(readFileSync(path)).toEqual(current);
54
- expect(h.child("wallpaper").request.cmd).toEqual([
55
- "/usr/bin/feh",
56
- "--no-fehbg",
57
- "--bg-fill",
58
- path,
59
- ]);
60
- expect(h.child("wallpaper").request.env.DISPLAY).toBe(":99");
61
- h.child("wallpaper").exit(0);
62
- await settle();
63
- current = Buffer.from("updated avatar wallpaper");
64
- await h.manager.ensureDesktopRunning();
65
- await settle();
66
- expect(readFileSync(path)).toEqual(current);
67
- expect(h.count("wallpaper")).toBe(2);
68
- expect(h.count("x-server")).toBe(1);
69
- await h.manager.destroy();
70
- });
71
-
72
- test.each(["success", "failure"] as const)(
73
- "reconnects during a render queue the latest avatar after %s",
74
- async (outcome) => {
75
- let current = Buffer.from("first avatar");
76
- const pending: { finish: () => void; fail: () => void }[] = [];
77
- const h = newManager({
78
- renderWallpaper: () => {
79
- const snapshot = current;
80
- return new Promise((resolve, reject) => {
81
- pending.push({
82
- finish: () => resolve(snapshot),
83
- fail: () => reject(new Error("render failed")),
84
- });
85
- });
86
- },
87
- exitOnTerm: true,
88
- });
89
- try {
90
- await h.manager.ensureDesktopRunning();
91
- current = Buffer.from("second avatar");
92
- await h.manager.ensureDesktopRunning();
93
- current = Buffer.from("latest avatar");
94
- await h.manager.ensureDesktopRunning();
95
- expect(pending).toHaveLength(1);
96
-
97
- if (outcome === "success") {
98
- pending[0]!.finish();
99
- } else {
100
- pending[0]!.fail();
101
- }
102
- await settle();
103
- expect(pending).toHaveLength(2);
104
- expect(h.count("wallpaper")).toBe(0);
105
-
106
- pending[1]!.finish();
107
- await settle();
108
- expect(readFileSync(join(panelConfigDir, "wallpaper.png"))).toEqual(
109
- current,
110
- );
111
- expect(h.count("wallpaper")).toBe(1);
112
- expect(h.count("x-server")).toBe(1);
113
- expect(pending).toHaveLength(2);
114
- } finally {
115
- await h.manager.destroy();
116
- }
117
- },
118
- );
119
-
120
- test("pending and queued renders neither delay Chrome nor apply after shutdown", async () => {
121
- let finish!: (png: Buffer) => void;
122
- let renders = 0;
123
- const h = newManager({
124
- renderWallpaper: () => {
125
- renders++;
126
- return new Promise((resolve) => {
127
- finish = resolve;
128
- });
129
- },
130
- exitOnTerm: true,
131
- });
132
- await h.manager.ensureDesktopRunning();
133
- await h.manager.ensureDesktopRunning();
134
- await settle();
135
- expect(h.count("browser")).toBe(1);
136
- expect(renders).toBe(1);
137
- await h.manager.destroy();
138
- finish(Buffer.from("stale render"));
139
- await settle();
140
- expect(h.count("wallpaper")).toBe(0);
141
- expect(renders).toBe(1);
142
- });
143
-
144
- test.each(["render", "spawn", "exit"] as const)(
145
- "wallpaper %s failure leaves the viewer connected",
146
- async (failure) => {
147
- const h = newManager({
148
- renderWallpaper: async () => {
149
- if (failure === "render") {
150
- throw new Error("render failed");
151
- }
152
- return Buffer.from("wallpaper");
153
- },
154
- failSpawn: failure === "spawn" ? ["wallpaper"] : [],
155
- exitOnTerm: true,
156
- });
157
- const { viewer, lost } = newViewer();
158
- h.manager.acquireViewerSlot(viewer);
159
- await h.manager.ensureDesktopRunning();
160
- await settle();
161
- if (failure === "exit") {
162
- h.child("wallpaper").exit(1);
163
- await settle();
164
- }
165
- expect(lost).toEqual([]);
166
- expect(h.count("browser")).toBe(1);
167
- expect(h.terminated()).toEqual([]);
168
- await h.manager.destroy();
169
- },
170
- );
171
- });
172
-
173
- describe("DesktopSessionManager process tree", () => {
174
- test("concurrent callers share one start of the whole tree", async () => {
175
- const h = newManager({
176
- sourceEnv: {
177
- PATH: "/usr/bin",
178
- HOME: "/data",
179
- LANG: "C.UTF-8",
180
- // Neither the kata chroot overlay nor secrets reach the desktop.
181
- LD_LIBRARY_PATH: "/data/system/usr/lib",
182
- VELLUM_SANDBOX_RUNTIME: "kata",
183
- OPENAI_API_KEY: "sk-secret",
184
- },
185
- });
186
- await Promise.all([
187
- h.manager.ensureDesktopRunning(),
188
- h.manager.ensureDesktopRunning(),
189
- ]);
190
- await settle();
191
-
192
- // The dock waits on the Chromium path its launcher points at, so it comes
193
- // up alongside the browser rather than with the rest of the tree.
194
- expect(h.roles()).toEqual([
195
- "x-server",
196
- "window-manager",
197
- "compositor",
198
- "clipboard",
199
- "panel",
200
- "browser",
201
- ]);
202
-
203
- const x = h.child("x-server").request.cmd;
204
- expect(x.slice(0, 2)).toEqual(["/usr/bin/Xtigervnc", ":99"]);
205
- expect(x).toContain("-localhost");
206
- expect(x[x.indexOf("-SecurityTypes") + 1]).toBe("None");
207
- expect(x[x.indexOf("-rfbport") + 1]).toBe(String(DESKTOP_VNC_PORT));
208
- expect(x[x.indexOf("-geometry") + 1]).toBe("1440x900");
209
- for (const role of [
210
- "window-manager",
211
- "compositor",
212
- "clipboard",
213
- "browser",
214
- ] as const) {
215
- expect(h.child(role).request.env).toEqual({
216
- PATH: "/usr/bin",
217
- HOME: "/data",
218
- LANG: "C.UTF-8",
219
- DISPLAY: ":99",
220
- });
221
- }
222
- expect(h.child("window-manager").request.cmd[0]).toBe("/usr/bin/openbox");
223
- // The compositor precedes the dock so it has an ARGB visual.
224
- expect(h.child("compositor").request.cmd).toEqual(["/usr/bin/xcompmgr"]);
225
- expect(h.child("panel").request.cmd).toEqual([
226
- "/usr/bin/dbus-run-session",
227
- "--",
228
- "/usr/bin/plank",
229
- ]);
230
- expect(h.child("panel").request.env).toEqual({
231
- ...h.child("browser").request.env,
232
- XDG_CONFIG_HOME: panelConfigDir,
233
- XDG_DATA_HOME: panelConfigDir,
234
- GSETTINGS_BACKEND: "keyfile",
235
- });
236
- expect(h.child("clipboard").request.cmd).toEqual([
237
- "/usr/bin/tigervncconfig",
238
- "-nowin",
239
- ]);
240
- const browser = h.child("browser").request.cmd;
241
- expect(browser[0]).toBe("/fake/chromium");
242
- expect(browser).toContain(`--user-data-dir=${profileDir}`);
243
- // Explicit geometry matching the X server, so the window does not depend
244
- // on openbox being up to honor --start-maximized.
245
- expect(browser).toContain("--window-position=0,0");
246
- expect(browser).toContain("--window-size=1440,900");
247
-
248
- // A running tree is reused rather than started again.
249
- await h.manager.ensureDesktopRunning();
250
- expect(h.count("x-server")).toBe(1);
251
- });
252
-
253
- test("falls back to vncconfig when tigervncconfig is absent", async () => {
254
- const h = newManager({ missingBinaries: ["tigervncconfig"] });
255
- await h.manager.ensureDesktopRunning();
256
- expect(h.child("clipboard").request.cmd).toEqual([
257
- "/usr/bin/vncconfig",
258
- "-nowin",
259
- ]);
260
- });
261
-
262
- test("a missing binary fails the start before anything is spawned", async () => {
263
- const h = newManager({
264
- missingBinaries: [
265
- "Xtigervnc",
266
- "xcompmgr",
267
- "plank",
268
- "tigervncconfig",
269
- "vncconfig",
270
- "xterm",
271
- ],
272
- });
273
- await expect(h.manager.ensureDesktopRunning()).rejects.toThrow(
274
- "Desktop component is missing: Xtigervnc",
275
- );
276
- expect(h.spawned).toEqual([]);
277
- });
278
-
279
- test("the dock is generated with the resolved Chrome and terminal", async () => {
280
- const h = newManager();
281
- await h.manager.ensureDesktopRunning();
282
- await settle();
283
-
284
- const chromium = readFileSync(
285
- join(panelConfigDir, "applications", "google-chrome.desktop"),
286
- "utf8",
287
- );
288
- expect(chromium).toContain(`Exec="/fake/chromium"`);
289
- expect(chromium).toContain(`"--user-data-dir=${profileDir}"`);
290
- expect(chromium).toContain("Icon=/fake/product_logo_64.png");
291
-
292
- const terminal = readFileSync(
293
- join(panelConfigDir, "applications", "xterm.desktop"),
294
- "utf8",
295
- );
296
- expect(terminal).toContain(`Exec="/usr/bin/xterm"`);
297
- expect(terminal).toContain(`Icon=${join(panelConfigDir, "terminal.png")}`);
298
-
299
- const bytes = readFileSync(join(panelConfigDir, "terminal.png"));
300
- expect([...bytes.subarray(0, 8)]).toEqual([
301
- 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
302
- ]);
303
- // A complete IEND chunk catches a truncated icon.
304
- expect([...bytes.subarray(-12)]).toEqual([
305
- 0, 0, 0, 0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
306
- ]);
307
- });
308
-
309
- test("a VNC port that never opens fails the start and kills the X server, and a retry works", async () => {
310
- const h = newManager();
311
- h.setVncReady(false);
312
-
313
- await expect(h.manager.ensureDesktopRunning()).rejects.toThrow(/not ready/);
314
- expect(h.terminated()).toEqual([h.child("x-server")]);
315
-
316
- h.setVncReady(true);
317
- await h.manager.ensureDesktopRunning();
318
- expect(h.count("x-server")).toBe(2);
319
- });
320
-
321
- test("a retry spawns its X server only after the failed one is gone", async () => {
322
- const h = newManager();
323
- h.setVncReady(false);
324
- const { viewer, lost } = newViewer();
325
- h.manager.acquireViewerSlot(viewer);
326
-
327
- await expect(h.manager.ensureDesktopRunning()).rejects.toThrow(/not ready/);
328
- // The viewer hears about it before the kill grace, not after.
329
- expect(lost).toEqual([{ code: 4011, reason: "Desktop failed to start" }]);
330
- const first = h.child("x-server");
331
- expect(h.killed).toEqual([{ child: first, signal: "SIGTERM" }]);
332
-
333
- // Reconnect while the first X server is still ignoring its SIGTERM.
334
- h.setVncReady(true);
335
- const retry = h.manager.ensureDesktopRunning();
336
- await sleep(KILL_GRACE_MS / 2);
337
- expect(h.count("x-server")).toBe(1);
338
-
339
- // The SIGKILL alone does not free the display and port; the exit does.
340
- await waitFor(() => h.killed.length === 2, { intervalMs: 1 });
341
- expect(h.killed[1]).toEqual({ child: first, signal: "SIGKILL" });
342
- expect(h.count("x-server")).toBe(1);
343
-
344
- first.exit(0);
345
- await retry;
346
- expect(h.count("x-server")).toBe(2);
347
- });
348
-
349
- test("a retry stops waiting on an X server that survives SIGKILL", async () => {
350
- const h = newManager();
351
- h.setVncReady(false);
352
- await expect(h.manager.ensureDesktopRunning()).rejects.toThrow(/not ready/);
353
-
354
- h.setVncReady(true);
355
- const started = Date.now();
356
- await h.manager.ensureDesktopRunning();
357
- expect(Date.now() - started).toBeGreaterThanOrEqual(KILL_GRACE_MS * 2 - 4);
358
- expect(h.killed.map((k) => k.signal)).toEqual(["SIGTERM", "SIGKILL"]);
359
- expect(h.count("x-server")).toBe(2);
360
- });
361
-
362
- test("a spawn that fails after the X server is up rolls the tree back, and a retry starts clean", async () => {
363
- const failSpawn: DesktopChildRole[] = ["clipboard"];
364
- const h = newManager({ failSpawn });
365
- const { viewer, lost } = newViewer();
366
- h.manager.acquireViewerSlot(viewer);
367
-
368
- await expect(h.manager.ensureDesktopRunning()).rejects.toThrow(
369
- "spawn clipboard failed",
370
- );
371
- expect(
372
- h
373
- .terminated()
374
- .map((c) => c.role)
375
- .sort(),
376
- ).toEqual(["compositor", "window-manager", "x-server"]);
377
- expect(lost).toEqual([{ code: 4011, reason: "Desktop failed to start" }]);
378
-
379
- failSpawn.length = 0;
380
- await h.manager.ensureDesktopRunning();
381
- await settle();
382
- expect(h.roles().slice(3)).toEqual([
383
- "x-server",
384
- "window-manager",
385
- "compositor",
386
- "clipboard",
387
- "panel",
388
- "browser",
389
- ]);
390
- expect(h.terminated()).toHaveLength(3);
391
- });
392
-
393
- test("a dock or compositor that will not spawn leaves the desktop up", async () => {
394
- const h = newManager({ failSpawn: ["compositor", "panel"] });
395
- const { viewer, lost } = newViewer();
396
- h.manager.acquireViewerSlot(viewer);
397
-
398
- await h.manager.ensureDesktopRunning();
399
- await settle();
400
-
401
- expect(lost).toEqual([]);
402
- expect(h.killed).toEqual([]);
403
- expect(h.roles()).toEqual([
404
- "x-server",
405
- "window-manager",
406
- "clipboard",
407
- "browser",
408
- ]);
409
- });
410
-
411
- test("an X server exit tears the tree down and tells the viewer", async () => {
412
- const h = newManager();
413
- const { viewer, lost } = newViewer();
414
- expect(h.manager.acquireViewerSlot(viewer)).toEqual({ ok: true });
415
- await h.manager.ensureDesktopRunning();
416
- await settle();
417
-
418
- h.child("x-server").exit(1);
419
- await settle();
420
-
421
- expect(lost).toEqual([
422
- { code: 4011, reason: "Desktop stopped: x-server exited" },
423
- ]);
424
- expect(
425
- h
426
- .terminated()
427
- .map((c) => c.role)
428
- .sort(),
429
- ).toEqual([
430
- "browser",
431
- "clipboard",
432
- "compositor",
433
- "panel",
434
- "window-manager",
435
- ]);
436
- // The slot is free and the next start builds a fresh tree.
437
- expect(h.manager.acquireViewerSlot(newViewer().viewer)).toEqual({
438
- ok: true,
439
- });
440
- await h.manager.ensureDesktopRunning();
441
- expect(h.count("x-server")).toBe(2);
442
- });
443
-
444
- test("a panel exit keeps applications alive until their group is cleaned up at teardown", async () => {
445
- const h = newManager({ exitOnTerm: true });
446
- const { viewer, lost } = newViewer();
447
- h.manager.acquireViewerSlot(viewer);
448
- await h.manager.ensureDesktopRunning();
449
- await settle();
450
-
451
- h.child("panel").exit(1);
452
- await settle();
453
-
454
- expect(lost).toEqual([]);
455
- expect(h.killed).toEqual([]);
456
- // Not relaunched, and the tree it belonged to is untouched.
457
- expect(h.count("panel")).toBe(1);
458
- await h.manager.ensureDesktopRunning();
459
- expect(h.count("x-server")).toBe(1);
460
-
461
- await h.manager.destroy();
462
- expect(h.killed.filter((k) => k.child === h.child("panel"))).toEqual([
463
- { child: h.child("panel"), signal: "SIGTERM" },
464
- { child: h.child("panel"), signal: "SIGKILL" },
465
- ]);
466
- });
467
-
468
- test("a browser exit with nobody watching keeps the desktop and the next viewer gets a fresh one", async () => {
469
- const h = newManager();
470
- await h.manager.ensureDesktopRunning();
471
- await settle();
472
-
473
- h.child("browser").exit(0);
474
- await settle();
475
- expect(h.killed).toEqual([]);
476
- expect(h.count("browser")).toBe(1);
477
-
478
- await h.manager.ensureDesktopRunning();
479
- await settle();
480
- expect(h.count("x-server")).toBe(1);
481
- expect(h.count("browser")).toBe(2);
482
- });
483
-
484
- test("a browser exit under a viewer relaunches it, until it crash loops", async () => {
485
- const h = newManager();
486
- const { viewer, lost } = newViewer();
487
- h.manager.acquireViewerSlot(viewer);
488
- await h.manager.ensureDesktopRunning();
489
- await settle();
490
-
491
- for (let exits = 1; exits <= 3; exits += 1) {
492
- h.child("browser").exit(1);
493
- await settle();
494
- expect(h.count("browser")).toBe(exits + 1);
495
- expect(lost).toEqual([]);
496
- }
497
-
498
- h.child("browser").exit(1);
499
- await settle();
500
- expect(h.count("browser")).toBe(4);
501
- expect(lost).toEqual([
502
- { code: 4011, reason: "Desktop browser keeps crashing" },
503
- ]);
504
- expect(
505
- h
506
- .terminated()
507
- .map((c) => c.role)
508
- .sort(),
509
- ).toEqual([
510
- "clipboard",
511
- "compositor",
512
- "panel",
513
- "window-manager",
514
- "x-server",
515
- ]);
516
- });
517
-
518
- test("a browser that cannot be resolved takes the desktop down", async () => {
519
- const h = newManager();
520
- h.setChromiumPath(async () => {
521
- throw new Error("playwright install failed");
522
- });
523
- const { viewer, lost } = newViewer();
524
- h.manager.acquireViewerSlot(viewer);
525
- await h.manager.ensureDesktopRunning();
526
- await settle();
527
-
528
- expect(lost).toEqual([
529
- { code: 4011, reason: "Desktop browser failed to start" },
530
- ]);
531
- // The dock never got its Chromium path, so only the three fatal children
532
- // and no panel are killed.
533
- expect(
534
- h
535
- .terminated()
536
- .map((c) => c.role)
537
- .sort(),
538
- ).toEqual(["clipboard", "compositor", "window-manager", "x-server"]);
539
- });
540
-
541
- test("destroy terminates, hard-kills stragglers after the grace, and refuses what comes after", async () => {
542
- const h = newManager({ exitOnKill: true });
543
- const { viewer, lost } = newViewer();
544
- h.manager.acquireViewerSlot(viewer);
545
- await h.manager.ensureDesktopRunning();
546
- await settle();
547
-
548
- const started = Date.now();
549
- await Promise.all([h.manager.destroy(), h.manager.destroy()]);
550
-
551
- expect(Date.now() - started).toBeGreaterThanOrEqual(KILL_GRACE_MS - 2);
552
- expect(lost).toEqual([
553
- { code: 1001, reason: "The assistant is shutting down" },
554
- ]);
555
- expect(h.killed.map((k) => k.signal)).toEqual([
556
- ...Array(6).fill("SIGTERM"),
557
- ...Array(6).fill("SIGKILL"),
558
- ]);
559
- expect(h.manager.acquireViewerSlot(newViewer().viewer)).toEqual(
560
- SHUTTING_DOWN,
561
- );
562
- await expect(h.manager.ensureDesktopRunning()).rejects.toMatchObject({
563
- loss: SHUTTING_DOWN.loss,
564
- });
565
- });
566
-
567
- test("destroy still clears dock descendants when every direct child exits on SIGTERM", async () => {
568
- const h = newManager({ exitOnTerm: true });
569
- await h.manager.ensureDesktopRunning();
570
- await settle();
571
-
572
- await h.manager.destroy();
573
- expect(h.killed.filter((k) => k.signal === "SIGTERM")).toHaveLength(6);
574
- expect(h.killed.filter((k) => k.signal === "SIGKILL")).toEqual([
575
- { child: h.child("panel"), signal: "SIGKILL" },
576
- ]);
577
- });
578
- });
579
-
580
- describe("DesktopSessionManager viewer slot", () => {
581
- test("holds one viewer and only the holder can release it", () => {
582
- const h = newManager();
583
- const first = newViewer().viewer;
584
- const second = newViewer().viewer;
585
-
586
- expect(h.manager.acquireViewerSlot(first)).toEqual({ ok: true });
587
- expect(h.manager.acquireViewerSlot(second)).toEqual(BUSY);
588
-
589
- h.manager.releaseViewerSlot(second);
590
- expect(h.manager.acquireViewerSlot(second)).toEqual(BUSY);
591
-
592
- h.manager.releaseViewerSlot(first);
593
- expect(h.manager.acquireViewerSlot(second)).toEqual({ ok: true });
594
- });
595
-
596
- test("the tree lingers after the last viewer leaves, then is torn down", async () => {
597
- const h = newManager();
598
- const { viewer } = newViewer();
599
- h.manager.acquireViewerSlot(viewer);
600
- await h.manager.ensureDesktopRunning();
601
- await settle();
602
-
603
- h.manager.releaseViewerSlot(viewer);
604
- expect(h.killed).toEqual([]);
605
-
606
- await sleep(LINGER_MS * 2);
607
- expect(h.terminated()).toHaveLength(6);
608
- await h.manager.ensureDesktopRunning();
609
- expect(h.count("x-server")).toBe(2);
610
- });
611
-
612
- test("a viewer returning inside the linger window keeps the tree", async () => {
613
- const h = newManager();
614
- const { viewer } = newViewer();
615
- h.manager.acquireViewerSlot(viewer);
616
- await h.manager.ensureDesktopRunning();
617
- await settle();
618
-
619
- h.manager.releaseViewerSlot(viewer);
620
- h.manager.acquireViewerSlot(viewer);
621
- await sleep(LINGER_MS * 2);
622
-
623
- expect(h.killed).toEqual([]);
624
- await h.manager.ensureDesktopRunning();
625
- expect(h.count("x-server")).toBe(1);
626
- });
627
- });