@vellumai/assistant 0.5.15 → 0.6.0

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 (503) hide show
  1. package/ARCHITECTURE.md +3 -3
  2. package/Dockerfile +0 -3
  3. package/docs/architecture/integrations.md +15 -14
  4. package/knip.json +4 -1
  5. package/openapi.yaml +670 -122
  6. package/package.json +1 -1
  7. package/src/__tests__/actor-token-service.test.ts +68 -0
  8. package/src/__tests__/agent-loop.test.ts +0 -32
  9. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  10. package/src/__tests__/anthropic-provider.test.ts +57 -3
  11. package/src/__tests__/app-compiler.test.ts +120 -0
  12. package/src/__tests__/assistant-feature-flags-integration.test.ts +5 -377
  13. package/src/__tests__/call-conversation-messages.test.ts +2 -6
  14. package/src/__tests__/call-domain.test.ts +2 -6
  15. package/src/__tests__/call-pointer-messages.test.ts +2 -14
  16. package/src/__tests__/call-recovery.test.ts +2 -6
  17. package/src/__tests__/call-routes-http.test.ts +2 -6
  18. package/src/__tests__/call-store.test.ts +2 -6
  19. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
  20. package/src/__tests__/canonical-guardian-store.test.ts +2 -6
  21. package/src/__tests__/ces-rpc-credential-backend.test.ts +4 -1
  22. package/src/__tests__/channel-delivery-store.test.ts +2 -6
  23. package/src/__tests__/channel-retry-sweep.test.ts +2 -6
  24. package/src/__tests__/checker.test.ts +84 -3
  25. package/src/__tests__/clawhub.test.ts +54 -24
  26. package/src/__tests__/cli-command-risk-guard.test.ts +108 -6
  27. package/src/__tests__/cli-memory.test.ts +377 -0
  28. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +12 -2
  29. package/src/__tests__/config-schema.test.ts +1 -3
  30. package/src/__tests__/config-set-platform-guard.test.ts +302 -0
  31. package/src/__tests__/config-watcher-feature-flags.test.ts +211 -0
  32. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
  33. package/src/__tests__/contacts-tools.test.ts +31 -0
  34. package/src/__tests__/context-overflow-reducer.test.ts +86 -0
  35. package/src/__tests__/context-token-estimator.test.ts +175 -10
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +9 -0
  37. package/src/__tests__/conversation-agent-loop.test.ts +9 -0
  38. package/src/__tests__/conversation-attachments.test.ts +2 -6
  39. package/src/__tests__/conversation-attention-store.test.ts +2 -6
  40. package/src/__tests__/conversation-clear-safety.test.ts +2 -6
  41. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
  42. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
  43. package/src/__tests__/conversation-disk-view.test.ts +2 -6
  44. package/src/__tests__/conversation-error.test.ts +33 -2
  45. package/src/__tests__/conversation-fork-crud.test.ts +2 -6
  46. package/src/__tests__/conversation-history-web-search.test.ts +5 -0
  47. package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
  48. package/src/__tests__/conversation-media-retry.test.ts +91 -0
  49. package/src/__tests__/conversation-runtime-assembly.test.ts +7 -4
  50. package/src/__tests__/conversation-slash-commands.test.ts +2 -6
  51. package/src/__tests__/conversation-starter-routes.test.ts +20 -11
  52. package/src/__tests__/conversation-store.test.ts +2 -6
  53. package/src/__tests__/conversation-usage.test.ts +3 -6
  54. package/src/__tests__/conversation-wipe.test.ts +11 -408
  55. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
  56. package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
  57. package/src/__tests__/credential-security-e2e.test.ts +6 -1
  58. package/src/__tests__/docker-signing-key-bootstrap.test.ts +7 -73
  59. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -7
  60. package/src/__tests__/followup-tools.test.ts +2 -6
  61. package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
  62. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
  63. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
  64. package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
  65. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
  66. package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
  67. package/src/__tests__/guardian-action-store.test.ts +2 -6
  68. package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
  69. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
  70. package/src/__tests__/guardian-dispatch.test.ts +2 -6
  71. package/src/__tests__/guardian-grant-minting.test.ts +2 -14
  72. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
  73. package/src/__tests__/guardian-routing-invariants.test.ts +343 -6
  74. package/src/__tests__/guardian-routing-state.test.ts +2 -6
  75. package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
  76. package/src/__tests__/heartbeat-service.test.ts +1 -3
  77. package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
  78. package/src/__tests__/injection-block.test.ts +154 -0
  79. package/src/__tests__/install-meta.test.ts +506 -0
  80. package/src/__tests__/install-skill-routing.test.ts +292 -0
  81. package/src/__tests__/intent-routing.test.ts +6 -18
  82. package/src/__tests__/invite-redemption-service.test.ts +2 -6
  83. package/src/__tests__/invite-routes-http.test.ts +2 -6
  84. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -14
  85. package/src/__tests__/list-messages-attachments.test.ts +2 -6
  86. package/src/__tests__/llm-context-route-provider.test.ts +2 -6
  87. package/src/__tests__/llm-request-log-turn-query.test.ts +2 -6
  88. package/src/__tests__/llm-usage-store.test.ts +2 -6
  89. package/src/__tests__/log-export-workspace.test.ts +4 -34
  90. package/src/__tests__/managed-skill-lifecycle.test.ts +7 -37
  91. package/src/__tests__/managed-store.test.ts +40 -21
  92. package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
  93. package/src/__tests__/memory-recall-log-store.test.ts +2 -6
  94. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
  95. package/src/__tests__/messaging-send-tool.test.ts +6 -6
  96. package/src/__tests__/migration-cross-version-compatibility.test.ts +1 -29
  97. package/src/__tests__/migration-export-http.test.ts +3 -34
  98. package/src/__tests__/migration-import-commit-http.test.ts +1 -29
  99. package/src/__tests__/migration-import-preflight-http.test.ts +3 -34
  100. package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +2 -1
  101. package/src/__tests__/non-member-access-request.test.ts +2 -6
  102. package/src/__tests__/notification-guardian-path.test.ts +2 -6
  103. package/src/__tests__/oauth-apps-routes.test.ts +120 -10
  104. package/src/__tests__/oauth-cli.test.ts +364 -2
  105. package/src/__tests__/oauth-connect-orchestrator.test.ts +709 -0
  106. package/src/__tests__/oauth-provider-serializer.test.ts +2 -1
  107. package/src/__tests__/oauth-provider-visibility.test.ts +149 -0
  108. package/src/__tests__/oauth-providers-routes.test.ts +5 -2
  109. package/src/__tests__/oauth-store.test.ts +0 -5
  110. package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
  111. package/src/__tests__/outlook-attachments.test.ts +301 -0
  112. package/src/__tests__/outlook-automation-tools.test.ts +425 -0
  113. package/src/__tests__/outlook-categories.test.ts +212 -0
  114. package/src/__tests__/outlook-client-automation.test.ts +246 -0
  115. package/src/__tests__/outlook-compose-tools.test.ts +325 -0
  116. package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
  117. package/src/__tests__/outlook-email-watcher.test.ts +322 -0
  118. package/src/__tests__/outlook-follow-up.test.ts +196 -0
  119. package/src/__tests__/outlook-messaging-provider.test.ts +1071 -0
  120. package/src/__tests__/outlook-trash.test.ts +77 -0
  121. package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
  122. package/src/__tests__/path-policy.test.ts +2 -17
  123. package/src/__tests__/permission-types.test.ts +0 -1
  124. package/src/__tests__/platform-callback-registration.test.ts +7 -11
  125. package/src/__tests__/playbook-execution.test.ts +76 -80
  126. package/src/__tests__/playbook-tools.test.ts +5 -7
  127. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  128. package/src/__tests__/provider-error-scenarios.test.ts +21 -2
  129. package/src/__tests__/qdrant-manager.test.ts +68 -21
  130. package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
  131. package/src/__tests__/registry.test.ts +2 -2
  132. package/src/__tests__/require-fresh-approval.test.ts +64 -3
  133. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
  134. package/src/__tests__/runtime-events-sse.test.ts +2 -6
  135. package/src/__tests__/sandbox-diagnostics.test.ts +20 -29
  136. package/src/__tests__/scaffold-managed-skill-tool.test.ts +2 -10
  137. package/src/__tests__/schedule-store.test.ts +2 -6
  138. package/src/__tests__/schedule-tools.test.ts +2 -6
  139. package/src/__tests__/scheduler-recurrence.test.ts +1 -5
  140. package/src/__tests__/scoped-approval-grants.test.ts +2 -6
  141. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
  142. package/src/__tests__/search-skills-unified.test.ts +421 -0
  143. package/src/__tests__/secret-allowlist.test.ts +20 -35
  144. package/src/__tests__/secret-onetime-send.test.ts +2 -0
  145. package/src/__tests__/send-endpoint-busy.test.ts +2 -6
  146. package/src/__tests__/sequence-store.test.ts +2 -6
  147. package/src/__tests__/server-history-render.test.ts +2 -6
  148. package/src/__tests__/shell-credential-ref.test.ts +0 -5
  149. package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
  150. package/src/__tests__/skill-feature-flags.test.ts +6 -6
  151. package/src/__tests__/skill-load-feature-flag.test.ts +13 -54
  152. package/src/__tests__/skill-load-inline-command.test.ts +3 -65
  153. package/src/__tests__/skill-load-inline-includes.test.ts +3 -65
  154. package/src/__tests__/skill-load-tool.test.ts +3 -67
  155. package/src/__tests__/skill-memory.test.ts +480 -195
  156. package/src/__tests__/skills-uninstall.test.ts +2 -2
  157. package/src/__tests__/skills.test.ts +23 -50
  158. package/src/__tests__/slack-channel-config.test.ts +2 -21
  159. package/src/__tests__/slack-inbound-verification.test.ts +2 -6
  160. package/src/__tests__/starter-bundle.test.ts +2 -8
  161. package/src/__tests__/stt-hints.test.ts +7 -2
  162. package/src/__tests__/system-prompt.test.ts +25 -45
  163. package/src/__tests__/task-compiler.test.ts +2 -27
  164. package/src/__tests__/task-management-tools.test.ts +2 -27
  165. package/src/__tests__/task-memory-cleanup.test.ts +173 -250
  166. package/src/__tests__/task-runner.test.ts +2 -27
  167. package/src/__tests__/task-scheduler.test.ts +2 -27
  168. package/src/__tests__/terminal-tools.test.ts +1 -17
  169. package/src/__tests__/test-preload.ts +3 -0
  170. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +0 -79
  171. package/src/__tests__/tool-approval-handler.test.ts +4 -27
  172. package/src/__tests__/tool-execution-abort-cleanup.test.ts +2 -11
  173. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -25
  174. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  175. package/src/__tests__/tool-executor.test.ts +0 -1
  176. package/src/__tests__/tool-grant-request-escalation.test.ts +4 -27
  177. package/src/__tests__/tool-preview-lifecycle.test.ts +0 -20
  178. package/src/__tests__/tool-side-effects-slack-dm.test.ts +276 -0
  179. package/src/__tests__/trust-store.test.ts +10 -42
  180. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -30
  181. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +3 -27
  182. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -28
  183. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -28
  184. package/src/__tests__/trusted-contact-verification.test.ts +2 -28
  185. package/src/__tests__/turn-boundary-resolution.test.ts +2 -34
  186. package/src/__tests__/twilio-provider.test.ts +0 -16
  187. package/src/__tests__/twilio-routes-twiml.test.ts +7 -12
  188. package/src/__tests__/twilio-routes.test.ts +0 -24
  189. package/src/__tests__/update-bulletin.test.ts +17 -89
  190. package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -26
  191. package/src/__tests__/usage-routes.test.ts +2 -27
  192. package/src/__tests__/user-reference.test.ts +1 -5
  193. package/src/__tests__/vbundle-pax-and-symlink.test.ts +4 -34
  194. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +2 -53
  195. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  196. package/src/__tests__/voice-invite-redemption.test.ts +2 -27
  197. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -30
  198. package/src/__tests__/voice-session-bridge.test.ts +2 -27
  199. package/src/__tests__/volume-security-guard.test.ts +2 -0
  200. package/src/__tests__/workspace-lifecycle.test.ts +29 -1
  201. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +4 -29
  202. package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +2 -2
  203. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +4 -29
  204. package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
  205. package/src/__tests__/workspace-migration-down-functions.test.ts +0 -6
  206. package/src/__tests__/workspace-policy.test.ts +1 -1
  207. package/src/acp/client-handler.ts +1 -2
  208. package/src/agent/attachments.ts +7 -2
  209. package/src/agent/image-optimize.ts +165 -0
  210. package/src/agent/loop.ts +1 -15
  211. package/src/bundler/app-compiler.ts +179 -2
  212. package/src/bundler/package-resolver.ts +3 -5
  213. package/src/cli/__tests__/notifications.test.ts +1 -24
  214. package/src/cli/cli-memory.ts +179 -0
  215. package/src/cli/commands/avatar.ts +3 -3
  216. package/src/cli/commands/config.ts +26 -13
  217. package/src/cli/commands/doctor.ts +2 -2
  218. package/src/cli/commands/memory.ts +41 -55
  219. package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
  220. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
  221. package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
  222. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
  223. package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
  224. package/src/cli/commands/oauth/connect.ts +26 -6
  225. package/src/cli/commands/oauth/mode.ts +7 -0
  226. package/src/cli/commands/oauth/providers.ts +49 -42
  227. package/src/cli/commands/oauth/shared.ts +39 -3
  228. package/src/cli/commands/platform/__tests__/connect.test.ts +3 -49
  229. package/src/cli/commands/platform/__tests__/disconnect.test.ts +3 -49
  230. package/src/cli/commands/platform/__tests__/status.test.ts +5 -55
  231. package/src/cli/commands/platform/index.ts +16 -16
  232. package/src/cli/commands/skills.ts +88 -16
  233. package/src/cli/commands/trust.ts +2 -2
  234. package/src/cli/lib/daemon-credential-client.ts +2 -3
  235. package/src/config/bundled-skills/acp/TOOLS.json +1 -1
  236. package/src/config/bundled-skills/computer-use/TOOLS.json +7 -7
  237. package/src/config/bundled-skills/contacts/SKILL.md +0 -1
  238. package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
  239. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
  240. package/src/config/bundled-skills/gmail/SKILL.md +2 -10
  241. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
  242. package/src/config/bundled-skills/messaging/SKILL.md +26 -19
  243. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
  244. package/src/config/bundled-skills/outlook/SKILL.md +189 -0
  245. package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
  246. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
  247. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
  248. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
  249. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
  250. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
  251. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
  252. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
  253. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
  254. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
  255. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
  256. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
  257. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
  258. package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
  259. package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
  260. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
  261. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
  262. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
  263. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
  264. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
  265. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
  266. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
  267. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
  268. package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
  269. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
  270. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
  271. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
  272. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
  273. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  274. package/src/config/bundled-skills/slack/SKILL.md +1 -7
  275. package/src/config/bundled-tool-registry.ts +56 -4
  276. package/src/config/env-registry.ts +15 -8
  277. package/src/config/feature-flag-registry.json +29 -116
  278. package/src/config/loader.ts +4 -0
  279. package/src/config/schemas/platform.ts +8 -0
  280. package/src/config/schemas/security.ts +0 -6
  281. package/src/config/schemas/services.ts +8 -0
  282. package/src/config/schemas/timeouts.ts +1 -1
  283. package/src/config/skills.ts +18 -7
  284. package/src/context/token-estimator.ts +25 -18
  285. package/src/context/window-manager.ts +32 -9
  286. package/src/credential-execution/approval-bridge.ts +0 -1
  287. package/src/credential-execution/process-manager.ts +3 -1
  288. package/src/daemon/config-watcher.ts +51 -0
  289. package/src/daemon/context-overflow-reducer.ts +46 -2
  290. package/src/daemon/conversation-agent-loop-handlers.ts +123 -82
  291. package/src/daemon/conversation-agent-loop.ts +99 -63
  292. package/src/daemon/conversation-error.ts +31 -8
  293. package/src/daemon/conversation-lifecycle.ts +33 -0
  294. package/src/daemon/conversation-media-retry.ts +85 -7
  295. package/src/daemon/conversation-notifiers.ts +4 -1
  296. package/src/daemon/conversation-process.ts +1 -0
  297. package/src/daemon/conversation-runtime-assembly.ts +5 -0
  298. package/src/daemon/conversation-usage.ts +1 -0
  299. package/src/daemon/conversation.ts +41 -2
  300. package/src/daemon/daemon-control.ts +8 -2
  301. package/src/daemon/handlers/shared.ts +22 -12
  302. package/src/daemon/handlers/skills.ts +423 -201
  303. package/src/daemon/lifecycle.ts +52 -4
  304. package/src/daemon/main.ts +5 -1
  305. package/src/daemon/message-types/conversations.ts +5 -1
  306. package/src/daemon/message-types/messages.ts +3 -1
  307. package/src/daemon/message-types/skills.ts +97 -36
  308. package/src/daemon/providers-setup.ts +7 -0
  309. package/src/daemon/server.ts +35 -22
  310. package/src/daemon/tool-side-effects.ts +27 -5
  311. package/src/events/domain-events.ts +1 -2
  312. package/src/heartbeat/heartbeat-service.ts +1 -0
  313. package/src/hooks/cli.ts +2 -2
  314. package/src/hooks/runner.ts +15 -38
  315. package/src/inbound/platform-callback-registration.ts +14 -14
  316. package/src/memory/admin.ts +11 -45
  317. package/src/memory/conversation-bootstrap.ts +2 -0
  318. package/src/memory/conversation-crud.ts +242 -348
  319. package/src/memory/conversation-group-migration.ts +157 -0
  320. package/src/memory/conversation-queries.ts +4 -2
  321. package/src/memory/db-init.ts +39 -3
  322. package/src/memory/embed.ts +73 -0
  323. package/src/memory/embedding-backend.ts +8 -14
  324. package/src/memory/embedding-runtime-manager.ts +12 -114
  325. package/src/memory/fingerprint.ts +2 -2
  326. package/src/memory/graph/bootstrap.ts +512 -0
  327. package/src/memory/graph/capability-seed.ts +297 -0
  328. package/src/memory/graph/consolidation.ts +691 -0
  329. package/src/memory/graph/conversation-graph-memory.ts +630 -0
  330. package/src/memory/graph/decay.test.ts +208 -0
  331. package/src/memory/graph/decay.ts +195 -0
  332. package/src/memory/graph/extraction-job.ts +69 -0
  333. package/src/memory/graph/extraction.test.ts +936 -0
  334. package/src/memory/graph/extraction.ts +1254 -0
  335. package/src/memory/graph/graph-search.ts +266 -0
  336. package/src/memory/graph/image-ref-utils.ts +29 -0
  337. package/src/memory/graph/injection.test.ts +513 -0
  338. package/src/memory/graph/injection.ts +439 -0
  339. package/src/memory/graph/inspect.ts +534 -0
  340. package/src/memory/graph/narrative.ts +267 -0
  341. package/src/memory/graph/pattern-scan.ts +269 -0
  342. package/src/memory/graph/retriever.ts +1008 -0
  343. package/src/memory/graph/scoring.test.ts +548 -0
  344. package/src/memory/graph/scoring.ts +232 -0
  345. package/src/memory/graph/serendipity.ts +65 -0
  346. package/src/memory/graph/store.test.ts +1050 -0
  347. package/src/memory/graph/store.ts +699 -0
  348. package/src/memory/graph/tool-handlers.ts +426 -0
  349. package/src/memory/graph/tools.ts +141 -0
  350. package/src/memory/graph/triggers.test.ts +487 -0
  351. package/src/memory/graph/triggers.ts +223 -0
  352. package/src/memory/graph/types.ts +271 -0
  353. package/src/memory/group-crud.ts +191 -0
  354. package/src/memory/indexer.ts +37 -19
  355. package/src/memory/job-handlers/cleanup.ts +0 -53
  356. package/src/memory/job-handlers/conversation-starters.ts +91 -53
  357. package/src/memory/job-handlers/embedding.test.ts +3 -27
  358. package/src/memory/job-handlers/embedding.ts +5 -31
  359. package/src/memory/job-handlers/index-maintenance.ts +23 -11
  360. package/src/memory/job-handlers/summarization.ts +32 -17
  361. package/src/memory/job-utils.ts +1 -1
  362. package/src/memory/jobs-store.ts +50 -70
  363. package/src/memory/jobs-worker.ts +147 -112
  364. package/src/memory/llm-usage-store.ts +35 -2
  365. package/src/memory/message-content.ts +1 -0
  366. package/src/memory/migrations/201-oauth-providers-feature-flag.ts +11 -0
  367. package/src/memory/migrations/202-drop-callback-transport-column.ts +13 -0
  368. package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
  369. package/src/memory/migrations/203-drop-memory-items-tables.ts +23 -0
  370. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
  371. package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
  372. package/src/memory/migrations/index.ts +6 -0
  373. package/src/memory/migrations/registry.ts +8 -0
  374. package/src/memory/qdrant-client.ts +44 -17
  375. package/src/memory/qdrant-manager.ts +26 -5
  376. package/src/memory/schema/index.ts +1 -0
  377. package/src/memory/schema/memory-graph.ts +139 -0
  378. package/src/memory/schema/oauth.ts +1 -1
  379. package/src/memory/search/semantic.ts +47 -91
  380. package/src/memory/slack-thread-store.ts +17 -0
  381. package/src/memory/task-memory-cleanup.ts +28 -50
  382. package/src/messaging/providers/outlook/adapter.ts +200 -0
  383. package/src/messaging/providers/outlook/client.ts +610 -0
  384. package/src/messaging/providers/outlook/types.ts +201 -0
  385. package/src/notifications/adapters/macos.ts +1 -0
  386. package/src/notifications/adapters/slack.ts +1 -1
  387. package/src/notifications/copy-composer.ts +9 -0
  388. package/src/notifications/signal.ts +16 -0
  389. package/src/oauth/__tests__/identity-verifier.test.ts +1 -1
  390. package/src/oauth/connect-orchestrator.ts +10 -3
  391. package/src/oauth/oauth-store.ts +10 -11
  392. package/src/oauth/provider-serializer.ts +3 -0
  393. package/src/oauth/provider-visibility.ts +16 -0
  394. package/src/oauth/seed-providers.ts +50 -17
  395. package/src/permissions/checker.ts +62 -9
  396. package/src/permissions/defaults.ts +4 -4
  397. package/src/permissions/types.ts +2 -4
  398. package/src/permissions/workspace-policy.ts +1 -1
  399. package/src/playbooks/playbook-compiler.ts +19 -18
  400. package/src/playbooks/types.ts +4 -3
  401. package/src/prompts/system-prompt.ts +6 -93
  402. package/src/prompts/templates/UPDATES.md +6 -0
  403. package/src/providers/anthropic/client.ts +47 -19
  404. package/src/providers/gemini/client.ts +1 -1
  405. package/src/providers/openai/client.ts +1 -1
  406. package/src/providers/registry.ts +1 -1
  407. package/src/providers/retry.ts +19 -3
  408. package/src/runtime/actor-trust-resolver.ts +5 -1
  409. package/src/runtime/auth/__tests__/credential-service.test.ts +1 -27
  410. package/src/runtime/auth/__tests__/token-service.test.ts +1 -25
  411. package/src/runtime/auth/route-policy.ts +7 -4
  412. package/src/runtime/guardian-reply-router.ts +10 -2
  413. package/src/runtime/http-server.ts +23 -3
  414. package/src/runtime/middleware/auth.ts +20 -0
  415. package/src/runtime/routes/attachment-routes.test.ts +106 -0
  416. package/src/runtime/routes/attachment-routes.ts +106 -16
  417. package/src/runtime/routes/brain-graph-routes.ts +21 -22
  418. package/src/runtime/routes/btw-routes.ts +8 -0
  419. package/src/runtime/routes/conversation-management-routes.ts +2 -0
  420. package/src/runtime/routes/conversation-query-routes.ts +2 -58
  421. package/src/runtime/routes/conversation-starter-routes.ts +2 -2
  422. package/src/runtime/routes/debug-routes.ts +1 -1
  423. package/src/runtime/routes/global-search-routes.ts +21 -19
  424. package/src/runtime/routes/group-routes.ts +207 -0
  425. package/src/runtime/routes/guardian-action-routes.ts +21 -10
  426. package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
  427. package/src/runtime/routes/inbound-message-handler.ts +19 -0
  428. package/src/runtime/routes/inbound-stages/background-dispatch.ts +43 -2
  429. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
  430. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
  431. package/src/runtime/routes/memory-item-routes.test.ts +2 -31
  432. package/src/runtime/routes/memory-item-routes.ts +385 -341
  433. package/src/runtime/routes/oauth-apps.ts +18 -1
  434. package/src/runtime/routes/oauth-providers.ts +13 -1
  435. package/src/runtime/routes/schedule-routes.ts +2 -0
  436. package/src/runtime/routes/settings-routes.ts +1 -0
  437. package/src/runtime/routes/skills-routes.ts +103 -37
  438. package/src/runtime/routes/usage-routes.ts +19 -2
  439. package/src/runtime/routes/work-items-routes.test.ts +2 -27
  440. package/src/runtime/routes/workspace-routes.test.ts +3 -27
  441. package/src/schedule/scheduler.ts +8 -1
  442. package/src/security/oauth2.ts +1 -1
  443. package/src/security/secret-allowlist.ts +4 -4
  444. package/src/security/secure-keys.ts +4 -8
  445. package/src/shared/provider-env-vars.ts +19 -0
  446. package/src/skills/catalog-cache.ts +5 -0
  447. package/src/skills/catalog-install.ts +15 -14
  448. package/src/skills/clawhub.ts +134 -154
  449. package/src/skills/install-meta.ts +208 -0
  450. package/src/skills/managed-store.ts +27 -16
  451. package/src/skills/skill-memory.ts +210 -96
  452. package/src/skills/skillssh-registry.ts +19 -17
  453. package/src/tasks/task-runner.ts +3 -1
  454. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
  455. package/src/tools/browser/runtime-check.ts +3 -1
  456. package/src/tools/memory/register.ts +63 -46
  457. package/src/tools/permission-checker.ts +7 -19
  458. package/src/tools/shared/filesystem/image-read.ts +22 -85
  459. package/src/tools/skills/skill-script-runner.ts +1 -1
  460. package/src/tools/terminal/safe-env.ts +1 -0
  461. package/src/tools/tool-manifest.ts +3 -3
  462. package/src/util/browser.ts +25 -10
  463. package/src/util/bun-runtime.ts +172 -0
  464. package/src/util/device-id.ts +3 -65
  465. package/src/watcher/providers/outlook-calendar.ts +343 -0
  466. package/src/watcher/providers/outlook.ts +198 -0
  467. package/src/workspace/git-service.ts +27 -6
  468. package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
  469. package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
  470. package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
  471. package/src/workspace/migrations/registry.ts +6 -0
  472. package/src/__tests__/context-memory-e2e.test.ts +0 -415
  473. package/src/__tests__/journal-context.test.ts +0 -268
  474. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
  475. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
  476. package/src/__tests__/memory-query-builder.test.ts +0 -59
  477. package/src/__tests__/memory-recall-quality.test.ts +0 -1046
  478. package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
  479. package/src/__tests__/memory-regressions.test.ts +0 -3696
  480. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
  481. package/src/daemon/conversation-memory.ts +0 -207
  482. package/src/memory/conversation-starters-cadence.ts +0 -74
  483. package/src/memory/items-extractor.ts +0 -860
  484. package/src/memory/job-handlers/batch-extraction.ts +0 -741
  485. package/src/memory/job-handlers/extraction.ts +0 -40
  486. package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -383
  487. package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
  488. package/src/memory/journal-memory.ts +0 -224
  489. package/src/memory/query-builder.ts +0 -47
  490. package/src/memory/query-expansion.ts +0 -83
  491. package/src/memory/retriever.test.ts +0 -1590
  492. package/src/memory/retriever.ts +0 -1323
  493. package/src/memory/search/formatting.test.ts +0 -140
  494. package/src/memory/search/formatting.ts +0 -262
  495. package/src/memory/search/mmr.ts +0 -136
  496. package/src/memory/search/ranking.ts +0 -15
  497. package/src/memory/search/staleness.ts +0 -40
  498. package/src/memory/search/tier-classifier.ts +0 -18
  499. package/src/memory/search/types.ts +0 -121
  500. package/src/prompts/journal-context.ts +0 -156
  501. package/src/tools/memory/definitions.ts +0 -69
  502. package/src/tools/memory/handlers.test.ts +0 -590
  503. package/src/tools/memory/handlers.ts +0 -434
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * HTTP route definitions for model configuration, embedding configuration,
3
- * permissions configuration, conversation search, message content, LLM
3
+ * conversation search, message content, LLM
4
4
  * context inspection, and queued message deletion.
