@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,452 @@
1
+ /**
2
+ * Tests for the host-access gate in the permission checker.
3
+ *
4
+ * When the `permission-controls-v2` feature flag is enabled, the permission
5
+ * checker replaces the risk-classification path with a simple binary check:
6
+ * - Host tools + hostAccess=false → falls through to interactive prompter
7
+ * - Host tools + hostAccess=true → auto-allowed
8
+ * - Non-host tools → auto-allowed (no risk classification)
9
+ * - requireFreshApproval → falls through to interactive prompter
10
+ * - forcePromptSideEffects + side-effect tool → falls through to prompter
11
+ *
12
+ * When the flag is off, existing risk-level behavior is completely unchanged.
13
+ */
14
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
15
+
16
+ import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
17
+ import {
18
+ initPermissionModeStore,
19
+ resetForTesting as resetPermissionModeStore,
20
+ setHostAccess,
21
+ } from "../permissions/permission-mode-store.js";
22
+ import type { PermissionPrompter } from "../permissions/prompter.js";
23
+ import { RiskLevel } from "../permissions/types.js";
24
+ import { PermissionChecker } from "../tools/permission-checker.js";
25
+ import type {
26
+ ExecutionTarget,
27
+ Tool,
28
+ ToolContext,
29
+ ToolLifecycleEvent,
30
+ } from "../tools/types.js";
31
+
32
+ // ---------------------------------------------------------------------------
33
+ // Mocks — suppress the risk classification / trust-rule subsystem so we can
34
+ // test the v2 early-return gate in isolation.
35
+ // ---------------------------------------------------------------------------
36
+
37
+ mock.module("../permissions/checker.js", () => ({
38
+ classifyRisk: async () => RiskLevel.Low,
39
+ check: async () => ({ decision: "allow", reason: "" }),
40
+ generateAllowlistOptions: async () => [],
41
+ generateScopeOptions: () => [],
42
+ }));
43
+
44
+ mock.module("../hooks/manager.js", () => ({
45
+ getHookManager: () => ({
46
+ trigger: async () => {},
47
+ }),
48
+ }));
49
+
50
+ // ---------------------------------------------------------------------------
51
+ // Helpers
52
+ // ---------------------------------------------------------------------------
53
+
54
+ function makePrompter(): PermissionPrompter {
55
+ return {
56
+ prompt: async () => ({ decision: "allow" as const }),
57
+ } as unknown as PermissionPrompter;
58
+ }
59
+
60
+ function makeTool(name: string): Tool {
61
+ return {
62
+ name,
63
+ description: "test tool",
64
+ category: "test",
65
+ defaultRiskLevel: RiskLevel.Low,
66
+ getDefinition: () => ({
67
+ name,
68
+ description: "test",
69
+ input_schema: { type: "object" as const, properties: {} },
70
+ }),
71
+ execute: async () => ({ content: "", isError: false }),
72
+ };
73
+ }
74
+
75
+ function makeContext(overrides?: Partial<ToolContext>): ToolContext {
76
+ return {
77
+ workingDir: "/tmp/test",
78
+ conversationId: "test-conv",
79
+ trustClass: "guardian",
80
+ isInteractive: true,
81
+ ...overrides,
82
+ } as ToolContext;
83
+ }
84
+
85
+ const noopEmit = (_event: ToolLifecycleEvent): void => {};
86
+ const noopSanitize = (
87
+ _name: string,
88
+ input: Record<string, unknown>,
89
+ ): Record<string, unknown> => input;
90
+ const noopDiff = () => undefined;
91
+ const executionTarget: ExecutionTarget = "host";
92
+
93
+ // ---------------------------------------------------------------------------
94
+ // Setup / teardown
95
+ // ---------------------------------------------------------------------------
96
+
97
+ beforeEach(() => {
98
+ _setOverridesForTesting({});
99
+ resetPermissionModeStore();
100
+ initPermissionModeStore();
101
+ });
102
+
103
+ afterEach(() => {
104
+ _setOverridesForTesting({});
105
+ resetPermissionModeStore();
106
+ });
107
+
108
+ // ---------------------------------------------------------------------------
109
+ // Tests
110
+ // ---------------------------------------------------------------------------
111
+
112
+ describe("permission-checker host-access gate (v2)", () => {
113
+ describe("when permission-controls-v2 flag is ON", () => {
114
+ beforeEach(() => {
115
+ _setOverridesForTesting({ "permission-controls-v2": true });
116
+ });
117
+
118
+ const HOST_TOOL_NAMES = [
119
+ "host_bash",
120
+ "host_file_read",
121
+ "host_file_write",
122
+ "host_file_edit",
123
+ "computer_use_run_applescript",
124
+ ];
125
+
126
+ describe("host tools with hostAccess=false", () => {
127
+ beforeEach(() => {
128
+ setHostAccess(false);
129
+ });
130
+
131
+ for (const toolName of HOST_TOOL_NAMES) {
132
+ test(`${toolName} falls through to prompter (interactive prompt)`, async () => {
133
+ const promptSpy = mock(() =>
134
+ Promise.resolve({ decision: "allow" as const }),
135
+ );
136
+ const prompter = {
137
+ prompt: promptSpy,
138
+ } as unknown as PermissionPrompter;
139
+ const checker = new PermissionChecker(prompter);
140
+ const result = await checker.checkPermission(
141
+ toolName,
142
+ {},
143
+ makeTool(toolName),
144
+ makeContext(),
145
+ executionTarget,
146
+ noopEmit,
147
+ noopSanitize,
148
+ Date.now(),
149
+ noopDiff,
150
+ );
151
+
152
+ // The prompter should have been called (interactive dialog)
153
+ expect(promptSpy).toHaveBeenCalled();
154
+ // Since the mock prompter returns "allow", the result should be allowed
155
+ expect(result.allowed).toBe(true);
156
+ expect(result.decision).toBe("allow");
157
+ });
158
+ }
159
+
160
+ test("host tool denied by user through prompter returns allowed=false", async () => {
161
+ const promptSpy = mock(() =>
162
+ Promise.resolve({ decision: "deny" as const }),
163
+ );
164
+ const prompter = {
165
+ prompt: promptSpy,
166
+ } as unknown as PermissionPrompter;
167
+ const checker = new PermissionChecker(prompter);
168
+ const result = await checker.checkPermission(
169
+ "host_bash",
170
+ {},
171
+ makeTool("host_bash"),
172
+ makeContext(),
173
+ executionTarget,
174
+ noopEmit,
175
+ noopSanitize,
176
+ Date.now(),
177
+ noopDiff,
178
+ );
179
+
180
+ expect(promptSpy).toHaveBeenCalled();
181
+ expect(result.allowed).toBe(false);
182
+ expect(result.decision).toBe("deny");
183
+ });
184
+ });
185
+
186
+ describe("host tools with hostAccess=true", () => {
187
+ beforeEach(() => {
188
+ setHostAccess(true);
189
+ });
190
+
191
+ for (const toolName of HOST_TOOL_NAMES) {
192
+ test(`${toolName} is auto-allowed`, async () => {
193
+ const checker = new PermissionChecker(makePrompter());
194
+ const result = await checker.checkPermission(
195
+ toolName,
196
+ {},
197
+ makeTool(toolName),
198
+ makeContext(),
199
+ executionTarget,
200
+ noopEmit,
201
+ noopSanitize,
202
+ Date.now(),
203
+ noopDiff,
204
+ );
205
+
206
+ expect(result.allowed).toBe(true);
207
+ expect(result.decision).toBe("allow");
208
+ });
209
+ }
210
+ });
211
+
212
+ describe("non-host tools are auto-allowed (no risk classification)", () => {
213
+ for (const toolName of [
214
+ "bash",
215
+ "file_read",
216
+ "file_write",
217
+ "web_search",
218
+ ]) {
219
+ test(`${toolName} is auto-allowed regardless of hostAccess`, async () => {
220
+ setHostAccess(false);
221
+ const checker = new PermissionChecker(makePrompter());
222
+ const result = await checker.checkPermission(
223
+ toolName,
224
+ {},
225
+ makeTool(toolName),
226
+ makeContext(),
227
+ "sandbox",
228
+ noopEmit,
229
+ noopSanitize,
230
+ Date.now(),
231
+ noopDiff,
232
+ );
233
+
234
+ expect(result.allowed).toBe(true);
235
+ expect(result.decision).toBe("allow");
236
+ });
237
+ }
238
+ });
239
+
240
+ describe("requireFreshApproval bypasses v2 auto-allow", () => {
241
+ beforeEach(() => {
242
+ setHostAccess(true);
243
+ });
244
+
245
+ test("host tool with requireFreshApproval falls through to prompter", async () => {
246
+ const promptSpy = mock(() =>
247
+ Promise.resolve({ decision: "allow" as const }),
248
+ );
249
+ const prompter = {
250
+ prompt: promptSpy,
251
+ } as unknown as PermissionPrompter;
252
+ const checker = new PermissionChecker(prompter);
253
+ const result = await checker.checkPermission(
254
+ "host_bash",
255
+ {},
256
+ makeTool("host_bash"),
257
+ makeContext({ requireFreshApproval: true }),
258
+ executionTarget,
259
+ noopEmit,
260
+ noopSanitize,
261
+ Date.now(),
262
+ noopDiff,
263
+ );
264
+
265
+ expect(promptSpy).toHaveBeenCalled();
266
+ expect(result.allowed).toBe(true);
267
+ expect(result.decision).toBe("allow");
268
+ });
269
+
270
+ test("non-host side-effect tool with requireFreshApproval falls through to prompter", async () => {
271
+ const promptSpy = mock(() =>
272
+ Promise.resolve({ decision: "allow" as const }),
273
+ );
274
+ const prompter = {
275
+ prompt: promptSpy,
276
+ } as unknown as PermissionPrompter;
277
+ const checker = new PermissionChecker(prompter);
278
+ const result = await checker.checkPermission(
279
+ "bash",
280
+ { command: "echo hi" },
281
+ makeTool("bash"),
282
+ makeContext({ requireFreshApproval: true }),
283
+ "sandbox",
284
+ noopEmit,
285
+ noopSanitize,
286
+ Date.now(),
287
+ noopDiff,
288
+ );
289
+
290
+ expect(promptSpy).toHaveBeenCalled();
291
+ expect(result.allowed).toBe(true);
292
+ expect(result.decision).toBe("allow");
293
+ });
294
+ });
295
+
296
+ describe("non-interactive guardian session with hostAccess=false", () => {
297
+ beforeEach(() => {
298
+ setHostAccess(false);
299
+ });
300
+
301
+ test("host tool is NOT auto-approved (denies instead of guardian_auto_approve)", async () => {
302
+ const promptSpy = mock(() =>
303
+ Promise.resolve({ decision: "allow" as const }),
304
+ );
305
+ const prompter = {
306
+ prompt: promptSpy,
307
+ } as unknown as PermissionPrompter;
308
+ const checker = new PermissionChecker(prompter);
309
+ const result = await checker.checkPermission(
310
+ "host_bash",
311
+ {},
312
+ makeTool("host_bash"),
313
+ makeContext({ isInteractive: false, trustClass: "guardian" }),
314
+ executionTarget,
315
+ noopEmit,
316
+ noopSanitize,
317
+ Date.now(),
318
+ noopDiff,
319
+ );
320
+
321
+ // v2ForcePrompt is true (hostAccess=false), so the non-interactive
322
+ // guardian auto-approve must NOT fire. Since there is no interactive
323
+ // client, the tool should be denied.
324
+ expect(promptSpy).not.toHaveBeenCalled();
325
+ expect(result.allowed).toBe(false);
326
+ expect(result.decision).toBe("denied");
327
+ });
328
+ });
329
+
330
+ describe("forcePromptSideEffects bypasses v2 auto-allow for side-effect tools", () => {
331
+ beforeEach(() => {
332
+ setHostAccess(true);
333
+ });
334
+
335
+ test("host side-effect tool with forcePromptSideEffects falls through to prompter", async () => {
336
+ const promptSpy = mock(() =>
337
+ Promise.resolve({ decision: "allow" as const }),
338
+ );
339
+ const prompter = {
340
+ prompt: promptSpy,
341
+ } as unknown as PermissionPrompter;
342
+ const checker = new PermissionChecker(prompter);
343
+ const result = await checker.checkPermission(
344
+ "host_bash",
345
+ {},
346
+ makeTool("host_bash"),
347
+ makeContext({ forcePromptSideEffects: true }),
348
+ executionTarget,
349
+ noopEmit,
350
+ noopSanitize,
351
+ Date.now(),
352
+ noopDiff,
353
+ );
354
+
355
+ expect(promptSpy).toHaveBeenCalled();
356
+ expect(result.allowed).toBe(true);
357
+ expect(result.decision).toBe("allow");
358
+ });
359
+
360
+ test("non-host side-effect tool with forcePromptSideEffects falls through to prompter", async () => {
361
+ const promptSpy = mock(() =>
362
+ Promise.resolve({ decision: "allow" as const }),
363
+ );
364
+ const prompter = {
365
+ prompt: promptSpy,
366
+ } as unknown as PermissionPrompter;
367
+ const checker = new PermissionChecker(prompter);
368
+ const result = await checker.checkPermission(
369
+ "bash",
370
+ { command: "echo hi" },
371
+ makeTool("bash"),
372
+ makeContext({ forcePromptSideEffects: true }),
373
+ "sandbox",
374
+ noopEmit,
375
+ noopSanitize,
376
+ Date.now(),
377
+ noopDiff,
378
+ );
379
+
380
+ expect(promptSpy).toHaveBeenCalled();
381
+ expect(result.allowed).toBe(true);
382
+ expect(result.decision).toBe("allow");
383
+ });
384
+
385
+ test("non-host read-only tool with forcePromptSideEffects is still auto-allowed", async () => {
386
+ const checker = new PermissionChecker(makePrompter());
387
+ const result = await checker.checkPermission(
388
+ "file_read",
389
+ {},
390
+ makeTool("file_read"),
391
+ makeContext({ forcePromptSideEffects: true }),
392
+ "sandbox",
393
+ noopEmit,
394
+ noopSanitize,
395
+ Date.now(),
396
+ noopDiff,
397
+ );
398
+
399
+ // file_read is not a side-effect tool, so v2 auto-allows it
400
+ expect(result.allowed).toBe(true);
401
+ expect(result.decision).toBe("allow");
402
+ });
403
+ });
404
+ });
405
+
406
+ describe("when permission-controls-v2 flag is OFF", () => {
407
+ beforeEach(() => {
408
+ _setOverridesForTesting({ "permission-controls-v2": false });
409
+ });
410
+
411
+ test("host_bash falls through to existing risk classification (returns allow from mocked checker)", async () => {
412
+ const checker = new PermissionChecker(makePrompter());
413
+ const result = await checker.checkPermission(
414
+ "host_bash",
415
+ {},
416
+ makeTool("host_bash"),
417
+ makeContext(),
418
+ executionTarget,
419
+ noopEmit,
420
+ noopSanitize,
421
+ Date.now(),
422
+ noopDiff,
423
+ );
424
+
425
+ // The mocked checker returns 'allow', so the result should be
426
+ // allowed with the old risk-classification path's risk level.
427
+ expect(result.allowed).toBe(true);
428
+ expect(result.decision).toBe("allow");
429
+ // When flag is off, riskLevel comes from classifyRisk (mocked as "low")
430
+ expect(result.riskLevel).toBe(RiskLevel.Low);
431
+ });
432
+
433
+ test("non-host tools also follow old path", async () => {
434
+ const checker = new PermissionChecker(makePrompter());
435
+ const result = await checker.checkPermission(
436
+ "bash",
437
+ { command: "echo hello" },
438
+ makeTool("bash"),
439
+ makeContext(),
440
+ "sandbox",
441
+ noopEmit,
442
+ noopSanitize,
443
+ Date.now(),
444
+ noopDiff,
445
+ );
446
+
447
+ expect(result.allowed).toBe(true);
448
+ expect(result.decision).toBe("allow");
449
+ expect(result.riskLevel).toBe(RiskLevel.Low);
450
+ });
451
+ });
452
+ });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Tests for the `permission-controls-v2` feature flag.
3
+ *
4
+ * Verifies:
5
+ * - The flag defaults to disabled (not enabled)
6
+ * - The flag can be enabled via `_setOverridesForTesting`
7
+ */
8
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
9
+
10
+ import {
11
+ _setOverridesForTesting,
12
+ isAssistantFeatureFlagEnabled,
13
+ } from "../config/assistant-feature-flags.js";
14
+ import type { AssistantConfig } from "../config/schema.js";
15
+
16
+ // ---------------------------------------------------------------------------
17
+ // Helpers
18
+ // ---------------------------------------------------------------------------
19
+
20
+ function makeConfig(): AssistantConfig {
21
+ return {} as AssistantConfig;
22
+ }
23
+
24
+ // ---------------------------------------------------------------------------
25
+ // Setup / teardown
26
+ // ---------------------------------------------------------------------------
27
+
28
+ beforeEach(() => {
29
+ _setOverridesForTesting({});
30
+ });
31
+
32
+ afterEach(() => {
33
+ _setOverridesForTesting({});
34
+ });
35
+
36
+ // ---------------------------------------------------------------------------
37
+ // Tests
38
+ // ---------------------------------------------------------------------------
39
+
40
+ describe("permission-controls-v2 feature flag", () => {
41
+ test("defaults to disabled", () => {
42
+ const config = makeConfig();
43
+ expect(
44
+ isAssistantFeatureFlagEnabled("permission-controls-v2", config),
45
+ ).toBe(false);
46
+ });
47
+
48
+ test("can be enabled via overrides", () => {
49
+ _setOverridesForTesting({ "permission-controls-v2": true });
50
+ const config = makeConfig();
51
+ expect(
52
+ isAssistantFeatureFlagEnabled("permission-controls-v2", config),
53
+ ).toBe(true);
54
+ });
55
+ });