@vellumai/assistant 0.8.8 → 0.8.9-dev.202606091926.ebb2d62

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 (490) hide show
  1. package/ARCHITECTURE.md +6 -6
  2. package/bun.lock +2 -2
  3. package/docs/activation-funnel-telemetry.md +310 -0
  4. package/examples/plugins/echo/README.md +61 -60
  5. package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
  6. package/examples/plugins/echo/hooks/stop.ts +16 -0
  7. package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
  8. package/examples/plugins/echo/package.json +1 -2
  9. package/examples/plugins/echo/src/emit.ts +19 -0
  10. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
  11. package/openapi.yaml +273 -121
  12. package/package.json +2 -2
  13. package/scripts/sync-llm-catalog.ts +2 -0
  14. package/src/__tests__/activation-early-marking.test.ts +120 -0
  15. package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
  16. package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
  17. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
  18. package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
  19. package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
  20. package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
  21. package/src/__tests__/agent-loop-thinking.test.ts +36 -20
  22. package/src/__tests__/agent-loop.test.ts +441 -96
  23. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
  24. package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
  25. package/src/__tests__/anthropic-provider.test.ts +23 -8
  26. package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
  27. package/src/__tests__/app-control-flow.test.ts +1 -1
  28. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  29. package/src/__tests__/app-executors.test.ts +132 -0
  30. package/src/__tests__/approval-cascade.test.ts +6 -5
  31. package/src/__tests__/approval-routes-http.test.ts +4 -1
  32. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  33. package/src/__tests__/build-persisted-content.test.ts +75 -1
  34. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  35. package/src/__tests__/channel-approvals.test.ts +1 -1
  36. package/src/__tests__/compaction-circuit.test.ts +258 -0
  37. package/src/__tests__/compaction-direct.test.ts +146 -0
  38. package/src/__tests__/compaction-events.test.ts +7 -7
  39. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  40. package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
  41. package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
  42. package/src/__tests__/context-overflow-reducer.test.ts +265 -125
  43. package/src/__tests__/context-window-manager-compact-retry.test.ts +121 -15
  44. package/src/__tests__/conversation-abort-tool-results.test.ts +7 -5
  45. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
  46. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
  47. package/src/__tests__/conversation-agent-loop-overflow.test.ts +158 -234
  48. package/src/__tests__/conversation-agent-loop.test.ts +342 -623
  49. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  50. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -5
  51. package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
  52. package/src/__tests__/conversation-error.test.ts +15 -1
  53. package/src/__tests__/conversation-history-web-search.test.ts +6 -1
  54. package/src/__tests__/conversation-media-retry.test.ts +1 -1
  55. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +44 -4
  56. package/src/__tests__/conversation-process-callsite.test.ts +15 -15
  57. package/src/__tests__/conversation-provider-retry-repair.test.ts +66 -65
  58. package/src/__tests__/conversation-queue.test.ts +10 -10
  59. package/src/__tests__/conversation-runtime-assembly.test.ts +1059 -231
  60. package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
  61. package/src/__tests__/conversation-slash-queue.test.ts +7 -5
  62. package/src/__tests__/conversation-slash-unknown.test.ts +7 -5
  63. package/src/__tests__/conversation-speed-override.test.ts +11 -10
  64. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  65. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
  66. package/src/__tests__/conversation-surfaces-app-control.test.ts +48 -1
  67. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
  68. package/src/__tests__/conversation-undo.test.ts +2 -2
  69. package/src/__tests__/conversation-workspace-cache-state.test.ts +24 -21
  70. package/src/__tests__/conversation-workspace-injection.test.ts +69 -7
  71. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +15 -12
  72. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  73. package/src/__tests__/corrected-target.test.ts +93 -0
  74. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -4
  75. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  76. package/src/__tests__/cu-unified-flow.test.ts +36 -0
  77. package/src/__tests__/db-acp-history.test.ts +101 -0
  78. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  79. package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
  80. package/src/__tests__/empty-response-hook.test.ts +1 -1
  81. package/src/__tests__/file-write-tool.test.ts +63 -0
  82. package/src/__tests__/gateway-only-guard.test.ts +17 -2
  83. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  84. package/src/__tests__/guardian-routing-invariants.test.ts +93 -4
  85. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  87. package/src/__tests__/heartbeat-service.test.ts +1 -0
  88. package/src/__tests__/history-repair-hook.test.ts +5 -1
  89. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  90. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  91. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  92. package/src/__tests__/inference-profile-reaper.test.ts +62 -0
  93. package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
  94. package/src/__tests__/injector-background-turn.test.ts +13 -23
  95. package/src/__tests__/injector-chain.test.ts +268 -44
  96. package/src/__tests__/injector-disk-pressure.test.ts +210 -52
  97. package/src/__tests__/injector-document-comments.test.ts +97 -114
  98. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  99. package/src/__tests__/injector-v3-suppression.test.ts +4 -4
  100. package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  102. package/src/__tests__/llm-catalog-parity.test.ts +4 -0
  103. package/src/__tests__/llm-resolver.test.ts +73 -0
  104. package/src/__tests__/memory-retrieval-hook.test.ts +156 -38
  105. package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
  106. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  107. package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
  108. package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
  109. package/src/__tests__/persist-unsendable-image.test.ts +97 -1
  110. package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
  111. package/src/__tests__/plugin-api-shim.test.ts +6 -9
  112. package/src/__tests__/plugin-bootstrap.test.ts +91 -81
  113. package/src/__tests__/plugin-registry.test.ts +3 -49
  114. package/src/__tests__/plugin-skill-contribution.test.ts +15 -14
  115. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  116. package/src/__tests__/plugin-types.test.ts +0 -70
  117. package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
  118. package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
  119. package/src/__tests__/published-app-updater.test.ts +138 -0
  120. package/src/__tests__/reaction-persistence.test.ts +1 -1
  121. package/src/__tests__/retry-thinking-adaptive-only.test.ts +245 -0
  122. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  123. package/src/__tests__/server-history-render.test.ts +39 -0
  124. package/src/__tests__/skill-feature-flags-integration.test.ts +31 -0
  125. package/src/__tests__/steer-tool-repair.test.ts +1 -1
  126. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  127. package/src/__tests__/subagent-detail.test.ts +25 -7
  128. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  129. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  130. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  131. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  132. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  133. package/src/__tests__/title-generate-hook.test.ts +5 -1
  134. package/src/__tests__/tool-error-hook.test.ts +1 -1
  135. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
  136. package/src/__tests__/tool-start-timestamp.test.ts +218 -0
  137. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  138. package/src/__tests__/web-fetch.test.ts +45 -0
  139. package/src/acp/__tests__/agent-process.test.ts +161 -0
  140. package/src/acp/__tests__/client-handler.test.ts +40 -0
  141. package/src/acp/__tests__/helpers/acp-config-stub.ts +0 -2
  142. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  143. package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
  144. package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
  145. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  146. package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
  147. package/src/acp/agent-process.ts +61 -1
  148. package/src/acp/auto-install.test.ts +280 -0
  149. package/src/acp/auto-install.ts +232 -0
  150. package/src/acp/client-handler.ts +31 -0
  151. package/src/acp/prepare-agent-env.ts +80 -27
  152. package/src/acp/resolve-agent.test.ts +188 -28
  153. package/src/acp/resolve-agent.ts +119 -42
  154. package/src/acp/resume-hint.ts +23 -0
  155. package/src/acp/session-manager.ts +507 -73
  156. package/src/agent/compaction-circuit.ts +60 -102
  157. package/src/agent/loop.ts +403 -251
  158. package/src/api/events/tool-result.ts +9 -0
  159. package/src/api/events/tool-use-start.ts +7 -0
  160. package/src/api/responses/conversation-message.ts +72 -13
  161. package/src/api/responses/memory-v3-selection-log.ts +19 -10
  162. package/src/approvals/guardian-request-resolvers.ts +27 -1
  163. package/src/background-wake/next-wake.ts +1 -0
  164. package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
  165. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  166. package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
  167. package/src/cli/commands/memory-v3.ts +57 -199
  168. package/src/cli/commands/plugins.ts +43 -37
  169. package/src/cli/lib/__tests__/install-from-github.test.ts +790 -111
  170. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
  171. package/src/cli/lib/__tests__/plugin-details.test.ts +381 -0
  172. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +270 -0
  173. package/src/cli/lib/__tests__/search-plugins.test.ts +233 -32
  174. package/src/cli/lib/install-from-github.ts +797 -60
  175. package/src/cli/lib/plugin-catalog-cache.ts +84 -0
  176. package/src/cli/lib/plugin-details.ts +416 -0
  177. package/src/cli/lib/plugin-marketplace.ts +215 -0
  178. package/src/cli/lib/search-plugins.ts +201 -29
  179. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  180. package/src/config/acp-defaults.test.ts +10 -0
  181. package/src/config/acp-defaults.ts +9 -3
  182. package/src/config/acp-schema.ts +1 -7
  183. package/src/config/bundled-skills/acp/SKILL.md +80 -41
  184. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  185. package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
  186. package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
  187. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  188. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  189. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  190. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  191. package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
  192. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  193. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  194. package/src/config/bundled-tool-registry.ts +4 -0
  195. package/src/config/call-site-defaults.ts +0 -3
  196. package/src/config/feature-flag-registry.json +10 -56
  197. package/src/config/llm-resolver.ts +39 -7
  198. package/src/config/loader.ts +5 -22
  199. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
  200. package/src/config/schemas/call-site-catalog.ts +0 -21
  201. package/src/config/schemas/heartbeat.ts +9 -0
  202. package/src/config/schemas/llm.ts +17 -3
  203. package/src/config/schemas/memory-v3.ts +58 -8
  204. package/src/config/seed-inference-profiles.ts +18 -0
  205. package/src/context/compactor.ts +22 -4
  206. package/src/context/post-turn-tool-result-truncation.ts +39 -1
  207. package/src/context/strip-injections.ts +8 -2
  208. package/src/daemon/conversation-agent-loop-handlers.ts +120 -42
  209. package/src/daemon/conversation-agent-loop.ts +308 -1297
  210. package/src/daemon/conversation-error.ts +31 -4
  211. package/src/daemon/conversation-history.ts +1 -1
  212. package/src/daemon/conversation-lifecycle.ts +11 -255
  213. package/src/daemon/conversation-media-retry.ts +19 -6
  214. package/src/daemon/conversation-messaging.ts +17 -0
  215. package/src/daemon/conversation-process.ts +22 -141
  216. package/src/daemon/conversation-queue-manager.ts +8 -0
  217. package/src/daemon/conversation-registry.ts +159 -0
  218. package/src/daemon/conversation-runtime-assembly.ts +361 -393
  219. package/src/daemon/conversation-store.ts +9 -90
  220. package/src/daemon/conversation-surfaces.ts +165 -11
  221. package/src/daemon/conversation-workspace.ts +17 -0
  222. package/src/daemon/conversation.ts +444 -62
  223. package/src/daemon/disk-pressure-policy.ts +0 -1
  224. package/src/daemon/external-plugins-bootstrap.ts +36 -46
  225. package/src/daemon/handlers/config-channels.ts +11 -2
  226. package/src/daemon/handlers/conversations.ts +3 -1
  227. package/src/daemon/handlers/shared.ts +9 -1
  228. package/src/daemon/handlers/skills.ts +4 -1
  229. package/src/daemon/host-app-control-proxy.ts +72 -57
  230. package/src/daemon/host-proxy-preactivation.ts +1 -3
  231. package/src/daemon/lifecycle.ts +21 -7
  232. package/src/daemon/persist-unsendable-image.ts +62 -25
  233. package/src/daemon/process-message.ts +1 -1
  234. package/src/daemon/server.ts +2 -0
  235. package/src/daemon/tool-side-effects.ts +15 -0
  236. package/src/daemon/wake-conversation-ops.ts +269 -0
  237. package/src/embedded/plugin-api.ts +2 -2
  238. package/src/export/__tests__/transcript-formatter.test.ts +5 -0
  239. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  240. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  241. package/src/heartbeat/heartbeat-service.ts +26 -0
  242. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  243. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  244. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  245. package/src/ipc/skill-routes/memory.ts +4 -2
  246. package/src/memory/__tests__/activation-session-store.test.ts +41 -0
  247. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
  248. package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
  249. package/src/memory/activation-session-store.ts +43 -0
  250. package/src/memory/conversation-crud.ts +29 -19
  251. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  252. package/src/memory/db-init.ts +6 -0
  253. package/src/memory/embedding-backend.ts +5 -22
  254. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  255. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
  256. package/src/memory/jobs-worker.ts +25 -1
  257. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  258. package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
  259. package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
  260. package/src/memory/migrations/index.ts +3 -0
  261. package/src/memory/onboarding-events-store.ts +66 -18
  262. package/src/memory/schema/acp.ts +4 -0
  263. package/src/memory/schema/infrastructure.ts +13 -0
  264. package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
  265. package/src/memory/v2/__tests__/page-store.test.ts +22 -0
  266. package/src/memory/v2/consolidation-job.ts +2 -63
  267. package/src/memory/v2/types.ts +5 -0
  268. package/src/messaging/providers/telegram-bot/api.ts +14 -5
  269. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  270. package/src/notifications/access-request-copy.ts +298 -0
  271. package/src/notifications/adapters/slack.ts +3 -3
  272. package/src/notifications/adapters/telegram.ts +9 -2
  273. package/src/notifications/copy-composer.ts +49 -267
  274. package/src/notifications/decision-engine.ts +16 -35
  275. package/src/notifications/home-feed-side-effect.ts +1 -6
  276. package/src/plugin-api/constants.ts +4 -0
  277. package/src/plugin-api/index.ts +40 -11
  278. package/src/plugin-api/types.ts +108 -0
  279. package/src/plugins/defaults/compaction/compact.ts +106 -0
  280. package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +250 -42
  281. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  282. package/src/plugins/defaults/compaction/manager-store.ts +57 -0
  283. package/src/plugins/defaults/compaction/package.json +1 -2
  284. package/src/{context → plugins/defaults/compaction}/window-manager.ts +95 -25
  285. package/src/plugins/defaults/empty-response/package.json +0 -1
  286. package/src/plugins/defaults/history-repair/package.json +0 -1
  287. package/src/plugins/defaults/index.ts +156 -26
  288. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
  289. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +285 -0
  290. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  291. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
  292. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  293. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
  294. package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +71 -0
  295. package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
  296. package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
  297. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +147 -134
  298. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +456 -0
  299. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +662 -0
  300. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
  301. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +91 -0
  302. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
  303. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
  304. package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
  305. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +74 -19
  306. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
  307. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +592 -0
  308. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -24
  309. package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +91 -0
  310. package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
  311. package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
  312. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  313. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  314. package/src/plugins/defaults/memory-v3-shadow/injector.ts +76 -0
  315. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +555 -0
  316. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +266 -0
  317. package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
  318. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +71 -0
  319. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
  320. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +16 -8
  321. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
  322. package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
  323. package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
  324. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +156 -0
  325. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +382 -0
  326. package/src/plugins/defaults/memory-v3-shadow/types.ts +92 -0
  327. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +4 -1
  328. package/src/plugins/defaults/title-generate/package.json +0 -1
  329. package/src/plugins/defaults/tool-error/package.json +0 -1
  330. package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
  331. package/src/plugins/external-api.ts +12 -2
  332. package/src/plugins/pipeline.ts +6 -293
  333. package/src/plugins/registry.ts +9 -37
  334. package/src/plugins/types.ts +76 -381
  335. package/src/plugins/user-loader.ts +30 -127
  336. package/src/prompts/__tests__/system-prompt.test.ts +6 -0
  337. package/src/prompts/system-prompt.ts +61 -10
  338. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +71 -4
  339. package/src/providers/anthropic/client.ts +9 -10
  340. package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
  341. package/src/providers/inference/logit-bias.ts +55 -0
  342. package/src/providers/model-catalog.ts +57 -0
  343. package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
  344. package/src/providers/openai/chat-completions-provider.ts +44 -1
  345. package/src/providers/retry.ts +57 -7
  346. package/src/providers/types.ts +6 -0
  347. package/src/runtime/__tests__/agent-wake.test.ts +555 -691
  348. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  349. package/src/runtime/agent-wake.ts +108 -209
  350. package/src/runtime/assistant-event-hub.ts +1 -1
  351. package/src/runtime/channel-approvals.ts +1 -1
  352. package/src/runtime/interactive-ui.ts +1 -1
  353. package/src/runtime/routes/__tests__/acp-routes.test.ts +466 -55
  354. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  355. package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
  356. package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
  357. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  358. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  359. package/src/runtime/routes/acp-routes.test.ts +185 -32
  360. package/src/runtime/routes/acp-routes.ts +328 -30
  361. package/src/runtime/routes/app-management-routes.ts +3 -0
  362. package/src/runtime/routes/approval-routes.ts +1 -1
  363. package/src/runtime/routes/browser-routes.ts +1 -1
  364. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  365. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  366. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  367. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  368. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  369. package/src/runtime/routes/conversation-routes.ts +30 -2
  370. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  371. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  372. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  373. package/src/runtime/routes/host-cu-routes.ts +1 -1
  374. package/src/runtime/routes/identity-routes.ts +18 -3
  375. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  376. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  377. package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
  378. package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
  379. package/src/runtime/routes/memory-v3-routes.ts +65 -305
  380. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
  381. package/src/runtime/routes/playground/helpers.ts +1 -1
  382. package/src/runtime/routes/plugins-routes.ts +337 -35
  383. package/src/runtime/routes/stt-routes.ts +45 -12
  384. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  385. package/src/runtime/routes/work-items-routes.ts +2 -4
  386. package/src/runtime/routes/workspace-routes.ts +50 -15
  387. package/src/runtime/services/conversation-serializer.ts +1 -1
  388. package/src/runtime/verification-outbound-actions.ts +147 -2
  389. package/src/runtime/verification-templates.ts +29 -3
  390. package/src/services/published-app-updater.ts +30 -8
  391. package/src/signals/cancel.ts +2 -4
  392. package/src/subagent/manager.ts +21 -5
  393. package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
  394. package/src/telemetry/activation-funnel.ts +167 -0
  395. package/src/telemetry/types.ts +13 -0
  396. package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
  397. package/src/telemetry/usage-telemetry-reporter.ts +26 -1
  398. package/src/tools/acp/context.ts +20 -0
  399. package/src/tools/acp/list-agents.test.ts +9 -19
  400. package/src/tools/acp/list-agents.ts +3 -15
  401. package/src/tools/acp/spawn.test.ts +173 -202
  402. package/src/tools/acp/spawn.ts +37 -172
  403. package/src/tools/acp/steer.test.ts +105 -8
  404. package/src/tools/acp/steer.ts +48 -17
  405. package/src/tools/apps/executors.ts +166 -50
  406. package/src/tools/browser/browser-execution.ts +12 -2
  407. package/src/tools/filesystem/write.ts +34 -0
  408. package/src/tools/network/web-fetch.ts +65 -24
  409. package/src/tools/skills/load.ts +1 -1
  410. package/src/tools/subagent/spawn.ts +2 -4
  411. package/src/tools/ui-surface/definitions.ts +32 -5
  412. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  413. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
  414. package/docs/plugins.md +0 -832
  415. package/examples/plugins/echo/register.ts +0 -143
  416. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  417. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  418. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  419. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
  420. package/src/__tests__/pipeline-runner.test.ts +0 -554
  421. package/src/daemon/wake-target-adapter.ts +0 -253
  422. package/src/memory/v3/__tests__/assign.test.ts +0 -242
  423. package/src/memory/v3/__tests__/capabilities.test.ts +0 -118
  424. package/src/memory/v3/__tests__/core.test.ts +0 -39
  425. package/src/memory/v3/__tests__/health.test.ts +0 -219
  426. package/src/memory/v3/__tests__/maintain-job.test.ts +0 -288
  427. package/src/memory/v3/__tests__/needle.test.ts +0 -107
  428. package/src/memory/v3/__tests__/orchestrate.test.ts +0 -436
  429. package/src/memory/v3/__tests__/provider-blocks.test.ts +0 -13
  430. package/src/memory/v3/__tests__/reconcile.test.ts +0 -274
  431. package/src/memory/v3/__tests__/render-injection.test.ts +0 -61
  432. package/src/memory/v3/__tests__/router.test.ts +0 -332
  433. package/src/memory/v3/__tests__/selector.test.ts +0 -470
  434. package/src/memory/v3/__tests__/shadow-plugin.test.ts +0 -432
  435. package/src/memory/v3/__tests__/snapshot.test.ts +0 -168
  436. package/src/memory/v3/__tests__/tree.test.ts +0 -192
  437. package/src/memory/v3/assign.ts +0 -268
  438. package/src/memory/v3/capabilities.ts +0 -124
  439. package/src/memory/v3/core.ts +0 -26
  440. package/src/memory/v3/health.ts +0 -0
  441. package/src/memory/v3/maintain-job.ts +0 -314
  442. package/src/memory/v3/needle.ts +0 -115
  443. package/src/memory/v3/orchestrate.ts +0 -126
  444. package/src/memory/v3/page-content.ts +0 -34
  445. package/src/memory/v3/provider-blocks.ts +0 -26
  446. package/src/memory/v3/reconcile.ts +0 -523
  447. package/src/memory/v3/router.ts +0 -190
  448. package/src/memory/v3/selection-log-store.ts +0 -84
  449. package/src/memory/v3/selector.ts +0 -226
  450. package/src/memory/v3/shadow-plugin.ts +0 -411
  451. package/src/memory/v3/snapshot.ts +0 -209
  452. package/src/memory/v3/tree.ts +0 -174
  453. package/src/memory/v3/types.ts +0 -59
  454. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  455. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  456. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  457. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  458. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  459. package/src/plugins/defaults/compaction/register.ts +0 -35
  460. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  461. package/src/plugins/defaults/empty-response/register.ts +0 -23
  462. package/src/plugins/defaults/history-repair/register.ts +0 -24
  463. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +0 -216
  464. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  465. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  466. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  467. package/src/plugins/defaults/title-generate/register.ts +0 -35
  468. package/src/plugins/defaults/tool-error/register.ts +0 -23
  469. package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
  470. package/src/proactive-artifact/aux-message-injector.ts +0 -97
  471. package/src/proactive-artifact/decision.test.ts +0 -226
  472. package/src/proactive-artifact/decision.ts +0 -165
  473. package/src/proactive-artifact/index.ts +0 -7
  474. package/src/proactive-artifact/job.test.ts +0 -962
  475. package/src/proactive-artifact/job.ts +0 -372
  476. package/src/proactive-artifact/message-copy.ts +0 -58
  477. package/src/proactive-artifact/trigger-state.test.ts +0 -286
  478. package/src/proactive-artifact/trigger-state.ts +0 -123
  479. package/src/util/map-limit.ts +0 -27
  480. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  481. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  482. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  483. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  484. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  485. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  486. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  487. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  488. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  489. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  490. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
