@vellumai/assistant 0.7.2 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (347) hide show
  1. package/ARCHITECTURE.md +16 -1
  2. package/docs/architecture/memory.md +5 -2
  3. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
  4. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -9
  5. package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
  6. package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
  7. package/openapi.yaml +449 -22
  8. package/package.json +1 -1
  9. package/src/__tests__/app-control-flow.test.ts +21 -11
  10. package/src/__tests__/assistant-event-hub.test.ts +48 -0
  11. package/src/__tests__/assistant-event.test.ts +0 -10
  12. package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -7
  13. package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -0
  14. package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
  15. package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
  16. package/src/__tests__/call-conversation-messages.test.ts +8 -2
  17. package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
  18. package/src/__tests__/channel-readiness-service.test.ts +4 -2
  19. package/src/__tests__/config-loader-backfill.test.ts +379 -0
  20. package/src/__tests__/config-schema.test.ts +1 -0
  21. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +18 -9
  22. package/src/__tests__/config-watcher.test.ts +140 -69
  23. package/src/__tests__/context-search-agent-runner.test.ts +61 -3
  24. package/src/__tests__/context-search-conversations-source.test.ts +0 -24
  25. package/src/__tests__/context-search-fanout.test.ts +0 -1
  26. package/src/__tests__/context-search-memory-source.test.ts +3 -7
  27. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
  28. package/src/__tests__/context-search-pkb-source.test.ts +0 -1
  29. package/src/__tests__/context-search-workspace-source.test.ts +0 -1
  30. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  31. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
  32. package/src/__tests__/conversation-agent-loop.test.ts +454 -5
  33. package/src/__tests__/conversation-error.test.ts +150 -3
  34. package/src/__tests__/conversation-process-callsite.test.ts +43 -0
  35. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  36. package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
  37. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  38. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  39. package/src/__tests__/conversation-store.test.ts +0 -18
  40. package/src/__tests__/conversation-surfaces-app-control.test.ts +15 -4
  41. package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
  42. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
  43. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  44. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  45. package/src/__tests__/credentials-cli.test.ts +7 -0
  46. package/src/__tests__/cu-unified-flow.test.ts +176 -10
  47. package/src/__tests__/date-context.test.ts +164 -2
  48. package/src/__tests__/disk-pressure-guard.test.ts +262 -0
  49. package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
  50. package/src/__tests__/disk-pressure-policy.test.ts +241 -0
  51. package/src/__tests__/disk-pressure-routes.test.ts +379 -0
  52. package/src/__tests__/disk-pressure-tools.test.ts +277 -0
  53. package/src/__tests__/disk-usage.test.ts +150 -0
  54. package/src/__tests__/events-client-registration.test.ts +52 -0
  55. package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
  56. package/src/__tests__/file-write-tool.test.ts +4 -10
  57. package/src/__tests__/filing-service.test.ts +3 -4
  58. package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
  59. package/src/__tests__/heartbeat-service.test.ts +260 -11
  60. package/src/__tests__/host-app-control-proxy.test.ts +195 -25
  61. package/src/__tests__/host-bash-proxy.test.ts +227 -34
  62. package/src/__tests__/host-bash-routes.test.ts +178 -13
  63. package/src/__tests__/host-cu-proxy.test.ts +210 -3
  64. package/src/__tests__/host-cu-routes-targeted.test.ts +141 -12
  65. package/src/__tests__/host-file-proxy-targeted.test.ts +48 -9
  66. package/src/__tests__/host-file-proxy.test.ts +268 -6
  67. package/src/__tests__/host-file-routes-targeted.test.ts +175 -17
  68. package/src/__tests__/host-transfer-proxy-targeted.test.ts +408 -59
  69. package/src/__tests__/host-transfer-routes-targeted.test.ts +232 -17
  70. package/src/__tests__/http-user-message-parity.test.ts +107 -1
  71. package/src/__tests__/injector-chain.test.ts +18 -6
  72. package/src/__tests__/injector-disk-pressure.test.ts +224 -0
  73. package/src/__tests__/managed-profile-guard.test.ts +18 -0
  74. package/src/__tests__/mcp-abort-signal.test.ts +130 -0
  75. package/src/__tests__/memory-admin-recall.test.ts +3 -11
  76. package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
  77. package/src/__tests__/normalize-onboarding.test.ts +180 -0
  78. package/src/__tests__/oauth-connect-routes.test.ts +316 -0
  79. package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
  80. package/src/__tests__/onboarding-persona-write.test.ts +308 -0
  81. package/src/__tests__/openai-provider.test.ts +45 -8
  82. package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
  83. package/src/__tests__/platform-callback-registration.test.ts +21 -4
  84. package/src/__tests__/platform.test.ts +2 -1
  85. package/src/__tests__/playbook-execution.test.ts +0 -43
  86. package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
  87. package/src/__tests__/prechat-onboarding-contract.test.ts +214 -27
  88. package/src/__tests__/provider-tool-name.test.ts +23 -0
  89. package/src/__tests__/relay-server.test.ts +15 -4
  90. package/src/__tests__/runtime-events-sse.test.ts +4 -8
  91. package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
  92. package/src/__tests__/secret-ingress-http.test.ts +0 -1
  93. package/src/__tests__/suggestion-routes.test.ts +46 -0
  94. package/src/__tests__/twilio-validation.test.ts +2 -2
  95. package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
  96. package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
  97. package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
  98. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
  99. package/src/approvals/guardian-decision-primitive.ts +13 -0
  100. package/src/approvals/guardian-request-resolvers.ts +16 -17
  101. package/src/backup/snapshot-lock.ts +2 -27
  102. package/src/bundler/compiler-tools.ts +3 -2
  103. package/src/calls/call-conversation-messages.ts +46 -10
  104. package/src/cli/commands/__tests__/webhooks.test.ts +0 -4
  105. package/src/cli/commands/bash.ts +35 -108
  106. package/src/cli/commands/contacts.ts +64 -25
  107. package/src/cli/commands/credentials.ts +56 -0
  108. package/src/cli/commands/memory-v2.ts +7 -6
  109. package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
  110. package/src/cli/commands/oauth/connect.ts +127 -1
  111. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -3
  112. package/src/cli/commands/platform/__tests__/connect.test.ts +7 -1
  113. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
  114. package/src/cli/commands/platform/__tests__/status.test.ts +103 -6
  115. package/src/cli/commands/platform/index.ts +16 -7
  116. package/src/cli/commands/status.ts +57 -0
  117. package/src/cli/program.ts +4 -2
  118. package/src/config/assistant-feature-flags.ts +13 -3
  119. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
  120. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +13 -7
  121. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
  122. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
  123. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
  124. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
  125. package/src/config/env.ts +0 -8
  126. package/src/config/feature-flag-registry.json +27 -3
  127. package/src/config/loader.ts +127 -8
  128. package/src/config/schemas/__tests__/memory-v2.test.ts +10 -5
  129. package/src/config/schemas/call-site-catalog.ts +14 -0
  130. package/src/config/schemas/channels.ts +0 -5
  131. package/src/config/schemas/heartbeat.ts +1 -1
  132. package/src/config/schemas/llm.ts +2 -0
  133. package/src/config/schemas/memory-lifecycle.ts +13 -0
  134. package/src/config/schemas/memory-v2.ts +75 -11
  135. package/src/config/schemas/platform.ts +43 -3
  136. package/src/config/schemas/services.ts +28 -0
  137. package/src/config/seed-inference-profiles.ts +230 -33
  138. package/src/contacts/contact-store.ts +0 -25
  139. package/src/daemon/__tests__/conversation-tool-setup.test.ts +86 -25
  140. package/src/daemon/assistant-attachments.ts +4 -4
  141. package/src/daemon/config-watcher.ts +85 -57
  142. package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
  143. package/src/daemon/conversation-agent-loop.ts +170 -33
  144. package/src/daemon/conversation-error.ts +87 -15
  145. package/src/daemon/conversation-lifecycle.ts +1 -3
  146. package/src/daemon/conversation-process.ts +8 -0
  147. package/src/daemon/conversation-runtime-assembly.ts +26 -0
  148. package/src/daemon/conversation-store.ts +2 -2
  149. package/src/daemon/conversation-surfaces.ts +195 -15
  150. package/src/daemon/conversation-tool-setup.ts +57 -14
  151. package/src/daemon/conversation.ts +17 -22
  152. package/src/daemon/date-context.ts +71 -22
  153. package/src/daemon/disk-pressure-background-gate.ts +73 -0
  154. package/src/daemon/disk-pressure-guard.ts +343 -0
  155. package/src/daemon/disk-pressure-policy.ts +163 -0
  156. package/src/daemon/handlers/shared.ts +0 -1
  157. package/src/daemon/handlers/skills.ts +3 -4
  158. package/src/daemon/host-app-control-proxy.ts +137 -41
  159. package/src/daemon/host-bash-proxy.ts +46 -21
  160. package/src/daemon/host-cu-proxy.ts +49 -3
  161. package/src/daemon/host-file-proxy.ts +43 -7
  162. package/src/daemon/host-transfer-proxy.ts +95 -4
  163. package/src/daemon/lifecycle.ts +79 -28
  164. package/src/daemon/meet-host-supervisor.ts +4 -4
  165. package/src/daemon/meet-manifest-loader.ts +0 -1
  166. package/src/daemon/memory-v2-startup.ts +14 -4
  167. package/src/daemon/message-protocol.ts +3 -0
  168. package/src/daemon/message-types/conversations.ts +4 -0
  169. package/src/daemon/message-types/disk-pressure.ts +9 -0
  170. package/src/daemon/message-types/messages.ts +3 -0
  171. package/src/daemon/profiler-run-store.ts +5 -5
  172. package/src/daemon/tool-setup-types.ts +2 -2
  173. package/src/documents/document-store.ts +85 -0
  174. package/src/filing/filing-service.ts +30 -5
  175. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +9 -16
  176. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +36 -0
  177. package/src/heartbeat/heartbeat-run-store.ts +13 -0
  178. package/src/heartbeat/heartbeat-service.ts +205 -31
  179. package/src/home/feed-scheduler.ts +18 -0
  180. package/src/inbound/platform-callback-registration.ts +8 -15
  181. package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
  182. package/src/ipc/assistant-server.ts +56 -2
  183. package/src/ipc/gateway-client.ts +37 -3
  184. package/src/live-voice/live-voice-archive.ts +4 -4
  185. package/src/live-voice/protocol.ts +5 -7
  186. package/src/media/image-service.ts +1 -7
  187. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
  188. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
  189. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
  190. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
  191. package/src/memory/admin.ts +5 -9
  192. package/src/memory/context-search/agent-runner.ts +19 -2
  193. package/src/memory/context-search/sources/conversations.ts +2 -11
  194. package/src/memory/context-search/sources/memory-v2.ts +5 -4
  195. package/src/memory/context-search/sources/memory.ts +0 -1
  196. package/src/memory/context-search/types.ts +0 -1
  197. package/src/memory/conversation-crud.ts +4 -12
  198. package/src/memory/db-init.ts +2 -0
  199. package/src/memory/embedding-runtime-manager.ts +119 -5
  200. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +32 -21
  201. package/src/memory/graph/conversation-graph-memory.ts +42 -54
  202. package/src/memory/graph/extraction.ts +1 -3
  203. package/src/memory/graph/graph-search.test.ts +10 -67
  204. package/src/memory/graph/graph-search.ts +1 -20
  205. package/src/memory/graph/retriever.test.ts +6 -0
  206. package/src/memory/graph/retriever.ts +6 -10
  207. package/src/memory/indexer.ts +54 -45
  208. package/src/memory/job-handlers/backfill.ts +2 -11
  209. package/src/memory/job-handlers/cleanup.ts +43 -0
  210. package/src/memory/job-handlers/embedding.ts +6 -8
  211. package/src/memory/job-handlers/summarization.ts +2 -7
  212. package/src/memory/jobs-store.ts +48 -0
  213. package/src/memory/jobs-worker.ts +81 -43
  214. package/src/memory/memory-v2-activation-log-store.ts +32 -14
  215. package/src/memory/memory-v2-concept-frequency.ts +169 -0
  216. package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
  217. package/src/memory/migrations/index.ts +1 -0
  218. package/src/memory/pkb/pkb-search.test.ts +6 -0
  219. package/src/memory/qdrant-client.ts +0 -13
  220. package/src/memory/rerank-local.ts +374 -0
  221. package/src/memory/search/semantic.ts +6 -67
  222. package/src/memory/trace-event-store.ts +1 -17
  223. package/src/memory/v2/__tests__/activation.test.ts +311 -250
  224. package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
  225. package/src/memory/v2/__tests__/injection.test.ts +157 -167
  226. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
  227. package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
  228. package/src/memory/v2/__tests__/reranker.test.ts +338 -0
  229. package/src/memory/v2/__tests__/sim.test.ts +5 -199
  230. package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
  231. package/src/memory/v2/__tests__/static-context.test.ts +76 -1
  232. package/src/memory/v2/activation.ts +149 -156
  233. package/src/memory/v2/consolidation-job.ts +62 -12
  234. package/src/memory/v2/injection.ts +47 -60
  235. package/src/memory/v2/prompts/consolidation.ts +36 -1
  236. package/src/memory/v2/qdrant.ts +99 -0
  237. package/src/memory/v2/reranker.ts +177 -0
  238. package/src/memory/v2/sim.ts +10 -84
  239. package/src/memory/v2/skill-content.ts +4 -3
  240. package/src/memory/v2/skill-store.ts +82 -59
  241. package/src/memory/v2/static-context.ts +22 -0
  242. package/src/memory/v2/types.ts +10 -10
  243. package/src/notifications/copy-composer.ts +13 -0
  244. package/src/notifications/signal.ts +4 -0
  245. package/src/oauth/AGENTS.md +3 -1
  246. package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
  247. package/src/oauth/connect-orchestrator.ts +2 -0
  248. package/src/oauth/connection-resolver.test.ts +66 -1
  249. package/src/oauth/connection-resolver.ts +55 -1
  250. package/src/oauth/oauth-connect-state.ts +77 -0
  251. package/src/oauth/seed-providers.ts +58 -1
  252. package/src/plugins/defaults/injectors.ts +35 -2
  253. package/src/plugins/defaults/memory-retrieval.ts +5 -6
  254. package/src/plugins/types.ts +7 -0
  255. package/src/proactive-artifact/aux-message-injector.ts +74 -0
  256. package/src/proactive-artifact/decision.test.ts +226 -0
  257. package/src/proactive-artifact/decision.ts +165 -0
  258. package/src/proactive-artifact/index.ts +7 -0
  259. package/src/proactive-artifact/job.test.ts +867 -0
  260. package/src/proactive-artifact/job.ts +352 -0
  261. package/src/proactive-artifact/message-copy.ts +41 -0
  262. package/src/proactive-artifact/trigger-state.test.ts +277 -0
  263. package/src/proactive-artifact/trigger-state.ts +119 -0
  264. package/src/prompts/normalize-onboarding.ts +80 -0
  265. package/src/prompts/persona-resolver.ts +101 -9
  266. package/src/prompts/system-prompt.ts +21 -7
  267. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  268. package/src/providers/__tests__/retry-callsite.test.ts +222 -1
  269. package/src/providers/model-intents.ts +7 -0
  270. package/src/providers/openrouter/client.ts +8 -0
  271. package/src/providers/retry.ts +50 -0
  272. package/src/providers/types.ts +1 -0
  273. package/src/runtime/__tests__/agent-wake.test.ts +456 -3
  274. package/src/runtime/agent-wake.ts +238 -100
  275. package/src/runtime/assistant-event-hub.ts +36 -6
  276. package/src/runtime/assistant-event.ts +0 -1
  277. package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
  278. package/src/runtime/auth/route-policy.ts +14 -1
  279. package/src/runtime/auth/same-actor.ts +216 -0
  280. package/src/runtime/channel-retry-sweep.ts +65 -1
  281. package/src/runtime/guardian-reply-router.ts +10 -0
  282. package/src/runtime/local-actor-identity.ts +52 -11
  283. package/src/runtime/pending-interactions.ts +8 -0
  284. package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
  285. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -5
  286. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
  287. package/src/runtime/routes/client-routes.ts +20 -2
  288. package/src/runtime/routes/contact-routes.ts +0 -25
  289. package/src/runtime/routes/conversation-routes.ts +35 -26
  290. package/src/runtime/routes/debug-bash-routes.ts +163 -0
  291. package/src/runtime/routes/disk-pressure-routes.ts +121 -0
  292. package/src/runtime/routes/document-pdf-renderer.ts +6 -2
  293. package/src/runtime/routes/documents-routes.ts +2 -75
  294. package/src/runtime/routes/events-routes.ts +41 -9
  295. package/src/runtime/routes/host-bash-routes.ts +23 -3
  296. package/src/runtime/routes/host-cu-routes.ts +33 -6
  297. package/src/runtime/routes/host-file-routes.ts +32 -6
  298. package/src/runtime/routes/host-transfer-routes.ts +79 -16
  299. package/src/runtime/routes/identity-routes.ts +7 -138
  300. package/src/runtime/routes/inbound-message-handler.ts +77 -12
  301. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
  302. package/src/runtime/routes/index.ts +6 -0
  303. package/src/runtime/routes/memory-item-routes.test.ts +41 -15
  304. package/src/runtime/routes/memory-v2-routes.ts +33 -0
  305. package/src/runtime/routes/oauth-connect-routes.ts +153 -0
  306. package/src/runtime/verification-outbound-actions.ts +4 -4
  307. package/src/schedule/run-script.ts +37 -5
  308. package/src/schedule/scheduler.ts +20 -1
  309. package/src/security/encrypted-store.ts +2 -0
  310. package/src/security/secure-keys.ts +55 -0
  311. package/src/skills/remote-skill-policy.ts +4 -10
  312. package/src/subagent/index.ts +1 -7
  313. package/src/subagent/manager.ts +1 -15
  314. package/src/tasks/task-runner.ts +0 -1
  315. package/src/tasks/task-store.ts +0 -3
  316. package/src/tools/background-tool-registry.ts +17 -3
  317. package/src/tools/host-filesystem/edit.test.ts +151 -0
  318. package/src/tools/host-filesystem/edit.ts +43 -1
  319. package/src/tools/host-filesystem/read.test.ts +129 -0
  320. package/src/tools/host-filesystem/read.ts +43 -1
  321. package/src/tools/host-filesystem/transfer.test.ts +127 -2
  322. package/src/tools/host-filesystem/transfer.ts +56 -11
  323. package/src/tools/host-filesystem/write.test.ts +134 -0
  324. package/src/tools/host-filesystem/write.ts +43 -1
  325. package/src/tools/host-terminal/host-shell.ts +13 -6
  326. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  327. package/src/tools/memory/register.test.ts +12 -9
  328. package/src/tools/memory/register.ts +1 -2
  329. package/src/tools/provider-tool-name.ts +28 -0
  330. package/src/tools/registry.ts +30 -9
  331. package/src/tools/terminal/shell.ts +9 -1
  332. package/src/tools/tool-approval-handler.ts +31 -6
  333. package/src/tools/types.ts +24 -2
  334. package/src/tts/provider-catalog.ts +3 -5
  335. package/src/util/disk-usage.ts +138 -0
  336. package/src/util/platform.ts +21 -11
  337. package/src/util/process-liveness.ts +26 -0
  338. package/src/workspace/heartbeat-service.ts +19 -0
  339. package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
  340. package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
  341. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
  342. package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
  343. package/src/workspace/migrations/registry.ts +8 -0
  344. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
  345. package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
  346. package/src/memory/v2/skill-qdrant.ts +0 -404
  347. package/src/signals/bash.ts +0 -198
