@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,180 @@
1
+ /**
2
+ * Singleton runtime store for the two-axis permission mode.
3
+ *
4
+ * Reads initial state from the `permissions` section of config.json on
5
+ * initialization and persists mutations back to the config file via the
6
+ * raw-config read/write helpers so env-var–derived keys are never leaked
7
+ * to disk.
8
+ *
9
+ * Downstream consumers (e.g. SSE broadcast) register change listeners
10
+ * via `onModeChanged()`.
11
+ */
12
+
13
+ import {
14
+ invalidateConfigCache,
15
+ loadConfig,
16
+ loadRawConfig,
17
+ saveRawConfig,
18
+ } from "../config/loader.js";
19
+ import { getLogger } from "../util/logger.js";
20
+ import type { PermissionMode } from "./permission-mode.js";
21
+ import { DEFAULT_PERMISSION_MODE } from "./permission-mode.js";
22
+
23
+ const log = getLogger("permission-mode-store");
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // Types
27
+ // ---------------------------------------------------------------------------
28
+
29
+ export type ModeChangeListener = (mode: PermissionMode) => void;
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // Module-level state
33
+ // ---------------------------------------------------------------------------
34
+
35
+ let currentMode: PermissionMode = { ...DEFAULT_PERMISSION_MODE };
36
+ let initialized = false;
37
+ const listeners: ModeChangeListener[] = [];
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Internal helpers
41
+ // ---------------------------------------------------------------------------
42
+
43
+ function notifyListeners(): void {
44
+ const snapshot = { ...currentMode };
45
+ for (const listener of listeners) {
46
+ try {
47
+ listener(snapshot);
48
+ } catch (err) {
49
+ log.error({ err }, "Error in permission mode change listener");
50
+ }
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Persist the current in-memory permission mode to config.json.
56
+ *
57
+ * Uses the raw-config pattern (loadRawConfig → mutate → saveRawConfig) so
58
+ * that env-var–derived fields (API keys, dataDir) are never written to disk.
59
+ */
60
+ function persistToConfig(): void {
61
+ try {
62
+ const raw = loadRawConfig();
63
+
64
+ // Ensure the permissions object exists
65
+ if (
66
+ raw.permissions == null ||
67
+ typeof raw.permissions !== "object" ||
68
+ Array.isArray(raw.permissions)
69
+ ) {
70
+ raw.permissions = {};
71
+ }
72
+
73
+ const permissions = raw.permissions as Record<string, unknown>;
74
+ permissions.askBeforeActing = currentMode.askBeforeActing;
75
+ permissions.hostAccess = currentMode.hostAccess;
76
+
77
+ saveRawConfig(raw);
78
+
79
+ // Invalidate the cached config so the next loadConfig() picks up the
80
+ // persisted values rather than returning stale in-memory state.
81
+ invalidateConfigCache();
82
+ } catch (err) {
83
+ log.error({ err }, "Failed to persist permission mode to config");
84
+ }
85
+ }
86
+
87
+ // ---------------------------------------------------------------------------
88
+ // Public API
89
+ // ---------------------------------------------------------------------------
90
+
91
+ /**
92
+ * Initialize the store from the current config. Safe to call multiple times;
93
+ * subsequent calls are no-ops unless `resetForTesting()` has been called.
94
+ */
95
+ export function initPermissionModeStore(): void {
96
+ if (initialized) return;
97
+
98
+ try {
99
+ const config = loadConfig();
100
+ currentMode = {
101
+ askBeforeActing: config.permissions.askBeforeActing,
102
+ hostAccess: config.permissions.hostAccess,
103
+ };
104
+ } catch (err) {
105
+ log.warn(
106
+ { err },
107
+ "Failed to load permission mode from config; using defaults",
108
+ );
109
+ currentMode = { ...DEFAULT_PERMISSION_MODE };
110
+ }
111
+
112
+ initialized = true;
113
+ }
114
+
115
+ /**
116
+ * Return the current permission mode. Initializes from config on first call
117
+ * if `initPermissionModeStore()` hasn't been called yet.
118
+ */
119
+ export function getMode(): PermissionMode {
120
+ if (!initialized) {
121
+ initPermissionModeStore();
122
+ }
123
+ return { ...currentMode };
124
+ }
125
+
126
+ /**
127
+ * Update the `askBeforeActing` axis. Persists to config.json and notifies
128
+ * change listeners.
129
+ */
130
+ export function setAskBeforeActing(value: boolean): void {
131
+ if (!initialized) {
132
+ initPermissionModeStore();
133
+ }
134
+
135
+ if (currentMode.askBeforeActing === value) return;
136
+
137
+ currentMode.askBeforeActing = value;
138
+ persistToConfig();
139
+ notifyListeners();
140
+ }
141
+
142
+ /**
143
+ * Update the `hostAccess` axis. Persists to config.json and notifies
144
+ * change listeners.
145
+ */
146
+ export function setHostAccess(value: boolean): void {
147
+ if (!initialized) {
148
+ initPermissionModeStore();
149
+ }
150
+
151
+ if (currentMode.hostAccess === value) return;
152
+
153
+ currentMode.hostAccess = value;
154
+ persistToConfig();
155
+ notifyListeners();
156
+ }
157
+
158
+ /**
159
+ * Register a callback that fires whenever the permission mode changes.
160
+ * Returns an unsubscribe function.
161
+ */
162
+ export function onModeChanged(callback: ModeChangeListener): () => void {
163
+ listeners.push(callback);
164
+ return () => {
165
+ const idx = listeners.indexOf(callback);
166
+ if (idx >= 0) {
167
+ listeners.splice(idx, 1);
168
+ }
169
+ };
170
+ }
171
+
172
+ /**
173
+ * Reset the store to uninitialized state. **Test-only** — production code
174
+ * should never call this.
175
+ */
176
+ export function resetForTesting(): void {
177
+ currentMode = { ...DEFAULT_PERMISSION_MODE };
178
+ initialized = false;
179
+ listeners.length = 0;
180
+ }
@@ -0,0 +1,31 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * Two-axis permission model:
5
+ * - `askBeforeActing` — LLM behavior toggle: when true the assistant checks in
6
+ * with the user before taking actions.
7
+ * - `hostAccess` — System-enforced gate: when true the assistant can execute
8
+ * commands on the host machine without prompting.
9
+ */
10
+ export type PermissionMode = {
11
+ askBeforeActing: boolean;
12
+ hostAccess: boolean;
13
+ };
14
+
15
+ export const DEFAULT_PERMISSION_MODE: PermissionMode = {
16
+ askBeforeActing: true,
17
+ hostAccess: false,
18
+ };
19
+
20
+ export const PermissionModeSchema = z.object({
21
+ askBeforeActing: z
22
+ .boolean({ error: "permissionMode.askBeforeActing must be a boolean" })
23
+ .default(true)
24
+ .describe("Whether the assistant should check in before taking actions"),
25
+ hostAccess: z
26
+ .boolean({ error: "permissionMode.hostAccess must be a boolean" })
27
+ .default(false)
28
+ .describe(
29
+ "Whether the assistant can execute commands on the host machine without prompting",
30
+ ),
31
+ });
@@ -58,7 +58,6 @@ export class PermissionPrompter {
58
58
  newContent: string;
59
59
  isNewFile: boolean;
60
60
  },
61
- sandboxed?: boolean,
62
61
  conversationId?: string,
63
62
  executionTarget?: ExecutionTarget,
64
63
  persistentDecisionsAllowed?: boolean,
@@ -119,7 +118,6 @@ export class PermissionPrompter {
119
118
  scope: o.scope,
120
119
  })),
