@agent-native/core 0.111.4 → 0.113.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 (574) hide show
  1. package/corpus/README.md +4 -2
  2. package/corpus/core/CHANGELOG.md +34 -0
  3. package/corpus/core/docs/AGENTS.md +7 -0
  4. package/corpus/core/docs/content/integrations.mdx +63 -2
  5. package/corpus/core/docs/design/provider-integration-authority.md +117 -0
  6. package/corpus/core/package.json +8 -1
  7. package/corpus/core/scripts/materialize-source-corpus.mjs +9 -2
  8. package/corpus/core/src/cli/atomic-json-file.ts +324 -0
  9. package/corpus/core/src/cli/claude-code-participant.ts +515 -0
  10. package/corpus/core/src/cli/code-agent-executor.ts +35 -15
  11. package/corpus/core/src/cli/code-agent-runs.concurrent-worker.ts +33 -0
  12. package/corpus/core/src/cli/code-agent-runs.ts +70 -36
  13. package/corpus/core/src/cli/codex-cli-participant.ts +496 -0
  14. package/corpus/core/src/cli/multi-frontier-runs.ts +1952 -0
  15. package/corpus/core/src/client/chat/ChatHistoryList.tsx +7 -404
  16. package/corpus/core/src/coding-tools/index.ts +27 -8
  17. package/corpus/core/src/embeddings/index.ts +233 -0
  18. package/corpus/core/src/index.ts +2 -0
  19. package/corpus/core/src/integrations/index.ts +10 -0
  20. package/corpus/core/src/integrations/slack-oauth.ts +1 -0
  21. package/corpus/core/src/integrations/webhook-delivery.ts +55 -0
  22. package/corpus/core/src/notifications/channels.ts +4 -10
  23. package/corpus/core/src/provider-api/actions/custom-provider-registration.ts +197 -0
  24. package/corpus/core/src/provider-api/actions/delete-staged-dataset.ts +3 -42
  25. package/corpus/core/src/provider-api/actions/list-staged-datasets.ts +3 -45
  26. package/corpus/core/src/provider-api/actions/provider-api-audit.ts +88 -0
  27. package/corpus/core/src/provider-api/actions/provider-api.ts +460 -0
  28. package/corpus/core/src/provider-api/actions/query-staged-dataset.ts +3 -140
  29. package/corpus/core/src/provider-api/actions/staged-datasets.ts +359 -0
  30. package/corpus/core/src/provider-api/gong.ts +108 -0
  31. package/corpus/core/src/scripts/docs/source-search.ts +2 -1
  32. package/corpus/core/src/search/index.ts +413 -0
  33. package/corpus/core/src/server/google-oauth-credentials.ts +80 -3
  34. package/corpus/core/src/server/index.ts +6 -0
  35. package/corpus/core/src/styles/chat-history-list.css +1 -313
  36. package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +32 -12
  37. package/corpus/core/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +10 -0
  38. package/corpus/core/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  39. package/corpus/core/src/templates/default/.agents/skills/integration-webhooks/SKILL.md +323 -0
  40. package/corpus/core/src/templates/default/.agents/skills/onboarding/SKILL.md +56 -0
  41. package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +273 -0
  42. package/corpus/core/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +11 -2
  43. package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  44. package/corpus/core/src/templates/default/AGENTS.md +25 -18
  45. package/corpus/core/src/templates/headless/.agents/skills/actions/SKILL.md +512 -0
  46. package/corpus/core/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +10 -0
  47. package/corpus/core/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  48. package/corpus/core/src/templates/headless/.agents/skills/integration-webhooks/SKILL.md +323 -0
  49. package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +273 -0
  50. package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  51. package/corpus/core/src/templates/headless/AGENTS.md +7 -0
  52. package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -12
  53. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +10 -0
  54. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  55. package/corpus/core/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  56. package/corpus/core/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +11 -2
  57. package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  58. package/corpus/core/src/templates/workspace-core/AGENTS.md +4 -0
  59. package/corpus/core/src/templates/workspace-root/AGENTS.md +4 -0
  60. package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +32 -12
  61. package/corpus/templates/analytics/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  62. package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +11 -2
  63. package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  64. package/corpus/templates/analytics/actions/delete-staged-dataset.ts +3 -23
  65. package/corpus/templates/analytics/actions/list-staged-datasets.ts +3 -27
  66. package/corpus/templates/analytics/actions/provider-api-catalog.ts +16 -19
  67. package/corpus/templates/analytics/actions/provider-api-docs.ts +3 -5
  68. package/corpus/templates/analytics/actions/provider-api-request.ts +162 -185
  69. package/corpus/templates/analytics/actions/query-staged-dataset.ts +3 -47
  70. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +52 -161
  71. package/corpus/templates/assets/.agents/skills/actions/SKILL.md +32 -12
  72. package/corpus/templates/assets/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  73. package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +11 -2
  74. package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  75. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +63 -160
  76. package/corpus/templates/brain/.agents/skills/actions/SKILL.md +32 -12
  77. package/corpus/templates/brain/.agents/skills/brain/RUNBOOK.md +48 -5
  78. package/corpus/templates/brain/.agents/skills/brain/SKILL.md +46 -14
  79. package/corpus/templates/brain/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  80. package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +11 -2
  81. package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  82. package/corpus/templates/brain/README.md +34 -3
  83. package/corpus/templates/brain/actions/_schemas.ts +13 -7
  84. package/corpus/templates/brain/actions/approve-proposal.ts +2 -0
  85. package/corpus/templates/brain/actions/claim-distillation.ts +24 -27
  86. package/corpus/templates/brain/actions/create-source.ts +1 -1
  87. package/corpus/templates/brain/actions/delete-staged-dataset.ts +3 -24
  88. package/corpus/templates/brain/actions/get-knowledge.ts +6 -2
  89. package/corpus/templates/brain/actions/get-pilot-report.ts +44 -8
  90. package/corpus/templates/brain/actions/import-capture.ts +21 -9
  91. package/corpus/templates/brain/actions/import-transcript.ts +42 -14
  92. package/corpus/templates/brain/actions/list-captures.ts +10 -1
  93. package/corpus/templates/brain/actions/list-distillation-queue.ts +39 -14
  94. package/corpus/templates/brain/actions/list-projects.ts +51 -0
  95. package/corpus/templates/brain/actions/list-proposals.ts +80 -4
  96. package/corpus/templates/brain/actions/list-sources.ts +17 -3
  97. package/corpus/templates/brain/actions/list-staged-datasets.ts +3 -28
  98. package/corpus/templates/brain/actions/manage-project.ts +118 -0
  99. package/corpus/templates/brain/actions/mark-capture-distilled.ts +68 -20
  100. package/corpus/templates/brain/actions/navigate.ts +1 -0
  101. package/corpus/templates/brain/actions/provider-api-catalog.ts +5 -11
  102. package/corpus/templates/brain/actions/provider-api-docs.ts +3 -5
  103. package/corpus/templates/brain/actions/provider-api-request.ts +3 -37
  104. package/corpus/templates/brain/actions/query-staged-dataset.ts +3 -48
  105. package/corpus/templates/brain/actions/reject-proposal.ts +6 -1
  106. package/corpus/templates/brain/actions/resanitize-captures.ts +159 -33
  107. package/corpus/templates/brain/actions/review-proposal.ts +2 -0
  108. package/corpus/templates/brain/actions/search-everything.ts +10 -1
  109. package/corpus/templates/brain/actions/search-knowledge.ts +1 -1
  110. package/corpus/templates/brain/actions/set-settings.ts +36 -1
  111. package/corpus/templates/brain/actions/update-proposal.ts +2 -0
  112. package/corpus/templates/brain/actions/update-source.ts +5 -1
  113. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +48 -154
  114. package/corpus/templates/brain/app/hooks/use-distillation-bridge.ts +18 -9
  115. package/corpus/templates/brain/app/hooks/use-navigation-state.ts +3 -0
  116. package/corpus/templates/brain/app/i18n-data.ts +731 -2
  117. package/corpus/templates/brain/app/lib/brain.ts +88 -1
  118. package/corpus/templates/brain/app/lib/ingest-handoff.ts +35 -0
  119. package/corpus/templates/brain/app/routes/ops.tsx +47 -0
  120. package/corpus/templates/brain/app/routes/review.tsx +41 -2
  121. package/corpus/templates/brain/app/routes/search.tsx +33 -2
  122. package/corpus/templates/brain/app/routes/settings.tsx +158 -0
  123. package/corpus/templates/brain/app/routes/sources.tsx +31 -0
  124. package/corpus/templates/brain/changelog/2026-07-19-added-private-source-safe-semantic-search.md +6 -0
  125. package/corpus/templates/brain/changelog/2026-07-19-slack-backfills-can-now-join-configured-public-channels-befo.md +6 -0
  126. package/corpus/templates/brain/changelog/2026-07-19-slack-backfills-now-continue-across-the-configured-number-of.md +6 -0
  127. package/corpus/templates/brain/changelog/2026-07-19-slack-backfills-now-start-with-a-safe-four-week-window-and-r.md +6 -0
  128. package/corpus/templates/brain/jobs/process-ingest-queue.ts +270 -36
  129. package/corpus/templates/brain/package.json +1 -0
  130. package/corpus/templates/brain/server/db/index.ts +18 -0
  131. package/corpus/templates/brain/server/db/schema.ts +197 -1
  132. package/corpus/templates/brain/server/jobs/distillation-queue.ts +12 -5
  133. package/corpus/templates/brain/server/lib/audiences.ts +708 -0
  134. package/corpus/templates/brain/server/lib/brain-health.ts +251 -38
  135. package/corpus/templates/brain/server/lib/brain.ts +877 -50
  136. package/corpus/templates/brain/server/lib/capture-sanitization.ts +217 -53
  137. package/corpus/templates/brain/server/lib/connectors.ts +609 -72
  138. package/corpus/templates/brain/server/lib/demo.ts +17 -4
  139. package/corpus/templates/brain/server/lib/hybrid-search.ts +363 -0
  140. package/corpus/templates/brain/server/lib/ingest-queue.ts +104 -0
  141. package/corpus/templates/brain/server/lib/privacy-readiness.ts +24 -0
  142. package/corpus/templates/brain/server/lib/search-index-contracts.ts +72 -0
  143. package/corpus/templates/brain/server/lib/search-index.ts +714 -0
  144. package/corpus/templates/brain/server/lib/search.ts +120 -4
  145. package/corpus/templates/brain/server/lib/sensitivity-policy.ts +174 -0
  146. package/corpus/templates/brain/server/lib/slack-channel-membership.ts +44 -0
  147. package/corpus/templates/brain/server/lib/slack-events.ts +281 -0
  148. package/corpus/templates/brain/server/onboarding.ts +29 -0
  149. package/corpus/templates/brain/server/plugins/db.ts +204 -0
  150. package/corpus/templates/brain/server/register-secrets.ts +46 -0
  151. package/corpus/templates/brain/server/routes/api/_agent-native/brain/ingest.post.ts +36 -16
  152. package/corpus/templates/brain/server/routes/api/_agent-native/brain/slack-events.post.ts +28 -0
  153. package/corpus/templates/brain/shared/slack-source-config.ts +60 -0
  154. package/corpus/templates/brain/shared/types.ts +10 -0
  155. package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +32 -12
  156. package/corpus/templates/calendar/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  157. package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +11 -2
  158. package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  159. package/corpus/templates/calendar/actions/delete-staged-dataset.ts +3 -24
  160. package/corpus/templates/calendar/actions/list-staged-datasets.ts +3 -28
  161. package/corpus/templates/calendar/actions/provider-api-catalog.ts +5 -11
  162. package/corpus/templates/calendar/actions/provider-api-docs.ts +3 -5
  163. package/corpus/templates/calendar/actions/provider-api-request.ts +3 -37
  164. package/corpus/templates/calendar/actions/query-staged-dataset.ts +3 -48
  165. package/corpus/templates/calendar/server/handlers/gong.ts +6 -61
  166. package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -8
  167. package/corpus/templates/calendar/server/lib/google-calendar.ts +7 -45
  168. package/corpus/templates/chat/.agents/skills/actions/SKILL.md +32 -12
  169. package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +10 -0
  170. package/corpus/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  171. package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +11 -2
  172. package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  173. package/corpus/templates/chat/AGENTS.md +5 -2
  174. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +51 -157
  175. package/corpus/templates/clips/.agents/skills/actions/SKILL.md +32 -12
  176. package/corpus/templates/clips/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  177. package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +11 -2
  178. package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  179. package/corpus/templates/clips/AGENTS.md +11 -0
  180. package/corpus/templates/clips/actions/export-to-brain.ts +505 -171
  181. package/corpus/templates/clips/changelog/2026-07-19-ready-clips-transcripts-can-be-backfilled-to-brain-for-a-bou.md +6 -0
  182. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +1 -1
  183. package/corpus/templates/clips/server/lib/google-calendar-client.ts +12 -22
  184. package/corpus/templates/clips/server/lib/google-calendar-oauth.ts +9 -6
  185. package/corpus/templates/clips/server/lib/slack-oauth.ts +12 -47
  186. package/corpus/templates/clips/server/routes/_agent-native/google/auth-url.get.ts +2 -6
  187. package/corpus/templates/clips/server/routes/api/auth/google-calendar.get.ts +4 -4
  188. package/corpus/templates/content/.agents/skills/actions/SKILL.md +32 -12
  189. package/corpus/templates/content/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  190. package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +11 -2
  191. package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  192. package/corpus/templates/content/actions/delete-staged-dataset.ts +3 -24
  193. package/corpus/templates/content/actions/list-staged-datasets.ts +3 -28
  194. package/corpus/templates/content/actions/provider-api-catalog.ts +5 -11
  195. package/corpus/templates/content/actions/provider-api-docs.ts +3 -5
  196. package/corpus/templates/content/actions/provider-api-request.ts +3 -37
  197. package/corpus/templates/content/actions/query-staged-dataset.ts +3 -48
  198. package/corpus/templates/design/.agents/skills/actions/SKILL.md +32 -12
  199. package/corpus/templates/design/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  200. package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +11 -2
  201. package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  202. package/corpus/templates/design/actions/delete-staged-dataset.ts +4 -23
  203. package/corpus/templates/design/actions/list-staged-datasets.ts +4 -27
  204. package/corpus/templates/design/actions/provider-api-catalog.ts +15 -18
  205. package/corpus/templates/design/actions/provider-api-docs.ts +57 -48
  206. package/corpus/templates/design/actions/provider-api-request.ts +140 -164
  207. package/corpus/templates/design/actions/query-staged-dataset.ts +4 -47
  208. package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +32 -12
  209. package/corpus/templates/dispatch/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  210. package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +11 -2
  211. package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  212. package/corpus/templates/dispatch/actions/delete-staged-dataset.ts +4 -23
  213. package/corpus/templates/dispatch/actions/list-staged-datasets.ts +4 -30
  214. package/corpus/templates/dispatch/actions/provider-api-catalog.ts +15 -18
  215. package/corpus/templates/dispatch/actions/provider-api-docs.ts +57 -48
  216. package/corpus/templates/dispatch/actions/provider-api-request.ts +138 -163
  217. package/corpus/templates/dispatch/actions/query-staged-dataset.ts +4 -47
  218. package/corpus/templates/forms/.agents/skills/actions/SKILL.md +32 -12
  219. package/corpus/templates/forms/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  220. package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +11 -2
  221. package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  222. package/corpus/templates/forms/server/lib/integrations.ts +23 -22
  223. package/corpus/templates/macros/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  224. package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  225. package/corpus/templates/mail/.agents/skills/actions/SKILL.md +32 -12
  226. package/corpus/templates/mail/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  227. package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +11 -2
  228. package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  229. package/corpus/templates/mail/actions/delete-staged-dataset.ts +4 -23
  230. package/corpus/templates/mail/actions/list-staged-datasets.ts +4 -27
  231. package/corpus/templates/mail/actions/provider-api-catalog.ts +15 -18
  232. package/corpus/templates/mail/actions/provider-api-docs.ts +57 -48
  233. package/corpus/templates/mail/actions/provider-api-request.ts +146 -173
  234. package/corpus/templates/mail/actions/query-staged-dataset.ts +4 -47
  235. package/corpus/templates/mail/server/handlers/gong.ts +6 -61
  236. package/corpus/templates/mail/server/lib/google-auth.ts +10 -13
  237. package/corpus/templates/plan/.agents/skills/actions/SKILL.md +32 -12
  238. package/corpus/templates/plan/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  239. package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +11 -2
  240. package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  241. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +47 -156
  242. package/corpus/templates/slides/.agents/skills/actions/SKILL.md +32 -12
  243. package/corpus/templates/slides/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  244. package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +11 -2
  245. package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  246. package/corpus/templates/slides/actions/delete-staged-dataset.ts +4 -23
  247. package/corpus/templates/slides/actions/list-staged-datasets.ts +4 -27
  248. package/corpus/templates/slides/actions/provider-api-catalog.ts +15 -18
  249. package/corpus/templates/slides/actions/provider-api-docs.ts +57 -48
  250. package/corpus/templates/slides/actions/provider-api-request.ts +145 -172
  251. package/corpus/templates/slides/actions/query-staged-dataset.ts +4 -47
  252. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +11 -36
  253. package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +32 -12
  254. package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +10 -0
  255. package/corpus/templates/tasks/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  256. package/corpus/templates/tasks/.agents/skills/self-modifying-code/SKILL.md +11 -2
  257. package/corpus/templates/tasks/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  258. package/corpus/toolkit/CHANGELOG.md +125 -0
  259. package/corpus/toolkit/README.md +60 -0
  260. package/corpus/toolkit/export-snapshot.json +35 -0
  261. package/corpus/toolkit/migration-manifest.json +4 -0
  262. package/corpus/toolkit/package.json +281 -0
  263. package/corpus/toolkit/scripts/finalize-build.mjs +55 -0
  264. package/corpus/toolkit/src/app-shell/header-actions.tsx +84 -0
  265. package/corpus/toolkit/src/app-shell/index.ts +1 -0
  266. package/corpus/toolkit/src/chat-history/ChatHistoryList.tsx +469 -0
  267. package/corpus/toolkit/src/chat-history/index.ts +7 -0
  268. package/corpus/toolkit/src/chat-history.css +314 -0
  269. package/corpus/toolkit/src/collab-ui/AgentPresenceChip.tsx +69 -0
  270. package/corpus/toolkit/src/collab-ui/LiveCursorOverlay.tsx +241 -0
  271. package/corpus/toolkit/src/collab-ui/PresenceBar.tsx +346 -0
  272. package/corpus/toolkit/src/collab-ui/RecentEditHighlights.tsx +225 -0
  273. package/corpus/toolkit/src/collab-ui/RemoteSelectionRings.tsx +227 -0
  274. package/corpus/toolkit/src/collab-ui/agent-identity.ts +16 -0
  275. package/corpus/toolkit/src/collab-ui/index.ts +39 -0
  276. package/corpus/toolkit/src/collab-ui/lead-client.ts +32 -0
  277. package/corpus/toolkit/src/collab-ui/types.ts +96 -0
  278. package/corpus/toolkit/src/composer/AgentComposerFrame.tsx +59 -0
  279. package/corpus/toolkit/src/composer/ComposerPlusMenu.tsx +983 -0
  280. package/corpus/toolkit/src/composer/MentionPopover.tsx +412 -0
  281. package/corpus/toolkit/src/composer/PastedTextChip.tsx +150 -0
  282. package/corpus/toolkit/src/composer/PromptComposer.tsx +718 -0
  283. package/corpus/toolkit/src/composer/RealtimeVoiceMode.tsx +856 -0
  284. package/corpus/toolkit/src/composer/TiptapComposer.tsx +2936 -0
  285. package/corpus/toolkit/src/composer/VoiceButton.tsx +255 -0
  286. package/corpus/toolkit/src/composer/asset-picker-url.ts +80 -0
  287. package/corpus/toolkit/src/composer/attachment-accept.ts +71 -0
  288. package/corpus/toolkit/src/composer/draft-key.ts +7 -0
  289. package/corpus/toolkit/src/composer/extensions/FileReference.tsx +55 -0
  290. package/corpus/toolkit/src/composer/extensions/MentionReference.tsx +93 -0
  291. package/corpus/toolkit/src/composer/extensions/SkillReference.tsx +56 -0
  292. package/corpus/toolkit/src/composer/index.ts +79 -0
  293. package/corpus/toolkit/src/composer/pasted-text.ts +160 -0
  294. package/corpus/toolkit/src/composer/prompt-attachments.ts +93 -0
  295. package/corpus/toolkit/src/composer/realtime-voice-audio-level.ts +64 -0
  296. package/corpus/toolkit/src/composer/realtime-voice-transcript.ts +134 -0
  297. package/corpus/toolkit/src/composer/runtime-adapters.tsx +343 -0
  298. package/corpus/toolkit/src/composer/types.ts +66 -0
  299. package/corpus/toolkit/src/composer/use-file-search.ts +64 -0
  300. package/corpus/toolkit/src/composer/use-mention-search.ts +90 -0
  301. package/corpus/toolkit/src/composer/use-skills.ts +45 -0
  302. package/corpus/toolkit/src/composer/useRealtimeVoiceMode.tsx +2117 -0
  303. package/corpus/toolkit/src/composer/useVoiceDictation.ts +1191 -0
  304. package/corpus/toolkit/src/context-ui/ContextMeter.tsx +101 -0
  305. package/corpus/toolkit/src/context-ui/ContextSegmentRow.tsx +184 -0
  306. package/corpus/toolkit/src/context-ui/ContextTreemap.tsx +125 -0
  307. package/corpus/toolkit/src/context-ui/ContextXRayPanel.tsx +377 -0
  308. package/corpus/toolkit/src/context-ui/format.ts +42 -0
  309. package/corpus/toolkit/src/context-ui/index.ts +15 -0
  310. package/corpus/toolkit/src/context-ui/types.ts +43 -0
  311. package/corpus/toolkit/src/design-tweaks/index.ts +1 -0
  312. package/corpus/toolkit/src/design-tweaks/visual-style-controls.tsx +1084 -0
  313. package/corpus/toolkit/src/editor/BubbleToolbar.tsx +253 -0
  314. package/corpus/toolkit/src/editor/CodeBlockNode.tsx +254 -0
  315. package/corpus/toolkit/src/editor/DragHandle.ts +1437 -0
  316. package/corpus/toolkit/src/editor/ImageExtension.ts +306 -0
  317. package/corpus/toolkit/src/editor/RegistryBlockContext.tsx +107 -0
  318. package/corpus/toolkit/src/editor/RegistryBlockNode.tsx +652 -0
  319. package/corpus/toolkit/src/editor/RichMarkdownEditor.tsx +81 -0
  320. package/corpus/toolkit/src/editor/RunId.ts +61 -0
  321. package/corpus/toolkit/src/editor/SharedRichEditor.tsx +321 -0
  322. package/corpus/toolkit/src/editor/SlashCommandMenu.tsx +310 -0
  323. package/corpus/toolkit/src/editor/extensions.ts +402 -0
  324. package/corpus/toolkit/src/editor/gfmDoc.ts +92 -0
  325. package/corpus/toolkit/src/editor/index.ts +93 -0
  326. package/corpus/toolkit/src/editor/registrySlashCommands.ts +131 -0
  327. package/corpus/toolkit/src/editor/surgical-apply.ts +192 -0
  328. package/corpus/toolkit/src/editor/useCollabReconcile.ts +589 -0
  329. package/corpus/toolkit/src/editor.css +510 -0
  330. package/corpus/toolkit/src/hooks/index.ts +2 -0
  331. package/corpus/toolkit/src/hooks/use-mobile.tsx +21 -0
  332. package/corpus/toolkit/src/hooks/use-toast.ts +188 -0
  333. package/corpus/toolkit/src/index.ts +8 -0
  334. package/corpus/toolkit/src/onboarding/index.ts +1 -0
  335. package/corpus/toolkit/src/provider.tsx +47 -0
  336. package/corpus/toolkit/src/sharing/VisibilityBadge.tsx +37 -0
  337. package/corpus/toolkit/src/sharing/index.ts +4 -0
  338. package/corpus/toolkit/src/styles.css +21 -0
  339. package/corpus/toolkit/src/ui/accordion.tsx +56 -0
  340. package/corpus/toolkit/src/ui/alert-dialog.tsx +141 -0
  341. package/corpus/toolkit/src/ui/alert.tsx +59 -0
  342. package/corpus/toolkit/src/ui/aspect-ratio.tsx +5 -0
  343. package/corpus/toolkit/src/ui/avatar.tsx +48 -0
  344. package/corpus/toolkit/src/ui/badge.tsx +37 -0
  345. package/corpus/toolkit/src/ui/breadcrumb.tsx +115 -0
  346. package/corpus/toolkit/src/ui/button.tsx +78 -0
  347. package/corpus/toolkit/src/ui/calendar.tsx +214 -0
  348. package/corpus/toolkit/src/ui/card.tsx +86 -0
  349. package/corpus/toolkit/src/ui/carousel.tsx +260 -0
  350. package/corpus/toolkit/src/ui/chart.tsx +375 -0
  351. package/corpus/toolkit/src/ui/checkbox.tsx +28 -0
  352. package/corpus/toolkit/src/ui/collapsible.tsx +9 -0
  353. package/corpus/toolkit/src/ui/command.tsx +174 -0
  354. package/corpus/toolkit/src/ui/context-menu.tsx +202 -0
  355. package/corpus/toolkit/src/ui/date-picker.tsx +64 -0
  356. package/corpus/toolkit/src/ui/dialog.tsx +146 -0
  357. package/corpus/toolkit/src/ui/drawer.tsx +126 -0
  358. package/corpus/toolkit/src/ui/dropdown-menu.tsx +218 -0
  359. package/corpus/toolkit/src/ui/form.tsx +177 -0
  360. package/corpus/toolkit/src/ui/hover-card.tsx +27 -0
  361. package/corpus/toolkit/src/ui/index.ts +52 -0
  362. package/corpus/toolkit/src/ui/input-otp.tsx +69 -0
  363. package/corpus/toolkit/src/ui/input.tsx +22 -0
  364. package/corpus/toolkit/src/ui/label.tsx +24 -0
  365. package/corpus/toolkit/src/ui/logo.tsx +36 -0
  366. package/corpus/toolkit/src/ui/menubar.tsx +235 -0
  367. package/corpus/toolkit/src/ui/navigation-menu.tsx +128 -0
  368. package/corpus/toolkit/src/ui/pagination.tsx +121 -0
  369. package/corpus/toolkit/src/ui/popover.tsx +44 -0
  370. package/corpus/toolkit/src/ui/progress.tsx +26 -0
  371. package/corpus/toolkit/src/ui/radio-group.tsx +42 -0
  372. package/corpus/toolkit/src/ui/resizable.tsx +43 -0
  373. package/corpus/toolkit/src/ui/scroll-area.tsx +46 -0
  374. package/corpus/toolkit/src/ui/select.tsx +158 -0
  375. package/corpus/toolkit/src/ui/separator.tsx +29 -0
  376. package/corpus/toolkit/src/ui/sheet.tsx +160 -0
  377. package/corpus/toolkit/src/ui/sidebar.tsx +777 -0
  378. package/corpus/toolkit/src/ui/skeleton.tsx +18 -0
  379. package/corpus/toolkit/src/ui/slider.tsx +26 -0
  380. package/corpus/toolkit/src/ui/sonner.tsx +58 -0
  381. package/corpus/toolkit/src/ui/spinner.tsx +17 -0
  382. package/corpus/toolkit/src/ui/switch.tsx +27 -0
  383. package/corpus/toolkit/src/ui/table.tsx +117 -0
  384. package/corpus/toolkit/src/ui/tabs.tsx +53 -0
  385. package/corpus/toolkit/src/ui/textarea.tsx +23 -0
  386. package/corpus/toolkit/src/ui/toast.tsx +127 -0
  387. package/corpus/toolkit/src/ui/toaster.tsx +33 -0
  388. package/corpus/toolkit/src/ui/toggle-group.tsx +59 -0
  389. package/corpus/toolkit/src/ui/toggle.tsx +43 -0
  390. package/corpus/toolkit/src/ui/tooltip.tsx +53 -0
  391. package/corpus/toolkit/src/ui/use-toast.ts +3 -0
  392. package/corpus/toolkit/src/utils.ts +8 -0
  393. package/corpus/toolkit/tsconfig.json +23 -0
  394. package/dist/cli/atomic-json-file.d.ts +30 -0
  395. package/dist/cli/atomic-json-file.d.ts.map +1 -0
  396. package/dist/cli/atomic-json-file.js +240 -0
  397. package/dist/cli/atomic-json-file.js.map +1 -0
  398. package/dist/cli/claude-code-participant.d.ts +77 -0
  399. package/dist/cli/claude-code-participant.d.ts.map +1 -0
  400. package/dist/cli/claude-code-participant.js +355 -0
  401. package/dist/cli/claude-code-participant.js.map +1 -0
  402. package/dist/cli/code-agent-executor.d.ts +8 -9
  403. package/dist/cli/code-agent-executor.d.ts.map +1 -1
  404. package/dist/cli/code-agent-executor.js +27 -13
  405. package/dist/cli/code-agent-executor.js.map +1 -1
  406. package/dist/cli/code-agent-runs.concurrent-worker.d.ts +2 -0
  407. package/dist/cli/code-agent-runs.concurrent-worker.d.ts.map +1 -0
  408. package/dist/cli/code-agent-runs.concurrent-worker.js +32 -0
  409. package/dist/cli/code-agent-runs.concurrent-worker.js.map +1 -0
  410. package/dist/cli/code-agent-runs.d.ts +5 -0
  411. package/dist/cli/code-agent-runs.d.ts.map +1 -1
  412. package/dist/cli/code-agent-runs.js +51 -33
  413. package/dist/cli/code-agent-runs.js.map +1 -1
  414. package/dist/cli/codex-cli-participant.d.ts +77 -0
  415. package/dist/cli/codex-cli-participant.d.ts.map +1 -0
  416. package/dist/cli/codex-cli-participant.js +354 -0
  417. package/dist/cli/codex-cli-participant.js.map +1 -0
  418. package/dist/cli/multi-frontier-runs.d.ts +246 -0
  419. package/dist/cli/multi-frontier-runs.d.ts.map +1 -0
  420. package/dist/cli/multi-frontier-runs.js +1247 -0
  421. package/dist/cli/multi-frontier-runs.js.map +1 -0
  422. package/dist/client/chat/ChatHistoryList.d.ts +1 -87
  423. package/dist/client/chat/ChatHistoryList.d.ts.map +1 -1
  424. package/dist/client/chat/ChatHistoryList.js +1 -82
  425. package/dist/client/chat/ChatHistoryList.js.map +1 -1
  426. package/dist/coding-tools/index.d.ts +1 -0
  427. package/dist/coding-tools/index.d.ts.map +1 -1
  428. package/dist/coding-tools/index.js +25 -7
  429. package/dist/coding-tools/index.js.map +1 -1
  430. package/dist/collab/awareness.d.ts +2 -2
  431. package/dist/collab/awareness.d.ts.map +1 -1
  432. package/dist/embeddings/index.d.ts +24 -0
  433. package/dist/embeddings/index.d.ts.map +1 -0
  434. package/dist/embeddings/index.js +172 -0
  435. package/dist/embeddings/index.js.map +1 -0
  436. package/dist/index.d.ts +2 -0
  437. package/dist/index.d.ts.map +1 -1
  438. package/dist/index.js +2 -0
  439. package/dist/index.js.map +1 -1
  440. package/dist/integrations/index.d.ts +2 -1
  441. package/dist/integrations/index.d.ts.map +1 -1
  442. package/dist/integrations/index.js +2 -1
  443. package/dist/integrations/index.js.map +1 -1
  444. package/dist/integrations/slack-manifest.d.ts +1 -1
  445. package/dist/integrations/slack-oauth.d.ts +1 -1
  446. package/dist/integrations/slack-oauth.d.ts.map +1 -1
  447. package/dist/integrations/slack-oauth.js +1 -0
  448. package/dist/integrations/slack-oauth.js.map +1 -1
  449. package/dist/integrations/webhook-delivery.d.ts +23 -0
  450. package/dist/integrations/webhook-delivery.d.ts.map +1 -0
  451. package/dist/integrations/webhook-delivery.js +32 -0
  452. package/dist/integrations/webhook-delivery.js.map +1 -0
  453. package/dist/notifications/channels.d.ts.map +1 -1
  454. package/dist/notifications/channels.js +4 -9
  455. package/dist/notifications/channels.js.map +1 -1
  456. package/dist/notifications/routes.d.ts +3 -3
  457. package/dist/progress/routes.d.ts +1 -1
  458. package/dist/provider-api/actions/custom-provider-registration.d.ts +136 -0
  459. package/dist/provider-api/actions/custom-provider-registration.d.ts.map +1 -0
  460. package/dist/provider-api/actions/custom-provider-registration.js +154 -0
  461. package/dist/provider-api/actions/custom-provider-registration.js.map +1 -0
  462. package/dist/provider-api/actions/delete-staged-dataset.d.ts +1 -1
  463. package/dist/provider-api/actions/delete-staged-dataset.d.ts.map +1 -1
  464. package/dist/provider-api/actions/delete-staged-dataset.js +3 -34
  465. package/dist/provider-api/actions/delete-staged-dataset.js.map +1 -1
  466. package/dist/provider-api/actions/list-staged-datasets.d.ts +2 -3
  467. package/dist/provider-api/actions/list-staged-datasets.d.ts.map +1 -1
  468. package/dist/provider-api/actions/list-staged-datasets.js +3 -40
  469. package/dist/provider-api/actions/list-staged-datasets.js.map +1 -1
  470. package/dist/provider-api/actions/provider-api-audit.d.ts +7 -0
  471. package/dist/provider-api/actions/provider-api-audit.d.ts.map +1 -0
  472. package/dist/provider-api/actions/provider-api-audit.js +74 -0
  473. package/dist/provider-api/actions/provider-api-audit.js.map +1 -0
  474. package/dist/provider-api/actions/provider-api.d.ts +370 -0
  475. package/dist/provider-api/actions/provider-api.d.ts.map +1 -0
  476. package/dist/provider-api/actions/provider-api.js +280 -0
  477. package/dist/provider-api/actions/provider-api.js.map +1 -0
  478. package/dist/provider-api/actions/query-staged-dataset.d.ts +1 -1
  479. package/dist/provider-api/actions/query-staged-dataset.d.ts.map +1 -1
  480. package/dist/provider-api/actions/query-staged-dataset.js +3 -116
  481. package/dist/provider-api/actions/query-staged-dataset.js.map +1 -1
  482. package/dist/provider-api/actions/staged-datasets.d.ts +190 -0
  483. package/dist/provider-api/actions/staged-datasets.d.ts.map +1 -0
  484. package/dist/provider-api/actions/staged-datasets.js +210 -0
  485. package/dist/provider-api/actions/staged-datasets.js.map +1 -0
  486. package/dist/provider-api/gong.d.ts +44 -0
  487. package/dist/provider-api/gong.d.ts.map +1 -0
  488. package/dist/provider-api/gong.js +56 -0
  489. package/dist/provider-api/gong.js.map +1 -0
  490. package/dist/resources/handlers.d.ts +1 -1
  491. package/dist/scripts/docs/source-search.d.ts +2 -1
  492. package/dist/scripts/docs/source-search.d.ts.map +1 -1
  493. package/dist/scripts/docs/source-search.js +2 -1
  494. package/dist/scripts/docs/source-search.js.map +1 -1
  495. package/dist/search/index.d.ts +88 -0
  496. package/dist/search/index.d.ts.map +1 -0
  497. package/dist/search/index.js +267 -0
  498. package/dist/search/index.js.map +1 -0
  499. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  500. package/dist/server/google-oauth-credentials.d.ts +35 -0
  501. package/dist/server/google-oauth-credentials.d.ts.map +1 -1
  502. package/dist/server/google-oauth-credentials.js +48 -2
  503. package/dist/server/google-oauth-credentials.js.map +1 -1
  504. package/dist/server/index.d.ts +1 -1
  505. package/dist/server/index.d.ts.map +1 -1
  506. package/dist/server/index.js +1 -1
  507. package/dist/server/index.js.map +1 -1
  508. package/dist/styles/chat-history-list.css +1 -313
  509. package/dist/templates/chat/.agents/skills/actions/SKILL.md +32 -12
  510. package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +10 -0
  511. package/dist/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  512. package/dist/templates/chat/.agents/skills/self-modifying-code/SKILL.md +11 -2
  513. package/dist/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  514. package/dist/templates/chat/AGENTS.md +5 -2
  515. package/dist/templates/chat/app/components/layout/Sidebar.tsx +51 -157
  516. package/dist/templates/default/.agents/skills/actions/SKILL.md +32 -12
  517. package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +10 -0
  518. package/dist/templates/default/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  519. package/dist/templates/default/.agents/skills/integration-webhooks/SKILL.md +323 -0
  520. package/dist/templates/default/.agents/skills/onboarding/SKILL.md +56 -0
  521. package/dist/templates/default/.agents/skills/secrets/SKILL.md +273 -0
  522. package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +11 -2
  523. package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  524. package/dist/templates/default/AGENTS.md +25 -18
  525. package/dist/templates/headless/.agents/skills/actions/SKILL.md +512 -0
  526. package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +10 -0
  527. package/dist/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  528. package/dist/templates/headless/.agents/skills/integration-webhooks/SKILL.md +323 -0
  529. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +273 -0
  530. package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  531. package/dist/templates/headless/AGENTS.md +7 -0
  532. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -12
  533. package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +10 -0
  534. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  535. package/dist/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  536. package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +11 -2
  537. package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  538. package/dist/templates/workspace-core/AGENTS.md +4 -0
  539. package/dist/templates/workspace-root/AGENTS.md +4 -0
  540. package/docs/AGENTS.md +7 -0
  541. package/docs/content/integrations.mdx +63 -2
  542. package/docs/design/provider-integration-authority.md +117 -0
  543. package/package.json +9 -2
  544. package/src/templates/chat/.agents/skills/actions/SKILL.md +32 -12
  545. package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +10 -0
  546. package/src/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  547. package/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +11 -2
  548. package/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  549. package/src/templates/chat/AGENTS.md +5 -2
  550. package/src/templates/chat/app/components/layout/Sidebar.tsx +51 -157
  551. package/src/templates/default/.agents/skills/actions/SKILL.md +32 -12
  552. package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +10 -0
  553. package/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  554. package/src/templates/default/.agents/skills/integration-webhooks/SKILL.md +323 -0
  555. package/src/templates/default/.agents/skills/onboarding/SKILL.md +56 -0
  556. package/src/templates/default/.agents/skills/secrets/SKILL.md +273 -0
  557. package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +11 -2
  558. package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  559. package/src/templates/default/AGENTS.md +25 -18
  560. package/src/templates/headless/.agents/skills/actions/SKILL.md +512 -0
  561. package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +10 -0
  562. package/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  563. package/src/templates/headless/.agents/skills/integration-webhooks/SKILL.md +323 -0
  564. package/src/templates/headless/.agents/skills/secrets/SKILL.md +273 -0
  565. package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  566. package/src/templates/headless/AGENTS.md +7 -0
  567. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -12
  568. package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +10 -0
  569. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  570. package/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +102 -0
  571. package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +11 -2
  572. package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
  573. package/src/templates/workspace-core/AGENTS.md +4 -0
  574. package/src/templates/workspace-root/AGENTS.md +4 -0