@@ -42,6 +42,20 @@ let mockPlatformFetchCallIndex = 0;
42
42
 
43
43
  let mockIsManagedMode: (key: string) => boolean = () => false;
44
44
 
45
+ // Configurable logger mock: by default no-ops; individual tests can override
46
+ // mockLogInfo to write to process.stdout so the JSON-mode suppression guard is
47
+ // exercised (the real CLI logger writes log lines to stdout).
48
+ let mockLogInfo: (msg: string) => void = () => {};
49
+
50
+ let mockCliIpcCallFn: (
51
+ method: string,
52
+ params?: Record<string, unknown>,
53
+ opts?: { timeoutMs?: number },
54
+ ) => Promise<{ ok: boolean; result?: unknown; error?: string; statusCode?: number }> = async () => ({
55
+ ok: false,
56
+ error: "IPC unavailable (default mock — forces fallback)",
57
+ });
58
+
45
59
  // ---------------------------------------------------------------------------
46
60
  // Mocks
47
61
  // ---------------------------------------------------------------------------
@@ -101,7 +115,7 @@ mock.module("../../../../util/logger.js", () => ({
101
115
  debug: () => {},
102
116
  }),
103
117
  getCliLogger: () => ({
104
- info: () => {},
118
+ info: (msg: string) => mockLogInfo(msg),
105
119
  warn: () => {},
106
120
  error: () => {},
107
121
  debug: () => {},
@@ -127,6 +141,14 @@ mock.module("../../../../security/secure-keys.js", () => ({
127
141
  _resetBackend: () => {},
128
142
  }));
129
143
 
144
+ mock.module("../../../../ipc/cli-client.js", () => ({
145
+ cliIpcCall: (
146
+ method: string,
147
+ params?: Record<string, unknown>,
148
+ opts?: { timeoutMs?: number },
149
+ ) => mockCliIpcCallFn(method, params, opts),
150
+ }));
151
+
130
152
  mock.module("../../../lib/daemon-credential-client.js", () => ({
131
153
  deleteSecureKeyViaDaemon: async () => "not-found" as const,
132
154
  setSecureKeyViaDaemon: async () => false,
@@ -254,6 +276,8 @@ describe("assistant oauth connect", () => {
254
276
  mockPlatformFetchResults = [];
255
277
  mockPlatformFetchCallIndex = 0;
256
278
  mockIsManagedMode = () => false;
279
+ mockCliIpcCallFn = async () => ({ ok: false, error: "IPC unavailable" });
280
+ mockLogInfo = () => {};
257
281
  process.exitCode = 0;
258
282
  });
259
283
 
@@ -724,6 +748,418 @@ describe("assistant oauth connect", () => {
724
748
  expect(parsed.error).toContain("--field");
725
749
  });
726
750
 
751
+ // -------------------------------------------------------------------------
752
+ // IPC-first path (daemon-orchestrated)
753
+ // -------------------------------------------------------------------------
754
+
755
+ describe("IPC-first path (BYO mode via daemon)", () => {
756
+ beforeEach(() => {
757
+ // Set up a valid BYO provider and app for all IPC tests
758
+ mockGetProvider = () => ({
759
+ provider: "google",
760
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
761
+ tokenExchangeUrl: "https://oauth2.googleapis.com/token",
762
+ tokenExchangeBodyFormat: "form",
763
+ managedServiceConfigKey: null,
764
+ });
765
+ mockIsManagedMode = () => false;
766
+ mockGetMostRecentAppByProvider = () => ({
767
+ id: "app-1",
768
+ clientId: "ipc-client-id",
769
+ clientSecretCredentialPath: "oauth_app/app-1/client_secret",
770
+ provider: "google",
771
+ createdAt: 0,
772
+ updatedAt: 0,
773
+ });
774
+ });
775
+
776
+ test("IPC start succeeds + polling returns complete → exits 0 with success output", async () => {
777
+ let pollCallCount = 0;
778
+ mockCliIpcCallFn = async (method) => {
779
+ if (method === "internal_oauth_connect_start") {
780
+ return {
781
+ ok: true,
782
+ result: {
783
+ auth_url: "https://accounts.google.com/o/oauth2/auth?state=ipc-state",
784
+ state: "ipc-state",
785
+ },
786
+ };
787
+ }
788
+ if (method === "internal_oauth_connect_status") {
789
+ pollCallCount++;
790
+ return {
791
+ ok: true,
792
+ result: {
793
+ status: "complete",
794
+ service: "google",
795
+ account_info: "user@example.com",
796
+ },
797
+ };
798
+ }
799
+ return { ok: false, error: "unexpected method" };
800
+ };
801
+
802
+ const { exitCode, stdout } = await runCommand([
803
+ "connect",
804
+ "google",
805
+ "--json",
806
+ ]);
807
+ expect(exitCode).toBe(0);
808
+ const parsed = JSON.parse(stdout);
809
+ expect(parsed.ok).toBe(true);
810
+ expect(parsed.accountInfo).toBe("user@example.com");
811
+ expect(mockOpenInBrowserCalls.length).toBe(1);
812
+ expect(mockOpenInBrowserCalls[0]).toBe(
813
+ "https://accounts.google.com/o/oauth2/auth?state=ipc-state",
814
+ );
815
+ expect(pollCallCount).toBeGreaterThanOrEqual(1);
816
+ });
817
+
818
+ test("IPC start succeeds + polling returns error → exits 1 with error message", async () => {
819
+ mockCliIpcCallFn = async (method) => {
820
+ if (method === "internal_oauth_connect_start") {
821
+ return {
822
+ ok: true,
823
+ result: {
824
+ auth_url: "https://accounts.google.com/o/oauth2/auth?state=ipc-state",
825
+ state: "ipc-state",
826
+ },
827
+ };
828
+ }
829
+ if (method === "internal_oauth_connect_status") {
830
+ return {
831
+ ok: true,
832
+ result: {
833
+ status: "error",
834
+ service: "google",
835
+ error: "exchange failed",
836
+ },
837
+ };
838
+ }
839
+ return { ok: false, error: "unexpected method" };
840
+ };
841
+
842
+ const { exitCode, stdout } = await runCommand([
843
+ "connect",
844
+ "google",
845
+ "--json",
846
+ ]);
847
+ expect(exitCode).toBe(1);
848
+ const parsed = JSON.parse(stdout);
849
+ expect(parsed.ok).toBe(false);
850
+ expect(parsed.error).toBe("exchange failed");
851
+ });
852
+
853
+ test("IPC start + --no-browser + json → returns deferred JSON without polling status", async () => {
854
+ let statusCallCount = 0;
855
+ mockCliIpcCallFn = async (method) => {
856
+ if (method === "internal_oauth_connect_start") {
857
+ return {
858
+ ok: true,
859
+ result: {
860
+ auth_url: "https://accounts.google.com/o/oauth2/auth?state=ipc-state",
861
+ state: "ipc-state",
862
+ },
863
+ };
864
+ }
865
+ if (method === "internal_oauth_connect_status") {
866
+ statusCallCount++;
867
+ }
868
+ return { ok: false, error: "unexpected method" };
869
+ };
870
+
871
+ const { exitCode, stdout } = await runCommand([
872
+ "connect",
873
+ "google",
874
+ "--no-browser",
875
+ "--json",
876
+ ]);
877
+ expect(exitCode).toBe(0);
878
+ const parsed = JSON.parse(stdout);
879
+ expect(parsed.ok).toBe(true);
880
+ expect(parsed.deferred).toBe(true);
881
+ expect(parsed.authUrl).toBe("https://accounts.google.com/o/oauth2/auth?state=ipc-state");
882
+ expect(parsed.state).toBe("ipc-state");
883
+ expect(parsed.service).toBe("google");
884
+ // Should NOT poll status when --no-browser is set
885
+ expect(statusCallCount).toBe(0);
886
+ // Should NOT open browser
887
+ expect(mockOpenInBrowserCalls.length).toBe(0);
888
+ });
889
+
890
+ test("IPC start + --no-browser without json → prints URL to stdout", async () => {
891
+ mockCliIpcCallFn = async (method) => {
892
+ if (method === "internal_oauth_connect_start") {
893
+ return {
894
+ ok: true,
895
+ result: {
896
+ auth_url: "https://accounts.google.com/o/oauth2/auth?state=ipc-state",
897
+ state: "ipc-state",
898
+ },
899
+ };
900
+ }
901
+ return { ok: false, error: "unexpected method" };
902
+ };
903
+
904
+ const { exitCode, stdout } = await runCommand([
905
+ "connect",
906
+ "google",
907
+ "--no-browser",
908
+ ]);
909
+ expect(exitCode).toBe(0);
910
+ expect(stdout).toContain("https://accounts.google.com/o/oauth2/auth?state=ipc-state");
911
+ expect(mockOpenInBrowserCalls.length).toBe(0);
912
+ });
913
+
914
+ test("IPC returns ok:false → falls back to in-process orchestrateOAuthConnect", async () => {
915
+ // Default mockCliIpcCallFn already returns ok: false
916
+ let orchestratorCalled = false;
917
+ mockOrchestrateOAuthConnect = async () => {
918
+ orchestratorCalled = true;
919
+ return {
920
+ success: true,
921
+ deferred: false,
922
+ grantedScopes: ["email"],
923
+ accountInfo: "fallback@example.com",
924
+ };
925
+ };
926
+
927
+ const { exitCode, stdout } = await runCommand([
928
+ "connect",
929
+ "google",
930
+ "--json",
931
+ ]);
932
+ expect(exitCode).toBe(0);
933
+ expect(orchestratorCalled).toBe(true);
934
+ const parsed = JSON.parse(stdout);
935
+ expect(parsed.ok).toBe(true);
936
+ expect(parsed.accountInfo).toBe("fallback@example.com");
937
+ });
938
+
939
+ test("IPC returns ok:false with statusCode → surfaces daemon error, does NOT fall back", async () => {
940
+ // Daemon was reachable but returned an error (e.g. 500)
941
+ mockCliIpcCallFn = async (method) => {
942
+ if (method === "internal_oauth_connect_start") {
943
+ return { ok: false, statusCode: 500, error: "internal server error" };
944
+ }
945
+ return { ok: false, error: "unexpected method" };
946
+ };
947
+ let orchestratorCalled = false;
948
+ mockOrchestrateOAuthConnect = async () => {
949
+ orchestratorCalled = true;
950
+ return { success: true, deferred: false, grantedScopes: [] };
951
+ };
952
+
953
+ const { exitCode, stdout } = await runCommand([
954
+ "connect",
955
+ "google",
956
+ "--json",
957
+ ]);
958
+ expect(exitCode).toBe(1);
959
+ // Must NOT fall back to the in-process orchestrator
960
+ expect(orchestratorCalled).toBe(false);
961
+ const parsed = JSON.parse(stdout);
962
+ expect(parsed.ok).toBe(false);
963
+ expect(parsed.error).toBe("internal server error");
964
+ });
965
+
966
+ test("IPC poll returns ok:false with statusCode → breaks early with error, does NOT wait for timeout", async () => {
967
+ // Fix 1: daemon was reachable during status poll but errored — should surface the
968
+ // error immediately instead of waiting out the full 5-minute timeout.
969
+ mockCliIpcCallFn = async (method) => {
970
+ if (method === "internal_oauth_connect_start") {
971
+ return {
972
+ ok: true,
973
+ result: {
974
+ auth_url: "https://accounts.google.com/o/oauth2/auth?state=poll-err-state",
975
+ state: "poll-err-state",
976
+ },
977
+ };
978
+ }
979
+ if (method === "internal_oauth_connect_status") {
980
+ return { ok: false, statusCode: 500, error: "poll error" };
981
+ }
982
+ return { ok: false, error: "unexpected method" };
983
+ };
984
+
985
+ const { exitCode, stdout } = await runCommand([
986
+ "connect",
987
+ "google",
988
+ "--json",
989
+ ]);
990
+ expect(exitCode).toBe(1);
991
+ const parsed = JSON.parse(stdout);
992
+ expect(parsed.ok).toBe(false);
993
+ // The daemon error should be surfaced, not a timeout sentinel
994
+ expect(parsed.error).toBe("poll error");
995
+ });
996
+
997
+ test("IPC start returns ok:true with no auth_url → surfaces error, does NOT call in-process orchestrator", async () => {
998
+ // Fix 2: daemon returns { ok: true } but without an auth_url — malformed response
999
+ // should be an error, not a silent fallback to in-process (which has heap-split bug).
1000
+ mockCliIpcCallFn = async (method) => {
1001
+ if (method === "internal_oauth_connect_start") {
1002
+ return { ok: true, result: {} };
1003
+ }
1004
+ return { ok: false, error: "unexpected method" };
1005
+ };
1006
+ let orchestratorCalled = false;
1007
+ mockOrchestrateOAuthConnect = async () => {
1008
+ orchestratorCalled = true;
1009
+ return { success: true, deferred: false, grantedScopes: [] };
1010
+ };
1011
+
1012
+ const { exitCode, stdout } = await runCommand([
1013
+ "connect",
1014
+ "google",
1015
+ "--json",
1016
+ ]);
1017
+ expect(exitCode).toBe(1);
1018
+ // Must NOT fall back to the in-process orchestrator
1019
+ expect(orchestratorCalled).toBe(false);
1020
+ const parsed = JSON.parse(stdout);
1021
+ expect(parsed.ok).toBe(false);
1022
+ expect(parsed.error).toContain("assistant returned unexpected response");
1023
+ });
1024
+
1025
+ test("IPC poll: transient ok:false with no statusCode does not abort the flow (continues to next poll)", async () => {
1026
+ // Verifies intentional behavior: a single IPC status call returning { ok: false }
1027
+ // with NO statusCode (socket error / timeout) is treated as a transient failure and
1028
+ // silently retried. Only ok:false WITH a statusCode (i.e., the daemon was reachable
1029
+ // and returned an HTTP error) causes an early abort.
1030
+ let statusCallCount = 0;
1031
+ mockCliIpcCallFn = async (method) => {
1032
+ if (method === "internal_oauth_connect_start") {
1033
+ return {
1034
+ ok: true,
1035
+ result: {
1036
+ auth_url: "https://accounts.google.com/o/oauth2/auth?state=transient-state",
1037
+ state: "transient-state",
1038
+ },
1039
+ };
1040
+ }
1041
+ if (method === "internal_oauth_connect_status") {
1042
+ statusCallCount++;
1043
+ if (statusCallCount === 1) {
1044
+ // First poll: transient IPC failure (no statusCode — socket error/timeout)
1045
+ return { ok: false };
1046
+ }
1047
+ // Second poll: succeeds
1048
+ return {
1049
+ ok: true,
1050
+ result: {
1051
+ status: "complete",
1052
+ service: "google",
1053
+ account_info: "user@example.com",
1054
+ },
1055
+ };
1056
+ }
1057
+ return { ok: false, error: "unexpected method" };
1058
+ };
1059
+
1060
+ const { exitCode, stdout } = await runCommand([
1061
+ "connect",
1062
+ "google",
1063
+ "--json",
1064
+ ]);
1065
+ expect(exitCode).toBe(0);
1066
+ const parsed = JSON.parse(stdout);
1067
+ expect(parsed.ok).toBe(true);
1068
+ expect(parsed.accountInfo).toBe("user@example.com");
1069
+ // Both poll calls were made — the transient failure did not abort the loop
1070
+ expect(statusCallCount).toBeGreaterThanOrEqual(2);
1071
+ });
1072
+
1073
+ test("IPC success path with --json: stdout does NOT contain 'Waiting for authorization' text", async () => {
1074
+ // Regression guard for P1: the browser-wait log.info must be suppressed in JSON mode
1075
+ // so that machine consumers parsing stdout as JSON don't see corrupted non-JSON output.
1076
+ //
1077
+ // We configure the logger mock to write to process.stdout (matching the real CLI logger's
1078
+ // behavior) so this test would FAIL if the `if (!jsonMode)` guard were removed from connect.ts.
1079
+ mockLogInfo = (msg: string) => {
1080
+ process.stdout.write(msg + "\n");
1081
+ };
1082
+
1083
+ mockCliIpcCallFn = async (method) => {
1084
+ if (method === "internal_oauth_connect_start") {
1085
+ return {
1086
+ ok: true,
1087
+ result: {
1088
+ auth_url: "https://accounts.google.com/o/oauth2/auth?state=json-mode-state",
1089
+ state: "json-mode-state",
1090
+ },
1091
+ };
1092
+ }
1093
+ if (method === "internal_oauth_connect_status") {
1094
+ return {
1095
+ ok: true,
1096
+ result: {
1097
+ status: "complete",
1098
+ service: "google",
1099
+ account_info: "user@example.com",
1100
+ },
1101
+ };
1102
+ }
1103
+ return { ok: false, error: "unexpected method" };
1104
+ };
1105
+
1106
+ const { exitCode, stdout } = await runCommand([
1107
+ "connect",
1108
+ "google",
1109
+ "--json",
1110
+ ]);
1111
+ expect(exitCode).toBe(0);
1112
+ // The suppressed log line must not appear anywhere in stdout
1113
+ expect(stdout).not.toContain("Waiting for authorization");
1114
+ // stdout must be valid JSON — no plain-text lines mixed in
1115
+ expect(() => JSON.parse(stdout)).not.toThrow();
1116
+ const parsed = JSON.parse(stdout);
1117
+ expect(parsed.ok).toBe(true);
1118
+ });
1119
+
1120
+ test("IPC start with --callback-transport=gateway passes callbackTransport in body", async () => {
1121
+ let capturedParams: Record<string, unknown> | undefined;
1122
+ mockCliIpcCallFn = async (method, params) => {
1123
+ if (method === "internal_oauth_connect_start") {
1124
+ capturedParams = params;
1125
+ return {
1126
+ ok: true,
1127
+ result: {
1128
+ auth_url: "https://accounts.google.com/o/oauth2/auth?state=gw-state",
1129
+ state: "gw-state",
1130
+ },
1131
+ };
1132
+ }
1133
+ if (method === "internal_oauth_connect_status") {
1134
+ return {
1135
+ ok: true,
1136
+ result: {
1137
+ status: "complete",
1138
+ service: "google",
1139
+ account_info: "gw-user@example.com",
1140
+ },
1141
+ };
1142
+ }
1143
+ return { ok: false, error: "unexpected method" };
1144
+ };
1145
+
1146
+ const { exitCode, stdout } = await runCommand([
1147
+ "connect",
1148
+ "google",
1149
+ "--callback-transport",
1150
+ "gateway",
1151
+ "--json",
1152
+ ]);
1153
+ expect(exitCode).toBe(0);
1154
+ // Verify callbackTransport was forwarded in the IPC body
1155
+ expect(capturedParams).toBeDefined();
1156
+ expect((capturedParams!.body as Record<string, unknown>).callbackTransport).toBe("gateway");
1157
+ const parsed = JSON.parse(stdout);
1158
+ expect(parsed.ok).toBe(true);
1159
+ expect(parsed.accountInfo).toBe("gw-user@example.com");
1160
+ });
1161
+ });
1162
+
727
1163
  // -------------------------------------------------------------------------
728
1164
  // Orchestrator error propagation
729
1165
  // -------------------------------------------------------------------------
@@ -3,6 +3,7 @@ import { createServer, type Server } from "node:http";
3
3
  import type { Command } from "commander";
4
4
 
5
5
  import { getIsContainerized } from "../../../config/env-registry.js";
6
+ import { cliIpcCall } from "../../../ipc/cli-client.js";
6
7
  import { orchestrateOAuthConnect } from "../../../oauth/connect-orchestrator.js";
7
8
  import {
8
9
  getAppByProviderAndClientId,
@@ -69,6 +70,39 @@ function startManagedRedirectServer(provider: string): Promise<{
69
70
  });
70
71
  }
71
72
 
73
+ // ---------------------------------------------------------------------------
74
+ // IPC polling helpers
75
+ // ---------------------------------------------------------------------------
76
+
77
+ type OAuthConnectStatusResponse =
78
+ | { status: "pending"; service: string }
79
+ | { status: "complete"; service: string; account_info?: string; granted_scopes?: string[] }
80
+ | { status: "error"; service: string; error?: string };
81
+
82
+ async function pollOAuthConnectStatus(
83
+ state: string,
84
+ opts: { intervalMs: number; timeoutMs: number },
85
+ ): Promise<OAuthConnectStatusResponse> {
86
+ const deadline = Date.now() + opts.timeoutMs;
87
+ while (Date.now() < deadline) {
88
+ const r = await cliIpcCall<OAuthConnectStatusResponse>(
89
+ "internal_oauth_connect_status",
90
+ { pathParams: { state } },
91
+ );
92
+ if (r.ok && r.result) {
93
+ const { status } = r.result;
94
+ if (status === "complete" || status === "error") {
95
+ return r.result;
96
+ }
97
+ }
98
+ if (!r.ok && r.statusCode !== undefined) {
99
+ return { status: "error", service: "?", error: r.error ?? "assistant error during OAuth status poll" };
100
+ }
101
+ await new Promise<void>((res) => setTimeout(res, opts.intervalMs));
102
+ }
103
+ return { status: "error", service: "?", error: "Timed out waiting for OAuth callback" };
104
+ }
105
+
72
106
  // ---------------------------------------------------------------------------
73
107
  // Command registration
74
108
  // ---------------------------------------------------------------------------
@@ -392,7 +426,99 @@ Examples:
392
426
  }
393
427
  }
394
428
 
395
- // e. Call the orchestrator
429
+ // e. Try daemon-orchestrated path first (fixes heap-split for gateway transport).
430
+ const startResult = await cliIpcCall<{ auth_url: string; state: string }>(
431
+ "internal_oauth_connect_start",
432
+ {
433
+ body: {
434
+ service: provider,
435
+ clientId,
436
+ ...(clientSecret !== undefined ? { clientSecret } : {}),
437
+ callbackTransport: opts.callbackTransport,
438
+ ...(opts.scopes ? { requestedScopes: opts.scopes } : {}),
439
+ },
440
+ },
441
+ );
442
+
443
+ if (startResult.ok && startResult.result?.auth_url) {
444
+ const { auth_url, state } = startResult.result;
445
+
446
+ if (opts.browser !== false) {
447
+ await openInHostBrowser(auth_url);
448
+
449
+ if (!jsonMode) {
450
+ log.info("Waiting for authorization in browser... (press Ctrl+C to cancel)");
451
+ }
452
+ const final = await pollOAuthConnectStatus(state, {
453
+ intervalMs: 2000,
454
+ timeoutMs: 5 * 60 * 1000, // match LOOPBACK_TIMEOUT_MS in oauth2.ts (5 min)
455
+ });
456
+
457
+ if (final.status === "complete") {
458
+ if (jsonMode) {
459
+ writeOutput(cmd, {
460
+ ok: true,
461
+ grantedScopes: final.granted_scopes ?? [],
462
+ accountInfo: final.account_info,
463
+ });
464
+ } else {
465
+ process.stdout.write(
466
+ `Connected to ${provider}${final.account_info ? ` as ${final.account_info}` : ""}\n`,
467
+ );
468
+ }
469
+ return;
470
+ }
471
+
472
+ if (final.status === "error") {
473
+ // Includes the timeout sentinel emitted by pollOAuthConnectStatus.
474
+ writeError(final.error ?? "OAuth connect failed");
475
+ return;
476
+ }
477
+
478
+ // Defensive: pollOAuthConnectStatus should never return pending,
479
+ // but TS narrowing requires us to handle it.
480
+ writeError("OAuth connect ended in an unexpected pending state");
481
+ return;
482
+ } else {
483
+ // --no-browser: return the URL immediately, matching existing deferred behavior.
484
+ if (jsonMode) {
485
+ writeOutput(cmd, {
486
+ ok: true,
487
+ deferred: true,
488
+ authUrl: auth_url,
489
+ state,
490
+ service: provider,
491
+ });
492
+ } else {
493
+ process.stdout.write(
494
+ `\nAuthorize with ${provider}:\n\n${auth_url}\n\nThe connection will complete automatically once you authorize.\n`,
495
+ );
496
+ }
497
+ return;
498
+ }
499
+ }
500
+
501
+ // ok:true but no auth_url means a malformed daemon response — surface an error rather
502
+ // than falling back to in-process (which would re-introduce the heap-split bug for
503
+ // gateway transport).
504
+ if (startResult.ok && !startResult.result?.auth_url) {
505
+ writeError("assistant returned unexpected response for OAuth connect start");
506
+ return;
507
+ }
508
+
509
+ // If the daemon was reachable but returned an error, surface it rather than
510
+ // falling back to in-process (which would re-introduce the heap-split bug for
511
+ // gateway transport).
512
+ if (!startResult.ok && startResult.statusCode !== undefined) {
513
+ writeError(startResult.error ?? "OAuth connect failed (assistant error)");
514
+ return;
515
+ }
516
+
517
+ // IPC unavailable (daemon unreachable, older daemon without this route, socket missing).
518
+ // Fall through to the existing in-process flow. This still carries the heap-split bug
519
+ // for gateway transport, but if the daemon is unreachable we have a worse problem;
520
+ // the fallback preserves existing behavior as a regression guard.
521
+ // e. Call the orchestrator (in-process fallback)
396
522
  const result = await orchestrateOAuthConnect({
397
523
  service: provider,
398
524
  clientId,
@@ -10,7 +10,6 @@ let mockResolvePlatformCallbackRegistrationContext: () => Promise<
10
10
  isPlatform: false,
11
11
  platformBaseUrl: "",
12
12
  assistantId: "",
13
- hasInternalApiKey: false,
14
13
  hasAssistantApiKey: false,
15
14
  authHeader: null,
16
15
  enabled: false,
@@ -93,7 +92,6 @@ function connectedContext(
93
92
  isPlatform: false,
94
93
  platformBaseUrl: "https://dev-platform.vellum.ai",
95
94
  assistantId: "019d6d4f-6dbd-779f-91d3-cb273b9429a5",
96
- hasInternalApiKey: false,
97
95
  hasAssistantApiKey: true,
98
96
  authHeader: "Api-Key vak_test123",
99
97
  enabled: false,
@@ -181,7 +179,6 @@ describe("assistant platform callback-routes list", () => {
181
179
  isPlatform: false,
182
180
  platformBaseUrl: "",
183
181
  assistantId: "",
184
- hasInternalApiKey: false,
185
182
  hasAssistantApiKey: false,
186
183
  authHeader: null,
187
184
  enabled: false,
@@ -32,6 +32,13 @@ mock.module("../../../../security/secure-keys.js", () => ({
32
32
  onCesClientChanged: () => ({ unsubscribe: () => {} }),
33
33
  setCesReconnect: () => {},
34
34
  getActiveBackendName: () => "file",
35
+ getActiveBackendInfoAsync: async () => ({
36
+ backend: "encrypted-store",
37
+ storePath: "/tmp/keys.enc",
38
+ storeKeyPath: "/tmp/store.key",
39
+ storeExists: false,
40
+ storeKeyExists: false,
41
+ }),
35
42
  _resetBackend: () => {},
36
43
  }));
37
44
 
@@ -45,7 +52,6 @@ mock.module("../../../../inbound/platform-callback-registration.js", () => ({
45
52
  isPlatform: false,
46
53
  platformBaseUrl: "",
47
54
  assistantId: "",
48
- hasInternalApiKey: false,
49
55
  hasAssistantApiKey: false,
50
56
  authHeader: null,
51
57
  enabled: false,
@@ -39,7 +39,6 @@ mock.module("../../../../inbound/platform-callback-registration.js", () => ({
39
39
  isPlatform: false,
40
40
  platformBaseUrl: "",
41
41
  assistantId: "",
42
- hasInternalApiKey: false,
43
42
  hasAssistantApiKey: false,
44
43
  authHeader: null,
45
44
  enabled: false,
@@ -64,6 +63,13 @@ mock.module("../../../../security/secure-keys.js", () => ({
64
63
  onCesClientChanged: () => ({ unsubscribe: () => {} }),
65
64
  setCesReconnect: () => {},
66
65
  getActiveBackendName: () => "file",
66
+ getActiveBackendInfoAsync: async () => ({
67
+ backend: "encrypted-store",
68
+ storePath: "/tmp/keys.enc",
69
+ storeKeyPath: "/tmp/store.key",
70
+ storeExists: false,
71
+ storeKeyExists: false,
72
+ }),
67
73
  _resetBackend: () => {},
68
74
  }));
69
75