5
5
  *
6
6
  * These routes expose conversation query functionality over the HTTP API.
@@ -10,8 +10,6 @@
10
10
  * PUT /v1/model/image-gen — set image-gen model
11
11
  * GET /v1/config/embeddings — current embedding config
12
12
  * PUT /v1/config/embeddings — set embedding provider/model
13
- * GET /v1/config/permissions/skip — dangerouslySkipPermissions status
14
- * PUT /v1/config/permissions/skip — toggle dangerouslySkipPermissions
15
13
  * GET /v1/config — full raw workspace config
16
14
  * PATCH /v1/config — deep-merge partial config
17
15
  * GET /v1/conversations/search — search conversations
@@ -24,7 +22,6 @@ import { z } from "zod";
24
22
 
25
23
  import {
26
24
  deepMergeOverwrite,
27
- getConfig,
28
25
  loadRawConfig,
29
26
  saveRawConfig,
30
27
  } from "../../config/loader.js";
@@ -113,9 +110,7 @@ function applyStoredProviderToLlmContextResult(
113
110
  const mergedSummary = normalized.summary
114
111
  ? { ...normalized.summary, provider }
115
112
  : { provider };
116
- const summary = attachEstimatedCost(
117
- mergedSummary as LlmContextSummary,
118
- );
113
+ const summary = attachEstimatedCost(mergedSummary as LlmContextSummary);
119
114
  return { ...normalized, summary };
120
115
  }
