@vellumai/assistant 0.11.3 → 0.11.4-dev.202608190019.b94dbf2

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 (596) hide show
  1. package/AGENTS.md +9 -3
  2. package/ARCHITECTURE.md +32 -10
  3. package/docs/architecture/memory.md +43 -5
  4. package/docs/architecture/security.md +96 -152
  5. package/docs/architecture/turn-actor.md +70 -0
  6. package/docs/browser-use-architecture-phase2.md +128 -56
  7. package/docs/flux-turn-detection-spike.md +248 -0
  8. package/docs/guardian-request-flow.md +35 -0
  9. package/docs/stt-provider-onboarding.md +3 -1
  10. package/knip.json +3 -0
  11. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  12. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  13. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  14. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  15. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  17. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  19. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  20. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  23. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +34 -0
  24. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
  25. package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
  26. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  27. package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  28. package/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
  29. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  30. package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
  31. package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  32. package/openapi.yaml +289 -113
  33. package/package.json +1 -1
  34. package/scripts/voice-ttft-spike.ts +3 -3
  35. package/scripts/write-plugin-api-shim.ts +10 -0
  36. package/src/__tests__/app-compiler.test.ts +38 -3
  37. package/src/__tests__/app-control-flow.test.ts +1 -0
  38. package/src/__tests__/approval-routes-http.test.ts +2 -2
  39. package/src/__tests__/assistant-feature-flag-guard.test.ts +25 -3
  40. package/src/__tests__/attachments-store.test.ts +21 -12
  41. package/src/__tests__/byok-default-profile-ensure.test.ts +17 -0
  42. package/src/__tests__/call-setup-flow-name-capture.test.ts +0 -1
  43. package/src/__tests__/call-site-routing-provider.test.ts +1 -1
  44. package/src/__tests__/channel-availability-routes.test.ts +14 -1
  45. package/src/__tests__/channel-capabilities-dedupe.test.ts +214 -0
  46. package/src/__tests__/channel-delivery-store.test.ts +14 -14
  47. package/src/__tests__/channel-inbound-disk-pressure.test.ts +4 -4
  48. package/src/__tests__/channel-setup-panel-ack.test.ts +1 -1
  49. package/src/__tests__/checker.test.ts +20 -314
  50. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
  51. package/src/__tests__/compaction-events.test.ts +8 -10
  52. package/src/__tests__/config-loader-backfill.test.ts +3 -3
  53. package/src/__tests__/config-schema.test.ts +25 -10
  54. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  55. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +8 -11
  56. package/src/__tests__/conversation-agent-loop-overflow.test.ts +8 -11
  57. package/src/__tests__/conversation-agent-loop.test.ts +32 -21
  58. package/src/__tests__/conversation-attachments.test.ts +0 -1
  59. package/src/__tests__/conversation-attention-store.test.ts +63 -0
  60. package/src/__tests__/conversation-confirmation-signals.test.ts +112 -0
  61. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -4
  62. package/src/__tests__/conversation-fork-crud.test.ts +69 -0
  63. package/src/__tests__/conversation-fork-referential.test.ts +67 -0
  64. package/src/__tests__/conversation-fork-retrospective.test.ts +24 -0
  65. package/src/__tests__/conversation-load-history-repair.test.ts +209 -0
  66. package/src/__tests__/conversation-notifiers-provenance.test.ts +59 -0
  67. package/src/__tests__/conversation-queue.test.ts +154 -4
  68. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
  69. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +1 -1
  70. package/src/__tests__/conversation-routes-guardian-reply.test.ts +9 -9
  71. package/src/__tests__/conversation-routes-hidden-queue.test.ts +1 -1
  72. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -1
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +187 -102
  74. package/src/__tests__/conversation-runtime-workspace.test.ts +14 -10
  75. package/src/__tests__/conversation-slash-queue.test.ts +3 -0
  76. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
  77. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -0
  78. package/src/__tests__/conversation-surfaces-app-control.test.ts +1 -0
  79. package/src/__tests__/conversation-surfaces-app-open.test.ts +1 -1
  80. package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -1
  81. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +21 -14
  82. package/src/__tests__/conversation-surfaces-queued-emit.test.ts +1 -0
  83. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1 -0
  84. package/src/__tests__/conversation-surfaces-standalone.test.ts +1 -0
  85. package/src/__tests__/conversation-surfaces-state-update.test.ts +1 -1
  86. package/src/__tests__/conversation-surfaces-table-action.test.ts +1 -1
  87. package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -1
  88. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
  89. package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
  90. package/src/__tests__/credential-prompt-route.test.ts +7 -10
  91. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  92. package/src/__tests__/cu-unified-flow.test.ts +1 -0
  93. package/src/__tests__/custom-profile-ensure.test.ts +5 -1
  94. package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
  95. package/src/__tests__/discord-access-request-privacy.test.ts +5 -1
  96. package/src/__tests__/discord-requester-notice-privacy.test.ts +3 -3
  97. package/src/__tests__/document-append-idempotency.test.ts +233 -0
  98. package/src/__tests__/document-sync-tags.test.ts +0 -75
  99. package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
  100. package/src/__tests__/edit-propagation.test.ts +107 -11
  101. package/src/__tests__/file-ops-service.test.ts +163 -30
  102. package/src/__tests__/filesystem-tools.test.ts +23 -24
  103. package/src/__tests__/gateway-only-guard.test.ts +2 -5
  104. package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
  105. package/src/__tests__/helpers/mock-actor-context.ts +49 -0
  106. package/src/__tests__/helpers/mock-conversation.ts +13 -1
  107. package/src/__tests__/host-file-read-tool.test.ts +16 -19
  108. package/src/__tests__/http-user-message-parity.test.ts +1 -1
  109. package/src/__tests__/init-feature-flag-overrides.test.ts +49 -0
  110. package/src/__tests__/injector-chain.test.ts +63 -41
  111. package/src/__tests__/injector-disk-pressure.test.ts +11 -23
  112. package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
  113. package/src/__tests__/llm-context-resolution.test.ts +73 -1
  114. package/src/__tests__/llm-schema.test.ts +5 -2
  115. package/src/__tests__/managed-skill-lifecycle.test.ts +7 -0
  116. package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
  117. package/src/__tests__/media-generate-image.test.ts +131 -21
  118. package/src/__tests__/memory-retrieval-hook.test.ts +100 -7
  119. package/src/__tests__/messages-read-boundary-guard.test.ts +134 -0
  120. package/src/__tests__/mtime-cache.test.ts +3 -1
  121. package/src/__tests__/non-member-access-request.test.ts +0 -20
  122. package/src/__tests__/outbound-slack-persistence.test.ts +40 -1
  123. package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
  124. package/src/__tests__/plugin-api-store-credential.test.ts +261 -0
  125. package/src/__tests__/plugin-api-webhook-url.test.ts +10 -7
  126. package/src/__tests__/plugin-disabled-state.test.ts +2 -0
  127. package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
  128. package/src/__tests__/plugin-execution-context.test.ts +73 -0
  129. package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
  130. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +7 -4
  131. package/src/__tests__/plugin-secret-pattern-contribution.test.ts +1 -1
  132. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +14 -7
  133. package/src/__tests__/provider-commit-message-generator.test.ts +20 -0
  134. package/src/__tests__/proxy-approval-callback.test.ts +1 -0
  135. package/src/__tests__/qdrant-manager.test.ts +14 -1
  136. package/src/__tests__/reaction-persistence.test.ts +200 -7
  137. package/src/__tests__/require-fresh-approval.test.ts +0 -4
  138. package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
  139. package/src/__tests__/run-conversation-turn-persistence.test.ts +460 -105
  140. package/src/__tests__/run-due-schedules.test.ts +21 -0
  141. package/src/__tests__/scaffold-managed-skill-tool.test.ts +187 -18
  142. package/src/__tests__/schedule-routes.test.ts +23 -0
  143. package/src/__tests__/schedule-store.test.ts +17 -0
  144. package/src/__tests__/scoped-approval-grants.test.ts +11 -6
  145. package/src/__tests__/secret-ingress-channel.test.ts +0 -1
  146. package/src/__tests__/secret-ingress-http.test.ts +1 -1
  147. package/src/__tests__/send-endpoint-busy.test.ts +3 -3
  148. package/src/__tests__/skills.test.ts +32 -0
  149. package/src/__tests__/slack-edit-ordering-characterization.test.ts +0 -1
  150. package/src/__tests__/starter-task-flow.test.ts +5 -4
  151. package/src/__tests__/subagent-call-site-routing.test.ts +31 -19
  152. package/src/__tests__/subagent-fork-prompt-role.test.ts +1 -1
  153. package/src/__tests__/subagent-spawn-and-await.test.ts +18 -17
  154. package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
  155. package/src/__tests__/subagent-tools.test.ts +81 -101
  156. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +1 -0
  157. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  158. package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
  159. package/src/__tests__/tool-executor.test.ts +68 -39
  160. package/src/__tests__/turn-events-store.test.ts +43 -0
  161. package/src/__tests__/ui-choice-copy-surfaces.test.ts +1 -1
  162. package/src/__tests__/ui-shape-teaching.test.ts +33 -0
  163. package/src/__tests__/ui-visual-surface.test.ts +1 -1
  164. package/src/__tests__/ui-voice-picker-surface.test.ts +128 -0
  165. package/src/__tests__/ui-work-result-surface.test.ts +1 -1
  166. package/src/__tests__/user-plugin-loader.test.ts +3 -1
  167. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  168. package/src/__tests__/visible-app-context.test.ts +16 -9
  169. package/src/__tests__/voice-config-update.test.ts +40 -0
  170. package/src/__tests__/voice-scoped-grant-consumer.test.ts +5 -3
  171. package/src/__tests__/voice-session-bridge.test.ts +85 -29
  172. package/src/__tests__/worker-entrypoint-guards.test.ts +54 -0
  173. package/src/__tests__/worker-plugin-surface.test.ts +77 -0
  174. package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +158 -0
  175. package/src/__tests__/workspace-migration-143-repair-deprecated-codex-model-id.test.ts +133 -0
  176. package/src/__tests__/workspace-migration-144-convert-stranded-subscription-openai-profiles.test.ts +316 -0
  177. package/src/__tests__/workspace-migration-145-collapse-profile-bindings-to-entries.test.ts +325 -0
  178. package/src/__tests__/workspace-migration-146-repair-retired-fireworks-deepseek-flash-model-id.test.ts +235 -0
  179. package/src/acp/__tests__/acp-claude-oauth.test.ts +10 -2
  180. package/src/acp/__tests__/auth-required.test.ts +161 -0
  181. package/src/acp/acp-claude-oauth.ts +19 -2
  182. package/src/acp/agent-process.test.ts +100 -0
  183. package/src/acp/agent-process.ts +29 -26
  184. package/src/acp/auth-required.ts +102 -0
  185. package/src/acp/session-manager.test.ts +119 -0
  186. package/src/acp/session-manager.ts +76 -3
  187. package/src/api/events/acp-auth-required.ts +55 -0
  188. package/src/api/events/host-file.ts +2 -2
  189. package/src/api/index.ts +7 -0
  190. package/src/api/surfaces.ts +12 -3
  191. package/src/apps/app-store.ts +3 -0
  192. package/src/bundler/package-resolver.ts +2 -30
  193. package/src/calls/__tests__/voice-session-bridge.test.ts +194 -11
  194. package/src/calls/__tests__/voice-triage-escalate.test.ts +102 -0
  195. package/src/calls/call-controller.ts +19 -3
  196. package/src/calls/call-setup-flow.ts +0 -1
  197. package/src/calls/media-stream-stt-session.ts +15 -0
  198. package/src/calls/voice-session-bridge.ts +115 -41
  199. package/src/calls/voice-triage-escalate.ts +105 -2
  200. package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
  201. package/src/channels/config.ts +13 -0
  202. package/src/channels/plugin-channel-declarations.ts +108 -0
  203. package/src/channels/types.ts +30 -0
  204. package/src/cli/AGENTS.md +5 -2
  205. package/src/cli/bundled-modules.ts +29 -0
  206. package/src/cli/commands/credentials.help.ts +2 -2
  207. package/src/cli/commands/db/repair.ts +4 -8
  208. package/src/cli/commands/domain.ts +6 -3
  209. package/src/cli/commands/email.ts +6 -3
  210. package/src/cli/commands/inference-providers.ts +1 -1
  211. package/src/cli/commands/keys.ts +8 -3
  212. package/src/cli/commands/mcp.help.ts +13 -4
  213. package/src/cli/commands/mcp.ts +9 -0
  214. package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
  215. package/src/cli/commands/memory/__tests__/memory-v3.test.ts +128 -5
  216. package/src/cli/commands/memory/index.help.ts +84 -28
  217. package/src/cli/commands/memory/index.ts +2 -0
  218. package/src/cli/commands/memory/memory-v2.ts +58 -54
  219. package/src/cli/commands/memory/memory-v3.ts +64 -0
  220. package/src/cli/commands/memory/memory-validate.ts +18 -0
  221. package/src/cli/commands/plugins.ts +85 -36
  222. package/src/cli/commands/schedules.ts +35 -1
  223. package/src/cli/commands/stt.help.ts +27 -2
  224. package/src/cli/commands/trust.ts +3 -14
  225. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +39 -0
  226. package/src/cli/lib/bundled-marketplace.json +14 -1
  227. package/src/cli/lib/upgrade-plugin.ts +42 -0
  228. package/src/config/__tests__/balanced-model-experiment.test.ts +278 -0
  229. package/src/config/__tests__/default-profile-catalog.test.ts +34 -2
  230. package/src/config/__tests__/default-provider.test.ts +6 -1
  231. package/src/config/__tests__/profile-materialization.test.ts +75 -19
  232. package/src/config/assistant-feature-flags.ts +36 -15
  233. package/src/config/balanced-model-experiment.ts +35 -0
  234. package/src/config/bundled-skills/acp/SKILL.md +6 -7
  235. package/src/config/bundled-skills/document-editor/SKILL.md +2 -2
  236. package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
  237. package/src/config/bundled-skills/image-studio/SKILL.md +5 -4
  238. package/src/config/bundled-skills/image-studio/TOOLS.json +1 -1
  239. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +101 -0
  240. package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
  241. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  242. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.test.ts +65 -0
  243. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +7 -1
  244. package/src/config/bundled-skills/settings/tools/shared.ts +16 -0
  245. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -1
  246. package/src/config/bundled-skills/skill-management/TOOLS.json +9 -3
  247. package/src/config/bundled-skills/subagent/SKILL.md +17 -12
  248. package/src/config/bundled-skills/subagent/TOOLS.json +4 -4
  249. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
  250. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
  251. package/src/config/call-site-defaults.ts +11 -5
  252. package/src/config/default-profile-catalog.ts +179 -16
  253. package/src/config/default-profile-names.ts +4 -1
  254. package/src/config/default-provider-resolution.ts +4 -0
  255. package/src/config/feature-flag-registry.json +12 -12
  256. package/src/config/llm-context-resolution.ts +11 -3
  257. package/src/config/llm-resolver.ts +28 -1
  258. package/src/config/profile-materialization.ts +70 -22
  259. package/src/config/schemas/__tests__/live-voice.test.ts +107 -4
  260. package/src/config/schemas/call-site-catalog.ts +4 -4
  261. package/src/config/schemas/live-voice.ts +57 -23
  262. package/src/config/schemas/llm.ts +59 -32
  263. package/src/config/schemas/mcp.ts +23 -0
  264. package/src/config/schemas/plugin-updates.ts +6 -2
  265. package/src/config/schemas/stt.ts +1 -0
  266. package/src/config/skills.ts +9 -2
  267. package/src/context/outbound-sanitize.ts +96 -1
  268. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
  269. package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +82 -0
  270. package/src/daemon/conversation-agent-loop-handlers.ts +15 -10
  271. package/src/daemon/conversation-agent-loop.ts +31 -19
  272. package/src/daemon/conversation-messaging.ts +5 -1
  273. package/src/daemon/conversation-notifiers.ts +20 -10
  274. package/src/daemon/conversation-process.ts +20 -6
  275. package/src/daemon/conversation-runtime-assembly.ts +12 -6
  276. package/src/daemon/conversation-store.ts +14 -4
  277. package/src/daemon/conversation-surfaces.ts +75 -26
  278. package/src/daemon/conversation-tool-setup.ts +3 -6
  279. package/src/daemon/conversation.ts +154 -51
  280. package/src/daemon/doordash-steps.ts +2 -2
  281. package/src/daemon/lifecycle.ts +14 -1
  282. package/src/daemon/mcp-reload-service.ts +36 -6
  283. package/src/daemon/process-message.ts +13 -26
  284. package/src/daemon/providers-setup.ts +6 -3
  285. package/src/daemon/trust-context-types.ts +29 -0
  286. package/src/daemon/trust-context.ts +12 -7
  287. package/src/daemon/wake-conversation-ops.ts +3 -2
  288. package/src/daemon/windows-compiled-entry.ts +4 -0
  289. package/src/documents/document-store.ts +143 -240
  290. package/src/hooks/hook-loader.ts +3 -3
  291. package/src/hooks/registry.ts +103 -45
  292. package/src/hooks/types.ts +5 -0
  293. package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
  294. package/src/inbound/oauth-callback-url.ts +61 -0
  295. package/src/ipc/gateway-client.test.ts +1 -1
  296. package/src/ipc/gateway-client.ts +14 -21
  297. package/src/ipc/gateway-flag-listener.ts +17 -3
  298. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
  299. package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
  300. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +1050 -0
  301. package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
  302. package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
  303. package/src/live-voice/__tests__/live-voice-progress.test.ts +60 -194
  304. package/src/live-voice/__tests__/live-voice-stt.test.ts +14 -0
  305. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +29 -0
  306. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
  307. package/src/live-voice/__tests__/live-voice-vad.test.ts +0 -16
  308. package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
  309. package/src/live-voice/live-voice-archive.ts +2 -0
  310. package/src/live-voice/live-voice-manager.ts +16 -3
  311. package/src/live-voice/live-voice-metrics.ts +57 -32
  312. package/src/live-voice/live-voice-photo.ts +1 -2
  313. package/src/live-voice/live-voice-session.ts +598 -323
  314. package/src/live-voice/progress-narration.ts +277 -0
  315. package/src/live-voice/protocol.ts +21 -1
  316. package/src/live-voice/windows-compiled-live-voice.ts +4 -0
  317. package/src/mcp/__tests__/effective-config.test.ts +238 -0
  318. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
  319. package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +200 -0
  320. package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
  321. package/src/mcp/__tests__/plugin-server-credential-isolation.test.ts +95 -0
  322. package/src/mcp/client.ts +16 -11
  323. package/src/mcp/effective-config.ts +113 -0
  324. package/src/mcp/manager.ts +11 -6
  325. package/src/mcp/mcp-auth-orchestrator.ts +13 -22
  326. package/src/mcp/mcp-oauth-provider.ts +205 -240
  327. package/src/monitoring/__tests__/plugin-auto-update.test.ts +166 -3
  328. package/src/monitoring/control.ts +1 -0
  329. package/src/monitoring/db-integrity-sample.ts +4 -5
  330. package/src/monitoring/plugin-auto-update.ts +128 -24
  331. package/src/notifications/AGENTS.md +2 -0
  332. package/src/notifications/approval-card-data.ts +33 -0
  333. package/src/notifications/signal.ts +1 -0
  334. package/src/permissions/AGENTS.md +16 -0
  335. package/src/permissions/checker.test.ts +75 -122
  336. package/src/permissions/checker.ts +44 -560
  337. package/src/permissions/confirmation-guardian-request.test.ts +15 -11
  338. package/src/permissions/confirmation-guardian-request.ts +2 -2
  339. package/src/permissions/prompter.ts +1 -5
  340. package/src/permissions/question-guardian-request.test.ts +14 -6
  341. package/src/permissions/question-guardian-request.ts +1 -2
  342. package/src/persistence/attachments-store.ts +8 -1
  343. package/src/persistence/bookmark-crud.ts +3 -7
  344. package/src/persistence/conversation-attention-store.ts +16 -45
  345. package/src/persistence/conversation-crud.ts +33 -4
  346. package/src/persistence/conversation-lineage.ts +9 -0
  347. package/src/persistence/conversation-queries.ts +182 -52
  348. package/src/persistence/delivery-crud.ts +150 -36
  349. package/src/persistence/embeddings/qdrant-manager.ts +84 -49
  350. package/src/persistence/external-conversation-store.ts +32 -4
  351. package/src/persistence/llm-request-log-store.ts +4 -10
  352. package/src/persistence/llm-usage-store.ts +8 -3
  353. package/src/persistence/message-reads.test.ts +197 -0
  354. package/src/persistence/message-reads.ts +211 -0
  355. package/src/persistence/migrations/360-add-document-workspace-path.ts +5 -14
  356. package/src/persistence/migrations/366-chatgpt-subscription-row-identity.test.ts +120 -0
  357. package/src/persistence/migrations/366-chatgpt-subscription-row-identity.ts +62 -0
  358. package/src/persistence/real-user-turn-filter.ts +27 -3
  359. package/src/persistence/schema/documents.ts +4 -4
  360. package/src/persistence/steps.ts +9 -0
  361. package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
  362. package/src/plugin-api/constants.ts +8 -0
  363. package/src/plugin-api/conversation-turn.ts +195 -5
  364. package/src/plugin-api/index.ts +38 -6
  365. package/src/plugin-api/resolve-credential.ts +3 -2
  366. package/src/plugin-api/store-credential.ts +146 -0
  367. package/src/plugin-api/vision-support.test.ts +1 -1
  368. package/src/plugin-api/webhook-url.ts +13 -11
  369. package/src/plugins/__tests__/mcp-servers.test.ts +371 -0
  370. package/src/plugins/defaults/main.ts +21 -7
  371. package/src/plugins/defaults/memory/AGENTS.md +15 -3
  372. package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +204 -0
  373. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +72 -0
  374. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +4 -1
  375. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +4 -1
  376. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
  377. package/src/plugins/defaults/memory/buffer-format.ts +165 -0
  378. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +6 -0
  379. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +77 -0
  380. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +24 -6
  381. package/src/plugins/defaults/memory/graph/image-ref-utils.ts +3 -0
  382. package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -30
  383. package/src/plugins/defaults/memory/graph-topology/pending-buffer.test.ts +34 -0
  384. package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +17 -24
  385. package/src/plugins/defaults/memory/hooks/post-compact.ts +1 -4
  386. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +53 -5
  387. package/src/plugins/defaults/memory/indexer.ts +3 -1
  388. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +19 -7
  389. package/src/plugins/defaults/memory/memory-retrospective-job.ts +4 -4
  390. package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +281 -0
  391. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
  392. package/src/plugins/defaults/memory/src/memory-v3-routes.ts +207 -0
  393. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +147 -0
  394. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
  395. package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
  396. package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
  397. package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
  398. package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
  399. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
  400. package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +195 -58
  401. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +93 -24
  402. package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
  403. package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
  404. package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
  405. package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
  406. package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
  407. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
  408. package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
  409. package/src/plugins/defaults/memory/substrate/static-context.ts +160 -33
  410. package/src/plugins/defaults/memory/substrate/sweep-job.ts +2 -4
  411. package/src/plugins/defaults/memory/v1/graph/extraction.ts +3 -1
  412. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +18 -0
  413. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +66 -1
  414. package/src/plugins/defaults/memory/v3/card.ts +9 -9
  415. package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
  416. package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
  417. package/src/plugins/defaults/memory/v3/edge.ts +13 -57
  418. package/src/plugins/defaults/memory/v3/injector.ts +8 -0
  419. package/src/plugins/defaults/memory/v3/prune.ts +2 -0
  420. package/src/plugins/defaults/memory/v3/selection-log-store.ts +2 -0
  421. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +23 -9
  422. package/src/plugins/defaults/memory/worker-control.ts +1 -0
  423. package/src/plugins/defaults/memory/worker.ts +6 -3
  424. package/src/plugins/defaults/worker-entrypoints.ts +3 -0
  425. package/src/plugins/external-plugin-loader.ts +47 -0
  426. package/src/plugins/mcp-servers.ts +361 -0
  427. package/src/plugins/mtime-cache.ts +37 -46
  428. package/src/plugins/pipeline.ts +14 -7
  429. package/src/plugins/plugin-execution-context.ts +35 -11
  430. package/src/plugins/worker-plugin-surface.ts +33 -0
  431. package/src/prompts/templates/system-sections.ts +0 -7
  432. package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
  433. package/src/providers/__tests__/context-overflow-error.test.ts +24 -0
  434. package/src/providers/__tests__/dispatch-connection-routing.test.ts +214 -2
  435. package/src/providers/__tests__/preflight-resolved-config.test.ts +57 -0
  436. package/src/providers/__tests__/retry-callsite.test.ts +25 -2
  437. package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
  438. package/src/providers/anthropic/client.ts +332 -241
  439. package/src/providers/call-site-routing.ts +30 -3
  440. package/src/providers/connection-resolution.ts +194 -11
  441. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +4 -0
  442. package/src/providers/inference/adapter-factory.ts +3 -0
  443. package/src/providers/inference/auth.ts +6 -0
  444. package/src/providers/inference/connection-availability.ts +24 -2
  445. package/src/providers/inference/connections.ts +2 -0
  446. package/src/providers/model-catalog.ts +3 -3
  447. package/src/providers/model-intents.ts +28 -8
  448. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +163 -40
  449. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
  450. package/src/providers/openai/chat-completions-provider.ts +133 -36
  451. package/src/providers/openai/codex-models.ts +2 -1
  452. package/src/providers/provider-send-message.ts +32 -3
  453. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
  454. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +625 -0
  455. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
  456. package/src/providers/speech-to-text/__tests__/resolve.test.ts +285 -6
  457. package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
  458. package/src/providers/speech-to-text/deepgram-flux-realtime.ts +679 -0
  459. package/src/providers/speech-to-text/provider-catalog.ts +99 -8
  460. package/src/providers/speech-to-text/resolve.ts +25 -2
  461. package/src/routes/control.ts +1 -0
  462. package/src/routes/route-host-client.ts +1 -0
  463. package/src/routes/route-host-protocol.ts +7 -0
  464. package/src/routes/worker.ts +48 -15
  465. package/src/runtime/AGENTS.md +16 -17
  466. package/src/runtime/access-request-helper.ts +9 -12
  467. package/src/runtime/agent-wake.ts +18 -15
  468. package/src/runtime/effective-capabilities.test.ts +43 -0
  469. package/src/runtime/effective-capabilities.ts +27 -0
  470. package/src/runtime/guardian-reply-router.ts +6 -2
  471. package/src/runtime/pre-first-message-gate.ts +4 -0
  472. package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +12 -4
  473. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +522 -2
  474. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +52 -0
  475. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +61 -0
  476. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +44 -0
  477. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +102 -1
  478. package/src/runtime/routes/__tests__/plugins-routes.test.ts +132 -35
  479. package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +215 -0
  480. package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
  481. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
  482. package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
  483. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +133 -1
  484. package/src/runtime/routes/channel-availability-routes.ts +32 -14
  485. package/src/runtime/routes/channel-route-shared.ts +0 -6
  486. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +6 -6
  487. package/src/runtime/routes/conversation-list-routes.ts +181 -23
  488. package/src/runtime/routes/conversation-management-routes.ts +17 -12
  489. package/src/runtime/routes/conversation-query-routes.ts +40 -27
  490. package/src/runtime/routes/conversation-routes.ts +43 -29
  491. package/src/runtime/routes/credential-prompt-routes.ts +4 -7
  492. package/src/runtime/routes/credential-routes.ts +26 -82
  493. package/src/runtime/routes/default-provider-routes.ts +15 -0
  494. package/src/runtime/routes/documents-routes.ts +3 -222
  495. package/src/runtime/routes/inbound-message-handler.ts +21 -45
  496. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +0 -1
  497. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -9
  498. package/src/runtime/routes/inbound-stages/admission-policy.ts +1 -17
  499. package/src/runtime/routes/inbound-stages/bootstrap-intercept.test.ts +0 -1
  500. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -3
  501. package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -79
  502. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +0 -1
  503. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +12 -7
  504. package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -8
  505. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -79
  506. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +2 -3
  507. package/src/runtime/routes/inference-profiles-routes.ts +20 -11
  508. package/src/runtime/routes/inference-provider-connection-routes.ts +77 -15
  509. package/src/runtime/routes/log-export-routes.ts +3 -0
  510. package/src/runtime/routes/mcp-auth-routes.ts +148 -57
  511. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +2 -0
  512. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +3 -0
  513. package/src/runtime/routes/playground/inject-failures.ts +2 -2
  514. package/src/runtime/routes/playground/reset-circuit.ts +1 -1
  515. package/src/runtime/routes/plugins-routes.ts +38 -8
  516. package/src/runtime/routes/schedule-routes.ts +94 -7
  517. package/src/runtime/routes/settings-routes.ts +6 -6
  518. package/src/runtime/routes/stt-routes.ts +31 -25
  519. package/src/runtime/routes/surface-action-routes.ts +20 -19
  520. package/src/runtime/routes/surface-conversation-resolver.ts +3 -0
  521. package/src/runtime/routes/user-route-dispatcher.ts +69 -15
  522. package/src/runtime/routes/user-route-import.ts +108 -0
  523. package/src/runtime/routes/user-route-resolution.ts +18 -1
  524. package/src/runtime/routes/workspace-routes.ts +0 -9
  525. package/src/runtime/routes/workspace-utils.ts +3 -13
  526. package/src/runtime/services/conversation-serializer.ts +7 -2
  527. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +68 -5
  528. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +81 -0
  529. package/src/schedule/plugin-schedule-availability.ts +58 -0
  530. package/src/schedule/plugin-schedule-declarations.ts +23 -27
  531. package/src/schedule/plugin-schedule-reconciler.ts +12 -3
  532. package/src/schedule/schedule-store.ts +5 -1
  533. package/src/schedule/scheduler.ts +9 -4
  534. package/src/schedule/worker-control.ts +1 -0
  535. package/src/schedule/worker.ts +6 -0
  536. package/src/security/oauth2.ts +6 -22
  537. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
  538. package/src/stt/__tests__/types.test.ts +94 -0
  539. package/src/stt/daemon-batch-transcriber.ts +10 -0
  540. package/src/stt/stt-stream-session.ts +8 -4
  541. package/src/stt/types.ts +103 -0
  542. package/src/subagent/__tests__/consult-prompt.test.ts +26 -15
  543. package/src/subagent/consult-context.ts +11 -11
  544. package/src/subagent/consult-prompt.ts +26 -35
  545. package/src/subagent/manager.ts +21 -40
  546. package/src/subagent/notify.ts +7 -1
  547. package/src/subagent/types.ts +15 -12
  548. package/src/tools/__tests__/tool-input-schemas.test.ts +7 -7
  549. package/src/tools/acp/spawn.test.ts +97 -0
  550. package/src/tools/acp/spawn.ts +38 -4
  551. package/src/tools/credentials/ref-parse.ts +35 -0
  552. package/src/tools/credentials/resolve.ts +4 -10
  553. package/src/tools/credentials/store.ts +168 -0
  554. package/src/tools/document/document-tool.ts +12 -3
  555. package/src/tools/executor.ts +53 -15
  556. package/src/tools/filesystem/read.ts +27 -10
  557. package/src/tools/host-filesystem/read.ts +27 -15
  558. package/src/tools/network/url-safety.ts +9 -16
  559. package/src/tools/permission-checker.ts +43 -52
  560. package/src/tools/registry.ts +2 -1
  561. package/src/tools/shared/filesystem/file-ops-service.ts +63 -35
  562. package/src/tools/shared/filesystem/legacy-read-args.ts +22 -0
  563. package/src/tools/shared/filesystem/types.ts +5 -5
  564. package/src/tools/skills/scaffold-managed.ts +25 -7
  565. package/src/tools/subagent/spawn.ts +28 -88
  566. package/src/tools/tool-types.ts +26 -13
  567. package/src/tools/types.ts +6 -6
  568. package/src/tools/ui-surface/surface-shape-docs.ts +12 -1
  569. package/src/tools/workflows/run-workflow.ts +1 -2
  570. package/src/tts/__tests__/reasoning-tag-filter.test.ts +78 -0
  571. package/src/tts/reasoning-tag-filter.ts +89 -0
  572. package/src/util/__tests__/worker-process-command.test.ts +37 -0
  573. package/src/util/logger.ts +16 -0
  574. package/src/util/think-tag-stream.ts +95 -0
  575. package/src/util/worker-process.ts +37 -4
  576. package/src/windows-compiled-cli.ts +32 -0
  577. package/src/windows-compiled-entry.ts +4 -0
  578. package/src/windows-compiled-logger.ts +6 -0
  579. package/src/windows-compiled-worker-entry.ts +29 -0
  580. package/src/workspace/byok-default-profile-ensure.ts +76 -24
  581. package/src/workspace/custom-profile-ensure.ts +4 -24
  582. package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
  583. package/src/workspace/migrations/143-repair-deprecated-codex-model-id.ts +134 -0
  584. package/src/workspace/migrations/144-convert-stranded-subscription-openai-profiles.ts +265 -0
  585. package/src/workspace/migrations/145-collapse-profile-bindings-to-entries.ts +328 -0
  586. package/src/workspace/migrations/146-repair-retired-fireworks-deepseek-flash-model-id.ts +195 -0
  587. package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +0 -10
  588. package/src/workspace/migrations/registry.ts +10 -0
  589. package/src/workspace/provider-commit-message-generator.ts +7 -5
  590. package/src/__tests__/document-workspace-file.test.ts +0 -467
  591. package/src/live-voice/__tests__/front-decision.test.ts +0 -645
  592. package/src/live-voice/front-decision.ts +0 -476
  593. package/src/permissions/ipc-risk-types.ts +0 -143
  594. package/src/permissions/risk-types.ts +0 -76
  595. package/src/subagent/__tests__/consult-transcript.test.ts +0 -184
  596. package/src/subagent/consult-transcript.ts +0 -90
