@vellumai/assistant 0.5.5 → 0.5.7

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 (382) hide show
  1. package/.env.example +16 -2
  2. package/ARCHITECTURE.md +6 -75
  3. package/Dockerfile +4 -5
  4. package/README.md +0 -2
  5. package/bun.lock +0 -414
  6. package/docs/architecture/keychain-broker.md +45 -240
  7. package/docs/architecture/security.md +0 -17
  8. package/docs/credential-execution-service.md +2 -2
  9. package/node_modules/@vellumai/ces-contracts/package.json +1 -0
  10. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +119 -0
  11. package/node_modules/@vellumai/credential-storage/package.json +1 -0
  12. package/node_modules/@vellumai/egress-proxy/package.json +1 -0
  13. package/package.json +2 -3
  14. package/src/__tests__/actor-token-service.test.ts +1 -2
  15. package/src/__tests__/assistant-feature-flags-integration.test.ts +30 -29
  16. package/src/__tests__/browser-skill-endstate.test.ts +6 -5
  17. package/src/__tests__/btw-routes.test.ts +0 -39
  18. package/src/__tests__/call-domain.test.ts +0 -128
  19. package/src/__tests__/ces-rpc-credential-backend.test.ts +199 -0
  20. package/src/__tests__/channel-approval-routes.test.ts +0 -5
  21. package/src/__tests__/channel-readiness-service.test.ts +1 -60
  22. package/src/__tests__/checker.test.ts +4 -2
  23. package/src/__tests__/cli-command-risk-guard.test.ts +112 -0
  24. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  25. package/src/__tests__/config-schema.test.ts +3 -3
  26. package/src/__tests__/context-window-manager.test.ts +78 -0
  27. package/src/__tests__/conversation-attention-telegram.test.ts +0 -5
  28. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  29. package/src/__tests__/conversation-skill-tools.test.ts +0 -54
  30. package/src/__tests__/conversation-title-service.test.ts +117 -1
  31. package/src/__tests__/credential-execution-feature-gates.test.ts +28 -14
  32. package/src/__tests__/credential-execution-managed-contract.test.ts +33 -18
  33. package/src/__tests__/credential-security-e2e.test.ts +0 -66
  34. package/src/__tests__/credential-security-invariants.test.ts +4 -45
  35. package/src/__tests__/credentials-cli.test.ts +78 -0
  36. package/src/__tests__/db-migration-rollback.test.ts +2015 -1
  37. package/src/__tests__/docker-signing-key-bootstrap.test.ts +98 -0
  38. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -4
  39. package/src/__tests__/guardian-routing-state.test.ts +0 -5
  40. package/src/__tests__/host-shell-tool.test.ts +6 -7
  41. package/src/__tests__/http-user-message-parity.test.ts +3 -103
  42. package/src/__tests__/inbound-invite-redemption.test.ts +0 -4
  43. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -8
  44. package/src/__tests__/intent-routing.test.ts +0 -13
  45. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +178 -0
  46. package/src/__tests__/keychain-broker-client.test.ts +161 -22
  47. package/src/__tests__/memory-jobs-worker-backoff.test.ts +150 -0
  48. package/src/__tests__/memory-regressions.test.ts +8 -30
  49. package/src/__tests__/migration-export-http.test.ts +2 -2
  50. package/src/__tests__/migration-import-commit-http.test.ts +2 -2
  51. package/src/__tests__/migration-import-preflight-http.test.ts +2 -2
  52. package/src/__tests__/migration-validate-http.test.ts +2 -2
  53. package/src/__tests__/non-member-access-request.test.ts +0 -5
  54. package/src/__tests__/notification-decision-fallback.test.ts +4 -0
  55. package/src/__tests__/notification-decision-identity.test.ts +4 -0
  56. package/src/__tests__/permission-types.test.ts +1 -0
  57. package/src/__tests__/provider-managed-proxy-integration.test.ts +5 -6
  58. package/src/__tests__/qdrant-manager.test.ts +28 -2
  59. package/src/__tests__/registry.test.ts +0 -6
  60. package/src/__tests__/require-fresh-approval.test.ts +4 -0
  61. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -4
  62. package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -4
  63. package/src/__tests__/secure-keys.test.ts +83 -263
  64. package/src/__tests__/shell-identity.test.ts +96 -6
  65. package/src/__tests__/skill-feature-flags-integration.test.ts +22 -14
  66. package/src/__tests__/skill-feature-flags.test.ts +46 -45
  67. package/src/__tests__/skill-load-feature-flag.test.ts +7 -10
  68. package/src/__tests__/skill-load-inline-command.test.ts +8 -12
  69. package/src/__tests__/skill-load-inline-includes.test.ts +6 -10
  70. package/src/__tests__/skill-load-tool.test.ts +0 -2
  71. package/src/__tests__/skill-projection-feature-flag.test.ts +33 -29
  72. package/src/__tests__/skills.test.ts +0 -2
  73. package/src/__tests__/slack-inbound-verification.test.ts +0 -4
  74. package/src/__tests__/suggestion-routes.test.ts +1 -32
  75. package/src/__tests__/system-prompt.test.ts +0 -1
  76. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -0
  77. package/src/__tests__/tool-executor-shell-integration.test.ts +5 -3
  78. package/src/__tests__/tool-executor.test.ts +4 -0
  79. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -5
  80. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -4
  81. package/src/__tests__/update-bulletin.test.ts +0 -2
  82. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +6 -9
  83. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -6
  84. package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +252 -0
  85. package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +218 -0
  86. package/src/__tests__/workspace-migration-down-functions.test.ts +1009 -0
  87. package/src/__tests__/workspace-migrations-runner.test.ts +114 -0
  88. package/src/calls/audio-store.test.ts +97 -0
  89. package/src/calls/audio-store.ts +205 -0
  90. package/src/calls/call-controller.ts +85 -7
  91. package/src/calls/call-domain.ts +3 -0
  92. package/src/calls/call-store.ts +10 -3
  93. package/src/calls/fish-audio-client.ts +117 -0
  94. package/src/calls/relay-server.ts +27 -0
  95. package/src/calls/twilio-routes.ts +2 -1
  96. package/src/calls/types.ts +1 -0
  97. package/src/calls/voice-ingress-preflight.ts +0 -42
  98. package/src/calls/voice-quality.ts +26 -5
  99. package/src/calls/voice-session-bridge.ts +6 -12
  100. package/src/cli/commands/config.ts +1 -4
  101. package/src/cli/commands/conversations.ts +0 -18
  102. package/src/cli/commands/credentials.ts +34 -4
  103. package/src/cli/commands/oauth/index.ts +7 -0
  104. package/src/cli/commands/oauth/platform.ts +179 -0
  105. package/src/cli/commands/platform.ts +3 -3
  106. package/src/config/assistant-feature-flags.ts +186 -5
  107. package/src/config/bundled-skills/messaging/SKILL.md +5 -5
  108. package/src/config/bundled-skills/phone-calls/TOOLS.json +4 -0
  109. package/src/config/bundled-skills/settings/TOOLS.json +2 -2
  110. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +42 -0
  111. package/src/config/bundled-tool-registry.ts +1 -11
  112. package/src/config/env-registry.ts +1 -1
  113. package/src/config/env.ts +16 -16
  114. package/src/config/feature-flag-registry.json +48 -16
  115. package/src/config/loader.ts +98 -31
  116. package/src/config/schema.ts +4 -25
  117. package/src/config/schemas/calls.ts +13 -0
  118. package/src/config/schemas/fish-audio.ts +39 -0
  119. package/src/config/schemas/memory.ts +0 -4
  120. package/src/config/schemas/platform.ts +1 -1
  121. package/src/config/schemas/security.ts +4 -4
  122. package/src/config/types.ts +0 -1
  123. package/src/contacts/contact-store.ts +39 -0
  124. package/src/contacts/types.ts +2 -0
  125. package/src/context/window-manager.ts +53 -2
  126. package/src/credential-execution/approval-bridge.ts +1 -0
  127. package/src/credential-execution/executable-discovery.ts +28 -4
  128. package/src/credential-execution/feature-gates.ts +16 -0
  129. package/src/credential-execution/process-manager.ts +38 -0
  130. package/src/daemon/assistant-attachments.ts +9 -0
  131. package/src/daemon/config-watcher.ts +6 -4
  132. package/src/daemon/conversation-agent-loop.ts +0 -60
  133. package/src/daemon/conversation-memory.ts +0 -117
  134. package/src/daemon/conversation-runtime-assembly.ts +0 -2
  135. package/src/daemon/conversation-tool-setup.ts +0 -105
  136. package/src/daemon/conversation.ts +10 -1
  137. package/src/daemon/handlers/config-vercel.ts +92 -0
  138. package/src/daemon/handlers/conversations.ts +0 -11
  139. package/src/daemon/handlers/skills.ts +2 -15
  140. package/src/daemon/install-symlink.ts +195 -0
  141. package/src/daemon/lifecycle.ts +229 -96
  142. package/src/daemon/message-types/conversations.ts +3 -4
  143. package/src/daemon/message-types/diagnostics.ts +3 -22
  144. package/src/daemon/message-types/messages.ts +0 -2
  145. package/src/daemon/message-types/upgrades.ts +8 -0
  146. package/src/daemon/server.ts +30 -92
  147. package/src/events/domain-events.ts +2 -1
  148. package/src/followups/followup-store.ts +5 -2
  149. package/src/inbound/platform-callback-registration.ts +3 -3
  150. package/src/instrument.ts +8 -5
  151. package/src/memory/conversation-crud.ts +0 -236
  152. package/src/memory/conversation-title-service.ts +76 -11
  153. package/src/memory/db-init.ts +15 -11
  154. package/src/memory/indexer.ts +15 -106
  155. package/src/memory/items-extractor.ts +15 -1
  156. package/src/memory/job-handlers/conversation-starters.ts +4 -1
  157. package/src/memory/job-handlers/embedding.ts +0 -79
  158. package/src/memory/job-utils.ts +1 -1
  159. package/src/memory/jobs-store.ts +30 -13
  160. package/src/memory/jobs-worker.ts +31 -27
  161. package/src/memory/migrations/001-job-deferrals.ts +19 -0
  162. package/src/memory/migrations/004-entity-relation-dedup.ts +10 -0
  163. package/src/memory/migrations/005-fingerprint-scope-unique.ts +76 -0
  164. package/src/memory/migrations/006-scope-salted-fingerprints.ts +50 -0
  165. package/src/memory/migrations/007-assistant-id-to-self.ts +10 -0
  166. package/src/memory/migrations/008-remove-assistant-id-columns.ts +34 -0
  167. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +26 -0
  168. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +10 -0
  169. package/src/memory/migrations/015-drop-active-search-index.ts +17 -0
  170. package/src/memory/migrations/019-notification-tables-schema-migration.ts +12 -0
  171. package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +121 -0
  172. package/src/memory/migrations/024-embedding-vector-blob.ts +74 -0
  173. package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +82 -0
  174. package/src/memory/migrations/036-normalize-phone-identities.ts +11 -0
  175. package/src/memory/migrations/116-messages-fts.ts +106 -1
  176. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +52 -0
  177. package/src/memory/migrations/127-guardian-principal-id-not-null.ts +77 -0
  178. package/src/memory/migrations/134-contacts-notes-column.ts +13 -0
  179. package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +20 -0
  180. package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -0
  181. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +13 -0
  182. package/src/memory/migrations/141-rename-verification-table.ts +54 -0
  183. package/src/memory/migrations/142-rename-verification-session-id-column.ts +25 -0
  184. package/src/memory/migrations/143-rename-guardian-verification-values.ts +35 -0
  185. package/src/memory/migrations/144-rename-voice-to-phone.ts +136 -0
  186. package/src/memory/migrations/145-drop-accounts-table.ts +32 -0
  187. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +14 -1
  188. package/src/memory/migrations/148-drop-reminders-table.ts +35 -1
  189. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +69 -1
  190. package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +290 -0
  191. package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +51 -1
  192. package/src/memory/migrations/174-rename-thread-starters-table.ts +47 -1
  193. package/src/memory/migrations/176-drop-capability-card-state.ts +13 -0
  194. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +16 -0
  195. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +28 -1
  196. package/src/memory/migrations/189-drop-simplified-memory.ts +42 -0
  197. package/src/memory/migrations/190-call-session-skip-disclosure.ts +15 -0
  198. package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +64 -0
  199. package/src/memory/migrations/192-contacts-user-file-column.ts +15 -0
  200. package/src/memory/migrations/index.ts +5 -3
  201. package/src/memory/migrations/registry.ts +90 -0
  202. package/src/memory/migrations/validate-migration-state.ts +137 -11
  203. package/src/memory/qdrant-circuit-breaker.ts +9 -0
  204. package/src/memory/qdrant-client.ts +4 -6
  205. package/src/memory/qdrant-manager.ts +64 -7
  206. package/src/memory/schema/calls.ts +1 -0
  207. package/src/memory/schema/contacts.ts +1 -0
  208. package/src/memory/schema/conversations.ts +0 -3
  209. package/src/memory/schema/index.ts +0 -2
  210. package/src/messaging/draft-store.ts +2 -2
  211. package/src/notifications/decision-engine.ts +4 -1
  212. package/src/oauth/connection-resolver.ts +6 -4
  213. package/src/permissions/checker.ts +0 -38
  214. package/src/permissions/defaults.ts +3 -3
  215. package/src/permissions/shell-identity.ts +76 -22
  216. package/src/permissions/trust-client.ts +2 -13
  217. package/src/permissions/trust-store.ts +8 -3
  218. package/src/permissions/types.ts +4 -2
  219. package/src/platform/client.ts +35 -7
  220. package/src/prompts/persona-resolver.ts +138 -0
  221. package/src/prompts/system-prompt.ts +36 -4
  222. package/src/prompts/templates/users/default.md +1 -0
  223. package/src/providers/registry.ts +27 -40
  224. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
  225. package/src/runtime/auth/__tests__/external-assistant-id.test.ts +13 -68
  226. package/src/runtime/auth/external-assistant-id.ts +13 -59
  227. package/src/runtime/auth/route-policy.ts +29 -1
  228. package/src/runtime/auth/token-service.ts +53 -15
  229. package/src/runtime/channel-readiness-service.ts +1 -16
  230. package/src/runtime/http-server.ts +29 -2
  231. package/src/runtime/middleware/error-handler.ts +1 -9
  232. package/src/runtime/routes/audio-routes.ts +40 -0
  233. package/src/runtime/routes/btw-routes.ts +0 -17
  234. package/src/runtime/routes/conversation-management-routes.ts +0 -36
  235. package/src/runtime/routes/conversation-query-routes.ts +106 -2
  236. package/src/runtime/routes/conversation-routes.ts +4 -43
  237. package/src/runtime/routes/diagnostics-routes.ts +1 -477
  238. package/src/runtime/routes/identity-routes.ts +18 -29
  239. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -33
  240. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
  241. package/src/runtime/routes/integrations/vercel.ts +89 -0
  242. package/src/runtime/routes/log-export-routes.ts +5 -0
  243. package/src/runtime/routes/memory-item-routes.test.ts +221 -3
  244. package/src/runtime/routes/memory-item-routes.ts +144 -4
  245. package/src/runtime/routes/migration-rollback-routes.ts +209 -0
  246. package/src/runtime/routes/migration-routes.ts +17 -1
  247. package/src/runtime/routes/notification-routes.ts +58 -0
  248. package/src/runtime/routes/schedule-routes.ts +65 -0
  249. package/src/runtime/routes/settings-routes.ts +41 -1
  250. package/src/runtime/routes/tts-routes.ts +86 -0
  251. package/src/runtime/routes/upgrade-broadcast-routes.ts +175 -0
  252. package/src/runtime/routes/workspace-commit-routes.ts +62 -0
  253. package/src/runtime/routes/workspace-routes.test.ts +22 -1
  254. package/src/runtime/routes/workspace-routes.ts +1 -1
  255. package/src/runtime/routes/workspace-utils.ts +86 -2
  256. package/src/schedule/schedule-store.ts +0 -21
  257. package/src/security/ces-credential-client.ts +59 -22
  258. package/src/security/ces-rpc-credential-backend.ts +85 -0
  259. package/src/security/credential-backend.ts +12 -88
  260. package/src/security/keychain-broker-client.ts +10 -2
  261. package/src/security/secure-keys.ts +94 -113
  262. package/src/skills/catalog-install.ts +13 -7
  263. package/src/skills/inline-command-render.ts +5 -1
  264. package/src/skills/inline-command-runner.ts +30 -2
  265. package/src/telemetry/usage-telemetry-reporter.ts +4 -2
  266. package/src/tools/calls/call-start.ts +1 -0
  267. package/src/tools/executor.ts +0 -4
  268. package/src/tools/memory/handlers.ts +1 -129
  269. package/src/tools/network/script-proxy/session-manager.ts +19 -4
  270. package/src/tools/network/web-fetch.ts +3 -1
  271. package/src/tools/permission-checker.ts +18 -0
  272. package/src/tools/skills/execute.ts +1 -1
  273. package/src/tools/skills/load.ts +9 -2
  274. package/src/tools/types.ts +0 -8
  275. package/src/util/errors.ts +0 -12
  276. package/src/util/platform.ts +8 -55
  277. package/src/util/xml.ts +8 -0
  278. package/src/workspace/git-service.ts +5 -2
  279. package/src/workspace/heartbeat-service.ts +5 -24
  280. package/src/workspace/migrations/001-avatar-rename.ts +15 -0
  281. package/src/workspace/migrations/003-seed-device-id.ts +17 -1
  282. package/src/workspace/migrations/004-extract-collect-usage-data.ts +33 -0
  283. package/src/workspace/migrations/005-add-send-diagnostics.ts +3 -0
  284. package/src/workspace/migrations/006-services-config.ts +49 -0
  285. package/src/workspace/migrations/007-web-search-provider-rename.ts +27 -0
  286. package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +3 -0
  287. package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +4 -0
  288. package/src/workspace/migrations/010-app-dir-rename.ts +78 -0
  289. package/src/workspace/migrations/011-backfill-installation-id.ts +11 -0
  290. package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +44 -0
  291. package/src/workspace/migrations/013-repair-conversation-disk-view.ts +5 -0
  292. package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +153 -0
  293. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +156 -0
  294. package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +150 -0
  295. package/src/workspace/migrations/017-seed-persona-dirs.ts +95 -0
  296. package/src/workspace/migrations/migrate-to-workspace-volume.ts +23 -1
  297. package/src/workspace/migrations/registry.ts +8 -0
  298. package/src/workspace/migrations/runner.ts +106 -2
  299. package/src/workspace/migrations/types.ts +4 -0
  300. package/src/__tests__/archive-recall.test.ts +0 -560
  301. package/src/__tests__/claude-code-skill-regression.test.ts +0 -206
  302. package/src/__tests__/claude-code-tool-profiles.test.ts +0 -99
  303. package/src/__tests__/conversation-memory-dirty-tail.test.ts +0 -150
  304. package/src/__tests__/conversation-switch-memory-reduction.test.ts +0 -474
  305. package/src/__tests__/db-memory-archive-migration.test.ts +0 -372
  306. package/src/__tests__/db-memory-brief-state-migration.test.ts +0 -213
  307. package/src/__tests__/db-memory-reducer-checkpoints.test.ts +0 -273
  308. package/src/__tests__/diagnostics-export.test.ts +0 -288
  309. package/src/__tests__/local-gateway-health.test.ts +0 -209
  310. package/src/__tests__/memory-brief-open-loops.test.ts +0 -530
  311. package/src/__tests__/memory-brief-time.test.ts +0 -285
  312. package/src/__tests__/memory-brief-wrapper.test.ts +0 -311
  313. package/src/__tests__/memory-chunk-archive.test.ts +0 -400
  314. package/src/__tests__/memory-chunk-dual-write.test.ts +0 -453
  315. package/src/__tests__/memory-episode-archive.test.ts +0 -370
  316. package/src/__tests__/memory-episode-dual-write.test.ts +0 -626
  317. package/src/__tests__/memory-observation-archive.test.ts +0 -375
  318. package/src/__tests__/memory-observation-dual-write.test.ts +0 -318
  319. package/src/__tests__/memory-reducer-job.test.ts +0 -538
  320. package/src/__tests__/memory-reducer-scheduling.test.ts +0 -473
  321. package/src/__tests__/memory-reducer-store.test.ts +0 -728
  322. package/src/__tests__/memory-reducer-types.test.ts +0 -707
  323. package/src/__tests__/memory-reducer.test.ts +0 -704
  324. package/src/__tests__/memory-simplified-config.test.ts +0 -281
  325. package/src/__tests__/secret-ingress-handler.test.ts +0 -120
  326. package/src/__tests__/simplified-memory-e2e.test.ts +0 -666
  327. package/src/__tests__/simplified-memory-runtime.test.ts +0 -616
  328. package/src/__tests__/swarm-conversation-integration.test.ts +0 -358
  329. package/src/__tests__/swarm-dag-pathological.test.ts +0 -547
  330. package/src/__tests__/swarm-orchestrator.test.ts +0 -463
  331. package/src/__tests__/swarm-plan-validator.test.ts +0 -384
  332. package/src/__tests__/swarm-recursion.test.ts +0 -197
  333. package/src/__tests__/swarm-router-planner.test.ts +0 -234
  334. package/src/__tests__/swarm-tool.test.ts +0 -185
  335. package/src/__tests__/swarm-worker-backend.test.ts +0 -144
  336. package/src/__tests__/swarm-worker-runner.test.ts +0 -288
  337. package/src/commands/__tests__/cc-command-registry.test.ts +0 -396
  338. package/src/commands/cc-command-registry.ts +0 -248
  339. package/src/config/bundled-skills/claude-code/SKILL.md +0 -53
  340. package/src/config/bundled-skills/claude-code/TOOLS.json +0 -47
  341. package/src/config/bundled-skills/claude-code/tools/claude-code.ts +0 -12
  342. package/src/config/bundled-skills/orchestration/SKILL.md +0 -33
  343. package/src/config/bundled-skills/orchestration/TOOLS.json +0 -35
  344. package/src/config/bundled-skills/orchestration/tools/swarm-delegate.ts +0 -12
  345. package/src/config/schemas/memory-simplified.ts +0 -101
  346. package/src/config/schemas/swarm.ts +0 -82
  347. package/src/logfire.ts +0 -135
  348. package/src/memory/archive-recall.ts +0 -516
  349. package/src/memory/archive-store.ts +0 -400
  350. package/src/memory/brief-formatting.ts +0 -33
  351. package/src/memory/brief-open-loops.ts +0 -266
  352. package/src/memory/brief-time.ts +0 -162
  353. package/src/memory/brief.ts +0 -75
  354. package/src/memory/job-handlers/backfill-simplified-memory.ts +0 -462
  355. package/src/memory/job-handlers/reduce-conversation-memory.ts +0 -229
  356. package/src/memory/migrations/185-memory-brief-state.ts +0 -52
  357. package/src/memory/migrations/186-memory-archive.ts +0 -109
  358. package/src/memory/migrations/187-memory-reducer-checkpoints.ts +0 -19
  359. package/src/memory/reducer-scheduler.ts +0 -242
  360. package/src/memory/reducer-store.ts +0 -271
  361. package/src/memory/reducer-types.ts +0 -106
  362. package/src/memory/reducer.ts +0 -467
  363. package/src/memory/schema/memory-archive.ts +0 -121
  364. package/src/memory/schema/memory-brief.ts +0 -55
  365. package/src/runtime/local-gateway-health.ts +0 -275
  366. package/src/security/secret-ingress.ts +0 -68
  367. package/src/swarm/backend-claude-code.ts +0 -225
  368. package/src/swarm/checkpoint.ts +0 -137
  369. package/src/swarm/graph-utils.ts +0 -53
  370. package/src/swarm/index.ts +0 -55
  371. package/src/swarm/limits.ts +0 -66
  372. package/src/swarm/orchestrator.ts +0 -424
  373. package/src/swarm/plan-validator.ts +0 -117
  374. package/src/swarm/router-planner.ts +0 -162
  375. package/src/swarm/router-prompts.ts +0 -39
  376. package/src/swarm/synthesizer.ts +0 -81
  377. package/src/swarm/types.ts +0 -72
  378. package/src/swarm/worker-backend.ts +0 -131
  379. package/src/swarm/worker-prompts.ts +0 -80
  380. package/src/swarm/worker-runner.ts +0 -170
  381. package/src/tools/claude-code/claude-code.ts +0 -610
  382. package/src/tools/swarm/delegate.ts +0 -205
