@vellumai/assistant 0.8.7-dev.202606052232.2ddc989 → 0.8.8

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 (262) hide show
  1. package/bun.lock +2 -2
  2. package/docs/plugins.md +832 -0
  3. package/examples/plugins/echo/README.md +60 -61
  4. package/examples/plugins/echo/package.json +2 -1
  5. package/examples/plugins/echo/register.ts +143 -0
  6. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +6 -7
  7. package/openapi.yaml +5 -15
  8. package/package.json +2 -2
  9. package/src/__tests__/agent-loop-exit-reason.test.ts +56 -3
  10. package/src/__tests__/anthropic-provider.test.ts +1 -1
  11. package/src/__tests__/app-control-flow.test.ts +1 -1
  12. package/src/__tests__/app-dir-path-guard.test.ts +0 -1
  13. package/src/__tests__/approval-routes-http.test.ts +1 -4
  14. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  15. package/src/__tests__/channel-approvals.test.ts +1 -1
  16. package/src/__tests__/circuit-breaker-pipeline.test.ts +405 -0
  17. package/src/__tests__/compaction-pipeline.test.ts +210 -0
  18. package/src/__tests__/compaction-timeout-recovery.test.ts +251 -0
  19. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -0
  20. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +3 -0
  21. package/src/__tests__/conversation-agent-loop-overflow.test.ts +7 -3
  22. package/src/__tests__/conversation-agent-loop.test.ts +39 -42
  23. package/src/__tests__/conversation-clean-command.test.ts +2 -5
  24. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -4
  25. package/src/__tests__/conversation-runtime-assembly.test.ts +71 -140
  26. package/src/__tests__/conversation-runtime-workspace.test.ts +27 -108
  27. package/src/__tests__/conversation-starter-routes.test.ts +6 -14
  28. package/src/__tests__/conversation-workspace-cache-state.test.ts +16 -17
  29. package/src/__tests__/conversation-workspace-injection.test.ts +1 -61
  30. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -7
  31. package/src/__tests__/db-acp-history.test.ts +0 -101
  32. package/src/__tests__/dynamic-page-surface.test.ts +0 -31
  33. package/src/__tests__/file-write-tool.test.ts +0 -63
  34. package/src/__tests__/gateway-only-guard.test.ts +2 -12
  35. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  36. package/src/__tests__/guardian-routing-invariants.test.ts +4 -2
  37. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  38. package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -1
  39. package/src/__tests__/heartbeat-service.test.ts +0 -1
  40. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  41. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  42. package/src/__tests__/injector-background-turn.test.ts +1 -1
  43. package/src/__tests__/injector-chain.test.ts +6 -34
  44. package/src/__tests__/injector-disk-pressure.test.ts +34 -77
  45. package/src/__tests__/injector-document-comments.test.ts +1 -1
  46. package/src/__tests__/list-messages-hidden-metadata.test.ts +0 -38
  47. package/src/__tests__/memory-v2-static-injector.test.ts +1 -1
  48. package/src/__tests__/{overflow-reduction-loop.test.ts → overflow-reduce-pipeline.test.ts} +284 -64
  49. package/src/__tests__/pipeline-runner.test.ts +554 -0
  50. package/src/__tests__/plugin-api-shim.test.ts +6 -3
  51. package/src/__tests__/plugin-bootstrap.test.ts +23 -12
  52. package/src/__tests__/plugin-registry.test.ts +49 -3
  53. package/src/__tests__/plugin-types.test.ts +70 -0
  54. package/src/__tests__/reaction-persistence.test.ts +1 -1
  55. package/src/__tests__/send-endpoint-busy.test.ts +1 -4
  56. package/src/__tests__/skill-feature-flags-integration.test.ts +0 -33
  57. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  58. package/src/__tests__/subagent-fork-notifications.test.ts +3 -1
  59. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  60. package/src/__tests__/subagent-manager-notify.test.ts +3 -1
  61. package/src/__tests__/subagent-notify-parent.test.ts +3 -1
  62. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  63. package/src/__tests__/user-plugin-loader.test.ts +286 -54
  64. package/src/acp/__tests__/client-handler.test.ts +0 -40
  65. package/src/acp/__tests__/prepare-agent-env.test.ts +0 -137
  66. package/src/acp/__tests__/session-manager-persistence.test.ts +28 -95
  67. package/src/acp/agent-process.ts +1 -61
  68. package/src/acp/client-handler.ts +0 -31
  69. package/src/acp/prepare-agent-env.ts +29 -83
  70. package/src/acp/resolve-agent.test.ts +7 -320
  71. package/src/acp/resolve-agent.ts +18 -182
  72. package/src/acp/session-manager.ts +73 -495
  73. package/src/acp/types.ts +0 -8
  74. package/src/agent/compaction-circuit.ts +102 -60
  75. package/src/agent/loop.ts +59 -32
  76. package/src/api/responses/conversation-message.ts +1 -7
  77. package/src/approvals/guardian-request-resolvers.ts +1 -1
  78. package/src/background-wake/next-wake.ts +0 -1
  79. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  80. package/src/config/acp-defaults.test.ts +0 -10
  81. package/src/config/acp-defaults.ts +0 -6
  82. package/src/config/bundled-skills/acp/SKILL.md +31 -83
  83. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  84. package/src/config/bundled-skills/app-builder/SKILL.md +381 -224
  85. package/src/config/bundled-skills/app-builder/TOOLS.json +0 -29
  86. package/src/config/bundled-skills/document-editor/SKILL.md +23 -28
  87. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  88. package/src/config/bundled-tool-registry.ts +0 -2
  89. package/src/config/feature-flag-registry.json +5 -14
  90. package/src/config/schemas/heartbeat.ts +0 -9
  91. package/src/context/strip-injections.ts +2 -8
  92. package/src/context/window-manager.ts +1 -2
  93. package/src/daemon/conversation-agent-loop-handlers.ts +11 -0
  94. package/src/daemon/conversation-agent-loop.ts +279 -62
  95. package/src/daemon/conversation-runtime-assembly.ts +69 -106
  96. package/src/daemon/conversation-store.ts +90 -9
  97. package/src/daemon/conversation-workspace.ts +0 -17
  98. package/src/daemon/conversation.ts +6 -0
  99. package/src/daemon/external-plugins-bootstrap.ts +11 -11
  100. package/src/daemon/handlers/conversations.ts +1 -3
  101. package/src/daemon/handlers/skills.ts +1 -4
  102. package/src/daemon/lifecycle.ts +0 -21
  103. package/src/daemon/server.ts +0 -2
  104. package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -3
  105. package/src/heartbeat/heartbeat-run-store.ts +1 -23
  106. package/src/heartbeat/heartbeat-service.ts +0 -26
  107. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  108. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  109. package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -15
  110. package/src/ipc/skill-routes/memory.ts +2 -4
  111. package/src/memory/conversation-starter-checkpoints.ts +0 -1
  112. package/src/memory/db-init.ts +0 -2
  113. package/src/memory/job-handlers/conversation-starters.ts +2 -13
  114. package/src/memory/jobs-worker.ts +1 -1
  115. package/src/memory/migrations/index.ts +0 -1
  116. package/src/memory/schema/acp.ts +0 -4
  117. package/src/memory/v2/__tests__/consolidation-job.test.ts +3 -3
  118. package/src/memory/v2/consolidation-job.ts +4 -13
  119. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/assign.test.ts +4 -4
  120. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/live-integration.test.ts +4 -4
  121. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/maintain-job.test.ts +5 -5
  122. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/orchestrate.test.ts +3 -3
  123. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/reconcile.test.ts +2 -2
  124. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/render-injection.test.ts +1 -1
  125. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/router.test.ts +3 -3
  126. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selection-log-store.test.ts +8 -8
  127. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selector.test.ts +3 -3
  128. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/shadow-plugin.test.ts +12 -12
  129. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/assign.ts +5 -5
  130. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/capabilities.ts +2 -2
  131. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/maintain-job.ts +8 -8
  132. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/page-content.ts +2 -2
  133. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/provider-blocks.ts +1 -1
  134. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/reconcile.ts +3 -3
  135. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/render-injection.ts +1 -1
  136. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/router.ts +3 -3
  137. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selection-log-store.ts +4 -4
  138. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selector.ts +4 -4
  139. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/shadow-plugin.ts +90 -28
  140. package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/tree.ts +1 -1
  141. package/src/plugin-api/index.ts +5 -0
  142. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +93 -0
  143. package/src/plugins/defaults/{memory-v3-shadow → circuit-breaker}/package.json +2 -2
  144. package/src/plugins/defaults/circuit-breaker/register.ts +39 -0
  145. package/src/plugins/defaults/compaction/middlewares/compaction.ts +25 -0
  146. package/src/plugins/defaults/compaction/package.json +1 -1
  147. package/src/plugins/defaults/compaction/register.ts +19 -8
  148. package/src/plugins/defaults/compaction/terminal.ts +73 -0
  149. package/src/plugins/defaults/index.ts +5 -3
  150. package/src/plugins/defaults/{memory-retrieval/injectors.ts → injectors/register.ts} +7 -45
  151. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +7 -11
  152. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  153. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +126 -0
  154. package/src/plugins/defaults/overflow-reduce/package.json +15 -0
  155. package/src/plugins/defaults/overflow-reduce/register.ts +42 -0
  156. package/src/plugins/external-api.ts +2 -2
  157. package/src/plugins/pipeline.ts +293 -6
  158. package/src/plugins/registry.ts +37 -9
  159. package/src/plugins/types.ts +336 -32
  160. package/src/plugins/user-loader.ts +127 -30
  161. package/src/proactive-artifact/aux-message-injector.ts +1 -1
  162. package/src/proactive-artifact/job.test.ts +1 -1
  163. package/src/prompts/__tests__/system-prompt.test.ts +0 -6
  164. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +2 -4
  165. package/src/runtime/__tests__/agent-wake.test.ts +5 -5
  166. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  167. package/src/runtime/agent-wake.ts +3 -0
  168. package/src/runtime/assistant-event-hub.ts +1 -1
  169. package/src/runtime/channel-approvals.ts +1 -1
  170. package/src/runtime/interactive-ui.ts +1 -1
  171. package/src/runtime/routes/__tests__/acp-routes.test.ts +55 -283
  172. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  173. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +4 -5
  174. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -4
  175. package/src/runtime/routes/acp-routes.test.ts +25 -89
  176. package/src/runtime/routes/acp-routes.ts +29 -81
  177. package/src/runtime/routes/approval-routes.ts +1 -1
  178. package/src/runtime/routes/browser-routes.ts +1 -1
  179. package/src/runtime/routes/browser-tabs-routes.ts +10 -6
  180. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  181. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  182. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  183. package/src/runtime/routes/conversation-routes.ts +2 -15
  184. package/src/runtime/routes/conversation-starter-routes.ts +7 -13
  185. package/src/runtime/routes/conversations-import-routes.ts +7 -24
  186. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  187. package/src/runtime/routes/host-cu-routes.ts +1 -1
  188. package/src/runtime/routes/identity-routes.ts +3 -18
  189. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  190. package/src/runtime/routes/memory-v3-routes.ts +6 -16
  191. package/src/runtime/routes/playground/helpers.ts +1 -1
  192. package/src/runtime/routes/surface-conversation-resolver.ts +3 -4
  193. package/src/runtime/routes/work-items-routes.ts +4 -2
  194. package/src/runtime/services/conversation-serializer.ts +1 -1
  195. package/src/signals/cancel.ts +4 -2
  196. package/src/subagent/manager.ts +5 -17
  197. package/src/tools/acp/list-agents.test.ts +1 -7
  198. package/src/tools/acp/spawn.test.ts +55 -158
  199. package/src/tools/acp/spawn.ts +72 -47
  200. package/src/tools/acp/steer.test.ts +8 -105
  201. package/src/tools/acp/steer.ts +17 -48
  202. package/src/tools/apps/executors.ts +8 -13
  203. package/src/tools/filesystem/write.ts +0 -34
  204. package/src/tools/subagent/spawn.ts +4 -2
  205. package/src/tools/ui-surface/definitions.ts +4 -25
  206. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +5 -4
  207. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +45 -69
  208. package/examples/plugins/echo/hooks/post-tool-use.ts +0 -18
  209. package/examples/plugins/echo/hooks/stop.ts +0 -16
  210. package/examples/plugins/echo/hooks/user-prompt-submit.ts +0 -18
  211. package/examples/plugins/echo/src/emit.ts +0 -19
  212. package/src/__tests__/compaction-circuit.test.ts +0 -258
  213. package/src/__tests__/compaction-direct.test.ts +0 -132
  214. package/src/__tests__/conversations-import-system-filter.test.ts +0 -101
  215. package/src/acp/__tests__/agent-process.test.ts +0 -161
  216. package/src/acp/__tests__/helpers/acp-history-db.ts +0 -82
  217. package/src/acp/__tests__/helpers/exec-file-stub.ts +0 -101
  218. package/src/acp/__tests__/session-manager-resume.test.ts +0 -736
  219. package/src/acp/auto-install.test.ts +0 -196
  220. package/src/acp/auto-install.ts +0 -177
  221. package/src/acp/feature-gate.test.ts +0 -48
  222. package/src/acp/feature-gate.ts +0 -34
  223. package/src/acp/resume-hint.ts +0 -25
  224. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +0 -48
  225. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +0 -57
  226. package/src/config/bundled-skills/app-builder/references/SLIDES.md +0 -38
  227. package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -62
  228. package/src/daemon/conversation-registry.ts +0 -159
  229. package/src/daemon/overflow-reduction-loop.ts +0 -230
  230. package/src/memory/migrations/272-acp-session-history-cwd.ts +0 -36
  231. package/src/plugins/defaults/compaction/compact.ts +0 -59
  232. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +0 -14
  233. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +0 -19
  234. package/src/plugins/defaults/memory-v3-shadow/injector.ts +0 -75
  235. package/src/plugins/defaults/memory-v3-shadow/register.ts +0 -26
  236. package/src/tools/acp/context.ts +0 -20
  237. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/capabilities.test.ts +0 -0
  238. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/core.test.ts +0 -0
  239. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/eval-turns.json +0 -0
  240. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/live-turns.json +0 -0
  241. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/health.test.ts +0 -0
  242. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/needle.test.ts +0 -0
  243. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/provider-blocks.test.ts +0 -0
  244. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/snapshot.test.ts +0 -0
  245. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/tree.test.ts +0 -0
  246. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/types.test.ts +0 -0
  247. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-eviction.test.ts +0 -0
  248. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-skeleton.test.ts +0 -0
  249. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/core.ts +0 -0
  250. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/README.md +0 -0
  251. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/assignments.json +0 -0
  252. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/core.json +0 -0
  253. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-x.md +0 -0
  254. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-y.md +0 -0
  255. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-b/topic-z.md +0 -0
  256. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/health.ts +0 -0
  257. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/llm-retry.ts +0 -0
  258. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/needle.ts +0 -0
  259. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/orchestrate.ts +0 -0
  260. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/snapshot.ts +0 -0
  261. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/types.ts +0 -0
  262. /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/working-set.ts +0 -0