121
120
  diff,
122
- sandboxed,
123
121
  conversationId,
124
122
  executionTarget,
125
123
  persistentDecisionsAllowed: persistentDecisionsAllowed ?? true,
@@ -74,8 +74,17 @@ const HOST_TOOLS = new Set([
74
74
  "host_file_write",
75
75
  "host_file_edit",
76
76
  "host_bash",
77
+ "computer_use_run_applescript",
77
78
  ]);
78
79
 
80
+ /**
81
+ * Check whether a tool name is a host-level tool that requires the
82
+ * `hostAccess` permission to execute.
83
+ */
84
+ export function isHostTool(toolName: string): boolean {
85
+ return HOST_TOOLS.has(toolName);
86
+ }
87
+
79
88
  /** Safe local-only tools that are always workspace-scoped. */
80
89
  const ALWAYS_SCOPED_TOOLS = new Set([
81
90
  "skill_load",
@@ -2,7 +2,7 @@
2
2
  * Centralized platform API client.
3
3
  *
4
4
  * Owns managed proxy context resolution, prerequisite validation, and
5
- * authenticated fetch for all platform API calls that use Api-Key auth.
5
+ * authenticated fetch for all platform API calls.
6
6
  */
7
7
 
8
8
  import { getPlatformAssistantId } from "../config/env.js";
@@ -8,15 +8,17 @@ import {
8
8
  } from "node:fs";
9
9
  import { join } from "node:path";
10
10
 
11
+ import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
11
12
  import { getIsContainerized } from "../config/env-registry.js";
13
+ import { loadConfig } from "../config/loader.js";
12
14
  import { listConnections } from "../oauth/oauth-store.js";
15
+ import { getMode } from "../permissions/permission-mode-store.js";
13
16
  import { resolveBundledDir } from "../util/bundled-asset.js";
14
17
  import { getLogger } from "../util/logger.js";
15
18
  import {
16
19
  getConversationsDir,
17
20
  getWorkspaceDir,
18
21
  getWorkspacePromptPath,
19
- isMacOS,
20
22
  } from "../util/platform.js";
21
23
  import { stripCommentLines } from "../util/strip-comment-lines.js";
22
24
  import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "./cache-boundary.js";
@@ -86,6 +88,26 @@ export function ensurePromptFiles(): void {
86
88
  );
87
89
  }
88
90
  }