@@ -537,8 +537,8 @@ describe("keychain-broker-client", () => {
537
537
  writeFileSync(SOCKET_PATH, "");
538
538
  expect(client.isAvailable()).toBe(false);
539
539
 
540
- // Advance time past the first cooldown (30s)
541
- fakeNow += 30_001;
540
+ // Advance time past the first cooldown (5s)
541
+ fakeNow += 5_001;
542
542
  expect(client.isAvailable()).toBe(true);
543
543
 
544
544
  // Now start a real broker and verify the client reconnects
@@ -558,8 +558,8 @@ describe("keychain-broker-client", () => {
558
558
  const client = createBrokerClient();
559
559
  await client.ping();
560
560
 
561
- // Advance past first cooldown (30s)
562
- fakeNow += 30_001;
561
+ // Advance past first cooldown (5s)
562
+ fakeNow += 5_001;
563
563
 
564
564
  // Start broker — reconnection should succeed and reset counters
565
565
  const broker = createMockBroker();
@@ -578,15 +578,15 @@ describe("keychain-broker-client", () => {
578
578
  rmSync(SOCKET_PATH, { force: true });
579
579
 
580
580
  // This new failure should start from the beginning of the cooldown
581
- // schedule (30s), not escalated.
581
+ // schedule (5s), not escalated.
582
582
  await client.ping();
583
583
 
584
- // Verify cooldown is back to 30s (not 60s)
584
+ // Verify cooldown is back to 5s (not 15s)
585
585
  writeFileSync(SOCKET_PATH, "");
586
586
  expect(client.isAvailable()).toBe(false);
587
587
 
588
- // 30s should be enough to clear cooldown
589
- fakeNow += 30_001;
588
+ // 5s should be enough to clear cooldown
589
+ fakeNow += 5_001;
590
590
  expect(client.isAvailable()).toBe(true);
591
591
  }, 15_000);
592
592
 
@@ -594,60 +594,73 @@ describe("keychain-broker-client", () => {
594
594
  const client = createBrokerClient();
595
595
 
596
596
  // First failure round: two attempts (first + immediate retry) ->
597
- // consecutiveFailures=2, cooldown index = max(2-2,0) = 0 -> 30s.
597
+ // consecutiveFailures=2, cooldown index = max(2-2,0) = 0 -> 5s.
598
598
  await client.ping();
599
599
 
600
600
  writeFileSync(SOCKET_PATH, "");
601
601
  expect(client.isAvailable()).toBe(false);
602
602
 
603
- // 30s should clear the first cooldown
604
- fakeNow += 30_001;
603
+ // 5s should clear the first cooldown
604
+ fakeNow += 5_001;
605
605
  expect(client.isAvailable()).toBe(true);
606
606
 
607
607
  // Remove socket to trigger another failure. After cooldown elapses,
608
608
  // ensureConnected clears unavailableSince and tries connect().
609
609
  // This failure increments consecutiveFailures to 3 (no immediate retry
610
610
  // since consecutiveFailures > 1 after increment).
611
- // Cooldown index = max(3-2,0) = 1 -> 60s.
611
+ // Cooldown index = max(3-2,0) = 1 -> 15s.
612
612
  rmSync(SOCKET_PATH, { force: true });
613
613
  await client.ping();
614
614
 
615
615
  writeFileSync(SOCKET_PATH, "");
616
616
  expect(client.isAvailable()).toBe(false);
617
617
 
618
- fakeNow += 30_001;
619
- expect(client.isAvailable()).toBe(false); // 30s not enough
618
+ fakeNow += 5_001;
619
+ expect(client.isAvailable()).toBe(false); // 5s not enough
620
620
 
621
- fakeNow += 30_000; // total 60_001ms since this cooldown started
621
+ fakeNow += 10_000; // total 15_001ms since this cooldown started
622
622
  expect(client.isAvailable()).toBe(true);
623
623
 
624
- // Another failure -> consecutiveFailures=4, index = max(4-2,0) = 2 -> 120s (2min)
624
+ // Another failure -> consecutiveFailures=4, index = max(4-2,0) = 2 -> 30s
625
625
  rmSync(SOCKET_PATH, { force: true });
626
626
  await client.ping();
627
627
 
628
628
  writeFileSync(SOCKET_PATH, "");
629
629
  expect(client.isAvailable()).toBe(false);
630
630
 
631
- fakeNow += 60_001;
631
+ fakeNow += 15_001;
632
+ expect(client.isAvailable()).toBe(false);
633
+
634
+ fakeNow += 15_000; // total 30_001ms
635
+ expect(client.isAvailable()).toBe(true);
636
+
637
+ // Another failure -> consecutiveFailures=5, index = max(5-2,0) = 3 -> 60s
638
+ rmSync(SOCKET_PATH, { force: true });
639
+ await client.ping();
640
+
641
+ writeFileSync(SOCKET_PATH, "");
642
+ expect(client.isAvailable()).toBe(false);
643
+
644
+ fakeNow += 30_001;
632
645
  expect(client.isAvailable()).toBe(false);
633
646
 
634
- fakeNow += 60_000; // total 120_001ms
647
+ fakeNow += 30_000; // total 60_001ms
635
648
  expect(client.isAvailable()).toBe(true);
636
649
 
637
- // Another failure -> consecutiveFailures=5, index = max(5-2,0) = 3 -> 300s (5min)
650
+ // Another failure -> consecutiveFailures=6, index = min(max(6-2,0), 4) = 4 -> 300s (5min)
638
651
  rmSync(SOCKET_PATH, { force: true });
639
652
  await client.ping();
640
653
 
641
654
  writeFileSync(SOCKET_PATH, "");
642
655
  expect(client.isAvailable()).toBe(false);
643
656
 
644
- fakeNow += 120_001;
657
+ fakeNow += 60_001;
645
658
  expect(client.isAvailable()).toBe(false);
646
659
 
647
- fakeNow += 180_000; // total 300_001ms
660
+ fakeNow += 240_000; // total 300_001ms
648
661
  expect(client.isAvailable()).toBe(true);
649
662
 
650
- // Another failure -> consecutiveFailures=6, index = min(max(6-2,0), 3) = 3 -> 300s (capped)
663
+ // Another failure -> consecutiveFailures=7, index = min(max(7-2,0), 4) = 4 -> 300s (capped)
651
664
  rmSync(SOCKET_PATH, { force: true });
652
665
  await client.ping();
653
666
 
@@ -658,4 +671,130 @@ describe("keychain-broker-client", () => {
658
671
  expect(client.isAvailable()).toBe(true);
659
672
  });
660
673
  });
674
+
675
+ // -----------------------------------------------------------------------
676
+ // Connect timeout
677
+ // -----------------------------------------------------------------------
678
+ describe("connect timeout", () => {
679
+ let stopFn: (() => Promise<void>) | null = null;
680
+
681
+ beforeEach(() => {
682
+ writeFileSync(TOKEN_PATH, TEST_TOKEN);
683
+ });
684
+
685
+ afterEach(async () => {
686
+ if (stopFn) {
687
+ await stopFn();
688
+ stopFn = null;
689
+ }
690
+ });
691
+
692
+ test("rejects connect within 3 seconds when broker is unresponsive", async () => {
693
+ // Create a server that accepts connections but never responds
694
+ // (simulates an unresponsive broker process).
695
+ const activeConns = new Set<import("node:net").Socket>();
696
+ const server = createServer((conn) => {
697
+ activeConns.add(conn);
698
+ conn.on("close", () => activeConns.delete(conn));
699
+ // Accept connection but do nothing — no data, no close
700
+ });
701
+ await new Promise<void>((resolve) => {
702
+ server.listen(SOCKET_PATH, () => resolve());
703
+ });
704
+ stopFn = () =>
705
+ new Promise<void>((resolve) => {
706
+ for (const conn of activeConns) conn.destroy();
707
+ activeConns.clear();
708
+ server.close(() => resolve());
709
+ });
710
+
711
+ const client = createBrokerClient();
712
+ const start = Date.now();
713
+ const result = await client.ping();
714
+ const elapsed = Date.now() - start;
715
+
716
+ // Should return null (graceful fallback) and not hang indefinitely.
717
+ // The connect timeout is 3s; allow some slack but it should be well
718
+ // under 10s (the old behavior would hang for REQUEST_TIMEOUT_MS * retries).
719
+ expect(result).toBeNull();
720
+ expect(elapsed).toBeLessThan(10_000);
721
+ }, 15_000);
722
+
723
+ test("successful connect clears the connect timer", async () => {
724
+ // Normal broker that responds to pings — verifies the timer is cleared
725
+ // and doesn't fire after a successful connection.
726
+ const broker = createMockBroker();
727
+ broker.setHandler(() => ({ ok: true, result: { pong: true } }));
728
+ await broker.start();
729
+ stopFn = () => broker.stop();
730
+
731
+ const client = createBrokerClient();
732
+ const result = await client.ping();
733
+ expect(result).toEqual({ pong: true });
734
+
735
+ // Wait a bit past the connect timeout to ensure no stale timer fires
736
+ await new Promise((r) => setTimeout(r, 100));
737
+
738
+ // Client should still work fine
739
+ const result2 = await client.ping();
740
+ expect(result2).toEqual({ pong: true });
741
+ });
742
+ });
743
+
744
+ // -----------------------------------------------------------------------
745
+ // Reduced initial cooldown
746
+ // -----------------------------------------------------------------------
747
+ describe("reduced initial cooldown", () => {
748
+ const originalDateNow = Date.now;
749
+ let fakeNow: number;
750
+
751
+ beforeEach(() => {
752
+ fakeNow = originalDateNow.call(Date);
753
+ Date.now = () => fakeNow;
754
+ writeFileSync(TOKEN_PATH, TEST_TOKEN);
755
+ });
756
+
757
+ afterEach(() => {
758
+ Date.now = originalDateNow;
759
+ });
760
+
761
+ test("first cooldown is 5 seconds, not 30 seconds", async () => {
762
+ const client = createBrokerClient();
763
+
764
+ // Trigger two connection failures (first + immediate retry)
765
+ await client.ping();
766
+
767
+ writeFileSync(SOCKET_PATH, "");
768
+
769
+ // Should still be in cooldown at 4 seconds
770
+ fakeNow += 4_000;
771
+ expect(client.isAvailable()).toBe(false);
772
+
773
+ // Should be available after 5 seconds
774
+ fakeNow += 1_001;
775
+ expect(client.isAvailable()).toBe(true);
776
+ });
777
+
778
+ test("second cooldown is 15 seconds", async () => {
779
+ const client = createBrokerClient();
780
+
781
+ // First failure round -> cooldown 5s
782
+ await client.ping();
783
+
784
+ // Clear first cooldown
785
+ fakeNow += 5_001;
786
+
787
+ // Second failure -> cooldown 15s
788
+ await client.ping();
789
+
790
+ writeFileSync(SOCKET_PATH, "");
791
+ expect(client.isAvailable()).toBe(false);
792
+
793
+ fakeNow += 14_000;
794
+ expect(client.isAvailable()).toBe(false);
795
+
796
+ fakeNow += 1_001;
797
+ expect(client.isAvailable()).toBe(true);
798
+ });
799
+ });
661
800
  });
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Tests for adaptive poll interval backoff in the memory jobs worker.
3
+ *
4
+ * Verifies that when no jobs are claimable, the poll interval doubles each
5
+ * tick (1.5s -> 3s -> 6s -> ... -> 30s cap), and resets to 1.5s when work
6
+ * is found.
7
+ */
8
+ import { describe, expect, mock, test } from "bun:test";
9
+
10
+ // ── Mocks (must precede imports of tested module) ──────────────────
11
+
12
+ mock.module("../util/platform.js", () => ({
13
+ getDataDir: () => "/tmp/test-backoff",
14
+ isMacOS: () => false,
15
+ isLinux: () => true,
16
+ isWindows: () => false,
17
+ getPidPath: () => "/tmp/test-backoff/test.pid",
18
+ getDbPath: () => "/tmp/test-backoff/test.db",
19
+ getLogPath: () => "/tmp/test-backoff/test.log",
20
+ ensureDataDir: () => {},
21
+ }));
22
+
23
+ mock.module("../util/logger.js", () => ({
24
+ getLogger: () =>
25
+ new Proxy({} as Record<string, unknown>, {
26
+ get: () => () => {},
27
+ }),
28
+ }));
29
+
30
+ // Mock config — memory disabled so runMemoryJobsOnce returns 0 immediately
31
+ mock.module("../config/loader.js", () => ({
32
+ getConfig: () => ({
33
+ memory: { enabled: false },
34
+ }),
35
+ loadConfig: () => ({
36
+ memory: { enabled: false },
37
+ }),
38
+ }));
39
+
40
+ // Mock jobs-store (accesses DB)
41
+ mock.module("../memory/jobs-store.js", () => ({
42
+ resetRunningJobsToPending: () => 0,
43
+ claimMemoryJobs: () => [],
44
+ completeMemoryJob: () => {},
45
+ deferMemoryJob: () => "deferred",
46
+ failMemoryJob: () => {},
47
+ failStalledJobs: () => 0,
48
+ enqueueCleanupStaleSupersededItemsJob: () => null,
49
+ enqueuePruneOldConversationsJob: () => null,
50
+ }));
51
+
52
+ // Mock db.js (rawRun used in sweepStaleItems)
53
+ mock.module("../memory/db.js", () => ({
54
+ rawRun: () => 0,
55
+ }));
56
+
57
+ import {
58
+ POLL_INTERVAL_MAX_MS,
59
+ POLL_INTERVAL_MIN_MS,
60
+ startMemoryJobsWorker,
61
+ } from "../memory/jobs-worker.js";
62
+
63
+ describe("memory jobs worker adaptive poll interval", () => {
64
+ test("exports expected poll interval constants", () => {
65
+ expect(POLL_INTERVAL_MIN_MS).toBe(1_500);
66
+ expect(POLL_INTERVAL_MAX_MS).toBe(30_000);
67
+ });
68
+
69
+ test("backoff sequence doubles from min to max then caps", () => {
70
+ // Verify the math: starting at 1500, doubling each step, capped at 30000
71
+ const intervals: number[] = [];
72
+ let current = POLL_INTERVAL_MIN_MS;
73
+ for (let i = 0; i < 10; i++) {
74
+ intervals.push(current);
75
+ current = Math.min(current * 2, POLL_INTERVAL_MAX_MS);
76
+ }
77
+ expect(intervals).toEqual([
78
+ 1_500, // tick 1
79
+ 3_000, // tick 2
80
+ 6_000, // tick 3
81
+ 12_000, // tick 4
82
+ 24_000, // tick 5
83
+ 30_000, // tick 6 (capped)
84
+ 30_000, // stays capped
85
+ 30_000,
86
+ 30_000,
87
+ 30_000,
88
+ ]);
89
+ });
90
+
91
+ test("worker schedules setTimeout with increasing intervals when idle", async () => {
92
+ const timeoutDelays: number[] = [];
93
+ const originalSetTimeout = globalThis.setTimeout;
94
+ const originalClearTimeout = globalThis.clearTimeout;
95
+
96
+ // Collect pending timer callbacks so we can fire them manually
97
+ const pendingCallbacks: Array<() => void> = [];
98
+
99
+ globalThis.setTimeout = ((fn: () => void, delay?: number) => {
100
+ if (delay !== undefined && delay >= POLL_INTERVAL_MIN_MS) {
101
+ timeoutDelays.push(delay);
102
+ pendingCallbacks.push(fn);
103
+ }
104
+ return 999 as unknown as ReturnType<typeof setTimeout>;
105
+ }) as typeof setTimeout;
106
+ globalThis.clearTimeout = (() => {}) as typeof clearTimeout;
107
+
108
+ try {
109
+ const worker = startMemoryJobsWorker();
110
+
111
+ // Wait for the initial tick() promise to settle
112
+ await new Promise((resolve) => originalSetTimeout(resolve, 20));
113
+
114
+ // Fire pending timer callbacks to advance through the backoff sequence.
115
+ // Each callback triggers tick() which is async, so we await a microtask
116
+ // after each to let the promise chain settle and schedule the next timer.
117
+ for (let i = 0; i < 6; i++) {
118
+ const cb = pendingCallbacks.shift();
119
+ if (cb) {
120
+ cb();
121
+ await new Promise((resolve) => originalSetTimeout(resolve, 20));
122
+ }
123
+ }
124
+
125
+ worker.stop();
126
+
127
+ // We should have captured several setTimeout calls with increasing delays
128
+ expect(timeoutDelays.length).toBeGreaterThanOrEqual(4);
129
+
130
+ // Intervals should be non-decreasing (backoff)
131
+ for (let i = 1; i < timeoutDelays.length; i++) {
132
+ expect(timeoutDelays[i]).toBeGreaterThanOrEqual(timeoutDelays[i - 1]!);
133
+ }
134
+
135
+ // All intervals within bounds
136
+ for (const delay of timeoutDelays) {
137
+ expect(delay).toBeGreaterThanOrEqual(POLL_INTERVAL_MIN_MS);
138
+ expect(delay).toBeLessThanOrEqual(POLL_INTERVAL_MAX_MS);
139
+ }
140
+
141
+ // Should eventually reach the cap
142
+ expect(timeoutDelays[timeoutDelays.length - 1]).toBe(
143
+ POLL_INTERVAL_MAX_MS,
144
+ );
145
+ } finally {
146
+ globalThis.setTimeout = originalSetTimeout;
147
+ globalThis.clearTimeout = originalClearTimeout;
148
+ }
149
+ });
150
+ });
@@ -540,23 +540,13 @@ describe("Memory regressions", () => {
540
540
 
541
541
  test("memory_save sets verificationState to user_confirmed", async () => {
542
542
  const { handleMemorySave } = await import("../tools/memory/handlers.js");
543
- const legacyConfig = {
544
- ...DEFAULT_CONFIG,
545
- memory: {
546
- ...DEFAULT_CONFIG.memory,
547
- simplified: {
548
- ...DEFAULT_CONFIG.memory.simplified,
549
- enabled: false,
550
- },
551
- },
552
- };
553
543
 
554
544
  const result = await handleMemorySave(
555
545
  {
556
546
  statement: "User explicitly saved this preference",
557
547
  kind: "preference",
558
548
  },
559
- legacyConfig,
549
+ DEFAULT_CONFIG,
560
550
  "conv-verify-save",
561
551
  "msg-verify-save",
562
552
  );
@@ -573,23 +563,13 @@ describe("Memory regressions", () => {
573
563
 
574
564
  test("memory_save in different scopes creates separate items", async () => {
575
565
  const { handleMemorySave } = await import("../tools/memory/handlers.js");
576
- const legacyConfig = {
577
- ...DEFAULT_CONFIG,
578
- memory: {
579
- ...DEFAULT_CONFIG.memory,
580
- simplified: {
581
- ...DEFAULT_CONFIG.memory.simplified,
582
- enabled: false,
583
- },
584
- },
585
- };
586
566
 
587
567
  const sharedArgs = { statement: "I prefer dark mode", kind: "preference" };
588
568
 
589
569
  // Save in the default scope
590
570
  const r1 = await handleMemorySave(
591
571
  sharedArgs,
592
- legacyConfig,
572
+ DEFAULT_CONFIG,
593
573
  "conv-scope-1",
594
574
  "msg-scope-1",
595
575
  "default",
@@ -600,7 +580,7 @@ describe("Memory regressions", () => {
600
580
  // Save the identical statement in a private scope
601
581
  const r2 = await handleMemorySave(
602
582
  sharedArgs,
603
- legacyConfig,
583
+ DEFAULT_CONFIG,
604
584
  "conv-scope-2",
605
585
  "msg-scope-2",
606
586
  "private-abc",
@@ -624,7 +604,7 @@ describe("Memory regressions", () => {
624
604
  // Saving the same statement again in default scope should dedup (not create a third)
625
605
  const r3 = await handleMemorySave(
626
606
  sharedArgs,
627
- legacyConfig,
607
+ DEFAULT_CONFIG,
628
608
  "conv-scope-3",
629
609
  "msg-scope-3",
630
610
  "default",
@@ -3227,9 +3207,8 @@ describe("Memory regressions", () => {
3227
3207
  .filter((j) => JSON.parse(j.payload).messageId === "msg-untrusted-gate");
3228
3208
  expect(extractJobs.length).toBe(0);
3229
3209
 
3230
- // enqueuedJobs reflects legacy embed_segment + archive embed_chunk per
3231
- // segment, plus the summary job, with extract_items gated off.
3232
- const expectedJobs = result.indexedSegments * 2 + 1;
3210
+ // enqueuedJobs should reflect: embed jobs + summary (1), no extract (0)
3211
+ const expectedJobs = result.indexedSegments + 1; // embed per segment + summary
3233
3212
  expect(result.enqueuedJobs).toBe(expectedJobs);
3234
3213
  });
3235
3214
 
@@ -3410,9 +3389,8 @@ describe("Memory regressions", () => {
3410
3389
  .filter((j) => JSON.parse(j.payload).messageId === "msg-unverified-gate");
3411
3390
  expect(extractJobs.length).toBe(0);
3412
3391
 
3413
- // enqueuedJobs reflects legacy embed_segment + archive embed_chunk per
3414
- // segment, plus the summary job, with extract_items gated off.
3415
- const expectedJobs = result.indexedSegments * 2 + 1;
3392
+ // enqueuedJobs should reflect: embed jobs + summary (1), no extract (0)
3393
+ const expectedJobs = result.indexedSegments + 1; // embed per segment + summary
3416
3394
  expect(result.enqueuedJobs).toBe(expectedJobs);
3417
3395
  });
3418
3396
 
@@ -527,9 +527,9 @@ describe("integration: existing routes unaffected", () => {
527
527
  });
528
528
 
529
529
  test("GET /v1/health still works (not intercepted by migration routes)", async () => {
530
- const { handleHealth } =
530
+ const { handleDetailedHealth } =
531
531
  await import("../runtime/routes/identity-routes.js");
532
- const res = handleHealth();
532
+ const res = handleDetailedHealth();
533
533
  const body = (await res.json()) as Record<string, unknown>;
534
534
 
535
535
  expect(res.status).toBe(200);
@@ -939,9 +939,9 @@ describe("route policy registration", () => {
939
939
 
940
940
  describe("integration: existing routes unaffected", () => {
941
941
  test("GET /v1/health still works", async () => {
942
- const { handleHealth } =
942
+ const { handleDetailedHealth } =
943
943
  await import("../runtime/routes/identity-routes.js");
944
- const res = handleHealth();
944
+ const res = handleDetailedHealth();
945
945
  const body = (await res.json()) as Record<string, unknown>;
946
946
 
947
947
  expect(res.status).toBe(200);
@@ -792,9 +792,9 @@ describe("route policy registration", () => {
792
792
 
793
793
  describe("integration: existing routes unaffected", () => {
794
794
  test("GET /v1/health still works", async () => {
795
- const { handleHealth } =
795
+ const { handleDetailedHealth } =
796
796
  await import("../runtime/routes/identity-routes.js");
797
- const res = handleHealth();
797
+ const res = handleDetailedHealth();
798
798
  const body = (await res.json()) as Record<string, unknown>;
799
799
 
800
800
  expect(res.status).toBe(200);
@@ -684,9 +684,9 @@ describe("route policy registration", () => {
684
684
 
685
685
  describe("integration: existing routes unaffected", () => {
686
686
  test("GET /v1/health still works (not intercepted by migration routes)", async () => {
687
- const { handleHealth } =
687
+ const { handleDetailedHealth } =
688
688
  await import("../runtime/routes/identity-routes.js");
689
- const res = handleHealth();
689
+ const res = handleDetailedHealth();
690
690
  const body = (await res.json()) as Record<string, unknown>;
691
691
 
692
692
  expect(res.status).toBe(200);
@@ -37,11 +37,6 @@ mock.module("../util/logger.js", () => ({
37
37
  }),
38
38
  }));
39
39
 
40
- // Mock security check to always pass
41
- mock.module("../security/secret-ingress.js", () => ({
42
- checkIngressForSecrets: () => ({ blocked: false }),
43
- }));
44
-
45
40
  mock.module("../config/env.js", () => ({
46
41
  isHttpAuthDisabled: () => true,
47
42
  getGatewayInternalBaseUrl: () => "http://127.0.0.1:7830",
@@ -34,6 +34,10 @@ mock.module("../notifications/conversation-candidates.js", () => ({
34
34
  serializeCandidatesForPrompt: () => undefined,
35
35
  }));
36
36
 
37
+ mock.module("../prompts/persona-resolver.js", () => ({
38
+ resolveGuardianPersona: () => null,
39
+ }));
40
+
37
41
  let configuredProvider: { sendMessage: () => Promise<unknown> } | null = null;
38
42
  let extractedToolUse: unknown = null;
39
43
 
@@ -36,6 +36,10 @@ mock.module("../notifications/conversation-candidates.js", () => ({
36
36
  serializeCandidatesForPrompt: () => undefined,
37
37
  }));
38
38
 
39
+ mock.module("../prompts/persona-resolver.js", () => ({
40
+ resolveGuardianPersona: () => null,
41
+ }));
42
+
39
43
  // ── Identity context mock ─────────────────────────────────────────────
40
44
 
41
45
  let mockIdentityContext: string | null = null;
@@ -15,6 +15,7 @@ describe("isAllowDecision", () => {
15
15
  "always_allow",
16
16
  "always_allow_high_risk",
17
17
  "temporary_override",
18
+ "dangerously_skip_permissions",
18
19
  ];
19
20
 
20
21
  for (const decision of allowDecisions) {
@@ -193,13 +193,12 @@ describe("managed proxy integration — credential precedence", () => {
193
193
 
194
194
  const provider = getProvider("anthropic");
195
195
 
196
- // Unwrap RetryProvider → LogfireProvider → AnthropicProvider to inspect
197
- // the Anthropic SDK client's baseURL. The wrappers use private `inner`
198
- // and AnthropicProvider stores the SDK client as private `client`.
196
+ // Unwrap RetryProvider → AnthropicProvider to inspect the Anthropic
197
+ // SDK client's baseURL. RetryProvider stores the inner provider as
198
+ // private `inner` and AnthropicProvider stores the SDK client as
199
+ // private `client`.
199
200
  const retryInner = (provider as any).inner;
200
- // retryInner is the logfire wrapper; it also has an `inner` property
201
- const logfireInner = (retryInner as any).inner ?? retryInner;
202
- const anthropicClient = (logfireInner as any).client;
201
+ const anthropicClient = (retryInner as any).client;
203
202
 
204
203
  expect(anthropicClient).toBeDefined();
205
204
  const baseURL: string = anthropicClient.baseURL;
@@ -312,9 +312,10 @@ describe("QdrantManager", () => {
312
312
  expect(existsSync(pidPath)).toBe(false);
313
313
  }, 10_000);
314
314
 
315
- test("cleans up when process exits immediately", async () => {
315
+ test("fails fast with exit code when process exits immediately", async () => {
316
316
  const pidPath = join(testDataDir, "qdrant", "qdrant.pid");
317
317
 
318
+ // GIVEN a Qdrant binary that exits immediately with code 1
318
319
  placeFakeBinary("#!/bin/sh\nexit 1");
319
320
 
320
321
  const port = getTestPort();
@@ -323,9 +324,34 @@ describe("QdrantManager", () => {
323
324
  ...FAST_TIMEOUTS,
324
325
  });
325
326
 
326
- await expect(mgr.start()).rejects.toThrow("did not become ready");
327
+ // WHEN we start the manager
328
+ const startTime = Date.now();
329
+ await expect(mgr.start()).rejects.toThrow(
330
+ /exited with code \d+ before becoming ready/,
331
+ );
332
+ const elapsed = Date.now() - startTime;
333
+
334
+ // THEN it fails fast (well under the 100ms readyz timeout)
335
+ expect(elapsed).toBeLessThan(FAST_TIMEOUTS.readyzTimeoutMs);
336
+
337
+ // AND the PID file is cleaned up
327
338
  expect(existsSync(pidPath)).toBe(false);
328
339
  }, 10_000);
340
+
341
+ test("includes stderr in error when process crashes", async () => {
342
+ // GIVEN a Qdrant binary that writes to stderr before crashing
343
+ placeFakeBinary('#!/bin/sh\necho "fatal: storage corrupted" >&2\nexit 1');
344
+
345
+ const port = getTestPort();
346
+ const mgr = new QdrantManager({
347
+ url: `http://127.0.0.1:${port}`,
348
+ ...FAST_TIMEOUTS,
349
+ });
350
+
351
+ // WHEN we start the manager
352
+ // THEN the error includes the stderr output
353
+ await expect(mgr.start()).rejects.toThrow("storage corrupted");
354
+ }, 10_000);
329
355
  });
330
356
 
331
357
  // ── Binary Detection ─────────────────────────────────────────