@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.
- package/corpus/README.md +4 -2
- package/corpus/core/CHANGELOG.md +34 -0
- package/corpus/core/docs/AGENTS.md +7 -0
- package/corpus/core/docs/content/integrations.mdx +63 -2
- package/corpus/core/docs/design/provider-integration-authority.md +117 -0
- package/corpus/core/package.json +8 -1
- package/corpus/core/scripts/materialize-source-corpus.mjs +9 -2
- package/corpus/core/src/cli/atomic-json-file.ts +324 -0
- package/corpus/core/src/cli/claude-code-participant.ts +515 -0
- package/corpus/core/src/cli/code-agent-executor.ts +35 -15
- package/corpus/core/src/cli/code-agent-runs.concurrent-worker.ts +33 -0
- package/corpus/core/src/cli/code-agent-runs.ts +70 -36
- package/corpus/core/src/cli/codex-cli-participant.ts +496 -0
- package/corpus/core/src/cli/multi-frontier-runs.ts +1952 -0
- package/corpus/core/src/client/chat/ChatHistoryList.tsx +7 -404
- package/corpus/core/src/coding-tools/index.ts +27 -8
- package/corpus/core/src/embeddings/index.ts +233 -0
- package/corpus/core/src/index.ts +2 -0
- package/corpus/core/src/integrations/index.ts +10 -0
- package/corpus/core/src/integrations/slack-oauth.ts +1 -0
- package/corpus/core/src/integrations/webhook-delivery.ts +55 -0
- package/corpus/core/src/notifications/channels.ts +4 -10
- package/corpus/core/src/provider-api/actions/custom-provider-registration.ts +197 -0
- package/corpus/core/src/provider-api/actions/delete-staged-dataset.ts +3 -42
- package/corpus/core/src/provider-api/actions/list-staged-datasets.ts +3 -45
- package/corpus/core/src/provider-api/actions/provider-api-audit.ts +88 -0
- package/corpus/core/src/provider-api/actions/provider-api.ts +460 -0
- package/corpus/core/src/provider-api/actions/query-staged-dataset.ts +3 -140
- package/corpus/core/src/provider-api/actions/staged-datasets.ts +359 -0
- package/corpus/core/src/provider-api/gong.ts +108 -0
- package/corpus/core/src/scripts/docs/source-search.ts +2 -1
- package/corpus/core/src/search/index.ts +413 -0
- package/corpus/core/src/server/google-oauth-credentials.ts +80 -3
- package/corpus/core/src/server/index.ts +6 -0
- package/corpus/core/src/styles/chat-history-list.css +1 -313
- package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/core/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/corpus/core/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/core/src/templates/default/.agents/skills/integration-webhooks/SKILL.md +323 -0
- package/corpus/core/src/templates/default/.agents/skills/onboarding/SKILL.md +56 -0
- package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +273 -0
- package/corpus/core/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/core/src/templates/default/AGENTS.md +25 -18
- package/corpus/core/src/templates/headless/.agents/skills/actions/SKILL.md +512 -0
- package/corpus/core/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/corpus/core/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/core/src/templates/headless/.agents/skills/integration-webhooks/SKILL.md +323 -0
- package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +273 -0
- package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/core/src/templates/headless/AGENTS.md +7 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/core/src/templates/workspace-core/AGENTS.md +4 -0
- package/corpus/core/src/templates/workspace-root/AGENTS.md +4 -0
- package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/analytics/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/analytics/actions/delete-staged-dataset.ts +3 -23
- package/corpus/templates/analytics/actions/list-staged-datasets.ts +3 -27
- package/corpus/templates/analytics/actions/provider-api-catalog.ts +16 -19
- package/corpus/templates/analytics/actions/provider-api-docs.ts +3 -5
- package/corpus/templates/analytics/actions/provider-api-request.ts +162 -185
- package/corpus/templates/analytics/actions/query-staged-dataset.ts +3 -47
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +52 -161
- package/corpus/templates/assets/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/assets/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +63 -160
- package/corpus/templates/brain/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/brain/.agents/skills/brain/RUNBOOK.md +48 -5
- package/corpus/templates/brain/.agents/skills/brain/SKILL.md +46 -14
- package/corpus/templates/brain/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/brain/README.md +34 -3
- package/corpus/templates/brain/actions/_schemas.ts +13 -7
- package/corpus/templates/brain/actions/approve-proposal.ts +2 -0
- package/corpus/templates/brain/actions/claim-distillation.ts +24 -27
- package/corpus/templates/brain/actions/create-source.ts +1 -1
- package/corpus/templates/brain/actions/delete-staged-dataset.ts +3 -24
- package/corpus/templates/brain/actions/get-knowledge.ts +6 -2
- package/corpus/templates/brain/actions/get-pilot-report.ts +44 -8
- package/corpus/templates/brain/actions/import-capture.ts +21 -9
- package/corpus/templates/brain/actions/import-transcript.ts +42 -14
- package/corpus/templates/brain/actions/list-captures.ts +10 -1
- package/corpus/templates/brain/actions/list-distillation-queue.ts +39 -14
- package/corpus/templates/brain/actions/list-projects.ts +51 -0
- package/corpus/templates/brain/actions/list-proposals.ts +80 -4
- package/corpus/templates/brain/actions/list-sources.ts +17 -3
- package/corpus/templates/brain/actions/list-staged-datasets.ts +3 -28
- package/corpus/templates/brain/actions/manage-project.ts +118 -0
- package/corpus/templates/brain/actions/mark-capture-distilled.ts +68 -20
- package/corpus/templates/brain/actions/navigate.ts +1 -0
- package/corpus/templates/brain/actions/provider-api-catalog.ts +5 -11
- package/corpus/templates/brain/actions/provider-api-docs.ts +3 -5
- package/corpus/templates/brain/actions/provider-api-request.ts +3 -37
- package/corpus/templates/brain/actions/query-staged-dataset.ts +3 -48
- package/corpus/templates/brain/actions/reject-proposal.ts +6 -1
- package/corpus/templates/brain/actions/resanitize-captures.ts +159 -33
- package/corpus/templates/brain/actions/review-proposal.ts +2 -0
- package/corpus/templates/brain/actions/search-everything.ts +10 -1
- package/corpus/templates/brain/actions/search-knowledge.ts +1 -1
- package/corpus/templates/brain/actions/set-settings.ts +36 -1
- package/corpus/templates/brain/actions/update-proposal.ts +2 -0
- package/corpus/templates/brain/actions/update-source.ts +5 -1
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +48 -154
- package/corpus/templates/brain/app/hooks/use-distillation-bridge.ts +18 -9
- package/corpus/templates/brain/app/hooks/use-navigation-state.ts +3 -0
- package/corpus/templates/brain/app/i18n-data.ts +731 -2
- package/corpus/templates/brain/app/lib/brain.ts +88 -1
- package/corpus/templates/brain/app/lib/ingest-handoff.ts +35 -0
- package/corpus/templates/brain/app/routes/ops.tsx +47 -0
- package/corpus/templates/brain/app/routes/review.tsx +41 -2
- package/corpus/templates/brain/app/routes/search.tsx +33 -2
- package/corpus/templates/brain/app/routes/settings.tsx +158 -0
- package/corpus/templates/brain/app/routes/sources.tsx +31 -0
- package/corpus/templates/brain/changelog/2026-07-19-added-private-source-safe-semantic-search.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-19-slack-backfills-can-now-join-configured-public-channels-befo.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-19-slack-backfills-now-continue-across-the-configured-number-of.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-19-slack-backfills-now-start-with-a-safe-four-week-window-and-r.md +6 -0
- package/corpus/templates/brain/jobs/process-ingest-queue.ts +270 -36
- package/corpus/templates/brain/package.json +1 -0
- package/corpus/templates/brain/server/db/index.ts +18 -0
- package/corpus/templates/brain/server/db/schema.ts +197 -1
- package/corpus/templates/brain/server/jobs/distillation-queue.ts +12 -5
- package/corpus/templates/brain/server/lib/audiences.ts +708 -0
- package/corpus/templates/brain/server/lib/brain-health.ts +251 -38
- package/corpus/templates/brain/server/lib/brain.ts +877 -50
- package/corpus/templates/brain/server/lib/capture-sanitization.ts +217 -53
- package/corpus/templates/brain/server/lib/connectors.ts +609 -72
- package/corpus/templates/brain/server/lib/demo.ts +17 -4
- package/corpus/templates/brain/server/lib/hybrid-search.ts +363 -0
- package/corpus/templates/brain/server/lib/ingest-queue.ts +104 -0
- package/corpus/templates/brain/server/lib/privacy-readiness.ts +24 -0
- package/corpus/templates/brain/server/lib/search-index-contracts.ts +72 -0
- package/corpus/templates/brain/server/lib/search-index.ts +714 -0
- package/corpus/templates/brain/server/lib/search.ts +120 -4
- package/corpus/templates/brain/server/lib/sensitivity-policy.ts +174 -0
- package/corpus/templates/brain/server/lib/slack-channel-membership.ts +44 -0
- package/corpus/templates/brain/server/lib/slack-events.ts +281 -0
- package/corpus/templates/brain/server/onboarding.ts +29 -0
- package/corpus/templates/brain/server/plugins/db.ts +204 -0
- package/corpus/templates/brain/server/register-secrets.ts +46 -0
- package/corpus/templates/brain/server/routes/api/_agent-native/brain/ingest.post.ts +36 -16
- package/corpus/templates/brain/server/routes/api/_agent-native/brain/slack-events.post.ts +28 -0
- package/corpus/templates/brain/shared/slack-source-config.ts +60 -0
- package/corpus/templates/brain/shared/types.ts +10 -0
- package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/calendar/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/calendar/actions/delete-staged-dataset.ts +3 -24
- package/corpus/templates/calendar/actions/list-staged-datasets.ts +3 -28
- package/corpus/templates/calendar/actions/provider-api-catalog.ts +5 -11
- package/corpus/templates/calendar/actions/provider-api-docs.ts +3 -5
- package/corpus/templates/calendar/actions/provider-api-request.ts +3 -37
- package/corpus/templates/calendar/actions/query-staged-dataset.ts +3 -48
- package/corpus/templates/calendar/server/handlers/gong.ts +6 -61
- package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -8
- package/corpus/templates/calendar/server/lib/google-calendar.ts +7 -45
- package/corpus/templates/chat/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/corpus/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/chat/AGENTS.md +5 -2
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +51 -157
- package/corpus/templates/clips/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/clips/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/clips/AGENTS.md +11 -0
- package/corpus/templates/clips/actions/export-to-brain.ts +505 -171
- package/corpus/templates/clips/changelog/2026-07-19-ready-clips-transcripts-can-be-backfilled-to-brain-for-a-bou.md +6 -0
- package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +1 -1
- package/corpus/templates/clips/server/lib/google-calendar-client.ts +12 -22
- package/corpus/templates/clips/server/lib/google-calendar-oauth.ts +9 -6
- package/corpus/templates/clips/server/lib/slack-oauth.ts +12 -47
- package/corpus/templates/clips/server/routes/_agent-native/google/auth-url.get.ts +2 -6
- package/corpus/templates/clips/server/routes/api/auth/google-calendar.get.ts +4 -4
- package/corpus/templates/content/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/content/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/content/actions/delete-staged-dataset.ts +3 -24
- package/corpus/templates/content/actions/list-staged-datasets.ts +3 -28
- package/corpus/templates/content/actions/provider-api-catalog.ts +5 -11
- package/corpus/templates/content/actions/provider-api-docs.ts +3 -5
- package/corpus/templates/content/actions/provider-api-request.ts +3 -37
- package/corpus/templates/content/actions/query-staged-dataset.ts +3 -48
- package/corpus/templates/design/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/design/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/design/actions/delete-staged-dataset.ts +4 -23
- package/corpus/templates/design/actions/list-staged-datasets.ts +4 -27
- package/corpus/templates/design/actions/provider-api-catalog.ts +15 -18
- package/corpus/templates/design/actions/provider-api-docs.ts +57 -48
- package/corpus/templates/design/actions/provider-api-request.ts +140 -164
- package/corpus/templates/design/actions/query-staged-dataset.ts +4 -47
- package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/dispatch/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/dispatch/actions/delete-staged-dataset.ts +4 -23
- package/corpus/templates/dispatch/actions/list-staged-datasets.ts +4 -30
- package/corpus/templates/dispatch/actions/provider-api-catalog.ts +15 -18
- package/corpus/templates/dispatch/actions/provider-api-docs.ts +57 -48
- package/corpus/templates/dispatch/actions/provider-api-request.ts +138 -163
- package/corpus/templates/dispatch/actions/query-staged-dataset.ts +4 -47
- package/corpus/templates/forms/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/forms/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/forms/server/lib/integrations.ts +23 -22
- package/corpus/templates/macros/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/mail/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/mail/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/mail/actions/delete-staged-dataset.ts +4 -23
- package/corpus/templates/mail/actions/list-staged-datasets.ts +4 -27
- package/corpus/templates/mail/actions/provider-api-catalog.ts +15 -18
- package/corpus/templates/mail/actions/provider-api-docs.ts +57 -48
- package/corpus/templates/mail/actions/provider-api-request.ts +146 -173
- package/corpus/templates/mail/actions/query-staged-dataset.ts +4 -47
- package/corpus/templates/mail/server/handlers/gong.ts +6 -61
- package/corpus/templates/mail/server/lib/google-auth.ts +10 -13
- package/corpus/templates/plan/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/plan/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +47 -156
- package/corpus/templates/slides/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/slides/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/slides/actions/delete-staged-dataset.ts +4 -23
- package/corpus/templates/slides/actions/list-staged-datasets.ts +4 -27
- package/corpus/templates/slides/actions/provider-api-catalog.ts +15 -18
- package/corpus/templates/slides/actions/provider-api-docs.ts +57 -48
- package/corpus/templates/slides/actions/provider-api-request.ts +145 -172
- package/corpus/templates/slides/actions/query-staged-dataset.ts +4 -47
- package/corpus/templates/slides/server/lib/google-docs-oauth.ts +11 -36
- package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/corpus/templates/tasks/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/tasks/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/tasks/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/toolkit/CHANGELOG.md +125 -0
- package/corpus/toolkit/README.md +60 -0
- package/corpus/toolkit/export-snapshot.json +35 -0
- package/corpus/toolkit/migration-manifest.json +4 -0
- package/corpus/toolkit/package.json +281 -0
- package/corpus/toolkit/scripts/finalize-build.mjs +55 -0
- package/corpus/toolkit/src/app-shell/header-actions.tsx +84 -0
- package/corpus/toolkit/src/app-shell/index.ts +1 -0
- package/corpus/toolkit/src/chat-history/ChatHistoryList.tsx +469 -0
- package/corpus/toolkit/src/chat-history/index.ts +7 -0
- package/corpus/toolkit/src/chat-history.css +314 -0
- package/corpus/toolkit/src/collab-ui/AgentPresenceChip.tsx +69 -0
- package/corpus/toolkit/src/collab-ui/LiveCursorOverlay.tsx +241 -0
- package/corpus/toolkit/src/collab-ui/PresenceBar.tsx +346 -0
- package/corpus/toolkit/src/collab-ui/RecentEditHighlights.tsx +225 -0
- package/corpus/toolkit/src/collab-ui/RemoteSelectionRings.tsx +227 -0
- package/corpus/toolkit/src/collab-ui/agent-identity.ts +16 -0
- package/corpus/toolkit/src/collab-ui/index.ts +39 -0
- package/corpus/toolkit/src/collab-ui/lead-client.ts +32 -0
- package/corpus/toolkit/src/collab-ui/types.ts +96 -0
- package/corpus/toolkit/src/composer/AgentComposerFrame.tsx +59 -0
- package/corpus/toolkit/src/composer/ComposerPlusMenu.tsx +983 -0
- package/corpus/toolkit/src/composer/MentionPopover.tsx +412 -0
- package/corpus/toolkit/src/composer/PastedTextChip.tsx +150 -0
- package/corpus/toolkit/src/composer/PromptComposer.tsx +718 -0
- package/corpus/toolkit/src/composer/RealtimeVoiceMode.tsx +856 -0
- package/corpus/toolkit/src/composer/TiptapComposer.tsx +2936 -0
- package/corpus/toolkit/src/composer/VoiceButton.tsx +255 -0
- package/corpus/toolkit/src/composer/asset-picker-url.ts +80 -0
- package/corpus/toolkit/src/composer/attachment-accept.ts +71 -0
- package/corpus/toolkit/src/composer/draft-key.ts +7 -0
- package/corpus/toolkit/src/composer/extensions/FileReference.tsx +55 -0
- package/corpus/toolkit/src/composer/extensions/MentionReference.tsx +93 -0
- package/corpus/toolkit/src/composer/extensions/SkillReference.tsx +56 -0
- package/corpus/toolkit/src/composer/index.ts +79 -0
- package/corpus/toolkit/src/composer/pasted-text.ts +160 -0
- package/corpus/toolkit/src/composer/prompt-attachments.ts +93 -0
- package/corpus/toolkit/src/composer/realtime-voice-audio-level.ts +64 -0
- package/corpus/toolkit/src/composer/realtime-voice-transcript.ts +134 -0
- package/corpus/toolkit/src/composer/runtime-adapters.tsx +343 -0
- package/corpus/toolkit/src/composer/types.ts +66 -0
- package/corpus/toolkit/src/composer/use-file-search.ts +64 -0
- package/corpus/toolkit/src/composer/use-mention-search.ts +90 -0
- package/corpus/toolkit/src/composer/use-skills.ts +45 -0
- package/corpus/toolkit/src/composer/useRealtimeVoiceMode.tsx +2117 -0
- package/corpus/toolkit/src/composer/useVoiceDictation.ts +1191 -0
- package/corpus/toolkit/src/context-ui/ContextMeter.tsx +101 -0
- package/corpus/toolkit/src/context-ui/ContextSegmentRow.tsx +184 -0
- package/corpus/toolkit/src/context-ui/ContextTreemap.tsx +125 -0
- package/corpus/toolkit/src/context-ui/ContextXRayPanel.tsx +377 -0
- package/corpus/toolkit/src/context-ui/format.ts +42 -0
- package/corpus/toolkit/src/context-ui/index.ts +15 -0
- package/corpus/toolkit/src/context-ui/types.ts +43 -0
- package/corpus/toolkit/src/design-tweaks/index.ts +1 -0
- package/corpus/toolkit/src/design-tweaks/visual-style-controls.tsx +1084 -0
- package/corpus/toolkit/src/editor/BubbleToolbar.tsx +253 -0
- package/corpus/toolkit/src/editor/CodeBlockNode.tsx +254 -0
- package/corpus/toolkit/src/editor/DragHandle.ts +1437 -0
- package/corpus/toolkit/src/editor/ImageExtension.ts +306 -0
- package/corpus/toolkit/src/editor/RegistryBlockContext.tsx +107 -0
- package/corpus/toolkit/src/editor/RegistryBlockNode.tsx +652 -0
- package/corpus/toolkit/src/editor/RichMarkdownEditor.tsx +81 -0
- package/corpus/toolkit/src/editor/RunId.ts +61 -0
- package/corpus/toolkit/src/editor/SharedRichEditor.tsx +321 -0
- package/corpus/toolkit/src/editor/SlashCommandMenu.tsx +310 -0
- package/corpus/toolkit/src/editor/extensions.ts +402 -0
- package/corpus/toolkit/src/editor/gfmDoc.ts +92 -0
- package/corpus/toolkit/src/editor/index.ts +93 -0
- package/corpus/toolkit/src/editor/registrySlashCommands.ts +131 -0
- package/corpus/toolkit/src/editor/surgical-apply.ts +192 -0
- package/corpus/toolkit/src/editor/useCollabReconcile.ts +589 -0
- package/corpus/toolkit/src/editor.css +510 -0
- package/corpus/toolkit/src/hooks/index.ts +2 -0
- package/corpus/toolkit/src/hooks/use-mobile.tsx +21 -0
- package/corpus/toolkit/src/hooks/use-toast.ts +188 -0
- package/corpus/toolkit/src/index.ts +8 -0
- package/corpus/toolkit/src/onboarding/index.ts +1 -0
- package/corpus/toolkit/src/provider.tsx +47 -0
- package/corpus/toolkit/src/sharing/VisibilityBadge.tsx +37 -0
- package/corpus/toolkit/src/sharing/index.ts +4 -0
- package/corpus/toolkit/src/styles.css +21 -0
- package/corpus/toolkit/src/ui/accordion.tsx +56 -0
- package/corpus/toolkit/src/ui/alert-dialog.tsx +141 -0
- package/corpus/toolkit/src/ui/alert.tsx +59 -0
- package/corpus/toolkit/src/ui/aspect-ratio.tsx +5 -0
- package/corpus/toolkit/src/ui/avatar.tsx +48 -0
- package/corpus/toolkit/src/ui/badge.tsx +37 -0
- package/corpus/toolkit/src/ui/breadcrumb.tsx +115 -0
- package/corpus/toolkit/src/ui/button.tsx +78 -0
- package/corpus/toolkit/src/ui/calendar.tsx +214 -0
- package/corpus/toolkit/src/ui/card.tsx +86 -0
- package/corpus/toolkit/src/ui/carousel.tsx +260 -0
- package/corpus/toolkit/src/ui/chart.tsx +375 -0
- package/corpus/toolkit/src/ui/checkbox.tsx +28 -0
- package/corpus/toolkit/src/ui/collapsible.tsx +9 -0
- package/corpus/toolkit/src/ui/command.tsx +174 -0
- package/corpus/toolkit/src/ui/context-menu.tsx +202 -0
- package/corpus/toolkit/src/ui/date-picker.tsx +64 -0
- package/corpus/toolkit/src/ui/dialog.tsx +146 -0
- package/corpus/toolkit/src/ui/drawer.tsx +126 -0
- package/corpus/toolkit/src/ui/dropdown-menu.tsx +218 -0
- package/corpus/toolkit/src/ui/form.tsx +177 -0
- package/corpus/toolkit/src/ui/hover-card.tsx +27 -0
- package/corpus/toolkit/src/ui/index.ts +52 -0
- package/corpus/toolkit/src/ui/input-otp.tsx +69 -0
- package/corpus/toolkit/src/ui/input.tsx +22 -0
- package/corpus/toolkit/src/ui/label.tsx +24 -0
- package/corpus/toolkit/src/ui/logo.tsx +36 -0
- package/corpus/toolkit/src/ui/menubar.tsx +235 -0
- package/corpus/toolkit/src/ui/navigation-menu.tsx +128 -0
- package/corpus/toolkit/src/ui/pagination.tsx +121 -0
- package/corpus/toolkit/src/ui/popover.tsx +44 -0
- package/corpus/toolkit/src/ui/progress.tsx +26 -0
- package/corpus/toolkit/src/ui/radio-group.tsx +42 -0
- package/corpus/toolkit/src/ui/resizable.tsx +43 -0
- package/corpus/toolkit/src/ui/scroll-area.tsx +46 -0
- package/corpus/toolkit/src/ui/select.tsx +158 -0
- package/corpus/toolkit/src/ui/separator.tsx +29 -0
- package/corpus/toolkit/src/ui/sheet.tsx +160 -0
- package/corpus/toolkit/src/ui/sidebar.tsx +777 -0
- package/corpus/toolkit/src/ui/skeleton.tsx +18 -0
- package/corpus/toolkit/src/ui/slider.tsx +26 -0
- package/corpus/toolkit/src/ui/sonner.tsx +58 -0
- package/corpus/toolkit/src/ui/spinner.tsx +17 -0
- package/corpus/toolkit/src/ui/switch.tsx +27 -0
- package/corpus/toolkit/src/ui/table.tsx +117 -0
- package/corpus/toolkit/src/ui/tabs.tsx +53 -0
- package/corpus/toolkit/src/ui/textarea.tsx +23 -0
- package/corpus/toolkit/src/ui/toast.tsx +127 -0
- package/corpus/toolkit/src/ui/toaster.tsx +33 -0
- package/corpus/toolkit/src/ui/toggle-group.tsx +59 -0
- package/corpus/toolkit/src/ui/toggle.tsx +43 -0
- package/corpus/toolkit/src/ui/tooltip.tsx +53 -0
- package/corpus/toolkit/src/ui/use-toast.ts +3 -0
- package/corpus/toolkit/src/utils.ts +8 -0
- package/corpus/toolkit/tsconfig.json +23 -0
- package/dist/cli/atomic-json-file.d.ts +30 -0
- package/dist/cli/atomic-json-file.d.ts.map +1 -0
- package/dist/cli/atomic-json-file.js +240 -0
- package/dist/cli/atomic-json-file.js.map +1 -0
- package/dist/cli/claude-code-participant.d.ts +77 -0
- package/dist/cli/claude-code-participant.d.ts.map +1 -0
- package/dist/cli/claude-code-participant.js +355 -0
- package/dist/cli/claude-code-participant.js.map +1 -0
- package/dist/cli/code-agent-executor.d.ts +8 -9
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +27 -13
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/code-agent-runs.concurrent-worker.d.ts +2 -0
- package/dist/cli/code-agent-runs.concurrent-worker.d.ts.map +1 -0
- package/dist/cli/code-agent-runs.concurrent-worker.js +32 -0
- package/dist/cli/code-agent-runs.concurrent-worker.js.map +1 -0
- package/dist/cli/code-agent-runs.d.ts +5 -0
- package/dist/cli/code-agent-runs.d.ts.map +1 -1
- package/dist/cli/code-agent-runs.js +51 -33
- package/dist/cli/code-agent-runs.js.map +1 -1
- package/dist/cli/codex-cli-participant.d.ts +77 -0
- package/dist/cli/codex-cli-participant.d.ts.map +1 -0
- package/dist/cli/codex-cli-participant.js +354 -0
- package/dist/cli/codex-cli-participant.js.map +1 -0
- package/dist/cli/multi-frontier-runs.d.ts +246 -0
- package/dist/cli/multi-frontier-runs.d.ts.map +1 -0
- package/dist/cli/multi-frontier-runs.js +1247 -0
- package/dist/cli/multi-frontier-runs.js.map +1 -0
- package/dist/client/chat/ChatHistoryList.d.ts +1 -87
- package/dist/client/chat/ChatHistoryList.d.ts.map +1 -1
- package/dist/client/chat/ChatHistoryList.js +1 -82
- package/dist/client/chat/ChatHistoryList.js.map +1 -1
- package/dist/coding-tools/index.d.ts +1 -0
- package/dist/coding-tools/index.d.ts.map +1 -1
- package/dist/coding-tools/index.js +25 -7
- package/dist/coding-tools/index.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/embeddings/index.d.ts +24 -0
- package/dist/embeddings/index.d.ts.map +1 -0
- package/dist/embeddings/index.js +172 -0
- package/dist/embeddings/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/integrations/index.d.ts +2 -1
- package/dist/integrations/index.d.ts.map +1 -1
- package/dist/integrations/index.js +2 -1
- package/dist/integrations/index.js.map +1 -1
- package/dist/integrations/slack-manifest.d.ts +1 -1
- package/dist/integrations/slack-oauth.d.ts +1 -1
- package/dist/integrations/slack-oauth.d.ts.map +1 -1
- package/dist/integrations/slack-oauth.js +1 -0
- package/dist/integrations/slack-oauth.js.map +1 -1
- package/dist/integrations/webhook-delivery.d.ts +23 -0
- package/dist/integrations/webhook-delivery.d.ts.map +1 -0
- package/dist/integrations/webhook-delivery.js +32 -0
- package/dist/integrations/webhook-delivery.js.map +1 -0
- package/dist/notifications/channels.d.ts.map +1 -1
- package/dist/notifications/channels.js +4 -9
- package/dist/notifications/channels.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +136 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts.map +1 -0
- package/dist/provider-api/actions/custom-provider-registration.js +154 -0
- package/dist/provider-api/actions/custom-provider-registration.js.map +1 -0
- package/dist/provider-api/actions/delete-staged-dataset.d.ts +1 -1
- package/dist/provider-api/actions/delete-staged-dataset.d.ts.map +1 -1
- package/dist/provider-api/actions/delete-staged-dataset.js +3 -34
- package/dist/provider-api/actions/delete-staged-dataset.js.map +1 -1
- package/dist/provider-api/actions/list-staged-datasets.d.ts +2 -3
- package/dist/provider-api/actions/list-staged-datasets.d.ts.map +1 -1
- package/dist/provider-api/actions/list-staged-datasets.js +3 -40
- package/dist/provider-api/actions/list-staged-datasets.js.map +1 -1
- package/dist/provider-api/actions/provider-api-audit.d.ts +7 -0
- package/dist/provider-api/actions/provider-api-audit.d.ts.map +1 -0
- package/dist/provider-api/actions/provider-api-audit.js +74 -0
- package/dist/provider-api/actions/provider-api-audit.js.map +1 -0
- package/dist/provider-api/actions/provider-api.d.ts +370 -0
- package/dist/provider-api/actions/provider-api.d.ts.map +1 -0
- package/dist/provider-api/actions/provider-api.js +280 -0
- package/dist/provider-api/actions/provider-api.js.map +1 -0
- package/dist/provider-api/actions/query-staged-dataset.d.ts +1 -1
- package/dist/provider-api/actions/query-staged-dataset.d.ts.map +1 -1
- package/dist/provider-api/actions/query-staged-dataset.js +3 -116
- package/dist/provider-api/actions/query-staged-dataset.js.map +1 -1
- package/dist/provider-api/actions/staged-datasets.d.ts +190 -0
- package/dist/provider-api/actions/staged-datasets.d.ts.map +1 -0
- package/dist/provider-api/actions/staged-datasets.js +210 -0
- package/dist/provider-api/actions/staged-datasets.js.map +1 -0
- package/dist/provider-api/gong.d.ts +44 -0
- package/dist/provider-api/gong.d.ts.map +1 -0
- package/dist/provider-api/gong.js +56 -0
- package/dist/provider-api/gong.js.map +1 -0
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/docs/source-search.d.ts +2 -1
- package/dist/scripts/docs/source-search.d.ts.map +1 -1
- package/dist/scripts/docs/source-search.js +2 -1
- package/dist/scripts/docs/source-search.js.map +1 -1
- package/dist/search/index.d.ts +88 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +267 -0
- package/dist/search/index.js.map +1 -0
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/google-oauth-credentials.d.ts +35 -0
- package/dist/server/google-oauth-credentials.d.ts.map +1 -1
- package/dist/server/google-oauth-credentials.js +48 -2
- package/dist/server/google-oauth-credentials.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/styles/chat-history-list.css +1 -313
- package/dist/templates/chat/.agents/skills/actions/SKILL.md +32 -12
- package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/dist/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/dist/templates/chat/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/dist/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/dist/templates/chat/AGENTS.md +5 -2
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +51 -157
- package/dist/templates/default/.agents/skills/actions/SKILL.md +32 -12
- package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/dist/templates/default/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/dist/templates/default/.agents/skills/integration-webhooks/SKILL.md +323 -0
- package/dist/templates/default/.agents/skills/onboarding/SKILL.md +56 -0
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +273 -0
- package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/dist/templates/default/AGENTS.md +25 -18
- package/dist/templates/headless/.agents/skills/actions/SKILL.md +512 -0
- package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/dist/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/dist/templates/headless/.agents/skills/integration-webhooks/SKILL.md +323 -0
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +273 -0
- package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/dist/templates/headless/AGENTS.md +7 -0
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -12
- package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/dist/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/dist/templates/workspace-core/AGENTS.md +4 -0
- package/dist/templates/workspace-root/AGENTS.md +4 -0
- package/docs/AGENTS.md +7 -0
- package/docs/content/integrations.mdx +63 -2
- package/docs/design/provider-integration-authority.md +117 -0
- package/package.json +9 -2
- package/src/templates/chat/.agents/skills/actions/SKILL.md +32 -12
- package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/src/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/src/templates/chat/AGENTS.md +5 -2
- package/src/templates/chat/app/components/layout/Sidebar.tsx +51 -157
- package/src/templates/default/.agents/skills/actions/SKILL.md +32 -12
- package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/src/templates/default/.agents/skills/integration-webhooks/SKILL.md +323 -0
- package/src/templates/default/.agents/skills/onboarding/SKILL.md +56 -0
- package/src/templates/default/.agents/skills/secrets/SKILL.md +273 -0
- package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/src/templates/default/AGENTS.md +25 -18
- package/src/templates/headless/.agents/skills/actions/SKILL.md +512 -0
- package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/src/templates/headless/.agents/skills/integration-webhooks/SKILL.md +323 -0
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +273 -0
- package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/src/templates/headless/AGENTS.md +7 -0
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -12
- package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/src/templates/workspace-core/AGENTS.md +4 -0
- package/src/templates/workspace-root/AGENTS.md +4 -0
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import { getCredentialContext } from "@agent-native/core/server";
|
|
2
2
|
import { accessFilter, assertAccess } from "@agent-native/core/sharing";
|
|
3
|
-
import { and, desc, eq } from "drizzle-orm";
|
|
3
|
+
import { and, desc, eq, inArray } from "drizzle-orm";
|
|
4
4
|
|
|
5
5
|
import type {
|
|
6
6
|
BrainCaptureKind,
|
|
7
7
|
BrainSourceProvider,
|
|
8
8
|
} from "../../shared/types.js";
|
|
9
9
|
import { getDb, schema } from "../db/index.js";
|
|
10
|
+
import { listAccessibleAudienceIds } from "./audiences.js";
|
|
10
11
|
import {
|
|
12
|
+
BrainCaptureBlockedError,
|
|
11
13
|
createCapture,
|
|
12
14
|
nanoid,
|
|
13
15
|
nowIso,
|
|
14
16
|
parseJson,
|
|
17
|
+
readBrainSettings,
|
|
15
18
|
serializeCapture,
|
|
16
19
|
stableJson,
|
|
17
20
|
} from "./brain.js";
|
|
21
|
+
import {
|
|
22
|
+
ensureSlackPublicChannelMembership,
|
|
23
|
+
type SlackChannelJoinResponse,
|
|
24
|
+
} from "./slack-channel-membership.js";
|
|
18
25
|
import {
|
|
19
26
|
inspectSourceCredentialAvailability,
|
|
20
27
|
resolveSourceCredential,
|
|
@@ -31,6 +38,19 @@ export interface ConnectorSyncResult {
|
|
|
31
38
|
stats?: Record<string, unknown>;
|
|
32
39
|
}
|
|
33
40
|
|
|
41
|
+
async function createConnectorCapture(
|
|
42
|
+
values: Parameters<typeof createCapture>[0],
|
|
43
|
+
) {
|
|
44
|
+
try {
|
|
45
|
+
return { capture: await createCapture(values), blocked: false };
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error instanceof BrainCaptureBlockedError) {
|
|
48
|
+
return { capture: null, blocked: true };
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
34
54
|
export interface SlackPilotOptions {
|
|
35
55
|
readHistory?: boolean;
|
|
36
56
|
channelRefs?: string[];
|
|
@@ -145,6 +165,7 @@ interface SlackChannelCursor {
|
|
|
145
165
|
|
|
146
166
|
interface SlackSyncCursor {
|
|
147
167
|
channels?: Record<string, SlackChannelCursor>;
|
|
168
|
+
publicChannelOffset?: number;
|
|
148
169
|
retry?: RetryCursor;
|
|
149
170
|
lastRunAt?: string;
|
|
150
171
|
}
|
|
@@ -164,6 +185,8 @@ interface SlackChannel {
|
|
|
164
185
|
is_channel?: boolean;
|
|
165
186
|
is_group?: boolean;
|
|
166
187
|
is_archived?: boolean;
|
|
188
|
+
is_private?: boolean;
|
|
189
|
+
is_member?: boolean;
|
|
167
190
|
}
|
|
168
191
|
|
|
169
192
|
interface SlackMessage {
|
|
@@ -175,6 +198,7 @@ interface SlackMessage {
|
|
|
175
198
|
text?: string;
|
|
176
199
|
ts?: string;
|
|
177
200
|
thread_ts?: string;
|
|
201
|
+
reactions?: Array<{ name?: string; count?: number }>;
|
|
178
202
|
}
|
|
179
203
|
|
|
180
204
|
interface SlackHistoryResponse {
|
|
@@ -183,6 +207,10 @@ interface SlackHistoryResponse {
|
|
|
183
207
|
response_metadata?: { next_cursor?: string };
|
|
184
208
|
}
|
|
185
209
|
|
|
210
|
+
interface SlackRepliesResponse {
|
|
211
|
+
messages?: SlackMessage[];
|
|
212
|
+
}
|
|
213
|
+
|
|
186
214
|
interface SlackInfoResponse {
|
|
187
215
|
channel?: SlackChannel;
|
|
188
216
|
}
|
|
@@ -192,6 +220,19 @@ interface SlackListResponse {
|
|
|
192
220
|
response_metadata?: { next_cursor?: string };
|
|
193
221
|
}
|
|
194
222
|
|
|
223
|
+
interface SlackMembersResponse {
|
|
224
|
+
members?: string[];
|
|
225
|
+
response_metadata?: { next_cursor?: string };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
interface SlackUserInfoResponse {
|
|
229
|
+
user?: { profile?: { email?: string } };
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
type SlackUserEmailCache = Map<string, string | null>;
|
|
233
|
+
|
|
234
|
+
const SLACK_USER_LOOKUP_CONCURRENCY = 4;
|
|
235
|
+
|
|
195
236
|
interface SlackPermalinkResponse {
|
|
196
237
|
permalink?: string;
|
|
197
238
|
}
|
|
@@ -702,10 +743,6 @@ function readableJson(value: unknown): string {
|
|
|
702
743
|
return JSON.stringify(value, null, 2);
|
|
703
744
|
}
|
|
704
745
|
|
|
705
|
-
function slackUserLabel(message: SlackMessage): string {
|
|
706
|
-
return message.username ?? message.user ?? message.bot_id ?? "unknown";
|
|
707
|
-
}
|
|
708
|
-
|
|
709
746
|
function slackDirectConversationFromRef(
|
|
710
747
|
channelRef: string,
|
|
711
748
|
): SlackChannel | null {
|
|
@@ -726,32 +763,120 @@ function isUsableSlackChannel(channel: SlackChannel): boolean {
|
|
|
726
763
|
);
|
|
727
764
|
}
|
|
728
765
|
|
|
729
|
-
function
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
766
|
+
function slackReactionCount(message: SlackMessage) {
|
|
767
|
+
return (message.reactions ?? []).reduce(
|
|
768
|
+
(total, reaction) => total + Math.max(0, Number(reaction.count) || 0),
|
|
769
|
+
0,
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
function isSlackTextMessage(message: SlackMessage) {
|
|
774
|
+
return (
|
|
775
|
+
message.type === "message" &&
|
|
776
|
+
typeof message.text === "string" &&
|
|
777
|
+
message.text.trim().length > 0 &&
|
|
778
|
+
typeof message.ts === "string"
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
export interface SlackThreadCapture {
|
|
783
|
+
externalId: string;
|
|
784
|
+
title: string;
|
|
785
|
+
content: string;
|
|
786
|
+
capturedAt: string;
|
|
787
|
+
metadata: Record<string, unknown>;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* Builds the only Slack representation Brain persists. It deliberately omits
|
|
792
|
+
* Slack user ids, display names, and the raw Events/Web API payload.
|
|
793
|
+
*/
|
|
794
|
+
export function normalizeSlackThreadCapture(input: {
|
|
795
|
+
channel: SlackChannel;
|
|
796
|
+
messages: SlackMessage[];
|
|
797
|
+
permalink?: string | null;
|
|
798
|
+
syncRunId?: string;
|
|
799
|
+
}): SlackThreadCapture | null {
|
|
800
|
+
const messages = input.messages
|
|
801
|
+
.filter(isSlackTextMessage)
|
|
802
|
+
.sort((left, right) => Number(left.ts) - Number(right.ts));
|
|
803
|
+
const root = messages[0];
|
|
804
|
+
if (!root?.ts) return null;
|
|
805
|
+
|
|
806
|
+
let offset = 0;
|
|
807
|
+
const safeSegments = messages.map((message, index) => {
|
|
808
|
+
const capturedAt = isoFromSlackTs(message.ts) ?? message.ts!;
|
|
809
|
+
const text = `${capturedAt}\n${message.text!.trim()}`;
|
|
810
|
+
const startOffset = offset;
|
|
811
|
+
offset += text.length;
|
|
812
|
+
if (index < messages.length - 1) offset += 2;
|
|
813
|
+
return {
|
|
814
|
+
id: `slack:${input.channel.id}:${message.ts}`,
|
|
815
|
+
capturedAt,
|
|
816
|
+
sourceUrl: input.permalink ?? undefined,
|
|
817
|
+
text,
|
|
818
|
+
startOffset,
|
|
819
|
+
endOffset: startOffset + text.length,
|
|
820
|
+
reactionCount: slackReactionCount(message),
|
|
821
|
+
};
|
|
822
|
+
});
|
|
823
|
+
const content = safeSegments.map((segment) => segment.text).join("\n\n");
|
|
824
|
+
const threadTs = root.thread_ts ?? root.ts;
|
|
825
|
+
return {
|
|
826
|
+
externalId: `slack:${input.channel.id}:${threadTs}`,
|
|
827
|
+
title: `#${input.channel.name ?? input.channel.id} thread ${isoFromSlackTs(threadTs) ?? threadTs}`,
|
|
828
|
+
content,
|
|
829
|
+
capturedAt: isoFromSlackTs(threadTs) ?? nowIso(),
|
|
830
|
+
metadata: {
|
|
831
|
+
provider: "slack",
|
|
832
|
+
connector: "slack",
|
|
833
|
+
...(input.syncRunId ? { syncRunId: input.syncRunId } : {}),
|
|
834
|
+
channelId: input.channel.id,
|
|
835
|
+
channelName: input.channel.name,
|
|
836
|
+
threadTs,
|
|
837
|
+
messageCount: safeSegments.length,
|
|
838
|
+
reactionCount: safeSegments.reduce(
|
|
839
|
+
(total, segment) => total + segment.reactionCount,
|
|
840
|
+
0,
|
|
841
|
+
),
|
|
842
|
+
sourceUrl: input.permalink ?? null,
|
|
843
|
+
permalink: input.permalink ?? null,
|
|
844
|
+
// These offsets are against `content`, the safe persisted capture, never
|
|
845
|
+
// against a provider payload.
|
|
846
|
+
safeSegments,
|
|
847
|
+
},
|
|
848
|
+
};
|
|
745
849
|
}
|
|
746
850
|
|
|
747
851
|
async function slackApi<T>(
|
|
748
852
|
token: string,
|
|
749
853
|
method: string,
|
|
750
854
|
params: Record<string, string | number | boolean | null | undefined> = {},
|
|
855
|
+
options: {
|
|
856
|
+
httpMethod?: "GET" | "POST";
|
|
857
|
+
toleratedErrors?: readonly string[];
|
|
858
|
+
} = {},
|
|
751
859
|
): Promise<T> {
|
|
752
|
-
const
|
|
860
|
+
const httpMethod = options.httpMethod ?? "GET";
|
|
861
|
+
const url = buildUrl(
|
|
862
|
+
`https://slack.com/api/${method}`,
|
|
863
|
+
httpMethod === "GET" ? params : {},
|
|
864
|
+
);
|
|
865
|
+
const body = new URLSearchParams();
|
|
866
|
+
if (httpMethod === "POST") {
|
|
867
|
+
for (const [key, value] of Object.entries(params)) {
|
|
868
|
+
if (value !== null && value !== undefined) body.set(key, String(value));
|
|
869
|
+
}
|
|
870
|
+
}
|
|
753
871
|
const response = await fetch(url.toString(), {
|
|
754
|
-
|
|
872
|
+
method: httpMethod,
|
|
873
|
+
headers: {
|
|
874
|
+
Authorization: `Bearer ${token}`,
|
|
875
|
+
...(httpMethod === "POST"
|
|
876
|
+
? { "Content-Type": "application/x-www-form-urlencoded" }
|
|
877
|
+
: {}),
|
|
878
|
+
},
|
|
879
|
+
...(httpMethod === "POST" ? { body } : {}),
|
|
755
880
|
});
|
|
756
881
|
if (response.status === 429) {
|
|
757
882
|
throw new ConnectorRateLimitError(
|
|
@@ -773,6 +898,9 @@ async function slackApi<T>(
|
|
|
773
898
|
if (data.error === "ratelimited") {
|
|
774
899
|
throw new ConnectorRateLimitError("slack", method, 60);
|
|
775
900
|
}
|
|
901
|
+
if (data.error && options.toleratedErrors?.includes(data.error)) {
|
|
902
|
+
return data as T;
|
|
903
|
+
}
|
|
776
904
|
const details = [
|
|
777
905
|
data.needed ? `needed: ${data.needed}` : null,
|
|
778
906
|
data.provided ? `provided: ${data.provided}` : null,
|
|
@@ -810,6 +938,60 @@ async function resolveSlackChannelByName(
|
|
|
810
938
|
return null;
|
|
811
939
|
}
|
|
812
940
|
|
|
941
|
+
function matchesPublicChannelExclusion(
|
|
942
|
+
channel: SlackChannel,
|
|
943
|
+
patterns: string[],
|
|
944
|
+
) {
|
|
945
|
+
return patterns.some((pattern) => {
|
|
946
|
+
try {
|
|
947
|
+
const expression = new RegExp(pattern, "i");
|
|
948
|
+
return expression.test(channel.id) || expression.test(channel.name ?? "");
|
|
949
|
+
} catch {
|
|
950
|
+
return false;
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
async function listPublicSlackChannels(
|
|
956
|
+
token: string,
|
|
957
|
+
exclusionPatterns: string[],
|
|
958
|
+
): Promise<{ channels: SlackChannel[]; excluded: number }> {
|
|
959
|
+
const channels: SlackChannel[] = [];
|
|
960
|
+
const seenCursors = new Set<string>();
|
|
961
|
+
let cursor: string | undefined;
|
|
962
|
+
let excluded = 0;
|
|
963
|
+
for (;;) {
|
|
964
|
+
const page = await slackApi<SlackListResponse>(
|
|
965
|
+
token,
|
|
966
|
+
"conversations.list",
|
|
967
|
+
{
|
|
968
|
+
types: "public_channel",
|
|
969
|
+
exclude_archived: true,
|
|
970
|
+
limit: 200,
|
|
971
|
+
cursor,
|
|
972
|
+
},
|
|
973
|
+
);
|
|
974
|
+
for (const channel of page.channels ?? []) {
|
|
975
|
+
if (
|
|
976
|
+
channel.is_archived ||
|
|
977
|
+
channel.is_private ||
|
|
978
|
+
channel.is_channel === false
|
|
979
|
+
) {
|
|
980
|
+
continue;
|
|
981
|
+
}
|
|
982
|
+
if (matchesPublicChannelExclusion(channel, exclusionPatterns)) {
|
|
983
|
+
excluded += 1;
|
|
984
|
+
continue;
|
|
985
|
+
}
|
|
986
|
+
channels.push(channel);
|
|
987
|
+
}
|
|
988
|
+
cursor = page.response_metadata?.next_cursor;
|
|
989
|
+
if (!cursor || seenCursors.has(cursor)) break;
|
|
990
|
+
seenCursors.add(cursor);
|
|
991
|
+
}
|
|
992
|
+
return { channels, excluded };
|
|
993
|
+
}
|
|
994
|
+
|
|
813
995
|
async function resolveSlackChannel(
|
|
814
996
|
token: string,
|
|
815
997
|
channelRef: string,
|
|
@@ -848,6 +1030,121 @@ async function slackPermalink(
|
|
|
848
1030
|
return data.permalink ?? null;
|
|
849
1031
|
}
|
|
850
1032
|
|
|
1033
|
+
async function slackPrivateChannelMemberEmails(
|
|
1034
|
+
token: string,
|
|
1035
|
+
channelId: string,
|
|
1036
|
+
userEmailCache: SlackUserEmailCache,
|
|
1037
|
+
): Promise<string[] | null> {
|
|
1038
|
+
const memberIds = new Set<string>();
|
|
1039
|
+
const seenCursors = new Set<string>();
|
|
1040
|
+
let cursor: string | undefined;
|
|
1041
|
+
while (true) {
|
|
1042
|
+
const response = await slackApi<SlackMembersResponse>(
|
|
1043
|
+
token,
|
|
1044
|
+
"conversations.members",
|
|
1045
|
+
{ channel: channelId, limit: 1_000, cursor },
|
|
1046
|
+
);
|
|
1047
|
+
for (const memberId of response.members ?? []) {
|
|
1048
|
+
if (memberId) memberIds.add(memberId);
|
|
1049
|
+
}
|
|
1050
|
+
const nextCursor = response.response_metadata?.next_cursor?.trim();
|
|
1051
|
+
if (!nextCursor) break;
|
|
1052
|
+
if (seenCursors.has(nextCursor)) return null;
|
|
1053
|
+
seenCursors.add(nextCursor);
|
|
1054
|
+
cursor = nextCursor;
|
|
1055
|
+
}
|
|
1056
|
+
const userIds = Array.from(memberIds);
|
|
1057
|
+
if (!userIds.length) return null;
|
|
1058
|
+
if (
|
|
1059
|
+
userIds.some(
|
|
1060
|
+
(userId) => userEmailCache.has(userId) && !userEmailCache.get(userId),
|
|
1061
|
+
)
|
|
1062
|
+
) {
|
|
1063
|
+
return null;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
const uncachedUserIds = userIds.filter(
|
|
1067
|
+
(userId) => !userEmailCache.has(userId),
|
|
1068
|
+
);
|
|
1069
|
+
for (
|
|
1070
|
+
let offset = 0;
|
|
1071
|
+
offset < uncachedUserIds.length;
|
|
1072
|
+
offset += SLACK_USER_LOOKUP_CONCURRENCY
|
|
1073
|
+
) {
|
|
1074
|
+
const batch = uncachedUserIds.slice(
|
|
1075
|
+
offset,
|
|
1076
|
+
offset + SLACK_USER_LOOKUP_CONCURRENCY,
|
|
1077
|
+
);
|
|
1078
|
+
await Promise.all(
|
|
1079
|
+
batch.map(async (userId) => {
|
|
1080
|
+
const user = await slackApi<SlackUserInfoResponse>(
|
|
1081
|
+
token,
|
|
1082
|
+
"users.info",
|
|
1083
|
+
{ user: userId },
|
|
1084
|
+
);
|
|
1085
|
+
const email = user.user?.profile?.email?.trim().toLowerCase() ?? null;
|
|
1086
|
+
userEmailCache.set(userId, email || null);
|
|
1087
|
+
}),
|
|
1088
|
+
);
|
|
1089
|
+
if (batch.some((userId) => !userEmailCache.get(userId))) return null;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
const emails: string[] = [];
|
|
1093
|
+
for (const userId of userIds) {
|
|
1094
|
+
const email = userEmailCache.get(userId);
|
|
1095
|
+
if (!email) return null;
|
|
1096
|
+
emails.push(email);
|
|
1097
|
+
}
|
|
1098
|
+
return Array.from(new Set(emails)).sort();
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
function configuredSlackChannelIds(config: Record<string, unknown>) {
|
|
1102
|
+
return new Set(
|
|
1103
|
+
slackChannelRefsFromConfig(config).filter((value) =>
|
|
1104
|
+
/^[CG][A-Z0-9]+$/i.test(value),
|
|
1105
|
+
),
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
async function createSlackThreadCapture(input: {
|
|
1110
|
+
source: SourceRow;
|
|
1111
|
+
channel: SlackChannel;
|
|
1112
|
+
messages: SlackMessage[];
|
|
1113
|
+
permalink: string | null;
|
|
1114
|
+
syncRunId?: string;
|
|
1115
|
+
memberEmails?: string[] | null;
|
|
1116
|
+
}) {
|
|
1117
|
+
const normalized = normalizeSlackThreadCapture({
|
|
1118
|
+
channel: input.channel,
|
|
1119
|
+
messages: input.messages,
|
|
1120
|
+
permalink: input.permalink,
|
|
1121
|
+
syncRunId: input.syncRunId,
|
|
1122
|
+
});
|
|
1123
|
+
if (!normalized) return { capture: null, blocked: false };
|
|
1124
|
+
try {
|
|
1125
|
+
const capture = await createCapture({
|
|
1126
|
+
sourceId: input.source.id,
|
|
1127
|
+
externalId: normalized.externalId,
|
|
1128
|
+
title: normalized.title,
|
|
1129
|
+
kind: "message",
|
|
1130
|
+
content: normalized.content,
|
|
1131
|
+
capturedAt: normalized.capturedAt,
|
|
1132
|
+
metadata: normalized.metadata,
|
|
1133
|
+
audience: {
|
|
1134
|
+
kind: input.channel.is_private ? "slack-private-channel" : "org",
|
|
1135
|
+
memberEmails: input.memberEmails ?? undefined,
|
|
1136
|
+
upstreamRefHash: input.channel.id,
|
|
1137
|
+
},
|
|
1138
|
+
});
|
|
1139
|
+
return { capture, blocked: false };
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
if (error instanceof BrainCaptureBlockedError) {
|
|
1142
|
+
return { capture: null, blocked: true };
|
|
1143
|
+
}
|
|
1144
|
+
throw error;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
|
|
851
1148
|
export async function testSlackConnection(
|
|
852
1149
|
options: {
|
|
853
1150
|
channelRefs?: string[];
|
|
@@ -1659,10 +1956,32 @@ async function githubRefsFromLinkedSources(
|
|
|
1659
1956
|
Number(options.stats.linkedSourcesSkipped) + 1;
|
|
1660
1957
|
continue;
|
|
1661
1958
|
}
|
|
1959
|
+
const audienceIds = await listAccessibleAudienceIds([sourceId]);
|
|
1960
|
+
if (!audienceIds.length) continue;
|
|
1662
1961
|
const captures = await db
|
|
1663
|
-
.select(
|
|
1962
|
+
.select({
|
|
1963
|
+
id: schema.brainRawCaptures.id,
|
|
1964
|
+
title: schema.brainRawCaptures.title,
|
|
1965
|
+
content: schema.brainRawCaptures.content,
|
|
1966
|
+
metadataJson: schema.brainRawCaptures.metadataJson,
|
|
1967
|
+
})
|
|
1664
1968
|
.from(schema.brainRawCaptures)
|
|
1665
|
-
.
|
|
1969
|
+
.innerJoin(
|
|
1970
|
+
schema.brainCaptureAudiences,
|
|
1971
|
+
eq(schema.brainCaptureAudiences.captureId, schema.brainRawCaptures.id),
|
|
1972
|
+
)
|
|
1973
|
+
.innerJoin(
|
|
1974
|
+
schema.brainAudiences,
|
|
1975
|
+
eq(schema.brainAudiences.id, schema.brainCaptureAudiences.audienceId),
|
|
1976
|
+
)
|
|
1977
|
+
.where(
|
|
1978
|
+
and(
|
|
1979
|
+
eq(schema.brainRawCaptures.sourceId, sourceId),
|
|
1980
|
+
eq(schema.brainRawCaptures.sensitivityDisposition, "allowed"),
|
|
1981
|
+
inArray(schema.brainCaptureAudiences.audienceId, audienceIds),
|
|
1982
|
+
eq(schema.brainAudiences.kind, "org"),
|
|
1983
|
+
),
|
|
1984
|
+
)
|
|
1666
1985
|
.orderBy(desc(schema.brainRawCaptures.capturedAt))
|
|
1667
1986
|
.limit(options.captureLimit);
|
|
1668
1987
|
|
|
@@ -1675,7 +1994,6 @@ async function githubRefsFromLinkedSources(
|
|
|
1675
1994
|
capture.metadataJson,
|
|
1676
1995
|
{},
|
|
1677
1996
|
);
|
|
1678
|
-
const raw = objectValue(metadata.raw);
|
|
1679
1997
|
const linkedFrom = {
|
|
1680
1998
|
sourceId,
|
|
1681
1999
|
captureId: capture.id,
|
|
@@ -1684,7 +2002,6 @@ async function githubRefsFromLinkedSources(
|
|
|
1684
2002
|
};
|
|
1685
2003
|
const candidates = [
|
|
1686
2004
|
capture.content,
|
|
1687
|
-
typeof raw.text === "string" ? raw.text : "",
|
|
1688
2005
|
typeof metadata.sourceUrl === "string" ? metadata.sourceUrl : "",
|
|
1689
2006
|
typeof metadata.permalink === "string" ? metadata.permalink : "",
|
|
1690
2007
|
].join("\n");
|
|
@@ -1741,10 +2058,11 @@ async function syncFromConfiguredItems(
|
|
|
1741
2058
|
const config = parseJson<Record<string, unknown>>(source.configJson, {});
|
|
1742
2059
|
const items = transcriptItems(config);
|
|
1743
2060
|
const captures = [];
|
|
2061
|
+
let sensitivityBlocked = 0;
|
|
1744
2062
|
|
|
1745
2063
|
try {
|
|
1746
2064
|
for (const item of items) {
|
|
1747
|
-
const
|
|
2065
|
+
const captureResult = await createConnectorCapture({
|
|
1748
2066
|
sourceId: source.id,
|
|
1749
2067
|
externalId: item.externalId,
|
|
1750
2068
|
title: item.title,
|
|
@@ -1757,9 +2075,14 @@ async function syncFromConfiguredItems(
|
|
|
1757
2075
|
syncRunId: runId,
|
|
1758
2076
|
},
|
|
1759
2077
|
});
|
|
1760
|
-
|
|
2078
|
+
if (captureResult.capture)
|
|
2079
|
+
captures.push(serializeCapture(captureResult.capture));
|
|
2080
|
+
if (captureResult.blocked) sensitivityBlocked += 1;
|
|
1761
2081
|
}
|
|
1762
|
-
await finishRun(runId, "success", {
|
|
2082
|
+
await finishRun(runId, "success", {
|
|
2083
|
+
capturesCreated: captures.length,
|
|
2084
|
+
sensitivityBlocked,
|
|
2085
|
+
});
|
|
1763
2086
|
await getDb()
|
|
1764
2087
|
.update(schema.brainSources)
|
|
1765
2088
|
.set({
|
|
@@ -1841,6 +2164,12 @@ async function syncSlack(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
1841
2164
|
],
|
|
1842
2165
|
"slack",
|
|
1843
2166
|
);
|
|
2167
|
+
const includePublicChannels = configuredBoolean(
|
|
2168
|
+
config,
|
|
2169
|
+
["includePublicChannels"],
|
|
2170
|
+
false,
|
|
2171
|
+
"slack",
|
|
2172
|
+
);
|
|
1844
2173
|
const limit = configuredNumber(config, ["historyLimit", "limit"], 15, {
|
|
1845
2174
|
min: 1,
|
|
1846
2175
|
max: 15,
|
|
@@ -1877,11 +2206,19 @@ async function syncSlack(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
1877
2206
|
const captures = [];
|
|
1878
2207
|
const stats: Record<string, unknown> = {
|
|
1879
2208
|
configuredChannels: channelRefs.length,
|
|
2209
|
+
includePublicChannels,
|
|
2210
|
+
discoveredPublicChannels: 0,
|
|
2211
|
+
excludedPublicChannels: 0,
|
|
2212
|
+
eligibleChannels: 0,
|
|
1880
2213
|
scannedChannels: 0,
|
|
1881
2214
|
rejectedChannels: 0,
|
|
1882
2215
|
missingChannels: 0,
|
|
1883
2216
|
messagesSeen: 0,
|
|
1884
2217
|
capturesCreated: 0,
|
|
2218
|
+
threadsFetched: 0,
|
|
2219
|
+
sensitivityBlocked: 0,
|
|
2220
|
+
publicChannelsJoined: 0,
|
|
2221
|
+
publicChannelsAlreadyJoined: 0,
|
|
1885
2222
|
rateLimited: false,
|
|
1886
2223
|
};
|
|
1887
2224
|
|
|
@@ -1892,15 +2229,17 @@ async function syncSlack(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
1892
2229
|
"slack",
|
|
1893
2230
|
config,
|
|
1894
2231
|
);
|
|
1895
|
-
if (!channelRefs.length) {
|
|
2232
|
+
if (!channelRefs.length && !includePublicChannels) {
|
|
1896
2233
|
throw new Error(
|
|
1897
|
-
"Slack source must configure channelIds, channels, or
|
|
2234
|
+
"Slack source must configure channelIds, channels, allowedChannels, or includePublicChannels",
|
|
1898
2235
|
);
|
|
1899
2236
|
}
|
|
1900
2237
|
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
2238
|
+
const settings = await readBrainSettings();
|
|
2239
|
+
const publicExclusionPatterns =
|
|
2240
|
+
settings.publicChannelExclusionPatterns ?? [];
|
|
2241
|
+
const channelsById = new Map<string, SlackChannel>();
|
|
2242
|
+
for (const channelRef of channelRefs) {
|
|
1904
2243
|
const channel = await resolveSlackChannel(token, channelRef);
|
|
1905
2244
|
if (!channel) {
|
|
1906
2245
|
stats.missingChannels = Number(stats.missingChannels) + 1;
|
|
@@ -1910,6 +2249,87 @@ async function syncSlack(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
1910
2249
|
stats.rejectedChannels = Number(stats.rejectedChannels) + 1;
|
|
1911
2250
|
continue;
|
|
1912
2251
|
}
|
|
2252
|
+
const isExplicitId = /^[CG][A-Z0-9]+$/i.test(channelRef);
|
|
2253
|
+
if (channel.is_private && !isExplicitId) {
|
|
2254
|
+
stats.rejectedChannels = Number(stats.rejectedChannels) + 1;
|
|
2255
|
+
continue;
|
|
2256
|
+
}
|
|
2257
|
+
if (
|
|
2258
|
+
!channel.is_private &&
|
|
2259
|
+
matchesPublicChannelExclusion(channel, publicExclusionPatterns)
|
|
2260
|
+
) {
|
|
2261
|
+
stats.excludedPublicChannels = Number(stats.excludedPublicChannels) + 1;
|
|
2262
|
+
continue;
|
|
2263
|
+
}
|
|
2264
|
+
channelsById.set(channel.id, channel);
|
|
2265
|
+
}
|
|
2266
|
+
if (includePublicChannels) {
|
|
2267
|
+
const discovered = await listPublicSlackChannels(
|
|
2268
|
+
token,
|
|
2269
|
+
publicExclusionPatterns,
|
|
2270
|
+
);
|
|
2271
|
+
stats.discoveredPublicChannels = discovered.channels.length;
|
|
2272
|
+
stats.excludedPublicChannels =
|
|
2273
|
+
Number(stats.excludedPublicChannels) + discovered.excluded;
|
|
2274
|
+
for (const channel of discovered.channels) {
|
|
2275
|
+
channelsById.set(channel.id, channel);
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
const channels = [...channelsById.values()];
|
|
2279
|
+
stats.eligibleChannels = channels.length;
|
|
2280
|
+
const userEmailCache: SlackUserEmailCache = new Map();
|
|
2281
|
+
|
|
2282
|
+
const channelsToScan = includePublicChannels
|
|
2283
|
+
? (() => {
|
|
2284
|
+
const ordered = [...channels].sort((left, right) =>
|
|
2285
|
+
left.id.localeCompare(right.id),
|
|
2286
|
+
);
|
|
2287
|
+
if (!ordered.length) return ordered;
|
|
2288
|
+
const offset =
|
|
2289
|
+
Math.max(0, cursor.publicChannelOffset ?? 0) % ordered.length;
|
|
2290
|
+
const rotated = [
|
|
2291
|
+
...ordered.slice(offset),
|
|
2292
|
+
...ordered.slice(0, offset),
|
|
2293
|
+
];
|
|
2294
|
+
nextCursor.publicChannelOffset =
|
|
2295
|
+
(offset + Math.min(maxChannels, rotated.length)) % ordered.length;
|
|
2296
|
+
return rotated.slice(0, maxChannels);
|
|
2297
|
+
})()
|
|
2298
|
+
: channels.slice(0, maxChannels);
|
|
2299
|
+
|
|
2300
|
+
let permalinkCalls = 0;
|
|
2301
|
+
|
|
2302
|
+
for (const channel of channelsToScan) {
|
|
2303
|
+
const membership = await ensureSlackPublicChannelMembership(
|
|
2304
|
+
channel,
|
|
2305
|
+
(channelId) =>
|
|
2306
|
+
slackApi<SlackChannelJoinResponse>(
|
|
2307
|
+
token,
|
|
2308
|
+
"conversations.join",
|
|
2309
|
+
{ channel: channelId },
|
|
2310
|
+
{
|
|
2311
|
+
httpMethod: "POST",
|
|
2312
|
+
toleratedErrors: ["already_in_channel"],
|
|
2313
|
+
},
|
|
2314
|
+
),
|
|
2315
|
+
);
|
|
2316
|
+
if (membership === "joined") {
|
|
2317
|
+
stats.publicChannelsJoined = Number(stats.publicChannelsJoined) + 1;
|
|
2318
|
+
} else if (membership === "already_member") {
|
|
2319
|
+
stats.publicChannelsAlreadyJoined =
|
|
2320
|
+
Number(stats.publicChannelsAlreadyJoined) + 1;
|
|
2321
|
+
}
|
|
2322
|
+
const privateMemberEmails = channel.is_private
|
|
2323
|
+
? await slackPrivateChannelMemberEmails(
|
|
2324
|
+
token,
|
|
2325
|
+
channel.id,
|
|
2326
|
+
userEmailCache,
|
|
2327
|
+
)
|
|
2328
|
+
: null;
|
|
2329
|
+
if (channel.is_private && !privateMemberEmails?.length) {
|
|
2330
|
+
stats.rejectedChannels = Number(stats.rejectedChannels) + 1;
|
|
2331
|
+
continue;
|
|
2332
|
+
}
|
|
1913
2333
|
|
|
1914
2334
|
stats.scannedChannels = Number(stats.scannedChannels) + 1;
|
|
1915
2335
|
const channelCursor = nextCursor.channels?.[channel.id] ?? {};
|
|
@@ -1939,13 +2359,7 @@ async function syncSlack(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
1939
2359
|
"conversations.history",
|
|
1940
2360
|
params,
|
|
1941
2361
|
);
|
|
1942
|
-
const messages = (data.messages ?? []).filter(
|
|
1943
|
-
(message) =>
|
|
1944
|
-
message.type === "message" &&
|
|
1945
|
-
typeof message.text === "string" &&
|
|
1946
|
-
message.text.trim() &&
|
|
1947
|
-
typeof message.ts === "string",
|
|
1948
|
-
);
|
|
2362
|
+
const messages = (data.messages ?? []).filter(isSlackTextMessage);
|
|
1949
2363
|
stats.messagesSeen = Number(stats.messagesSeen) + messages.length;
|
|
1950
2364
|
|
|
1951
2365
|
const newest = newestSlackTs(messages);
|
|
@@ -1953,42 +2367,42 @@ async function syncSlack(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
1953
2367
|
channelCursor.pendingLatestTs = newest;
|
|
1954
2368
|
}
|
|
1955
2369
|
|
|
2370
|
+
const fetchedThreadTs = new Set<string>();
|
|
1956
2371
|
for (const message of messages) {
|
|
2372
|
+
const threadTs = message.thread_ts ?? message.ts;
|
|
2373
|
+
if (!threadTs || fetchedThreadTs.has(threadTs)) continue;
|
|
2374
|
+
fetchedThreadTs.add(threadTs);
|
|
1957
2375
|
let permalink: string | null = null;
|
|
1958
2376
|
if (permalinkCalls < permalinkLimit) {
|
|
1959
|
-
permalink = await slackPermalink(token, channel.id,
|
|
2377
|
+
permalink = await slackPermalink(token, channel.id, threadTs);
|
|
1960
2378
|
permalinkCalls += 1;
|
|
1961
2379
|
}
|
|
1962
|
-
const
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
ts: message.ts,
|
|
1976
|
-
threadTs: message.thread_ts,
|
|
1977
|
-
user: message.user,
|
|
1978
|
-
username: message.username,
|
|
1979
|
-
botId: message.bot_id,
|
|
1980
|
-
sourceUrl: permalink,
|
|
1981
|
-
permalink,
|
|
1982
|
-
raw: message,
|
|
1983
|
-
},
|
|
2380
|
+
const thread = await slackApi<SlackRepliesResponse>(
|
|
2381
|
+
token,
|
|
2382
|
+
"conversations.replies",
|
|
2383
|
+
{ channel: channel.id, ts: threadTs, limit: 1_000 },
|
|
2384
|
+
);
|
|
2385
|
+
stats.threadsFetched = Number(stats.threadsFetched) + 1;
|
|
2386
|
+
const captureResult = await createSlackThreadCapture({
|
|
2387
|
+
source,
|
|
2388
|
+
channel,
|
|
2389
|
+
messages: thread.messages?.length ? thread.messages : [message],
|
|
2390
|
+
permalink,
|
|
2391
|
+
syncRunId: runId,
|
|
2392
|
+
memberEmails: privateMemberEmails,
|
|
1984
2393
|
});
|
|
1985
|
-
|
|
2394
|
+
if (captureResult.capture)
|
|
2395
|
+
captures.push(serializeCapture(captureResult.capture));
|
|
2396
|
+
if (captureResult.blocked) {
|
|
2397
|
+
stats.sensitivityBlocked = Number(stats.sensitivityBlocked) + 1;
|
|
2398
|
+
}
|
|
1986
2399
|
}
|
|
1987
2400
|
|
|
1988
2401
|
const nextPage = data.response_metadata?.next_cursor;
|
|
1989
2402
|
if (data.has_more && nextPage) {
|
|
1990
2403
|
channelCursor.pageCursor = nextPage;
|
|
1991
2404
|
nextCursor.channels![channel.id] = channelCursor;
|
|
2405
|
+
if (page + 1 < pagesPerChannel) continue;
|
|
1992
2406
|
break;
|
|
1993
2407
|
}
|
|
1994
2408
|
|
|
@@ -2076,6 +2490,117 @@ async function syncSlack(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
2076
2490
|
}
|
|
2077
2491
|
}
|
|
2078
2492
|
|
|
2493
|
+
export async function refreshSlackThreadCapture(
|
|
2494
|
+
source: SourceRow,
|
|
2495
|
+
payloadJson: string,
|
|
2496
|
+
) {
|
|
2497
|
+
const payload = parseJson<Record<string, unknown>>(payloadJson, {});
|
|
2498
|
+
const channelId =
|
|
2499
|
+
typeof payload.channelId === "string" ? payload.channelId.trim() : "";
|
|
2500
|
+
const threadTs =
|
|
2501
|
+
typeof payload.threadTs === "string" ? payload.threadTs.trim() : "";
|
|
2502
|
+
if (!/^[CG][A-Z0-9]+$/i.test(channelId) || !slackTsFromDateish(threadTs)) {
|
|
2503
|
+
throw new Error("Slack thread refresh requires a channelId and threadTs");
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
const config = parseJson<Record<string, unknown>>(source.configJson, {});
|
|
2507
|
+
const includePublicChannels = configuredBoolean(
|
|
2508
|
+
config,
|
|
2509
|
+
["includePublicChannels"],
|
|
2510
|
+
false,
|
|
2511
|
+
"slack",
|
|
2512
|
+
);
|
|
2513
|
+
const explicitlyConfigured = configuredSlackChannelIds(config).has(channelId);
|
|
2514
|
+
if (
|
|
2515
|
+
!explicitlyConfigured &&
|
|
2516
|
+
!(includePublicChannels && channelId.startsWith("C"))
|
|
2517
|
+
) {
|
|
2518
|
+
throw new Error(
|
|
2519
|
+
`Slack thread refresh rejected for channel ${channelId}: it is not in this source's public or explicit channel scope`,
|
|
2520
|
+
);
|
|
2521
|
+
}
|
|
2522
|
+
const runId = await createRun(source);
|
|
2523
|
+
try {
|
|
2524
|
+
const token = await requireConnectorCredential(
|
|
2525
|
+
"SLACK_BOT_TOKEN",
|
|
2526
|
+
"Slack",
|
|
2527
|
+
"slack",
|
|
2528
|
+
config,
|
|
2529
|
+
);
|
|
2530
|
+
const channel = await resolveSlackChannel(token, channelId);
|
|
2531
|
+
if (!channel || !isUsableSlackChannel(channel)) {
|
|
2532
|
+
throw new Error(`Slack channel ${channelId} is unavailable for refresh`);
|
|
2533
|
+
}
|
|
2534
|
+
if (
|
|
2535
|
+
!channel.is_private &&
|
|
2536
|
+
matchesPublicChannelExclusion(
|
|
2537
|
+
channel,
|
|
2538
|
+
(await readBrainSettings()).publicChannelExclusionPatterns ?? [],
|
|
2539
|
+
)
|
|
2540
|
+
) {
|
|
2541
|
+
throw new Error(
|
|
2542
|
+
`Slack thread refresh rejected for channel ${channelId}: it matches a Brain public-channel exclusion`,
|
|
2543
|
+
);
|
|
2544
|
+
}
|
|
2545
|
+
const memberEmails = channel.is_private
|
|
2546
|
+
? await slackPrivateChannelMemberEmails(token, channel.id, new Map())
|
|
2547
|
+
: null;
|
|
2548
|
+
if (channel.is_private && !memberEmails?.length) {
|
|
2549
|
+
throw new Error(
|
|
2550
|
+
`Slack private channel ${channel.id} has no resolvable member emails; refusing to refresh without an ACL`,
|
|
2551
|
+
);
|
|
2552
|
+
}
|
|
2553
|
+
const [thread, permalink] = await Promise.all([
|
|
2554
|
+
slackApi<SlackRepliesResponse>(token, "conversations.replies", {
|
|
2555
|
+
channel: channel.id,
|
|
2556
|
+
ts: threadTs,
|
|
2557
|
+
limit: 1_000,
|
|
2558
|
+
}),
|
|
2559
|
+
slackPermalink(token, channel.id, threadTs),
|
|
2560
|
+
]);
|
|
2561
|
+
const captureResult = await createSlackThreadCapture({
|
|
2562
|
+
source,
|
|
2563
|
+
channel,
|
|
2564
|
+
messages: thread.messages ?? [],
|
|
2565
|
+
permalink,
|
|
2566
|
+
syncRunId: runId,
|
|
2567
|
+
memberEmails,
|
|
2568
|
+
});
|
|
2569
|
+
const stats = {
|
|
2570
|
+
channelId: channel.id,
|
|
2571
|
+
threadTs,
|
|
2572
|
+
threadsFetched: 1,
|
|
2573
|
+
capturesCreated: captureResult.capture ? 1 : 0,
|
|
2574
|
+
sensitivityBlocked: captureResult.blocked ? 1 : 0,
|
|
2575
|
+
};
|
|
2576
|
+
await finishRun(runId, "success", stats);
|
|
2577
|
+
await getDb()
|
|
2578
|
+
.update(schema.brainSources)
|
|
2579
|
+
.set({
|
|
2580
|
+
lastSyncedAt: nowIso(),
|
|
2581
|
+
lastError: null,
|
|
2582
|
+
status: "active",
|
|
2583
|
+
updatedAt: nowIso(),
|
|
2584
|
+
})
|
|
2585
|
+
.where(
|
|
2586
|
+
and(
|
|
2587
|
+
accessFilter(schema.brainSources, schema.brainSourceShares),
|
|
2588
|
+
eq(schema.brainSources.id, source.id),
|
|
2589
|
+
),
|
|
2590
|
+
);
|
|
2591
|
+
return {
|
|
2592
|
+
runId,
|
|
2593
|
+
capture: captureResult.capture
|
|
2594
|
+
? serializeCapture(captureResult.capture)
|
|
2595
|
+
: null,
|
|
2596
|
+
};
|
|
2597
|
+
} catch (error) {
|
|
2598
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2599
|
+
await finishRun(runId, "error", { capturesCreated: 0 }, message);
|
|
2600
|
+
throw error;
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2079
2604
|
async function syncGranola(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
2080
2605
|
const config = parseJson<Record<string, unknown>>(source.configJson, {});
|
|
2081
2606
|
if (isFixtureConfig(config) || transcriptItems(config).length > 0) {
|
|
@@ -2146,7 +2671,7 @@ async function syncGranola(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
2146
2671
|
...listed,
|
|
2147
2672
|
...note,
|
|
2148
2673
|
});
|
|
2149
|
-
const
|
|
2674
|
+
const captureResult = await createConnectorCapture({
|
|
2150
2675
|
sourceId: source.id,
|
|
2151
2676
|
externalId: normalized.externalId,
|
|
2152
2677
|
title: normalized.title,
|
|
@@ -2159,7 +2684,11 @@ async function syncGranola(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
2159
2684
|
syncRunId: runId,
|
|
2160
2685
|
},
|
|
2161
2686
|
});
|
|
2162
|
-
|
|
2687
|
+
if (captureResult.capture)
|
|
2688
|
+
captures.push(serializeCapture(captureResult.capture));
|
|
2689
|
+
if (captureResult.blocked) {
|
|
2690
|
+
stats.sensitivityBlocked = Number(stats.sensitivityBlocked ?? 0) + 1;
|
|
2691
|
+
}
|
|
2163
2692
|
|
|
2164
2693
|
const candidateUpdatedAt = note.updated_at ?? listed.updated_at;
|
|
2165
2694
|
if (
|
|
@@ -2449,7 +2978,7 @@ async function syncGitHub(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
2449
2978
|
ref.linkedFrom,
|
|
2450
2979
|
);
|
|
2451
2980
|
importedExternalIds.add(normalized.externalId);
|
|
2452
|
-
const
|
|
2981
|
+
const captureResult = await createConnectorCapture({
|
|
2453
2982
|
sourceId: source.id,
|
|
2454
2983
|
externalId: normalized.externalId,
|
|
2455
2984
|
title: normalized.title,
|
|
@@ -2461,7 +2990,11 @@ async function syncGitHub(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
2461
2990
|
syncRunId: runId,
|
|
2462
2991
|
},
|
|
2463
2992
|
});
|
|
2464
|
-
|
|
2993
|
+
if (captureResult.capture)
|
|
2994
|
+
captures.push(serializeCapture(captureResult.capture));
|
|
2995
|
+
if (captureResult.blocked) {
|
|
2996
|
+
stats.sensitivityBlocked = Number(stats.sensitivityBlocked ?? 0) + 1;
|
|
2997
|
+
}
|
|
2465
2998
|
stats.itemsSeen = Number(stats.itemsSeen) + 1;
|
|
2466
2999
|
stats.linkedRefsImported = Number(stats.linkedRefsImported) + 1;
|
|
2467
3000
|
}
|
|
@@ -2511,7 +3044,7 @@ async function syncGitHub(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
2511
3044
|
|
|
2512
3045
|
const normalized = normalizeGitHubIssue(repo, item, context);
|
|
2513
3046
|
importedExternalIds.add(normalized.externalId);
|
|
2514
|
-
const
|
|
3047
|
+
const captureResult = await createConnectorCapture({
|
|
2515
3048
|
sourceId: source.id,
|
|
2516
3049
|
externalId: normalized.externalId,
|
|
2517
3050
|
title: normalized.title,
|
|
@@ -2523,7 +3056,11 @@ async function syncGitHub(source: SourceRow): Promise<ConnectorSyncResult> {
|
|
|
2523
3056
|
syncRunId: runId,
|
|
2524
3057
|
},
|
|
2525
3058
|
});
|
|
2526
|
-
|
|
3059
|
+
if (captureResult.capture)
|
|
3060
|
+
captures.push(serializeCapture(captureResult.capture));
|
|
3061
|
+
if (captureResult.blocked) {
|
|
3062
|
+
stats.sensitivityBlocked = Number(stats.sensitivityBlocked ?? 0) + 1;
|
|
3063
|
+
}
|
|
2527
3064
|
|
|
2528
3065
|
const candidateUpdatedAt = item.updated_at;
|
|
2529
3066
|
if (
|