91
+
92
+ // Also seed BOOTSTRAP-REFERENCE.md (ui_show payloads read on-demand)
93
+ const refDest = getWorkspacePromptPath("BOOTSTRAP-REFERENCE.md");
94
+ if (!existsSync(refDest)) {
95
+ const refSrc = join(templatesDir, "BOOTSTRAP-REFERENCE.md");
96
+ try {
97
+ if (existsSync(refSrc)) {
98
+ copyFileSync(refSrc, refDest);
99
+ log.info(
100
+ { file: "BOOTSTRAP-REFERENCE.md", dest: refDest },
101
+ "Created BOOTSTRAP-REFERENCE.md for first-run onboarding",
102
+ );
103
+ }
104
+ } catch (err) {
105
+ log.warn(
106
+ { err, file: "BOOTSTRAP-REFERENCE.md" },
107
+ "Failed to create BOOTSTRAP-REFERENCE.md from template",
108
+ );
109
+ }
110
+ }
89
111
  }
90
112
 
91
113
  // Auto-delete stale BOOTSTRAP.md at startup. The model is instructed to
@@ -100,6 +122,20 @@ export function ensurePromptFiles(): void {
100
122
  if (existsSync(convDir) && readdirSync(convDir).length > 0) {
101
123
  unlinkSync(bootstrapCleanup);
102
124
  log.info("Auto-deleted stale BOOTSTRAP.md — prior conversations exist");
125
+
126
+ // Also clean up the reference file
127
+ const refCleanup = getWorkspacePromptPath("BOOTSTRAP-REFERENCE.md");
128
+ if (existsSync(refCleanup)) {
129
+ try {
130
+ unlinkSync(refCleanup);
131
+ log.info("Auto-deleted stale BOOTSTRAP-REFERENCE.md");
132
+ } catch (err) {
133
+ log.warn(
134
+ { err },
135
+ "Failed to auto-delete stale BOOTSTRAP-REFERENCE.md",
136
+ );
137
+ }
138
+ }
103
139
  }
104
140
  } catch (err) {
105
141
  log.warn({ err }, "Failed to auto-delete stale BOOTSTRAP.md");
@@ -277,6 +313,9 @@ export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
277
313
  // Journal entries are extracted into graph nodes by the memory pipeline.
278
314
  // Journal files remain writable on disk.
279
315
 
316
+ const askBeforeActingSection = buildAskBeforeActingSection();
317
+ if (askBeforeActingSection) dynamicParts.push(askBeforeActingSection);
318
+
280
319
  const dynamic = dynamicParts.join("\n\n");
281
320
 
282
321
  return staticParts.join("\n\n") + SYSTEM_PROMPT_CACHE_BOUNDARY + dynamic;
@@ -319,12 +358,6 @@ function buildAccessPreferenceSection(hasNoClient: boolean): string {
319
358
  "## External Service Access",
320
359
  "",
321
360
  "Priority: (1) sandbox `bash` - install tools yourself, only fall back to host when you need local files/auth; (2) `host_bash` with CLIs (gh, aws, etc.) using --json flags; (3) browser automation as last resort (no API, visual interaction, or OAuth consent).",
322
- ...(isMacOS()
323
- ? [
324
- "",
325
- "On macOS, prefer osascript/CLI via `host_bash` over computer use tools, which take over the user's cursor. Use foreground computer use only when no scripting alternative exists or the user explicitly asks.",
326
- ]
327
- : []),
328
361
  ].join("\n");
329
362
  }
330
363
 
@@ -358,6 +391,25 @@ function buildIntegrationSection(): string {
358
391
  return lines.join("\n");
359
392
  }
360
393
 