@@ -1,245 +1,226 @@
1
1
  /**
2
- * Tests for the `memory v3` CLI command group's daemon-side handlers.
2
+ * Tests for the `assistant memory v3` CLI subgroup (section-lane model).
3
3
  *
4
- * The CLI subcommands are thin IPC shells over the handlers in
5
- * `runtime/routes/memory-v3-routes.ts`; the logic worth testing lives there.
6
- * We exercise the handlers directly against a temp workspace + data dir
7
- * injected via their `deps` parameter. Generic taxonomy only
8
- * (domain-a/topic-x, etc.).
9
- *
10
- * Source-of-truth note: `health` and `set-core` build the leaf tree from each
11
- * concept page's `leaves:` frontmatter (via the page index) and union it over
12
- * `assignments.json`, matching the consolidation-injected health block. The
13
- * fixture below writes concept pages with `leaves:` frontmatter as the
14
- * authoritative membership and keeps a *stale* `assignments.json` to prove the
15
- * handlers read the frontmatter, not the stale assignments. The seeded
16
- * skill/CLI-command catalogs are mocked empty so `allSlugs` (derived from the
17
- * page index) is deterministic.
4
+ * Validates:
5
+ * - Subcommand registration (rebuild-index, backfill-sections) under
6
+ * `memory v3`.
7
+ * - Each subcommand maps to the right `cliIpcCall` method.
8
+ * - `backfill-sections` passes a long IPC timeout (the one-time full-corpus
9
+ * embed easily outlasts the default 60s), while `rebuild-index` does not.
10
+ * - IPC error paths return a non-zero exit code without throwing.
18
11
  */
