@agent-native/core 0.90.10 → 0.91.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 +2 -2
- package/corpus/core/CHANGELOG.md +30 -0
- package/corpus/core/docs/content/toolkit-settings.mdx +56 -3
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/agent/durable-background.ts +5 -5
- package/corpus/core/src/agent/engine/ai-sdk-engine.ts +40 -8
- package/corpus/core/src/agent/engine/anthropic-engine.ts +25 -7
- package/corpus/core/src/agent/engine/output-tokens.ts +94 -0
- package/corpus/core/src/agent/production-agent.ts +34 -6
- package/corpus/core/src/agent/run-ownership.ts +29 -1
- package/corpus/core/src/agent/types.ts +3 -2
- package/corpus/core/src/changelog/parse.ts +78 -0
- package/corpus/core/src/chat-threads/schema.ts +43 -0
- package/corpus/core/src/chat-threads/store.ts +144 -12
- package/corpus/core/src/cli/workspace-dev.ts +25 -5
- package/corpus/core/src/client/AgentPanel.tsx +79 -14
- package/corpus/core/src/client/AssistantChat.tsx +359 -425
- package/corpus/core/src/client/analytics-session.ts +70 -0
- package/corpus/core/src/client/analytics.ts +175 -49
- package/corpus/core/src/client/chat/message-components.tsx +22 -2
- package/corpus/core/src/client/components/ui/message-scroller.tsx +131 -0
- package/corpus/core/src/client/conversation/AgentConversation.tsx +63 -41
- package/corpus/core/src/client/error-capture.ts +616 -0
- package/corpus/core/src/client/index.ts +12 -0
- package/corpus/core/src/client/session-replay.ts +57 -7
- package/corpus/core/src/client/settings/SettingsPanel.tsx +123 -1
- package/corpus/core/src/client/settings/SettingsTabsPage.tsx +292 -45
- package/corpus/core/src/client/settings/index.ts +1 -0
- package/corpus/core/src/client/sharing/ShareButton.tsx +14 -11
- package/corpus/core/src/client/sharing/ShareDialog.tsx +13 -10
- package/corpus/core/src/db/client.ts +12 -9
- package/corpus/core/src/mcp/builtin-tools.ts +29 -2
- package/corpus/core/src/server/agent-chat-plugin.ts +174 -79
- package/corpus/core/src/server/onboarding-html.ts +28 -16
- package/corpus/core/src/shared/reasoning-effort.ts +23 -0
- package/corpus/core/src/sharing/actions/list-resource-shares.ts +45 -1
- package/corpus/core/src/sharing/actions/share-resource.ts +9 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
- package/corpus/core/src/vite/client.ts +217 -35
- package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +8 -7
- package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +14 -10
- package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +15 -15
- package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +38 -22
- package/corpus/templates/analytics/.agents/skills/data-programs/SKILL.md +114 -61
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +7 -7
- package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +1 -1
- package/corpus/templates/analytics/.builder/skills/bigquery/SKILL.md +17 -17
- package/corpus/templates/analytics/.builder/skills/gcloud/SKILL.md +5 -5
- package/corpus/templates/analytics/.builder/skills/github/SKILL.md +7 -7
- package/corpus/templates/analytics/.builder/skills/gong/SKILL.md +12 -12
- package/corpus/templates/analytics/.builder/skills/grafana/SKILL.md +7 -7
- package/corpus/templates/analytics/.builder/skills/sentry/SKILL.md +7 -7
- package/corpus/templates/analytics/.builder/skills/slack/SKILL.md +6 -6
- package/corpus/templates/analytics/.builder/skills/stripe/SKILL.md +7 -7
- package/corpus/templates/analytics/AGENTS.md +47 -2
- package/corpus/templates/analytics/actions/add-status-page-monitor.ts +36 -0
- package/corpus/templates/analytics/actions/capture-test-error.ts +33 -0
- package/corpus/templates/analytics/actions/delete-monitor.ts +24 -0
- package/corpus/templates/analytics/actions/delete-status-page.ts +23 -0
- package/corpus/templates/analytics/actions/get-error-issue.ts +36 -0
- package/corpus/templates/analytics/actions/get-monitor-stats.ts +55 -0
- package/corpus/templates/analytics/actions/get-monitor.ts +27 -0
- package/corpus/templates/analytics/actions/get-public-status-page.ts +41 -0
- package/corpus/templates/analytics/actions/get-status-page.ts +29 -0
- package/corpus/templates/analytics/actions/list-error-issues.ts +40 -0
- package/corpus/templates/analytics/actions/list-monitors.ts +21 -0
- package/corpus/templates/analytics/actions/list-status-pages.ts +21 -0
- package/corpus/templates/analytics/actions/match-error-issues.ts +51 -0
- package/corpus/templates/analytics/actions/navigate.ts +58 -4
- package/corpus/templates/analytics/actions/remove-status-page-monitor.ts +22 -0
- package/corpus/templates/analytics/actions/reorder-status-page-monitors.ts +25 -0
- package/corpus/templates/analytics/actions/resolve-error-issue.ts +38 -0
- package/corpus/templates/analytics/actions/run-monitor-check.ts +23 -0
- package/corpus/templates/analytics/actions/save-analysis.ts +1 -0
- package/corpus/templates/analytics/actions/save-monitor.ts +145 -0
- package/corpus/templates/analytics/actions/save-status-page.ts +47 -0
- package/corpus/templates/analytics/actions/view-screen.ts +212 -0
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +10 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +134 -39
- package/corpus/templates/analytics/app/components/monitoring/PublicStatusView.tsx +351 -0
- package/corpus/templates/analytics/app/components/monitoring/ResponseTimeChart.tsx +174 -0
- package/corpus/templates/analytics/app/components/monitoring/UptimeStatCards.tsx +85 -0
- package/corpus/templates/analytics/app/components/monitoring/UptimeTimelineBars.tsx +106 -0
- package/corpus/templates/analytics/app/components/monitoring/chart-utils.ts +101 -0
- package/corpus/templates/analytics/app/components/monitoring/index.ts +28 -0
- package/corpus/templates/analytics/app/components/monitoring/types.ts +42 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +34 -0
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +6 -0
- package/corpus/templates/analytics/app/i18n-data.ts +33 -0
- package/corpus/templates/analytics/app/pages/DataSources.tsx +28 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +77 -9
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +3 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +7 -0
- package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +205 -0
- package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +100 -0
- package/corpus/templates/analytics/app/pages/monitoring/UptimePanel.tsx +475 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueDetail.tsx +372 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +360 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/Sparkline.tsx +55 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +106 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/types.ts +75 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/utils.ts +132 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorDetail.tsx +535 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +1026 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorList.tsx +311 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/i18n.ts +235 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPageEditor.tsx +661 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPagesView.tsx +355 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/i18n.ts +106 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/slug.ts +24 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/types.ts +20 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-summary.ts +87 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +161 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/utils.ts +210 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +76 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +74 -9
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +197 -20
- package/corpus/templates/analytics/app/root.tsx +33 -1
- package/corpus/templates/analytics/app/routes/monitoring._index.tsx +10 -0
- package/corpus/templates/analytics/app/routes/status.$slug.tsx +118 -0
- package/corpus/templates/analytics/changelog/2026-07-08-add-uptime-monitors-that-ping-your-urls-and-alert-you-when-t.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-analytics-chats-keep-large-data-dictionaries-compact-so-prov.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-create-public-status-pages-that-share-the-live-health-of-cho.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-dashboard-extension-panels-use-clearer-open-copy.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-error-capture.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-fixed-single-panel-dashboard-drags-so-they-no-longer-rewrite.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-jump-straight-from-an-error-in-a-session-recording-to-its-fu.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-monitor-detail-and-list-now-show-colorful-uptime-timelines-r.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-pinned-ask-chats-now-show-a-pin-icon-in-the-sidebar.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-publish-a-public-uptime-status-page-with-colorful-uptime-tim.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-sessions-now-hide-visitor-emails-in-demo-mode-and-show-clean.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-settings-are-cleaner-searchable-and-alerts-have-their-own-tab.md +5 -0
- package/corpus/templates/analytics/changelog/2026-07-08-sidebar-sections-stay-collapsed-until-opened.md +5 -0
- package/corpus/templates/analytics/changelog/2026-07-08-the-uptime-monitor-list-now-has-a-current-status-overview-wi.md +6 -0
- package/corpus/templates/analytics/docs/error-capture.md +172 -0
- package/corpus/templates/analytics/docs/uptime-monitoring.md +150 -0
- package/corpus/templates/analytics/server/db/schema-errors.ts +150 -0
- package/corpus/templates/analytics/server/db/schema-monitoring.ts +177 -0
- package/corpus/templates/analytics/server/db/schema.ts +6 -0
- package/corpus/templates/analytics/server/jobs/uptime-monitors.ts +123 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +41 -0
- package/corpus/templates/analytics/server/lib/data-dictionary-context.ts +55 -12
- package/corpus/templates/analytics/server/lib/error-capture.ts +1331 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +47 -1
- package/corpus/templates/analytics/server/lib/monitor-stats.ts +494 -0
- package/corpus/templates/analytics/server/lib/status-pages.ts +798 -0
- package/corpus/templates/analytics/server/lib/uptime-monitors.ts +1665 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -37
- package/corpus/templates/analytics/server/plugins/auth.ts +11 -1
- package/corpus/templates/analytics/server/plugins/db.ts +408 -0
- package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +63 -0
- package/corpus/templates/assets/app/routes/_index.tsx +1 -1
- package/corpus/templates/assets/app/routes/settings.tsx +22 -1
- package/corpus/templates/assets/changelog/2026-07-08-recent-drafts-keep-comfortable-side-padding.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/brain/app/routes/settings.tsx +43 -5
- package/corpus/templates/brain/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/calendar/app/pages/Settings.tsx +44 -6
- package/corpus/templates/calendar/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/chat/app/routes/settings.tsx +16 -1
- package/corpus/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +79 -37
- package/corpus/templates/clips/actions/regenerate-chapters.ts +7 -0
- package/corpus/templates/clips/app/components/player/player-controls.tsx +35 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +162 -18
- package/corpus/templates/clips/app/hooks/use-auto-title.ts +15 -5
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +63 -6
- package/corpus/templates/clips/app/routes/download.tsx +12 -4
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -0
- package/corpus/templates/clips/app/routes/record.tsx +18 -1
- package/corpus/templates/clips/changelog/2026-07-07-auto-generated-chapter-requests-now-open-the-matching-agent-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-shared-clips-start-playback-reliably-from-the-first-play-click.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-the-clips-desktop-download-page-now-uses-the-agent-native-ap.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-camera-and-microphone-menus-now-show-which-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-copies-new-clip-links-after-saving.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-recordings-now-continue-after-granting-came.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-mobile-shared-clips-now-have-loom-style-tap-and-skip-controls.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-recordings-and-uploads-copy-links-after-saving.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-settings-are-cleaner-searchable-and-collapse-s3-with-builder.md +5 -0
- package/corpus/templates/clips/changelog/2026-07-08-transcripts-are-more-reliable-for-longer-desktop-recordings-.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -0
- package/corpus/templates/clips/chrome-extension/src/background.ts +162 -13
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +14 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +36 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +99 -25
- package/corpus/templates/clips/chrome-extension/src/permission.ts +63 -14
- package/corpus/templates/clips/chrome-extension/src/popup.ts +123 -23
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +47 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +33 -4
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +214 -29
- package/corpus/templates/content/actions/attach-content-database-source.ts +3 -0
- package/corpus/templates/content/actions/change-content-database-source-role.ts +1 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +42 -32
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +352 -81
- package/corpus/templates/content/app/components/editor/database/settings.tsx +49 -24
- package/corpus/templates/content/app/routes/_app.settings.tsx +19 -1
- package/corpus/templates/content/changelog/2026-07-07-builder-source-tag-fields-now-import-as-multi-select.md +6 -0
- package/corpus/templates/content/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/content/shared/api.ts +3 -0
- package/corpus/templates/content/shared/properties.ts +42 -0
- package/corpus/templates/design/actions/generate-design.ts +3 -0
- package/corpus/templates/design/actions/get-design-system.ts +147 -1
- package/corpus/templates/design/app/routes/settings.tsx +16 -1
- package/corpus/templates/design/changelog/2026-07-08-design-generation-now-follows-hydrated-builder-design-system.md +6 -0
- package/corpus/templates/design/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/dispatch/app/routes/settings.tsx +23 -2
- package/corpus/templates/dispatch/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/forms/app/routes/_app.settings.tsx +16 -1
- package/corpus/templates/forms/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/macros/app/routes/settings.tsx +16 -1
- package/corpus/templates/macros/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/mail/app/components/settings/GmailFiltersSection.tsx +1 -1
- package/corpus/templates/mail/app/components/settings/SnippetsSection.tsx +1 -1
- package/corpus/templates/mail/app/pages/SettingsPage.tsx +123 -105
- package/corpus/templates/mail/changelog/2026-07-08-settings-redesigned-with-a-consistent-searchable-layout.md +5 -0
- package/corpus/templates/plan/app/routes/settings.tsx +23 -2
- package/corpus/templates/plan/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/slides/actions/add-slide.ts +1 -0
- package/corpus/templates/slides/actions/get-design-system.ts +147 -1
- package/corpus/templates/slides/app/pages/Index.tsx +46 -1
- package/corpus/templates/slides/app/routes/settings.tsx +16 -1
- package/corpus/templates/slides/changelog/2026-07-08-deck-generation-now-follows-hydrated-builder-design-system-g.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/dist/agent/durable-background.d.ts +1 -1
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +5 -3
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.js +24 -4
- package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
- package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
- package/dist/agent/engine/anthropic-engine.js +13 -3
- package/dist/agent/engine/anthropic-engine.js.map +1 -1
- package/dist/agent/engine/output-tokens.d.ts +27 -0
- package/dist/agent/engine/output-tokens.d.ts.map +1 -1
- package/dist/agent/engine/output-tokens.js +70 -0
- package/dist/agent/engine/output-tokens.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +28 -7
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-ownership.d.ts +6 -0
- package/dist/agent/run-ownership.d.ts.map +1 -1
- package/dist/agent/run-ownership.js +11 -1
- package/dist/agent/run-ownership.js.map +1 -1
- package/dist/agent/types.d.ts +3 -2
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/changelog/parse.d.ts +7 -0
- package/dist/changelog/parse.d.ts.map +1 -1
- package/dist/changelog/parse.js +64 -0
- package/dist/changelog/parse.js.map +1 -1
- package/dist/chat-threads/schema.d.ts +445 -0
- package/dist/chat-threads/schema.d.ts.map +1 -0
- package/dist/chat-threads/schema.js +39 -0
- package/dist/chat-threads/schema.js.map +1 -0
- package/dist/chat-threads/store.d.ts +12 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +99 -10
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/workspace-dev.d.ts.map +1 -1
- package/dist/cli/workspace-dev.js +20 -5
- package/dist/cli/workspace-dev.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +35 -7
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +105 -183
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/analytics-session.d.ts +3 -0
- package/dist/client/analytics-session.d.ts.map +1 -0
- package/dist/client/analytics-session.js +66 -0
- package/dist/client/analytics-session.js.map +1 -0
- package/dist/client/analytics.d.ts +32 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +116 -46
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +2 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +16 -6
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/components/ui/message-scroller.d.ts +16 -0
- package/dist/client/components/ui/message-scroller.d.ts.map +1 -0
- package/dist/client/components/ui/message-scroller.js +25 -0
- package/dist/client/components/ui/message-scroller.js.map +1 -0
- package/dist/client/conversation/AgentConversation.d.ts +1 -1
- package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
- package/dist/client/conversation/AgentConversation.js +3 -8
- package/dist/client/conversation/AgentConversation.js.map +1 -1
- package/dist/client/error-capture.d.ts +99 -0
- package/dist/client/error-capture.d.ts.map +1 -0
- package/dist/client/error-capture.js +437 -0
- package/dist/client/error-capture.js.map +1 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/session-replay.d.ts +22 -0
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +45 -4
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +100 -5
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/SettingsTabsPage.d.ts +49 -1
- package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
- package/dist/client/settings/SettingsTabsPage.js +131 -19
- package/dist/client/settings/SettingsTabsPage.js.map +1 -1
- package/dist/client/settings/index.d.ts +1 -1
- package/dist/client/settings/index.d.ts.map +1 -1
- package/dist/client/settings/index.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +13 -8
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/sharing/ShareDialog.d.ts.map +1 -1
- package/dist/client/sharing/ShareDialog.js +12 -7
- package/dist/client/sharing/ShareDialog.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +12 -7
- package/dist/db/client.js.map +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +21 -2
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/org/schema.d.ts +15 -15
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +109 -73
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +28 -16
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/shared/reasoning-effort.d.ts +1 -0
- package/dist/shared/reasoning-effort.d.ts.map +1 -1
- package/dist/shared/reasoning-effort.js +18 -0
- package/dist/shared/reasoning-effort.js.map +1 -1
- package/dist/sharing/actions/list-resource-shares.js +30 -1
- package/dist/sharing/actions/list-resource-shares.js.map +1 -1
- package/dist/sharing/actions/share-resource.js +6 -0
- package/dist/sharing/actions/share-resource.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
- package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +192 -30
- package/dist/vite/client.js.map +1 -1
- package/docs/content/toolkit-settings.mdx +56 -3
- package/package.json +2 -1
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
- package/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
|
@@ -242,4 +242,82 @@ export function rollupChangelog(
|
|
|
242
242
|
return `${head}\n\n${section}\n${rest}\n`;
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
+
function changelogHeader(markdown: string): string {
|
|
246
|
+
const doc = (markdown || CHANGELOG_HEADER).replace(/\s+$/, "");
|
|
247
|
+
const firstRelease = doc.search(/^##\s+(?!#)/m);
|
|
248
|
+
const header =
|
|
249
|
+
(firstRelease === -1 ? doc : doc.slice(0, firstRelease)).replace(
|
|
250
|
+
/\s+$/,
|
|
251
|
+
"",
|
|
252
|
+
) || CHANGELOG_HEADER.trim();
|
|
253
|
+
return header;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function pendingSectionTitle(entry: PendingChangelogEntry): string {
|
|
257
|
+
return entry.date?.match(ISO_DATE)?.[1] ?? "Unreleased";
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function pendingSectionSort(a: string, b: string): number {
|
|
261
|
+
const aDate = a.match(ISO_DATE)?.[1];
|
|
262
|
+
const bDate = b.match(ISO_DATE)?.[1];
|
|
263
|
+
if (aDate && bDate) return bDate.localeCompare(aDate);
|
|
264
|
+
if (!aDate && bDate) return -1;
|
|
265
|
+
if (aDate && !bDate) return 1;
|
|
266
|
+
return a.localeCompare(b);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Render an app-facing changelog that includes both released CHANGELOG.md
|
|
271
|
+
* sections and adjacent pending `changelog/*.md` entries. Unlike `release`,
|
|
272
|
+
* this is pure and non-destructive, so build/dev bundles can show current
|
|
273
|
+
* product notes without deleting the conflict-free pending files.
|
|
274
|
+
*/
|
|
275
|
+
export function mergePendingChangelog(
|
|
276
|
+
existing: string,
|
|
277
|
+
pending: PendingChangelogEntry[],
|
|
278
|
+
): string {
|
|
279
|
+
const pendingWithText = pending.filter((entry) => entry.text.trim());
|
|
280
|
+
if (pendingWithText.length === 0) return existing || CHANGELOG_HEADER;
|
|
281
|
+
|
|
282
|
+
const existingEntries = parseChangelog(existing);
|
|
283
|
+
const usedExistingIndexes = new Set<number>();
|
|
284
|
+
const pendingByTitle = new Map<string, PendingChangelogEntry[]>();
|
|
285
|
+
|
|
286
|
+
for (const entry of pendingWithText) {
|
|
287
|
+
const title = pendingSectionTitle(entry);
|
|
288
|
+
pendingByTitle.set(title, [...(pendingByTitle.get(title) ?? []), entry]);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const sections: string[] = [];
|
|
292
|
+
for (const title of [...pendingByTitle.keys()].sort(pendingSectionSort)) {
|
|
293
|
+
const body = renderReleaseBody(pendingByTitle.get(title) ?? []);
|
|
294
|
+
if (!body) continue;
|
|
295
|
+
|
|
296
|
+
const existingIndex = existingEntries.findIndex((entry, index) => {
|
|
297
|
+
if (usedExistingIndexes.has(index)) return false;
|
|
298
|
+
return entry.date === title || entry.title === title;
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
if (existingIndex === -1) {
|
|
302
|
+
sections.push(`## ${title}\n\n${body}`);
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
usedExistingIndexes.add(existingIndex);
|
|
307
|
+
const existingEntry = existingEntries[existingIndex];
|
|
308
|
+
sections.push(
|
|
309
|
+
`## ${existingEntry.title}\n\n${[body, existingEntry.body]
|
|
310
|
+
.filter(Boolean)
|
|
311
|
+
.join("\n\n")}`,
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
existingEntries.forEach((entry, index) => {
|
|
316
|
+
if (usedExistingIndexes.has(index)) return;
|
|
317
|
+
sections.push(`## ${entry.title}\n\n${entry.body}`);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
return `${changelogHeader(existing)}\n\n${sections.join("\n\n")}\n`;
|
|
321
|
+
}
|
|
322
|
+
|
|
245
323
|
export { CHANGELOG_HEADER, GROUP_LABELS };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { table, text, integer } from "../db/schema.js";
|
|
2
|
+
import { createSharesTable, ownableColumns } from "../sharing/schema.js";
|
|
3
|
+
|
|
4
|
+
export const chatThreads = table("chat_threads", {
|
|
5
|
+
id: text("id").primaryKey(),
|
|
6
|
+
title: text("title").notNull().default(""),
|
|
7
|
+
preview: text("preview").notNull().default(""),
|
|
8
|
+
threadData: text("thread_data").notNull().default("{}"),
|
|
9
|
+
messageCount: integer("message_count").notNull().default(0),
|
|
10
|
+
createdAt: integer("created_at").notNull(),
|
|
11
|
+
updatedAt: integer("updated_at").notNull(),
|
|
12
|
+
scopeType: text("scope_type"),
|
|
13
|
+
scopeId: text("scope_id"),
|
|
14
|
+
scopeLabel: text("scope_label"),
|
|
15
|
+
pinnedAt: integer("pinned_at"),
|
|
16
|
+
archivedAt: integer("archived_at"),
|
|
17
|
+
shareTokenHash: text("share_token_hash"),
|
|
18
|
+
...ownableColumns(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const chatThreadShares = createSharesTable("chat_thread_shares");
|
|
22
|
+
|
|
23
|
+
export const CHAT_THREAD_SHARES_CREATE_SQL = `CREATE TABLE IF NOT EXISTS chat_thread_shares (
|
|
24
|
+
id TEXT PRIMARY KEY,
|
|
25
|
+
resource_id TEXT NOT NULL,
|
|
26
|
+
principal_type TEXT NOT NULL,
|
|
27
|
+
principal_id TEXT NOT NULL,
|
|
28
|
+
role TEXT NOT NULL DEFAULT 'viewer',
|
|
29
|
+
created_by TEXT NOT NULL,
|
|
30
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
31
|
+
)`;
|
|
32
|
+
|
|
33
|
+
export const CHAT_THREAD_SHARES_CREATE_SQL_PG = `CREATE TABLE IF NOT EXISTS chat_thread_shares (
|
|
34
|
+
id TEXT PRIMARY KEY,
|
|
35
|
+
resource_id TEXT NOT NULL,
|
|
36
|
+
principal_type TEXT NOT NULL,
|
|
37
|
+
principal_id TEXT NOT NULL,
|
|
38
|
+
role TEXT NOT NULL DEFAULT 'viewer',
|
|
39
|
+
created_by TEXT NOT NULL,
|
|
40
|
+
created_at TEXT NOT NULL DEFAULT now()
|
|
41
|
+
)`;
|
|
42
|
+
|
|
43
|
+
export const CHAT_THREAD_SHARES_RESOURCE_INDEX_SQL = `CREATE INDEX IF NOT EXISTS chat_thread_shares_resource_idx ON chat_thread_shares (resource_id)`;
|
|
@@ -6,13 +6,25 @@ import {
|
|
|
6
6
|
normalizeThreadTitle,
|
|
7
7
|
} from "../agent/thread-data-builder.js";
|
|
8
8
|
import { getDbExec, intType, isPostgres } from "../db/client.js";
|
|
9
|
+
import { createGetDb } from "../db/create-get-db.js";
|
|
9
10
|
import {
|
|
10
11
|
ensureColumnExists,
|
|
11
12
|
ensureIndexExists,
|
|
12
13
|
ensureTableExists,
|
|
13
14
|
} from "../db/ddl-guard.js";
|
|
14
15
|
import { widenIntColumnsToBigInt } from "../db/widen-columns.js";
|
|
16
|
+
import { getRequestOrgId } from "../server/request-context.js";
|
|
17
|
+
import { resolveAccess, type AccessContext } from "../sharing/access.js";
|
|
18
|
+
import { registerShareableResource } from "../sharing/registry.js";
|
|
19
|
+
import { roleSatisfies, type ShareRole } from "../sharing/schema.js";
|
|
15
20
|
import { emitChatThreadChange } from "./emitter.js";
|
|
21
|
+
import {
|
|
22
|
+
chatThreads,
|
|
23
|
+
chatThreadShares,
|
|
24
|
+
CHAT_THREAD_SHARES_CREATE_SQL,
|
|
25
|
+
CHAT_THREAD_SHARES_CREATE_SQL_PG,
|
|
26
|
+
CHAT_THREAD_SHARES_RESOURCE_INDEX_SQL,
|
|
27
|
+
} from "./schema.js";
|
|
16
28
|
|
|
17
29
|
let _initPromise: Promise<void> | undefined;
|
|
18
30
|
|
|
@@ -33,6 +45,7 @@ let _initPromise: Promise<void> | undefined;
|
|
|
33
45
|
const _threadDataLocks = new Map<string, Promise<unknown>>();
|
|
34
46
|
const DEFAULT_THREAD_DATA_UPDATE_ATTEMPTS = 12;
|
|
35
47
|
const THREAD_DATA_CONFLICT_BACKOFF_MS = 25;
|
|
48
|
+
const getChatThreadsDb = createGetDb({ chatThreads, chatThreadShares });
|
|
36
49
|
|
|
37
50
|
export function withThreadDataLock<T>(
|
|
38
51
|
threadId: string,
|
|
@@ -73,7 +86,9 @@ async function ensureTable(): Promise<void> {
|
|
|
73
86
|
scope_label TEXT,
|
|
74
87
|
pinned_at ${intType()},
|
|
75
88
|
archived_at ${intType()},
|
|
76
|
-
share_token_hash TEXT
|
|
89
|
+
share_token_hash TEXT,
|
|
90
|
+
org_id TEXT,
|
|
91
|
+
visibility TEXT NOT NULL DEFAULT 'private'
|
|
77
92
|
)
|
|
78
93
|
`;
|
|
79
94
|
|
|
@@ -100,6 +115,8 @@ async function ensureTable(): Promise<void> {
|
|
|
100
115
|
["pinned_at", intType()],
|
|
101
116
|
["archived_at", intType()],
|
|
102
117
|
["share_token_hash", "TEXT"],
|
|
118
|
+
["org_id", "TEXT"],
|
|
119
|
+
["visibility", "TEXT NOT NULL DEFAULT 'private'"],
|
|
103
120
|
] as const) {
|
|
104
121
|
await ensureColumnExists(
|
|
105
122
|
"chat_threads",
|
|
@@ -107,6 +124,10 @@ async function ensureTable(): Promise<void> {
|
|
|
107
124
|
`ALTER TABLE chat_threads ADD COLUMN IF NOT EXISTS ${col} ${type}`,
|
|
108
125
|
);
|
|
109
126
|
}
|
|
127
|
+
await ensureTableExists(
|
|
128
|
+
"chat_thread_shares",
|
|
129
|
+
CHAT_THREAD_SHARES_CREATE_SQL_PG,
|
|
130
|
+
);
|
|
110
131
|
// Widen millisecond-timestamp columns that older deployments created as
|
|
111
132
|
// 32-bit `INTEGER`; on Postgres the `Date.now()` written on every turn
|
|
112
133
|
// overflows int4. No-op once widened / on fresh BIGINT databases.
|
|
@@ -134,6 +155,10 @@ async function ensureTable(): Promise<void> {
|
|
|
134
155
|
"chat_threads_share_token_idx",
|
|
135
156
|
`CREATE INDEX IF NOT EXISTS chat_threads_share_token_idx ON chat_threads (share_token_hash)`,
|
|
136
157
|
);
|
|
158
|
+
await ensureIndexExists(
|
|
159
|
+
"chat_thread_shares_resource_idx",
|
|
160
|
+
CHAT_THREAD_SHARES_RESOURCE_INDEX_SQL,
|
|
161
|
+
);
|
|
137
162
|
// One-time backfill of message_count for legacy rows written before
|
|
138
163
|
// the column was maintained.
|
|
139
164
|
await backfillLegacyMessageCounts(client);
|
|
@@ -153,6 +178,8 @@ async function ensureTable(): Promise<void> {
|
|
|
153
178
|
["pinned_at", intType()],
|
|
154
179
|
["archived_at", intType()],
|
|
155
180
|
["share_token_hash", "TEXT"],
|
|
181
|
+
["org_id", "TEXT"],
|
|
182
|
+
["visibility", "TEXT NOT NULL DEFAULT 'private'"],
|
|
156
183
|
] as const) {
|
|
157
184
|
try {
|
|
158
185
|
await client.execute(
|
|
@@ -162,6 +189,11 @@ async function ensureTable(): Promise<void> {
|
|
|
162
189
|
// Column already exists.
|
|
163
190
|
}
|
|
164
191
|
}
|
|
192
|
+
try {
|
|
193
|
+
await client.execute(CHAT_THREAD_SHARES_CREATE_SQL);
|
|
194
|
+
} catch {
|
|
195
|
+
// Table already exists.
|
|
196
|
+
}
|
|
165
197
|
// Widen millisecond-timestamp columns that older deployments created as
|
|
166
198
|
// 32-bit `INTEGER`; on Postgres the `Date.now()` written on every turn
|
|
167
199
|
// overflows int4. No-op once widened / on fresh BIGINT databases.
|
|
@@ -181,6 +213,7 @@ async function ensureTable(): Promise<void> {
|
|
|
181
213
|
`CREATE INDEX IF NOT EXISTS chat_threads_owner_updated_idx ON chat_threads (owner_email, updated_at)`,
|
|
182
214
|
`CREATE INDEX IF NOT EXISTS chat_threads_scope_updated_idx ON chat_threads (scope_type, scope_id, updated_at)`,
|
|
183
215
|
`CREATE INDEX IF NOT EXISTS chat_threads_share_token_idx ON chat_threads (share_token_hash)`,
|
|
216
|
+
CHAT_THREAD_SHARES_RESOURCE_INDEX_SQL,
|
|
184
217
|
]) {
|
|
185
218
|
try {
|
|
186
219
|
await client.execute(ddl);
|
|
@@ -261,6 +294,8 @@ export interface ChatThread {
|
|
|
261
294
|
scope: ChatThreadScope | null;
|
|
262
295
|
pinnedAt: number | null;
|
|
263
296
|
archivedAt: number | null;
|
|
297
|
+
orgId: string | null;
|
|
298
|
+
visibility: "private" | "org" | "public";
|
|
264
299
|
}
|
|
265
300
|
|
|
266
301
|
export interface ChatThreadSummary {
|
|
@@ -273,6 +308,8 @@ export interface ChatThreadSummary {
|
|
|
273
308
|
scope: ChatThreadScope | null;
|
|
274
309
|
pinnedAt: number | null;
|
|
275
310
|
archivedAt: number | null;
|
|
311
|
+
orgId: string | null;
|
|
312
|
+
visibility: "private" | "org" | "public";
|
|
276
313
|
}
|
|
277
314
|
|
|
278
315
|
export interface ForkThreadSourceSnapshot {
|
|
@@ -297,6 +334,10 @@ function readNullableNumber(value: unknown): number | null {
|
|
|
297
334
|
return Number.isFinite(n) && n > 0 ? n : null;
|
|
298
335
|
}
|
|
299
336
|
|
|
337
|
+
function readVisibility(value: unknown): "private" | "org" | "public" {
|
|
338
|
+
return value === "org" || value === "public" ? value : "private";
|
|
339
|
+
}
|
|
340
|
+
|
|
300
341
|
function normalizeForkSourceSnapshot(
|
|
301
342
|
source: ForkThreadSourceSnapshot | null | undefined,
|
|
302
343
|
): {
|
|
@@ -359,6 +400,8 @@ function rowToThread(r: Record<string, unknown>): ChatThread {
|
|
|
359
400
|
scope: readScope(r),
|
|
360
401
|
pinnedAt: readNullableNumber(r.pinned_at),
|
|
361
402
|
archivedAt: readNullableNumber(r.archived_at),
|
|
403
|
+
orgId: (r.org_id as string | null | undefined) ?? null,
|
|
404
|
+
visibility: readVisibility(r.visibility),
|
|
362
405
|
};
|
|
363
406
|
}
|
|
364
407
|
|
|
@@ -378,6 +421,8 @@ function rowToSummary(r: Record<string, unknown>): ChatThreadSummary | null {
|
|
|
378
421
|
scope: readScope(r),
|
|
379
422
|
pinnedAt: readNullableNumber(r.pinned_at),
|
|
380
423
|
archivedAt: readNullableNumber(r.archived_at),
|
|
424
|
+
orgId: (r.org_id as string | null | undefined) ?? null,
|
|
425
|
+
visibility: readVisibility(r.visibility),
|
|
381
426
|
};
|
|
382
427
|
}
|
|
383
428
|
|
|
@@ -391,9 +436,10 @@ export async function createThread(
|
|
|
391
436
|
const now = Date.now();
|
|
392
437
|
const title = opts?.title ?? "";
|
|
393
438
|
const scope = opts?.scope ?? null;
|
|
439
|
+
const orgId = getRequestOrgId() ?? null;
|
|
394
440
|
|
|
395
441
|
await client.execute({
|
|
396
|
-
sql: `INSERT INTO chat_threads (id, owner_email, title, preview, thread_data, message_count, created_at, updated_at, scope_type, scope_id, scope_label) VALUES (?, ?, ?, '', '{}', 0, ?, ?, ?, ?,
|
|
442
|
+
sql: `INSERT INTO chat_threads (id, owner_email, title, preview, thread_data, message_count, created_at, updated_at, scope_type, scope_id, scope_label, org_id, visibility) VALUES (?, ?, ?, '', '{}', 0, ?, ?, ?, ?, ?, ?, 'private')`,
|
|
397
443
|
args: [
|
|
398
444
|
id,
|
|
399
445
|
ownerEmail,
|
|
@@ -403,6 +449,7 @@ export async function createThread(
|
|
|
403
449
|
scope?.type ?? null,
|
|
404
450
|
scope?.id ?? null,
|
|
405
451
|
scope?.label ?? null,
|
|
452
|
+
orgId,
|
|
406
453
|
],
|
|
407
454
|
});
|
|
408
455
|
|
|
@@ -418,10 +465,12 @@ export async function createThread(
|
|
|
418
465
|
scope,
|
|
419
466
|
pinnedAt: null,
|
|
420
467
|
archivedAt: null,
|
|
468
|
+
orgId,
|
|
469
|
+
visibility: "private",
|
|
421
470
|
};
|
|
422
471
|
}
|
|
423
472
|
|
|
424
|
-
const THREAD_COLUMNS = `id, owner_email, title, preview, thread_data, message_count, created_at, updated_at, scope_type, scope_id, scope_label, pinned_at, archived_at`;
|
|
473
|
+
const THREAD_COLUMNS = `id, owner_email, title, preview, thread_data, message_count, created_at, updated_at, scope_type, scope_id, scope_label, pinned_at, archived_at, org_id, visibility`;
|
|
425
474
|
// The list/summary path deliberately omits `thread_data`: it is the full
|
|
426
475
|
// message-history JSON blob and selecting it for every row turns "open the
|
|
427
476
|
// sidebar" into "download every conversation". The summary derives nothing
|
|
@@ -429,7 +478,41 @@ const THREAD_COLUMNS = `id, owner_email, title, preview, thread_data, message_co
|
|
|
429
478
|
// (message_count is maintained on write and backfilled for legacy rows at
|
|
430
479
|
// bootstrap). The detail path (`THREAD_COLUMNS` / `getThread`) still returns
|
|
431
480
|
// the full blob.
|
|
432
|
-
const SUMMARY_COLUMNS = `id, title, preview, message_count, created_at, updated_at, scope_type, scope_id, scope_label, pinned_at, archived_at`;
|
|
481
|
+
const SUMMARY_COLUMNS = `id, title, preview, message_count, created_at, updated_at, scope_type, scope_id, scope_label, pinned_at, archived_at, org_id, visibility`;
|
|
482
|
+
|
|
483
|
+
export function registerChatThreadsShareable(): void {
|
|
484
|
+
registerShareableResource({
|
|
485
|
+
type: "chat_thread",
|
|
486
|
+
resourceTable: chatThreads,
|
|
487
|
+
sharesTable: chatThreadShares,
|
|
488
|
+
displayName: "Chat",
|
|
489
|
+
titleColumn: "title",
|
|
490
|
+
getResourcePath: (thread) =>
|
|
491
|
+
`/?thread=${encodeURIComponent(String(thread.id ?? ""))}`,
|
|
492
|
+
getDb: () => getChatThreadsDb(),
|
|
493
|
+
allowPublic: false,
|
|
494
|
+
ownerAccessIgnoresOrg: true,
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
export async function ensureChatThreadTables(): Promise<void> {
|
|
499
|
+
await ensureTable();
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
export async function resolveThreadAccess(
|
|
503
|
+
userEmail: string | null | undefined,
|
|
504
|
+
threadId: string | null | undefined,
|
|
505
|
+
minRole: ShareRole | "owner" = "viewer",
|
|
506
|
+
ctx: Omit<AccessContext, "userEmail"> = {},
|
|
507
|
+
): Promise<ChatThread | null> {
|
|
508
|
+
if (!userEmail || !threadId) return null;
|
|
509
|
+
const access = await resolveAccess("chat_thread", threadId, {
|
|
510
|
+
userEmail,
|
|
511
|
+
orgId: ctx.orgId,
|
|
512
|
+
});
|
|
513
|
+
if (!access || !roleSatisfies(access.role, minRole)) return null;
|
|
514
|
+
return await getThread(threadId);
|
|
515
|
+
}
|
|
433
516
|
|
|
434
517
|
export async function getThread(id: string): Promise<ChatThread | null> {
|
|
435
518
|
await ensureTable();
|
|
@@ -445,7 +528,11 @@ export async function getThread(id: string): Promise<ChatThread | null> {
|
|
|
445
528
|
export async function forkThread(
|
|
446
529
|
sourceId: string,
|
|
447
530
|
ownerEmail: string,
|
|
448
|
-
opts?: {
|
|
531
|
+
opts?: {
|
|
532
|
+
id?: string;
|
|
533
|
+
source?: ForkThreadSourceSnapshot | null;
|
|
534
|
+
sourceAccessGranted?: boolean;
|
|
535
|
+
},
|
|
449
536
|
): Promise<ChatThread | null> {
|
|
450
537
|
const snapshot = normalizeForkSourceSnapshot(opts?.source);
|
|
451
538
|
let source = await getThread(sourceId);
|
|
@@ -494,13 +581,19 @@ export async function forkThread(
|
|
|
494
581
|
messageCount: snapshot.messageCount,
|
|
495
582
|
};
|
|
496
583
|
}
|
|
497
|
-
if (
|
|
584
|
+
if (
|
|
585
|
+
!source ||
|
|
586
|
+
(!opts?.sourceAccessGranted && source.ownerEmail !== ownerEmail)
|
|
587
|
+
) {
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
498
590
|
const id = opts?.id ?? generateId();
|
|
499
591
|
const now = Date.now();
|
|
500
592
|
const title = source.title ? `${source.title} (fork)` : "";
|
|
501
593
|
const client = getDbExec();
|
|
594
|
+
const orgId = getRequestOrgId() ?? null;
|
|
502
595
|
await client.execute({
|
|
503
|
-
sql: `INSERT INTO chat_threads (id, owner_email, title, preview, thread_data, message_count, created_at, updated_at, scope_type, scope_id, scope_label) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
|
596
|
+
sql: `INSERT INTO chat_threads (id, owner_email, title, preview, thread_data, message_count, created_at, updated_at, scope_type, scope_id, scope_label, org_id, visibility) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'private')`,
|
|
504
597
|
args: [
|
|
505
598
|
id,
|
|
506
599
|
ownerEmail,
|
|
@@ -513,6 +606,7 @@ export async function forkThread(
|
|
|
513
606
|
source.scope?.type ?? null,
|
|
514
607
|
source.scope?.id ?? null,
|
|
515
608
|
source.scope?.label ?? null,
|
|
609
|
+
orgId,
|
|
516
610
|
],
|
|
517
611
|
});
|
|
518
612
|
return {
|
|
@@ -527,6 +621,8 @@ export async function forkThread(
|
|
|
527
621
|
scope: source.scope,
|
|
528
622
|
pinnedAt: null,
|
|
529
623
|
archivedAt: null,
|
|
624
|
+
orgId,
|
|
625
|
+
visibility: "private",
|
|
530
626
|
};
|
|
531
627
|
}
|
|
532
628
|
|
|
@@ -542,6 +638,28 @@ export interface ListThreadsOptions {
|
|
|
542
638
|
scope?: { type: string; id: string };
|
|
543
639
|
/** When true, returns only threads with no scope (general chats). */
|
|
544
640
|
unscopedOnly?: boolean;
|
|
641
|
+
orgId?: string | null;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function chatThreadAccessSql(
|
|
645
|
+
userEmail: string,
|
|
646
|
+
orgId: string | null | undefined,
|
|
647
|
+
): { sql: string; args: (string | number)[] } {
|
|
648
|
+
const normalizedEmail = userEmail.trim().toLowerCase();
|
|
649
|
+
const clauses = [
|
|
650
|
+
`LOWER(owner_email) = ?`,
|
|
651
|
+
`EXISTS (SELECT 1 FROM chat_thread_shares WHERE chat_thread_shares.resource_id = chat_threads.id AND chat_thread_shares.principal_type = 'user' AND LOWER(chat_thread_shares.principal_id) = ?)`,
|
|
652
|
+
];
|
|
653
|
+
const args: (string | number)[] = [normalizedEmail, normalizedEmail];
|
|
654
|
+
if (orgId) {
|
|
655
|
+
clauses.push(`(visibility = 'org' AND org_id = ?)`);
|
|
656
|
+
args.push(orgId);
|
|
657
|
+
clauses.push(
|
|
658
|
+
`EXISTS (SELECT 1 FROM chat_thread_shares WHERE chat_thread_shares.resource_id = chat_threads.id AND chat_thread_shares.principal_type = 'org' AND chat_thread_shares.principal_id = ?)`,
|
|
659
|
+
);
|
|
660
|
+
args.push(orgId);
|
|
661
|
+
}
|
|
662
|
+
return { sql: `(${clauses.join(" OR ")})`, args };
|
|
545
663
|
}
|
|
546
664
|
|
|
547
665
|
export async function listThreads(
|
|
@@ -562,8 +680,12 @@ export async function listThreads(
|
|
|
562
680
|
// maintained on every write and backfilled for legacy rows at bootstrap,
|
|
563
681
|
// so the old `OR thread_data LIKE '%"messages"%'` substring scan over the
|
|
564
682
|
// full blob is no longer needed here.
|
|
565
|
-
const
|
|
566
|
-
|
|
683
|
+
const access = chatThreadAccessSql(
|
|
684
|
+
ownerEmail,
|
|
685
|
+
opts.orgId ?? getRequestOrgId(),
|
|
686
|
+
);
|
|
687
|
+
const filters: string[] = [access.sql, `message_count > 0`];
|
|
688
|
+
const args: (string | number)[] = [...access.args];
|
|
567
689
|
if (opts.scope) {
|
|
568
690
|
filters.push(`scope_type = ? AND scope_id = ?`);
|
|
569
691
|
args.push(opts.scope.type, opts.scope.id);
|
|
@@ -588,7 +710,7 @@ export async function searchThreads(
|
|
|
588
710
|
ownerEmail: string,
|
|
589
711
|
query: string,
|
|
590
712
|
limit = 50,
|
|
591
|
-
options: { scope?: { type: string; id: string } } = {},
|
|
713
|
+
options: { scope?: { type: string; id: string }; orgId?: string | null } = {},
|
|
592
714
|
): Promise<ChatThreadSummary[]> {
|
|
593
715
|
await ensureTable();
|
|
594
716
|
const client = getDbExec();
|
|
@@ -596,12 +718,16 @@ export async function searchThreads(
|
|
|
596
718
|
// The count-guard uses the maintained/backfilled `message_count` column
|
|
597
719
|
// (same as listThreads). The content match still scans `thread_data` —
|
|
598
720
|
// search legitimately needs to look inside message history.
|
|
721
|
+
const access = chatThreadAccessSql(
|
|
722
|
+
ownerEmail,
|
|
723
|
+
options.orgId ?? getRequestOrgId(),
|
|
724
|
+
);
|
|
599
725
|
const filters: string[] = [
|
|
600
|
-
|
|
726
|
+
access.sql,
|
|
601
727
|
`message_count > 0`,
|
|
602
728
|
`(title LIKE ? ESCAPE '!' OR preview LIKE ? ESCAPE '!' OR thread_data LIKE ? ESCAPE '!')`,
|
|
603
729
|
];
|
|
604
|
-
const args: (string | number)[] = [
|
|
730
|
+
const args: (string | number)[] = [...access.args, pattern, pattern, pattern];
|
|
605
731
|
if (options.scope) {
|
|
606
732
|
filters.push(`scope_type = ? AND scope_id = ?`);
|
|
607
733
|
args.push(options.scope.type, options.scope.id);
|
|
@@ -1137,6 +1263,12 @@ export async function deleteThread(id: string): Promise<boolean> {
|
|
|
1137
1263
|
args: [id],
|
|
1138
1264
|
});
|
|
1139
1265
|
if (result.rowsAffected > 0) {
|
|
1266
|
+
await client
|
|
1267
|
+
.execute({
|
|
1268
|
+
sql: `DELETE FROM chat_thread_shares WHERE resource_id = ?`,
|
|
1269
|
+
args: [id],
|
|
1270
|
+
})
|
|
1271
|
+
.catch(() => {});
|
|
1140
1272
|
emitChatThreadChange(id);
|
|
1141
1273
|
return true;
|
|
1142
1274
|
}
|
|
@@ -83,6 +83,7 @@ const DEFAULT_PROXY_RESPONSE_TIMEOUT_MS = 5_000;
|
|
|
83
83
|
const DEFAULT_PROXY_NON_HTML_RESPONSE_TIMEOUT_MS = 120_000;
|
|
84
84
|
const APP_OUTPUT_TAIL_BYTES = 8_000;
|
|
85
85
|
const POLLING_WATCH_INTERVAL_MS = "1000";
|
|
86
|
+
const reportedDiscoverAppsReadFailures = new Set<string>();
|
|
86
87
|
const STARTING_APP_RESPONSE_HEADERS: http.OutgoingHttpHeaders = {
|
|
87
88
|
"content-type": "text/html; charset=utf-8",
|
|
88
89
|
"cache-control": "no-store, no-cache, max-age=0, must-revalidate",
|
|
@@ -287,6 +288,23 @@ function readJson(file: string): any {
|
|
|
287
288
|
}
|
|
288
289
|
}
|
|
289
290
|
|
|
291
|
+
function shouldReportDiscoverAppsReadFailure(
|
|
292
|
+
appsDir: string,
|
|
293
|
+
code: string | undefined,
|
|
294
|
+
): boolean {
|
|
295
|
+
if (code === "ENOENT") return false;
|
|
296
|
+
const key = `${appsDir}:${code ?? "unknown"}`;
|
|
297
|
+
if (reportedDiscoverAppsReadFailures.has(key)) return false;
|
|
298
|
+
reportedDiscoverAppsReadFailures.add(key);
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function shouldCaptureDiscoverAppsReadFailure(
|
|
303
|
+
code: string | undefined,
|
|
304
|
+
): boolean {
|
|
305
|
+
return code !== "EACCES" && code !== "EPERM";
|
|
306
|
+
}
|
|
307
|
+
|
|
290
308
|
function discoverApps(appsDir: string, appPortStart: number): WorkspaceApp[] {
|
|
291
309
|
if (!fs.existsSync(appsDir)) return [];
|
|
292
310
|
// existsSync -> readdirSync is a TOCTOU race. Treat ENOENT as "no apps
|
|
@@ -296,15 +314,17 @@ function discoverApps(appsDir: string, appPortStart: number): WorkspaceApp[] {
|
|
|
296
314
|
entries = fs.readdirSync(appsDir, { withFileTypes: true });
|
|
297
315
|
} catch (err) {
|
|
298
316
|
const code = (err as NodeJS.ErrnoException).code;
|
|
299
|
-
if (code
|
|
317
|
+
if (shouldReportDiscoverAppsReadFailure(appsDir, code)) {
|
|
300
318
|
console.warn(
|
|
301
319
|
`[workspace] Could not read ${appsDir} (${code ?? "unknown"}): ` +
|
|
302
320
|
`${(err as Error).message}`,
|
|
303
321
|
);
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
322
|
+
if (shouldCaptureDiscoverAppsReadFailure(code)) {
|
|
323
|
+
Sentry.captureException(err, {
|
|
324
|
+
tags: { handled: "dev-discover-readdir" },
|
|
325
|
+
level: "warning",
|
|
326
|
+
});
|
|
327
|
+
}
|
|
308
328
|
}
|
|
309
329
|
return [];
|
|
310
330
|
}
|