394
+ function buildAskBeforeActingSection(): string | null {
395
+ try {
396
+ const config = loadConfig();
397
+ if (!isAssistantFeatureFlagEnabled("permission-controls-v2", config)) {
398
+ return null;
399
+ }
400
+ const mode = getMode();
401
+ if (!mode.askBeforeActing) return null;
402
+
403
+ return [
404
+ "## Action Confirmation Mode",
405
+ "",
406
+ 'You are in "Ask before acting" mode. Use your judgment about when to check in with the user before proceeding. You should ask for confirmation before actions that are costly, time-consuming, or hard to reverse — for example: sending emails or messages, deleting files or data, making purchases, posting publicly, modifying permissions, or taking actions with significant real-world consequences. You do NOT need to ask before routine low-stakes actions like reading files, searching, running safe shell commands, or making code edits — just do those.',
407
+ ].join("\n");
408
+ } catch {
409
+ return null;
410
+ }
411
+ }
412
+
361
413
  function buildContainerizedSection(): string {
362
414
  const workspaceDir = getWorkspaceDir();
363
415
  return [
@@ -0,0 +1,100 @@
1
+ _ Reference payloads for BOOTSTRAP.md onboarding. Read by the assistant when needed.
2
+ _ This file is deleted alongside BOOTSTRAP.md when onboarding completes.
3
+
4
+ ## Personality Form
5
+
6
+ Use this exact `ui_show` payload for Step 2 (Personality Quiz):
7
+
8
+ ui_show({
9
+ surface_type: "form",
10
+ data: {
11
+ description: "Let's figure out how we work together. Pick what feels right.",
12
+ fields: [
13
+ {
14
+ id: "communication_style",
15
+ type: "select",
16
+ label: "When we're going back and forth, it's more like...",
17
+ required: true,
18
+ options: [
19
+ { label: "Casual friends texting", value: "casual_friends" },
20
+ { label: "Sharp coworkers who respect each other", value: "sharp_coworkers" },
21
+ { label: "Chill and low-key, no drama", value: "chill" },
22
+ { label: "High energy sparring partners", value: "sparring" },
23
+ { label: "Professional but warm", value: "professional_warm" }
24
+ ]
25
+ },
26
+ {
27
+ id: "task_style",
28
+ type: "select",
29
+ label: "When I'm doing something for you, you want me to...",
30
+ required: true,
31
+ options: [
32
+ { label: "Just do it, don't explain unless I ask", value: "just_do_it" },
33
+ { label: "Walk me through your thinking", value: "explain" },
34
+ { label: "Ask me before making big decisions", value: "check_first" },
35
+ { label: "Be opinionated, push back if you disagree", value: "opinionated" }
36
+ ]
37
+ },
38
+ {
39
+ id: "humor",
40
+ type: "select",
41
+ label: "When it comes to humor...",
42
+ required: true,
43
+ options: [
44
+ { label: "Dry and deadpan", value: "dry" },
45
+ { label: "Playful and light", value: "playful" },
46
+ { label: "Keep it professional", value: "professional" },
47
+ { label: "Match my energy", value: "match" }
48
+ ]
49
+ },
50
+ {
51
+ id: "depth",
52
+ type: "select",
53
+ label: "When explaining things...",
54
+ required: true,
55
+ options: [
56
+ { label: "Keep it simple", value: "simple" },
57
+ { label: "I like details", value: "detailed" },
58
+ { label: "Depends on the topic", value: "adaptive" }
59
+ ]
60
+ }
61
+ ],
62
+ submitLabel: "Lock it in"
63
+ }
64
+ })
65
+
66
+ ## Task Card (Email Not Connected)
67
+
68
+ Use this `ui_show` payload for Step 4 when Gmail/Outlook is NOT in the Connected Services section:
69
+
70
+ ui_show({
71
+ surface_type: "card",
72
+ data: {
73
+ title: "Pick something. I'll do it right now.",
74
+ body: "These are real, not demos."
75
+ },
76
+ actions: [
77
+ { id: "relay_prompt", label: "Connect my email", data: { prompt: "I'd like to connect my Gmail or Outlook so you can help me manage my email and calendar" } },
78
+ { id: "relay_prompt", label: "Research a topic and make me a deck", data: { prompt: "I'd like you to research a topic for me and turn it into a visual deck" } },
79
+ { id: "relay_prompt", label: "Build me something", data: { prompt: "Help me build a simple interactive app or tool" } },
80
+ { id: "relay_prompt", label: "Do something with a photo", data: { prompt: "I have a photo I'd like you to analyze, edit, or create something from" } }
81
+ ]
82
+ })
83
+
84
+ ## Task Card (Email Already Connected)
85
+
86
+ Use this `ui_show` payload for Step 4 when Google or Outlook IS in the Connected Services section:
87
+
88
+ ui_show({
89
+ surface_type: "card",
90
+ data: {
91
+ title: "Pick something. I'll do it right now.",
92
+ body: "These are real, not demos."
93
+ },
94
+ actions: [
95
+ { id: "relay_prompt", label: "Check my email", data: { prompt: "Check my email and calendar and give me a summary of what's going on" } },
96
+ { id: "relay_prompt", label: "Research a topic and make me a deck", data: { prompt: "I'd like you to research a topic for me and turn it into a visual deck" } },
97
+ { id: "relay_prompt", label: "Build me something", data: { prompt: "Help me build a simple interactive app or tool" } },
98
+ { id: "relay_prompt", label: "Do something with a photo", data: { prompt: "I have a photo I'd like you to analyze, edit, or create something from" } }
99
+ ]
100
+ })