@vellumai/assistant 0.12.1-staging.1 → 0.12.1

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 (404) 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/openapi.yaml +1 -291
  5. package/package.json +1 -1
  6. package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
  7. package/src/__tests__/app-compiler.test.ts +0 -6
  8. package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
  9. package/src/__tests__/app-dir-path-guard.test.ts +3 -1
  10. package/src/__tests__/app-source-watcher.test.ts +218 -0
  11. package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
  12. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
  13. package/src/__tests__/computer-use-tools.test.ts +5 -17
  14. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  15. package/src/__tests__/config-schema.test.ts +29 -28
  16. package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
  17. package/src/__tests__/config-watcher.test.ts +8 -23
  18. package/src/__tests__/connection-model-compat.test.ts +2 -2
  19. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  20. package/src/__tests__/conversation-pairing.test.ts +0 -26
  21. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
  22. package/src/__tests__/conversation-queue.test.ts +207 -48
  23. package/src/__tests__/conversation-retry-discard.test.ts +1 -54
  24. package/src/__tests__/conversation-skill-tools.test.ts +0 -27
  25. package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
  26. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
  27. package/src/__tests__/conversation-title-service.test.ts +10 -14
  28. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
  29. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
  30. package/src/__tests__/credential-record-retire.test.ts +1 -171
  31. package/src/__tests__/credential-routes.test.ts +3 -212
  32. package/src/__tests__/credential-security-invariants.test.ts +1 -2
  33. package/src/__tests__/cu-unified-flow.test.ts +2 -8
  34. package/src/__tests__/drain-kick-guard.test.ts +2 -0
  35. package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
  36. package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
  37. package/src/__tests__/host-bash-proxy.test.ts +45 -26
  38. package/src/__tests__/host-browser-proxy.test.ts +17 -6
  39. package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
  40. package/src/__tests__/host-file-proxy.test.ts +23 -11
  41. package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
  42. package/src/__tests__/llm-catalog-parity.test.ts +0 -25
  43. package/src/__tests__/mcp-auth-routes.test.ts +9 -6
  44. package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
  45. package/src/__tests__/mcp-health-check.test.ts +11 -8
  46. package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
  47. package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
  48. package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
  49. package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
  50. package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
  51. package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
  52. package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
  53. package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
  54. package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
  55. package/src/__tests__/messaging-send-tool.test.ts +548 -355
  56. package/src/__tests__/model-intents.test.ts +0 -3
  57. package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
  58. package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
  59. package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
  60. package/src/__tests__/script-proxy-certs.test.ts +0 -35
  61. package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
  62. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  63. package/src/__tests__/speaker-identification.test.ts +56 -0
  64. package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
  65. package/src/__tests__/subagent-tools.test.ts +2 -3
  66. package/src/__tests__/telephony-tts-guard.test.ts +3 -38
  67. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
  68. package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
  69. package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
  70. package/src/__tests__/workspace-git-service.test.ts +0 -26
  71. package/src/acp/__tests__/agent-process.test.ts +4 -258
  72. package/src/acp/__tests__/auth-required.test.ts +0 -96
  73. package/src/acp/__tests__/client-handler.test.ts +2 -90
  74. package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
  75. package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
  76. package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
  77. package/src/acp/__tests__/session-manager.test.ts +4 -895
  78. package/src/acp/agent-process.test.ts +1 -4
  79. package/src/acp/agent-process.ts +9 -94
  80. package/src/acp/auth-required.ts +1 -50
  81. package/src/acp/auto-install.test.ts +7 -9
  82. package/src/acp/client-handler.ts +3 -16
  83. package/src/acp/resolve-agent.test.ts +6 -220
  84. package/src/acp/resolve-agent.ts +23 -88
  85. package/src/acp/session-manager.test.ts +3 -196
  86. package/src/acp/session-manager.ts +18 -441
  87. package/src/acp/types.ts +5 -50
  88. package/src/api/events/app-files-changed.ts +3 -4
  89. package/src/api/index.ts +0 -6
  90. package/src/apps/app-store.ts +1 -1
  91. package/src/bundler/app-compiler.ts +0 -15
  92. package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
  93. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
  94. package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
  95. package/src/calls/call-constants.ts +4 -24
  96. package/src/calls/call-controller.ts +199 -499
  97. package/src/calls/call-transport.ts +0 -16
  98. package/src/calls/media-stream-output.ts +0 -32
  99. package/src/calls/media-stream-server.ts +30 -82
  100. package/src/calls/media-stream-stt-session.ts +0 -15
  101. package/src/calls/resolve-call-tts-provider.ts +2 -33
  102. package/src/calls/speaker-identification.ts +233 -0
  103. package/src/calls/tts-call-strategy.ts +5 -9
  104. package/src/calls/types.ts +0 -2
  105. package/src/calls/voice-control-protocol.ts +21 -53
  106. package/src/calls/voice-session-bridge.ts +46 -59
  107. package/src/calls/voice-triage-escalate.ts +56 -175
  108. package/src/cli/commands/apps.help.ts +13 -67
  109. package/src/cli/commands/apps.ts +0 -183
  110. package/src/cli/commands/channels/index.help.ts +2 -70
  111. package/src/cli/commands/channels/index.ts +3 -16
  112. package/src/cli/commands/credentials.help.ts +2 -6
  113. package/src/cli/commands/credentials.ts +2 -2
  114. package/src/cli/commands/mcp.help.ts +8 -8
  115. package/src/cli/commands/mcp.ts +1 -1
  116. package/src/cli/commands/roadmap.help.ts +1 -5
  117. package/src/cli/commands/roadmap.ts +1 -1
  118. package/src/cli/lib/bundled-marketplace.json +90 -103
  119. package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
  120. package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
  121. package/src/config/__tests__/platform-rehydration.test.ts +0 -93
  122. package/src/config/acp-defaults.test.ts +3 -13
  123. package/src/config/acp-defaults.ts +6 -23
  124. package/src/config/acp-schema.ts +2 -30
  125. package/src/config/bundled-skills/acp/SKILL.md +14 -22
  126. package/src/config/bundled-skills/acp/TOOLS.json +1 -5
  127. package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
  128. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
  129. package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
  130. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
  131. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
  132. package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
  133. package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
  134. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  135. package/src/config/default-profile-catalog.ts +1 -1
  136. package/src/config/env.ts +2 -2
  137. package/src/config/feature-flag-registry.json +12 -8
  138. package/src/config/memory-v3-gate.test.ts +0 -31
  139. package/src/config/memory-v3-gate.ts +16 -20
  140. package/src/config/platform-rehydration.ts +21 -75
  141. package/src/config/schema.ts +2 -2
  142. package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
  143. package/src/config/schemas/calls.ts +28 -1
  144. package/src/config/schemas/live-voice.ts +173 -1
  145. package/src/config/schemas/mcp.ts +1 -1
  146. package/src/config/schemas/memory-retrospective.ts +0 -10
  147. package/src/config/schemas/skills.ts +14 -0
  148. package/src/credential-execution/process-manager.test.ts +19 -18
  149. package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
  150. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
  151. package/src/daemon/app-source-watcher.ts +218 -0
  152. package/src/daemon/config-watcher.ts +194 -13
  153. package/src/daemon/conversation-process.ts +64 -35
  154. package/src/daemon/conversation-skill-tools.ts +31 -13
  155. package/src/daemon/conversation-store.ts +1 -1
  156. package/src/daemon/conversation-surfaces.ts +8 -10
  157. package/src/daemon/conversation-tool-setup.ts +43 -37
  158. package/src/daemon/conversation.ts +3 -0
  159. package/src/daemon/host-bash-proxy.ts +12 -8
  160. package/src/daemon/host-browser-proxy.ts +1 -15
  161. package/src/daemon/host-file-proxy.ts +10 -8
  162. package/src/daemon/host-transfer-proxy.ts +18 -14
  163. package/src/daemon/lifecycle.ts +5 -0
  164. package/src/daemon/mcp-reload-service.ts +5 -5
  165. package/src/daemon/message-types/sync.ts +0 -1
  166. package/src/daemon/providers-setup.ts +1 -1
  167. package/src/daemon/shutdown-handlers.ts +9 -1
  168. package/src/daemon/skill-memory-refresh.ts +0 -64
  169. package/src/daemon/tool-side-effects.ts +18 -7
  170. package/src/hooks/types.ts +0 -33
  171. package/src/inbound/platform-callback-registration.ts +5 -4
  172. package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
  173. package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
  174. package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
  175. package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
  176. package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
  177. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
  178. package/src/live-voice/live-voice-session.ts +693 -213
  179. package/src/{calls → live-voice}/progress-narration.ts +2 -2
  180. package/src/live-voice/protocol.ts +2 -0
  181. package/src/mcp/__tests__/effective-config.test.ts +2 -2
  182. package/src/mcp/effective-config.ts +3 -3
  183. package/src/mcp/mcp-header-store.ts +45 -29
  184. package/src/mcp/startup.ts +4 -8
  185. package/src/messaging/provider.ts +3 -10
  186. package/src/messaging/providers/callback-routing.ts +0 -18
  187. package/src/messaging/providers/channel-transport.ts +0 -56
  188. package/src/messaging/providers/discord/transport.ts +0 -17
  189. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
  190. package/src/messaging/providers/slack/adapter.ts +44 -7
  191. package/src/messaging/providers/slack/transport.ts +0 -16
  192. package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
  193. package/src/messaging/providers/telegram-bot/client.ts +26 -0
  194. package/src/messaging/providers/telegram-bot/transport.ts +0 -20
  195. package/src/messaging/providers/whatsapp/adapter.ts +48 -1
  196. package/src/messaging/providers/whatsapp/client.ts +29 -0
  197. package/src/messaging/providers/whatsapp/transport.ts +0 -18
  198. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
  199. package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
  200. package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
  201. package/src/notifications/assistant-reply-producer.ts +3 -8
  202. package/src/notifications/conversation-pairing.ts +16 -36
  203. package/src/notifications/delivered-post-record.ts +1 -11
  204. package/src/notifications/home-feed-side-effect.ts +7 -55
  205. package/src/outbound-proxy/certs.ts +5 -3
  206. package/src/permissions/checker.test.ts +6 -11
  207. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  208. package/src/persistence/conversation-crud.ts +63 -71
  209. package/src/persistence/conversation-lineage.ts +4 -12
  210. package/src/persistence/conversation-title-service.ts +26 -9
  211. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  212. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  213. package/src/persistence/message-reads.ts +0 -30
  214. package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
  215. package/src/persistence/schema/memory-core.ts +0 -5
  216. package/src/platform/client.test.ts +0 -2
  217. package/src/platform/client.ts +10 -2
  218. package/src/plugin-api/constants.ts +0 -2
  219. package/src/plugin-api/index.ts +0 -1
  220. package/src/plugin-api/types.ts +0 -2
  221. package/src/plugins/defaults/index.ts +0 -2
  222. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
  223. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
  224. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
  225. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
  226. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
  227. package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
  228. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
  229. package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
  230. package/src/plugins/defaults/memory/hooks/init.ts +0 -10
  231. package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
  232. package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
  233. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
  234. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
  235. package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
  236. package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
  237. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
  238. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
  239. package/src/plugins/defaults/memory/startup.ts +1 -6
  240. package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
  241. package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
  242. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
  243. package/src/plugins/defaults/memory/worker.ts +0 -6
  244. package/src/plugins/mcp-servers.ts +75 -15
  245. package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
  246. package/src/providers/gemini/client.ts +23 -9
  247. package/src/providers/model-catalog.ts +0 -34
  248. package/src/providers/model-intents.ts +5 -10
  249. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
  250. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
  251. package/src/providers/openai/chat-completions-provider.ts +78 -192
  252. package/src/providers/openai/codex-models.ts +4 -0
  253. package/src/runtime/AGENTS.md +0 -2
  254. package/src/runtime/auth/same-actor.ts +3 -38
  255. package/src/runtime/http-server.ts +151 -160
  256. package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
  257. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
  258. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
  259. package/src/runtime/routes/acp-routes.test.ts +0 -15
  260. package/src/runtime/routes/acp-routes.ts +9 -72
  261. package/src/runtime/routes/app-management-routes.ts +0 -73
  262. package/src/runtime/routes/app-routes.ts +1 -1
  263. package/src/runtime/routes/conversation-list-routes.ts +3 -14
  264. package/src/runtime/routes/conversation-query-routes.ts +0 -40
  265. package/src/runtime/routes/credential-routes.ts +10 -19
  266. package/src/runtime/routes/diagnostics-routes.ts +3 -55
  267. package/src/runtime/routes/index.ts +0 -4
  268. package/src/runtime/routes/log-export-routes.ts +0 -2
  269. package/src/runtime/routes/mcp-auth-routes.ts +47 -39
  270. package/src/runtime/routes/migration-routes.ts +21 -8
  271. package/src/runtime/routes/platform-routes.ts +15 -18
  272. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
  273. package/src/runtime/services/conversation-serializer.ts +3 -16
  274. package/src/runtime/sync/resource-sync-events.ts +1 -2
  275. package/src/schedule/worker.ts +1 -1
  276. package/src/security/ces-rpc-record-backend.ts +0 -7
  277. package/src/subagent/consult-context.ts +25 -12
  278. package/src/tools/acp/list-agents.test.ts +1 -3
  279. package/src/tools/acp/spawn.test.ts +11 -146
  280. package/src/tools/acp/spawn.ts +3 -21
  281. package/src/tools/acp/status.ts +3 -40
  282. package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
  283. package/src/tools/capability-offer.test.ts +2 -22
  284. package/src/tools/capability-offer.ts +1 -16
  285. package/src/tools/computer-use/definitions.ts +2 -4
  286. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
  287. package/src/tools/credentials/metadata-store.ts +0 -100
  288. package/src/tools/host-filesystem/edit.test.ts +1 -2
  289. package/src/tools/host-filesystem/edit.ts +2 -2
  290. package/src/tools/host-filesystem/read.test.ts +1 -2
  291. package/src/tools/host-filesystem/read.ts +2 -2
  292. package/src/tools/host-filesystem/transfer.test.ts +1 -2
  293. package/src/tools/host-filesystem/transfer.ts +2 -2
  294. package/src/tools/host-filesystem/write.test.ts +1 -2
  295. package/src/tools/host-filesystem/write.ts +2 -2
  296. package/src/tools/host-terminal/host-shell.test.ts +0 -16
  297. package/src/tools/host-terminal/host-shell.ts +20 -4
  298. package/src/tools/policy-context.ts +7 -6
  299. package/src/tools/subagent/spawn.ts +8 -5
  300. package/src/tools/watch/watch-retro-report.ts +8 -0
  301. package/src/util/__tests__/language-subtag.test.ts +1 -23
  302. package/src/util/fs-watcher-error.ts +36 -0
  303. package/src/util/language-subtag.ts +0 -16
  304. package/src/util/platform.ts +0 -8
  305. package/src/workspace/git-service.ts +54 -5
  306. package/src/workspace/migrations/registry.ts +0 -6
  307. package/scripts/smoke-desktop-window-theme.ts +0 -186
  308. package/src/__tests__/git-porcelain.test.ts +0 -47
  309. package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
  310. package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
  311. package/src/__tests__/resolve-app.test.ts +0 -135
  312. package/src/__tests__/source-fingerprint.test.ts +0 -184
  313. package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
  314. package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
  315. package/src/acp/model-config.test.ts +0 -166
  316. package/src/acp/model-config.ts +0 -138
  317. package/src/api/events/acp-session-model-update.test.ts +0 -88
  318. package/src/api/events/acp-session-model-update.ts +0 -46
  319. package/src/apps/resolve-app.ts +0 -81
  320. package/src/apps/source-fingerprint.ts +0 -266
  321. package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
  322. package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
  323. package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
  324. package/src/calls/barge-in-guard.ts +0 -118
  325. package/src/calls/voice-leg-coordinator.ts +0 -189
  326. package/src/calls/voice-progress-cadence.ts +0 -423
  327. package/src/cli/commands/__tests__/apps.test.ts +0 -245
  328. package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
  329. package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
  330. package/src/cli/commands/channels/send.ts +0 -128
  331. package/src/config/__tests__/platform-identity.test.ts +0 -117
  332. package/src/config/acp-agent-write.ts +0 -43
  333. package/src/config/acp-schema.test.ts +0 -81
  334. package/src/config/platform-identity.ts +0 -144
  335. package/src/config/schemas/__tests__/voice.test.ts +0 -148
  336. package/src/config/schemas/voice.ts +0 -150
  337. package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
  338. package/src/daemon/app-change-notify.ts +0 -45
  339. package/src/desktop/__tests__/fake-desktop.ts +0 -119
  340. package/src/desktop/desktop-chrome-policy.test.ts +0 -71
  341. package/src/desktop/desktop-chrome-policy.ts +0 -42
  342. package/src/desktop/desktop-dependencies.test.ts +0 -102
  343. package/src/desktop/desktop-dependencies.ts +0 -306
  344. package/src/desktop/desktop-feature.test.ts +0 -18
  345. package/src/desktop/desktop-feature.ts +0 -19
  346. package/src/desktop/desktop-panel-config.test.ts +0 -135
  347. package/src/desktop/desktop-panel-config.ts +0 -149
  348. package/src/desktop/desktop-session-manager.test.ts +0 -627
  349. package/src/desktop/desktop-session-manager.ts +0 -814
  350. package/src/desktop/desktop-stream-bridge.test.ts +0 -395
  351. package/src/desktop/desktop-stream-bridge.ts +0 -214
  352. package/src/desktop/desktop-wallpaper.test.ts +0 -191
  353. package/src/desktop/desktop-wallpaper.ts +0 -113
  354. package/src/desktop/desktop-window-theme.ts +0 -170
  355. package/src/i18n/AGENTS.md +0 -22
  356. package/src/i18n/__tests__/i18n.test.ts +0 -108
  357. package/src/i18n/index.ts +0 -16
  358. package/src/i18n/locales.ts +0 -93
  359. package/src/i18n/messages.ts +0 -61
  360. package/src/i18n/title.ts +0 -25
  361. package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
  362. package/src/mcp/spec-schema.ts +0 -111
  363. package/src/mcp/workspace-mcp-config.ts +0 -188
  364. package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
  365. package/src/persistence/conversation-title-placeholders.ts +0 -23
  366. package/src/persistence/message-cursor.ts +0 -78
  367. package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
  368. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
  369. package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
  370. package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
  371. package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
  372. package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
  373. package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
  374. package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
  375. package/src/providers/gemini-thought-signature.test.ts +0 -63
  376. package/src/providers/gemini-thought-signature.ts +0 -44
  377. package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
  378. package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
  379. package/src/providers/openai/google-thought-signature.ts +0 -320
  380. package/src/runtime/__tests__/channel-send.test.ts +0 -443
  381. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
  382. package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
  383. package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
  384. package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
  385. package/src/runtime/channel-send.ts +0 -316
  386. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
  387. package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
  388. package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
  389. package/src/runtime/routes/channel-send-routes.ts +0 -85
  390. package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
  391. package/src/runtime/routes/desktop-setup-routes.ts +0 -35
  392. package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
  393. package/src/security/ces-http-record-backend.ts +0 -120
  394. package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
  395. package/src/skills/workspace-skill-md-signature.ts +0 -50
  396. package/src/tools/acp/status.test.ts +0 -94
  397. package/src/util/ca-bundle.ts +0 -13
  398. package/src/workspace/git-porcelain.ts +0 -66
  399. package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
  400. package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
  401. package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
  402. package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
  403. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
  404. /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
