@vellumai/assistant 0.6.0 → 0.6.2

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 (358) hide show
  1. package/AGENTS.md +4 -0
  2. package/ARCHITECTURE.md +68 -15
  3. package/Dockerfile +2 -2
  4. package/bun.lock +6 -2
  5. package/docker-entrypoint.sh +42 -1
  6. package/docs/architecture/integrations.md +1 -1
  7. package/docs/architecture/memory.md +21 -24
  8. package/node_modules/@vellumai/ces-contracts/src/handles.ts +7 -9
  9. package/openapi.yaml +539 -4
  10. package/package.json +5 -1
  11. package/src/__tests__/anthropic-provider.test.ts +160 -95
  12. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  13. package/src/__tests__/app-executors.test.ts +47 -1
  14. package/src/__tests__/app-source-watcher.test.ts +159 -0
  15. package/src/__tests__/assistant-event-hub.test.ts +30 -0
  16. package/src/__tests__/checker.test.ts +138 -172
  17. package/src/__tests__/cli-command-risk-guard.test.ts +1 -1
  18. package/src/__tests__/config-schema.test.ts +5 -0
  19. package/src/__tests__/context-overflow-approval.test.ts +5 -5
  20. package/src/__tests__/conversation-agent-loop-overflow.test.ts +4 -6
  21. package/src/__tests__/conversation-agent-loop.test.ts +4 -51
  22. package/src/__tests__/conversation-analysis-routes.test.ts +169 -0
  23. package/src/__tests__/conversation-directories-parse.test.ts +105 -0
  24. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  25. package/src/__tests__/conversation-runtime-assembly.test.ts +653 -832
  26. package/src/__tests__/conversation-runtime-workspace.test.ts +1 -93
  27. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +17 -4
  28. package/src/__tests__/conversation-wipe.test.ts +2 -6
  29. package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -12
  30. package/src/__tests__/conversation-workspace-injection.test.ts +25 -26
  31. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
  32. package/src/__tests__/copy-composer-tc-templates.test.ts +335 -0
  33. package/src/__tests__/credential-execution-approval-bridge.test.ts +0 -2
  34. package/src/__tests__/date-context.test.ts +76 -210
  35. package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -1
  36. package/src/__tests__/file-list-tool.test.ts +219 -0
  37. package/src/__tests__/first-greeting.test.ts +1 -1
  38. package/src/__tests__/heartbeat-service.test.ts +180 -3
  39. package/src/__tests__/identity-routes.test.ts +328 -0
  40. package/src/__tests__/init-feature-flag-overrides.test.ts +167 -0
  41. package/src/__tests__/injection-block.test.ts +24 -0
  42. package/src/__tests__/inline-command-runner.test.ts +7 -5
  43. package/src/__tests__/install-skill-routing.test.ts +7 -6
  44. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +15 -14
  45. package/src/__tests__/list-messages-tool-merge.test.ts +300 -0
  46. package/src/__tests__/llm-context-normalization.test.ts +18 -18
  47. package/src/__tests__/llm-context-route-provider.test.ts +101 -0
  48. package/src/__tests__/llm-request-log-turn-query.test.ts +162 -0
  49. package/src/__tests__/log-export-workspace.test.ts +257 -100
  50. package/src/__tests__/managed-credential-catalog-cli.test.ts +12 -14
  51. package/src/__tests__/mcp-abort-signal.test.ts +5 -0
  52. package/src/__tests__/mcp-client-auth.test.ts +5 -0
  53. package/src/__tests__/memory-recall-log-store.test.ts +132 -0
  54. package/src/__tests__/migration-export-streaming.test.ts +304 -0
  55. package/src/__tests__/migration-import-commit-http.test.ts +11 -10
  56. package/src/__tests__/mock-fetch.ts +87 -0
  57. package/src/__tests__/navigate-settings-tab.test.ts +14 -1
  58. package/src/__tests__/notification-broadcaster.test.ts +65 -0
  59. package/src/__tests__/notification-decision-recipient-context.test.ts +282 -0
  60. package/src/__tests__/onboarding-template-contract.test.ts +63 -14
  61. package/src/__tests__/parser.test.ts +32 -0
  62. package/src/__tests__/permission-checker-host-gate.test.ts +452 -0
  63. package/src/__tests__/permission-controls-v2-flag.test.ts +55 -0
  64. package/src/__tests__/permission-mode-sse.test.ts +418 -0
  65. package/src/__tests__/permission-mode-store.test.ts +277 -0
  66. package/src/__tests__/permission-mode.test.ts +101 -0
  67. package/src/__tests__/pkb-autoinject.test.ts +96 -0
  68. package/src/__tests__/platform-bash-auto-approve.test.ts +359 -0
  69. package/src/__tests__/profiler-routes.test.ts +502 -0
  70. package/src/__tests__/profiler-run-store.test.ts +441 -0
  71. package/src/__tests__/proxy-approval-callback.test.ts +4 -75
  72. package/src/__tests__/registry.test.ts +1 -1
  73. package/src/__tests__/require-fresh-approval.test.ts +0 -2
  74. package/src/__tests__/sandbox-diagnostics.test.ts +1 -32
  75. package/src/__tests__/sandbox-host-parity.test.ts +5 -4
  76. package/src/__tests__/scheduler-reuse-conversation.test.ts +368 -0
  77. package/src/__tests__/scrub-corrupted-image-attachments.test.ts +278 -0
  78. package/src/__tests__/search-skills-unified.test.ts +4 -3
  79. package/src/__tests__/send-endpoint-busy.test.ts +42 -3
  80. package/src/__tests__/set-permission-mode.test.ts +274 -0
  81. package/src/__tests__/skill-load-feature-flag.test.ts +12 -0
  82. package/src/__tests__/skill-memory.test.ts +2 -783
  83. package/src/__tests__/strip-memory-injections.test.ts +187 -0
  84. package/src/__tests__/subagent-detail.test.ts +84 -0
  85. package/src/__tests__/subagent-disposal.test.ts +308 -0
  86. package/src/__tests__/subagent-manager-notify.test.ts +19 -10
  87. package/src/__tests__/subagent-notify-parent.test.ts +390 -0
  88. package/src/__tests__/subagent-role-registry.test.ts +108 -0
  89. package/src/__tests__/subagent-tool-filtering.test.ts +71 -0
  90. package/src/__tests__/subagent-tools.test.ts +464 -4
  91. package/src/__tests__/system-prompt-ask-mode.test.ts +139 -0
  92. package/src/__tests__/task-memory-cleanup.test.ts +12 -12
  93. package/src/__tests__/terminal-sandbox.test.ts +1 -1
  94. package/src/__tests__/terminal-tools.test.ts +16 -29
  95. package/src/__tests__/test-preload.ts +18 -0
  96. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -1
  97. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -8
  98. package/src/__tests__/tool-executor.test.ts +4 -27
  99. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  100. package/src/__tests__/top-level-renderer.test.ts +10 -13
  101. package/src/__tests__/transport-hints-queue.test.ts +77 -0
  102. package/src/__tests__/trust-store.test.ts +4 -4
  103. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +116 -2
  104. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +387 -0
  105. package/src/__tests__/workspace-migration-030-seed-pkb-autoinject.test.ts +168 -0
  106. package/src/__tests__/workspace-policy.test.ts +2 -7
  107. package/src/agent/loop.ts +6 -29
  108. package/src/approvals/guardian-request-resolvers.ts +24 -0
  109. package/src/avatar/traits-png-sync.ts +3 -3
  110. package/src/channels/types.ts +5 -0
  111. package/src/cli/__tests__/run-assistant-command.ts +56 -0
  112. package/src/cli/__tests__/unknown-command.test.ts +33 -0
  113. package/src/cli/commands/__tests__/email-download.test.ts +245 -0
  114. package/src/cli/commands/__tests__/email-list.test.ts +192 -0
  115. package/src/cli/commands/__tests__/email-register.test.ts +186 -0
  116. package/src/cli/commands/__tests__/email-send.test.ts +291 -0
  117. package/src/cli/commands/__tests__/email-status.test.ts +181 -0
  118. package/src/cli/commands/__tests__/email-unregister.test.ts +139 -0
  119. package/src/cli/commands/__tests__/routes.test.ts +562 -0
  120. package/src/cli/commands/conversations.ts +1 -8
  121. package/src/cli/commands/default-action.ts +68 -1
  122. package/src/cli/commands/email.ts +584 -835
  123. package/src/cli/commands/memory.ts +1 -34
  124. package/src/cli/commands/notifications.ts +7 -2
  125. package/src/cli/commands/oauth/__tests__/connect.test.ts +27 -0
  126. package/src/cli/commands/oauth/connect.ts +25 -5
  127. package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
  128. package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
  129. package/src/cli/commands/platform/__tests__/status.test.ts +1 -1
  130. package/src/cli/commands/routes.ts +396 -0
  131. package/src/cli/commands/skills.ts +130 -20
  132. package/src/cli/program.ts +11 -2
  133. package/src/cli.ts +1 -120
  134. package/src/config/assistant-feature-flags.ts +59 -55
  135. package/src/config/bundled-skills/app-builder/SKILL.md +91 -5
  136. package/src/config/bundled-skills/gmail/SKILL.md +13 -8
  137. package/src/config/bundled-skills/gmail/TOOLS.json +1 -1
  138. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -1
  139. package/src/config/bundled-skills/messaging/SKILL.md +7 -0
  140. package/src/config/bundled-skills/schedule/SKILL.md +22 -2
  141. package/src/config/bundled-skills/schedule/TOOLS.json +8 -0
  142. package/src/config/bundled-skills/settings/TOOLS.json +1 -1
  143. package/src/config/bundled-skills/settings/tools/avatar-get.ts +3 -13
  144. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +2 -4
  145. package/src/config/bundled-skills/settings/tools/avatar-update.ts +5 -2
  146. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +8 -3
  147. package/src/config/bundled-skills/slack/SKILL.md +2 -0
  148. package/src/config/bundled-skills/subagent/SKILL.md +43 -3
  149. package/src/config/bundled-skills/subagent/TOOLS.json +29 -4
  150. package/src/config/env-registry.ts +63 -0
  151. package/src/config/feature-flag-registry.json +17 -1
  152. package/src/config/schema.ts +8 -0
  153. package/src/config/schemas/filing.ts +51 -0
  154. package/src/config/schemas/heartbeat.ts +15 -12
  155. package/src/config/schemas/memory-lifecycle.ts +12 -0
  156. package/src/config/schemas/security.ts +14 -0
  157. package/src/config/schemas/services.ts +8 -0
  158. package/src/credential-execution/approval-bridge.ts +0 -1
  159. package/src/credential-execution/managed-catalog.ts +3 -7
  160. package/src/daemon/app-source-watcher.ts +93 -0
  161. package/src/daemon/config-watcher.ts +85 -3
  162. package/src/daemon/context-overflow-approval.ts +0 -1
  163. package/src/daemon/conversation-agent-loop-handlers.ts +20 -0
  164. package/src/daemon/conversation-agent-loop.ts +179 -65
  165. package/src/daemon/conversation-attachments.ts +0 -1
  166. package/src/daemon/conversation-history.ts +4 -19
  167. package/src/daemon/conversation-lifecycle.ts +8 -14
  168. package/src/daemon/conversation-messaging.ts +3 -0
  169. package/src/daemon/conversation-process.ts +30 -8
  170. package/src/daemon/conversation-queue-manager.ts +8 -0
  171. package/src/daemon/conversation-runtime-assembly.ts +359 -308
  172. package/src/daemon/conversation-surfaces.ts +65 -0
  173. package/src/daemon/conversation-tool-setup.ts +44 -17
  174. package/src/daemon/conversation-workspace.ts +1 -2
  175. package/src/daemon/conversation.ts +19 -3
  176. package/src/daemon/date-context.ts +26 -53
  177. package/src/daemon/first-greeting.ts +1 -1
  178. package/src/daemon/handlers/conversations.ts +5 -7
  179. package/src/daemon/handlers/shared.test.ts +143 -0
  180. package/src/daemon/handlers/shared.ts +70 -5
  181. package/src/daemon/handlers/skills.ts +11 -18
  182. package/src/daemon/lifecycle.ts +220 -158
  183. package/src/daemon/message-types/conversations.ts +29 -6
  184. package/src/daemon/message-types/messages.ts +9 -2
  185. package/src/daemon/message-types/notifications.ts +12 -0
  186. package/src/daemon/message-types/schedules.ts +1 -0
  187. package/src/daemon/message-types/settings.ts +18 -0
  188. package/src/daemon/profiler-run-store.ts +557 -0
  189. package/src/daemon/server.ts +87 -10
  190. package/src/daemon/shutdown-handlers.ts +5 -0
  191. package/src/daemon/tool-side-effects.ts +23 -3
  192. package/src/daemon/transport-hints.ts +33 -0
  193. package/src/export/transcript-formatter.ts +148 -0
  194. package/src/filing/filing-service.ts +228 -0
  195. package/src/heartbeat/heartbeat-service.ts +96 -7
  196. package/src/index.ts +1 -1
  197. package/src/mcp/client.ts +6 -0
  198. package/src/mcp/mcp-oauth-provider.ts +149 -27
  199. package/src/memory/admin.ts +33 -32
  200. package/src/memory/app-store.ts +69 -0
  201. package/src/memory/conversation-bootstrap.ts +1 -1
  202. package/src/memory/conversation-crud.ts +151 -117
  203. package/src/memory/conversation-directories.ts +39 -0
  204. package/src/memory/conversation-group-migration.ts +66 -6
  205. package/src/memory/conversation-queries.ts +58 -12
  206. package/src/memory/conversation-title-service.ts +1 -0
  207. package/src/memory/db-init.ts +182 -376
  208. package/src/memory/embedding-local.ts +1 -1
  209. package/src/memory/graph/bootstrap.ts +75 -66
  210. package/src/memory/graph/capability-seed.ts +167 -17
  211. package/src/memory/graph/consolidation.ts +38 -4
  212. package/src/memory/graph/conversation-graph-memory.ts +133 -104
  213. package/src/memory/graph/extraction-job.ts +9 -4
  214. package/src/memory/graph/extraction.ts +66 -23
  215. package/src/memory/graph/graph-memory-state-store.ts +37 -0
  216. package/src/memory/graph/graph-search.ts +29 -15
  217. package/src/memory/graph/injection.ts +38 -8
  218. package/src/memory/graph/inspect.ts +12 -3
  219. package/src/memory/graph/retriever.ts +365 -262
  220. package/src/memory/graph/store.test.ts +48 -0
  221. package/src/memory/graph/store.ts +150 -11
  222. package/src/memory/graph/tool-handlers.ts +84 -209
  223. package/src/memory/graph/tools.ts +8 -52
  224. package/src/memory/graph/types.ts +24 -0
  225. package/src/memory/group-crud.ts +25 -9
  226. package/src/memory/job-handlers/cleanup.ts +44 -1
  227. package/src/memory/jobs-store.ts +70 -60
  228. package/src/memory/jobs-worker.ts +44 -28
  229. package/src/memory/llm-request-log-store.ts +96 -12
  230. package/src/memory/memory-recall-log-store.ts +49 -5
  231. package/src/memory/migrations/203-drop-memory-items-tables.ts +33 -1
  232. package/src/memory/migrations/206-memory-graph-node-edits.ts +19 -0
  233. package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +131 -0
  234. package/src/memory/migrations/207-conversation-graph-memory-state.ts +20 -0
  235. package/src/memory/migrations/208-conversations-last-message-at.ts +35 -0
  236. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +85 -0
  237. package/src/memory/migrations/210-schedule-reuse-conversation.ts +13 -0
  238. package/src/memory/migrations/211-memory-recall-logs-query-context.ts +21 -0
  239. package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +19 -0
  240. package/src/memory/migrations/index.ts +8 -0
  241. package/src/memory/migrations/registry.ts +8 -0
  242. package/src/memory/schema/conversations.ts +14 -0
  243. package/src/memory/schema/infrastructure.ts +8 -1
  244. package/src/memory/schema/memory-core.ts +0 -51
  245. package/src/memory/schema/memory-graph.ts +15 -0
  246. package/src/memory/task-memory-cleanup.ts +30 -11
  247. package/src/messaging/provider.ts +1 -1
  248. package/src/notifications/broadcaster.ts +6 -0
  249. package/src/notifications/conversation-pairing.ts +12 -4
  250. package/src/notifications/copy-composer.ts +86 -0
  251. package/src/notifications/decision-engine.ts +35 -0
  252. package/src/notifications/emit-signal.ts +14 -0
  253. package/src/notifications/signal.ts +11 -0
  254. package/src/oauth/platform-connection.test.ts +2 -2
  255. package/src/oauth/seed-providers.ts +1 -0
  256. package/src/permissions/checker.ts +15 -4
  257. package/src/permissions/defaults.ts +7 -8
  258. package/src/permissions/permission-mode-store.ts +180 -0
  259. package/src/permissions/permission-mode.ts +31 -0
  260. package/src/permissions/prompter.ts +0 -2
  261. package/src/permissions/workspace-policy.ts +9 -0
  262. package/src/platform/client.ts +1 -1
  263. package/src/prompts/system-prompt.ts +59 -7
  264. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +100 -0
  265. package/src/prompts/templates/BOOTSTRAP.md +76 -162
  266. package/src/prompts/templates/HEARTBEAT.md +3 -1
  267. package/src/prompts/templates/SOUL.md +30 -9
  268. package/src/prompts/templates/UPDATES.md +8 -0
  269. package/src/providers/anthropic/client.ts +107 -219
  270. package/src/runtime/assistant-event-hub.ts +22 -0
  271. package/src/runtime/auth/route-policy.ts +23 -0
  272. package/src/runtime/auth/token-service.ts +8 -0
  273. package/src/runtime/http-server.ts +32 -2
  274. package/src/runtime/http-types.ts +12 -1
  275. package/src/runtime/migrations/vbundle-builder.ts +389 -3
  276. package/src/runtime/migrations/vbundle-importer.ts +8 -6
  277. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +378 -0
  278. package/src/runtime/routes/app-management-routes.ts +1 -11
  279. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +26 -0
  280. package/src/runtime/routes/archive-utils.ts +29 -0
  281. package/src/runtime/routes/avatar-routes.ts +2 -9
  282. package/src/runtime/routes/btw-routes.ts +14 -1
  283. package/src/runtime/routes/conversation-analysis-routes.ts +185 -0
  284. package/src/runtime/routes/conversation-management-routes.ts +1 -14
  285. package/src/runtime/routes/conversation-query-routes.ts +49 -3
  286. package/src/runtime/routes/conversation-routes.ts +270 -44
  287. package/src/runtime/routes/group-routes.ts +22 -8
  288. package/src/runtime/routes/heartbeat-routes.ts +4 -10
  289. package/src/runtime/routes/identity-routes.ts +53 -18
  290. package/src/runtime/routes/llm-context-normalization.ts +14 -10
  291. package/src/runtime/routes/log-export/AGENTS.md +104 -0
  292. package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +103 -0
  293. package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +716 -0
  294. package/src/runtime/routes/log-export/workspace-allowlist.ts +458 -0
  295. package/src/runtime/routes/log-export-routes.ts +41 -278
  296. package/src/runtime/routes/memory-item-routes.test.ts +168 -233
  297. package/src/runtime/routes/migration-routes.ts +18 -7
  298. package/src/runtime/routes/profiler-routes.ts +350 -0
  299. package/src/runtime/routes/schedule-routes.ts +27 -12
  300. package/src/runtime/routes/settings-routes.ts +95 -8
  301. package/src/runtime/routes/subagents-routes.ts +28 -7
  302. package/src/runtime/routes/user-route-dispatcher.ts +223 -0
  303. package/src/runtime/routes/user-routes.ts +41 -0
  304. package/src/runtime/routes/workspace-routes.ts +0 -1
  305. package/src/schedule/schedule-store.ts +30 -0
  306. package/src/schedule/scheduler.ts +45 -18
  307. package/src/skills/catalog-install.ts +10 -2
  308. package/src/skills/inline-command-runner.ts +12 -14
  309. package/src/skills/managed-store.ts +2 -2
  310. package/src/skills/skill-memory.ts +1 -293
  311. package/src/subagent/index.ts +13 -3
  312. package/src/subagent/manager.ts +308 -29
  313. package/src/subagent/types.ts +68 -0
  314. package/src/tasks/task-runner.ts +4 -4
  315. package/src/tools/apps/executors.ts +29 -4
  316. package/src/tools/filesystem/list.ts +93 -0
  317. package/src/tools/permission-checker.ts +78 -18
  318. package/src/tools/registry.ts +4 -0
  319. package/src/tools/schedule/create.ts +3 -0
  320. package/src/tools/schedule/list.ts +1 -0
  321. package/src/tools/schedule/update.ts +6 -0
  322. package/src/tools/secret-detection-handler.ts +0 -1
  323. package/src/tools/shared/filesystem/errors.ts +5 -0
  324. package/src/tools/shared/filesystem/file-ops-service.ts +90 -2
  325. package/src/tools/shared/filesystem/types.ts +17 -0
  326. package/src/tools/shared/shell-output.ts +31 -2
  327. package/src/tools/skills/sandbox-runner.ts +3 -6
  328. package/src/tools/subagent/abort.ts +12 -2
  329. package/src/tools/subagent/message.ts +9 -2
  330. package/src/tools/subagent/notify-parent.ts +79 -0
  331. package/src/tools/subagent/read.ts +29 -8
  332. package/src/tools/subagent/resolve.ts +21 -0
  333. package/src/tools/subagent/spawn.ts +2 -0
  334. package/src/tools/subagent/status.ts +11 -1
  335. package/src/tools/system/avatar-generator.ts +3 -3
  336. package/src/tools/system/register.ts +23 -0
  337. package/src/tools/system/set-permission-mode.ts +103 -0
  338. package/src/tools/terminal/parser.ts +30 -5
  339. package/src/tools/terminal/safe-env.ts +16 -1
  340. package/src/tools/terminal/sandbox-diagnostics.ts +4 -4
  341. package/src/tools/terminal/sandbox.ts +4 -1
  342. package/src/tools/terminal/shell.ts +3 -5
  343. package/src/tools/tool-manifest.ts +6 -0
  344. package/src/tools/types.ts +2 -3
  345. package/src/util/logger.ts +1 -1
  346. package/src/util/platform.ts +50 -17
  347. package/src/watcher/provider-types.ts +1 -1
  348. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +2 -2
  349. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +2 -2
  350. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +270 -0
  351. package/src/workspace/migrations/029-seed-pkb.ts +85 -0
  352. package/src/workspace/migrations/030-seed-pkb-autoinject.ts +73 -0
  353. package/src/workspace/migrations/registry.ts +6 -0
  354. package/src/workspace/top-level-renderer.ts +5 -9
  355. package/src/__tests__/cli-memory.test.ts +0 -377
  356. package/src/__tests__/clipboard.test.ts +0 -88
  357. package/src/cli/cli-memory.ts +0 -179
  358. package/src/util/clipboard.ts +0 -34