@@ -198,7 +198,6 @@ mock.module("../agent/loop.js", () => ({
198
198
  }));
199
199
 
200
200
  import { Conversation } from "../daemon/conversation.js";
201
- import { refreshWorkspaceTopLevelContextIfNeeded } from "../daemon/conversation-workspace.js";
202
201
 
203
202
  // ---------------------------------------------------------------------------
204
203
  // Helpers
@@ -250,7 +249,7 @@ describe("Conversation workspace cache state", () => {
250
249
  });
251
250
 
252
251
  test("refreshWorkspaceTopLevelContextIfNeeded populates context and clears dirty", () => {
253
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
252
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
254
253
 
255
254
  expect(conversation.isWorkspaceTopLevelDirty()).toBe(false);
256
255
  expect(conversation.getWorkspaceTopLevelContext()).not.toBeNull();
@@ -266,10 +265,10 @@ describe("Conversation workspace cache state", () => {
266
265
  });
267
266
 
268
267
  test("refreshWorkspaceTopLevelContextIfNeeded no-ops when not dirty and cache exists", () => {
269
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
268
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
270
269
  const first = conversation.getWorkspaceTopLevelContext();
271
270
 
272
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
271
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
273
272
  const second = conversation.getWorkspaceTopLevelContext();
274
273
 
275
274
  // Same reference — no recomputation
@@ -277,7 +276,7 @@ describe("Conversation workspace cache state", () => {
277
276
  });
278
277
 
279
278
  test("markWorkspaceTopLevelDirty sets dirty flag", () => {
280
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
279
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
281
280
  expect(conversation.isWorkspaceTopLevelDirty()).toBe(false);
282
281
 
283
282
  conversation.markWorkspaceTopLevelDirty();
@@ -285,10 +284,10 @@ describe("Conversation workspace cache state", () => {
285
284
  });
286
285
 
287
286
  test("refresh after marking dirty produces fresh context", () => {
288
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
287
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
289
288
 
290
289
  conversation.markWorkspaceTopLevelDirty();
291
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
290
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
292
291
 
293
292
  expect(conversation.getWorkspaceTopLevelContext()).not.toBeNull();
294
293
  expect(conversation.getWorkspaceTopLevelContext()!).toContain(
@@ -300,7 +299,7 @@ describe("Conversation workspace cache state", () => {
300
299
  test("renders client-reported host env when set on the conversation", () => {
301
300
  conversation.hostHomeDir = "/Users/alice";
302
301
  conversation.hostUsername = "alice";
303
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
302
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
304
303
 
305
304
  const block = conversation.getWorkspaceTopLevelContext();
306
305
  expect(block).not.toBeNull();
@@ -310,7 +309,7 @@ describe("Conversation workspace cache state", () => {
310
309
 
311
310
  test("falls back to daemon os info when client host env is absent", async () => {
312
311
  const { homedir, userInfo } = await import("node:os");
313
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
312
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
314
313
 
315
314
  const block = conversation.getWorkspaceTopLevelContext();
316
315
  expect(block).not.toBeNull();
@@ -321,7 +320,7 @@ describe("Conversation workspace cache state", () => {
321
320
  test("re-renders with updated host env after marking dirty", () => {
322
321
  conversation.hostHomeDir = "/Users/alice";
323
322
  conversation.hostUsername = "alice";
324
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
323
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
325
324
  expect(conversation.getWorkspaceTopLevelContext()!).toContain(
326
325
  "Host home directory: /Users/alice",
327
326
  );
@@ -329,7 +328,7 @@ describe("Conversation workspace cache state", () => {
329
328
  conversation.hostHomeDir = "/Users/bob";
330
329
  conversation.hostUsername = "bob";
331
330
  conversation.markWorkspaceTopLevelDirty();
332
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
331
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
333
332
 
334
333
  const block = conversation.getWorkspaceTopLevelContext();
335
334
  expect(block).not.toBeNull();
@@ -345,7 +344,7 @@ describe("Conversation workspace cache state", () => {
345
344
  // Simulate a macOS turn populating host env.
346
345
  conversation.hostHomeDir = "/Users/alice";
347
346
  conversation.hostUsername = "alice";
348
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
347
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
349
348
  expect(conversation.getWorkspaceTopLevelContext()!).toContain(
350
349
  "Host home directory: /Users/alice",
351
350
  );
@@ -356,7 +355,7 @@ describe("Conversation workspace cache state", () => {
356
355
  conversation.hostHomeDir = undefined;
357
356
  conversation.hostUsername = undefined;
358
357
  conversation.markWorkspaceTopLevelDirty();
359
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
358
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
360
359
 
361
360
  const block = conversation.getWorkspaceTopLevelContext();
362
361
  expect(block).not.toBeNull();
@@ -382,7 +381,7 @@ describe("Conversation workspace cache state", () => {
382
381
  expect(conversation.hostUsername).toBe("alice");
383
382
  expect(conversation.isWorkspaceTopLevelDirty()).toBe(true);
384
383
 
385
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
384
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
386
385
  const block = conversation.getWorkspaceTopLevelContext();
387
386
  expect(block!).toContain("Host home directory: /Users/alice");
388
387
  expect(block!).toContain("Host username: alice");
@@ -456,7 +455,7 @@ describe("Conversation workspace cache state", () => {
456
455
  hostUsername: "alice",
457
456
  });
458
457
  // Render once so the dirty flag clears.
459
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
458
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
460
459
  expect(conversation.isWorkspaceTopLevelDirty()).toBe(false);
461
460
 
462
461
  // Re-apply the same values — dirty flag should remain false so we don't
@@ -477,7 +476,7 @@ describe("Conversation workspace cache state", () => {
477
476
  hostHomeDir: "/Users/alice",
478
477
  hostUsername: "alice",
479
478
  });
480
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
479
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
481
480
  expect(conversation.isWorkspaceTopLevelDirty()).toBe(false);
482
481
 
483
482
  // New values — should mark dirty so the next render picks them up.
@@ -501,7 +500,7 @@ describe("Conversation workspace cache state", () => {
501
500
 
502
501
  try {
503
502
  const tempConversation = makeConversation(workspaceRoot);
504
- refreshWorkspaceTopLevelContextIfNeeded(tempConversation);
503
+ tempConversation.refreshWorkspaceTopLevelContextIfNeeded();
505
504
 
506
505
  expect(tempConversation.getWorkspaceTopLevelContext()!).toContain(
507
506
  `Current conversation attachments: conversations/${legacyDirName}/attachments/`,
@@ -295,14 +295,6 @@ mock.module("../memory/canonical-guardian-store.js", () => ({
295
295
  }));
296
296
 
297
297
  import { Conversation } from "../daemon/conversation.js";
298
- import {
299
- clearConversations,
300
- findConversation,
301
- removeSubagentConversation,
302
- setConversation,
303
- setSubagentConversation,
304
- } from "../daemon/conversation-registry.js";
305
- import { resolveWorkspaceTopLevelContext } from "../daemon/conversation-workspace.js";
306
298
  import { resetPluginRegistryAndRegisterDefaults } from "../plugins/defaults/index.js";
307
299
 
308
300
  function makeConversation(): Conversation {
@@ -317,7 +309,7 @@ function makeConversation(): Conversation {
317
309
  };
318
310
  },
319
311
  };
320
- const conversation = new Conversation(
312
+ return new Conversation(
321
313
  "conv-1",
322
314
  provider,
323
315
  "system prompt",
@@ -325,10 +317,6 @@ function makeConversation(): Conversation {
325
317
  "/tmp",
326
318
  { maxTokens: 4096 },
327
319
  );
328
- // Mirror production: top-level conversations are registered in the store, so
329
- // the workspace injector can resolve them by id via the conversation registry.
330
- setConversation(conversation.conversationId, conversation);
331
- return conversation;
332
320
  }
333
321
 
334
322
  function messageText(message: Message): string {
@@ -347,7 +335,6 @@ describe("Conversation workspace injection", () => {
347
335
  runCalls = [];
348
336
  agentLoopScript = () => {};
349
337
  scanCallCount = 0;
350
- clearConversations();
351
338
  resetPluginRegistryAndRegisterDefaults();
352
339
  });
353
340
 
@@ -430,58 +417,11 @@ describe("Conversation workspace injection", () => {
430
417
  });
431
418
  });
432
419
 
433
- describe("Conversation workspace injection — subagents", () => {
434
- beforeEach(() => {
435
- scanCallCount = 0;
436
- clearConversations();
437
- resetPluginRegistryAndRegisterDefaults();
438
- });
439
-
440
- test("workspace context resolves for subagent conversations not in the store", () => {
441
- const provider = {
442
- name: "mock",
443
- async sendMessage(): Promise<ProviderResponse> {
444
- return {
445
- content: [],
446
- model: "mock",
447
- usage: { inputTokens: 0, outputTokens: 0 },
448
- stopReason: "end_turn",
449
- };
450
- },
451
- };
452
- const subagentId = "subagent-conv-1";
453
- const conversation = new Conversation(
454
- subagentId,
455
- provider,
456
- "system prompt",
457
- () => {},
458
- "/tmp",
459
- { maxTokens: 4096 },
460
- );
461
- setSubagentConversation(subagentId, conversation);
462
-
463
- try {
464
- // Subagents live only in the manager's index, never in the
465
- // eviction-managed store, so the store lookup must not see them.
466
- expect(findConversation(subagentId)).toBeUndefined();
467
-
468
- // The per-conversation workspace lookup still resolves them, so subagent
469
- // turns retain workspace grounding.
470
- const context = resolveWorkspaceTopLevelContext(subagentId);
471
- expect(context).not.toBeNull();
472
- expect(context).toContain("Root: /tmp");
473
- } finally {
474
- removeSubagentConversation(subagentId, conversation);
475
- }
476
- });
477
- });
478
-
479
420
  describe("Conversation workspace dirty-refresh E2E", () => {
480
421
  beforeEach(() => {
481
422
  runCalls = [];
482
423
  agentLoopScript = () => {};
483
424
  scanCallCount = 0;
484
- clearConversations();
485
425
  resetPluginRegistryAndRegisterDefaults();
486
426
  });
487
427
 
@@ -273,7 +273,6 @@ mock.module("../memory/canonical-guardian-store.js", () => ({
273
273
  }));
274
274
 
275
275
  import { Conversation } from "../daemon/conversation.js";
276
- import { refreshWorkspaceTopLevelContextIfNeeded } from "../daemon/conversation-workspace.js";
277
276
 
278
277
  function makeConversation(): Conversation {
279
278
  const provider = {
@@ -311,7 +310,7 @@ describe("Conversation workspace dirty on file mutations", () => {
311
310
  await conversation.loadFromDb();
312
311
 
313
312
  // Prime the cache so dirty=false
314
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
313
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
315
314
  expect(conversation.isWorkspaceTopLevelDirty()).toBe(false);
316
315
 
317
316
  agentLoopScript = (onEvent) => {
@@ -340,7 +339,7 @@ describe("Conversation workspace dirty on file mutations", () => {
340
339
  const conversation = makeConversation();
341
340
  await conversation.loadFromDb();
342
341
 
343
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
342
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
344
343
  expect(conversation.isWorkspaceTopLevelDirty()).toBe(false);
345
344
 
346
345
  agentLoopScript = (onEvent) => {
@@ -371,7 +370,7 @@ describe("Conversation workspace dirty on file mutations", () => {
371
370
  const conversation = makeConversation();
372
371
  await conversation.loadFromDb();
373
372
 
374
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
373
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
375
374
  expect(conversation.isWorkspaceTopLevelDirty()).toBe(false);
376
375
 
377
376
  agentLoopScript = (onEvent) => {
@@ -400,7 +399,7 @@ describe("Conversation workspace dirty on file mutations", () => {
400
399
  const conversation = makeConversation();
401
400
  await conversation.loadFromDb();
402
401
 
403
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
402
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
404
403
  expect(conversation.isWorkspaceTopLevelDirty()).toBe(false);
405
404
 
406
405
  agentLoopScript = (onEvent) => {
@@ -429,7 +428,7 @@ describe("Conversation workspace dirty on file mutations", () => {
429
428
  const conversation = makeConversation();
430
429
  await conversation.loadFromDb();
431
430
 
432
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
431
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
433
432
  expect(conversation.isWorkspaceTopLevelDirty()).toBe(false);
434
433
 
435
434
  agentLoopScript = (onEvent) => {
@@ -458,7 +457,7 @@ describe("Conversation workspace dirty on file mutations", () => {
458
457
  const conversation = makeConversation();
459
458
  await conversation.loadFromDb();
460
459
 
461
- refreshWorkspaceTopLevelContextIfNeeded(conversation);
460
+ conversation.refreshWorkspaceTopLevelContextIfNeeded();
462
461
  expect(conversation.isWorkspaceTopLevelDirty()).toBe(false);
463
462
 
464
463
  agentLoopScript = (onEvent) => {
@@ -5,7 +5,6 @@ import { drizzle } from "drizzle-orm/bun-sqlite";
5
5
 
6
6
  import { getSqliteFrom } from "../memory/db-connection.js";
7
7
  import { migrate230AcpSessionHistory } from "../memory/migrations/230-acp-session-history.js";
8
- import { migrateAcpSessionHistoryCwd } from "../memory/migrations/272-acp-session-history-cwd.js";
9
8
  import * as schema from "../memory/schema.js";
10
9
 
11
10
  function createTestDb() {
@@ -283,103 +282,3 @@ describe("acp_session_history migration", () => {
283
282
  expect(row?.id).toBe("history-rerun");
284
283
  });
285
284
  });
286
-
287
- describe("acp_session_history cwd migration (272)", () => {
288
- function readColumns(raw: Database): Map<string, ColumnRow> {
289
- const columns = raw
290
- .query(`PRAGMA table_info(acp_session_history)`)
291
- .all() as ColumnRow[];
292
- return new Map(columns.map((c) => [c.name, c]));
293
- }
294
-
295
- test("adds a nullable cwd TEXT column to an upgraded table", () => {
296
- const db = createTestDb();
297
- const raw = getSqliteFrom(db);
298
- bootstrapCheckpointsTable(raw);
299
-
300
- migrate230AcpSessionHistory(db);
301
- expect(readColumns(raw).has("cwd")).toBe(false);
302
-
303
- migrateAcpSessionHistoryCwd(db);
304
-
305
- const cwd = readColumns(raw).get("cwd");
306
- expect(cwd).toBeDefined();
307
- expect(cwd?.type).toBe("TEXT");
308
- expect(cwd?.notnull).toBe(0);
309
- });
310
-
311
- test("re-running is a no-op, including with a cleared checkpoint", () => {
312
- const db = createTestDb();
313
- const raw = getSqliteFrom(db);
314
- bootstrapCheckpointsTable(raw);
315
-
316
- migrate230AcpSessionHistory(db);
317
- migrateAcpSessionHistoryCwd(db);
318
-
319
- // Second run short-circuits on the completed checkpoint.
320
- expect(() => migrateAcpSessionHistoryCwd(db)).not.toThrow();
321
-
322
- // Even with the checkpoint cleared (simulating crash recovery), the
323
- // column-existence guard makes the ALTER a no-op.
324
- raw
325
- .query(`DELETE FROM memory_checkpoints WHERE key = ?`)
326
- .run("migration_acp_session_history_cwd_v1");
327
- expect(() => migrateAcpSessionHistoryCwd(db)).not.toThrow();
328
-
329
- const columns = raw
330
- .query(`PRAGMA table_info(acp_session_history)`)
331
- .all() as ColumnRow[];
332
- expect(columns.filter((c) => c.name === "cwd")).toHaveLength(1);
333
- });
334
-
335
- test("legacy rows read back with cwd null; new rows round-trip cwd", () => {
336
- const db = createTestDb();
337
- const raw = getSqliteFrom(db);
338
- bootstrapCheckpointsTable(raw);
339
-
340
- migrate230AcpSessionHistory(db);
341
-
342
- // Legacy row inserted before the cwd column existed.
343
- raw
344
- .query(
345
- /*sql*/ `
346
- INSERT INTO acp_session_history (
347
- id, agent_id, acp_session_id, parent_conversation_id,
348
- started_at, status
349
- ) VALUES (?, ?, ?, ?, ?, ?)
350
- `,
351
- )
352
- .run("legacy-1", "agent-old", "acp-old", "conv-old", 100, "completed");
353
-
354
- migrateAcpSessionHistoryCwd(db);
355
-
356
- const legacy = raw
357
- .query(`SELECT cwd FROM acp_session_history WHERE id = 'legacy-1'`)
358
- .get() as { cwd: string | null } | null;
359
- expect(legacy?.cwd).toBeNull();
360
-
361
- raw
362
- .query(
363
- /*sql*/ `
364
- INSERT INTO acp_session_history (
365
- id, agent_id, acp_session_id, parent_conversation_id,
366
- started_at, status, cwd
367
- ) VALUES (?, ?, ?, ?, ?, ?, ?)
368
- `,
369
- )
370
- .run(
371
- "new-1",
372
- "agent-new",
373
- "acp-new",
374
- "conv-new",
375
- 200,
376
- "completed",
377
- "/Users/me/project",
378
- );
379
-
380
- const fresh = raw
381
- .query(`SELECT cwd FROM acp_session_history WHERE id = 'new-1'`)
382
- .get() as { cwd: string | null } | null;
383
- expect(fresh?.cwd).toBe("/Users/me/project");
384
- });
385
- });
@@ -94,37 +94,6 @@ describe("ui_show dynamic_page app substitute guard", () => {
94
94
  expect(proxied).toBe(false);
95
95
  });
96
96
 
97
- test("rejects dynamic_page with a clean title but substantial interactive html", async () => {
98
- let proxied = false;
99
-
100
- const result = await uiShowTool.execute(
101
- {
102
- surface_type: "dynamic_page",
103
- title: "Labor Market Stats",
104
- data: {
105
- html:
106
- "<div id='root'></div><script>" +
107
- "const data=[/*...*/];".padEnd(2100, "/") +
108
- "new Chart(document.getElementById('root'), {});</script>",
109
- preview: { title: "Labor Market Stats" },
110
- },
111
- },
112
- {
113
- conversationId: "conversation-123",
114
- workingDir: "/tmp",
115
- trustClass: "guardian",
116
- proxyToolResolver: async () => {
117
- proxied = true;
118
- return { content: "proxied", isError: false };
119
- },
120
- },
121
- );
122
-
123
- expect(result.isError).toBe(true);
124
- expect(result.content).toContain('skill: "app-builder"');
125
- expect(proxied).toBe(false);
126
- });
127
-
128
97
  test("allows transient non-app dynamic_page surfaces", async () => {
129
98
  let proxied = false;
130
99
 
@@ -260,66 +260,3 @@ describe("file_write tool PKB re-index hook", () => {
260
260
  expect(existsSync(join(workingDir, "pkb", "oops.md"))).toBe(true);
261
261
  });
262
262
  });
263
-
264
- describe("file_write artifact-HTML guard", () => {
265
- test("rejects a self-contained interactive HTML visualization", async () => {
266
- const dir = makeTempDir();
267
- const html =
268
- "<!doctype html><html><head><title>Food Market</title></head>" +
269
- "<body><canvas id='c'></canvas><script>" +
270
- ("const data=[{x:1,y:2}];").padEnd(4000, "/") +
271
- "new Chart(document.getElementById('c'), {data});</script></body></html>";
272
-
273
- const result = await fileWriteTool.execute(
274
- { path: "food-market-stats.html", content: html },
275
- makeContext(dir),
276
- );
277
-
278
- expect(result.isError).toBe(true);
279
- expect(result.content).toContain('skill: "app-builder"');
280
- expect(existsSync(join(dir, "food-market-stats.html"))).toBe(false);
281
- });
282
-
283
- test("allows app-builder's thin shell index.html (external module script)", async () => {
284
- const dir = makeTempDir();
285
- const shell =
286
- "<!doctype html><html><head>" +
287
- "<link rel='stylesheet' href='/src/styles.css'>".padEnd(3200, " ") +
288
- "</head><body><div id='app'></div>" +
289
- "<script type='module' src='/src/main.tsx'></script></body></html>";
290
-
291
- const result = await fileWriteTool.execute(
292
- { path: "src/index.html", content: shell },
293
- makeContext(dir),
294
- );
295
-
296
- expect(result.isError).toBe(false);
297
- expect(existsSync(join(dir, "src", "index.html"))).toBe(true);
298
- });
299
-
300
- test("allows a small/static HTML snippet", async () => {
301
- const dir = makeTempDir();
302
- const result = await fileWriteTool.execute(
303
- { path: "note.html", content: "<html><body><h1>Hi</h1></body></html>" },
304
- makeContext(dir),
305
- );
306
-
307
- expect(result.isError).toBe(false);
308
- expect(existsSync(join(dir, "note.html"))).toBe(true);
309
- });
310
-
311
- test("allows a non-HTML file even with inline script-like content", async () => {
312
- const dir = makeTempDir();
313
- const result = await fileWriteTool.execute(
314
- {
315
- path: "notes.md",
316
- content:
317
- "<script>" + "x".padEnd(2000, "x") + "</script>" + "\n# notes\n",
318
- },
319
- makeContext(dir),
320
- );
321
-
322
- expect(result.isError).toBe(false);
323
- expect(existsSync(join(dir, "notes.md"))).toBe(true);
324
- });
325
- });
@@ -27,7 +27,6 @@ const ALLOWLIST = new Set([
27
27
  "clients/shared/App/Auth/PlatformOAuthService.swift", // comment explaining runtimeUrl vs platformUrl
28
28
  "clients/macos/vellum-assistant/App/AppDelegate.swift",
29
29
  "clients/macos/vellum-assistant/Features/Settings/SettingsConnectTab.swift",
30
- "apps/macos/src/main/bundle-flow.ts", // Electron main calls the local gateway (gatewayPort) with a Guardian token to scan bundles
31
30
  ".claude/skills/update/SKILL.md", // daemon health check script
32
31
 
33
32
  // --- Test fixtures that poll the daemon directly (gateway may require auth) ---
@@ -85,21 +84,12 @@ function isGatewayInternal(filePath: string): boolean {
85
84
  return filePath.startsWith("gateway/");
86
85
  }
87
86
 
88
- /** Additional files allowed for the interpolated-port check only (use gateway port, not runtime). */
89
- const INTERPOLATED_PORT_ALLOWLIST = new Set([
90
- "apps/macos/src/main/bundle-flow.ts",
91
- ]);
92
-
93
87
  /** Shared violation filter: exempt test files, gateway internals, and allowlisted paths. */
94
- function filterViolations(
95
- files: string[],
96
- extraAllowlist?: Set<string>,
97
- ): string[] {
88
+ function filterViolations(files: string[]): string[] {
98
89
  return files.filter((f) => {
99
90
  if (isTestFile(f)) return false;
100
91
  if (isGatewayInternal(f)) return false;
101
92
  if (ALLOWLIST.has(f)) return false;
102
- if (extraAllowlist?.has(f)) return false;
103
93
  return true;
104
94
  });
105
95
  }
@@ -191,7 +181,7 @@ describe("gateway-only API consumption guard", () => {
191
181
  }
192
182
 
193
183
  const files = grepOutput.split("\n").filter((f) => f.length > 0);
194
- const violations = filterViolations(files, INTERPOLATED_PORT_ALLOWLIST);
184
+ const violations = filterViolations(files);
195
185
 
196
186
  if (violations.length > 0) {
197
187
  const message = [
@@ -20,7 +20,7 @@ mock.module("../util/logger.js", () => ({
20
20
  }));
21
21
 
22
22
  const _conversationMocks = new Map<string, unknown>();
23
- mock.module("../daemon/conversation-registry.js", () => ({
23
+ mock.module("../daemon/conversation-store.js", () => ({
24
24
  findConversation: (id: string) => _conversationMocks.get(id),
25
25
  }));
26
26
 
@@ -21,7 +21,7 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
21
21
  mock.module("../config/env.js", () => ({ isHttpAuthDisabled: () => true }));
22
22
 
23
23
  const _conversationMocks = new Map<string, unknown>();
24
- mock.module("../daemon/conversation-registry.js", () => ({
24
+ mock.module("../daemon/conversation-store.js", () => ({
25
25
  findConversation: (id: string) => _conversationMocks.get(id),
26
26
  }));
27
27
 
@@ -51,7 +51,9 @@ import {
51
51
  routeGuardianReply,
52
52
  } from "../runtime/guardian-reply-router.js";
53
53
  import * as pendingInteractions from "../runtime/pending-interactions.js";
54
- import { listGuardianDecisionPrompts } from "../runtime/routes/guardian-action-routes.js";
54
+ import {
55
+ listGuardianDecisionPrompts,
56
+ } from "../runtime/routes/guardian-action-routes.js";
55
57
 
56
58
  initializeDb();
57
59
 
@@ -143,7 +143,7 @@ mock.module("../util/logger.js", () => ({
143
143
  import {
144
144
  clearConversations,
145
145
  setConversation,
146
- } from "../daemon/conversation-registry.js";
146
+ } from "../daemon/conversation-store.js";
147
147
  import { handleConfirmationResponse } from "../daemon/handlers/conversations.js";
148
148
 
149
149
  describe("handleConfirmationResponse canonical status sync", () => {
@@ -56,7 +56,6 @@ mock.module("../heartbeat/heartbeat-run-store.js", () => ({
56
56
  markStaleRunsAsMissed: mockMarkStaleRunsAsMissed,
57
57
  markStaleRunningAsError: mockMarkStaleRunningAsError,
58
58
  countCompletedHeartbeatRuns: mock(() => 10),
59
- countCompletedRunsToday: mock(() => 0),
60
59
  countRecentConsecutiveRuns: mock(() => 0),
61
60
  }));
62
61
 
@@ -32,7 +32,6 @@ mock.module("../heartbeat/heartbeat-run-store.js", () => ({
32
32
  markStaleRunningAsError: mockMarkStaleRunningAsError,
33
33
  listHeartbeatRuns: mockListHeartbeatRuns,
34
34
  countCompletedHeartbeatRuns: mockCountCompletedHeartbeatRuns,
35
- countCompletedRunsToday: mock(() => 0),
36
35
  countRecentConsecutiveRuns: mock(() => 0),
37
36
  }));
38
37
 
@@ -47,7 +47,7 @@ interface FakeConversation {
47
47
 
48
48
  const conversations = new Map<string, FakeConversation>();
49
49
 
50
- mock.module("../daemon/conversation-registry.js", () => ({
50
+ mock.module("../daemon/conversation-store.js", () => ({
51
51
  findConversation: (id: string) => conversations.get(id),
52
52
  }));
53
53
 
@@ -8,9 +8,9 @@
8
8
  * 4. Untargeted (no targetClientId, no header) → 200 accepted (regression)
9
9
  *
10
10
  * Resolution goes through conversation.hostCuProxy?.resolve(...). The
11
- * conversation registry is mocked to return a controlled conversation object.
11
+ * conversation store is mocked to return a controlled conversation object.
12
12
  *
13
- * Note: host-cu-routes.ts has a deep import chain (conversation-registry
13
+ * Note: host-cu-routes.ts has a deep import chain (conversation-store
14
14
  * conversation.ts → ces-client → service-contracts) that requires mocking
15
15
  * before the module loads. We use dynamic imports to ensure all mocks are
16
16
  * registered before the route module is evaluated.
@@ -75,7 +75,7 @@ const conversationStore = new Map<
75
75
  { hostCuProxy?: { processObservation: (...args: unknown[]) => void } }
76
76
  >();
77
77
 
78
- mock.module("../daemon/conversation-registry.js", () => ({
78
+ mock.module("../daemon/conversation-store.js", () => ({
79
79
  findConversation: (conversationId: string) =>
80
80
  conversationStore.get(conversationId),
81
81
  }));
@@ -23,7 +23,7 @@ mock.module("../config/loader.js", () => ({
23
23
  import {
24
24
  DEFAULT_INJECTOR_ORDER,
25
25
  defaultInjectors,
26
- } from "../plugins/defaults/memory-retrieval/injectors.js";
26
+ } from "../plugins/defaults/injectors/register.js";
27
27
  import type { Injector, TurnContext } from "../plugins/types.js";
28
28
 
29
29
  function findInjector(name: string): Injector {