@@ -1,306 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { createReadStream, existsSync } from "node:fs";
3
- import { chmod, mkdir, mkdtemp, rename, rm, writeFile } from "node:fs/promises";
4
- import { tmpdir } from "node:os";
5
- import { join } from "node:path";
6
-
7
- import { SYNC_TAGS } from "../daemon/message-types/sync.js";
8
- import { publishSyncInvalidation } from "../runtime/sync/sync-publisher.js";
9
- import { writeCombinedCABundle } from "../util/ca-bundle.js";
10
- import { terminateProcessTree } from "../util/host-process.js";
11
- import { getLogger } from "../util/logger.js";
12
- import { getExternalDir } from "../util/platform.js";
13
-
14
- const log = getLogger("desktop-dependencies");
15
- const CHROME_VERSION = "153.0.8010.36-1";
16
- const CHROME_PACKAGES = {
17
- x64: {
18
- arch: "amd64",
19
- sha256: "9bb44e33031c2f2857cf36b4343051a12f93058e4b781e3c76313df87f6c8d32",
20
- },
21
- arm64: {
22
- arch: "arm64",
23
- sha256: "1fcf6ec51a9d52e26ff1ad807225f725be55069ad2b68c5d69361a2746665188",
24
- },
25
- } as const;
26
-
27
- const DESKTOP_BINARIES = {
28
- xServer: ["Xtigervnc"],
29
- windowManager: ["openbox"],
30
- compositor: ["xcompmgr"],
31
- panel: ["plank"],
32
- panelSession: ["dbus-run-session"],
33
- clipboard: ["tigervncconfig", "vncconfig"],
34
- terminal: ["xterm"],
35
- wallpaper: ["feh"],
36
- } as const;
37
-
38
- const DESKTOP_PACKAGES = [
39
- "dbus-x11",
40
- "feh",
41
- "gnome-mines",
42
- "openbox",
43
- "tigervnc-standalone-server",
44
- "tigervnc-common",
45
- "plank",
46
- "bamfdaemon",
47
- "dbus-daemon",
48
- "xauth",
49
- "xcompmgr",
50
- "xfonts-base",
51
- "xterm",
52
- "fonts-liberation",
53
- "libgtk-3-0",
54
- "libvulkan1",
55
- "libcurl4",
56
- ];
57
-
58
- export type DesktopSetupStatus = {
59
- state: "required" | "installing" | "ready" | "failed" | "unsupported";
60
- stage?: "packages" | "chrome" | "checking";
61
- };
62
-
63
- export function desktopChromePath(): string {
64
- return join(
65
- getExternalDir(),
66
- "desktop",
67
- `chrome-${CHROME_VERSION}`,
68
- "opt/google/chrome/chrome",
69
- );
70
- }
71
-
72
- export function resolveDesktopBinaries(
73
- which: (name: string) => string | null = Bun.which,
74
- ) {
75
- const resolved = {} as Record<keyof typeof DESKTOP_BINARIES, string>;
76
- for (const [role, names] of Object.entries(DESKTOP_BINARIES)) {
77
- const path = names.map((name) => which(name)).find(Boolean);
78
- if (!path) {
79
- throw new Error(`Desktop component is missing: ${names[0]}`);
80
- }
81
- resolved[role as keyof typeof DESKTOP_BINARIES] = path;
82
- }
83
- return resolved;
84
- }
85
-
86
- export class DesktopDependencyInstaller {
87
- private installing: Promise<void> | null = null;
88
- private status: DesktopSetupStatus | null = null;
89
-
90
- constructor(
91
- private readonly dependencies: {
92
- supported: () => boolean;
93
- ready: () => boolean;
94
- install: (
95
- onStage: (stage: NonNullable<DesktopSetupStatus["stage"]>) => void,
96
- ) => Promise<void>;
97
- notify: () => Promise<unknown>;
98
- } = {
99
- supported: () =>
100
- process.platform === "linux" &&
101
- process.arch in CHROME_PACKAGES &&
102
- process.getuid?.() === 0,
103
- ready: () => {
104
- try {
105
- resolveDesktopBinaries();
106
- return (
107
- existsSync(desktopChromePath() + ".ready") &&
108
- existsSync(desktopChromePath()) &&
109
- existsSync("/usr/games/gnome-mines") &&
110
- existsSync("/usr/share/fonts/X11/misc/fonts.dir") &&
111
- existsSync("/usr/share/dbus-1/services/org.ayatana.bamf.service")
112
- );
113
- } catch {
114
- return false;
115
- }
116
- },
117
- install: installDesktopDependencies,
118
- notify: () => publishSyncInvalidation([SYNC_TAGS.assistantDesktop]),
119
- },
120
- ) {}
121
-
122
- getStatus(): DesktopSetupStatus {
123
- if (this.installing) {
124
- return this.status!;
125
- }
126
- if (!this.dependencies.supported()) {
127
- return { state: "unsupported" };
128
- }
129
- if (this.status?.state === "failed") {
130
- return this.status;
131
- }
132
- return { state: this.dependencies.ready() ? "ready" : "required" };
133
- }
134
-
135
- start(): DesktopSetupStatus {
136
- const status = this.getStatus();
137
- if (
138
- status.state === "ready" ||
139
- status.state === "installing" ||
140
- status.state === "unsupported"
141
- ) {
142
- return status;
143
- }
144
- this.status = { state: "installing", stage: "packages" };
145
- this.installing = Promise.resolve()
146
- .then(async () => {
147
- await this.dependencies.install((stage) =>
148
- this.update({ state: "installing", stage }),
149
- );
150
- if (!this.dependencies.ready()) {
151
- throw new Error("Desktop components are missing after installation");
152
- }
153
- this.status = { state: "ready" };
154
- })
155
- .catch((err: unknown) => {
156
- log.warn({ err }, "Desktop installation failed");
157
- this.status = { state: "failed" };
158
- })
159
- .finally(() => {
160
- this.installing = null;
161
- this.update(this.status!);
162
- });
163
- this.update(this.status);
164
- return this.status;
165
- }
166
-
167
- async ensureReady(): Promise<void> {
168
- this.start();
169
- await this.installing;
170
- if (this.getStatus().state !== "ready") {
171
- throw new Error("Desktop setup did not complete");
172
- }
173
- }
174
-
175
- private update(status: DesktopSetupStatus): void {
176
- this.status = status;
177
- void this.dependencies.notify().catch((err: unknown) => {
178
- log.warn({ err }, "Desktop setup notification failed");
179
- });
180
- }
181
- }
182
-
183
- async function run(command: string[]): Promise<void> {
184
- const proc = Bun.spawn(command, {
185
- env: {
186
- PATH: "/usr/sbin:/usr/bin:/sbin:/bin",
187
- HOME: "/root",
188
- DEBIAN_FRONTEND: "noninteractive",
189
- },
190
- stdin: "ignore",
191
- stdout: "pipe",
192
- stderr: "pipe",
193
- windowsHide: true,
194
- detached: true,
195
- });
196
- const timeout = setTimeout(() => terminateProcessTree(proc), 10 * 60_000);
197
- let output = "";
198
- const drain = async (stream: ReadableStream<Uint8Array>) => {
199
- for await (const chunk of stream) {
200
- output = (output + new TextDecoder().decode(chunk)).slice(-8_000);
201
- }
202
- };
203
- const [code] = await Promise.all([
204
- proc.exited,
205
- drain(proc.stdout),
206
- drain(proc.stderr),
207
- ]).finally(() => clearTimeout(timeout));
208
- if (code !== 0) {
209
- throw new Error(`Desktop installer exited with ${code}: ${output}`);
210
- }
211
- }
212
-
213
- async function installDesktopDependencies(
214
- onStage: (stage: NonNullable<DesktopSetupStatus["stage"]>) => void,
215
- ): Promise<void> {
216
- const extraCA = process.env.NODE_EXTRA_CA_CERTS;
217
- if (!extraCA) {
218
- return installDesktopComponents(onStage);
219
- }
220
- const caDir = await mkdtemp(join(tmpdir(), "desktop-ca-"));
221
- try {
222
- const caBundle = join(caDir, "ca.pem");
223
- await writeCombinedCABundle(
224
- "/etc/ssl/certs/ca-certificates.crt",
225
- extraCA,
226
- caBundle,
227
- );
228
- // apt's unprivileged downloader must be able to read the public CAs.
229
- await chmod(caBundle, 0o644);
230
- await chmod(caDir, 0o755);
231
- await installDesktopComponents(onStage, caBundle);
232
- } finally {
233
- await rm(caDir, { recursive: true, force: true });
234
- }
235
- }
236
-
237
- async function installDesktopComponents(
238
- onStage: (stage: NonNullable<DesktopSetupStatus["stage"]>) => void,
239
- caBundle?: string,
240
- ): Promise<void> {
241
- const chrome = CHROME_PACKAGES[process.arch as keyof typeof CHROME_PACKAGES];
242
- const apt = [
243
- "/usr/bin/apt-get",
244
- ...(caBundle ? ["-o", `Acquire::https::CaInfo=${caBundle}`] : []),
245
- ];
246
- await rm(desktopChromePath() + ".ready", { force: true });
247
- // Desktop binaries, X assets and the loader share the image root.
248
- await run([...apt, "update"]);
249
- await run([
250
- ...apt,
251
- "install",
252
- "-y",
253
- "--no-install-recommends",
254
- "--no-upgrade",
255
- "--no-remove",
256
- "-o",
257
- "DPkg::Lock::Timeout=120",
258
- ...DESKTOP_PACKAGES,
259
- ]);
260
- onStage("chrome");
261
- if (!existsSync(desktopChromePath())) {
262
- const downloadDir = await mkdtemp(join(tmpdir(), "desktop-chrome-"));
263
- const installRoot = join(getExternalDir(), "desktop");
264
- await mkdir(installRoot, { recursive: true });
265
- const staging = await mkdtemp(join(installRoot, ".install-"));
266
- try {
267
- const deb = join(downloadDir, "chrome.deb");
268
- await run([
269
- "curl",
270
- ...(caBundle ? ["--cacert", caBundle] : []),
271
- "--fail",
272
- "--location",
273
- "--proto",
274
- "=https",
275
- "--proto-redir",
276
- "=https",
277
- "--retry",
278
- "2",
279
- "--max-time",
280
- "300",
281
- "--output",
282
- deb,
283
- `https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${CHROME_VERSION}_${chrome.arch}.deb`,
284
- ]);
285
- const hash = createHash("sha256");
286
- for await (const chunk of createReadStream(deb)) {
287
- hash.update(chunk);
288
- }
289
- if (hash.digest("hex") !== chrome.sha256) {
290
- throw new Error("Chrome download checksum mismatch");
291
- }
292
- await run(["dpkg-deb", "--extract", deb, staging]);
293
- await rename(staging, join(installRoot, `chrome-${CHROME_VERSION}`));
294
- } finally {
295
- await Promise.all([
296
- rm(downloadDir, { recursive: true, force: true }),
297
- rm(staging, { recursive: true, force: true }),
298
- ]);
299
- }
300
- }
301
- onStage("checking");
302
- await run([desktopChromePath(), "--version"]);
303
- await writeFile(desktopChromePath() + ".ready", "");
304
- }
305
-
306
- export const desktopDependencyInstaller = new DesktopDependencyInstaller();
@@ -1,18 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
-
3
- import { setOverridesForTesting } from "../__tests__/feature-flag-test-helpers.js";
4
- import type { AssistantConfig } from "../config/schema.js";
5
- import { isAssistantDesktopEnabled } from "./desktop-feature.js";
6
-
7
- describe("isAssistantDesktopEnabled", () => {
8
- const config = {} as AssistantConfig;
9
-
10
- test("needs both the flag and a containerized runtime", () => {
11
- setOverridesForTesting({ "assistant-desktop": true });
12
- expect(isAssistantDesktopEnabled(config, true)).toBe(true);
13
- expect(isAssistantDesktopEnabled(config, false)).toBe(false);
14
-
15
- setOverridesForTesting({ "assistant-desktop": false });
16
- expect(isAssistantDesktopEnabled(config, true)).toBe(false);
17
- });
18
- });
@@ -1,19 +0,0 @@
1
- import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
2
- import { getIsContainerized } from "../config/env-registry.js";
3
- import type { AssistantConfig } from "../config/schema.js";
4
-
5
- const ASSISTANT_DESKTOP_FLAG = "assistant-desktop" as const;
6
-
7
- /**
8
- * Whether this daemon serves `/v1/desktop/stream`: the `assistant-desktop` flag
9
- * plus a containerized runtime where desktop components can be installed.
10
- */
11
- export function isAssistantDesktopEnabled(
12
- config: AssistantConfig,
13
- containerized: boolean = getIsContainerized(),
14
- ): boolean {
15
- return (
16
- containerized &&
17
- isAssistantFeatureFlagEnabled(ASSISTANT_DESKTOP_FLAG, config)
18
- );
19
- }
@@ -1,135 +0,0 @@
1
- import * as fs from "node:fs";
2
- import {
3
- mkdirSync,
4
- mkdtempSync,
5
- readFileSync,
6
- rmSync,
7
- writeFileSync,
8
- } from "node:fs";
9
- import { tmpdir } from "node:os";
10
- import { join } from "node:path";
11
- import { afterEach, expect, spyOn, test } from "bun:test";
12
-
13
- import { writeDesktopPanelConfig } from "./desktop-panel-config.js";
14
-
15
- const workspaces: string[] = [];
16
-
17
- afterEach(() => {
18
- for (const dir of workspaces.splice(0)) {
19
- rmSync(dir, { recursive: true, force: true });
20
- }
21
- });
22
-
23
- test("initializes the dock and preserves user changes across restarts", () => {
24
- const workspace = mkdtempSync(join(tmpdir(), "desktop-dock-"));
25
- workspaces.push(workspace);
26
- const configDir = join(workspace, "data", "desktop-panel");
27
- const profileDir = join(workspace, "data", "desktop-profile");
28
- mkdirSync(configDir, { recursive: true });
29
- mkdirSync(profileDir, { recursive: true });
30
- writeFileSync(join(profileDir, "Preferences"), "browser preferences");
31
- writeFileSync(join(configDir, "wallpaper.png"), "keep");
32
- const request = {
33
- configDir,
34
- chromiumPath: "/opt/chrome-v1/chrome",
35
- chromiumProfileDir: profileDir,
36
- terminalPath: "/usr/bin/xterm",
37
- };
38
- writeDesktopPanelConfig(request);
39
- const settingsPath = join(configDir, "glib-2.0", "settings", "keyfile");
40
- const pinsDir = join(configDir, "plank", "dock1", "launchers");
41
- const settings = readFileSync(settingsPath, "utf8");
42
- expect(settings.length).toBeGreaterThan(0);
43
- expect(
44
- readFileSync(join(pinsDir, "chrome.dockitem"), "utf8"),
45
- ).not.toBeEmpty();
46
-
47
- expect(readFileSync(join(pinsDir, "mines.dockitem"), "utf8")).toContain(
48
- "applications/org.gnome.Mines.desktop",
49
- );
50
- expect(
51
- readFileSync(
52
- join(configDir, "applications", "org.gnome.Mines.desktop"),
53
- "utf8",
54
- ),
55
- ).toContain("Exec=/usr/games/gnome-mines");
56
-
57
- // Removed pins stay removed across restarts.
58
- rmSync(join(pinsDir, "chrome.dockitem"));
59
- rmSync(join(pinsDir, "mines.dockitem"));
60
- const customSettings = settings.replace("icon-size=48", "icon-size=64");
61
- writeFileSync(settingsPath, customSettings);
62
- writeDesktopPanelConfig({
63
- ...request,
64
- chromiumPath: "/opt/chrome-v2/chrome",
65
- });
66
- expect(() => readFileSync(join(pinsDir, "chrome.dockitem"))).toThrow();
67
- expect(() => readFileSync(join(pinsDir, "mines.dockitem"))).toThrow();
68
- expect(readFileSync(settingsPath, "utf8")).toBe(customSettings);
69
- expect(
70
- readFileSync(
71
- join(configDir, "applications", "google-chrome.desktop"),
72
- "utf8",
73
- ),
74
- ).toContain("/opt/chrome-v2/chrome");
75
- expect(readFileSync(join(profileDir, "Preferences"), "utf8")).toBe(
76
- "browser preferences",
77
- );
78
- expect(readFileSync(join(configDir, "wallpaper.png"), "utf8")).toBe("keep");
79
- });
80
-
81
- test("initialization recovers partial pin creation", () => {
82
- const workspace = mkdtempSync(join(tmpdir(), "desktop-dock-"));
83
- workspaces.push(workspace);
84
- const configDir = join(workspace, "data", "desktop-panel");
85
- const pinsDir = join(configDir, "plank", "dock1", "launchers");
86
- mkdirSync(pinsDir, { recursive: true });
87
- writeFileSync(join(pinsDir, "chrome.dockitem"), "existing pin");
88
- writeDesktopPanelConfig({
89
- configDir,
90
- chromiumPath: "/opt/chrome/chrome",
91
- chromiumProfileDir: join(workspace, "data", "desktop-profile"),
92
- terminalPath: "/usr/bin/xterm",
93
- });
94
- expect(readFileSync(join(pinsDir, "chrome.dockitem"), "utf8")).toBe(
95
- "existing pin",
96
- );
97
- expect(
98
- readFileSync(join(pinsDir, "terminal.dockitem"), "utf8"),
99
- ).not.toBeEmpty();
100
- expect(
101
- readFileSync(join(configDir, "glib-2.0", "settings", "keyfile"), "utf8"),
102
- ).not.toBeEmpty();
103
- });
104
-
105
- test("a failed settings write leaves initialization retryable", () => {
106
- const workspace = mkdtempSync(join(tmpdir(), "desktop-dock-"));
107
- workspaces.push(workspace);
108
- const configDir = join(workspace, "data", "desktop-panel");
109
- const settingsPath = join(configDir, "glib-2.0", "settings", "keyfile");
110
- const request = {
111
- configDir,
112
- chromiumPath: "/opt/chrome/chrome",
113
- chromiumProfileDir: join(workspace, "data", "desktop-profile"),
114
- terminalPath: "/usr/bin/xterm",
115
- };
116
- const write = fs.writeFileSync;
117
- const interrupted = spyOn(fs, "writeFileSync").mockImplementation(
118
- (...args) => {
119
- if (String(args[0]).startsWith(`${settingsPath}.`)) {
120
- write(args[0], "partial settings");
121
- throw new Error("interrupted write");
122
- }
123
- write(...args);
124
- },
125
- );
126
- try {
127
- expect(() => writeDesktopPanelConfig(request)).toThrow("interrupted write");
128
- } finally {
129
- interrupted.mockRestore();
130
- }
131
- expect(fs.existsSync(settingsPath)).toBe(false);
132
- writeDesktopPanelConfig(request);
133
- expect(readFileSync(settingsPath, "utf8")).not.toContain("partial settings");
134
- expect(readFileSync(settingsPath, "utf8")).not.toBeEmpty();
135
- });
@@ -1,149 +0,0 @@
1
- import { randomUUID } from "node:crypto";
2
- import {
3
- existsSync,
4
- linkSync,
5
- mkdirSync,
6
- rmSync,
7
- writeFileSync,
8
- } from "node:fs";
9
- import { dirname, join } from "node:path";
10
- import { pathToFileURL } from "node:url";
11
-
12
- // Absolute icon paths work without an installed icon theme.
13
- const TERMINAL_ICON_BASE64 = [
14
- "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAACBklEQVR42u2bP2vCQBjG/T",
15
- "QOQkDQQVopsQ6l4BD6CTI5dXLq5tJRCP0SDh0dumboKthv4CR0Cwidr3nkAhLa/DM5L3fP",
16
- "wQMiQd/n573vvYl3nQ4HB0eZMZ0+urGCWGGsKJa4siIZC2JymzTux9rjS8fjezEc3grHGW",
17
- "ohxIKYJBDE6NdpvB9rN5k8nL6o1+uLbtfRUogNMSJWxIzYLzXvYYqBrs7G/wIhZwTSw7vE",
18
- "vBiN7lpjPC3ELtPCqzLtozabT0GISqUD8gdTqO3mE8l02BWu9igibcr5IjVBFka/CIA9Kq",
19
- "kp5hPBE7wVaXKM+vXPZ4EsiG4WgMCk3P+nFgRZAEITp38qDcIsABFaS1MBwBs8ZgEQFgAQ",
20
- "BEAANQIYDG5EGH6K4/HnJLzGe9YAODefaLv90hJCIwDS5hMdDt9iNnuyF4COEJSlQBrCfP",
21
- "5sdhFEzmdBgBaLF3OXQUDYbD60h9B4H7Bev+dCwDVGN0I6Q1DWCWKq50FAyqjuFZS2wkUg",
22
- "qG6YlN8LYPnDMpgFAcuo0TdDaITyIBAAU4BFkMsgGyG2wrwZsvt2GJ+zXL6K1eotV7iuSv",
23
- "3Q+oFI3ufUsXxq/UisjPmqDZTWD0UxtcuYx/V8LM4/RvjXGAEQQM0ArN8gYf0WGes3Sdm9",
24
- "Tc76jZLcKsvN0twuzwMTPDLDQ1M8NseDkxwc9oxfPKEkIHDjoAYAAAAASUVORK5CYII=",
25
- ].join("");
26
-
27
- export interface DesktopPanelConfigRequest {
28
- /** Runtime directory the config, launchers and icons are written to. */
29
- readonly configDir: string;
30
- /** Google Chrome, as resolved for the desktop's own browser. */
31
- readonly chromiumPath: string;
32
- /** Profile the launcher shares with that browser, so it reuses the window. */
33
- readonly chromiumProfileDir: string;
34
- readonly terminalPath: string;
35
- }
36
-
37
- /** Generate managed launchers and seed the desktop dock on first use. */
38
- export function writeDesktopPanelConfig(
39
- request: DesktopPanelConfigRequest,
40
- ): void {
41
- const { configDir } = request;
42
- mkdirSync(configDir, { recursive: true });
43
-
44
- const terminalIcon = join(configDir, "terminal.png");
45
- const browserIcon = join(
46
- dirname(request.chromiumPath),
47
- "product_logo_64.png",
48
- );
49
- writeFileSync(terminalIcon, Buffer.from(TERMINAL_ICON_BASE64, "base64"));
50
-
51
- const applicationsDir = join(configDir, "applications");
52
- mkdirSync(applicationsDir, { recursive: true });
53
- const chromiumEntry = join(applicationsDir, "google-chrome.desktop");
54
- const terminalEntry = join(applicationsDir, "xterm.desktop");
55
- const minesEntry = join(applicationsDir, "org.gnome.Mines.desktop");
56
- writeFileSync(
57
- chromiumEntry,
58
- desktopEntry({
59
- name: "Google Chrome",
60
- // Chrome includes its profile path in WM_CLASS.
61
- windowClass: `google-chrome (${request.chromiumProfileDir})`,
62
- icon: browserIcon,
63
- exec: `"${request.chromiumPath}" --no-sandbox --no-first-run --disable-dev-shm-usage "--user-data-dir=${request.chromiumProfileDir}"`,
64
- }),
65
- );
66
- writeFileSync(
67
- terminalEntry,
68
- desktopEntry({
69
- name: "Terminal",
70
- windowClass: "XTerm",
71
- icon: terminalIcon,
72
- // `-fa` picks a scalable font through fontconfig; xterm otherwise falls
73
- // back to the `fixed` bitmap, which is unreadable at this geometry.
74
- exec: `"${request.terminalPath}" -fa Monospace -fs 11 -bg '#1c1c22' -fg '#e6e6ea' -title Terminal`,
75
- }),
76
- );
77
-
78
- writeFileSync(
79
- minesEntry,
80
- desktopEntry({
81
- name: "Mines",
82
- windowClass: "org.gnome.Mines",
83
- icon: "/usr/share/icons/hicolor/scalable/apps/org.gnome.Mines.svg",
84
- exec: "/usr/games/gnome-mines",
85
- }),
86
- );
87
-
88
- const launchersDir = join(configDir, "plank", "dock1", "launchers");
89
- const settingsDir = join(configDir, "glib-2.0", "settings");
90
- mkdirSync(launchersDir, { recursive: true });
91
- mkdirSync(settingsDir, { recursive: true });
92
- // The settings file completes initialization; pins can then be removed.
93
- if (existsSync(join(settingsDir, "keyfile"))) {
94
- return;
95
- }
96
- seedFile(join(launchersDir, "chrome.dockitem"), dockItem(chromiumEntry));
97
- seedFile(join(launchersDir, "terminal.dockitem"), dockItem(terminalEntry));
98
- seedFile(join(launchersDir, "mines.dockitem"), dockItem(minesEntry));
99
- seedFile(
100
- join(settingsDir, "keyfile"),
101
- [
102
- "[net/launchpad/plank/docks/dock1]",
103
- "dock-items=['chrome.dockitem', 'terminal.dockitem', 'mines.dockitem']",
104
- "icon-size=48",
105
- "hide-mode='none'",
106
- "theme='Matte'",
107
- "auto-pinning=false",
108
- "",
109
- ].join("\n"),
110
- );
111
- }
112
-
113
- function dockItem(launcher: string): string {
114
- return `[PlankDockItemPreferences]\nLauncher=${pathToFileURL(launcher).href}\n`;
115
- }
116
-
117
- function seedFile(path: string, contents: string): void {
118
- const temporaryPath = `${path}.${randomUUID()}.tmp`;
119
- try {
120
- writeFileSync(temporaryPath, contents, { flush: true });
121
- // Publish a complete file atomically without replacing user settings.
122
- linkSync(temporaryPath, path);
123
- } catch (err) {
124
- if ((err as NodeJS.ErrnoException).code !== "EEXIST") {
125
- throw err;
126
- }
127
- } finally {
128
- rmSync(temporaryPath, { force: true });
129
- }
130
- }
131
-
132
- function desktopEntry(entry: {
133
- name: string;
134
- windowClass: string;
135
- icon: string;
136
- exec: string;
137
- }): string {
138
- return [
139
- "[Desktop Entry]",
140
- "Type=Application",
141
- "Version=1.0",
142
- `Name=${entry.name}`,
143
- `Icon=${entry.icon}`,
144
- `StartupWMClass=${entry.windowClass}`,
145
- `Exec=${entry.exec}`,
146
- "Terminal=false",
147
- "",
148
- ].join("\n");
149
- }