121
116
 
@@ -324,57 +319,6 @@ export function conversationQueryRouteDefinitions(
324
319
  },
325
320
  },
326
321
 
327
- // ── Permissions config ─────────────────────────────────────────────
328
- {
329
- endpoint: "config/permissions/skip",
330
- method: "GET",
331
- policyKey: "config/permissions/skip",
332
- summary: "Get permission-skip flag",
333
- description: "Return whether dangerouslySkipPermissions is enabled.",
334
- tags: ["config"],
335
- responseBody: z.object({
336
- enabled: z.boolean(),
337
- }),
338
- handler: () => {
339
- const config = getConfig();
340
- return Response.json({
341
- enabled: config.permissions.dangerouslySkipPermissions,
342
- });
343
- },
344
- },
345
- {
346
- endpoint: "config/permissions/skip",
347
- method: "PUT",
348
- policyKey: "config/permissions/skip",
349
- summary: "Set permission-skip flag",
350
- description: "Enable or disable dangerouslySkipPermissions.",
351
- tags: ["config"],
352
- requestBody: z.object({
353
- enabled: z.boolean(),
354
- }),
355
- handler: async ({ req }) => {
356
- const body = (await req.json()) as { enabled?: unknown };
357
- if (typeof body.enabled !== "boolean") {
358
- return httpError(
359
- "BAD_REQUEST",
360
- "Missing or invalid field: enabled (boolean)",
361
- 400,
362
- );
363
- }
364
- const raw = loadRawConfig();
365
- const permissions: Record<string, unknown> =
366
- raw.permissions != null &&
367
- typeof raw.permissions === "object" &&
368
- !Array.isArray(raw.permissions)
369
- ? (raw.permissions as Record<string, unknown>)
370
- : {};
371
- permissions.dangerouslySkipPermissions = body.enabled;
372
- raw.permissions = permissions;
373
- saveRawConfig(raw);
374
- return Response.json({ enabled: body.enabled });
375
- },
376
- },
377
-
378
322
  // ── Full config read ─────────────────────────────────────────────