@@ -11,7 +11,9 @@ import { and, desc, eq, inArray, or, sql, type SQL } from "drizzle-orm";
11
11
 
12
12
  import type { BrainEvidence } from "../../shared/types.js";
13
13
  import { getDb, schema } from "../db/index.js";
14
+ import { listAccessibleAudienceIds } from "./audiences.js";
14
15
  import { parseJson, safeCitationUrl } from "./brain.js";
16
+ import { hybridSearchArtifacts } from "./hybrid-search.js";
15
17
 
16
18
  export type UniversalSearchType = "knowledge" | "capture" | "source";
17
19
 
@@ -35,10 +37,14 @@ export interface UniversalSearchResult {
35
37
  captureTitle?: string | null;
36
38
  quote?: string | null;
37
39
  sourceUrl?: string | null;
40
+ preview?: string | null;
41
+ verbatim?: boolean;
38
42
  } | null;
39
43
  confidence: number | null;
40
44
  updatedAt: string;
41
45
  score: number;
46
+ reasons?: string[];
47
+ lane?: "lexical" | "semantic" | "hybrid" | "like";
42
48
  }
43
49
 
44
50
  export type FederatedDelegationTarget = "analytics" | "mail" | "dispatch";
@@ -364,12 +370,27 @@ async function searchKnowledgeResults(
364
370
  terms: string[],
365
371
  limit: number,
366
372
  ): Promise<UniversalSearchResult[]> {
373
+ const audienceIds = await listAccessibleAudienceIds();
374
+ const accessibleSourceExists = sql`exists (
375
+ select 1 from ${schema.brainSources}
376
+ where ${schema.brainSources.id} = ${schema.brainKnowledge.sourceId}
377
+ and ${accessFilter(schema.brainSources, schema.brainSourceShares)}
378
+ )`;
367
379
  const rows = await getDb()
368
380
  .select()
369
381
  .from(schema.brainKnowledge)
370
382
  .where(
371
383
  and(
372
384
  accessFilter(schema.brainKnowledge, schema.brainKnowledgeShares),
385
+ or(
386
+ sql`${schema.brainKnowledge.captureId} IS NULL`,
387
+ audienceIds.length
388
+ ? and(
389
+ accessibleSourceExists,
390
+ inArray(schema.brainKnowledge.audienceId, audienceIds),
391
+ )
392
+ : undefined,
393
+ ),
373
394
  eq(schema.brainKnowledge.status, "published"),
374
395
  anyColumnMatches(
375
396
  [
@@ -437,6 +458,8 @@ async function searchCaptureResults(
437
458
  terms: string[],
438
459
  limit: number,
439
460
  ): Promise<UniversalSearchResult[]> {
461
+ const audienceIds = await listAccessibleAudienceIds();
462
+ if (!audienceIds.length) return [];
440
463
  const accessibleSourceExists = sql`exists (
441
464
  select 1 from ${schema.brainSources}
442
465
  where ${schema.brainSources.id} = ${schema.brainRawCaptures.sourceId}
@@ -448,6 +471,12 @@ async function searchCaptureResults(
448
471
  .where(
449
472
  and(
450
473
  accessibleSourceExists,
474
+ eq(schema.brainRawCaptures.sensitivityDisposition, "allowed"),
475
+ sql`exists (
476
+ select 1 from ${schema.brainCaptureAudiences}
477
+ where ${schema.brainCaptureAudiences.captureId} = ${schema.brainRawCaptures.id}
478
+ and ${inArray(schema.brainCaptureAudiences.audienceId, audienceIds)}
479
+ )`,
451
480
  anyColumnMatches(
452
481
  [
453
482
  schema.brainRawCaptures.title,
@@ -481,7 +510,9 @@ async function searchCaptureResults(
481
510
  citation: {
482
511
  captureId: row.id,
483
512
  captureTitle: redactSensitiveText(row.title),
484
- quote: snippet,
513
+ quote: null,
514
+ preview: snippet,
515
+ verbatim: false,
485
516
  sourceUrl,
486
517
  },
487
518
  confidence: null,
@@ -560,23 +591,99 @@ export async function searchEverythingRows(args: {
560
591
  query: string;
561
592
  type?: UniversalSearchType | "all";
562
593
  provider?: string;
594
+ kind?: string;
595
+ projectId?: string;
563
596
  status?: string;
564
597
  limit?: number;
565
598
  }): Promise<UniversalSearchResult[]> {
566
599
  const terms = normalizeSearchTerms(args.query);
567
600
  if (!terms.length) return [];
601
+ const projectSourceIds = args.projectId
602
+ ? (
603
+ await getDb()
604
+ .select({ sourceId: schema.brainProjectSources.sourceId })
605
+ .from(schema.brainProjectSources)
606
+ .innerJoin(
607
+ schema.brainProjects,
608
+ eq(schema.brainProjects.id, schema.brainProjectSources.projectId),
609
+ )
610
+ .where(
611
+ and(
612
+ eq(schema.brainProjectSources.projectId, args.projectId),
613
+ accessFilter(schema.brainProjects, schema.brainProjectShares),
614
+ ),
615
+ )
616
+ ).map((row) => row.sourceId)
617
+ : undefined;
618
+ if (projectSourceIds && !projectSourceIds.length) return [];
619
+ const projectSourceSet = projectSourceIds
620
+ ? new Set(projectSourceIds)
621
+ : undefined;
568
622
  const limit = args.limit ?? 25;
569
623
  const perTypeLimit = Math.max(limit, 10);
570
624
  const searches: Array<Promise<UniversalSearchResult[]>> = [];
571
625
  if (!args.type || args.type === "all" || args.type === "knowledge") {
572
626
  searches.push(searchKnowledgeResults(terms, perTypeLimit));
573
627
  }
574
- if (!args.type || args.type === "all" || args.type === "capture") {
628
+ if (
629
+ (!args.type || args.type === "all" || args.type === "capture") &&
630
+ !args.kind
631
+ ) {
575
632
  searches.push(searchCaptureResults(terms, perTypeLimit));
576
633
  }
577
634
  if (!args.type || args.type === "all" || args.type === "source") {
578
635
  searches.push(searchSourceResults(terms, perTypeLimit));
579
636
  }
637
+ if (!args.type || args.type === "all" || args.type === "capture") {
638
+ searches.push(
639
+ hybridSearchArtifacts({
640
+ query: args.query,
641
+ provider: args.provider,
642
+ kind: args.kind,
643
+ projectId: args.projectId,
644
+ limit: perTypeLimit,
645
+ })
646
+ .then(async (artifacts) => {
647
+ const sources = await accessibleSourceMap(
648
+ artifacts.map((artifact) => artifact.sourceId),
649
+ );
650
+ return artifacts.flatMap((artifact) => {
651
+ const source = sources.get(artifact.sourceId);
652
+ if (!source) return [];
653
+ const snippet = redactSensitiveText(
654
+ buildSnippet(artifact.text, terms),
655
+ );
656
+ return [
657
+ {
658
+ type: "capture" as const,
659
+ id: artifact.captureId,
660
+ title: redactSensitiveText(artifact.title),
661
+ snippet,
662
+ summary: snippet,
663
+ status: "indexed",
664
+ provider: source.provider,
665
+ source: serializeSourceInfo(source),
666
+ sourceUrl: null,
667
+ citation: {
668
+ captureId: artifact.captureId,
669
+ captureTitle: redactSensitiveText(artifact.title),
670
+ quote: null,
671
+ preview: snippet,
672
+ verbatim: false,
673
+ sourceUrl: null,
674
+ },
675
+ confidence: null,
676
+ updatedAt: artifact.capturedAt,
677
+ score: artifact.score * 100,
678
+ reasons: artifact.reasons,
679
+ lane: artifact.lane,
680
+ },
681
+ ];
682
+ });
683
+ })
684
+ .catch(() => []),
685
+ );
686
+ }
580
687
  const provider = args.provider?.toLowerCase();
581
688
  const status = args.status?.toLowerCase();
582
689
  const results = (await Promise.all(searches))
@@ -590,7 +697,10 @@ export async function searchEverythingRows(args: {
590
697
  const resultStatus = result.status.toLowerCase();
591
698
  const providerMatches = !provider || resultProvider === provider;
592
699
  const statusMatches = !status || resultStatus === status;
593
- return providerMatches && statusMatches;
700
+ const projectMatches =
701
+ !projectSourceSet ||
702
+ Boolean(result.source?.id && projectSourceSet.has(result.source.id));
703
+ return providerMatches && statusMatches && projectMatches;
594
704
  })
595
705
  .sort(
596
706
  (a, b) =>
@@ -598,7 +708,13 @@ export async function searchEverythingRows(args: {
598
708
  Date.parse(b.updatedAt) - Date.parse(a.updatedAt) ||
599
709
  a.title.localeCompare(b.title),
600
710
  );
601
- return results.slice(0, limit);
711
+ const deduped = new Map<string, UniversalSearchResult>();
712
+ for (const result of results) {
713
+ const key = `${result.type}:${result.id}`;
714
+ const current = deduped.get(key);
715
+ if (!current || result.score > current.score) deduped.set(key, result);
716
+ }
717
+ return Array.from(deduped.values()).slice(0, limit);
602
718
  }
603
719
 
604
720
  async function readBrainSourceProviderCoverage(): Promise<
@@ -0,0 +1,174 @@
1
+ import { z } from "zod";
2
+
3
+ import {
4
+ BRAIN_SENSITIVITY_POLICY_VERSION,
5
+ type BrainSafeSegment,
6
+ type BrainSensitivityCategory,
7
+ type BrainSensitivityDecision,
8
+ } from "./search-index-contracts.js";
9
+
10
+ export const MAX_CLASSIFIER_OUTPUT_CHARS = 80_000;
11
+ export const classifierDecisionSchema = z
12
+ .object({
13
+ disposition: z.enum(["allowed", "suppressed", "quarantined"]),
14
+ categories: z
15
+ .array(
16
+ z.enum([
17
+ "performance",
18
+ "discipline",
19
+ "termination",
20
+ "layoff-reorg",
21
+ "compensation",
22
+ "recruiting",
23
+ "health-accommodation",
24
+ "investigation",
25
+ "privileged-legal",
26
+ "secret-credential",
27
+ "personal",
28
+ ]),
29
+ )
30
+ .max(12),
31
+ safeContent: z.string().max(MAX_CLASSIFIER_OUTPUT_CHARS),
32
+ safeSegments: z
33
+ .array(
34
+ z.object({
35
+ text: z.string().min(1).max(8_000),
36
+ sourceUrl: z.string().url().optional(),
37
+ }),
38
+ )
39
+ .max(50),
40
+ })
41
+ .strict();
42
+
43
+ const HARD_CATEGORY_PATTERNS: ReadonlyArray<
44
+ readonly [BrainSensitivityCategory, RegExp]
45
+ > = [
46
+ [
47
+ "performance",
48
+ /\b(performance review|under[- ]?perform(?:er|ing)?|low performer|performance concern)\b/i,
49
+ ],
50
+ [
51
+ "discipline",
52
+ /\b(performance improvement plan|start (?:a )?pip|(?:place(?:d)?|put) (?:them|her|him|the employee) on (?:a )?pip|written warning|disciplinary action|final warning)\b/i,
53
+ ],
54
+ [
55
+ "termination",
56
+ /\b(employment termination|terminate the employee|terminat(?:e|ed|ion) (?:their|his|her|the employee'?s?) employment|fired|fire\s+(?:them|her|him)|severance (?:agreement|package|pay))\b/i,
57
+ ],
58
+ [
59
+ "layoff-reorg",
60
+ /\b(layoffs?|rif|reorg(?:anization)?|rightsizing|roles? impacted|role eliminat(?:ion|ed)|workforce reduction)\b/i,
61
+ ],
62
+ [
63
+ "compensation",
64
+ /\b(compensation (?:review|discussion|adjustment|change)|salary|(?:annual|signing|performance|retention) bonus|bonus (?:amount|payout|target)|equity grant|stock options?|pay band|payroll|pay raise|salary increase|comp adjustment)\b/i,
65
+ ],
66
+ [
67
+ "recruiting",
68
+ /\b(candidate|applicant|interview(?:er|ing)?|recruit(?:er|ing)?|resume|résumé|reference check|job offer|shortlist|hiring panel)\b/i,
69
+ ],
70
+ [
71
+ "health-accommodation",
72
+ /\b(health condition|medical (?:condition|diagnosis|leave|record|accommodation)|doctor(?:'s)? note|disability accommodation|workplace accommodation|fmla|mental health (?:condition|leave|accommodation)|pregnan(?:t|cy))\b/i,
73
+ ],
74
+ [
75
+ "investigation",
76
+ /\b(investigation|investigat(?:e|ing|ed)|harassment complaint|misconduct|whistleblower|ethics complaint)\b/i,
77
+ ],
78
+ [
79
+ "privileged-legal",
80
+ /\b(attorney[- ]client|legal privilege|privileged and confidential|outside counsel|litigation hold)\b/i,
81
+ ],
82
+ [
83
+ "secret-credential",
84
+ /\b(?:password|passcode|secret|api[- ]?key|access[- ]?token|private[- ]?key)\s*[:=]|\b(?:sk|pk|rk|ghp|gho|ghu|github_pat)[_-][A-Za-z0-9_=-]{12,}\b/i,
85
+ ],
86
+ ];
87
+
88
+ const PERSONAL_PATTERN =
89
+ /\b(home address|social security|ssn|birthday|spouse|husband|wife|children?)\b/i;
90
+ const PROMPT_INJECTION_PATTERN =
91
+ /\b(ignore (?:previous|all|privacy)|override (?:the |all )?(?:policy|rules)|reveal (?:the )?(?:secret|private)|persist every)\b/i;
92
+ export interface DeterministicSensitivityScreen {
93
+ categories: BrainSensitivityCategory[];
94
+ sensitiveLines: string[];
95
+ safeLines: string[];
96
+ }
97
+
98
+ export function screenSensitivityDeterministically(
99
+ content: string,
100
+ ): DeterministicSensitivityScreen {
101
+ const categories = new Set<BrainSensitivityCategory>();
102
+ const sensitiveLines: string[] = [];
103
+ const safeLines: string[] = [];
104
+
105
+ for (const rawLine of content.split(/\r?\n/g)) {
106
+ const line = rawLine.trim();
107
+ if (!line) continue;
108
+ let sensitive = false;
109
+ for (const [category, pattern] of HARD_CATEGORY_PATTERNS) {
110
+ if (!pattern.test(line)) continue;
111
+ categories.add(category);
112
+ sensitive = true;
113
+ }
114
+ if (PERSONAL_PATTERN.test(line)) {
115
+ categories.add("personal");
116
+ sensitive = true;
117
+ }
118
+ if (PROMPT_INJECTION_PATTERN.test(line)) sensitive = true;
119
+ (sensitive ? sensitiveLines : safeLines).push(line);
120
+ }
121
+
122
+ return { categories: [...categories], sensitiveLines, safeLines };
123
+ }
124
+
125
+ export function fallbackSensitivityDecision(
126
+ content: string,
127
+ capturedAt: string,
128
+ ): BrainSensitivityDecision {
129
+ const screen = screenSensitivityDeterministically(content);
130
+ const safeContent = screen.safeLines
131
+ .join("\n")
132
+ .slice(0, MAX_CLASSIFIER_OUTPUT_CHARS);
133
+ const safeSegments: BrainSafeSegment[] = safeContent
134
+ ? [{ id: "safe-1", capturedAt, text: safeContent, reactionCount: 0 }]
135
+ : [];
136
+ const disposition =
137
+ screen.categories.length || screen.sensitiveLines.length || !safeContent
138
+ ? "quarantined"
139
+ : "allowed";
140
+ return {
141
+ disposition,
142
+ categories: screen.categories,
143
+ confidenceBand:
144
+ disposition === "allowed" || screen.categories.length
145
+ ? "deterministic"
146
+ : "uncertain",
147
+ policyVersion: BRAIN_SENSITIVITY_POLICY_VERSION,
148
+ safeSegments,
149
+ safeContent,
150
+ classifier: "deterministic",
151
+ };
152
+ }
153
+
154
+ export function deterministicQuarantineDecision(
155
+ content: string,
156
+ capturedAt: string,
157
+ ): BrainSensitivityDecision | null {
158
+ const screen = screenSensitivityDeterministically(content);
159
+ if (!screen.categories.length) return null;
160
+ const safeContent = screen.safeLines
161
+ .join("\n")
162
+ .slice(0, MAX_CLASSIFIER_OUTPUT_CHARS);
163
+ return {
164
+ disposition: "suppressed",
165
+ categories: screen.categories,
166
+ confidenceBand: "deterministic",
167
+ policyVersion: BRAIN_SENSITIVITY_POLICY_VERSION,
168
+ safeSegments: safeContent
169
+ ? [{ id: "safe-1", capturedAt, text: safeContent, reactionCount: 0 }]
170
+ : [],
171
+ safeContent,
172
+ classifier: "deterministic",
173
+ };
174
+ }
@@ -0,0 +1,44 @@
1
+ export interface SlackChannelMembershipTarget {
2
+ id: string;
3
+ is_im?: boolean;
4
+ is_mpim?: boolean;
5
+ is_channel?: boolean;
6
+ is_group?: boolean;
7
+ is_private?: boolean;
8
+ is_member?: boolean;
9
+ }
10
+
11
+ export interface SlackChannelJoinResponse {
12
+ ok?: boolean;
13
+ error?: string;
14
+ }
15
+
16
+ export type SlackChannelMembershipResult =
17
+ | "not_public"
18
+ | "membership_unknown"
19
+ | "already_member"
20
+ | "joined";
21
+
22
+ export async function ensureSlackPublicChannelMembership(
23
+ channel: SlackChannelMembershipTarget,
24
+ joinChannel: (channelId: string) => Promise<SlackChannelJoinResponse>,
25
+ ): Promise<SlackChannelMembershipResult> {
26
+ if (
27
+ channel.is_private === true ||
28
+ channel.is_group === true ||
29
+ channel.is_im === true ||
30
+ channel.is_mpim === true ||
31
+ channel.is_channel === false
32
+ ) {
33
+ return "not_public";
34
+ }
35
+ if (channel.is_member === true) return "already_member";
36
+ if (channel.is_member !== false) return "membership_unknown";
37
+
38
+ const result = await joinChannel(channel.id);
39
+ if (result.ok !== false) return "joined";
40
+ if (result.error === "already_in_channel") return "already_member";
41
+ throw new Error(
42
+ `Slack conversations.join failed: ${result.error ?? "unknown"}`,
43
+ );
44
+ }
@@ -0,0 +1,281 @@
1
+ import crypto from "node:crypto";
2
+
3
+ import { and, eq } from "drizzle-orm";
4
+
5
+ import { getDb, schema } from "../db/index.js";
6
+ import { parseJson, retireUpstreamDeletedCapture } from "./brain.js";
7
+ import { enqueueBrainOperation } from "./ingest-queue.js";
8
+ import { resolveSourceCredential } from "./source-credentials.js";
9
+
10
+ export interface SlackEventsEnvelope {
11
+ type?: string;
12
+ challenge?: string;
13
+ team_id?: string;
14
+ api_app_id?: string;
15
+ event?: {
16
+ type?: string;
17
+ subtype?: string;
18
+ channel?: string;
19
+ ts?: string;
20
+ thread_ts?: string;
21
+ deleted_ts?: string;
22
+ previous_message?: { ts?: string; thread_ts?: string };
23
+ item?: { type?: string; channel?: string; ts?: string };
24
+ };
25
+ }
26
+
27
+ type SlackSource = typeof schema.brainSources.$inferSelect;
28
+
29
+ function objectValue(value: unknown): Record<string, unknown> {
30
+ return value && typeof value === "object"
31
+ ? (value as Record<string, unknown>)
32
+ : {};
33
+ }
34
+
35
+ function stringValue(value: unknown): string | undefined {
36
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
37
+ }
38
+
39
+ function configuredString(
40
+ config: Record<string, unknown>,
41
+ keys: string[],
42
+ ): string | undefined {
43
+ for (const candidate of [config, objectValue(config.slack)]) {
44
+ for (const key of keys) {
45
+ const value = stringValue(candidate[key]);
46
+ if (value) return value;
47
+ }
48
+ }
49
+ return undefined;
50
+ }
51
+
52
+ function configuredChannelIds(config: Record<string, unknown>) {
53
+ const result = new Set<string>();
54
+ for (const candidate of [config, objectValue(config.slack)]) {
55
+ for (const key of [
56
+ "channelIds",
57
+ "channels",
58
+ "allowedChannels",
59
+ "allowlistedChannels",
60
+ "allowList",
61
+ ]) {
62
+ const raw = candidate[key];
63
+ const values =
64
+ typeof raw === "string"
65
+ ? raw.split(",")
66
+ : Array.isArray(raw)
67
+ ? raw.filter((value): value is string => typeof value === "string")
68
+ : [];
69
+ for (const value of values) {
70
+ const id = value.trim().replace(/^#/, "");
71
+ if (/^[CG][A-Z0-9]+$/i.test(id)) result.add(id);
72
+ }
73
+ }
74
+ }
75
+ return result;
76
+ }
77
+
78
+ function includesPublicChannels(config: Record<string, unknown>) {
79
+ for (const candidate of [config, objectValue(config.slack)]) {
80
+ const value = candidate.includePublicChannels;
81
+ if (value === true) return true;
82
+ if (
83
+ typeof value === "string" &&
84
+ ["true", "1", "yes", "on"].includes(value.toLowerCase())
85
+ ) {
86
+ return true;
87
+ }
88
+ }
89
+ return false;
90
+ }
91
+
92
+ export function slackEventDirective(payload: SlackEventsEnvelope) {
93
+ const event = payload.event;
94
+ if (!event) return null;
95
+ if (event.type === "message") {
96
+ const retiring = event.subtype === "message_deleted";
97
+ const threadTs = retiring
98
+ ? (event.previous_message?.thread_ts ??
99
+ event.previous_message?.ts ??
100
+ event.deleted_ts)
101
+ : (event.thread_ts ?? event.ts);
102
+ return event.channel && threadTs
103
+ ? {
104
+ action: retiring ? ("retire" as const) : ("refresh" as const),
105
+ channelId: event.channel,
106
+ threadTs,
107
+ }
108
+ : null;
109
+ }
110
+ if (
111
+ (event.type === "reaction_added" || event.type === "reaction_removed") &&
112
+ event.item?.type === "message" &&
113
+ event.item.channel &&
114
+ event.item.ts
115
+ ) {
116
+ return {
117
+ action: "refresh" as const,
118
+ channelId: event.item.channel,
119
+ threadTs: event.item.ts,
120
+ };
121
+ }
122
+ return null;
123
+ }
124
+
125
+ function sourceMatchesEvent(
126
+ source: SlackSource,
127
+ payload: SlackEventsEnvelope,
128
+ location: { channelId: string; threadTs: string } | null,
129
+ ) {
130
+ const config = parseJson<Record<string, unknown>>(source.configJson, {});
131
+ const teamId = configuredString(config, ["slackTeamId", "teamId"]);
132
+ const appId = configuredString(config, ["slackAppId", "appId"]);
133
+ if (!teamId || teamId !== payload.team_id) return false;
134
+ if (appId && appId !== payload.api_app_id) return false;
135
+ if (!location) return payload.type === "url_verification";
136
+ return (
137
+ configuredChannelIds(config).has(location.channelId) ||
138
+ (includesPublicChannels(config) && /^C[A-Z0-9]+$/i.test(location.channelId))
139
+ );
140
+ }
141
+
142
+ export function parseSlackEventsEnvelope(
143
+ rawBody: string,
144
+ ): SlackEventsEnvelope | null {
145
+ try {
146
+ const parsed = JSON.parse(rawBody) as unknown;
147
+ return parsed && typeof parsed === "object"
148
+ ? (parsed as SlackEventsEnvelope)
149
+ : null;
150
+ } catch {
151
+ return null;
152
+ }
153
+ }
154
+
155
+ export function verifySlackEventSignature(input: {
156
+ rawBody: string;
157
+ timestamp?: string;
158
+ signature?: string;
159
+ signingSecret?: string;
160
+ nowMs?: number;
161
+ }) {
162
+ if (!input.timestamp || !input.signature || !input.signingSecret)
163
+ return false;
164
+ const timestamp = Number.parseInt(input.timestamp, 10);
165
+ if (!Number.isFinite(timestamp)) return false;
166
+ if (Math.abs((input.nowMs ?? Date.now()) / 1_000 - timestamp) > 300)
167
+ return false;
168
+ const expected = `v0=${crypto
169
+ .createHmac("sha256", input.signingSecret)
170
+ .update(`v0:${input.timestamp}:${input.rawBody}`)
171
+ .digest("hex")}`;
172
+ try {
173
+ return crypto.timingSafeEqual(
174
+ Buffer.from(input.signature),
175
+ Buffer.from(expected),
176
+ );
177
+ } catch {
178
+ return false;
179
+ }
180
+ }
181
+
182
+ async function matchingSlackSource(
183
+ payload: SlackEventsEnvelope,
184
+ location: { channelId: string; threadTs: string } | null,
185
+ ) {
186
+ const sources = await getDb()
187
+ .select()
188
+ .from(schema.brainSources)
189
+ // guard:allow-unscoped — Slack's signed Events API has no user session;
190
+ // each candidate must match its configured workspace and channel before use.
191
+ .where(
192
+ and(
193
+ eq(schema.brainSources.provider, "slack"),
194
+ eq(schema.brainSources.status, "active"),
195
+ ),
196
+ );
197
+ return (
198
+ sources.find((source) => sourceMatchesEvent(source, payload, location)) ??
199
+ null
200
+ );
201
+ }
202
+
203
+ async function sourceSigningSecret(source: SlackSource) {
204
+ const config = parseJson<Record<string, unknown>>(source.configJson, {});
205
+ return resolveSourceCredential({
206
+ provider: "slack",
207
+ key: "SLACK_SIGNING_SECRET",
208
+ ctx: { userEmail: source.ownerEmail, orgId: source.orgId },
209
+ workspaceConnectionId: configuredString(config, ["workspaceConnectionId"]),
210
+ });
211
+ }
212
+
213
+ export async function retireSlackThreadCapture(input: {
214
+ sourceId: string;
215
+ channelId: string;
216
+ threadTs: string;
217
+ }) {
218
+ return retireUpstreamDeletedCapture({
219
+ sourceId: input.sourceId,
220
+ externalId: `slack:${input.channelId}:${input.threadTs}`,
221
+ provider: "slack",
222
+ });
223
+ }
224
+
225
+ /**
226
+ * Verify a Brain Slack event and either enqueue an ID-only refresh or retire a
227
+ * deleted upstream thread. The raw event body is never stored or logged.
228
+ */
229
+ export async function enqueueSlackThreadRefreshFromEvent(input: {
230
+ rawBody: string;
231
+ timestamp?: string;
232
+ signature?: string;
233
+ }): Promise<
234
+ | { status: "invalid" | "ignored" | "queued"; challenge?: string }
235
+ | { status: "missing-signing-secret" }
236
+ > {
237
+ const payload = parseSlackEventsEnvelope(input.rawBody);
238
+ if (!payload?.team_id) return { status: "invalid" };
239
+ const directive = slackEventDirective(payload);
240
+ const source = await matchingSlackSource(payload, directive);
241
+ if (!source) return { status: "ignored" };
242
+ const signingSecret = await sourceSigningSecret(source);
243
+ if (!signingSecret) return { status: "missing-signing-secret" };
244
+ if (
245
+ !verifySlackEventSignature({
246
+ rawBody: input.rawBody,
247
+ timestamp: input.timestamp,
248
+ signature: input.signature,
249
+ signingSecret,
250
+ })
251
+ ) {
252
+ return { status: "invalid" };
253
+ }
254
+ if (
255
+ payload.type === "url_verification" &&
256
+ typeof payload.challenge === "string"
257
+ ) {
258
+ return { status: "queued", challenge: payload.challenge };
259
+ }
260
+ if (!directive) return { status: "ignored" };
261
+ if (directive.action === "retire") {
262
+ await retireSlackThreadCapture({
263
+ sourceId: source.id,
264
+ channelId: directive.channelId,
265
+ threadTs: directive.threadTs,
266
+ });
267
+ return { status: "queued" };
268
+ }
269
+ await enqueueBrainOperation({
270
+ operation: "slack-thread-refresh",
271
+ dedupeKey: `slack-thread-refresh:${source.id}:${directive.channelId}:${directive.threadTs}`,
272
+ sourceId: source.id,
273
+ priority: 20,
274
+ payload: {
275
+ teamId: payload.team_id,
276
+ channelId: directive.channelId,
277
+ threadTs: directive.threadTs,
278
+ },
279
+ });
280
+ return { status: "queued" };
281
+ }