@@ -26,6 +26,45 @@ export function getConversationDirName(
26
26
  return `${getConversationDirTimestamp(createdAtMs)}_${id}`;
27
27
  }
28
28
 
29
+ /**
30
+ * Parse a canonical conversation directory name (`<ISO-with-dashes>_<id>`)
31
+ * back into its components. Returns null for names that don't match the
32
+ * canonical format — callers should treat null as "skip this entry"
33
+ * rather than as an error.
34
+ *
35
+ * Inverse of {@link getConversationDirName}. Does NOT parse the legacy
36
+ * `<id>_<ISO-with-dashes>` format.
37
+ */
38
+ export function parseConversationDirName(
39
+ name: string,
40
+ ): { conversationId: string; createdAtMs: number } | null {
41
+ // Canonical format: YYYY-MM-DDTHH-MM-SS.sssZ_<uuid>
42
+ // The timestamp portion has 4 hyphens (date + time-component separators)
43
+ // and ends in `Z`. Anchor the regex to enforce that.
44
+ const match = name.match(
45
+ /^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2}\.\d{1,9}Z)_(.+)$/,
46
+ );
47
+ if (!match) return null;
48
+ const [, datePart, hh, mm, ssAndMs, conversationId] = match;
49
+ const iso = `${datePart}T${hh}:${mm}:${ssAndMs}`;
50
+ const ms = Date.parse(iso);
51
+ if (Number.isNaN(ms)) return null;
52
+ if (!conversationId) return null;
53
+ // Reject conversation IDs that are path-traversal-shaped or contain
54
+ // path separators. These are never valid conversation IDs and would
55
+ // be a defense-in-depth concern if parsed.conversationId is later used
56
+ // to construct filesystem paths.
57
+ if (
58
+ conversationId === "." ||
59
+ conversationId === ".." ||
60
+ conversationId.includes("/") ||
61
+ conversationId.includes("\\")
62
+ ) {
63
+ return null;
64
+ }
65
+ return { conversationId, createdAtMs: ms };
66
+ }
67
+
29
68
  /**
30
69
  * Return the absolute path to a conversation's timestamp-first disk-view
31
70
  * directory.
@@ -57,15 +57,45 @@ export function ensureGroupMigration(): void {
57
57
  }
58
58
  }
59
59
 
60
- // 3. Seed system groups (three: pinned, scheduled, background)
60
+ // 3. Seed system groups (four: pinned, scheduled, background, all)
61
+ const now = Math.floor(Date.now() / 1000);
61
62
  rawExec(`
62
- INSERT OR IGNORE INTO conversation_groups (id, name, sort_position, is_system_group)
63
+ INSERT OR IGNORE INTO conversation_groups (id, name, sort_position, is_system_group, created_at, updated_at)
63
64
  VALUES
64
- ('system:pinned', 'Pinned', 0, TRUE),
65
- ('system:scheduled', 'Scheduled', 1, TRUE),
66
- ('system:background', 'Background', 2, TRUE)
65
+ ('system:pinned', 'Pinned', 0, TRUE, ${now}, ${now}),
66
+ ('system:scheduled', 'Scheduled', 1, TRUE, ${now}, ${now}),
67
+ ('system:background', 'Background', 2, TRUE, ${now}, ${now}),
68
+ ('system:all', 'Recents', 3, TRUE, ${now}, ${now})
67
69
  `);
68
70
 
71
+ // One-time migration: move system:all to sortPosition 3 (from 999999).
72
+ // Bump custom groups at position 3+ up by 1 to make room. Wrapped in a
73
+ // transaction so a crash between the shift and the sentinel can't cause
74
+ // repeated drift on restart.
75
+ const sortShiftDone = rawGet<{ id: string }>(
76
+ "SELECT id FROM conversation_groups WHERE id = '_sort_shift_complete'",
77
+ );
78
+ if (!sortShiftDone) {
79
+ try {
80
+ rawExec("BEGIN");
81
+ rawRun(
82
+ "UPDATE conversation_groups SET sort_position = sort_position + 1 WHERE is_system_group = 0 AND sort_position >= 3",
83
+ );
84
+ rawRun(
85
+ "UPDATE conversation_groups SET sort_position = 3 WHERE id = 'system:all' AND sort_position != 3",
86
+ );
87
+ rawRun(
88
+ `INSERT OR IGNORE INTO conversation_groups (id, name, sort_position, is_system_group, created_at, updated_at)
89
+ VALUES ('_sort_shift_complete', '_sort_shift_complete', -1, TRUE, ${now}, ${now})`,
90
+ );
91
+ rawExec("COMMIT");
92
+ } catch (err) {
93
+ rawExec("ROLLBACK");
94
+ log.error({ err }, "Sort-position shift transaction failed, rolled back");
95
+ throw err;
96
+ }
97
+ }
98
+
69
99
  // 4. One-time backfill (guard: persistent marker prevents re-running on restart)
70
100
  //
71
101
  // The backfill sets group_id on existing conversations based on their attributes.
@@ -118,7 +148,7 @@ export function ensureGroupMigration(): void {
118
148
  // Step B: Scheduled -> system:scheduled (schedule/reminder source or has schedule_job_id)
119
149
  rawExec(`
120
150
  UPDATE conversations SET group_id = 'system:scheduled'
121
- WHERE (source IN ('schedule', 'reminder') OR schedule_job_id IS NOT NULL)
151
+ WHERE (source IN ('schedule', 'reminder') OR schedule_job_id IS NOT NULL OR conversation_type = 'scheduled')
122
152
  AND group_id IS NULL
123
153
  `);
124
154
 
@@ -153,5 +183,35 @@ export function ensureGroupMigration(): void {
153
183
  }
154
184
  }
155
185
 
186
+ // 5. One-time backfill: assign all ungrouped conversations to system:all
187
+ //
188
+ // Separate from the initial backfill above because system:all is added later.
189
+ // Uses its own sentinel so it runs exactly once, even on existing installations
190
+ // where the original backfill already completed.
191
+ const allBackfillDone = rawGet<{ id: string }>(
192
+ "SELECT id FROM conversation_groups WHERE id = '_backfill_all_complete'",
193
+ );
194
+
195
+ if (!allBackfillDone) {
196
+ try {
197
+ rawExec("BEGIN");
198
+
199
+ rawExec(`
200
+ UPDATE conversations SET group_id = 'system:all' WHERE group_id IS NULL
201
+ `);
202
+
203
+ rawExec(`
204
+ INSERT OR IGNORE INTO conversation_groups (id, name, sort_position, is_system_group)
205
+ VALUES ('_backfill_all_complete', '_backfill_all_complete', -1, TRUE)
206
+ `);
207
+
208
+ rawExec("COMMIT");
209
+ } catch (err) {
210
+ rawExec("ROLLBACK");
211
+ log.error({ err }, "system:all backfill transaction failed, rolled back");
212
+ throw err;
213
+ }
214
+ }
215
+
156
216
  migrated = true;
157
217
  }
@@ -14,7 +14,22 @@ const log = getLogger("conversation-store");
14
14
  * Build an FTS5 MATCH query string from natural text by extracting tokens.
15
15
  * Used for messages_fts full-text search over conversation content.
16
16
  */
