@agent-native/core 0.92.0 → 0.92.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +20 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/application-state/store.ts +12 -1
- package/corpus/core/src/cli/sync-builder-starter-manifest.ts +29 -1
- package/corpus/core/src/client/AssistantChat.tsx +27 -14
- package/corpus/core/src/client/PoweredByBadge.tsx +1 -8
- package/corpus/core/src/client/agent-chat-adapter.ts +37 -10
- package/corpus/core/src/client/chat/widgets/DataTableWidget.tsx +52 -1
- package/corpus/core/src/client/db-admin/TableEditor.tsx +49 -0
- package/corpus/core/src/client/db-admin/export-utils.ts +13 -4
- package/corpus/core/src/client/db-admin/useAgentSync.ts +72 -0
- package/corpus/core/src/client/error-capture.ts +69 -7
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +5 -1
- package/corpus/core/src/client/extensions/ExtensionViewer.tsx +53 -8
- package/corpus/core/src/client/extensions/InlineExtensionFrame.tsx +5 -1
- package/corpus/core/src/client/extensions/portable-extension.ts +1 -0
- package/corpus/core/src/client/org/OrgSwitcher.tsx +12 -9
- package/corpus/core/src/client/org/TeamPage.tsx +77 -71
- package/corpus/core/src/client/settings/SettingsPanel.tsx +205 -52
- package/corpus/core/src/client/settings/SettingsSection.tsx +8 -1
- package/corpus/core/src/client/settings/SettingsTabsPage.tsx +25 -9
- package/corpus/core/src/db-admin/agent-tools.ts +8 -2
- package/corpus/core/src/db-admin/operations.ts +116 -4
- package/corpus/core/src/db-admin/routes.ts +1 -0
- package/corpus/core/src/db-admin/types.ts +4 -0
- package/corpus/core/src/extensions/html-shell.ts +5 -4
- package/corpus/core/src/extensions/routes.ts +10 -0
- package/corpus/core/src/navigation/index.ts +1 -1
- package/corpus/core/src/notifications/channels.ts +1 -22
- package/corpus/core/src/resources/handlers.ts +10 -8
- package/corpus/core/src/server/poll.ts +293 -8
- package/corpus/core/src/styles/agent-native.css +27 -0
- package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/core/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +7 -0
- package/corpus/core/src/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/core/src/templates/default/AGENTS.md +4 -2
- package/corpus/core/src/templates/headless/AGENTS.md +4 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/core/src/templates/workspace-core/AGENTS.md +7 -1
- package/corpus/core/src/templates/workspace-root/AGENTS.md +7 -1
- package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +10 -0
- package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/analytics/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/analytics/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/templates/analytics/AGENTS.md +33 -14
- package/corpus/templates/analytics/actions/capture-test-error.ts +4 -0
- package/corpus/templates/analytics/actions/get-analytics-alert-rule-defaults.ts +23 -0
- package/corpus/templates/analytics/actions/get-error-issue.ts +1 -1
- package/corpus/templates/analytics/actions/list-analysis-revisions.ts +40 -0
- package/corpus/templates/analytics/actions/list-dashboard-revisions.ts +40 -0
- package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +299 -0
- package/corpus/templates/analytics/actions/navigate.ts +4 -2
- package/corpus/templates/analytics/actions/restore-analysis-revision.ts +43 -0
- package/corpus/templates/analytics/actions/restore-dashboard-revision.ts +68 -0
- package/corpus/templates/analytics/actions/save-analytics-alert-rule.ts +14 -0
- package/corpus/templates/analytics/actions/save-monitor.ts +1 -1
- package/corpus/templates/analytics/actions/view-screen.ts +24 -0
- package/corpus/templates/analytics/app/components/analysis/AnalysisHistoryPanel.tsx +181 -0
- package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +184 -0
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +22 -16
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +27 -21
- package/corpus/templates/analytics/app/hooks/use-analysis-revisions.ts +43 -0
- package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +110 -0
- package/corpus/templates/analytics/app/hooks/use-dashboard-revisions.ts +43 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +8 -3
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +64 -2
- package/corpus/templates/analytics/app/i18n-data.ts +783 -3
- package/corpus/templates/analytics/app/pages/Agents.tsx +359 -19
- package/corpus/templates/analytics/app/pages/Settings.tsx +3 -2
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +34 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +28 -0
- package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +18 -1
- package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +7 -10
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueDetail.tsx +479 -23
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +0 -9
- package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +11 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/types.ts +9 -1
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +6 -3
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +26 -30
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +9 -99
- package/corpus/templates/analytics/app/pages/settings/AlertRulesSettingsCard.tsx +262 -104
- package/corpus/templates/analytics/app/routes/team.tsx +1 -1
- package/corpus/templates/analytics/changelog/2026-07-08-admins-can-audit-dashboard-usage-ownership-and-cleanup-signa.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-agent-monitoring-stays-available-to-non-admins.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-alert-emails-now-show-the-message-without-raw-metadata-json.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-alert-rules-are-easier-to-scan-expand-and-edit-from-settings.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-analytics-alert-forms-remember-last-email-recipients.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-analytics-alert-rules-can-now-use-per-rule-slack-and-webhook.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-dashboard-history-and-chat-context.md +5 -0
- package/corpus/templates/analytics/changelog/2026-07-08-dashboard-usage-now-counts-explorer-dashboard-traffic.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-demo-mode-session-emails-are-filtered-and-anonymized.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-error-issue-detail-adds-stack-traces-and-frequency-bars.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-error-issue-detail-now-shows-the-latest-occurrence-message-a.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-monitoring-errors-only-show-test-action-when-empty.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-production-session-replay-now-requires-private-blob-storage-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-shared-extension-links-now-show-a-clear-message-when-you-do-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-team-settings-show-access-controls-next-to-member-lists.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-uptime-checks-no-longer-count-ssrf-setup-time-against-the-re.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-uptime-checks-reuse-one-keep-alive-connection-so-recorded-la.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-uptime-monitors-now-confirm-transient-timeout-failures-befor.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-uptime-monitors-now-use-a-10-second-request-timeout-by-defau.md +6 -0
- package/corpus/templates/analytics/docs/uptime-monitoring.md +30 -18
- package/corpus/templates/analytics/server/db/schema-monitoring.ts +1 -1
- package/corpus/templates/analytics/server/db/schema.ts +56 -0
- package/corpus/templates/analytics/server/lib/analytics-alerts.ts +92 -0
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +334 -5
- package/corpus/templates/analytics/server/lib/error-capture.ts +231 -36
- package/corpus/templates/analytics/server/lib/session-replay.ts +114 -8
- package/corpus/templates/analytics/server/lib/uptime-monitors.ts +244 -33
- package/corpus/templates/analytics/server/plugins/db.ts +112 -2
- package/corpus/templates/analytics/server/routes/api/dashboard-agent-context.json.get.ts +1 -0
- package/corpus/templates/assets/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/assets/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/assets/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/templates/assets/AGENTS.md +4 -0
- package/corpus/templates/assets/app/routes/settings.tsx +1 -1
- package/corpus/templates/assets/app/routes/team.tsx +1 -1
- package/corpus/templates/brain/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/brain/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/brain/AGENTS.md +4 -0
- package/corpus/templates/brain/app/routes/team.tsx +1 -1
- package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/calendar/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/calendar/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/templates/calendar/AGENTS.md +4 -0
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +11 -2
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +21 -8
- package/corpus/templates/calendar/app/components/calendar/MonthView.tsx +7 -1
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -2
- package/corpus/templates/calendar/app/lib/popover-click-guard.ts +48 -4
- package/corpus/templates/calendar/app/pages/Settings.tsx +1 -1
- package/corpus/templates/calendar/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/calendar/changelog/2026-07-08-clicking-empty-calendar-space-closes-an-open-event-popover-b.md +6 -0
- package/corpus/templates/chat/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/chat/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/chat/AGENTS.md +4 -0
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/chat/app/routes/settings.tsx +2 -2
- package/corpus/templates/chat/app/routes/team.tsx +1 -1
- package/corpus/templates/clips/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/clips/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/clips/AGENTS.md +4 -0
- package/corpus/templates/clips/actions/finalize-recording.ts +9 -3
- package/corpus/templates/clips/actions/set-thumbnail.ts +11 -2
- package/corpus/templates/clips/app/components/meetings/canvas-editor.tsx +1 -7
- package/corpus/templates/clips/app/components/player/player-controls.tsx +21 -13
- package/corpus/templates/clips/app/components/player/video-player.tsx +30 -75
- package/corpus/templates/clips/app/i18n/ar-SA.ts +6 -5
- package/corpus/templates/clips/app/i18n/de-DE.ts +6 -6
- package/corpus/templates/clips/app/i18n/en-US.ts +6 -5
- package/corpus/templates/clips/app/i18n/es-ES.ts +6 -5
- package/corpus/templates/clips/app/i18n/fr-FR.ts +6 -6
- package/corpus/templates/clips/app/i18n/hi-IN.ts +6 -5
- package/corpus/templates/clips/app/i18n/ja-JP.ts +6 -5
- package/corpus/templates/clips/app/i18n/ko-KR.ts +6 -5
- package/corpus/templates/clips/app/i18n/pt-BR.ts +6 -5
- package/corpus/templates/clips/app/i18n/zh-CN.ts +6 -5
- package/corpus/templates/clips/app/i18n/zh-TW.ts +6 -5
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +51 -118
- package/corpus/templates/clips/changelog/2026-07-08-hosted-clip-uploads-now-clear-failed-buffered-chunks.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-hosted-recording-uploads-now-avoid-sql-chunk-storage.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-meeting-recaps-now-keep-summaries-action-items-and-transcrip.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-video-playback-controls-now-match-loom-style-5-second-skips-.md +6 -0
- package/corpus/templates/clips/server/lib/recording-upload-state.ts +63 -0
- package/corpus/templates/clips/server/lib/video-storage.ts +4 -0
- package/corpus/templates/clips/server/routes/api/recordings/[recordingId]/thumbnail.post.ts +19 -13
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +40 -1
- package/corpus/templates/content/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/content/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/content/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/templates/content/AGENTS.md +4 -0
- package/corpus/templates/content/app/routes/_app.settings.tsx +2 -2
- package/corpus/templates/content/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/design/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/design/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/design/AGENTS.md +4 -0
- package/corpus/templates/design/actions/take-design-screenshot.ts +12 -9
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +57 -13
- package/corpus/templates/design/app/routes/team.tsx +1 -1
- package/corpus/templates/design/changelog/2026-07-08-local-images-added-to-designs-now-upload-to-file-storage-ins.md +6 -0
- package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/dispatch/AGENTS.md +4 -0
- package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/dispatch/app/routes/settings.tsx +2 -2
- package/corpus/templates/dispatch/app/routes/team.tsx +1 -1
- package/corpus/templates/forms/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/forms/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/forms/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/templates/forms/AGENTS.md +4 -0
- package/corpus/templates/forms/app/routes/_app.settings.tsx +2 -2
- package/corpus/templates/forms/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/forms/shared/navigation.ts +1 -1
- package/corpus/templates/macros/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/macros/AGENTS.md +4 -0
- package/corpus/templates/macros/app/routes/settings.tsx +2 -2
- package/corpus/templates/macros/app/routes/team.tsx +1 -1
- package/corpus/templates/mail/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/mail/.agents/skills/email-drafts/SKILL.md +1 -1
- package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/mail/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/mail/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/templates/mail/AGENTS.md +4 -0
- package/corpus/templates/mail/changelog/2026-07-08-mail-attachments-in-hosted-environments-now-require-file-sto.md +6 -0
- package/corpus/templates/mail/server/handlers/media.ts +26 -1
- package/corpus/templates/mail/server/lib/outgoing-email.ts +24 -1
- package/corpus/templates/mail/server/lib/upload-store.ts +2 -1
- package/corpus/templates/plan/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/plan/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/plan/AGENTS.md +4 -0
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/plan/app/routes/settings.tsx +2 -2
- package/corpus/templates/plan/app/routes/team.tsx +1 -1
- package/corpus/templates/plan/changelog/2026-07-08-hosted-plan-images-now-require-connected-storage.md +6 -0
- package/corpus/templates/plan/server/lib/plan-assets.ts +33 -4
- package/corpus/templates/slides/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/slides/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/slides/AGENTS.md +4 -0
- package/corpus/templates/slides/actions/generate-image-api.ts +15 -3
- package/corpus/templates/slides/app/routes/settings.tsx +2 -2
- package/corpus/templates/slides/app/routes/team.tsx +1 -1
- package/corpus/templates/slides/changelog/2026-07-08-generated-slide-images-now-return-hosted-file-storage-urls-i.md +6 -0
- package/corpus/templates/slides/shared/api.ts +1 -1
- package/dist/application-state/store.d.ts.map +1 -1
- package/dist/application-state/store.js +8 -2
- package/dist/application-state/store.js.map +1 -1
- package/dist/cli/sync-builder-starter-manifest.d.ts.map +1 -1
- package/dist/cli/sync-builder-starter-manifest.js +24 -1
- package/dist/cli/sync-builder-starter-manifest.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +24 -13
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/PoweredByBadge.d.ts +1 -1
- package/dist/client/PoweredByBadge.d.ts.map +1 -1
- package/dist/client/PoweredByBadge.js +3 -9
- package/dist/client/PoweredByBadge.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +28 -9
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/chat/widgets/DataTableWidget.d.ts.map +1 -1
- package/dist/client/chat/widgets/DataTableWidget.js +19 -2
- package/dist/client/chat/widgets/DataTableWidget.js.map +1 -1
- package/dist/client/db-admin/TableEditor.d.ts.map +1 -1
- package/dist/client/db-admin/TableEditor.js +19 -2
- package/dist/client/db-admin/TableEditor.js.map +1 -1
- package/dist/client/db-admin/export-utils.d.ts +2 -0
- package/dist/client/db-admin/export-utils.d.ts.map +1 -1
- package/dist/client/db-admin/export-utils.js +11 -3
- package/dist/client/db-admin/export-utils.js.map +1 -1
- package/dist/client/db-admin/useAgentSync.d.ts.map +1 -1
- package/dist/client/db-admin/useAgentSync.js +63 -0
- package/dist/client/db-admin/useAgentSync.js.map +1 -1
- package/dist/client/error-capture.d.ts.map +1 -1
- package/dist/client/error-capture.js +41 -7
- package/dist/client/error-capture.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +3 -1
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +32 -5
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/extensions/InlineExtensionFrame.d.ts.map +1 -1
- package/dist/client/extensions/InlineExtensionFrame.js +3 -1
- package/dist/client/extensions/InlineExtensionFrame.js.map +1 -1
- package/dist/client/extensions/portable-extension.d.ts.map +1 -1
- package/dist/client/extensions/portable-extension.js +1 -0
- package/dist/client/extensions/portable-extension.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts +1 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +11 -6
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +5 -5
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +37 -14
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/SettingsSection.js +1 -1
- package/dist/client/settings/SettingsSection.js.map +1 -1
- package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
- package/dist/client/settings/SettingsTabsPage.js +21 -10
- package/dist/client/settings/SettingsTabsPage.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/db-admin/agent-tools.d.ts.map +1 -1
- package/dist/db-admin/agent-tools.js +7 -2
- package/dist/db-admin/agent-tools.js.map +1 -1
- package/dist/db-admin/operations.d.ts.map +1 -1
- package/dist/db-admin/operations.js +90 -4
- package/dist/db-admin/operations.js.map +1 -1
- package/dist/db-admin/routes.d.ts.map +1 -1
- package/dist/db-admin/routes.js +1 -0
- package/dist/db-admin/routes.js.map +1 -1
- package/dist/db-admin/types.d.ts +4 -0
- package/dist/db-admin/types.d.ts.map +1 -1
- package/dist/db-admin/types.js.map +1 -1
- package/dist/extensions/html-shell.d.ts +5 -4
- package/dist/extensions/html-shell.d.ts.map +1 -1
- package/dist/extensions/html-shell.js.map +1 -1
- package/dist/extensions/routes.d.ts.map +1 -1
- package/dist/extensions/routes.js +8 -0
- package/dist/extensions/routes.js.map +1 -1
- package/dist/navigation/index.d.ts +1 -1
- package/dist/navigation/index.d.ts.map +1 -1
- package/dist/navigation/index.js +1 -1
- package/dist/navigation/index.js.map +1 -1
- package/dist/notifications/channels.js +1 -17
- package/dist/notifications/channels.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +5 -0
- package/dist/resources/handlers.d.ts.map +1 -1
- package/dist/resources/handlers.js +9 -8
- package/dist/resources/handlers.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/poll.d.ts +12 -4
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +236 -9
- package/dist/server/poll.js.map +1 -1
- package/dist/styles/agent-native.css +27 -0
- package/dist/templates/default/.agents/skills/actions/SKILL.md +5 -0
- package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/default/.agents/skills/security/SKILL.md +7 -0
- package/dist/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
- package/dist/templates/default/AGENTS.md +4 -2
- package/dist/templates/headless/AGENTS.md +4 -0
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
- package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
- package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
- package/dist/templates/workspace-core/AGENTS.md +7 -1
- package/dist/templates/workspace-root/AGENTS.md +7 -1
- package/package.json +1 -1
- package/src/templates/default/.agents/skills/actions/SKILL.md +5 -0
- package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/default/.agents/skills/security/SKILL.md +7 -0
- package/src/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
- package/src/templates/default/AGENTS.md +4 -2
- package/src/templates/headless/AGENTS.md +4 -0
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
- package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
- package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
- package/src/templates/workspace-core/AGENTS.md +7 -1
- package/src/templates/workspace-root/AGENTS.md +7 -1
|
@@ -31,7 +31,7 @@ function StatusBadge({ label, tone, size, }) {
|
|
|
31
31
|
: "bg-muted text-muted-foreground"), children: label }));
|
|
32
32
|
}
|
|
33
33
|
function PageSettingsSection({ id, icon, title, subtitle, badge, required, connected, open = false, onToggle, children, }) {
|
|
34
|
-
return (_jsxs("div", { id: id, className: cn("scroll-mt-16 overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm transition-colors", open ? "border-border" : "border-border/60"), children: [_jsxs("button", { type: "button", onClick: onToggle, "aria-expanded": open, className: "flex w-full items-start justify-between gap-4 px-5 py-4 text-start transition-colors hover:bg-muted/40 sm:px-6 sm:py-5", children: [_jsxs("div", { className: "flex min-w-0 items-start gap-3", children: [_jsx("span", { className: "mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground [&>svg]:size-[18px]", children: icon }), _jsxs("span", { className: "flex min-w-0 flex-col gap-1.5", children: [_jsxs("span", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "text-base font-semibold leading-none tracking-tight text-foreground", children: title }), connected && _jsx(ConnectedDot, { size: "md" }), required && !connected && (_jsx(StatusBadge, { label: "Required", tone: "required", size: "md" })), badge && _jsx(StatusBadge, { label: badge, tone: "muted", size: "md" })] }), subtitle && (_jsx("span", { className: "text-sm leading-snug text-muted-foreground", children: subtitle }))] })] }), _jsx(IconChevronDown, { size: 18, className: cn("mt-1 shrink-0 text-muted-foreground transition-transform", open && "rotate-180") })] }), open && (_jsx("div", { className: "border-t border-border/60 px-5 pb-5 pt-5 sm:px-6 sm:pb-6", children: children }))] }));
|
|
34
|
+
return (_jsxs("div", { id: id, className: cn("scroll-mt-16 overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm transition-colors", open ? "border-border" : "border-border/60"), children: [_jsxs("button", { type: "button", onClick: onToggle, "aria-expanded": open, className: "flex w-full items-start justify-between gap-4 px-5 py-4 text-start transition-colors hover:bg-muted/40 sm:px-6 sm:py-5", children: [_jsxs("div", { className: "flex min-w-0 items-start gap-3", children: [_jsx("span", { className: "mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground [&>svg]:size-[18px]", children: icon }), _jsxs("span", { className: "flex min-w-0 flex-col gap-1.5", children: [_jsxs("span", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "text-base font-semibold leading-none tracking-tight text-foreground", children: title }), connected && _jsx(ConnectedDot, { size: "md" }), required && !connected && (_jsx(StatusBadge, { label: "Required", tone: "required", size: "md" })), badge && _jsx(StatusBadge, { label: badge, tone: "muted", size: "md" })] }), subtitle && (_jsx("span", { className: "text-sm leading-snug text-muted-foreground", children: subtitle }))] })] }), _jsx(IconChevronDown, { size: 18, className: cn("mt-1 shrink-0 text-muted-foreground transition-transform", open && "rotate-180") })] }), open && (_jsx("div", { "data-agent-native-settings-page": "", className: "border-t border-border/60 px-5 pb-5 pt-5 sm:px-6 sm:pb-6", children: children }))] }));
|
|
35
35
|
}
|
|
36
36
|
function SidebarSettingsSection({ id, icon, title, subtitle, badge, required, connected, open = false, onToggle, children, }) {
|
|
37
37
|
return (_jsxs("div", { id: id, className: "rounded-lg border border-border bg-background/50", children: [_jsxs("button", { type: "button", onClick: onToggle, className: "flex w-full cursor-pointer items-center justify-between px-3 py-2.5 text-start rounded-lg hover:bg-accent/40 transition-colors", children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx("span", { className: "shrink-0 text-muted-foreground", children: icon }), _jsx("span", { className: "text-[12px] font-medium text-foreground truncate", children: title }), connected && _jsx(ConnectedDot, { size: "sm" }), required && !connected && (_jsx(StatusBadge, { label: "Required", tone: "muted", size: "sm" })), badge && _jsx(StatusBadge, { label: badge, tone: "muted", size: "sm" })] }), _jsx(IconChevronDown, { size: 12, className: `shrink-0 text-muted-foreground transition-transform ${open ? "rotate-180" : ""}` })] }), open && (_jsxs("div", { className: "border-t border-border px-3 pb-3 pt-2.5", children: [subtitle && (_jsx("p", { className: "text-[10px] text-muted-foreground mb-2.5", children: subtitle })), children] }))] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsSection.js","sourceRoot":"","sources":["../../../src/client/settings/SettingsSection.tsx"],"names":[],"mappings":"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","sourcesContent":["import { IconChevronDown, IconCheck } from \"@tabler/icons-react\";\nimport { createContext, useContext, type ReactNode } from \"react\";\n\nimport { cn } from \"../utils.js\";\n\n/**\n * Where a settings section is being rendered.\n *\n * - `sidebar`: the compact agent sidebar panel (dense, small type).\n * - `page`: the full-width settings page, styled as a polished card that\n * matches the shadcn `Card` surface used by app-owned settings tabs.\n */\nexport type SettingsSurface = \"sidebar\" | \"page\";\n\nconst SettingsSurfaceContext = createContext<SettingsSurface>(\"sidebar\");\n\nexport function SettingsSurfaceProvider({\n surface,\n children,\n}: {\n surface: SettingsSurface;\n children: ReactNode;\n}) {\n return (\n <SettingsSurfaceContext.Provider value={surface}>\n {children}\n </SettingsSurfaceContext.Provider>\n );\n}\n\nexport function useSettingsSurface(): SettingsSurface {\n return useContext(SettingsSurfaceContext);\n}\n\ninterface SettingsSectionProps {\n id?: string;\n icon: ReactNode;\n title: string;\n subtitle?: string;\n badge?: string;\n required?: boolean;\n connected?: boolean;\n open?: boolean;\n onToggle?: () => void;\n children: ReactNode;\n}\n\n/**\n * Collapsible settings section. Renders as a compact row in the agent sidebar\n * and as a polished, shadcn-style card on the full settings page (so the\n * framework tabs match app-owned General/Team cards). The visual surface is\n * read from `SettingsSurfaceContext`.\n */\nexport function SettingsSection(props: SettingsSectionProps) {\n const surface = useSettingsSurface();\n return surface === \"page\" ? (\n <PageSettingsSection {...props} />\n ) : (\n <SidebarSettingsSection {...props} />\n );\n}\n\nfunction ConnectedDot({ size }: { size: \"sm\" | \"md\" }) {\n const dim = size === \"sm\" ? \"h-4 w-4\" : \"h-5 w-5\";\n const stroke = size === \"sm\" ? 3 : 2.5;\n const glyph = size === \"sm\" ? 10 : 12;\n return (\n <span\n className={cn(\n \"flex shrink-0 items-center justify-center rounded-full bg-green-500/15 text-green-500\",\n dim,\n )}\n >\n <IconCheck size={glyph} stroke={stroke} />\n </span>\n );\n}\n\nfunction StatusBadge({\n label,\n tone,\n size,\n}: {\n label: string;\n tone: \"muted\" | \"required\";\n size: \"sm\" | \"md\";\n}) {\n return (\n <span\n className={cn(\n \"shrink-0 rounded-full font-semibold uppercase tracking-wide\",\n size === \"sm\" ? \"px-1.5 py-0.5 text-[9px]\" : \"px-2 py-0.5 text-[10px]\",\n tone === \"required\"\n ? \"bg-amber-500/15 text-amber-600 dark:text-amber-400\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {label}\n </span>\n );\n}\n\nfunction PageSettingsSection({\n id,\n icon,\n title,\n subtitle,\n badge,\n required,\n connected,\n open = false,\n onToggle,\n children,\n}: SettingsSectionProps) {\n return (\n <div\n id={id}\n className={cn(\n \"scroll-mt-16 overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm transition-colors\",\n open ? \"border-border\" : \"border-border/60\",\n )}\n >\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={open}\n className=\"flex w-full items-start justify-between gap-4 px-5 py-4 text-start transition-colors hover:bg-muted/40 sm:px-6 sm:py-5\"\n >\n <div className=\"flex min-w-0 items-start gap-3\">\n <span className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground [&>svg]:size-[18px]\">\n {icon}\n </span>\n <span className=\"flex min-w-0 flex-col gap-1.5\">\n <span className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-base font-semibold leading-none tracking-tight text-foreground\">\n {title}\n </span>\n {connected && <ConnectedDot size=\"md\" />}\n {required && !connected && (\n <StatusBadge label=\"Required\" tone=\"required\" size=\"md\" />\n )}\n {badge && <StatusBadge label={badge} tone=\"muted\" size=\"md\" />}\n </span>\n {subtitle && (\n <span className=\"text-sm leading-snug text-muted-foreground\">\n {subtitle}\n </span>\n )}\n </span>\n </div>\n <IconChevronDown\n size={18}\n className={cn(\n \"mt-1 shrink-0 text-muted-foreground transition-transform\",\n open && \"rotate-180\",\n )}\n />\n </button>\n {open && (\n <div className=\"border-t border-border/60 px-5 pb-5 pt-5 sm:px-6 sm:pb-6\">\n {children}\n </div>\n )}\n </div>\n );\n}\n\nfunction SidebarSettingsSection({\n id,\n icon,\n title,\n subtitle,\n badge,\n required,\n connected,\n open = false,\n onToggle,\n children,\n}: SettingsSectionProps) {\n return (\n <div id={id} className=\"rounded-lg border border-border bg-background/50\">\n <button\n type=\"button\"\n onClick={onToggle}\n className=\"flex w-full cursor-pointer items-center justify-between px-3 py-2.5 text-start rounded-lg hover:bg-accent/40 transition-colors\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <span className=\"shrink-0 text-muted-foreground\">{icon}</span>\n <span className=\"text-[12px] font-medium text-foreground truncate\">\n {title}\n </span>\n {connected && <ConnectedDot size=\"sm\" />}\n {required && !connected && (\n <StatusBadge label=\"Required\" tone=\"muted\" size=\"sm\" />\n )}\n {badge && <StatusBadge label={badge} tone=\"muted\" size=\"sm\" />}\n </div>\n <IconChevronDown\n size={12}\n className={`shrink-0 text-muted-foreground transition-transform ${open ? \"rotate-180\" : \"\"}`}\n />\n </button>\n {open && (\n <div className=\"border-t border-border px-3 pb-3 pt-2.5\">\n {subtitle && (\n <p className=\"text-[10px] text-muted-foreground mb-2.5\">\n {subtitle}\n </p>\n )}\n {children}\n </div>\n )}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SettingsSection.js","sourceRoot":"","sources":["../../../src/client/settings/SettingsSection.tsx"],"names":[],"mappings":"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","sourcesContent":["import { IconChevronDown, IconCheck } from \"@tabler/icons-react\";\nimport { createContext, useContext, type ReactNode } from \"react\";\n\nimport { cn } from \"../utils.js\";\n\n/**\n * Where a settings section is being rendered.\n *\n * - `sidebar`: the compact agent sidebar panel (dense, small type).\n * - `page`: the full-width settings page, styled as a polished card that\n * matches the shadcn `Card` surface used by app-owned settings tabs.\n */\nexport type SettingsSurface = \"sidebar\" | \"page\";\n\nconst SettingsSurfaceContext = createContext<SettingsSurface>(\"sidebar\");\n\nexport function SettingsSurfaceProvider({\n surface,\n children,\n}: {\n surface: SettingsSurface;\n children: ReactNode;\n}) {\n return (\n <SettingsSurfaceContext.Provider value={surface}>\n {children}\n </SettingsSurfaceContext.Provider>\n );\n}\n\nexport function useSettingsSurface(): SettingsSurface {\n return useContext(SettingsSurfaceContext);\n}\n\ninterface SettingsSectionProps {\n id?: string;\n icon: ReactNode;\n title: string;\n subtitle?: string;\n badge?: string;\n required?: boolean;\n connected?: boolean;\n open?: boolean;\n onToggle?: () => void;\n children: ReactNode;\n}\n\n/**\n * Collapsible settings section. Renders as a compact row in the agent sidebar\n * and as a polished, shadcn-style card on the full settings page (so the\n * framework tabs match app-owned General/Team cards). The visual surface is\n * read from `SettingsSurfaceContext`.\n */\nexport function SettingsSection(props: SettingsSectionProps) {\n const surface = useSettingsSurface();\n return surface === \"page\" ? (\n <PageSettingsSection {...props} />\n ) : (\n <SidebarSettingsSection {...props} />\n );\n}\n\nfunction ConnectedDot({ size }: { size: \"sm\" | \"md\" }) {\n const dim = size === \"sm\" ? \"h-4 w-4\" : \"h-5 w-5\";\n const stroke = size === \"sm\" ? 3 : 2.5;\n const glyph = size === \"sm\" ? 10 : 12;\n return (\n <span\n className={cn(\n \"flex shrink-0 items-center justify-center rounded-full bg-green-500/15 text-green-500\",\n dim,\n )}\n >\n <IconCheck size={glyph} stroke={stroke} />\n </span>\n );\n}\n\nfunction StatusBadge({\n label,\n tone,\n size,\n}: {\n label: string;\n tone: \"muted\" | \"required\";\n size: \"sm\" | \"md\";\n}) {\n return (\n <span\n className={cn(\n \"shrink-0 rounded-full font-semibold uppercase tracking-wide\",\n size === \"sm\" ? \"px-1.5 py-0.5 text-[9px]\" : \"px-2 py-0.5 text-[10px]\",\n tone === \"required\"\n ? \"bg-amber-500/15 text-amber-600 dark:text-amber-400\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {label}\n </span>\n );\n}\n\nfunction PageSettingsSection({\n id,\n icon,\n title,\n subtitle,\n badge,\n required,\n connected,\n open = false,\n onToggle,\n children,\n}: SettingsSectionProps) {\n return (\n <div\n id={id}\n className={cn(\n \"scroll-mt-16 overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm transition-colors\",\n open ? \"border-border\" : \"border-border/60\",\n )}\n >\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={open}\n className=\"flex w-full items-start justify-between gap-4 px-5 py-4 text-start transition-colors hover:bg-muted/40 sm:px-6 sm:py-5\"\n >\n <div className=\"flex min-w-0 items-start gap-3\">\n <span className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground [&>svg]:size-[18px]\">\n {icon}\n </span>\n <span className=\"flex min-w-0 flex-col gap-1.5\">\n <span className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-base font-semibold leading-none tracking-tight text-foreground\">\n {title}\n </span>\n {connected && <ConnectedDot size=\"md\" />}\n {required && !connected && (\n <StatusBadge label=\"Required\" tone=\"required\" size=\"md\" />\n )}\n {badge && <StatusBadge label={badge} tone=\"muted\" size=\"md\" />}\n </span>\n {subtitle && (\n <span className=\"text-sm leading-snug text-muted-foreground\">\n {subtitle}\n </span>\n )}\n </span>\n </div>\n <IconChevronDown\n size={18}\n className={cn(\n \"mt-1 shrink-0 text-muted-foreground transition-transform\",\n open && \"rotate-180\",\n )}\n />\n </button>\n {open && (\n <div\n // `data-agent-native-settings-page` lets the shared stylesheet nudge\n // the smallest fixed type (authored dense for the compact sidebar) up\n // to a comfortable, consistent size on the full settings page so every\n // framework section body reads like the shadcn cards around it.\n data-agent-native-settings-page=\"\"\n className=\"border-t border-border/60 px-5 pb-5 pt-5 sm:px-6 sm:pb-6\"\n >\n {children}\n </div>\n )}\n </div>\n );\n}\n\nfunction SidebarSettingsSection({\n id,\n icon,\n title,\n subtitle,\n badge,\n required,\n connected,\n open = false,\n onToggle,\n children,\n}: SettingsSectionProps) {\n return (\n <div id={id} className=\"rounded-lg border border-border bg-background/50\">\n <button\n type=\"button\"\n onClick={onToggle}\n className=\"flex w-full cursor-pointer items-center justify-between px-3 py-2.5 text-start rounded-lg hover:bg-accent/40 transition-colors\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <span className=\"shrink-0 text-muted-foreground\">{icon}</span>\n <span className=\"text-[12px] font-medium text-foreground truncate\">\n {title}\n </span>\n {connected && <ConnectedDot size=\"sm\" />}\n {required && !connected && (\n <StatusBadge label=\"Required\" tone=\"muted\" size=\"sm\" />\n )}\n {badge && <StatusBadge label={badge} tone=\"muted\" size=\"sm\" />}\n </div>\n <IconChevronDown\n size={12}\n className={`shrink-0 text-muted-foreground transition-transform ${open ? \"rotate-180\" : \"\"}`}\n />\n </button>\n {open && (\n <div className=\"border-t border-border px-3 pb-3 pt-2.5\">\n {subtitle && (\n <p className=\"text-[10px] text-muted-foreground mb-2.5\">\n {subtitle}\n </p>\n )}\n {children}\n </div>\n )}\n </div>\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsTabsPage.d.ts","sourceRoot":"","sources":["../../../src/client/settings/SettingsTabsPage.tsx"],"names":[],"mappings":"AAOA,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAIf,KAAK,eAAe,GAAG,aAAa,CAAC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE7D;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,SAAS,CAAC;IACnB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,aAAa,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,SAAS,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,aAAa,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACtC,6CAA6C;IAC7C,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC7C;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;
|
|
1
|
+
{"version":3,"file":"SettingsTabsPage.d.ts","sourceRoot":"","sources":["../../../src/client/settings/SettingsTabsPage.tsx"],"names":[],"mappings":"AAOA,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAIf,KAAK,eAAe,GAAG,aAAa,CAAC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE7D;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,SAAS,CAAC;IACnB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,aAAa,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,SAAS,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,aAAa,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACtC,6CAA6C;IAC7C,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC7C;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAgED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,SAAc,EACd,YAAwB,EACxB,SAAkB,EAClB,aAA4B,EAC5B,SAA+B,EAC/B,UAAsB,EACtB,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,YAAmB,EACnB,iBAAqC,EACrC,aAAa,EACb,oBAAoB,EACpB,KAAK,EACL,aAAa,GACd,EAAE,qBAAqB,+BAgTvB"}
|
|
@@ -20,18 +20,28 @@ function normalizeTabId(value) {
|
|
|
20
20
|
if (normalized === "workspace" || normalized === "workspace-settings") {
|
|
21
21
|
return "workspace";
|
|
22
22
|
}
|
|
23
|
-
if (normalized === "organization" || normalized === "org") {
|
|
24
|
-
return "team";
|
|
25
|
-
}
|
|
26
23
|
return normalized;
|
|
27
24
|
}
|
|
25
|
+
function resolveTabId(tabs, value) {
|
|
26
|
+
const normalized = normalizeTabId(value);
|
|
27
|
+
if (!normalized)
|
|
28
|
+
return null;
|
|
29
|
+
if (tabs.some((tab) => tab.id === normalized))
|
|
30
|
+
return normalized;
|
|
31
|
+
if (normalized === "organization" ||
|
|
32
|
+
normalized === "org" ||
|
|
33
|
+
normalized === "team") {
|
|
34
|
+
if (tabs.some((tab) => tab.id === "organization"))
|
|
35
|
+
return "organization";
|
|
36
|
+
if (tabs.some((tab) => tab.id === "team"))
|
|
37
|
+
return "team";
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
28
41
|
function activeTabFromHash(tabs, defaultTab) {
|
|
29
42
|
if (typeof window === "undefined")
|
|
30
43
|
return defaultTab;
|
|
31
|
-
|
|
32
|
-
if (fromHash && tabs.some((tab) => tab.id === fromHash))
|
|
33
|
-
return fromHash;
|
|
34
|
-
return defaultTab;
|
|
44
|
+
return resolveTabId(tabs, window.location.hash) ?? defaultTab;
|
|
35
45
|
}
|
|
36
46
|
function updateHashForTab(tabId) {
|
|
37
47
|
if (typeof window === "undefined")
|
|
@@ -42,6 +52,7 @@ function updateHashForTab(tabId) {
|
|
|
42
52
|
}
|
|
43
53
|
export function SettingsTabsPage({ general, team, whatsNew, extraTabs = [], generalLabel = "General", teamLabel = "Team", whatsNewLabel = "What's new", ariaLabel = "Settings sections", defaultTab = "general", className, navClassName, contentClassName, enableSearch = true, searchPlaceholder = "Search settings", searchEntries, generalSearchEntries, value, onValueChange, }) {
|
|
44
54
|
const tabs = useMemo(() => {
|
|
55
|
+
const hasOrganizationTab = extraTabs.some((tab) => tab.id === "organization");
|
|
45
56
|
const next = [
|
|
46
57
|
{
|
|
47
58
|
id: "general",
|
|
@@ -52,7 +63,7 @@ export function SettingsTabsPage({ general, team, whatsNew, extraTabs = [], gene
|
|
|
52
63
|
},
|
|
53
64
|
];
|
|
54
65
|
next.push(...extraTabs);
|
|
55
|
-
if (team) {
|
|
66
|
+
if (team && !hasOrganizationTab) {
|
|
56
67
|
next.push({
|
|
57
68
|
id: "team",
|
|
58
69
|
label: teamLabel,
|
|
@@ -107,8 +118,8 @@ export function SettingsTabsPage({ general, team, whatsNew, extraTabs = [], gene
|
|
|
107
118
|
if (isControlled)
|
|
108
119
|
return;
|
|
109
120
|
const handleHashChange = () => {
|
|
110
|
-
const fromHash =
|
|
111
|
-
if (fromHash
|
|
121
|
+
const fromHash = resolveTabId(tabs, window.location.hash);
|
|
122
|
+
if (fromHash) {
|
|
112
123
|
setInternalTab(fromHash);
|
|
113
124
|
}
|
|
114
125
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsTabsPage.js","sourceRoot":"","sources":["../../../src/client/settings/SettingsTabsPage.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n IconHistory,\n IconSearch,\n IconSettings,\n IconUsers,\n IconX,\n} from \"@tabler/icons-react\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useState,\n type ComponentType,\n type ReactNode,\n} from \"react\";\n\nimport { cn } from \"../utils.js\";\n\ntype SettingsTabIcon = ComponentType<{ className?: string }>;\n\n/**\n * A single deep-link target inside settings that the settings search can jump\n * to. Entries usually map to a section within a tab (via a `hash`/anchor id),\n * making individual controls discoverable without hunting through every tab.\n */\nexport interface SettingsSearchEntry {\n /** Stable unique id for the entry. */\n id: string;\n /** Primary label shown in the search results. */\n label: string;\n /** Extra space-separated terms to match against (synonyms, provider names). */\n keywords?: string;\n /** Optional secondary description shown under the label. */\n description?: string;\n /** Tab to activate when the entry is picked. Defaults to the owning tab. */\n tabId?: string;\n /**\n * Optional section id / DOM element id to open + scroll to after switching\n * tabs. Handled by the inner panels' own hash listeners.\n */\n hash?: string;\n /** Optional icon override; defaults to the owning tab's icon. */\n icon?: SettingsTabIcon;\n}\n\nexport interface SettingsTabItem {\n id: string;\n label: string;\n icon?: SettingsTabIcon;\n content: ReactNode;\n /** Extra space-separated terms so this tab is findable via search. */\n keywords?: string;\n /** Deep-link entries within this tab for the settings search. */\n searchEntries?: SettingsSearchEntry[];\n}\n\nexport interface SettingsTabsPageProps {\n general: ReactNode;\n team?: ReactNode;\n whatsNew?: ReactNode;\n extraTabs?: SettingsTabItem[];\n generalLabel?: string;\n teamLabel?: string;\n whatsNewLabel?: string;\n ariaLabel?: string;\n defaultTab?: string;\n className?: string;\n navClassName?: string;\n contentClassName?: string;\n /** Whether to render the settings search box. Defaults to true. */\n enableSearch?: boolean;\n /** Placeholder for the settings search box. */\n searchPlaceholder?: string;\n /** Extra global search entries (e.g. anchors within the General tab). */\n searchEntries?: SettingsSearchEntry[];\n /** Deep-link entries for the General tab. */\n generalSearchEntries?: SettingsSearchEntry[];\n /**\n * Controlled active tab id. When provided, the parent owns tab state (and is\n * responsible for URL/app-state sync); the component skips its own hash-based\n * tab tracking. Leave undefined for the default uncontrolled, hash-driven\n * behavior.\n */\n value?: string;\n /**\n * Called whenever the active tab changes via a tab click or a search result\n * selection. Fires in both controlled and uncontrolled modes.\n */\n onValueChange?: (tabId: string) => void;\n}\n\ninterface ResolvedSearchEntry extends SettingsSearchEntry {\n tabId: string;\n tabLabel: string;\n icon?: SettingsTabIcon;\n haystack: string;\n}\n\nfunction normalizeTabId(value?: string | null): string | null {\n const normalized = value\n ?.replace(/^#/, \"\")\n .trim()\n .toLowerCase()\n .replace(/['\"]/g, \"\")\n .replace(/[\\s_]+/g, \"-\");\n if (!normalized) return null;\n if (\n normalized === \"whats-new\" ||\n normalized === \"what-s-new\" ||\n normalized === \"changelog\" ||\n normalized === \"updates\"\n ) {\n return \"whats-new\";\n }\n if (normalized === \"workspace\" || normalized === \"workspace-settings\") {\n return \"workspace\";\n }\n if (normalized === \"organization\" || normalized === \"org\") {\n return \"team\";\n }\n return normalized;\n}\n\nfunction activeTabFromHash(\n tabs: SettingsTabItem[],\n defaultTab: string,\n): string {\n if (typeof window === \"undefined\") return defaultTab;\n const fromHash = normalizeTabId(window.location.hash);\n if (fromHash && tabs.some((tab) => tab.id === fromHash)) return fromHash;\n return defaultTab;\n}\n\nfunction updateHashForTab(tabId: string) {\n if (typeof window === \"undefined\") return;\n const { pathname, search } = window.location;\n const hash = tabId === \"general\" ? \"\" : `#${encodeURIComponent(tabId)}`;\n window.history.pushState(null, \"\", `${pathname}${search}${hash}`);\n}\n\nexport function SettingsTabsPage({\n general,\n team,\n whatsNew,\n extraTabs = [],\n generalLabel = \"General\",\n teamLabel = \"Team\",\n whatsNewLabel = \"What's new\",\n ariaLabel = \"Settings sections\",\n defaultTab = \"general\",\n className,\n navClassName,\n contentClassName,\n enableSearch = true,\n searchPlaceholder = \"Search settings\",\n searchEntries,\n generalSearchEntries,\n value,\n onValueChange,\n}: SettingsTabsPageProps) {\n const tabs = useMemo<SettingsTabItem[]>(() => {\n const next: SettingsTabItem[] = [\n {\n id: \"general\",\n label: generalLabel,\n icon: IconSettings,\n content: general,\n searchEntries: generalSearchEntries,\n },\n ];\n next.push(...extraTabs);\n if (team) {\n next.push({\n id: \"team\",\n label: teamLabel,\n icon: IconUsers,\n content: team,\n });\n }\n if (whatsNew) {\n next.push({\n id: \"whats-new\",\n label: whatsNewLabel,\n icon: IconHistory,\n content: whatsNew,\n });\n }\n return next;\n }, [\n extraTabs,\n general,\n generalLabel,\n generalSearchEntries,\n team,\n teamLabel,\n whatsNew,\n whatsNewLabel,\n ]);\n\n const fallbackTab = tabs.some((tab) => tab.id === defaultTab)\n ? defaultTab\n : (tabs[0]?.id ?? \"general\");\n const isControlled = value !== undefined;\n const [internalTab, setInternalTab] = useState(() =>\n activeTabFromHash(tabs, fallbackTab),\n );\n const activeTab = isControlled ? value : internalTab;\n const [query, setQuery] = useState(\"\");\n\n const changeTab = useCallback(\n (tabId: string) => {\n if (!isControlled) setInternalTab(tabId);\n onValueChange?.(tabId);\n },\n [isControlled, onValueChange],\n );\n\n useEffect(() => {\n // In controlled mode the parent owns (and validates) the active tab.\n if (isControlled) return;\n if (tabs.some((tab) => tab.id === internalTab)) return;\n setInternalTab(fallbackTab);\n }, [fallbackTab, internalTab, isControlled, tabs]);\n\n useEffect(() => {\n // Hash-driven tab tracking only applies to the uncontrolled mode. Only\n // react to hashes that name a top-level tab. Section-level hashes\n // (e.g. `#llm`, `#secrets`) are consumed by the inner panels, so leave\n // the active tab untouched to avoid bouncing back to General.\n if (isControlled) return;\n const handleHashChange = () => {\n const fromHash = normalizeTabId(window.location.hash);\n if (fromHash && tabs.some((tab) => tab.id === fromHash)) {\n setInternalTab(fromHash);\n }\n };\n window.addEventListener(\"hashchange\", handleHashChange);\n return () => window.removeEventListener(\"hashchange\", handleHashChange);\n }, [isControlled, tabs]);\n\n const selectedTab = tabs.find((tab) => tab.id === activeTab) ?? tabs[0];\n\n // Flatten tab + deep-link entries into one searchable index.\n const searchIndex = useMemo<ResolvedSearchEntry[]>(() => {\n const entries: ResolvedSearchEntry[] = [];\n const seen = new Set<string>();\n const add = (entry: ResolvedSearchEntry) => {\n if (seen.has(entry.id)) return;\n seen.add(entry.id);\n entries.push(entry);\n };\n for (const tab of tabs) {\n add({\n id: `tab:${tab.id}`,\n label: tab.label,\n keywords: tab.keywords,\n tabId: tab.id,\n tabLabel: tab.label,\n icon: tab.icon,\n haystack: `${tab.label} ${tab.keywords ?? \"\"}`.toLowerCase(),\n });\n for (const sub of tab.searchEntries ?? []) {\n add({\n ...sub,\n tabId: sub.tabId ?? tab.id,\n tabLabel: tab.label,\n icon: sub.icon ?? tab.icon,\n haystack:\n `${sub.label} ${sub.keywords ?? \"\"} ${sub.description ?? \"\"} ${tab.label}`.toLowerCase(),\n });\n }\n }\n for (const sub of searchEntries ?? []) {\n const owner = tabs.find((tab) => tab.id === (sub.tabId ?? \"general\"));\n add({\n ...sub,\n tabId: sub.tabId ?? \"general\",\n tabLabel: owner?.label ?? sub.tabId ?? \"General\",\n icon: sub.icon ?? owner?.icon,\n haystack:\n `${sub.label} ${sub.keywords ?? \"\"} ${sub.description ?? \"\"} ${owner?.label ?? \"\"}`.toLowerCase(),\n });\n }\n return entries;\n }, [searchEntries, tabs]);\n\n const trimmedQuery = query.trim().toLowerCase();\n const results = useMemo<ResolvedSearchEntry[]>(() => {\n if (!trimmedQuery) return [];\n const terms = trimmedQuery.split(/\\s+/).filter(Boolean);\n return searchIndex\n .filter((entry) => terms.every((term) => entry.haystack.includes(term)))\n .sort((a, b) => {\n const aStarts = a.label.toLowerCase().startsWith(trimmedQuery) ? 0 : 1;\n const bStarts = b.label.toLowerCase().startsWith(trimmedQuery) ? 0 : 1;\n if (aStarts !== bStarts) return aStarts - bStarts;\n return a.label.localeCompare(b.label);\n });\n }, [searchIndex, trimmedQuery]);\n\n const selectEntry = (entry: ResolvedSearchEntry) => {\n changeTab(entry.tabId);\n setQuery(\"\");\n if (typeof window === \"undefined\") return;\n const hash = entry.hash?.replace(/^#/, \"\");\n if (hash) {\n const { pathname, search } = window.location;\n window.history.pushState(null, \"\", `${pathname}${search}#${hash}`);\n // Let the inner panels open + scroll to their section.\n window.dispatchEvent(new Event(\"hashchange\"));\n window.requestAnimationFrame(() => {\n document\n .getElementById(hash)\n ?.scrollIntoView({ block: \"start\", behavior: \"smooth\" });\n });\n } else if (!isControlled) {\n updateHashForTab(entry.tabId);\n }\n };\n\n const searching = enableSearch && trimmedQuery.length > 0;\n\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full flex-col overflow-hidden bg-background sm:flex-row\",\n className,\n )}\n >\n <div\n className={cn(\n \"flex shrink-0 flex-col gap-2 border-b border-border bg-background p-2 sm:min-h-0 sm:w-56 sm:overflow-y-auto sm:border-b-0 sm:border-e sm:p-3\",\n navClassName,\n )}\n >\n {enableSearch ? (\n <div className=\"relative sm:mb-1\">\n <IconSearch className=\"pointer-events-none absolute start-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\" />\n <input\n type=\"search\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === \"Escape\") setQuery(\"\");\n if (event.key === \"Enter\" && results[0]) {\n event.preventDefault();\n selectEntry(results[0]);\n }\n }}\n placeholder={searchPlaceholder}\n aria-label={searchPlaceholder}\n className=\"h-8 w-full rounded-md border border-border bg-background ps-8 pe-7 text-[13px] text-foreground outline-none transition-colors placeholder:text-muted-foreground focus:border-foreground/30 focus:ring-2 focus:ring-accent/40\"\n />\n {query ? (\n <button\n type=\"button\"\n onClick={() => setQuery(\"\")}\n aria-label=\"Clear search\"\n className=\"absolute end-1.5 top-1/2 flex size-5 -translate-y-1/2 items-center justify-center rounded text-muted-foreground hover:bg-accent/60 hover:text-foreground\"\n >\n <IconX className=\"size-3.5\" />\n </button>\n ) : null}\n </div>\n ) : null}\n\n {searching ? (\n <div\n role=\"listbox\"\n aria-label=\"Settings search results\"\n className=\"flex flex-col gap-0.5\"\n >\n {results.length === 0 ? (\n <p className=\"px-2 py-6 text-center text-[12px] text-muted-foreground\">\n No matching settings\n </p>\n ) : (\n results.map((entry) => {\n const Icon = entry.icon;\n return (\n <button\n key={entry.id}\n type=\"button\"\n role=\"option\"\n aria-selected={false}\n onClick={() => selectEntry(entry)}\n className=\"flex items-start gap-2 rounded-md px-2.5 py-2 text-start text-sm text-foreground transition-colors hover:bg-accent/60\"\n >\n {Icon ? (\n <Icon className=\"mt-0.5 size-4 shrink-0 text-muted-foreground\" />\n ) : null}\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"truncate font-medium\">\n {entry.label}\n </span>\n <span className=\"truncate text-[11px] text-muted-foreground\">\n {entry.description ?? entry.tabLabel}\n </span>\n </span>\n </button>\n );\n })\n )}\n </div>\n ) : (\n <nav\n aria-label={ariaLabel}\n role=\"tablist\"\n className=\"flex gap-1 overflow-x-auto sm:flex-col sm:overflow-x-visible\"\n >\n {tabs.map((tab) => {\n const Icon = tab.icon;\n const selected = tab.id === selectedTab?.id;\n return (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n aria-controls={`settings-tabpanel-${tab.id}`}\n id={`settings-tab-${tab.id}`}\n onClick={() => {\n changeTab(tab.id);\n if (!isControlled) updateHashForTab(tab.id);\n }}\n className={cn(\n \"flex min-h-9 shrink-0 items-center gap-2 rounded-md px-3 py-2 text-start text-sm font-medium transition-colors sm:w-full\",\n selected\n ? \"bg-accent text-foreground\"\n : \"text-muted-foreground hover:bg-accent/50 hover:text-foreground\",\n )}\n >\n {Icon ? (\n <Icon\n className={cn(\n \"size-4 shrink-0\",\n selected ? \"text-foreground\" : \"text-muted-foreground\",\n )}\n />\n ) : null}\n <span className=\"truncate\">{tab.label}</span>\n </button>\n );\n })}\n </nav>\n )}\n </div>\n <div\n id={`settings-tabpanel-${selectedTab?.id ?? \"general\"}`}\n role=\"tabpanel\"\n aria-labelledby={`settings-tab-${selectedTab?.id ?? \"general\"}`}\n className={cn(\n \"min-h-0 min-w-0 flex-1 overflow-y-auto p-4 sm:p-6\",\n contentClassName,\n )}\n >\n {selectedTab?.content}\n </div>\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SettingsTabsPage.js","sourceRoot":"","sources":["../../../src/client/settings/SettingsTabsPage.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n IconHistory,\n IconSearch,\n IconSettings,\n IconUsers,\n IconX,\n} from \"@tabler/icons-react\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useState,\n type ComponentType,\n type ReactNode,\n} from \"react\";\n\nimport { cn } from \"../utils.js\";\n\ntype SettingsTabIcon = ComponentType<{ className?: string }>;\n\n/**\n * A single deep-link target inside settings that the settings search can jump\n * to. Entries usually map to a section within a tab (via a `hash`/anchor id),\n * making individual controls discoverable without hunting through every tab.\n */\nexport interface SettingsSearchEntry {\n /** Stable unique id for the entry. */\n id: string;\n /** Primary label shown in the search results. */\n label: string;\n /** Extra space-separated terms to match against (synonyms, provider names). */\n keywords?: string;\n /** Optional secondary description shown under the label. */\n description?: string;\n /** Tab to activate when the entry is picked. Defaults to the owning tab. */\n tabId?: string;\n /**\n * Optional section id / DOM element id to open + scroll to after switching\n * tabs. Handled by the inner panels' own hash listeners.\n */\n hash?: string;\n /** Optional icon override; defaults to the owning tab's icon. */\n icon?: SettingsTabIcon;\n}\n\nexport interface SettingsTabItem {\n id: string;\n label: string;\n icon?: SettingsTabIcon;\n content: ReactNode;\n /** Extra space-separated terms so this tab is findable via search. */\n keywords?: string;\n /** Deep-link entries within this tab for the settings search. */\n searchEntries?: SettingsSearchEntry[];\n}\n\nexport interface SettingsTabsPageProps {\n general: ReactNode;\n team?: ReactNode;\n whatsNew?: ReactNode;\n extraTabs?: SettingsTabItem[];\n generalLabel?: string;\n teamLabel?: string;\n whatsNewLabel?: string;\n ariaLabel?: string;\n defaultTab?: string;\n className?: string;\n navClassName?: string;\n contentClassName?: string;\n /** Whether to render the settings search box. Defaults to true. */\n enableSearch?: boolean;\n /** Placeholder for the settings search box. */\n searchPlaceholder?: string;\n /** Extra global search entries (e.g. anchors within the General tab). */\n searchEntries?: SettingsSearchEntry[];\n /** Deep-link entries for the General tab. */\n generalSearchEntries?: SettingsSearchEntry[];\n /**\n * Controlled active tab id. When provided, the parent owns tab state (and is\n * responsible for URL/app-state sync); the component skips its own hash-based\n * tab tracking. Leave undefined for the default uncontrolled, hash-driven\n * behavior.\n */\n value?: string;\n /**\n * Called whenever the active tab changes via a tab click or a search result\n * selection. Fires in both controlled and uncontrolled modes.\n */\n onValueChange?: (tabId: string) => void;\n}\n\ninterface ResolvedSearchEntry extends SettingsSearchEntry {\n tabId: string;\n tabLabel: string;\n icon?: SettingsTabIcon;\n haystack: string;\n}\n\nfunction normalizeTabId(value?: string | null): string | null {\n const normalized = value\n ?.replace(/^#/, \"\")\n .trim()\n .toLowerCase()\n .replace(/['\"]/g, \"\")\n .replace(/[\\s_]+/g, \"-\");\n if (!normalized) return null;\n if (\n normalized === \"whats-new\" ||\n normalized === \"what-s-new\" ||\n normalized === \"changelog\" ||\n normalized === \"updates\"\n ) {\n return \"whats-new\";\n }\n if (normalized === \"workspace\" || normalized === \"workspace-settings\") {\n return \"workspace\";\n }\n return normalized;\n}\n\nfunction resolveTabId(\n tabs: SettingsTabItem[],\n value?: string | null,\n): string | null {\n const normalized = normalizeTabId(value);\n if (!normalized) return null;\n if (tabs.some((tab) => tab.id === normalized)) return normalized;\n if (\n normalized === \"organization\" ||\n normalized === \"org\" ||\n normalized === \"team\"\n ) {\n if (tabs.some((tab) => tab.id === \"organization\")) return \"organization\";\n if (tabs.some((tab) => tab.id === \"team\")) return \"team\";\n }\n return null;\n}\n\nfunction activeTabFromHash(\n tabs: SettingsTabItem[],\n defaultTab: string,\n): string {\n if (typeof window === \"undefined\") return defaultTab;\n return resolveTabId(tabs, window.location.hash) ?? defaultTab;\n}\n\nfunction updateHashForTab(tabId: string) {\n if (typeof window === \"undefined\") return;\n const { pathname, search } = window.location;\n const hash = tabId === \"general\" ? \"\" : `#${encodeURIComponent(tabId)}`;\n window.history.pushState(null, \"\", `${pathname}${search}${hash}`);\n}\n\nexport function SettingsTabsPage({\n general,\n team,\n whatsNew,\n extraTabs = [],\n generalLabel = \"General\",\n teamLabel = \"Team\",\n whatsNewLabel = \"What's new\",\n ariaLabel = \"Settings sections\",\n defaultTab = \"general\",\n className,\n navClassName,\n contentClassName,\n enableSearch = true,\n searchPlaceholder = \"Search settings\",\n searchEntries,\n generalSearchEntries,\n value,\n onValueChange,\n}: SettingsTabsPageProps) {\n const tabs = useMemo<SettingsTabItem[]>(() => {\n const hasOrganizationTab = extraTabs.some(\n (tab) => tab.id === \"organization\",\n );\n const next: SettingsTabItem[] = [\n {\n id: \"general\",\n label: generalLabel,\n icon: IconSettings,\n content: general,\n searchEntries: generalSearchEntries,\n },\n ];\n next.push(...extraTabs);\n if (team && !hasOrganizationTab) {\n next.push({\n id: \"team\",\n label: teamLabel,\n icon: IconUsers,\n content: team,\n });\n }\n if (whatsNew) {\n next.push({\n id: \"whats-new\",\n label: whatsNewLabel,\n icon: IconHistory,\n content: whatsNew,\n });\n }\n return next;\n }, [\n extraTabs,\n general,\n generalLabel,\n generalSearchEntries,\n team,\n teamLabel,\n whatsNew,\n whatsNewLabel,\n ]);\n\n const fallbackTab = tabs.some((tab) => tab.id === defaultTab)\n ? defaultTab\n : (tabs[0]?.id ?? \"general\");\n const isControlled = value !== undefined;\n const [internalTab, setInternalTab] = useState(() =>\n activeTabFromHash(tabs, fallbackTab),\n );\n const activeTab = isControlled ? value : internalTab;\n const [query, setQuery] = useState(\"\");\n\n const changeTab = useCallback(\n (tabId: string) => {\n if (!isControlled) setInternalTab(tabId);\n onValueChange?.(tabId);\n },\n [isControlled, onValueChange],\n );\n\n useEffect(() => {\n // In controlled mode the parent owns (and validates) the active tab.\n if (isControlled) return;\n if (tabs.some((tab) => tab.id === internalTab)) return;\n setInternalTab(fallbackTab);\n }, [fallbackTab, internalTab, isControlled, tabs]);\n\n useEffect(() => {\n // Hash-driven tab tracking only applies to the uncontrolled mode. Only\n // react to hashes that name a top-level tab. Section-level hashes\n // (e.g. `#llm`, `#secrets`) are consumed by the inner panels, so leave\n // the active tab untouched to avoid bouncing back to General.\n if (isControlled) return;\n const handleHashChange = () => {\n const fromHash = resolveTabId(tabs, window.location.hash);\n if (fromHash) {\n setInternalTab(fromHash);\n }\n };\n window.addEventListener(\"hashchange\", handleHashChange);\n return () => window.removeEventListener(\"hashchange\", handleHashChange);\n }, [isControlled, tabs]);\n\n const selectedTab = tabs.find((tab) => tab.id === activeTab) ?? tabs[0];\n\n // Flatten tab + deep-link entries into one searchable index.\n const searchIndex = useMemo<ResolvedSearchEntry[]>(() => {\n const entries: ResolvedSearchEntry[] = [];\n const seen = new Set<string>();\n const add = (entry: ResolvedSearchEntry) => {\n if (seen.has(entry.id)) return;\n seen.add(entry.id);\n entries.push(entry);\n };\n for (const tab of tabs) {\n add({\n id: `tab:${tab.id}`,\n label: tab.label,\n keywords: tab.keywords,\n tabId: tab.id,\n tabLabel: tab.label,\n icon: tab.icon,\n haystack: `${tab.label} ${tab.keywords ?? \"\"}`.toLowerCase(),\n });\n for (const sub of tab.searchEntries ?? []) {\n add({\n ...sub,\n tabId: sub.tabId ?? tab.id,\n tabLabel: tab.label,\n icon: sub.icon ?? tab.icon,\n haystack:\n `${sub.label} ${sub.keywords ?? \"\"} ${sub.description ?? \"\"} ${tab.label}`.toLowerCase(),\n });\n }\n }\n for (const sub of searchEntries ?? []) {\n const owner = tabs.find((tab) => tab.id === (sub.tabId ?? \"general\"));\n add({\n ...sub,\n tabId: sub.tabId ?? \"general\",\n tabLabel: owner?.label ?? sub.tabId ?? \"General\",\n icon: sub.icon ?? owner?.icon,\n haystack:\n `${sub.label} ${sub.keywords ?? \"\"} ${sub.description ?? \"\"} ${owner?.label ?? \"\"}`.toLowerCase(),\n });\n }\n return entries;\n }, [searchEntries, tabs]);\n\n const trimmedQuery = query.trim().toLowerCase();\n const results = useMemo<ResolvedSearchEntry[]>(() => {\n if (!trimmedQuery) return [];\n const terms = trimmedQuery.split(/\\s+/).filter(Boolean);\n return searchIndex\n .filter((entry) => terms.every((term) => entry.haystack.includes(term)))\n .sort((a, b) => {\n const aStarts = a.label.toLowerCase().startsWith(trimmedQuery) ? 0 : 1;\n const bStarts = b.label.toLowerCase().startsWith(trimmedQuery) ? 0 : 1;\n if (aStarts !== bStarts) return aStarts - bStarts;\n return a.label.localeCompare(b.label);\n });\n }, [searchIndex, trimmedQuery]);\n\n const selectEntry = (entry: ResolvedSearchEntry) => {\n changeTab(entry.tabId);\n setQuery(\"\");\n if (typeof window === \"undefined\") return;\n const hash = entry.hash?.replace(/^#/, \"\");\n if (hash) {\n const { pathname, search } = window.location;\n window.history.pushState(null, \"\", `${pathname}${search}#${hash}`);\n // Let the inner panels open + scroll to their section.\n window.dispatchEvent(new Event(\"hashchange\"));\n window.requestAnimationFrame(() => {\n document\n .getElementById(hash)\n ?.scrollIntoView({ block: \"start\", behavior: \"smooth\" });\n });\n } else if (!isControlled) {\n updateHashForTab(entry.tabId);\n }\n };\n\n const searching = enableSearch && trimmedQuery.length > 0;\n\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full flex-col overflow-hidden bg-background sm:flex-row\",\n className,\n )}\n >\n <div\n className={cn(\n \"flex shrink-0 flex-col gap-2 border-b border-border bg-background p-2 sm:min-h-0 sm:w-56 sm:overflow-y-auto sm:border-b-0 sm:border-e sm:p-3\",\n navClassName,\n )}\n >\n {enableSearch ? (\n <div className=\"relative sm:mb-1\">\n <IconSearch className=\"pointer-events-none absolute start-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\" />\n <input\n type=\"search\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === \"Escape\") setQuery(\"\");\n if (event.key === \"Enter\" && results[0]) {\n event.preventDefault();\n selectEntry(results[0]);\n }\n }}\n placeholder={searchPlaceholder}\n aria-label={searchPlaceholder}\n className=\"h-8 w-full rounded-md border border-border bg-background ps-8 pe-7 text-[13px] text-foreground outline-none transition-colors placeholder:text-muted-foreground focus:border-foreground/30 focus:ring-2 focus:ring-accent/40\"\n />\n {query ? (\n <button\n type=\"button\"\n onClick={() => setQuery(\"\")}\n aria-label=\"Clear search\"\n className=\"absolute end-1.5 top-1/2 flex size-5 -translate-y-1/2 items-center justify-center rounded text-muted-foreground hover:bg-accent/60 hover:text-foreground\"\n >\n <IconX className=\"size-3.5\" />\n </button>\n ) : null}\n </div>\n ) : null}\n\n {searching ? (\n <div\n role=\"listbox\"\n aria-label=\"Settings search results\"\n className=\"flex flex-col gap-0.5\"\n >\n {results.length === 0 ? (\n <p className=\"px-2 py-6 text-center text-[12px] text-muted-foreground\">\n No matching settings\n </p>\n ) : (\n results.map((entry) => {\n const Icon = entry.icon;\n return (\n <button\n key={entry.id}\n type=\"button\"\n role=\"option\"\n aria-selected={false}\n onClick={() => selectEntry(entry)}\n className=\"flex items-start gap-2 rounded-md px-2.5 py-2 text-start text-sm text-foreground transition-colors hover:bg-accent/60\"\n >\n {Icon ? (\n <Icon className=\"mt-0.5 size-4 shrink-0 text-muted-foreground\" />\n ) : null}\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"truncate font-medium\">\n {entry.label}\n </span>\n <span className=\"truncate text-[11px] text-muted-foreground\">\n {entry.description ?? entry.tabLabel}\n </span>\n </span>\n </button>\n );\n })\n )}\n </div>\n ) : (\n <nav\n aria-label={ariaLabel}\n role=\"tablist\"\n className=\"flex gap-1 overflow-x-auto sm:flex-col sm:overflow-x-visible\"\n >\n {tabs.map((tab) => {\n const Icon = tab.icon;\n const selected = tab.id === selectedTab?.id;\n return (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n aria-controls={`settings-tabpanel-${tab.id}`}\n id={`settings-tab-${tab.id}`}\n onClick={() => {\n changeTab(tab.id);\n if (!isControlled) updateHashForTab(tab.id);\n }}\n className={cn(\n \"flex min-h-9 shrink-0 items-center gap-2 rounded-md px-3 py-2 text-start text-sm font-medium transition-colors sm:w-full\",\n selected\n ? \"bg-accent text-foreground\"\n : \"text-muted-foreground hover:bg-accent/50 hover:text-foreground\",\n )}\n >\n {Icon ? (\n <Icon\n className={cn(\n \"size-4 shrink-0\",\n selected ? \"text-foreground\" : \"text-muted-foreground\",\n )}\n />\n ) : null}\n <span className=\"truncate\">{tab.label}</span>\n </button>\n );\n })}\n </nav>\n )}\n </div>\n <div\n id={`settings-tabpanel-${selectedTab?.id ?? \"general\"}`}\n role=\"tabpanel\"\n aria-labelledby={`settings-tab-${selectedTab?.id ?? \"general\"}`}\n className={cn(\n \"min-h-0 min-w-0 flex-1 overflow-y-auto p-4 sm:p-6\",\n contentClassName,\n )}\n >\n {selectedTab?.content}\n </div>\n </div>\n );\n}\n"]}
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
26
26
|
* Body: { update: string (base64), requestSource?: string }
|
|
27
27
|
*/
|
|
28
28
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
29
|
-
ok?: undefined;
|
|
30
29
|
error: string;
|
|
30
|
+
ok?: undefined;
|
|
31
31
|
} | {
|
|
32
32
|
error?: undefined;
|
|
33
33
|
ok: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-tools.d.ts","sourceRoot":"","sources":["../../src/db-admin/agent-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAuBhE,wBAAgB,uBAAuB,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"agent-tools.d.ts","sourceRoot":"","sources":["../../src/db-admin/agent-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAuBhE,wBAAgB,uBAAuB,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAsKrE"}
|
|
@@ -37,7 +37,7 @@ export function createDbAdminAgentTools() {
|
|
|
37
37
|
},
|
|
38
38
|
"db-admin-rows": {
|
|
39
39
|
tool: {
|
|
40
|
-
description:
|
|
40
|
+
description: 'DEV ONLY. Read rows from one table (unscoped) with pagination, sorting, and filters. Large text/JSON cells are previewed by default; pass includeLargeCells: "true" only when you need the full value.',
|
|
41
41
|
parameters: {
|
|
42
42
|
type: "object",
|
|
43
43
|
properties: {
|
|
@@ -58,6 +58,10 @@ export function createDbAdminAgentTools() {
|
|
|
58
58
|
type: "string",
|
|
59
59
|
description: 'JSON array of filters, e.g. \'[{"column":"status","op":"eq","value":"draft"}]\'. Ops: eq, neq, lt, lte, gt, gte, like, ilike, in, is_null, not_null.',
|
|
60
60
|
},
|
|
61
|
+
includeLargeCells: {
|
|
62
|
+
type: "string",
|
|
63
|
+
description: 'Set to "true" to return full large text/JSON cells instead of previews.',
|
|
64
|
+
},
|
|
61
65
|
},
|
|
62
66
|
required: ["table"],
|
|
63
67
|
},
|
|
@@ -69,6 +73,7 @@ export function createDbAdminAgentTools() {
|
|
|
69
73
|
pageSize: Number(args.pageSize) || 50,
|
|
70
74
|
sort: parseJson(args.sort, "sort"),
|
|
71
75
|
filters: parseJson(args.filters, "filters"),
|
|
76
|
+
includeLargeCells: String(args.includeLargeCells) === "true",
|
|
72
77
|
});
|
|
73
78
|
return JSON.stringify(result);
|
|
74
79
|
},
|
|
@@ -112,7 +117,7 @@ export function createDbAdminAgentTools() {
|
|
|
112
117
|
},
|
|
113
118
|
"db-admin-query": {
|
|
114
119
|
tool: {
|
|
115
|
-
description: 'DEV ONLY. Run arbitrary SQL against the full database (unscoped). PREFER
|
|
120
|
+
description: 'DEV ONLY. Run arbitrary SQL against the full database (unscoped). PREFER this over db-query/db-exec for database-admin work and for tables without owner_email/org_id scoping. Bare SELECTs are auto-limited to 100 rows, and large string cells are truncated in the tool result. Destructive statements require confirmDestructive: "true".',
|
|
116
121
|
parameters: {
|
|
117
122
|
type: "object",
|
|
118
123
|
properties: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-tools.js","sourceRoot":"","sources":["../../src/db-admin/agent-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Dev-only agent tools for the database admin.\n *\n * These mirror the HTTP routes and call the SAME `operations.ts` functions, so\n * the agent can introspect and edit the full database during local development.\n * They are spread into the DEV actions surface ONLY (never `prodActions`) and\n * the dev surface itself is gated to dev + localhost upstream.\n *\n * Complex params (sort / filters / inserts / updates / deletes / params) are\n * accepted as JSON strings and parsed here, matching how the framework's other\n * structured CLI-style tools accept JSON-encoded arguments.\n */\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport {\n applyMutations,\n getRows,\n getTableSchema,\n listTables,\n runSql,\n DbAdminConfirmRequiredError,\n} from \"./operations.js\";\nimport type { DbAdminFilter, DbAdminMutation, DbAdminSort } from \"./types.js\";\n\nfunction parseJson<T>(value: unknown, field: string): T | undefined {\n if (value == null || value === \"\") return undefined;\n if (typeof value !== \"string\") return value as T;\n try {\n return JSON.parse(value) as T;\n } catch {\n throw new Error(\n `Invalid JSON for \"${field}\": ${String(value).slice(0, 200)}`,\n );\n }\n}\n\nexport function createDbAdminAgentTools(): Record<string, ActionEntry> {\n return {\n \"db-admin-tables\": {\n tool: {\n description:\n \"DEV ONLY. List every table and view in the full database (unscoped) with row counts. Use to see the whole data model before reading or editing rows.\",\n parameters: { type: \"object\", properties: {} },\n },\n readOnly: true,\n run: async () => JSON.stringify(await listTables()),\n },\n\n \"db-admin-schema\": {\n tool: {\n description:\n \"DEV ONLY. Get the full schema for one table or view: columns, types, nullability, primary key, foreign keys, indexes, and row count.\",\n parameters: {\n type: \"object\",\n properties: {\n table: { type: \"string\", description: \"Table or view name\" },\n },\n required: [\"table\"],\n },\n },\n readOnly: true,\n run: async (args: Record<string, string>) =>\n JSON.stringify(await getTableSchema(String(args.table))),\n },\n\n \"db-admin-rows\": {\n tool: {\n description:\n \"DEV ONLY. Read rows from one table (unscoped) with pagination, sorting, and filters. Returns column metadata, the page of rows, and the total count.\",\n parameters: {\n type: \"object\",\n properties: {\n table: { type: \"string\", description: \"Table or view name\" },\n page: {\n type: \"string\",\n description: \"1-based page number (default 1)\",\n },\n pageSize: {\n type: \"string\",\n description: \"Rows per page (default 50, max 1000)\",\n },\n sort: {\n type: \"string\",\n description:\n 'JSON array of sort specs, e.g. \\'[{\"column\":\"created_at\",\"dir\":\"desc\"}]\\'',\n },\n filters: {\n type: \"string\",\n description:\n 'JSON array of filters, e.g. \\'[{\"column\":\"status\",\"op\":\"eq\",\"value\":\"draft\"}]\\'. Ops: eq, neq, lt, lte, gt, gte, like, ilike, in, is_null, not_null.',\n },\n },\n required: [\"table\"],\n },\n },\n readOnly: true,\n run: async (args: Record<string, string>) => {\n const result = await getRows(String(args.table), {\n page: Number(args.page) || 1,\n pageSize: Number(args.pageSize) || 50,\n sort: parseJson<DbAdminSort[]>(args.sort, \"sort\"),\n filters: parseJson<DbAdminFilter[]>(args.filters, \"filters\"),\n });\n return JSON.stringify(result);\n },\n },\n\n \"db-admin-mutate\": {\n tool: {\n description:\n 'DEV ONLY. Insert, update, and/or delete rows in one table (unscoped — full database access). PREFER THIS over db-exec/db-patch for any database-admin edit, and ALWAYS use it (not db-exec) for tables without owner_email/org_id columns — db-exec auto-scopes to the current user and will match 0 rows on unscoped tables. Pass `dryRun: \"true\"` to get the SQL without executing. Each update/delete must include a where clause.',\n parameters: {\n type: \"object\",\n properties: {\n table: { type: \"string\", description: \"Table name\" },\n inserts: {\n type: \"string\",\n description:\n 'JSON array of row objects to insert, e.g. \\'[{\"id\":\"1\",\"title\":\"Hi\"}]\\'',\n },\n updates: {\n type: \"string\",\n description:\n 'JSON array of {where, set} objects, e.g. \\'[{\"where\":{\"id\":\"1\"},\"set\":{\"title\":\"Bye\"}}]\\'',\n },\n deletes: {\n type: \"string\",\n description: 'JSON array of where objects, e.g. \\'[{\"id\":\"1\"}]\\'',\n },\n dryRun: {\n type: \"string\",\n description: 'Set to \"true\" to return SQL without executing',\n },\n },\n required: [\"table\"],\n },\n },\n run: async (args: Record<string, string>) => {\n const mutation: DbAdminMutation = {\n inserts: parseJson<Record<string, unknown>[]>(\n args.inserts,\n \"inserts\",\n ),\n updates: parseJson<\n { where: Record<string, unknown>; set: Record<string, unknown> }[]\n >(args.updates, \"updates\"),\n deletes: parseJson<Record<string, unknown>[]>(\n args.deletes,\n \"deletes\",\n ),\n dryRun: String(args.dryRun) === \"true\",\n };\n return JSON.stringify(\n await applyMutations(String(args.table), mutation),\n );\n },\n },\n\n \"db-admin-query\": {\n tool: {\n description:\n 'DEV ONLY. Run arbitrary SQL against the full database (unscoped). PREFER THIS over db-query/db-exec for database-admin work and for any table without owner_email/org_id scoping (the scoped tools match 0 rows on those). Bare SELECTs are auto-limited to 100 rows. Destructive statements (DROP / TRUNCATE / unscoped DELETE or UPDATE) require confirmDestructive: \"true\".',\n parameters: {\n type: \"object\",\n properties: {\n sql: { type: \"string\", description: \"SQL statement to run\" },\n params: {\n type: \"string\",\n description:\n \"Optional JSON array of positional bind args for ? placeholders\",\n },\n confirmDestructive: {\n type: \"string\",\n description: 'Set to \"true\" to allow destructive statements',\n },\n },\n required: [\"sql\"],\n },\n },\n run: async (args: Record<string, string>) => {\n try {\n const result = await runSql(\n String(args.sql),\n parseJson<unknown[]>(args.params, \"params\"),\n { confirmDestructive: String(args.confirmDestructive) === \"true\" },\n );\n return JSON.stringify(result);\n } catch (err) {\n if (err instanceof DbAdminConfirmRequiredError) {\n return JSON.stringify({ needsConfirm: true, error: err.message });\n }\n throw err;\n }\n },\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agent-tools.js","sourceRoot":"","sources":["../../src/db-admin/agent-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Dev-only agent tools for the database admin.\n *\n * These mirror the HTTP routes and call the SAME `operations.ts` functions, so\n * the agent can introspect and edit the full database during local development.\n * They are spread into the DEV actions surface ONLY (never `prodActions`) and\n * the dev surface itself is gated to dev + localhost upstream.\n *\n * Complex params (sort / filters / inserts / updates / deletes / params) are\n * accepted as JSON strings and parsed here, matching how the framework's other\n * structured CLI-style tools accept JSON-encoded arguments.\n */\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport {\n applyMutations,\n getRows,\n getTableSchema,\n listTables,\n runSql,\n DbAdminConfirmRequiredError,\n} from \"./operations.js\";\nimport type { DbAdminFilter, DbAdminMutation, DbAdminSort } from \"./types.js\";\n\nfunction parseJson<T>(value: unknown, field: string): T | undefined {\n if (value == null || value === \"\") return undefined;\n if (typeof value !== \"string\") return value as T;\n try {\n return JSON.parse(value) as T;\n } catch {\n throw new Error(\n `Invalid JSON for \"${field}\": ${String(value).slice(0, 200)}`,\n );\n }\n}\n\nexport function createDbAdminAgentTools(): Record<string, ActionEntry> {\n return {\n \"db-admin-tables\": {\n tool: {\n description:\n \"DEV ONLY. List every table and view in the full database (unscoped) with row counts. Use to see the whole data model before reading or editing rows.\",\n parameters: { type: \"object\", properties: {} },\n },\n readOnly: true,\n run: async () => JSON.stringify(await listTables()),\n },\n\n \"db-admin-schema\": {\n tool: {\n description:\n \"DEV ONLY. Get the full schema for one table or view: columns, types, nullability, primary key, foreign keys, indexes, and row count.\",\n parameters: {\n type: \"object\",\n properties: {\n table: { type: \"string\", description: \"Table or view name\" },\n },\n required: [\"table\"],\n },\n },\n readOnly: true,\n run: async (args: Record<string, string>) =>\n JSON.stringify(await getTableSchema(String(args.table))),\n },\n\n \"db-admin-rows\": {\n tool: {\n description:\n 'DEV ONLY. Read rows from one table (unscoped) with pagination, sorting, and filters. Large text/JSON cells are previewed by default; pass includeLargeCells: \"true\" only when you need the full value.',\n parameters: {\n type: \"object\",\n properties: {\n table: { type: \"string\", description: \"Table or view name\" },\n page: {\n type: \"string\",\n description: \"1-based page number (default 1)\",\n },\n pageSize: {\n type: \"string\",\n description: \"Rows per page (default 50, max 1000)\",\n },\n sort: {\n type: \"string\",\n description:\n 'JSON array of sort specs, e.g. \\'[{\"column\":\"created_at\",\"dir\":\"desc\"}]\\'',\n },\n filters: {\n type: \"string\",\n description:\n 'JSON array of filters, e.g. \\'[{\"column\":\"status\",\"op\":\"eq\",\"value\":\"draft\"}]\\'. Ops: eq, neq, lt, lte, gt, gte, like, ilike, in, is_null, not_null.',\n },\n includeLargeCells: {\n type: \"string\",\n description:\n 'Set to \"true\" to return full large text/JSON cells instead of previews.',\n },\n },\n required: [\"table\"],\n },\n },\n readOnly: true,\n run: async (args: Record<string, string>) => {\n const result = await getRows(String(args.table), {\n page: Number(args.page) || 1,\n pageSize: Number(args.pageSize) || 50,\n sort: parseJson<DbAdminSort[]>(args.sort, \"sort\"),\n filters: parseJson<DbAdminFilter[]>(args.filters, \"filters\"),\n includeLargeCells: String(args.includeLargeCells) === \"true\",\n });\n return JSON.stringify(result);\n },\n },\n\n \"db-admin-mutate\": {\n tool: {\n description:\n 'DEV ONLY. Insert, update, and/or delete rows in one table (unscoped — full database access). PREFER THIS over db-exec/db-patch for any database-admin edit, and ALWAYS use it (not db-exec) for tables without owner_email/org_id columns — db-exec auto-scopes to the current user and will match 0 rows on unscoped tables. Pass `dryRun: \"true\"` to get the SQL without executing. Each update/delete must include a where clause.',\n parameters: {\n type: \"object\",\n properties: {\n table: { type: \"string\", description: \"Table name\" },\n inserts: {\n type: \"string\",\n description:\n 'JSON array of row objects to insert, e.g. \\'[{\"id\":\"1\",\"title\":\"Hi\"}]\\'',\n },\n updates: {\n type: \"string\",\n description:\n 'JSON array of {where, set} objects, e.g. \\'[{\"where\":{\"id\":\"1\"},\"set\":{\"title\":\"Bye\"}}]\\'',\n },\n deletes: {\n type: \"string\",\n description: 'JSON array of where objects, e.g. \\'[{\"id\":\"1\"}]\\'',\n },\n dryRun: {\n type: \"string\",\n description: 'Set to \"true\" to return SQL without executing',\n },\n },\n required: [\"table\"],\n },\n },\n run: async (args: Record<string, string>) => {\n const mutation: DbAdminMutation = {\n inserts: parseJson<Record<string, unknown>[]>(\n args.inserts,\n \"inserts\",\n ),\n updates: parseJson<\n { where: Record<string, unknown>; set: Record<string, unknown> }[]\n >(args.updates, \"updates\"),\n deletes: parseJson<Record<string, unknown>[]>(\n args.deletes,\n \"deletes\",\n ),\n dryRun: String(args.dryRun) === \"true\",\n };\n return JSON.stringify(\n await applyMutations(String(args.table), mutation),\n );\n },\n },\n\n \"db-admin-query\": {\n tool: {\n description:\n 'DEV ONLY. Run arbitrary SQL against the full database (unscoped). PREFER this over db-query/db-exec for database-admin work and for tables without owner_email/org_id scoping. Bare SELECTs are auto-limited to 100 rows, and large string cells are truncated in the tool result. Destructive statements require confirmDestructive: \"true\".',\n parameters: {\n type: \"object\",\n properties: {\n sql: { type: \"string\", description: \"SQL statement to run\" },\n params: {\n type: \"string\",\n description:\n \"Optional JSON array of positional bind args for ? placeholders\",\n },\n confirmDestructive: {\n type: \"string\",\n description: 'Set to \"true\" to allow destructive statements',\n },\n },\n required: [\"sql\"],\n },\n },\n run: async (args: Record<string, string>) => {\n try {\n const result = await runSql(\n String(args.sql),\n parseJson<unknown[]>(args.params, \"params\"),\n { confirmDestructive: String(args.confirmDestructive) === \"true\" },\n );\n return JSON.stringify(result);\n } catch (err) {\n if (err instanceof DbAdminConfirmRequiredError) {\n return JSON.stringify({ needsConfirm: true, error: err.message });\n }\n throw err;\n }\n },\n },\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../src/db-admin/operations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,OAAO,EACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAEV,cAAc,EAId,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../src/db-admin/operations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,OAAO,EACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAEV,cAAc,EAId,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAWpB,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAgJD,wBAAsB,UAAU,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC;IAClE,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,mBAAmB,EAAE,CAAC;CAC/B,CAAC,CAwCD;AAuBD,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,kBAAkB,CAAC,CAK7B;AA+RD,wBAAsB,OAAO,CAC3B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,kBAAkB,EACvB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,iBAAiB,CAAC,CAmC5B;AA6DD,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EACb,CAAC,EAAE,eAAe,EAClB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,qBAAqB,CAAC,CA+ChC;AAMD,6EAA6E;AAC7E,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,QAAQ,CAAC,YAAY,QAAQ;IAC7B,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAmCD,wBAAsB,MAAM,CAC1B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,OAAO,EAAE,GAAG,SAAS,EAC7B,IAAI,GAAE;IAAE,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAO,EAC3C,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,kBAAkB,CAAC,CA2C7B"}
|
|
@@ -19,6 +19,8 @@ import { notifyActionChange } from "../server/action-change.js";
|
|
|
19
19
|
// Identifier validation + quoting
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
21
|
const IDENT_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
22
|
+
const LARGE_CELL_PREVIEW_CHARS = 16 * 1024;
|
|
23
|
+
const LARGE_CELL_SUFFIX = "\n...[db-admin truncated large cell; request includeLargeCells=true for the full value]";
|
|
22
24
|
/** Throw on any identifier that isn't a plain `[A-Za-z_][A-Za-z0-9_]*`. */
|
|
23
25
|
function assertIdent(name, kind = "identifier") {
|
|
24
26
|
if (typeof name !== "string" || !IDENT_RE.test(name)) {
|
|
@@ -39,6 +41,80 @@ function dialect(runtime) {
|
|
|
39
41
|
function isPostgresRuntime(runtime) {
|
|
40
42
|
return dialect(runtime) === "postgres";
|
|
41
43
|
}
|
|
44
|
+
function isPreviewableLargeColumn(column) {
|
|
45
|
+
const type = column.type.toLowerCase();
|
|
46
|
+
return /\b(text|char|varchar|character|jsonb?|xml|clob)\b/.test(type);
|
|
47
|
+
}
|
|
48
|
+
function markLargeValuePreviewColumns(columns, includeLargeCells) {
|
|
49
|
+
if (includeLargeCells)
|
|
50
|
+
return columns;
|
|
51
|
+
return columns.map((column) => isPreviewableLargeColumn(column)
|
|
52
|
+
? { ...column, largeValuePreview: true }
|
|
53
|
+
: column);
|
|
54
|
+
}
|
|
55
|
+
function buildRowsSelectList(columns, includeLargeCells) {
|
|
56
|
+
if (includeLargeCells) {
|
|
57
|
+
return columns.map((column) => quoteIdent(column.name)).join(", ");
|
|
58
|
+
}
|
|
59
|
+
return columns
|
|
60
|
+
.map((column) => {
|
|
61
|
+
const quoted = quoteIdent(column.name);
|
|
62
|
+
if (!isPreviewableLargeColumn(column))
|
|
63
|
+
return quoted;
|
|
64
|
+
const textValue = `CAST(${quoted} AS TEXT)`;
|
|
65
|
+
return `CASE WHEN length(${textValue}) > ${LARGE_CELL_PREVIEW_CHARS} THEN substr(${textValue}, 1, ${LARGE_CELL_PREVIEW_CHARS}) || '${LARGE_CELL_SUFFIX.replace(/'/g, "''")}' ELSE ${textValue} END AS ${quoted}`;
|
|
66
|
+
})
|
|
67
|
+
.join(", ");
|
|
68
|
+
}
|
|
69
|
+
function truncateLargeResultCells(rows) {
|
|
70
|
+
let truncatedCells = 0;
|
|
71
|
+
const mapped = rows.map((row) => {
|
|
72
|
+
let changed = false;
|
|
73
|
+
const next = {};
|
|
74
|
+
for (const [key, value] of Object.entries(row)) {
|
|
75
|
+
if (typeof value === "string" &&
|
|
76
|
+
value.length > LARGE_CELL_PREVIEW_CHARS) {
|
|
77
|
+
next[key] =
|
|
78
|
+
`${value.slice(0, LARGE_CELL_PREVIEW_CHARS)}${LARGE_CELL_SUFFIX}`;
|
|
79
|
+
truncatedCells += 1;
|
|
80
|
+
changed = true;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
next[key] = value;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return changed ? next : row;
|
|
87
|
+
});
|
|
88
|
+
return { rows: mapped, truncatedCells };
|
|
89
|
+
}
|
|
90
|
+
function countTruncatedResultCells(rows) {
|
|
91
|
+
let truncatedCells = 0;
|
|
92
|
+
for (const row of rows) {
|
|
93
|
+
for (const value of Object.values(row)) {
|
|
94
|
+
if (typeof value === "string" && value.endsWith(LARGE_CELL_SUFFIX)) {
|
|
95
|
+
truncatedCells += 1;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return truncatedCells;
|
|
100
|
+
}
|
|
101
|
+
function containsLargeCellPreview(value) {
|
|
102
|
+
if (typeof value === "string")
|
|
103
|
+
return value.endsWith(LARGE_CELL_SUFFIX);
|
|
104
|
+
if (Array.isArray(value))
|
|
105
|
+
return value.some(containsLargeCellPreview);
|
|
106
|
+
if (value && typeof value === "object") {
|
|
107
|
+
return Object.values(value).some(containsLargeCellPreview);
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
function assertNoLargeCellPreviewMutation(row, context) {
|
|
112
|
+
for (const [column, value] of Object.entries(row)) {
|
|
113
|
+
if (containsLargeCellPreview(value)) {
|
|
114
|
+
throw new Error(`Refusing to ${context} with previewed large-cell value in column "${column}". Reload the row with includeLargeCells=true before saving.`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
42
118
|
// ---------------------------------------------------------------------------
|
|
43
119
|
// Notify the UI after a real mutation so polling refetches.
|
|
44
120
|
// ---------------------------------------------------------------------------
|
|
@@ -370,21 +446,25 @@ export async function getRows(table, req, runtime) {
|
|
|
370
446
|
const where = buildWhere(req.filters, runtime);
|
|
371
447
|
const orderBy = buildOrderBy(req.sort);
|
|
372
448
|
const quoted = quoteIdent(table);
|
|
449
|
+
const includeLargeCells = req.includeLargeCells === true;
|
|
450
|
+
const selectList = buildRowsSelectList(schema.columns, includeLargeCells);
|
|
373
451
|
const countRes = await client.execute({
|
|
374
452
|
sql: `SELECT COUNT(*) AS c FROM ${quoted}${where.clause}`,
|
|
375
453
|
args: where.args,
|
|
376
454
|
});
|
|
377
455
|
const total = Number(countRes.rows[0]?.c ?? 0) || 0;
|
|
378
456
|
const rowsRes = await client.execute({
|
|
379
|
-
sql: `SELECT
|
|
457
|
+
sql: `SELECT ${selectList} FROM ${quoted}${where.clause}${orderBy} LIMIT ? OFFSET ?`,
|
|
380
458
|
args: [...where.args, pageSize, offset],
|
|
381
459
|
});
|
|
460
|
+
const rows = rowsRes.rows;
|
|
382
461
|
return {
|
|
383
|
-
columns: schema.columns,
|
|
384
|
-
rows
|
|
462
|
+
columns: markLargeValuePreviewColumns(schema.columns, includeLargeCells),
|
|
463
|
+
rows,
|
|
385
464
|
total,
|
|
386
465
|
page,
|
|
387
466
|
pageSize,
|
|
467
|
+
truncatedCells: includeLargeCells ? 0 : countTruncatedResultCells(rows),
|
|
388
468
|
};
|
|
389
469
|
}
|
|
390
470
|
// ---------------------------------------------------------------------------
|
|
@@ -395,6 +475,7 @@ function buildInsert(table, row) {
|
|
|
395
475
|
if (cols.length === 0) {
|
|
396
476
|
throw new Error("Cannot insert an empty row");
|
|
397
477
|
}
|
|
478
|
+
assertNoLargeCellPreviewMutation(row, "insert");
|
|
398
479
|
cols.forEach((c) => assertIdent(c, "column name"));
|
|
399
480
|
const sql = `INSERT INTO ${quoteIdent(table)} (${cols
|
|
400
481
|
.map(quoteIdent)
|
|
@@ -409,6 +490,8 @@ function buildUpdate(table, set, where) {
|
|
|
409
490
|
if (whereCols.length === 0) {
|
|
410
491
|
throw new Error("Update requires a non-empty where clause");
|
|
411
492
|
}
|
|
493
|
+
assertNoLargeCellPreviewMutation(set, "update");
|
|
494
|
+
assertNoLargeCellPreviewMutation(where, "match rows");
|
|
412
495
|
setCols.forEach((c) => assertIdent(c, "column name"));
|
|
413
496
|
whereCols.forEach((c) => assertIdent(c, "column name"));
|
|
414
497
|
const setSql = setCols.map((c) => `${quoteIdent(c)} = ?`).join(", ");
|
|
@@ -424,6 +507,7 @@ function buildDelete(table, where) {
|
|
|
424
507
|
if (whereCols.length === 0) {
|
|
425
508
|
throw new Error("Delete requires a non-empty where clause");
|
|
426
509
|
}
|
|
510
|
+
assertNoLargeCellPreviewMutation(where, "delete");
|
|
427
511
|
whereCols.forEach((c) => assertIdent(c, "column name"));
|
|
428
512
|
const whereSql = whereCols.map((c) => `${quoteIdent(c)} = ?`).join(" AND ");
|
|
429
513
|
const sql = `DELETE FROM ${quoteIdent(table)} WHERE ${whereSql}`;
|
|
@@ -536,7 +620,8 @@ export async function runSql(sql, params, opts = {}, runtime) {
|
|
|
536
620
|
const started = Date.now();
|
|
537
621
|
const res = await client.execute(params && params.length > 0 ? { sql: finalSql, args: params } : finalSql);
|
|
538
622
|
const durationMs = Date.now() - started;
|
|
539
|
-
const
|
|
623
|
+
const truncation = truncateLargeResultCells((res.rows ?? []));
|
|
624
|
+
const rows = truncation.rows;
|
|
540
625
|
const columns = rows.length > 0 && rows[0] && typeof rows[0] === "object"
|
|
541
626
|
? Object.keys(rows[0])
|
|
542
627
|
: [];
|
|
@@ -547,6 +632,7 @@ export async function runSql(sql, params, opts = {}, runtime) {
|
|
|
547
632
|
rows,
|
|
548
633
|
rowsAffected: res.rowsAffected ?? 0,
|
|
549
634
|
durationMs,
|
|
635
|
+
truncatedCells: truncation.truncatedCells,
|
|
550
636
|
};
|
|
551
637
|
}
|
|
552
638
|
//# sourceMappingURL=operations.js.map
|