379
323
  {
380
324
  endpoint: "config",
@@ -161,9 +161,9 @@ function handleListConversationStarters(url: URL): Response {
161
161
  });
162
162
  }
163
163
 
164
- // No starters — check whether we have memory items to generate from.
164
+ // No starters — check whether we have memory graph nodes to generate from.
165
165
  const memoryCount = rawGet<{ c: number }>(
166
- `SELECT COUNT(*) AS c FROM memory_items WHERE status = 'active' AND scope_id = ?`,
166
+ `SELECT COUNT(*) AS c FROM memory_graph_nodes WHERE fidelity != 'gone' AND scope_id = ?`,
167
167
  scopeId,
168
168
  );
169
169
 
@@ -32,7 +32,7 @@ function getDatabaseSizeBytes(): number | null {
32
32
  function getMemoryItemCount(): number {
33
33
  try {
34
34
  const rows = rawAll<{ c: number }>(
35
- "SELECT COUNT(*) AS c FROM memory_items",
35
+ "SELECT COUNT(*) AS c FROM memory_graph_nodes",
36
36
  );
37
37
  return rows[0]?.c ?? 0;
38
38
  } catch {
@@ -100,34 +100,36 @@ function searchMemoryItems(query: string, limit: number): GlobalSearchMemory[] {
100
100
 
101
101
  interface MemoryRow {
102
102
  id: string;
103
- kind: string;
104
- statement: string;
105
- subject: string;
103
+ type: string;
104
+ content: string;
106
105
  confidence: number;
107
- last_seen_at: number;
106
+ last_accessed: number;
108
107
  }
109
108
 
110
- // Search on both statement and subject for broader recall
111
109
  const rows = rawAll<MemoryRow>(
112
- `SELECT id, kind, statement, subject, confidence, last_seen_at
113
- FROM memory_items
114
- WHERE (statement LIKE ? OR subject LIKE ?) AND status = 'active'
115
- ORDER BY last_seen_at DESC
110
+ `SELECT id, type, content, confidence, last_accessed
111
+ FROM memory_graph_nodes
112
+ WHERE content LIKE ? AND fidelity != 'gone'
113
+ ORDER BY last_accessed DESC
116
114
  LIMIT ?`,
117
115
  likePattern,
118
- likePattern,
119
116
  limit,
120
117
  );
121
118
 
122
- return rows.map((r) => ({
123
- id: r.id,
124
- kind: r.kind,
125
- text: r.statement,
126
- subject: r.subject || null,
127
- confidence: r.confidence,
128
- updatedAt: r.last_seen_at,
129
- source: "lexical" as const,
130
- }));
119
+ return rows.map((r) => {
120
+ const nl = r.content.indexOf("\n");
121
+ const subject = nl >= 0 ? r.content.slice(0, nl) : r.content;
122
+ const statement = nl >= 0 ? r.content.slice(nl + 1) : r.content;
123
+ return {
124
+ id: r.id,
125
+ kind: r.type,
126
+ text: statement,
127
+ subject: subject || null,
128
+ confidence: r.confidence,
129
+ updatedAt: r.last_accessed,
130
+ source: "lexical" as const,
131
+ };
132
+ });
131
133
  }
132
134
 
133
135
  async function searchMemoriesSemantic(
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Route handlers for conversation group management.
3
+ *
4
+ * GET /v1/groups — list all groups
5
+ * POST /v1/groups — create a custom group
6
+ * PATCH /v1/groups/:groupId — update a group
7
+ * DELETE /v1/groups/:groupId — delete a group
8
+ * POST /v1/groups/reorder — reorder groups
9
+ */
10
+
11
+ import { z } from "zod";
12
+
13
+ import {
14
+ createGroup,
15
+ deleteGroup,
16
+ getGroup,
17
+ listGroups,
18
+ reorderGroups,
19
+ updateGroup,
20
+ } from "../../memory/group-crud.js";
21
+ import { httpError } from "../http-errors.js";
22
+ import type { RouteDefinition } from "../http-router.js";
23
+
24
+ function serializeGroup(group: ReturnType<typeof getGroup>) {
25
+ if (!group) return null;
26
+ return {
27
+ id: group.id,
28
+ name: group.name,
29
+ sortPosition: group.sortPosition,
30
+ isSystemGroup: group.isSystemGroup,
31
+ };
32
+ }
33
+
34
+ export function groupRouteDefinitions(): RouteDefinition[] {
35
+ return [
36
+ {
37
+ endpoint: "groups",
38
+ method: "GET",
39
+ policyKey: "groups",
40
+ summary: "List groups",
41
+ description: "Return all conversation groups.",
42
+ tags: ["groups"],
43
+ handler: () => {
44
+ const groups = listGroups();
45
+ return Response.json({
46
+ groups: groups.map(serializeGroup),
47
+ });
48
+ },
49
+ },
50
+ {
51
+ endpoint: "groups",
52
+ method: "POST",
53
+ policyKey: "groups",
54
+ summary: "Create group",
55
+ description:
56
+ "Create a new custom conversation group. Server assigns sort_position.",
57
+ tags: ["groups"],
58
+ requestBody: z.object({
59
+ name: z.string().describe("Group name"),
60
+ }),
61
+ handler: async ({ req }) => {
62
+ const body = (await req.json()) as { name?: string };
63
+ if (!body.name || typeof body.name !== "string") {
64
+ return httpError("BAD_REQUEST", "Missing or invalid name", 400);
65
+ }
66
+ const group = createGroup(body.name);
67
+ return Response.json(serializeGroup(group), { status: 201 });
68
+ },
69
+ },
70
+ {
71
+ endpoint: "groups/:groupId",
72
+ method: "PATCH",
73
+ policyKey: "groups",
74
+ summary: "Update group",
75
+ description: "Update a conversation group's name or sort position.",
76
+ tags: ["groups"],
77
+ requestBody: z.object({
78
+ name: z.string().optional(),
79
+ sortPosition: z.number().optional(),
80
+ }),
81
+ handler: async ({ req, params }) => {
82
+ const groupId = params.groupId;
83
+ const existing = getGroup(groupId);
84
+ if (!existing) {
85
+ return httpError("NOT_FOUND", "Group not found", 404);
86
+ }
87
+ const body = (await req.json()) as {
88
+ name?: string;
89
+ sortPosition?: number;
90
+ };
91
+ if (body.name !== undefined && typeof body.name !== "string") {
92
+ return httpError("BAD_REQUEST", "name must be a string", 400);
93
+ }
94
+ if (
95
+ body.sortPosition !== undefined &&
96
+ typeof body.sortPosition !== "number"
97
+ ) {
98
+ return httpError("BAD_REQUEST", "sortPosition must be a number", 400);
99
+ }
100
+ // System groups allow name changes but block sortPosition/delete.
101
+ if (existing.isSystemGroup && body.sortPosition !== undefined) {
102
+ return httpError(
103
+ "FORBIDDEN",
104
+ "System group sort position cannot be changed",
105
+ 403,
106
+ );
107
+ }
108
+ // Custom group sort_position must be >= 3
109
+ if (
110
+ body.sortPosition !== undefined &&
111
+ (typeof body.sortPosition !== "number" ||
112
+ !isFinite(body.sortPosition) ||
113
+ body.sortPosition < 3)
114
+ ) {
115
+ return httpError(
116
+ "BAD_REQUEST",
117
+ "Custom group sort_position must be >= 3",
118
+ 400,
119
+ );
120
+ }
121
+ const updated = updateGroup(groupId, {
122
+ name: body.name,
123
+ sortPosition: body.sortPosition,
124
+ });
125
+ if (!updated) {
126
+ return httpError("NOT_FOUND", "Group not found", 404);
127
+ }
128
+ return Response.json(serializeGroup(updated));
129
+ },
130
+ },
131
+ {
132
+ endpoint: "groups/:groupId",
133
+ method: "DELETE",
134
+ policyKey: "groups",
135
+ summary: "Delete group",
136
+ description: "Delete a custom conversation group.",
137
+ tags: ["groups"],
138
+ handler: ({ params }) => {
139
+ const groupId = params.groupId;
140
+ const existing = getGroup(groupId);
141
+ if (!existing) {
142
+ return httpError("NOT_FOUND", "Group not found", 404);
143
+ }
144
+ // System groups cannot be deleted
145
+ if (existing.isSystemGroup) {
146
+ return httpError("FORBIDDEN", "System groups cannot be deleted", 403);
147
+ }
148
+ deleteGroup(groupId);
149
+ return new Response(null, { status: 204 });
150
+ },
151
+ },
152
+ {
153
+ endpoint: "groups/reorder",
154
+ method: "POST",
155
+ policyKey: "groups/reorder",
156
+ summary: "Reorder groups",
157
+ description: "Batch-update sort positions for conversation groups.",
158
+ tags: ["groups"],
159
+ requestBody: z.object({
160
+ updates: z
161
+ .array(
162
+ z.object({
163
+ groupId: z.string(),
164
+ sortPosition: z.number(),
165
+ }),
166
+ )
167
+ .describe("Array of { groupId, sortPosition } objects"),
168
+ }),
169
+ handler: async ({ req }) => {
170
+ const body = (await req.json()) as {
171
+ updates?: Array<{
172
+ groupId: string;
173
+ sortPosition: number;
174
+ }>;
175
+ };
176
+ if (!Array.isArray(body.updates)) {
177
+ return httpError("BAD_REQUEST", "Missing updates array", 400);
178
+ }
179
+ // Validate: no system group reordering, no sort_position < 3 for custom groups
180
+ for (const update of body.updates) {
181
+ const group = getGroup(update.groupId);
182
+ if (!group) continue;
183
+ if (group.isSystemGroup) {
184
+ return httpError(
185
+ "FORBIDDEN",
186
+ `Cannot reorder system group: ${update.groupId}`,
187
+ 403,
188
+ );
189
+ }
190
+ if (
191
+ typeof update.sortPosition !== "number" ||
192
+ !isFinite(update.sortPosition) ||
193
+ update.sortPosition < 3
194
+ ) {
195
+ return httpError(
196
+ "BAD_REQUEST",
197
+ `Custom group sort_position must be >= 3 (got ${update.sortPosition} for ${update.groupId})`,
198
+ 400,
199
+ );
200
+ }
201
+ }
202
+ reorderGroups(body.updates);
203
+ return Response.json({ ok: true });
204
+ },
205
+ },
206
+ ];
207
+ }
@@ -23,7 +23,10 @@ import { requireBoundGuardian } from "../auth/require-bound-guardian.js";
23
23
  import type { AuthContext } from "../auth/types.js";
24
24
  import { processGuardianDecision } from "../guardian-action-service.js";
25
25
  import type { GuardianDecisionPrompt } from "../guardian-decision-types.js";
26
- import { buildDecisionActions } from "../guardian-decision-types.js";
26
+ import {
27
+ buildDecisionActions,
28
+ GUARDIAN_DECISION_ACTIONS,
29
+ } from "../guardian-decision-types.js";
27
30
  import { httpError } from "../http-errors.js";
28
31
  import type { RouteDefinition } from "../http-router.js";
29
32
 
@@ -190,13 +193,15 @@ export function listGuardianDecisionPrompts(params: {
190
193
  * Map a canonical guardian request to the client-facing prompt format.
191
194
  *
192
195
  * Generates kind-specific questionText and action sets:
193
- * - `tool_approval`: "Approve tool: <name>" with approve/reject actions
194
- * - `pending_question`: voice-originated question with approve/reject actions
195
- * - `access_request`: explicit "Access Request" label with approve/reject actions
196
- * and text fallback instructions (request code + "open invite flow")
196
+ * - `tool_approval`: temporal modes (approve_once, approve_10m, approve_conversation) + reject
197
+ * - `pending_question`: approve_once + reject only
198
+ * - `access_request`: approve_once + reject only, with text fallback instructions
199
+ * (request code + "open invite flow")
200
+ * - `tool_grant_request`: approve_once + reject only
197
201
  *
198
- * All kinds use `forGuardianOnBehalf: true` (no approve_always) since the
199
- * guardian is acting on behalf of a requester.
202
+ * Only `tool_approval` receives temporal modes because time-scoped grants
203
+ * are meaningful only for tool execution. All other kinds get a simple
204
+ * approve_once/reject pair.
200
205
  */
201
206
  function mapCanonicalRequestToPrompt(
202
207
  req: CanonicalGuardianRequest,
@@ -204,9 +209,15 @@ function mapCanonicalRequestToPrompt(
204
209
  ): GuardianDecisionPrompt {
205
210
  const questionText = buildKindAwareQuestionText(req);
206
211
 
207
- // Guardian-on-behalf prompts include approve_once, temporal modes
208
- // (approve_10m, approve_conversation), and reject but not approve_always.
209
- const actions = buildDecisionActions({ forGuardianOnBehalf: true });
212
+ // Only tool_approval gets temporal modes (approve_10m, approve_conversation);
213
+ // all other kinds get a simple approve_once + reject pair.
214
+ const actions =
215
+ req.kind === "tool_approval"
216
+ ? buildDecisionActions({ forGuardianOnBehalf: true })
217
+ : [
218
+ GUARDIAN_DECISION_ACTIONS.approve_once,
219
+ GUARDIAN_DECISION_ACTIONS.reject,
220
+ ];
210
221
 
211
222
  const expiresAt = req.expiresAt
212
223
  ? new Date(req.expiresAt).getTime()
@@ -19,7 +19,7 @@ import { getLogger } from "../../util/logger.js";
19
19
  import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
20
20
  import { mintCredentialPair } from "../auth/credential-service.js";
21
21
  import { httpError } from "../http-errors.js";
22
- import { isPrivateAddress } from "../middleware/auth.js";
22
+ import { isLoopbackAddress, isPrivateAddress } from "../middleware/auth.js";
23
23
 
24
24
  /** Bun server shape needed for requestIP -- avoids importing the full Bun type. */
25
25
  type ServerWithRequestIP = {
@@ -87,30 +87,34 @@ export async function handleGuardianBootstrap(
87
87
  req: Request,
88
88
  server: ServerWithRequestIP,
89
89
  ): Promise<Response> {
90
- // Reject non-private-network peers (allows loopback, Docker bridge, etc.)
90
+ // In non-containerized (bare-metal) mode, restrict to loopback only
91
+ // the runtime binds to localhost and LAN peers should not be able to
92
+ // bootstrap even if they somehow reach the endpoint.
93
+ // In containerized (Docker) mode, accept any private-network peer because
94
+ // the gateway connects over the Docker bridge (e.g. 172.17.0.1) and the
95
+ // GUARDIAN_BOOTSTRAP_SECRET enforced at the gateway layer provides the
96
+ // real authentication.
91
97
  const peerIp = server.requestIP(req)?.address;
92
- if ((!peerIp || !isPrivateAddress(peerIp)) && !isHttpAuthDisabled()) {
98
+ const containerized = getIsContainerized();
99
+ const peerAllowed = containerized
100
+ ? isPrivateAddress(peerIp ?? "")
101
+ : isLoopbackAddress(peerIp ?? "");
102
+ if (!peerAllowed && !isHttpAuthDisabled()) {
93
103
  return httpError("FORBIDDEN", "Bootstrap endpoint is local-only", 403);
94
104
  }
95
105
 
96
- // Reject requests forwarded from public networks. The gateway sets
97
- // x-forwarded-for to the real client IP; if that IP is on a private
98
- // network (loopback, Docker bridge, RFC 1918) the request is still
99
- // considered local. Only reject when the forwarded IP is public.
106
+ // In non-containerized mode, any x-forwarded-for header means the request
107
+ // came through the gateway from a non-loopback client. Legitimate bare-metal
108
+ // bootstrap clients connect from localhost; the gateway does not inject
109
+ // x-forwarded-for for loopback peers (see gateway/src/index.ts). Reject
110
+ // forwarded requests to prevent LAN-adjacent clients from bootstrapping.
100
111
  //
101
- // Skip this check when running in a container: the peer IP was already
102
- // validated above (Docker bridge network = private), so the request
103
- // reached us through a co-located gateway. The x-forwarded-for header
104
- // reflects the original external client (e.g. platform proxy) and is
105
- // not meaningful for local-only enforcement in this topology.
112
+ // In containerized mode, skip this check: the peer IP was already validated
113
+ // above (Docker bridge network = private), and the x-forwarded-for header
114
+ // reflects the original external client which is not meaningful for
115
+ // local-only enforcement in this topology.
106
116
  const forwarded = req.headers.get("x-forwarded-for");
107
- const forwardedIp = forwarded ? forwarded.split(",")[0].trim() : null;
108
- if (
109
- forwardedIp &&
110
- !isPrivateAddress(forwardedIp) &&
111
- !isHttpAuthDisabled() &&
112
- !getIsContainerized()
113
- ) {
117
+ if (forwarded && !isHttpAuthDisabled() && !getIsContainerized()) {
114
118
  return httpError("FORBIDDEN", "Bootstrap endpoint is local-only", 403);
115
119
  }
116
120
 
@@ -44,6 +44,7 @@ import { processChannelMessageInBackground } from "./inbound-stages/background-d
44
44
  import { handleBootstrapIntercept } from "./inbound-stages/bootstrap-intercept.js";
45
45
  import { handleEditIntercept } from "./inbound-stages/edit-intercept.js";
46
46
  import { handleEscalationIntercept } from "./inbound-stages/escalation-intercept.js";
47
+ import { handleGuardianActivationIntercept } from "./inbound-stages/guardian-activation-intercept.js";
47
48
  import { handleGuardianReplyIntercept } from "./inbound-stages/guardian-reply-intercept.js";
48
49
  import { runSecretIngressCheck } from "./inbound-stages/secret-ingress-check.js";
49
50
  import { tryTranscribeAudioAttachments } from "./inbound-stages/transcribe-audio.js";
@@ -199,6 +200,24 @@ export async function handleChannelInbound(
199
200
  // ACL deny path rather than bypassing it.
200
201
  const hasSenderIdentityClaim = rawSenderId !== undefined;
201
202
 
203
+ // ── Guardian channel activation ──
204
+ // When a bare /start arrives on a channel with no guardian, auto-initiate
205
+ // guardian verification so the first user can claim the channel.
206
+ const guardianActivationResponse = await handleGuardianActivationIntercept({
207
+ sourceChannel,
208
+ conversationExternalId,
209
+ rawSenderId,
210
+ canonicalSenderId,
211
+ actorDisplayName: body.actorDisplayName,
212
+ actorUsername: body.actorUsername,
213
+ sourceMetadata: body.sourceMetadata,
214
+ replyCallbackUrl: body.replyCallbackUrl,
215
+ mintBearerToken,
216
+ assistantId,
217
+ externalMessageId,
218
+ });
219
+ if (guardianActivationResponse) return guardianActivationResponse;
220
+
202
221
  // ── Ingress ACL enforcement ──
203
222
  const aclResult = await enforceIngressAcl({
204
223
  canonicalSenderId,
@@ -15,6 +15,7 @@ import * as deliveryCrud from "../../../memory/delivery-crud.js";
15
15
  import * as deliveryStatus from "../../../memory/delivery-status.js";
16
16
  import {
17
17
  extractChannelFromCallbackUrl,
18
+ extractMessageTsFromCallbackUrl,
18
19
  extractThreadTsFromCallbackUrl,
19
20
  setThreadTs,
20
21
  } from "../../../memory/slack-thread-store.js";
@@ -328,9 +329,49 @@ export function setSlackThinkingStatus(
328
329
  // the correct thread for the Assistants API status.
329
330
  const threadTs = extractThreadTsFromCallbackUrl(callbackUrl);
330
331
 
331
- // If there's no thread context, we can't set a thread status — bail.
332
+ // For non-threaded DMs, fall back to emoji reaction on the original message.
332
333
  if (!threadTs) {
333
- return () => {};
334
+ const messageTs = extractMessageTsFromCallbackUrl(callbackUrl);
335
+ if (!messageTs) return () => {};
336
+
337
+ const addPromise = deliverChannelReply(
338
+ callbackUrl,
339
+ {
340
+ chatId,
341
+ assistantId,
342
+ reaction: { action: "add", name: "eyes", messageTs },
343
+ },
344
+ mintBearerToken(),
345
+ ).catch((err) => {
346
+ log.debug({ err, chatId, messageTs }, "Failed to add Slack eyes reaction");
347
+ });
348
+
349
+ const clearReaction = () => {
350
+ if (cleared) return;
351
+ cleared = true;
352
+ clearTimeout(safetyTimer);
353
+ void addPromise.then(() =>
354
+ deliverChannelReply(
355
+ callbackUrl,
356
+ {
357
+ chatId,
358
+ assistantId,
359
+ reaction: { action: "remove", name: "eyes", messageTs },
360
+ },
361
+ mintBearerToken(),
362
+ ).catch((err) => {
363
+ log.debug(
364
+ { err, chatId, messageTs },
365
+ "Failed to remove Slack eyes reaction",
366
+ );
367
+ }),
368
+ );
369
+ };
370
+
371
+ const safetyTimer = setTimeout(clearReaction, SLACK_THINKING_MAX_DURATION_MS);
372
+ (safetyTimer as { unref?: () => void }).unref?.();
373
+
374
+ return clearReaction;
334
375
  }
335
376
 
336
377
  // Track the set promise so clear waits for it to settle first,