19
12
 
20
- import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
21
- import { tmpdir } from "node:os";
22
- import { join } from "node:path";
23
- import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
24
-
25
- import * as cliCommandStore from "../../../memory/v2/cli-command-store.js";
26
- import { invalidatePageIndex } from "../../../memory/v2/page-index.js";
27
- import * as skillStore from "../../../memory/v2/skill-store.js";
28
- import {
29
- handleMemoryV3Health,
30
- handleMemoryV3Reconcile,
31
- handleMemoryV3SetCore,
32
- UnknownLeafError,
33
- } from "../../../runtime/routes/memory-v3-routes.js";
34
-
35
- // ---------------------------------------------------------------------------
36
- // Temp data-dir fixture
37
- // ---------------------------------------------------------------------------
38
-
39
- let workspaceDir: string;
40
- let dataDir: string;
41
-
42
- /** Write a leaf markdown file with the given frontmatter under leaves/. */
43
- async function writeLeaf(
44
- relPath: string,
45
- frontmatter: { path: string; in_core: boolean; id?: string },
46
- body = "description",
47
- ): Promise<void> {
48
- const file = join(dataDir, "leaves", `${relPath}.md`);
49
- await mkdir(join(file, ".."), { recursive: true });
50
- const fm = [
51
- "---",
52
- `path: ${frontmatter.path}`,
53
- `in_core: ${frontmatter.in_core}`,
54
- ...(frontmatter.id ? [`id: ${frontmatter.id}`] : []),
55
- "---",
56
- body,
57
- "",
58
- ].join("\n");
59
- await writeFile(file, fm);
13
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
14
+
15
+ import { Command } from "commander";
16
+
17
+ // ---------------------------------------------------------------------------
18
+ // Mock state
19
+ // ---------------------------------------------------------------------------
20
+
21
+ /** The last `cliIpcCall` invocation captured for assertions. */
22
+ let lastIpcCall: {
23
+ method: string;
24
+
25
+ params?: any;
26
+ options?: { timeoutMs?: number; signal?: AbortSignal };
27
+ } | null = null;
28
+
29
+ /** The result that cliIpcCall will return. */
30
+ let mockIpcResult: {
31
+ ok: boolean;
32
+ result?: unknown;
33
+ error?: string;
34
+ } = { ok: true, result: { articles: 3, sections: 12, failures: 0 } };
35
+
36
+ /** Captured log output for assertion. */
37
+ let logOutput: string[] = [];
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Mocks
41
+ // ---------------------------------------------------------------------------
42
+
43
+ mock.module("../../../ipc/cli-client.js", () => ({
44
+ cliIpcCall: async (
45
+ method: string,
46
+ params?: any,
47
+ options?: { timeoutMs?: number; signal?: AbortSignal },
48
+ ) => {
49
+ lastIpcCall = { method, params, options };
50
+ return mockIpcResult;
51
+ },
52
+ }));
53
+
54
+ const capture = (...args: unknown[]) => {
55
+ logOutput.push(args.map(String).join(" "));
56
+ };
57
+ const fakeLogger = {
58
+ info: capture,
59
+ warn: capture,
60
+ error: capture,
61
+ debug: () => {},
62
+ };
63
+ mock.module("../../../util/logger.js", () => ({
64
+ getLogger: () => fakeLogger,
65
+ getCliLogger: () => fakeLogger,
66
+ }));
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // Import modules under test (after mocks)
70
+ // ---------------------------------------------------------------------------
71
+
72
+ const { registerMemoryV3Command } = await import("../memory-v3.js");
73
+
74
+ // ---------------------------------------------------------------------------
75
+ // Test helpers
76
+ // ---------------------------------------------------------------------------
77
+
78
+ function buildProgram(): Command {
79
+ const program = new Command();
80
+ program.exitOverride();
81
+ program.configureOutput({
82
+ writeErr: () => {},
83
+ writeOut: () => {},
84
+ });
85
+ registerMemoryV3Command(program);
86
+ return program;
60
87
  }
61
88
 
62
- /** Write a concept page with `leaves:` frontmatter under memory/concepts/. */
63
- async function writePage(slug: string, leaves: string[]): Promise<void> {
64
- const file = join(workspaceDir, "memory", "concepts", `${slug}.md`);
65
- await mkdir(join(file, ".."), { recursive: true });
66
- const fm = [
67
- "---",
68
- `summary: ${slug} summary`,
69
- "leaves:",
70
- ...leaves.map((l) => ` - ${l}`),
71
- "---",
72
- `${slug} body`,
73
- "",
74
- ].join("\n");
75
- await writeFile(file, fm);
89
+ async function runCommand(
90
+ args: string[],
91
+ ): Promise<{ stdout: string; exitCode: number }> {
92
+ const originalStdoutWrite = process.stdout.write.bind(process.stdout);
93
+ const originalStderrWrite = process.stderr.write.bind(process.stderr);
94
+ const stdoutChunks: string[] = [];
95
+
96
+ process.stdout.write = ((chunk: unknown) => {
97
+ stdoutChunks.push(typeof chunk === "string" ? chunk : String(chunk));
98
+ return true;
99
+ }) as typeof process.stdout.write;
100
+
101
+ process.stderr.write = (() => true) as typeof process.stderr.write;
102
+
103
+ process.exitCode = 0;
104
+
105
+ try {
106
+ const program = buildProgram();
107
+ await program.parseAsync(["node", "assistant", ...args]);
108
+ } catch {
109
+ if (process.exitCode === 0) process.exitCode = 1;
110
+ } finally {
111
+ process.stdout.write = originalStdoutWrite;
112
+ process.stderr.write = originalStderrWrite;
113
+ }
114
+
115
+ const exitCode = process.exitCode ?? 0;
116
+ process.exitCode = 0;
117
+
118
+ return { exitCode, stdout: stdoutChunks.join("") };
76
119
  }
77
120
 
78
- beforeEach(async () => {
79
- workspaceDir = await mkdtemp(join(tmpdir(), "mem-v3-cli-ws-"));
80
- dataDir = join(workspaceDir, "memory", "v3", "data");
81
- await mkdir(dataDir, { recursive: true });
82
-
83
- // Keep the page index deterministic regardless of the on-disk seeded
84
- // catalogs, and clear any module-cached index from a prior test.
85
- spyOn(skillStore, "listSkillEntries").mockReturnValue([]);
86
- spyOn(cliCommandStore, "listCliCommandEntries").mockReturnValue([]);
87
- invalidatePageIndex();
88
-
89
- // A small generic tree: two leaves under domain-a, one under domain-b.
90
- await writeLeaf("domain-a/topic-x", {
91
- path: "domain-a/topic-x",
92
- in_core: true,
93
- id: "leaf-x",
94
- });
95
- await writeLeaf("domain-a/topic-y", {
96
- path: "domain-a/topic-y",
97
- in_core: false,
98
- id: "leaf-y",
99
- });
100
- await writeLeaf("domain-b/topic-z", {
101
- path: "domain-b/topic-z",
102
- in_core: false,
103
- id: "leaf-z",
104
- });
121
+ // ---------------------------------------------------------------------------
122
+ // Setup
123
+ // ---------------------------------------------------------------------------
105
124
 
106
- // Authoritative membership lives in each page's `leaves:` frontmatter.
107
- await writePage("page-1", ["domain-a/topic-x"]);
108
- await writePage("page-2", ["domain-a/topic-x", "domain-a/topic-y"]);
109
- await writePage("page-3", ["domain-b/topic-z"]);
110
-
111
- // STALE assignments.json: deliberately divergent from the frontmatter above.
112
- // It re-maps the SAME slugs that already carry `leaves:` frontmatter to the
113
- // WRONG leaves. `loadLeafTree`'s per-page precedence only lets frontmatter win
114
- // when it is non-empty, so for these slugs the frontmatter wins and
115
- // assignments.json contributes no membership — proving the handlers read the
116
- // page index, not these stale assignments (the regression Defect A guards
117
- // against). We deliberately avoid a slug that exists ONLY in assignments.json:
118
- // such a slug has no frontmatter, falls back to its assignments entry, and
119
- // would inflate the cost preview below with phantom membership.
120
- await writeFile(
121
- join(dataDir, "assignments.json"),
122
- JSON.stringify({
123
- "page-1": ["domain-a/bogus-leaf"],
124
- "page-2": ["domain-b/topic-z"],
125
- }),
126
- );
127
- await writeFile(
128
- join(dataDir, "core.json"),
129
- JSON.stringify({ alwaysOn: ["domain-a/topic-x"] }),
130
- );
125
+ beforeEach(() => {
126
+ lastIpcCall = null;
127
+ mockIpcResult = {
128
+ ok: true,
129
+ result: { articles: 3, sections: 12, failures: 0 },
130
+ };
131
+ logOutput = [];
132
+ process.exitCode = 0;
131
133
  });
132
134
 
133
- afterEach(async () => {
134
- invalidatePageIndex();
135
- await rm(workspaceDir, { recursive: true, force: true });
135
+ // ---------------------------------------------------------------------------
136
+ // Subcommand registration
137
+ // ---------------------------------------------------------------------------
138
+
139
+ describe("subcommand registration", () => {
140
+ test("registers v3 under memory with the expected subcommands", () => {
141
+ const program = buildProgram();
142
+ const memory = program.commands.find((c) => c.name() === "memory");
143
+ expect(memory).toBeDefined();
144
+ const v3 = memory!.commands.find((c) => c.name() === "v3");
145
+ expect(v3).toBeDefined();
146
+ const subcommandNames = v3!.commands.map((c) => c.name()).sort();
147
+ expect(subcommandNames).toEqual(["backfill-sections", "rebuild-index"]);
148
+ });
136
149
  });
137
150
 
138
151
  // ---------------------------------------------------------------------------
139
- // set-core
152
+ // rebuild-index
140
153
  // ---------------------------------------------------------------------------
141
154
 
142
- describe("handleMemoryV3SetCore", () => {
143
- test("rejects an unknown leaf and does not write", async () => {
144
- const call = handleMemoryV3SetCore(
145
- { add: ["domain-a/does-not-exist"], write: true },
146
- { dataDir, workspaceDir },
147
- );
148
- await expect(call).rejects.toThrow(/domain-a\/does-not-exist/);
149
- await expect(
150
- handleMemoryV3SetCore(
151
- { add: ["domain-a/does-not-exist"], write: true },
152
- { dataDir, workspaceDir },
153
- ),
154
- ).rejects.toBeInstanceOf(UnknownLeafError);
155
+ describe("memory v3 rebuild-index", () => {
156
+ test("sends memory_v3_rebuild_index with the default (no) timeout", async () => {
157
+ mockIpcResult = { ok: true, result: { invalidated: true } };
155
158
 
156
- // core.json must be untouched (still just the original entry).
157
- const core = JSON.parse(await readFile(join(dataDir, "core.json"), "utf8"));
158
- expect(core.alwaysOn).toEqual(["domain-a/topic-x"]);
159
- });
159
+ const { exitCode } = await runCommand(["memory", "v3", "rebuild-index"]);
160
160
 
161
- test("previews the always-on page count from frontmatter membership", async () => {
162
- // Adding topic-y to core: core = {topic-x, topic-y}. Membership comes from
163
- // page `leaves:` frontmatter — topic-x → {page-1, page-2}, topic-y →
164
- // {page-2} ⇒ unique always-on slugs {page-1, page-2} = 2. If the handler
165
- // read the stale assignments.json instead (page-1 → bogus-leaf, page-2 →
166
- // topic-z), topic-x/topic-y would have no members and this would be 0.
167
- const result = await handleMemoryV3SetCore(
168
- { add: ["domain-a/topic-y"] },
169
- { dataDir, workspaceDir },
170
- );
171
- expect(result.written).toBe(false);
172
- expect(result.nextCore).toEqual(["domain-a/topic-x", "domain-a/topic-y"]);
173
- expect(result.alwaysOnPageCount).toBe(2);
174
-
175
- // No write happened — core.json still holds only the original entry.
176
- const core = JSON.parse(await readFile(join(dataDir, "core.json"), "utf8"));
177
- expect(core.alwaysOn).toEqual(["domain-a/topic-x"]);
161
+ expect(exitCode).toBe(0);
162
+ expect(lastIpcCall!.method).toBe("memory_v3_rebuild_index");
163
+ expect(lastIpcCall!.params!.body).toEqual({});
164
+ // rebuild-index is fast; it relies on the default call timeout.
165
+ expect(lastIpcCall!.options).toBeUndefined();
178
166
  });
179
167
 
180
- test("writes core.json on --yes (write: true)", async () => {
181
- const result = await handleMemoryV3SetCore(
182
- { add: ["domain-b/topic-z"], write: true },
183
- { dataDir, workspaceDir },
184
- );
185
- expect(result.written).toBe(true);
186
- expect(result.nextCore).toEqual(["domain-a/topic-x", "domain-b/topic-z"]);
168
+ test("exits with code 1 on IPC failure", async () => {
169
+ mockIpcResult = { ok: false, error: "Daemon down" };
187
170
 
188
- const core = JSON.parse(await readFile(join(dataDir, "core.json"), "utf8"));
189
- expect(core.alwaysOn).toEqual(["domain-a/topic-x", "domain-b/topic-z"]);
190
- });
171
+ const { exitCode } = await runCommand(["memory", "v3", "rebuild-index"]);
191
172
 
192
- test("remove is idempotent for an absent entry", async () => {
193
- const result = await handleMemoryV3SetCore(
194
- { remove: ["domain-a/topic-y"], write: true },
195
- { dataDir, workspaceDir },
196
- );
197
- // topic-y was never in core; result is the original core unchanged.
198
- expect(result.nextCore).toEqual(["domain-a/topic-x"]);
173
+ expect(exitCode).toBe(1);
199
174
  });
200
175
  });
201
176
 
202
177
  // ---------------------------------------------------------------------------
203
- // health
178
+ // backfill-sections
204
179
  // ---------------------------------------------------------------------------
205
180
 
206
- describe("handleMemoryV3Health", () => {
207
- test("computes the slug universe from page frontmatter, not assignments.json", async () => {
208
- const result = await handleMemoryV3Health({ dataDir, workspaceDir });
209
- // domain-b/topic-z has a single member ⇒ a tiny leaf, so the report is
210
- // non-empty and renders the memory-v3 health header.
211
- expect(result.rendered).toContain("memory-v3 health:");
212
- expect(result.counts.tinyLeaves).toBeGreaterThanOrEqual(1);
213
- // Every page leaf ref (from frontmatter) resolves to a real leaf file ⇒ no
214
- // dangling refs. If assignments.json were the source, page-1's bogus-leaf
215
- // would dangle.
216
- expect(result.counts.danglingRefs).toBe(0);
217
- // The slug universe is the page-index pages (page-1..3), all assigned via
218
- // frontmatter, so nothing is unassigned.
219
- expect(result.counts.unassigned).toBe(0);
181
+ describe("memory v3 backfill-sections", () => {
182
+ test("sends memory_v3_backfill_sections with a long (30-min) IPC timeout", async () => {
183
+ mockIpcResult = {
184
+ ok: true,
185
+ result: { articles: 50, sections: 400, failures: 0 },
186
+ };
187
+
188
+ const { exitCode } = await runCommand([
189
+ "memory",
190
+ "v3",
191
+ "backfill-sections",
192
+ ]);
193
+
194
+ expect(exitCode).toBe(0);
195
+ expect(lastIpcCall!.method).toBe("memory_v3_backfill_sections");
196
+ expect(lastIpcCall!.params!.body).toEqual({});
197
+ // The one-time full-corpus embed is long-running, so the CLI must override
198
+ // the default 60s timeout with a generous ceiling (30 min).
199
+ expect(lastIpcCall!.options!.timeoutMs).toBe(30 * 60 * 1000);
220
200
  });
221
201
 
222
- test("flags a page frontmatter ref with no backing leaf as dangling", async () => {
223
- await writePage("page-4", ["domain-a/missing-leaf"]);
224
- invalidatePageIndex();
225
- const result = await handleMemoryV3Health({ dataDir, workspaceDir });
226
- expect(result.counts.danglingRefs).toBeGreaterThanOrEqual(1);
202
+ test("summarizes embedded sections on success", async () => {
203
+ mockIpcResult = {
204
+ ok: true,
205
+ result: { articles: 7, sections: 42, failures: 0 },
206
+ };
207
+
208
+ await runCommand(["memory", "v3", "backfill-sections"]);
209
+
210
+ expect(
211
+ logOutput.some((line) => line.includes("42") && line.includes("7")),
212
+ ).toBe(true);
227
213
  });
228
- });
229
214
 
230
- // ---------------------------------------------------------------------------
231
- // reconcile
232
- // ---------------------------------------------------------------------------
215
+ test("exits with code 1 on IPC failure", async () => {
216
+ mockIpcResult = { ok: false, error: "Memory v3 not enabled" };
217
+
218
+ const { exitCode } = await runCommand([
219
+ "memory",
220
+ "v3",
221
+ "backfill-sections",
222
+ ]);
233
223
 
234
- describe("handleMemoryV3Reconcile", () => {
235
- test("no-op reconcile against an unchanged tree returns empty diffs", async () => {
236
- // v1: prevLeaves is derived from the current tree, so diffing
237
- // current-vs-current yields no renames/deletes — reconcile runs as a
238
- // convergence/prune pass. This still drives the full reconcileTree path
239
- // (snapshot → apply → validate → invalidate).
240
- const result = await handleMemoryV3Reconcile({ dataDir, workspaceDir });
241
- expect(result.renames).toEqual([]);
242
- expect(result.deleted).toEqual([]);
243
- expect(result.prunedCore).toEqual([]);
224
+ expect(exitCode).toBe(1);
244
225
  });
245
226
  });
@@ -79,7 +79,7 @@ export function registerChannelVerificationSessionsCommand(
79
79
  "after",
80
80
  `
81
81
  Verification sessions are used to verify guardian bindings and trusted
82
- contacts across channels (telegram, phone, slack). Three flows exist:
82
+ contacts across channels (telegram, phone, slack, email). Three flows exist:
83
83
 
84
84
  1. Inbound challenge — the assistant generates a secret code and waits
85
85
  for the guardian to send it back on the channel. Used when the
@@ -107,10 +107,10 @@ Examples:
107
107
  cvs
108
108
  .command("create")
109
109
  .description("Create a new verification session")
110
- .option("--channel <channel>", "Channel type (telegram, phone, slack)")
110
+ .option("--channel <channel>", "Channel type (telegram, phone, slack, email)")
111
111
  .option(
112
112
  "--destination <destination>",
113
- "Destination address for outbound verification (handle, phone number, or user ID)",
113
+ "Destination address for outbound verification (handle, phone number, user ID, or email address)",
114
114
  )
115
115
  .option("--rebind", "Replace existing guardian binding")
116
116
  .option(
@@ -140,7 +140,7 @@ Routes between three creation modes based on the provided options:
140
140
 
141
141
  2. Outbound: --channel <ch> --destination <dest>
142
142
  Sends a verification code to the given destination. Supports telegram
143
- (handle or chat ID), phone (E.164 number), and slack (user ID).
143
+ (handle or chat ID), phone (E.164 number), slack (user ID), and email.
144
144
  Use --rebind to replace an existing guardian binding.
145
145
 
146
146
  3. Inbound: --channel <ch> (no --destination)
@@ -240,7 +240,7 @@ Examples:
240
240
  )
241
241
  .requiredOption(
242
242
  "--channel <channel>",
243
- "Channel type (telegram, phone, slack)",
243
+ "Channel type (telegram, phone, slack, email)",
244
244
  )
245
245
  .option(
246
246
  "--origin-conversation-id <id>",
@@ -290,7 +290,7 @@ Examples:
290
290
  .description("Cancel all active verification sessions for a channel")
291
291
  .requiredOption(
292
292
  "--channel <channel>",
293
- "Channel type (telegram, phone, slack)",
293
+ "Channel type (telegram, phone, slack, email)",
294
294
  )
295
295
  .addHelpText(
296
296
  "after",
@@ -507,7 +507,9 @@ describe("assistant db repair — conversation-backfill step", () => {
507
507
  expect(parsed.steps[1].result.data.recovered).toBe(0);
508
508
  expect(parsed.steps[1].result.data.skipped).toBe(1);
509
509
  expect(parsed.steps[1].result.status).toBe("ok");
510
- });
510
+ // Two full repair passes (each walks the DB via integrity-check) exceed
511
+ // bun's 5s per-test default, so raise the ceiling to keep CI stable.
512
+ }, 30_000);
511
513
 
512
514
  test("reports nothing-to-backfill on an empty conversations dir", async () => {
513
515
  await initSchema();