@@ -69,6 +69,7 @@ mock.module("../../../../util/logger.js", () => ({
69
69
  // ---------------------------------------------------------------------------
70
70
 
71
71
  const { registerMemoryV2Command } = await import("../memory-v2.js");
72
+ const { registerMemoryValidateCommand } = await import("../memory-validate.js");
72
73
 
73
74
  // ---------------------------------------------------------------------------
74
75
  // Test helpers
@@ -88,6 +89,7 @@ function buildProgram(): Command {
88
89
  const memory = program.command("memory");
89
90
  applyCommandHelp(memory, memoryHelp);
90
91
  registerMemoryV2Command(memory);
92
+ registerMemoryValidateCommand(memory);
91
93
  return program;
92
94
  }
93
95
 
@@ -287,7 +289,7 @@ describe("memory v2 validate", () => {
287
289
  result: {
288
290
  pageCount: 0,
289
291
  edgeCount: 0,
290
- missingEdgeEndpoints: [],
292
+ danglingLinks: [],
291
293
  oversizedPages: [],
292
294
  parseFailures: [],
293
295
  },
@@ -306,7 +308,7 @@ describe("memory v2 validate", () => {
306
308
  result: {
307
309
  pageCount: 49,
308
310
  edgeCount: 166,
309
- missingEdgeEndpoints: [],
311
+ danglingLinks: [],
310
312
  oversizedPages: [],
311
313
  parseFailures: [],
312
314
  },
@@ -318,7 +320,7 @@ describe("memory v2 validate", () => {
318
320
  expect(logOutput.some((line) => line.includes("Pages: 49"))).toBe(true);
319
321
  expect(logOutput.some((line) => line.includes("Edges: 166"))).toBe(true);
320
322
  expect(
321
- logOutput.some((line) => line.includes("Missing edge endpoints: none")),
323
+ logOutput.some((line) => line.includes("Dangling links: none")),
322
324
  ).toBe(true);
323
325
  expect(
324
326
  logOutput.some((line) => line.includes("Oversized pages: none")),
@@ -334,7 +336,9 @@ describe("memory v2 validate", () => {
334
336
  result: {
335
337
  pageCount: 10,
336
338
  edgeCount: 20,
337
- missingEdgeEndpoints: [{ from: "people/alice", to: "people/missing" }],
339
+ danglingLinks: [
340
+ { from: "people/alice", to: "people/missing", kind: "links" },
341
+ ],
338
342
  oversizedPages: [{ slug: "arcs/big-day", chars: 12345 }],
339
343
  parseFailures: [
340
344
  { slug: "people/broken", error: "missing frontmatter" },
@@ -345,9 +349,11 @@ describe("memory v2 validate", () => {
345
349
  const { exitCode } = await runCommand(["memory", "v2", "validate"]);
346
350
 
347
351
  expect(exitCode).toBe(1);
348
- expect(logOutput.some((line) => line.includes("people/missing"))).toBe(
349
- true,
350
- );
352
+ expect(
353
+ logOutput.some((line) =>
354
+ line.includes("people/alice → people/missing (links)"),
355
+ ),
356
+ ).toBe(true);
351
357
  expect(logOutput.some((line) => line.includes("arcs/big-day"))).toBe(true);
352
358
  expect(logOutput.some((line) => line.includes("people/broken"))).toBe(true);
353
359
  });
@@ -360,3 +366,47 @@ describe("memory v2 validate", () => {
360
366
  expect(exitCode).toBe(1);
361
367
  });
362
368
  });
369
+
370
+ describe("memory validate (top-level, same report)", () => {
371
+ test("sends memory_v2_validate and prints the report", async () => {
372
+ mockIpcResult = {
373
+ ok: true,
374
+ result: {
375
+ pageCount: 49,
376
+ edgeCount: 166,
377
+ danglingLinks: [],
378
+ oversizedPages: [],
379
+ parseFailures: [],
380
+ },
381
+ };
382
+
383
+ const { exitCode } = await runCommand(["memory", "validate"]);
384
+
385
+ expect(exitCode).toBe(0);
386
+ expect(lastIpcCall!.method).toBe("memory_v2_validate");
387
+ expect(logOutput.some((line) => line.includes("Pages: 49"))).toBe(true);
388
+ expect(
389
+ logOutput.some((line) => line.includes("Dangling links: none")),
390
+ ).toBe(true);
391
+ });
392
+
393
+ test("exits non-zero on violations, like the v2 spelling", async () => {
394
+ mockIpcResult = {
395
+ ok: true,
396
+ result: {
397
+ pageCount: 1,
398
+ edgeCount: 0,
399
+ danglingLinks: [{ from: "a", to: "missing", kind: "wikilink" }],
400
+ oversizedPages: [],
401
+ parseFailures: [],
402
+ },
403
+ };
404
+
405
+ const { exitCode } = await runCommand(["memory", "validate"]);
406
+
407
+ expect(exitCode).toBe(1);
408
+ expect(
409
+ logOutput.some((line) => line.includes("a → missing (wikilink)")),
410
+ ).toBe(true);
411
+ });
412
+ });
@@ -2,12 +2,13 @@
2
2
  * Tests for the `assistant memory v3` CLI subgroup (section-lane model).
3
3
  *
4
4
  * Validates:
5
- * - Subcommand registration (rebuild-index, backfill-sections) under
6
- * `memory v3`.
7
- * - Each subcommand maps to the right `cliIpcCall` method.
5
+ * - Subcommand registration (rebuild-index, backfill-sections, gate-stats)
6
+ * under `memory v3`.
7
+ * - `rebuild-index` and `backfill-sections` route through IPC to the daemon.
8
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.
9
+ * embed easily outlasts the default 60s).
10
+ * - `gate-stats` calls handleMemoryV3GateStats directly — no daemon required.
11
+ * - Error paths return a non-zero exit code without throwing.
11
12
  */
12
13
 
13
14
  import { beforeEach, describe, expect, mock, test } from "bun:test";
@@ -39,6 +40,47 @@ let mockIpcResult: {
39
40
  /** Captured log output for assertion. */
40
41
  let logOutput: string[] = [];
41
42
 
43
+ /** Shared fake gate-stats payload used across gate-stats tests. */
44
+ const fakeGateStats = {
45
+ lookbackDays: 30,
46
+ totalRuns: 10,
47
+ buckets: [
48
+ {
49
+ pageCountRange: "0–9",
50
+ total: 2,
51
+ scored: 1,
52
+ passed: 2,
53
+ scoredPassRate: 1,
54
+ reasons: { dense_pass: 1, dense_disabled: 1 },
55
+ },
56
+ {
57
+ pageCountRange: "10–49",
58
+ total: 5,
59
+ scored: 4,
60
+ passed: 3,
61
+ scoredPassRate: 0.75,
62
+ reasons: { dense_pass: 3, fail_no_signal: 1 },
63
+ },
64
+ {
65
+ pageCountRange: "50–199",
66
+ total: 2,
67
+ scored: 2,
68
+ passed: 1,
69
+ scoredPassRate: 0.5,
70
+ reasons: { dense_pass: 1, fail_no_signal: 1 },
71
+ },
72
+ {
73
+ pageCountRange: "200+",
74
+ total: 1,
75
+ scored: 1,
76
+ passed: 0,
77
+ scoredPassRate: 0,
78
+ reasons: { fail_no_signal: 1 },
79
+ },
80
+ ],
81
+ unknownPageCount: { total: 0, passed: 0, reasons: {} },
82
+ };
83
+
42
84
  // ---------------------------------------------------------------------------
43
85
  // Mocks
44
86
  // ---------------------------------------------------------------------------
@@ -68,6 +110,33 @@ mock.module("../../../../util/logger.js", () => ({
68
110
  getCliLogger: () => fakeLogger,
69
111
  }));
70
112
 
113
+ // ---------------------------------------------------------------------------
114
+ // gate-stats direct-invocation mocks
115
+ // ---------------------------------------------------------------------------
116
+
117
+ /** Args captured from the last handleMemoryV3GateStats call. */
118
+ let lastGateStatsArgs: { lookbackDays: number; db: unknown } | null = null;
119
+
120
+ /** What handleMemoryV3GateStats returns, or an error to throw. */
121
+ let gateStatsImpl: (() => unknown) | null = null;
122
+
123
+ mock.module(
124
+ "../../../../plugins/defaults/memory/src/memory-v3-routes.js",
125
+ () => ({
126
+ handleMemoryV3GateStats: (lookbackDays: number, db: unknown) => {
127
+ lastGateStatsArgs = { lookbackDays, db };
128
+ if (gateStatsImpl) {
129
+ return gateStatsImpl();
130
+ }
131
+ return fakeGateStats;
132
+ },
133
+ }),
134
+ );
135
+
136
+ mock.module("../../../../persistence/db-connection.js", () => ({
137
+ getTelemetrySqlite: () => ({}),
138
+ }));
139
+
71
140
  // ---------------------------------------------------------------------------
72
141
  // Import modules under test (after mocks)
73
142
  // ---------------------------------------------------------------------------
@@ -135,6 +204,8 @@ beforeEach(() => {
135
204
  ok: true,
136
205
  result: { articles: 3, sections: 12, failures: 0 },
137
206
  };
207
+ lastGateStatsArgs = null;
208
+ gateStatsImpl = null;
138
209
  logOutput = [];
139
210
  process.exitCode = 0;
140
211
  });
@@ -155,6 +226,7 @@ describe("subcommand registration", () => {
155
226
  "backfill-sections",
156
227
  "eval",
157
228
  "eval-tally",
229
+ "gate-stats",
158
230
  "rebuild-index",
159
231
  ]);
160
232
  });
@@ -236,3 +308,54 @@ describe("memory v3 backfill-sections", () => {
236
308
  expect(exitCode).toBe(1);
237
309
  });
238
310
  });
311
+
312
+ // ---------------------------------------------------------------------------
313
+ // gate-stats (direct invocation — no daemon required)
314
+ // ---------------------------------------------------------------------------
315
+
316
+ describe("memory v3 gate-stats", () => {
317
+ test("calls handleMemoryV3GateStats directly with default lookback (no IPC)", async () => {
318
+ const { exitCode } = await runCommand(["memory", "v3", "gate-stats"]);
319
+
320
+ expect(exitCode).toBe(0);
321
+ // Must NOT have gone through IPC.
322
+ expect(lastIpcCall).toBeNull();
323
+ // Must have called the handler directly with the default lookback.
324
+ expect(lastGateStatsArgs!.lookbackDays).toBe(30);
325
+ });
326
+
327
+ test("forwards --lookback-days directly to handleMemoryV3GateStats", async () => {
328
+ await runCommand(["memory", "v3", "gate-stats", "--lookback-days", "7"]);
329
+
330
+ expect(lastIpcCall).toBeNull();
331
+ expect(lastGateStatsArgs!.lookbackDays).toBe(7);
332
+ });
333
+
334
+ test("prints formatted table on success (no --json)", async () => {
335
+ await runCommand(["memory", "v3", "gate-stats"]);
336
+
337
+ expect(logOutput.some((l) => l.includes("Gate-stats"))).toBe(true);
338
+ expect(logOutput.some((l) => l.includes("10–49"))).toBe(true);
339
+ expect(logOutput.some((l) => l.includes("75.0%"))).toBe(true);
340
+ });
341
+
342
+ test("emits raw JSON with --json", async () => {
343
+ await runCommand(["memory", "v3", "gate-stats", "--json"]);
344
+
345
+ const raw = logOutput.join("");
346
+ const parsed = JSON.parse(raw) as typeof fakeGateStats;
347
+ expect(parsed.totalRuns).toBe(10);
348
+ expect(parsed.buckets).toHaveLength(4);
349
+ });
350
+
351
+ test("exits with code 1 when handleMemoryV3GateStats throws", async () => {
352
+ gateStatsImpl = () => {
353
+ throw new Error("telemetry DB locked");
354
+ };
355
+
356
+ const { exitCode } = await runCommand(["memory", "v3", "gate-stats"]);
357
+
358
+ expect(exitCode).toBe(1);
359
+ expect(logOutput.some((l) => l.includes("telemetry DB locked"))).toBe(true);
360
+ });
361
+ });
@@ -23,7 +23,7 @@ The 'items' subgroup exposes full CRUD over individual memory items
23
23
 
24
24
  The memory subsystem retrieves concept pages two ways: the v2 concept-page
25
25
  activation model (prose pages with directed edges) and the v3 section-lane
26
- model (section-grain lanes cached as live shadow state). Each subgroup exposes
26
+ model (section-grain lanes held in memory inside the assistant). Each subgroup exposes
27
27
  operator-facing maintenance verbs — reindexing, backfills, validation, and evals.
28
28
 
29
29
  Examples:
@@ -34,7 +34,7 @@ Examples:
34
34
  $ assistant memory items list --search "coffee"
35
35
  $ assistant memory items update 9f2c4f3a-3f1a-41e4-88e7-abc123 --statement "Prefers tea"
36
36
  $ assistant memory items delete 9f2c4f3a-3f1a-41e4-88e7-abc123
37
- $ assistant memory v2 validate
37
+ $ assistant memory validate
38
38
  $ assistant memory v3 rebuild-index
39
39
  $ assistant memory ingest --dir .mv3/staging --dry-run`,
40
40
  subcommands: [
@@ -43,8 +43,9 @@ Examples:
43
43
  description:
44
44
  "Content-based list, delete, and update of memory graph nodes",
45
45
  helpText: `
46
- Memory nodes are raw graph records (content, type, fidelity) produced by the
47
- memory v2 subsystem. Unlike 'memory items', which addresses nodes by UUID, these
46
+ Memory nodes are raw graph records (content, type, fidelity) in the memory
47
+ graph store, which every memory tier writes to. Unlike 'memory items', which
48
+ addresses nodes by UUID, these
48
49
  commands address nodes by content text — matching the way an operator refers to
49
50
  a remembered fact without first looking up its ID.
50
51
 
@@ -390,7 +391,6 @@ except reembed-skills which runs synchronously inside the assistant.
390
391
  Read-only subcommands print diagnostic reports without mutating state.
391
392
 
392
393
  Examples:
393
- $ assistant memory v2 validate
394
394
  $ assistant memory v2 reembed
395
395
  $ assistant memory v2 reembed-skills
396
396
  $ assistant memory v2 activation`,
@@ -400,9 +400,10 @@ Examples:
400
400
  description:
401
401
  "Refresh dense + sparse vectors for every concept page in Qdrant",
402
402
  helpText: `
403
- Fans out an embed_concept_page job per concept page slug (plus the four
404
- reserved meta-file slugs) so each page's dense and sparse vectors get
405
- recomputed against the current embedding backend. Useful after upgrading
403
+ Fans out an embed_concept_page job per concept page slug so each page's
404
+ dense and sparse vectors get recomputed against the current embedding
405
+ backend (the direct-injected memory/*.md meta files are not embedded and are
406
+ not enqueued). Useful after upgrading
406
407
  the embedding model or recovering a corrupted Qdrant collection.
407
408
 
408
409
  The fan-out runs on the background memory worker — this command returns
@@ -449,20 +450,13 @@ Examples:
449
450
  {
450
451
  name: "validate",
451
452
  description:
452
- "Print a diagnostic report of v2 workspace state (read-only)",
453
+ "Same report as 'memory validate' (read-only concept-page check)",
453
454
  helpText: `
454
- Walks the v2 concept-page tree on disk and reports:
455
- - Page count
456
- - Edge count (total and unique outgoing targets)
457
- - Missing outgoing edge targets (orphan edges)
458
- - Oversized pages (over the per-folder size cap)
459
- - Parse failures (missing or malformed frontmatter)
460
-
461
- Read-only — does not mutate the workspace. Exits non-zero if any
462
- violations are reported.
455
+ Identical to 'assistant memory validate'; prefer that spelling. The report
456
+ covers the concept-page store, which is the same under memory v2 and v3.
463
457
 
464
458
  Examples:
465
- $ assistant memory v2 validate`,
459
+ $ assistant memory validate`,
466
460
  },
467
461
  {
468
462
  name: "ema",
@@ -600,19 +594,21 @@ Examples:
600
594
  name: "v3",
601
595
  description: "Memory v3 live-lane maintenance (section-lane model)",
602
596
  helpText: `
603
- The v3 memory subsystem retrieves concept pages over section-grain lanes and
604
- caches them as live shadow lanes inside the assistant. These commands maintain
605
- that live state safely.
597
+ The v3 memory subsystem retrieves concept pages over section-grain lanes held
598
+ in memory inside the assistant. These commands maintain that live state
599
+ safely.
606
600
 
607
601
  Examples:
608
602
  $ assistant memory v3 rebuild-index
609
- $ assistant memory v3 backfill-sections`,
603
+ $ assistant memory v3 backfill-sections
604
+ $ assistant memory v3 gate-stats
605
+ $ assistant memory v3 gate-stats --lookback-days 7 --json`,
610
606
  subcommands: [
611
607
  {
612
608
  name: "rebuild-index",
613
609
  description: "Invalidate the v3 lanes so the next turn rebuilds",
614
610
  helpText: `
615
- Drops the assistant's cached v3 shadow lanes so the section index is rebuilt
611
+ Drops the assistant's in-memory v3 lanes so the section index is rebuilt
616
612
  from the current on-disk state on the next turn. Useful after editing concept
617
613
  pages out-of-band.
618
614
 
@@ -633,10 +629,10 @@ Examples:
633
629
  Embeds EVERY concept page's sections — including synthetic skill and CLI
634
630
  capability rows — into the section dense store in one pass, then advances
635
631
  the maintain checkpoint so the next incremental pass only re-embeds future
636
- edits. Use this once on an existing install before the section-lane A/B and
637
- cutover: the dense collection starts empty, and the periodic maintenance
638
- pass only re-embeds pages edited since its last run (and never the synthetic
639
- rows), so most of the corpus would otherwise never be embedded.
632
+ edits. Use this once on an install whose section dense store is empty or
633
+ predates v3: the periodic maintenance pass only re-embeds pages edited since
634
+ its last run (and never the synthetic rows), so most of the corpus would
635
+ otherwise never be embedded.
640
636
 
641
637
  Idempotent and safe to re-run. Runs inside the assistant so it uses the live
642
638
  configuration and advances the checkpoint the assistant reads.
@@ -716,6 +712,46 @@ Examples:
716
712
  $ assistant memory v3 eval --snapshot .mv3/snapshot/concepts --staging .mv3/staging --out .mv3/eval
717
713
  $ assistant memory v3 eval --snapshot .mv3/snapshot/concepts --staging .mv3/staging --out .mv3/eval --turns-file .mv3/eval/key.json
718
714
  $ assistant memory v3 eval --snapshot .mv3/snapshot/concepts --staging .mv3/staging --out .mv3/eval --exclude-conversation <migration-conv-id>`,
715
+ },
716
+ {
717
+ name: "gate-stats",
718
+ description:
719
+ "Show injection gate pass rates bucketed by corpus size (read-only)",
720
+ options: [
721
+ {
722
+ flags: "--lookback-days <n>",
723
+ description: "Days of telemetry to aggregate (1–90, default 30)",
724
+ defaultValue: "30",
725
+ },
726
+ {
727
+ flags: "--json",
728
+ description: "Emit raw JSON instead of a formatted table",
729
+ },
730
+ ],
731
+ helpText: `
732
+ Reads the memory v3 injection gate telemetry outbox and prints pass rates
733
+ and reason distributions grouped by concept page count bucket
734
+ (0–9 / 10–49 / 50–199 / 200+). Scored runs (dense lane was available and
735
+ actually weighed scores) are reported separately from pass-open shortcuts
736
+ (dense disabled / unavailable / gate threw) so scoredPassRate reflects
737
+ only contested gate decisions — the signal relevant for threshold calibration.
738
+
739
+ Coverage is limited to runs still pending platform flush. In a healthy system
740
+ the outbox holds only the last few minutes to hours of events, so
741
+ --lookback-days is an upper bound, not a guarantee; long-window aggregation
742
+ lives on the platform side on top of flushed watchdog events.
743
+
744
+ Reads the telemetry database directly — the assistant does not need to be
745
+ running.
746
+
747
+ Intended use: verify that gate firing rates shift as expected after a
748
+ config or threshold change, and check whether the bm25-auto-calibration
749
+ flag is worth enabling for large corpora.
750
+
751
+ Examples:
752
+ $ assistant memory v3 gate-stats
753
+ $ assistant memory v3 gate-stats --lookback-days 7
754
+ $ assistant memory v3 gate-stats --json | jq '.buckets[] | select(.pageCountRange == "200+")'`,
719
755
  },
720
756
  {
721
757
  name: "eval-tally",
@@ -762,6 +798,26 @@ Example:
762
798
  },
763
799
  ],
764
800
  },
801
+ {
802
+ name: "validate",
803
+ description:
804
+ "Check the concept-page store for dangling links, oversized pages, and parse failures (read-only)",
805
+ helpText: `
806
+ Walks memory/concepts/ on disk and reports:
807
+ - Page count and edge count
808
+ - Dangling links: an edges: entry, a links: entry, or an inline
809
+ [[wikilink]] whose target page does not exist (targets under skills/
810
+ and cli-commands/ resolve against the registered capability catalog)
811
+ - Oversized pages (over the configured per-page character cap)
812
+ - Parse failures (malformed frontmatter)
813
+
814
+ Read-only. Exits non-zero if anything is reported. Works on every memory
815
+ tier, including before memory.v3.live or memory.v2.enabled is set, so it
816
+ doubles as the pre-flip check for a migration.
817
+
818
+ Examples:
819
+ $ assistant memory validate`,
820
+ },
765
821
  {
766
822
  name: "ingest",
767
823
  description:
@@ -8,6 +8,7 @@ import { registerMemoryIngestCommand } from "./memory-ingest.js";
8
8
  import { registerMemoryRetrospectiveCommand } from "./memory-retrospective.js";
9
9
  import { registerMemoryV2Command } from "./memory-v2.js";
10
10
  import { registerMemoryV3Command } from "./memory-v3.js";
11
+ import { registerMemoryValidateCommand } from "./memory-validate.js";
11
12
  import { registerMemoryNodesCommand } from "./nodes.js";
12
13
  import { registerMemoryWorkerCommand } from "./worker.js";
13
14
 
@@ -24,6 +25,7 @@ export function registerMemoryCommand(program: Command): void {
24
25
  registerMemoryV2Command(memory);
25
26
  registerMemoryV3Command(memory);
26
27
  registerMemoryIngestCommand(memory);
28
+ registerMemoryValidateCommand(memory);
27
29
  registerMemoryRetrospectiveCommand(memory);
28
30
  registerMemoryWorkerCommand(memory);
29
31
  },
@@ -12,8 +12,9 @@
12
12
  * from the current skill set.
13
13
  * - `activation` — refresh persisted activation state for every
14
14
  * conversation that has a stored row.
15
- * - `validate` — print a diagnostic report (page count, edge count, and
16
- * violation lists). Does not mutate the workspace.
15
+ * - `validate`: {@link runMemoryValidate}, also registered as the top-level
16
+ * `memory validate` (`memory-validate.ts`); kept here while this
17
+ * namespace exists.
17
18
  */
18
19
 
19
20
  import type { Command } from "commander";
@@ -59,6 +60,60 @@ async function runBackfillOp(op: MemoryV2BackfillOp): Promise<void> {
59
60
  log.info(`Queued ${op} job: ${result.result!.jobId}`);
60
61
  }
61
62
 
63
+ /**
64
+ * Print the validate report; sets a non-zero exit code on any violation.
65
+ * Registered as `memory validate` (`memory-validate.ts`) and `memory v2
66
+ * validate`.
67
+ */
68
+ export async function runMemoryValidate(): Promise<void> {
69
+ const result = await cliIpcCall<MemoryV2ValidateResult>(
70
+ "memory_v2_validate",
71
+ { body: {} },
72
+ );
73
+
74
+ if (!result.ok) {
75
+ log.error(result.error ?? "Failed to validate memory state");
76
+ process.exitCode = 1;
77
+ return;
78
+ }
79
+
80
+ const report = result.result!;
81
+ log.info(`Pages: ${report.pageCount}`);
82
+ log.info(`Edges: ${report.edgeCount}`);
83
+ log.info(
84
+ `Dangling links: ${
85
+ report.danglingLinks.length === 0 ? "none" : report.danglingLinks.length
86
+ }`,
87
+ );
88
+ for (const d of report.danglingLinks) {
89
+ log.info(` - ${d.from} → ${d.to} (${d.kind})`);
90
+ }
91
+ log.info(
92
+ `Oversized pages: ${
93
+ report.oversizedPages.length === 0 ? "none" : report.oversizedPages.length
94
+ }`,
95
+ );
96
+ for (const p of report.oversizedPages) {
97
+ log.info(` - ${p.slug}: ${p.chars} chars`);
98
+ }
99
+ log.info(
100
+ `Parse failures: ${
101
+ report.parseFailures.length === 0 ? "none" : report.parseFailures.length
102
+ }`,
103
+ );
104
+ for (const p of report.parseFailures) {
105
+ log.info(` - ${p.slug}: ${p.error}`);
106
+ }
107
+
108
+ if (
109
+ report.danglingLinks.length > 0 ||
110
+ report.oversizedPages.length > 0 ||
111
+ report.parseFailures.length > 0
112
+ ) {
113
+ process.exitCode = 1;
114
+ }
115
+ }
116
+
62
117
  // ---------------------------------------------------------------------------
63
118
  // Registration
64
119
  // ---------------------------------------------------------------------------
@@ -97,58 +152,7 @@ export function registerMemoryV2Command(memory: Command): void {
97
152
 
98
153
  // ── validate ──────────────────────────────────────────────────────────
99
154
 
100
- subcommand(v2, "validate").action(async () => {
101
- const result = await cliIpcCall<MemoryV2ValidateResult>(
102
- "memory_v2_validate",
103
- { body: {} },
104
- );
105
-
106
- if (!result.ok) {
107
- log.error(result.error ?? "Failed to validate memory v2 state");
108
- process.exitCode = 1;
109
- return;
110
- }
111
-
112
- const report = result.result!;
113
- log.info(`Pages: ${report.pageCount}`);
114
- log.info(`Edges: ${report.edgeCount}`);
115
- log.info(
116
- `Missing edge endpoints: ${
117
- report.missingEdgeEndpoints.length === 0
118
- ? "none"
119
- : report.missingEdgeEndpoints.length
120
- }`,
121
- );
122
- for (const m of report.missingEdgeEndpoints) {
123
- log.info(` - ${m.from} → ${m.to}`);
124
- }
125
- log.info(
126
- `Oversized pages: ${
127
- report.oversizedPages.length === 0
128
- ? "none"
129
- : report.oversizedPages.length
130
- }`,
131
- );
132
- for (const p of report.oversizedPages) {
133
- log.info(` - ${p.slug}: ${p.chars} chars`);
134
- }
135
- log.info(
136
- `Parse failures: ${
137
- report.parseFailures.length === 0 ? "none" : report.parseFailures.length
138
- }`,
139
- );
140
- for (const p of report.parseFailures) {
141
- log.info(` - ${p.slug}: ${p.error}`);
142
- }
143
-
144
- if (
145
- report.missingEdgeEndpoints.length > 0 ||
146
- report.oversizedPages.length > 0 ||
147
- report.parseFailures.length > 0
148
- ) {
149
- process.exitCode = 1;
150
- }
151
- });
155
+ subcommand(v2, "validate").action(runMemoryValidate);
152
156
 
153
157
  // ── ema ───────────────────────────────────────────────────────────────
154
158