@agent-native/core 0.120.2 → 0.120.3
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 +3 -3
- package/corpus/core/CHANGELOG.md +20 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/context-xray-local.ts +1 -1
- package/corpus/core/src/cli/index.ts +63 -18
- package/corpus/core/src/cli/skills.ts +5 -0
- package/corpus/core/src/cli/telemetry.ts +118 -1
- package/corpus/core/src/client/AgentPanel.tsx +10 -0
- package/corpus/core/src/client/CommandMenu.tsx +13 -1
- package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +39 -4
- package/corpus/core/src/client/analytics.ts +13 -0
- package/corpus/core/src/client/error-capture.ts +6 -1
- package/corpus/core/src/client/extensions/ExtensionsListPage.tsx +12 -5
- package/corpus/core/src/client/extensions/agent-native-extension-runtime.ts +1 -1
- package/corpus/core/src/client/navigation/index.ts +2 -0
- package/corpus/core/src/client/org/OrgSwitcher.tsx +14 -32
- package/corpus/core/src/client/settings/ExtensionsSettingsContent.tsx +1 -1
- package/corpus/core/src/extensions/theme.ts +1 -1
- package/corpus/core/src/localization/default-messages.ts +2 -0
- package/corpus/core/src/server/core-routes-plugin.ts +10 -1
- package/corpus/core/src/server/framework-request-handler.ts +17 -26
- package/corpus/core/src/styles/agent-native.css +13 -0
- package/corpus/core/src/templates/chat/app/components/layout/Layout.tsx +3 -0
- package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +78 -45
- package/corpus/core/src/templates/chat/app/global.css +1 -1
- package/corpus/core/src/templates/default/app/global.css +1 -1
- package/corpus/core/src/tracking/error-capture.ts +151 -0
- package/corpus/core/src/tracking/index.ts +5 -0
- package/corpus/templates/analytics/app/components/dashboard/CumulativeNetChart.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +1 -4
- package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/DataTable.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/DateRangePicker.tsx +2 -2
- package/corpus/templates/analytics/app/components/dashboard/MetricCard.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/RecentActivity.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/RevenueChart.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/RevenueComparisonChart.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +41 -9
- package/corpus/templates/analytics/app/components/dashboard/StatsCard.tsx +1 -1
- package/corpus/templates/analytics/app/components/dashboard/TimeSeriesChart.tsx +1 -1
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +2 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +28 -14
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +152 -124
- package/corpus/templates/analytics/app/global.css +5 -5
- package/corpus/templates/analytics/app/lib/dashboard-report-capture.ts +42 -0
- package/corpus/templates/analytics/app/pages/adhoc/_shared/KpiChart.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/ChartTypePicker.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/DateRangePicker.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/EventRow.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/SqlPreview.tsx +2 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +3 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/EmailReportDialog.tsx +2 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +162 -51
- package/corpus/templates/analytics/app/root.tsx +28 -0
- package/corpus/templates/analytics/changelog/2026-07-24-analytics-charts-now-explain-slow-loads-and-offer-a-direct-r.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-24-daily-dashboard-emails-now-load-signed-reports-more-reliably.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-24-manage-agent-is-clearly-marked-as-a-link-to-its-dedicated-pa.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +1 -1
- package/corpus/templates/analytics/server/db/schema.ts +5 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +21 -0
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +11 -0
- package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +54 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +235 -26
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +4 -1
- package/corpus/templates/analytics/server/plugins/db.ts +9 -0
- package/corpus/templates/analytics/shared/dashboard-report-timeouts.ts +1 -1
- package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +376 -0
- package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +14 -4
- package/corpus/templates/assets/app/components/layout/Layout.tsx +5 -0
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +118 -74
- package/corpus/templates/assets/app/global.css +1 -1
- package/corpus/templates/assets/app/i18n-data.ts +10 -0
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +99 -10
- package/corpus/templates/assets/app/routes/library.tsx +21 -198
- package/corpus/templates/assets/changelog/2026-07-21-unified-asset-preview-click-any-asset-to-open-one-preview-wi.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/brain/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +76 -43
- package/corpus/templates/brain/app/global.css +1 -1
- package/corpus/templates/brain/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +67 -52
- package/corpus/templates/calendar/app/global.css +1 -1
- package/corpus/templates/calendar/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/calendar/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/chat/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +78 -45
- package/corpus/templates/chat/app/global.css +1 -1
- package/corpus/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +65 -31
- package/corpus/templates/clips/app/components/library/organization-switcher.tsx +2 -2
- package/corpus/templates/clips/app/components/player/video-player.tsx +16 -1
- package/corpus/templates/clips/app/global.css +1 -1
- package/corpus/templates/clips/app/hooks/use-view-tracking.ts +55 -12
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +6 -5
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +7 -7
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -5
- package/corpus/templates/clips/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/clips/server/plugins/db.ts +113 -68
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +66 -42
- package/corpus/templates/content/app/global.css +1 -1
- package/corpus/templates/content/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/content/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +65 -30
- package/corpus/templates/design/app/entry.client.tsx +14 -1
- package/corpus/templates/design/app/global.css +1 -1
- package/corpus/templates/design/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/design/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/dispatch/app/global.css +1 -1
- package/corpus/templates/dispatch/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/forms/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +72 -37
- package/corpus/templates/forms/app/global.css +1 -1
- package/corpus/templates/forms/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-24-forms-sidebar-actions-now-keep-search-language-feedback-and-.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/macros/app/components/DailyProgress.tsx +5 -5
- package/corpus/templates/macros/app/components/ExerciseCard.tsx +2 -2
- package/corpus/templates/macros/app/components/MealCard.tsx +2 -2
- package/corpus/templates/macros/app/components/WeightCard.tsx +2 -2
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +56 -29
- package/corpus/templates/macros/app/components/ui/button.tsx +1 -2
- package/corpus/templates/macros/app/components/ui/card.tsx +1 -1
- package/corpus/templates/macros/app/global.css +1 -1
- package/corpus/templates/macros/app/routes/_index.tsx +1 -1
- package/corpus/templates/macros/app/routes/analytics.tsx +4 -7
- package/corpus/templates/macros/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/macros/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +125 -37
- package/corpus/templates/mail/app/global.css +1 -1
- package/corpus/templates/mail/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/mail/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/plan/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +90 -60
- package/corpus/templates/plan/app/global.css +1 -1
- package/corpus/templates/plan/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +69 -32
- package/corpus/templates/slides/app/global.css +1 -1
- package/corpus/templates/slides/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/tasks/app/global.css +1 -1
- package/corpus/templates/tasks/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/toolkit/CHANGELOG.md +8 -0
- package/corpus/toolkit/README.md +8 -1
- package/corpus/toolkit/agent-native.eject.json +1 -1
- package/corpus/toolkit/package.json +1 -1
- package/corpus/toolkit/src/app-shell/index.ts +1 -0
- package/corpus/toolkit/src/app-shell/sidebar-footer-actions.tsx +48 -0
- package/corpus/toolkit/src/chat-history.css +52 -1
- package/corpus/toolkit/src/design-system/default-adapter.tsx +1 -1
- package/corpus/toolkit/src/ui/button.tsx +1 -2
- package/corpus/toolkit/src/ui/card.tsx +1 -1
- package/corpus/toolkit/src/ui/table.tsx +4 -11
- package/dist/cli/context-xray-local.js +1 -1
- package/dist/cli/context-xray-local.js.map +1 -1
- package/dist/cli/index.js +56 -17
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +5 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/telemetry.d.ts +7 -0
- package/dist/cli/telemetry.d.ts.map +1 -1
- package/dist/cli/telemetry.js +91 -1
- package/dist/cli/telemetry.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +7 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +2 -2
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/CommandMenu.d.ts +2 -0
- package/dist/client/CommandMenu.d.ts.map +1 -1
- package/dist/client/CommandMenu.js +12 -1
- package/dist/client/CommandMenu.js.map +1 -1
- package/dist/client/agent-page/AgentTabsPage.d.ts +4 -0
- package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -1
- package/dist/client/agent-page/AgentTabsPage.js +8 -4
- package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +7 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/error-capture.d.ts.map +1 -1
- package/dist/client/error-capture.js +8 -1
- package/dist/client/error-capture.js.map +1 -1
- package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionsListPage.js +2 -2
- package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
- package/dist/client/extensions/agent-native-extension-runtime.js +1 -1
- package/dist/client/extensions/agent-native-extension-runtime.js.map +1 -1
- package/dist/client/navigation/index.d.ts +1 -1
- package/dist/client/navigation/index.d.ts.map +1 -1
- package/dist/client/navigation/index.js +1 -1
- package/dist/client/navigation/index.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +9 -13
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/settings/ExtensionsSettingsContent.js +1 -1
- package/dist/client/settings/ExtensionsSettingsContent.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/extensions/theme.js +1 -1
- package/dist/extensions/theme.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/localization/default-messages.d.ts +2 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +2 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +8 -1
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +17 -27
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/styles/agent-native.css +13 -0
- package/dist/templates/chat/app/components/layout/Layout.tsx +3 -0
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +78 -45
- package/dist/templates/chat/app/global.css +1 -1
- package/dist/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/dist/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/dist/templates/default/app/global.css +1 -1
- package/dist/tracking/error-capture.d.ts +14 -0
- package/dist/tracking/error-capture.d.ts.map +1 -0
- package/dist/tracking/error-capture.js +113 -0
- package/dist/tracking/error-capture.js.map +1 -0
- package/dist/tracking/index.d.ts +1 -0
- package/dist/tracking/index.d.ts.map +1 -1
- package/dist/tracking/index.js +1 -0
- package/dist/tracking/index.js.map +1 -1
- package/package.json +2 -2
- package/src/cli/context-xray-local.ts +1 -1
- package/src/cli/index.ts +63 -18
- package/src/cli/skills.ts +5 -0
- package/src/cli/telemetry.ts +118 -1
- package/src/client/AgentPanel.tsx +10 -0
- package/src/client/CommandMenu.tsx +13 -1
- package/src/client/agent-page/AgentTabsPage.tsx +39 -4
- package/src/client/analytics.ts +13 -0
- package/src/client/error-capture.ts +6 -1
- package/src/client/extensions/ExtensionsListPage.tsx +12 -5
- package/src/client/extensions/agent-native-extension-runtime.ts +1 -1
- package/src/client/navigation/index.ts +2 -0
- package/src/client/org/OrgSwitcher.tsx +14 -32
- package/src/client/settings/ExtensionsSettingsContent.tsx +1 -1
- package/src/extensions/theme.ts +1 -1
- package/src/localization/default-messages.ts +2 -0
- package/src/server/core-routes-plugin.ts +10 -1
- package/src/server/framework-request-handler.ts +17 -26
- package/src/styles/agent-native.css +13 -0
- package/src/templates/chat/app/components/layout/Layout.tsx +3 -0
- package/src/templates/chat/app/components/layout/Sidebar.tsx +78 -45
- package/src/templates/chat/app/global.css +1 -1
- package/src/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/src/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/src/templates/default/app/global.css +1 -1
- package/src/tracking/error-capture.ts +151 -0
- package/src/tracking/index.ts +5 -0
|
@@ -15,9 +15,11 @@ export {
|
|
|
15
15
|
type UseSemanticNavigationStateResult,
|
|
16
16
|
} from "../route-state.js";
|
|
17
17
|
export {
|
|
18
|
+
COMMAND_MENU_OPEN_EVENT,
|
|
18
19
|
CommandMenu,
|
|
19
20
|
openAgentSidebar,
|
|
20
21
|
openAgentSettings,
|
|
22
|
+
openCommandMenu,
|
|
21
23
|
submitToAgent,
|
|
22
24
|
useCommandMenuShortcut,
|
|
23
25
|
type CommandMenuProps,
|
|
@@ -102,7 +102,7 @@ const APP_SUBMENU_CONTENT_CLASS =
|
|
|
102
102
|
"z-50 w-72 rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2";
|
|
103
103
|
|
|
104
104
|
const SWITCHER_BUTTON_CLASS =
|
|
105
|
-
"flex w-full items-center gap-2 rounded-md border
|
|
105
|
+
"flex w-full items-center gap-2 rounded-md border-0 bg-accent/50 px-2.5 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent/70 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-60 cursor-pointer";
|
|
106
106
|
|
|
107
107
|
const DEFAULT_ORGANIZATION_SETTINGS_PATH = "/settings#organization";
|
|
108
108
|
const DEFAULT_PROFILE_PATH = "/settings#account";
|
|
@@ -151,33 +151,29 @@ function AppMenuLink({
|
|
|
151
151
|
onNavigate: () => void;
|
|
152
152
|
}) {
|
|
153
153
|
const Icon = appMenuIcon(app);
|
|
154
|
+
const description =
|
|
155
|
+
app.status === "pending"
|
|
156
|
+
? "Building"
|
|
157
|
+
: app.description?.trim() ||
|
|
158
|
+
(app.isDispatch ? "Workspace hub" : `${app.name} workspace`);
|
|
154
159
|
return (
|
|
155
160
|
<a
|
|
156
161
|
href={app.href}
|
|
157
162
|
onClick={onNavigate}
|
|
158
|
-
className=
|
|
159
|
-
app.isDispatch ? "border border-primary/20 bg-primary/5" : ""
|
|
160
|
-
}`}
|
|
163
|
+
className="flex items-center gap-2 rounded-sm px-2.5 py-2 text-xs outline-none hover:bg-accent focus:bg-accent"
|
|
161
164
|
>
|
|
162
|
-
<span
|
|
163
|
-
className={`flex h-7 w-7 shrink-0 items-center justify-center rounded-md ${
|
|
164
|
-
app.isDispatch
|
|
165
|
-
? "bg-primary text-primary-foreground"
|
|
166
|
-
: "bg-muted text-muted-foreground"
|
|
167
|
-
}`}
|
|
168
|
-
>
|
|
165
|
+
<span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground">
|
|
169
166
|
<Icon className="h-3.5 w-3.5" />
|
|
170
167
|
</span>
|
|
171
168
|
<span className="min-w-0 flex-1">
|
|
172
169
|
<span className="block truncate font-medium text-foreground">
|
|
173
170
|
{app.name}
|
|
174
171
|
</span>
|
|
175
|
-
<span
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
: "Open app"}
|
|
172
|
+
<span
|
|
173
|
+
className="block truncate text-[11px] text-muted-foreground"
|
|
174
|
+
title={description}
|
|
175
|
+
>
|
|
176
|
+
{description}
|
|
181
177
|
</span>
|
|
182
178
|
</span>
|
|
183
179
|
<IconArrowUpRight className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
|
@@ -187,14 +183,12 @@ function AppMenuLink({
|
|
|
187
183
|
|
|
188
184
|
function AppsSubmenu({
|
|
189
185
|
apps,
|
|
190
|
-
isWorkspace,
|
|
191
186
|
isLoading,
|
|
192
187
|
dispatchHref,
|
|
193
188
|
dispatchAllAppsHref,
|
|
194
189
|
onNavigate,
|
|
195
190
|
}: {
|
|
196
191
|
apps: OrgSwitcherAppLink[];
|
|
197
|
-
isWorkspace: boolean;
|
|
198
192
|
isLoading: boolean;
|
|
199
193
|
dispatchHref: string;
|
|
200
194
|
dispatchAllAppsHref: string;
|
|
@@ -241,17 +235,6 @@ function AppsSubmenu({
|
|
|
241
235
|
collisionPadding={12}
|
|
242
236
|
className={APP_SUBMENU_CONTENT_CLASS}
|
|
243
237
|
>
|
|
244
|
-
<div className="px-2.5 py-1.5">
|
|
245
|
-
<div className="text-[10px] uppercase tracking-wide text-muted-foreground">
|
|
246
|
-
{isWorkspace ? "Workspace apps" : "Default apps"}
|
|
247
|
-
</div>
|
|
248
|
-
<div className="mt-0.5 text-[11px] text-muted-foreground">
|
|
249
|
-
{isWorkspace
|
|
250
|
-
? "Dispatch is the workspace hub."
|
|
251
|
-
: "Dispatch is the home base."}
|
|
252
|
-
</div>
|
|
253
|
-
</div>
|
|
254
|
-
|
|
255
238
|
<AppMenuLink app={dispatchApp} onNavigate={onNavigate} />
|
|
256
239
|
|
|
257
240
|
{visibleNonDispatch.length > 0 && (
|
|
@@ -269,7 +252,7 @@ function AppsSubmenu({
|
|
|
269
252
|
onClick={onNavigate}
|
|
270
253
|
className="flex items-center gap-2 rounded-sm px-2.5 py-1.5 text-xs text-foreground outline-none hover:bg-accent focus:bg-accent"
|
|
271
254
|
>
|
|
272
|
-
<
|
|
255
|
+
<IconApps className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
|
273
256
|
<span className="flex-1">
|
|
274
257
|
{`View ${remainingCount} more in Dispatch`}
|
|
275
258
|
</span>
|
|
@@ -549,7 +532,6 @@ export function OrgSwitcher({
|
|
|
549
532
|
<div className="my-1 h-px bg-border" />
|
|
550
533
|
<AppsSubmenu
|
|
551
534
|
apps={appLinks.apps}
|
|
552
|
-
isWorkspace={appLinks.isWorkspace}
|
|
553
535
|
isLoading={appLinks.isLoading}
|
|
554
536
|
dispatchHref={appLinks.dispatchHref}
|
|
555
537
|
dispatchAllAppsHref={appLinks.dispatchAllAppsHref}
|
|
@@ -9,7 +9,7 @@ const ExtensionsListPage = lazy(() =>
|
|
|
9
9
|
|
|
10
10
|
export function ExtensionsSettingsContent() {
|
|
11
11
|
return (
|
|
12
|
-
<div className="mx-auto w-full max-w-5xl
|
|
12
|
+
<div className="mx-auto w-full max-w-5xl">
|
|
13
13
|
<Suspense
|
|
14
14
|
fallback={
|
|
15
15
|
<div className="flex min-h-[28rem] items-center justify-center text-muted-foreground">
|
|
@@ -92,7 +92,7 @@ export function getThemeVars(_isDark?: boolean): string {
|
|
|
92
92
|
--muted-foreground: 240 5% 64.9%;
|
|
93
93
|
--accent: 240 3.7% 15.9%;
|
|
94
94
|
--accent-foreground: 0 0% 98%;
|
|
95
|
-
--destructive: 0
|
|
95
|
+
--destructive: 0 91% 71%;
|
|
96
96
|
--destructive-foreground: 0 0% 98%;
|
|
97
97
|
--border: 240 3.7% 15.9%;
|
|
98
98
|
--input: 240 3.7% 15.9%;
|
|
@@ -172,6 +172,7 @@ const messages = {
|
|
|
172
172
|
workspaceControlPlane: "Workspace control plane",
|
|
173
173
|
workspaceSubtitle_one: "Workspace · {{count}} app",
|
|
174
174
|
workspaceSubtitle_other: "Workspace · {{count}} apps",
|
|
175
|
+
search: "Search",
|
|
175
176
|
chats: "Chats",
|
|
176
177
|
newChat: "New chat",
|
|
177
178
|
newDispatchChat: "New Dispatch chat",
|
|
@@ -310,6 +311,7 @@ const messages = {
|
|
|
310
311
|
newTerminal: "New terminal",
|
|
311
312
|
panelOptions: "Agent panel options",
|
|
312
313
|
collapseSidebar: "Collapse sidebar",
|
|
314
|
+
expandSidebar: "Expand sidebar",
|
|
313
315
|
hideChats: "Hide chats",
|
|
314
316
|
allChats: "All chats",
|
|
315
317
|
settings: "Settings",
|
|
@@ -97,6 +97,7 @@ import {
|
|
|
97
97
|
MCP_EMBED_CORS_ALLOW_HEADERS,
|
|
98
98
|
shouldAllowMcpEmbedCredentials,
|
|
99
99
|
} from "../shared/mcp-embed-headers.js";
|
|
100
|
+
import { captureException } from "../tracking/error-capture.js";
|
|
100
101
|
import { track } from "../tracking/index.js";
|
|
101
102
|
import { registerBuiltinProviders } from "../tracking/providers.js";
|
|
102
103
|
import { validateTrackPayload } from "../tracking/route.js";
|
|
@@ -140,7 +141,7 @@ import {
|
|
|
140
141
|
type BuilderRelayCredentials,
|
|
141
142
|
type BuilderPreviewRelayState,
|
|
142
143
|
} from "./builder-browser.js";
|
|
143
|
-
import { captureError } from "./capture-error.js";
|
|
144
|
+
import { captureError, registerErrorCaptureProvider } from "./capture-error.js";
|
|
144
145
|
import {
|
|
145
146
|
getAllowedCorsOrigin,
|
|
146
147
|
readCorsAllowedOrigins,
|
|
@@ -1197,6 +1198,14 @@ export function createCoreRoutesPlugin(
|
|
|
1197
1198
|
// already registered the same key win.
|
|
1198
1199
|
registerFrameworkSecrets();
|
|
1199
1200
|
registerBuiltinProviders();
|
|
1201
|
+
registerErrorCaptureProvider("agent-native-analytics", (error, context) =>
|
|
1202
|
+
captureException(error, {
|
|
1203
|
+
...context,
|
|
1204
|
+
handled: false,
|
|
1205
|
+
runtime: "node",
|
|
1206
|
+
source: "server",
|
|
1207
|
+
}),
|
|
1208
|
+
);
|
|
1200
1209
|
registerBuiltinNotificationChannels();
|
|
1201
1210
|
|
|
1202
1211
|
try {
|
|
@@ -602,33 +602,24 @@ function registerMiddleware(
|
|
|
602
602
|
status,
|
|
603
603
|
error: err,
|
|
604
604
|
});
|
|
605
|
-
// Forward 5xx to server
|
|
606
|
-
// fire here because we convert the throw into a
|
|
607
|
-
// and a console.error alone is invisible in
|
|
608
|
-
// 4xx are user-input errors (validation, auth)
|
|
609
|
-
// alerting on.
|
|
610
|
-
// doesn't pull @sentry/node into bundles that don't need it.
|
|
605
|
+
// Forward 5xx to the configured server error providers — Nitro's own
|
|
606
|
+
// `error` hook may not fire here because we convert the throw into a
|
|
607
|
+
// normal JSON response, and a console.error alone is invisible in
|
|
608
|
+
// deployed environments. 4xx are user-input errors (validation, auth)
|
|
609
|
+
// and aren't worth alerting on.
|
|
611
610
|
if (status >= 500) {
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
return undefined;
|
|
625
|
-
}
|
|
626
|
-
})(),
|
|
627
|
-
});
|
|
628
|
-
})
|
|
629
|
-
.catch(() => {
|
|
630
|
-
// Sentry is observability — never let it break a response path.
|
|
631
|
-
});
|
|
611
|
+
captureError(err, {
|
|
612
|
+
route: reqPath,
|
|
613
|
+
method: event.method,
|
|
614
|
+
tags: { status_code: String(status) },
|
|
615
|
+
userAgent: (() => {
|
|
616
|
+
try {
|
|
617
|
+
return event.headers?.get("user-agent") ?? undefined;
|
|
618
|
+
} catch {
|
|
619
|
+
return undefined;
|
|
620
|
+
}
|
|
621
|
+
})(),
|
|
622
|
+
});
|
|
632
623
|
}
|
|
633
624
|
try {
|
|
634
625
|
setResponseStatus(event, status);
|
|
@@ -310,6 +310,10 @@
|
|
|
310
310
|
opacity: 1;
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
+
/* A named chat surface already morphs from its old geometry during a
|
|
314
|
+
full-page-chat handoff. Override only the initial style of that panel so it
|
|
315
|
+
does not slide in from the right underneath the morph. Keeping the normal
|
|
316
|
+
rules intact preserves ordinary sidebar open/close animation. */
|
|
313
317
|
@starting-style {
|
|
314
318
|
.agent-sidebar-panel[data-agent-sidebar-animation="desktop"][data-agent-sidebar-state="open"] {
|
|
315
319
|
width: 0;
|
|
@@ -330,6 +334,15 @@
|
|
|
330
334
|
.agent-sidebar-backdrop[data-agent-sidebar-animation="mobile"][data-agent-sidebar-state="open"] {
|
|
331
335
|
opacity: 0;
|
|
332
336
|
}
|
|
337
|
+
|
|
338
|
+
.agent-native-chat-view-transition.agent-sidebar-panel[data-agent-sidebar-animation="desktop"][data-agent-sidebar-chat-handoff="true"] {
|
|
339
|
+
width: var(--agent-sidebar-width);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.agent-native-chat-view-transition.agent-sidebar-panel[data-agent-sidebar-animation="desktop"][data-agent-sidebar-chat-handoff="true"]
|
|
343
|
+
> .agent-sidebar-panel-inner {
|
|
344
|
+
transform: translateX(0);
|
|
345
|
+
}
|
|
333
346
|
}
|
|
334
347
|
|
|
335
348
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AgentSidebar,
|
|
3
3
|
focusAgentChat,
|
|
4
|
+
isAgentChatHomeHandoffActive,
|
|
4
5
|
navigateWithAgentChatViewTransition,
|
|
5
6
|
useAgentChatHomeHandoff,
|
|
6
7
|
useAgentChatHomeHandoffLinks,
|
|
@@ -57,6 +58,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
57
58
|
activePath: location.pathname,
|
|
58
59
|
enabled: !isChatRoute,
|
|
59
60
|
});
|
|
61
|
+
const chatHomeHandoffPending = isAgentChatHomeHandoffActive("chat");
|
|
60
62
|
useAgentChatHomeHandoffLinks({
|
|
61
63
|
storageKey: "chat",
|
|
62
64
|
isChatPath: (pathname) => pathname === "/" || pathname.startsWith("/chat/"),
|
|
@@ -164,6 +166,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
164
166
|
<AgentSidebar
|
|
165
167
|
position="right"
|
|
166
168
|
chatViewTransition
|
|
169
|
+
chatViewTransitionHandoff={chatHomeHandoffPending}
|
|
167
170
|
storageKey="chat"
|
|
168
171
|
browserTabId={TAB_ID}
|
|
169
172
|
openOnChatRunning={chatHomeHandoffActive}
|
|
@@ -4,9 +4,11 @@ import {
|
|
|
4
4
|
type ChatThreadSummary,
|
|
5
5
|
} from "@agent-native/core/client/agent-chat";
|
|
6
6
|
import { appPath } from "@agent-native/core/client/api-path";
|
|
7
|
-
import { useT } from "@agent-native/core/client/i18n";
|
|
7
|
+
import { LanguagePicker, useT } from "@agent-native/core/client/i18n";
|
|
8
|
+
import { openCommandMenu } from "@agent-native/core/client/navigation";
|
|
8
9
|
import { OrgSwitcher } from "@agent-native/core/client/org";
|
|
9
10
|
import { FeedbackButton } from "@agent-native/core/client/ui";
|
|
11
|
+
import { SidebarFooterActions } from "@agent-native/toolkit/app-shell";
|
|
10
12
|
import {
|
|
11
13
|
ChatHistoryRail,
|
|
12
14
|
type ChatHistoryItem,
|
|
@@ -16,6 +18,7 @@ import {
|
|
|
16
18
|
IconLayoutSidebarLeftCollapse,
|
|
17
19
|
IconLayoutSidebarLeftExpand,
|
|
18
20
|
IconMessageCircle,
|
|
21
|
+
IconSearch,
|
|
19
22
|
IconSettings,
|
|
20
23
|
} from "@tabler/icons-react";
|
|
21
24
|
import { useEffect, useMemo } from "react";
|
|
@@ -126,7 +129,7 @@ function chatThreadPath(threadId: string) {
|
|
|
126
129
|
return `/chat/${encodeURIComponent(threadId)}`;
|
|
127
130
|
}
|
|
128
131
|
|
|
129
|
-
function ChatThreadsSection() {
|
|
132
|
+
function ChatThreadsSection({ open }: { open: boolean }) {
|
|
130
133
|
const navigate = useNavigate();
|
|
131
134
|
const location = useLocation();
|
|
132
135
|
const t = useT();
|
|
@@ -230,36 +233,42 @@ function ChatThreadsSection() {
|
|
|
230
233
|
}
|
|
231
234
|
|
|
232
235
|
return (
|
|
233
|
-
<div
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
236
|
+
<div
|
|
237
|
+
className="an-chat-history-rail__collapse"
|
|
238
|
+
data-state={open ? "open" : "closed"}
|
|
239
|
+
aria-hidden={!open}
|
|
240
|
+
>
|
|
241
|
+
<div className="ms-4">
|
|
242
|
+
<ChatHistoryRail
|
|
243
|
+
items={chatItems}
|
|
244
|
+
activeId={displayedActiveThreadId}
|
|
245
|
+
onSelect={(threadId) => openThread(threadId)}
|
|
246
|
+
onNewChat={() => void handleNewChat()}
|
|
247
|
+
railLabels={{
|
|
248
|
+
newChat: t("chat.newChat"),
|
|
249
|
+
showMore: t("chat.chats"),
|
|
250
|
+
showLess: t("chat.chats"),
|
|
251
|
+
}}
|
|
252
|
+
renameMaxLength={160}
|
|
253
|
+
onTogglePin={(threadId) => {
|
|
254
|
+
const thread = visibleThreads.find((item) => item.id === threadId);
|
|
255
|
+
if (thread) void pinThread(threadId, !thread.pinnedAt);
|
|
256
|
+
}}
|
|
257
|
+
onRename={handleRenameThread}
|
|
258
|
+
onDelete={(threadId) => void handleArchiveThread(threadId)}
|
|
259
|
+
labels={{
|
|
260
|
+
options: (item) =>
|
|
261
|
+
t("chat.optionsFor", { title: item.titleText ?? "" }),
|
|
262
|
+
renameInput: (item) =>
|
|
263
|
+
t("chat.renameThread", { title: item.titleText ?? "" }),
|
|
264
|
+
rename: t("chat.renameChat"),
|
|
265
|
+
pin: t("chat.pinChat"),
|
|
266
|
+
unpin: t("chat.unpinChat"),
|
|
267
|
+
delete: t("chat.archiveChat"),
|
|
268
|
+
}}
|
|
269
|
+
className="min-w-0"
|
|
270
|
+
/>
|
|
271
|
+
</div>
|
|
263
272
|
</div>
|
|
264
273
|
);
|
|
265
274
|
}
|
|
@@ -281,14 +290,14 @@ export function Sidebar({
|
|
|
281
290
|
cn(
|
|
282
291
|
"flex items-center text-sm transition-colors",
|
|
283
292
|
collapsed
|
|
284
|
-
? "relative h-10 w-full justify-center rounded-none
|
|
293
|
+
? "relative h-10 w-full justify-center rounded-none px-0"
|
|
285
294
|
: "h-9 rounded-md gap-3 px-3",
|
|
286
295
|
isActive
|
|
287
296
|
? collapsed
|
|
288
|
-
? "
|
|
297
|
+
? "bg-sidebar-accent text-sidebar-accent-foreground"
|
|
289
298
|
: "bg-sidebar-accent text-sidebar-accent-foreground"
|
|
290
299
|
: collapsed
|
|
291
|
-
? "
|
|
300
|
+
? "text-sidebar-foreground/70 hover:bg-sidebar-accent/55 hover:text-sidebar-accent-foreground"
|
|
292
301
|
: "text-sidebar-foreground hover:bg-sidebar-accent/65 hover:text-sidebar-accent-foreground",
|
|
293
302
|
);
|
|
294
303
|
const collapseButton = collapsible ? (
|
|
@@ -317,6 +326,31 @@ export function Sidebar({
|
|
|
317
326
|
</TooltipContent>
|
|
318
327
|
</Tooltip>
|
|
319
328
|
) : null;
|
|
329
|
+
const searchButton = (
|
|
330
|
+
<Tooltip>
|
|
331
|
+
<TooltipTrigger asChild>
|
|
332
|
+
<button
|
|
333
|
+
type="button"
|
|
334
|
+
onClick={openCommandMenu}
|
|
335
|
+
aria-label={t("root.commandSearch")}
|
|
336
|
+
className="flex size-8 items-center justify-center rounded-md text-sidebar-foreground/65 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
337
|
+
>
|
|
338
|
+
<IconSearch className="size-4" />
|
|
339
|
+
</button>
|
|
340
|
+
</TooltipTrigger>
|
|
341
|
+
<TooltipContent side="right">{t("root.commandSearch")}</TooltipContent>
|
|
342
|
+
</Tooltip>
|
|
343
|
+
);
|
|
344
|
+
const translateButton = (
|
|
345
|
+
<LanguagePicker variant="ghost-icon" label={t("settings.languageLabel")} />
|
|
346
|
+
);
|
|
347
|
+
const feedbackButton = (
|
|
348
|
+
<FeedbackButton
|
|
349
|
+
variant={collapsed ? "icon" : "sidebar"}
|
|
350
|
+
side="right"
|
|
351
|
+
className={collapsed ? "h-8 w-8" : "min-w-0"}
|
|
352
|
+
/>
|
|
353
|
+
);
|
|
320
354
|
|
|
321
355
|
return (
|
|
322
356
|
<aside
|
|
@@ -411,8 +445,8 @@ export function Sidebar({
|
|
|
411
445
|
) : (
|
|
412
446
|
link
|
|
413
447
|
)}
|
|
414
|
-
{!collapsed && item.view === "chat"
|
|
415
|
-
<ChatThreadsSection />
|
|
448
|
+
{!collapsed && item.view === "chat" ? (
|
|
449
|
+
<ChatThreadsSection open={isChatRoute} />
|
|
416
450
|
) : null}
|
|
417
451
|
</div>
|
|
418
452
|
);
|
|
@@ -465,14 +499,13 @@ export function Sidebar({
|
|
|
465
499
|
/>
|
|
466
500
|
</div>
|
|
467
501
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
) : null}
|
|
502
|
+
<SidebarFooterActions
|
|
503
|
+
collapsed={collapsed}
|
|
504
|
+
feedback={feedbackButton}
|
|
505
|
+
translate={translateButton}
|
|
506
|
+
search={searchButton}
|
|
507
|
+
collapse={collapseButton}
|
|
508
|
+
/>
|
|
476
509
|
</div>
|
|
477
510
|
</aside>
|
|
478
511
|
);
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { trackingIdentityProperties } from "../observability/tracking-identity.js";
|
|
2
|
+
import type { CaptureErrorContext } from "../server/capture-error.js";
|
|
3
|
+
import { track } from "./registry.js";
|
|
4
|
+
|
|
5
|
+
export type TrackingExceptionLevel =
|
|
6
|
+
| "fatal"
|
|
7
|
+
| "error"
|
|
8
|
+
| "warning"
|
|
9
|
+
| "info"
|
|
10
|
+
| "debug";
|
|
11
|
+
|
|
12
|
+
export interface TrackingExceptionContext extends CaptureErrorContext {
|
|
13
|
+
/** Whether the caller handled the error. Server error hooks default false. */
|
|
14
|
+
handled?: boolean;
|
|
15
|
+
level?: TrackingExceptionLevel;
|
|
16
|
+
release?: string;
|
|
17
|
+
environment?: string;
|
|
18
|
+
runtime?: "node" | "cli";
|
|
19
|
+
source?: "server" | "cli";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const MAX_MESSAGE_LENGTH = 1000;
|
|
23
|
+
const MAX_STACK_LENGTH = 8000;
|
|
24
|
+
const MAX_TAGS = 30;
|
|
25
|
+
const MAX_EXTRA_KEYS = 30;
|
|
26
|
+
const MAX_EXTRA_VALUE_LENGTH = 1000;
|
|
27
|
+
const SECRET_RE = /\b(?:bearer|basic)\s+[^\s]+/gi;
|
|
28
|
+
const SECRET_KEY_RE =
|
|
29
|
+
/(?:authorization|cookie|set[-_]?cookie|token|secret|password|passwd|pwd|api[-_]?key|apikey|credential)/i;
|
|
30
|
+
|
|
31
|
+
function redact(value: string): string {
|
|
32
|
+
return value
|
|
33
|
+
.replace(SECRET_RE, (match) => `${match.split(/\s+/, 1)[0]} <redacted>`)
|
|
34
|
+
.replace(
|
|
35
|
+
/([A-Za-z0-9_$.-]*(?:authorization|cookie|token|secret|password|passwd|pwd|api[-_]?key|apikey|credential)[A-Za-z0-9_$.-]*\s*[:=]\s*)([^\s,;}]+)/gi,
|
|
36
|
+
"$1<redacted>",
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function boundedText(value: unknown, max: number): string {
|
|
41
|
+
const text = typeof value === "string" ? value : String(value ?? "");
|
|
42
|
+
const safe = redact(text);
|
|
43
|
+
return safe.length > max ? safe.slice(0, max) : safe;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function safeValue(value: unknown, depth = 2): unknown {
|
|
47
|
+
if (
|
|
48
|
+
value == null ||
|
|
49
|
+
typeof value === "boolean" ||
|
|
50
|
+
typeof value === "number"
|
|
51
|
+
) {
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
if (typeof value === "string")
|
|
55
|
+
return boundedText(value, MAX_EXTRA_VALUE_LENGTH);
|
|
56
|
+
if (depth <= 0) return boundedText(value, MAX_EXTRA_VALUE_LENGTH);
|
|
57
|
+
if (Array.isArray(value)) {
|
|
58
|
+
return value.slice(0, 20).map((item) => safeValue(item, depth - 1));
|
|
59
|
+
}
|
|
60
|
+
if (typeof value === "object") {
|
|
61
|
+
const out: Record<string, unknown> = {};
|
|
62
|
+
for (const [key, child] of Object.entries(value)) {
|
|
63
|
+
if (Object.keys(out).length >= MAX_EXTRA_KEYS) break;
|
|
64
|
+
const safeKey = boundedText(key, 100);
|
|
65
|
+
out[safeKey] = SECRET_KEY_RE.test(safeKey)
|
|
66
|
+
? "<redacted>"
|
|
67
|
+
: safeValue(child, depth - 1);
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
return boundedText(value, MAX_EXTRA_VALUE_LENGTH);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function exceptionParts(error: unknown): {
|
|
75
|
+
type: string;
|
|
76
|
+
message: string;
|
|
77
|
+
stack?: string;
|
|
78
|
+
} {
|
|
79
|
+
if (error instanceof Error) {
|
|
80
|
+
return {
|
|
81
|
+
type: boundedText(error.name || "Error", 200),
|
|
82
|
+
message: boundedText(
|
|
83
|
+
error.message || error.name || "Error",
|
|
84
|
+
MAX_MESSAGE_LENGTH,
|
|
85
|
+
),
|
|
86
|
+
...(error.stack
|
|
87
|
+
? { stack: boundedText(error.stack, MAX_STACK_LENGTH) }
|
|
88
|
+
: {}),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
type: "Error",
|
|
93
|
+
message: boundedText(error, MAX_MESSAGE_LENGTH),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function safeTags(
|
|
98
|
+
tags: Record<string, string | undefined> | undefined,
|
|
99
|
+
): Record<string, string> {
|
|
100
|
+
const out: Record<string, string> = {};
|
|
101
|
+
for (const [key, value] of Object.entries(tags ?? {})) {
|
|
102
|
+
if (Object.keys(out).length >= MAX_TAGS || value == null) break;
|
|
103
|
+
const safeKey = boundedText(key, 100);
|
|
104
|
+
out[safeKey] = SECRET_KEY_RE.test(safeKey)
|
|
105
|
+
? "<redacted>"
|
|
106
|
+
: boundedText(value, 200);
|
|
107
|
+
}
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Emit a bounded, redacted Node/CLI exception through first-party tracking. */
|
|
112
|
+
export function captureException(
|
|
113
|
+
error: unknown,
|
|
114
|
+
context: TrackingExceptionContext = {},
|
|
115
|
+
): void {
|
|
116
|
+
try {
|
|
117
|
+
const parts = exceptionParts(error);
|
|
118
|
+
const tags = safeTags({
|
|
119
|
+
...context.tags,
|
|
120
|
+
...(context.route ? { route: context.route } : {}),
|
|
121
|
+
...(context.method ? { method: context.method } : {}),
|
|
122
|
+
...(context.userAgent ? { userAgent: context.userAgent } : {}),
|
|
123
|
+
});
|
|
124
|
+
const extra = safeValue({
|
|
125
|
+
...context.extra,
|
|
126
|
+
...(context.contexts ? { contexts: context.contexts } : {}),
|
|
127
|
+
});
|
|
128
|
+
track("$exception", {
|
|
129
|
+
...trackingIdentityProperties(),
|
|
130
|
+
exceptionType: parts.type,
|
|
131
|
+
exceptionMessage: parts.message,
|
|
132
|
+
...(parts.stack ? { exceptionStack: parts.stack } : {}),
|
|
133
|
+
handled: context.handled ?? true,
|
|
134
|
+
level: context.level ?? "error",
|
|
135
|
+
occurredAt: new Date().toISOString(),
|
|
136
|
+
runtime: context.runtime ?? "node",
|
|
137
|
+
source: context.source ?? "server",
|
|
138
|
+
...(context.route ? { url: boundedText(context.route, 500) } : {}),
|
|
139
|
+
...(context.release
|
|
140
|
+
? { release: boundedText(context.release, 200) }
|
|
141
|
+
: {}),
|
|
142
|
+
...(context.environment
|
|
143
|
+
? { environment: boundedText(context.environment, 100) }
|
|
144
|
+
: {}),
|
|
145
|
+
...(Object.keys(tags).length ? { exceptionTags: tags } : {}),
|
|
146
|
+
...(extra && typeof extra === "object" ? { exceptionExtra: extra } : {}),
|
|
147
|
+
});
|
|
148
|
+
} catch {
|
|
149
|
+
// Error reporting must never mask the original failure.
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -7,4 +7,9 @@ export {
|
|
|
7
7
|
listTrackingProviders,
|
|
8
8
|
} from "./registry.js";
|
|
9
9
|
export { registerBuiltinProviders } from "./providers.js";
|
|
10
|
+
export {
|
|
11
|
+
captureException,
|
|
12
|
+
type TrackingExceptionContext,
|
|
13
|
+
type TrackingExceptionLevel,
|
|
14
|
+
} from "./error-capture.js";
|
|
10
15
|
export type { TrackingProvider, TrackingEvent } from "./types.js";
|
|
@@ -52,7 +52,7 @@ export function CumulativeNetChart({
|
|
|
52
52
|
const color = isPositive ? "#10b981" : "#ef4444";
|
|
53
53
|
|
|
54
54
|
return (
|
|
55
|
-
<Card className="bg-card
|
|
55
|
+
<Card className="bg-card">
|
|
56
56
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
57
57
|
<CardTitle className="text-base">{title}</CardTitle>
|
|
58
58
|
</CardHeader>
|