17
- export function buildFtsMatchQuery(text: string): string | null {
17
+ export function buildFtsMatchQuery(
18
+ text: string,
19
+ opts?: { allowFts5Syntax?: boolean },
20
+ ): string | null {
21
+ // If the query already contains FTS5 operators, pass it through directly
22
+ // so callers (e.g. the archive recall tool) can use exact-phrase, AND, OR,
23
+ // NOT, NEAR syntax. Only enabled when the caller explicitly opts in —
24
+ // user-facing search should always go through normal tokenization to avoid
25
+ // FTS5 boolean semantics leaking into sidebar/global search.
26
+ if (
27
+ opts?.allowFts5Syntax &&
28
+ /\bAND\b|\bOR\b|\bNOT\b|\bNEAR\s*\(|"[^"]+"/.test(text)
29
+ ) {
30
+ return text.trim();
31
+ }
32
+
18
33
  const tokens = text
19
34
  .toLowerCase()
20
35
  .split(/[^a-z0-9_]+/g)
@@ -22,7 +37,8 @@ export function buildFtsMatchQuery(text: string): string | null {
22
37
  .filter((token) => token.length >= 2);
23
38
  if (tokens.length === 0) return null;
24
39
  const unique = [...new Set(tokens)].slice(0, 24);
25
- return unique.map((token) => `"${token.replace(/"/g, '""')}"`).join(" OR ");
40
+ // Space-separated quoted tokens are implicit AND in FTS5.
41
+ return unique.map((token) => `"${token.replace(/"/g, '""')}"`).join(" ");
26
42
  }
27
43
 
28
44
  export function listConversations(
@@ -34,23 +50,49 @@ export function listConversations(
34
50
  ensureGroupMigration();
35
51
  const db = getDb();
36
52
  const where = backgroundOnly
37
- ? sql`${conversations.conversationType} = 'background'`
38
- : sql`${conversations.conversationType} NOT IN ('background', 'private')`;
53
+ ? sql`${conversations.conversationType} IN ('background', 'scheduled') AND (${conversations.source} IS NULL OR ${conversations.source} != 'subagent')`
54
+ : sql`${conversations.conversationType} NOT IN ('background', 'private', 'scheduled')`;
39
55
  const query = db
40
56
  .select()
41
57
  .from(conversations)
42
58
  .where(where)
43
- .orderBy(desc(conversations.updatedAt))
59
+ .orderBy(
60
+ desc(
61
+ sql`COALESCE(${conversations.lastMessageAt}, ${conversations.updatedAt})`,
62
+ ),
63
+ )
44
64
  .limit(limit ?? 100)
45
65
  .offset(offset);
46
66
  return query.all().map(parseConversation);
47
67
  }
48
68
 
69
+ export function listPinnedConversations(): ConversationRow[] {
70
+ ensureDisplayOrderMigration();
71
+ ensureGroupMigration();
72
+ const db = getDb();
73
+ const query = db
74
+ .select()
75
+ .from(conversations)
76
+ .where(
77
+ and(
78
+ sql`${conversations.conversationType} NOT IN ('background', 'private', 'scheduled')`,
79
+ sql`is_pinned = 1`,
80
+ ),
81
+ )
82
+ .orderBy(
83
+ sql`COALESCE(display_order, 999999) ASC`,
84
+ desc(
85
+ sql`COALESCE(${conversations.lastMessageAt}, ${conversations.updatedAt})`,
86
+ ),
87
+ );
88
+ return query.all().map(parseConversation);
89
+ }
90
+
49
91
  export function countConversations(backgroundOnly = false): number {
50
92
  const db = getDb();
51
93
  const where = backgroundOnly
52
- ? sql`${conversations.conversationType} = 'background'`
53
- : sql`${conversations.conversationType} NOT IN ('background', 'private')`;
94
+ ? sql`${conversations.conversationType} IN ('background', 'scheduled') AND (${conversations.source} IS NULL OR ${conversations.source} != 'subagent')`
95
+ : sql`${conversations.conversationType} NOT IN ('background', 'private', 'scheduled')`;
54
96
  const [{ total }] = db
55
97
  .select({ total: count() })
56
98
  .from(conversations)
@@ -65,9 +107,13 @@ export function getLatestConversation(): ConversationRow | null {
65
107
  .select()
66
108
  .from(conversations)
67
109
  .where(
68
- sql`${conversations.conversationType} NOT IN ('background', 'private')`,
110
+ sql`${conversations.conversationType} NOT IN ('background', 'private', 'scheduled')`,
111
+ )
112
+ .orderBy(
113
+ desc(
114
+ sql`COALESCE(${conversations.lastMessageAt}, ${conversations.updatedAt})`,
115
+ ),
69
116
  )
70
- .orderBy(desc(conversations.updatedAt))
71
117
  .limit(1)
72
118
  .get();
73
119
  return row ? parseConversation(row) : null;
@@ -172,7 +218,7 @@ export function searchConversations(
172
218
  FROM messages_fts f
173
219
  JOIN messages m ON m.id = f.message_id
174
220
  JOIN conversations c ON c.id = m.conversation_id
175
- WHERE messages_fts MATCH ? AND c.conversation_type NOT IN ('background', 'private')
221
+ WHERE messages_fts MATCH ? AND c.conversation_type NOT IN ('background', 'private', 'scheduled')
176
222
  LIMIT 1000
177
223
  `,
178
224
  ftsMatch,
@@ -197,7 +243,7 @@ export function searchConversations(
197
243
  SELECT DISTINCT m.conversation_id
198
244
  FROM messages m
199
245
  JOIN conversations c ON c.id = m.conversation_id
200
- WHERE m.content LIKE ? ESCAPE '\\' AND c.conversation_type NOT IN ('background', 'private')
246
+ WHERE m.content LIKE ? ESCAPE '\\' AND c.conversation_type NOT IN ('background', 'private', 'scheduled')
201
247
  LIMIT 1000
202
248
  `,
203
249
  likePattern,
@@ -211,7 +257,7 @@ export function searchConversations(
211
257
  .from(conversations)
212
258
  .where(
213
259
  and(
214
- sql`${conversations.conversationType} NOT IN ('background', 'private')`,
260
+ sql`${conversations.conversationType} NOT IN ('background', 'private', 'scheduled')`,
215
261
  sql`${conversations.title} LIKE ${titlePattern} ESCAPE '\\'`,
216
262
  ),
217
263
  )
@@ -34,6 +34,7 @@ export type TitleOrigin =
34
34
  | "subagent"
35
35
  | "sequence"
36
36
  | "heartbeat"
37
+ | "filing"
37
38
  | "local"
38
39
  | "task_submit"
39
40
  | "misc";