@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
@@ -0,0 +1,101 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { PermissionsConfigSchema } from "../config/schemas/security.js";
4
+ import {
5
+ DEFAULT_PERMISSION_MODE,
6
+ PermissionModeSchema,
7
+ } from "../permissions/permission-mode.js";
8
+
9
+ // ---------------------------------------------------------------------------
10
+ // Tests: PermissionModeSchema
11
+ // ---------------------------------------------------------------------------
12
+
13
+ describe("PermissionModeSchema", () => {
14
+ test("parses empty object with correct defaults", () => {
15
+ const result = PermissionModeSchema.parse({});
16
+ expect(result.askBeforeActing).toBe(true);
17
+ expect(result.hostAccess).toBe(false);
18
+ });
19
+
20
+ test("DEFAULT_PERMISSION_MODE matches schema defaults", () => {
21
+ const parsed = PermissionModeSchema.parse({});
22
+ expect(parsed).toEqual(DEFAULT_PERMISSION_MODE);
23
+ });
24
+
25
+ test("accepts explicit true/true", () => {
26
+ const result = PermissionModeSchema.parse({
27
+ askBeforeActing: true,
28
+ hostAccess: true,
29
+ });
30
+ expect(result.askBeforeActing).toBe(true);
31
+ expect(result.hostAccess).toBe(true);
32
+ });
33
+
34
+ test("accepts explicit false/false", () => {
35
+ const result = PermissionModeSchema.parse({
36
+ askBeforeActing: false,
37
+ hostAccess: false,
38
+ });
39
+ expect(result.askBeforeActing).toBe(false);
40
+ expect(result.hostAccess).toBe(false);
41
+ });
42
+
43
+ test("round-trips through JSON serialization", () => {
44
+ const original = { askBeforeActing: false, hostAccess: true };
45
+ const json = JSON.stringify(original);
46
+ const parsed = PermissionModeSchema.parse(JSON.parse(json));
47
+ expect(parsed).toEqual(original);
48
+ });
49
+
50
+ test("rejects non-boolean askBeforeActing", () => {
51
+ expect(() =>
52
+ PermissionModeSchema.parse({ askBeforeActing: "yes" }),
53
+ ).toThrow();
54
+ });
55
+
56
+ test("rejects non-boolean hostAccess", () => {
57
+ expect(() => PermissionModeSchema.parse({ hostAccess: "no" })).toThrow();
58
+ });
59
+ });
60
+
61
+ // ---------------------------------------------------------------------------
62
+ // Tests: PermissionsConfigSchema (permissionMode fields)
63
+ // ---------------------------------------------------------------------------
64
+
65
+ describe("PermissionsConfigSchema permissionMode fields", () => {
66
+ test("defaults askBeforeActing to true and hostAccess to false", () => {
67
+ const result = PermissionsConfigSchema.parse({});
68
+ expect(result.askBeforeActing).toBe(true);
69
+ expect(result.hostAccess).toBe(false);
70
+ });
71
+
72
+ test("preserves existing mode field alongside new fields", () => {
73
+ const result = PermissionsConfigSchema.parse({ mode: "strict" });
74
+ expect(result.mode).toBe("strict");
75
+ expect(result.askBeforeActing).toBe(true);
76
+ expect(result.hostAccess).toBe(false);
77
+ });
78
+
79
+ test("accepts overridden values for new fields", () => {
80
+ const result = PermissionsConfigSchema.parse({
81
+ mode: "workspace",
82
+ askBeforeActing: false,
83
+ hostAccess: true,
84
+ });
85
+ expect(result.mode).toBe("workspace");
86
+ expect(result.askBeforeActing).toBe(false);
87
+ expect(result.hostAccess).toBe(true);
88
+ });
89
+
90
+ test("round-trips new fields through JSON serialization", () => {
91
+ const input = {
92
+ mode: "workspace" as const,
93
+ askBeforeActing: false,
94
+ hostAccess: true,
95
+ };
96
+ const json = JSON.stringify(input);
97
+ const parsed = PermissionsConfigSchema.parse(JSON.parse(json));
98
+ expect(parsed.askBeforeActing).toBe(false);
99
+ expect(parsed.hostAccess).toBe(true);
100
+ });
101
+ });
@@ -0,0 +1,96 @@
1
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
5
+
6
+ import { readAutoinjectList } from "../daemon/conversation-runtime-assembly.js";
7
+
8
+ // ---------------------------------------------------------------------------
9
+ // Setup / Teardown
10
+ // ---------------------------------------------------------------------------
11
+
12
+ let pkbDir: string;
13
+ const dirs: string[] = [];
14
+
15
+ beforeEach(() => {
16
+ pkbDir = join(
17
+ tmpdir(),
18
+ `vellum-pkb-autoinject-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
19
+ );
20
+ mkdirSync(pkbDir, { recursive: true });
21
+ dirs.push(pkbDir);
22
+ });
23
+
24
+ afterEach(() => {
25
+ for (const dir of dirs.splice(0)) {
26
+ rmSync(dir, { recursive: true, force: true });
27
+ }
28
+ });
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Tests
32
+ // ---------------------------------------------------------------------------
33
+
34
+ describe("readAutoinjectList", () => {
35
+ test("returns null when _autoinject.md does not exist", () => {
36
+ expect(readAutoinjectList(pkbDir)).toBeNull();
37
+ });
38
+
39
+ test("returns empty array when _autoinject.md is empty", () => {
40
+ writeFileSync(join(pkbDir, "_autoinject.md"), "", "utf-8");
41
+ expect(readAutoinjectList(pkbDir)).toEqual([]);
42
+ });
43
+
44
+ test("returns empty array when _autoinject.md contains only comments", () => {
45
+ writeFileSync(
46
+ join(pkbDir, "_autoinject.md"),
47
+ "_ This is a comment\n_ Another comment\n",
48
+ "utf-8",
49
+ );
50
+ expect(readAutoinjectList(pkbDir)).toEqual([]);
51
+ });
52
+
53
+ test("parses standard default content", () => {
54
+ writeFileSync(
55
+ join(pkbDir, "_autoinject.md"),
56
+ "_ comment\n\nINDEX.md\nessentials.md\nthreads.md\nbuffer.md\n",
57
+ "utf-8",
58
+ );
59
+ expect(readAutoinjectList(pkbDir)).toEqual([
60
+ "INDEX.md",
61
+ "essentials.md",
62
+ "threads.md",
63
+ "buffer.md",
64
+ ]);
65
+ });
66
+
67
+ test("parses custom entries", () => {
68
+ writeFileSync(
69
+ join(pkbDir, "_autoinject.md"),
70
+ "INDEX.md\ncustom-topic.md\n",
71
+ "utf-8",
72
+ );
73
+ expect(readAutoinjectList(pkbDir)).toEqual([
74
+ "INDEX.md",
75
+ "custom-topic.md",
76
+ ]);
77
+ });
78
+
79
+ test("strips blank lines and whitespace", () => {
80
+ writeFileSync(
81
+ join(pkbDir, "_autoinject.md"),
82
+ "INDEX.md\n\n essentials.md \n\n",
83
+ "utf-8",
84
+ );
85
+ expect(readAutoinjectList(pkbDir)).toEqual(["INDEX.md", "essentials.md"]);
86
+ });
87
+
88
+ test("strips comment lines mixed with filenames", () => {
89
+ writeFileSync(
90
+ join(pkbDir, "_autoinject.md"),
91
+ "_ Always loaded files\nINDEX.md\n_ Core facts\nessentials.md\n",
92
+ "utf-8",
93
+ );
94
+ expect(readAutoinjectList(pkbDir)).toEqual(["INDEX.md", "essentials.md"]);
95
+ });
96
+ });
@@ -0,0 +1,359 @@
1
+ /**
2
+ * Tests for platform-hosted bash auto-approval.
3
+ *
4
+ * Verifies that bash and host_bash tools are auto-approved without prompting
5
+ * when running in platform-hosted mode (IS_PLATFORM=true) for guardian actors.
6
+ * Also verifies that deny rules, non-guardian actors, requireFreshApproval,
7
+ * and non-bash tools are unaffected by this auto-approval path.
8
+ */
9
+
10
+ import {
11
+ afterAll,
12
+ afterEach,
13
+ beforeEach,
14
+ describe,
15
+ expect,
16
+ mock,
17
+ test,
18
+ } from "bun:test";
19
+
20
+ import type { ScopeOption } from "../permissions/types.js";
21
+ import type { ToolExecutionResult } from "../tools/types.js";
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Mock setup — mirrors require-fresh-approval.test.ts patterns
25
+ // ---------------------------------------------------------------------------
26
+
27
+ const mockConfig = {
28
+ provider: "anthropic",
29
+ model: "test",
30
+ maxTokens: 4096,
31
+ dataDir: "/tmp",
32
+ timeouts: {
33
+ shellDefaultTimeoutSec: 120,
34
+ shellMaxTimeoutSec: 600,
35
+ permissionTimeoutSec: 300,
36
+ },
37
+ sandbox: {
38
+ enabled: false,
39
+ backend: "native" as const,
40
+ docker: {
41
+ image: "vellum-sandbox:latest",
42
+ cpus: 1,
43
+ memoryMb: 512,
44
+ pidsLimit: 256,
45
+ network: "none" as const,
46
+ },
47
+ },
48
+ rateLimit: { maxRequestsPerMinute: 0 },
49
+ secretDetection: {
50
+ enabled: false,
51
+ action: "warn" as const,
52
+ entropyThreshold: 4.0,
53
+ },
54
+ permissions: {
55
+ mode: "workspace" as const,
56
+ },
57
+ };
58
+
59
+ let fakeToolResult: ToolExecutionResult = { content: "ok", isError: false };
60
+
61
+ /** Override the check() result for specific tests. */
62
+ let checkResultOverride: { decision: string; reason: string } | undefined;
63
+
64
+ /** Override the risk level returned by classifyRisk(). Defaults to "medium". */
65
+ let riskOverride: string = "medium";
66
+
67
+ /** Scope options override. */
68
+ let scopeOptionsOverride: ScopeOption[] | undefined;
69
+
70
+ mock.module("../config/loader.js", () => ({
71
+ getConfig: () => mockConfig,
72
+ loadConfig: () => mockConfig,
73
+ invalidateConfigCache: () => {},
74
+ saveConfig: () => {},
75
+ loadRawConfig: () => ({}),
76
+ saveRawConfig: () => {},
77
+ getNestedValue: () => undefined,
78
+ setNestedValue: () => {},
79
+ }));
80
+
81
+ mock.module("../util/logger.js", () => ({
82
+ getLogger: () =>
83
+ new Proxy({} as Record<string, unknown>, {
84
+ get: () => () => {},
85
+ }),
86
+ truncateForLog: (value: string) => value,
87
+ }));
88
+
89
+ mock.module("../permissions/checker.js", () => ({
90
+ classifyRisk: async () => riskOverride,
91
+ check: async () => {
92
+ if (checkResultOverride) return checkResultOverride;
93
+ return { decision: "allow", reason: "allowed" };
94
+ },
95
+ generateAllowlistOptions: () => [
96
+ { label: "exact", description: "exact", pattern: "exact" },
97
+ ],
98
+ generateScopeOptions: () =>
99
+ scopeOptionsOverride ?? [{ label: "/tmp", scope: "/tmp" }],
100
+ }));
101
+
102
+ mock.module("../memory/tool-usage-store.js", () => ({
103
+ recordToolInvocation: () => {},
104
+ }));
105
+
106
+ mock.module("../tools/registry.js", () => ({
107
+ getTool: (name: string) => {
108
+ if (name === "unknown_tool") return undefined;
109
+ return {
110
+ name,
111
+ description: "test tool",
112
+ category: "shell",
113
+ defaultRiskLevel: "medium",
114
+ getDefinition: () => ({}),
115
+ execute: async () => fakeToolResult,
116
+ };
117
+ },
118
+ getAllTools: () => [],
119
+ }));
120
+
121
+ mock.module("../tools/shared/filesystem/path-policy.js", () => ({
122
+ sandboxPolicy: () => ({ ok: false }),
123
+ hostPolicy: () => ({ ok: false }),
124
+ }));
125
+
126
+ mock.module("../tools/terminal/sandbox.js", () => ({
127
+ wrapCommand: () => ({ command: "", sandboxed: false }),
128
+ }));
129
+
130
+ mock.module("../approvals/approval-primitive.js", () => ({
131
+ consumeGrantForInvocation: async () => ({ ok: false, reason: "no_grant" }),
132
+ }));
133
+
134
+ import { PermissionPrompter } from "../permissions/prompter.js";
135
+ import { clearAll as clearAllOverrides } from "../runtime/conversation-approval-overrides.js";
136
+ import { ToolExecutor } from "../tools/executor.js";
137
+ import type { ToolContext as TC } from "../tools/types.js";
138
+
139
+ function makeContext(overrides?: Partial<TC>): TC {
140
+ return {
141
+ workingDir: "/tmp/project",
142
+ conversationId: "conversation-1",
143
+ trustClass: "guardian",
144
+ isInteractive: true,
145
+ ...overrides,
146
+ };
147
+ }
148
+
149
+ function makePrompter(): PermissionPrompter {
150
+ return {
151
+ prompt: async () => ({ decision: "allow" as const }),
152
+ resolveConfirmation: () => {},
153
+ updateSender: () => {},
154
+ dispose: () => {},
155
+ } as unknown as PermissionPrompter;
156
+ }
157
+
158
+ afterAll(() => {
159
+ mock.restore();
160
+ });
161
+
162
+ // ---------------------------------------------------------------------------
163
+ // Platform-hosted bash auto-approval
164
+ // ---------------------------------------------------------------------------
165
+
166
+ describe("platform-hosted bash auto-approval", () => {
167
+ beforeEach(() => {
168
+ fakeToolResult = { content: "ok", isError: false };
169
+ checkResultOverride = undefined;
170
+ scopeOptionsOverride = undefined;
171
+ riskOverride = "medium";
172
+ clearAllOverrides();
173
+ });
174
+
175
+ afterEach(() => {
176
+ clearAllOverrides();
177
+ });
178
+
179
+ test("bash auto-approved in platform-hosted mode", async () => {
180
+ checkResultOverride = { decision: "prompt", reason: "Needs approval" };
181
+
182
+ let promptCalled = false;
183
+ const trackingPrompter = {
184
+ prompt: async () => {
185
+ promptCalled = true;
186
+ return { decision: "allow" as const };
187
+ },
188
+ resolveConfirmation: () => {},
189
+ updateSender: () => {},
190
+ dispose: () => {},
191
+ } as unknown as PermissionPrompter;
192
+
193
+ const executor = new ToolExecutor(trackingPrompter);
194
+ const result = await executor.execute(
195
+ "bash",
196
+ { command: "echo hello" },
197
+ makeContext({ isPlatformHosted: true, trustClass: "guardian" }),
198
+ );
199
+
200
+ expect(promptCalled).toBe(false);
201
+ expect(result.isError).toBe(false);
202
+ });
203
+
204
+ test("host_bash NOT auto-approved in platform-hosted mode", async () => {
205
+ checkResultOverride = { decision: "prompt", reason: "Needs approval" };
206
+
207
+ let promptCalled = false;
208
+ const trackingPrompter = {
209
+ prompt: async () => {
210
+ promptCalled = true;
211
+ return { decision: "allow" as const };
212
+ },
213
+ resolveConfirmation: () => {},
214
+ updateSender: () => {},
215
+ dispose: () => {},
216
+ } as unknown as PermissionPrompter;
217
+
218
+ const executor = new ToolExecutor(trackingPrompter);
219
+ await executor.execute(
220
+ "host_bash",
221
+ { command: "echo hello" },
222
+ makeContext({ isPlatformHosted: true, trustClass: "guardian" }),
223
+ );
224
+
225
+ expect(promptCalled).toBe(true);
226
+ });
227
+
228
+ test("bash NOT auto-approved when not platform-hosted", async () => {
229
+ checkResultOverride = { decision: "prompt", reason: "Needs approval" };
230
+
231
+ let promptCalled = false;
232
+ const trackingPrompter = {
233
+ prompt: async () => {
234
+ promptCalled = true;
235
+ return { decision: "allow" as const };
236
+ },
237
+ resolveConfirmation: () => {},
238
+ updateSender: () => {},
239
+ dispose: () => {},
240
+ } as unknown as PermissionPrompter;
241
+
242
+ const executor = new ToolExecutor(trackingPrompter);
243
+ await executor.execute(
244
+ "bash",
245
+ { command: "echo hello" },
246
+ makeContext({ isPlatformHosted: false, trustClass: "guardian" }),
247
+ );
248
+
249
+ expect(promptCalled).toBe(true);
250
+ });
251
+
252
+ test("bash NOT auto-approved for non-guardian actors", async () => {
253
+ checkResultOverride = { decision: "prompt", reason: "Needs approval" };
254
+
255
+ const executor = new ToolExecutor(makePrompter());
256
+ const result = await executor.execute(
257
+ "bash",
258
+ { command: "echo hello" },
259
+ makeContext({ isPlatformHosted: true, trustClass: "trusted_contact" }),
260
+ );
261
+
262
+ // Non-guardian actors are blocked by the pre-execution guardian approval
263
+ // gate before reaching the permission checker. The tool must NOT succeed
264
+ // via platform auto-approve.
265
+ expect(result.isError).toBe(true);
266
+ });
267
+
268
+ test("bash NOT auto-approved when requireFreshApproval is set", async () => {
269
+ checkResultOverride = { decision: "prompt", reason: "Needs approval" };
270
+
271
+ let promptCalled = false;
272
+ const trackingPrompter = {
273
+ prompt: async () => {
274
+ promptCalled = true;
275
+ return { decision: "allow" as const };
276
+ },
277
+ resolveConfirmation: () => {},
278
+ updateSender: () => {},
279
+ dispose: () => {},
280
+ } as unknown as PermissionPrompter;
281
+
282
+ const executor = new ToolExecutor(trackingPrompter);
283
+ await executor.execute(
284
+ "bash",
285
+ { command: "echo hello" },
286
+ makeContext({
287
+ isPlatformHosted: true,
288
+ trustClass: "guardian",
289
+ requireFreshApproval: true,
290
+ }),
291
+ );
292
+
293
+ expect(promptCalled).toBe(true);
294
+ });
295
+
296
+ test("deny rules still respected in platform-hosted mode", async () => {
297
+ checkResultOverride = { decision: "deny", reason: "Explicitly denied" };
298
+
299
+ const executor = new ToolExecutor(makePrompter());
300
+ const result = await executor.execute(
301
+ "bash",
302
+ { command: "rm -rf /" },
303
+ makeContext({ isPlatformHosted: true, trustClass: "guardian" }),
304
+ );
305
+
306
+ expect(result.isError).toBe(true);
307
+ expect(result.content).toContain("Explicitly denied");
308
+ });
309
+
310
+ test("high-risk bash auto-approved in platform-hosted mode", async () => {
311
+ riskOverride = "high";
312
+ checkResultOverride = { decision: "prompt", reason: "High risk command" };
313
+
314
+ let promptCalled = false;
315
+ const trackingPrompter = {
316
+ prompt: async () => {
317
+ promptCalled = true;
318
+ return { decision: "allow" as const };
319
+ },
320
+ resolveConfirmation: () => {},
321
+ updateSender: () => {},
322
+ dispose: () => {},
323
+ } as unknown as PermissionPrompter;
324
+
325
+ const executor = new ToolExecutor(trackingPrompter);
326
+ const result = await executor.execute(
327
+ "bash",
328
+ { command: "rm -rf /tmp/stuff" },
329
+ makeContext({ isPlatformHosted: true, trustClass: "guardian" }),
330
+ );
331
+
332
+ expect(promptCalled).toBe(false);
333
+ expect(result.isError).toBe(false);
334
+ });
335
+
336
+ test("non-bash tools NOT auto-approved in platform-hosted mode", async () => {
337
+ checkResultOverride = { decision: "prompt", reason: "Needs approval" };
338
+
339
+ let promptCalled = false;
340
+ const trackingPrompter = {
341
+ prompt: async () => {
342
+ promptCalled = true;
343
+ return { decision: "allow" as const };
344
+ },
345
+ resolveConfirmation: () => {},
346
+ updateSender: () => {},
347
+ dispose: () => {},
348
+ } as unknown as PermissionPrompter;
349
+
350
+ const executor = new ToolExecutor(trackingPrompter);
351
+ await executor.execute(
352
+ "file_write",
353
+ { path: "/tmp/test.txt", content: "hello" },
354
+ makeContext({ isPlatformHosted: true, trustClass: "guardian" }),
355
+ );
356
+
357
+ expect(promptCalled).toBe(true);
358
+ });
359
+ });