@agent-native/core 0.69.0 → 0.70.1
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/README.md +15 -15
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +109 -0
- package/corpus/core/docs/design/durable-agent-runs.md +217 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/action.ts +89 -0
- package/corpus/core/src/agent/model-config.ts +0 -2
- package/corpus/core/src/agent/run-loop-with-resume.ts +48 -0
- package/corpus/core/src/changelog/parse.ts +245 -0
- package/corpus/core/src/cli/changelog.ts +199 -0
- package/corpus/core/src/cli/index.ts +19 -0
- package/corpus/core/src/cli/recap.ts +24 -1
- package/corpus/core/src/cli/skills.ts +74 -47
- package/corpus/core/src/client/AgentPanel.tsx +5 -3
- package/corpus/core/src/client/AssistantChat.tsx +8 -0
- package/corpus/core/src/client/CommandMenu.tsx +183 -75
- package/corpus/core/src/client/agent-chat-adapter.ts +44 -7
- package/corpus/core/src/client/analytics.ts +181 -0
- package/corpus/core/src/client/changelog/Changelog.tsx +321 -0
- package/corpus/core/src/client/client-surface.ts +41 -0
- package/corpus/core/src/client/composer/TiptapComposer.tsx +123 -12
- package/corpus/core/src/client/feedback-context.ts +4 -0
- package/corpus/core/src/client/index.ts +12 -0
- package/corpus/core/src/client/mcp-apps/McpAppRenderer.tsx +54 -0
- package/corpus/core/src/client/settings/useBuilderStatus.ts +82 -20
- package/corpus/core/src/client/sse-event-processor.ts +7 -1
- package/corpus/core/src/mcp/build-server.ts +57 -1
- package/corpus/core/src/mcp/embed-app.ts +197 -7
- package/corpus/core/src/mcp/oauth-route.ts +109 -13
- package/corpus/core/src/server/attribution.ts +211 -0
- package/corpus/core/src/server/auth.ts +6 -0
- package/corpus/core/src/server/better-auth-instance.ts +49 -5
- package/corpus/core/src/server/builder-browser.ts +27 -1
- package/corpus/core/src/server/core-routes-plugin.ts +136 -0
- package/corpus/core/src/server/google-oauth.ts +19 -6
- package/corpus/core/src/server/onboarding-html.ts +35 -0
- package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
- package/corpus/core/src/styles/agent-conversation.css +21 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +22 -0
- package/corpus/templates/analytics/AGENTS.md +8 -1
- package/corpus/templates/analytics/CHANGELOG.md +10 -0
- package/corpus/templates/analytics/actions/install-dashboard-template.ts +99 -4
- package/corpus/templates/analytics/actions/open-traffic-dashboard.ts +1 -1
- package/corpus/templates/analytics/actions/update-dashboard.ts +39 -8
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +30 -3
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +180 -144
- package/corpus/templates/analytics/app/components/layout/Header.tsx +2 -3
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -5
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +221 -215
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +6 -6
- package/corpus/templates/analytics/app/lib/demo-dashboard-path.ts +1 -1
- package/corpus/templates/analytics/app/lib/last-opened.ts +2 -1
- package/corpus/templates/analytics/app/pages/Settings.tsx +4 -0
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +2 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +32 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +101 -99
- package/corpus/templates/analytics/app/pages/overview/OverviewPage.tsx +1 -1
- package/corpus/templates/analytics/app/routes/adhoc.$id.tsx +18 -5
- package/corpus/templates/analytics/app/routes/catalog.tsx +1 -1
- package/corpus/templates/analytics/app/routes/dashboards.$id.tsx +9 -0
- package/corpus/templates/analytics/app/routes/traffic.tsx +1 -1
- package/corpus/templates/analytics/changelog/2026-06-23-long-dashboard-and-analysis-names-in-the-sidebar-now-truncat.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-23-open-any-dashboard-chart-full-screen-in-a-modal-from-the-pan.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-23-the-dashboards-and-analyses-sidebar-settings-buttons-now-sta.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +145 -0
- package/corpus/templates/analytics/server/db/index.ts +1 -1
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +9 -2
- package/corpus/templates/analytics/server/lib/demo-dashboards.ts +1 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +2 -2
- package/corpus/templates/analytics/server/plugins/core-routes.ts +6 -6
- package/corpus/templates/assets/CHANGELOG.md +10 -0
- package/corpus/templates/assets/actions/generate-image.ts +24 -0
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +2 -2
- package/corpus/templates/assets/app/global.css +17 -1
- package/corpus/templates/assets/app/root.tsx +7 -1
- package/corpus/templates/assets/app/routes/_index.tsx +94 -14
- package/corpus/templates/assets/app/routes/settings.tsx +6 -0
- package/corpus/templates/assets/changelog/2026-06-23-chat-dates-in-the-sidebar-no-longer-wrap-onto-two-lines.md +6 -0
- package/corpus/templates/assets/changelog/2026-06-23-clicking-image-video-or-refine-on-the-start-screen-now-drops.md +6 -0
- package/corpus/templates/assets/changelog/2026-06-23-pick-your-image-generation-model-right-from-the-chat-model-m.md +6 -0
- package/corpus/templates/brain/CHANGELOG.md +10 -0
- package/corpus/templates/brain/app/root.tsx +7 -1
- package/corpus/templates/brain/app/routes/settings.tsx +8 -1
- package/corpus/templates/calendar/CHANGELOG.md +10 -0
- package/corpus/templates/calendar/app/pages/Settings.tsx +4 -0
- package/corpus/templates/calendar/app/root.tsx +7 -1
- package/corpus/templates/chat/CHANGELOG.md +10 -0
- package/corpus/templates/chat/app/root.tsx +7 -1
- package/corpus/templates/clips/CHANGELOG.md +10 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -20
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +33 -7
- package/corpus/templates/clips/app/components/player/sign-in-prompt-dialog.tsx +8 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +150 -20
- package/corpus/templates/clips/app/components/recorder/countdown-overlay.tsx +72 -48
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +7 -11
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +31 -0
- package/corpus/templates/clips/app/components/sharing/slack-share-hint.tsx +71 -0
- package/corpus/templates/clips/app/lib/countdown-audio-cue.ts +35 -17
- package/corpus/templates/clips/app/root.tsx +7 -1
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +15 -1
- package/corpus/templates/clips/app/routes/record.tsx +78 -5
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +86 -5
- package/corpus/templates/clips/changelog/2026-06-23-clips-shared-in-slack-no-longer-show-a-could-not-start-playb.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-made-the-play-button-on-shared-and-embedded-clips-scale-with.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-public-clip-share-links-now-show-whether-they-ll-play-inline.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-removed-select-button-from-library-hover-a-clip-to-select-it.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-screen-camera-recordings-now-keep-the-presenter-s-face-in-th.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-shared-video-links-now-play-for-anyone-without-signing-in.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-skip-or-cancel-the-recording-countdown-with-buttons-beside-t.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-the-desktop-camera-bubble-now-looks-sharp-the-instant-it-ope.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-the-desktop-recording-widget-now-grows-downward-only-when-yo.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-the-recording-start-sound-is-now-a-softer-more-modern-chime.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +17 -8
- package/corpus/templates/clips/chrome-extension/src/background.ts +769 -180
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +177 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +466 -329
- package/corpus/templates/clips/chrome-extension/src/overlay.css +377 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.html +12 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +330 -0
- package/corpus/templates/clips/chrome-extension/src/permission.html +227 -0
- package/corpus/templates/clips/chrome-extension/src/permission.ts +105 -0
- package/corpus/templates/clips/chrome-extension/src/popup.html +3 -0
- package/corpus/templates/clips/chrome-extension/src/popup.ts +50 -2
- package/corpus/templates/clips/chrome-extension/src/styles.css +50 -0
- package/corpus/templates/clips/chrome-extension/vite.config.ts +3 -0
- package/corpus/templates/clips/desktop/src/lib/audio-cue.ts +41 -24
- package/corpus/templates/clips/desktop/src/lib/bubble-webrtc.ts +119 -2
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +20 -0
- package/corpus/templates/clips/desktop/src/main.tsx +3 -0
- package/corpus/templates/clips/desktop/src/overlays/countdown.tsx +21 -2
- package/corpus/templates/clips/desktop/src/overlays/region-record-border.tsx +76 -0
- package/corpus/templates/clips/desktop/src/styles.css +119 -2
- package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +2 -1
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +140 -1
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -0
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +4 -1
- package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +85 -6
- package/corpus/templates/clips/shared/share-attribution.ts +79 -0
- package/corpus/templates/content/AGENTS.md +20 -3
- package/corpus/templates/content/CHANGELOG.md +10 -0
- package/corpus/templates/content/actions/_database-utils.ts +15 -0
- package/corpus/templates/content/actions/_property-utils.ts +371 -4
- package/corpus/templates/content/actions/configure-document-property.ts +35 -1
- package/corpus/templates/content/actions/create-content-database.ts +5 -1
- package/corpus/templates/content/actions/delete-document-property.ts +52 -2
- package/corpus/templates/content/actions/duplicate-document-property.ts +34 -17
- package/corpus/templates/content/actions/reorder-document-property.ts +79 -0
- package/corpus/templates/content/actions/set-document-property.ts +39 -0
- package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +806 -0
- package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +226 -68
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +59 -30
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +25 -1
- package/corpus/templates/content/app/components/editor/blockFieldSaveController.ts +180 -0
- package/corpus/templates/content/app/components/editor/blockFieldSaveRegistry.ts +179 -0
- package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +244 -0
- package/corpus/templates/content/app/components/editor/previewDocumentSaveRegistry.ts +132 -0
- package/corpus/templates/content/app/global.css +9 -0
- package/corpus/templates/content/app/hooks/use-document-properties.ts +21 -0
- package/corpus/templates/content/app/root.tsx +7 -1
- package/corpus/templates/content/server/db/schema.ts +30 -0
- package/corpus/templates/content/server/plugins/db.ts +87 -0
- package/corpus/templates/content/shared/api.ts +7 -0
- package/corpus/templates/content/shared/properties.ts +109 -0
- package/corpus/templates/design/CHANGELOG.md +10 -0
- package/corpus/templates/design/actions/generate-design.ts +4 -0
- package/corpus/templates/design/app/root.tsx +7 -1
- package/corpus/templates/design/app/routes/settings.tsx +10 -2
- package/corpus/templates/dispatch/CHANGELOG.md +10 -0
- package/corpus/templates/dispatch/app/root.tsx +7 -1
- package/corpus/templates/forms/.agents/skills/form-responses/SKILL.md +10 -0
- package/corpus/templates/forms/CHANGELOG.md +10 -0
- package/corpus/templates/forms/actions/export-responses.ts +6 -0
- package/corpus/templates/forms/actions/list-responses.ts +2 -0
- package/corpus/templates/forms/actions/response-insights.ts +2 -0
- package/corpus/templates/forms/app/pages/ResponsesPage.tsx +138 -1
- package/corpus/templates/forms/app/root.tsx +7 -1
- package/corpus/templates/forms/changelog/2026-06-23-response-tables-now-show-the-page-each-submission-came-from-.md +6 -0
- package/corpus/templates/forms/changelog/2026-06-23-response-tables-now-show-whether-feedback-came-from-the-web-.md +6 -0
- package/corpus/templates/forms/server/db/schema.ts +7 -0
- package/corpus/templates/forms/server/handlers/submissions.ts +19 -2
- package/corpus/templates/forms/server/lib/integrations.ts +76 -2
- package/corpus/templates/forms/server/plugins/db.ts +20 -0
- package/corpus/templates/forms/shared/types.ts +12 -0
- package/corpus/templates/macros/CHANGELOG.md +10 -0
- package/corpus/templates/macros/app/root.tsx +7 -1
- package/corpus/templates/mail/CHANGELOG.md +10 -0
- package/corpus/templates/mail/app/components/layout/CommandPalette.tsx +3 -0
- package/corpus/templates/mail/app/pages/SettingsPage.tsx +27 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +31 -17
- package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -4
- package/corpus/templates/plan/.agents/skills/visual-recap/SKILL.md +34 -24
- package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -4
- package/corpus/templates/plan/AGENTS.md +4 -0
- package/corpus/templates/plan/CHANGELOG.md +10 -0
- package/corpus/templates/plan/actions/view-screen.ts +5 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +98 -1
- package/corpus/templates/plan/app/components/plan/wireframe/html-artboard.css +3 -1
- package/corpus/templates/plan/app/pages/PlansPage.tsx +107 -7
- package/corpus/templates/plan/app/root.tsx +7 -1
- package/corpus/templates/plan/changelog/2026-06-23-large-diagrams-in-a-plan-now-scroll-within-their-block-inste.md +6 -0
- package/corpus/templates/plan/shared/share-attribution.ts +72 -0
- package/corpus/templates/slides/CHANGELOG.md +10 -0
- package/corpus/templates/slides/app/root.tsx +7 -1
- package/corpus/templates/videos/CHANGELOG.md +4 -151
- package/corpus/templates/videos/app/root.tsx +7 -1
- package/dist/action.js +87 -0
- package/dist/action.js.map +1 -1
- package/dist/agent/engine/builder-engine.d.ts +1 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/model-config.d.ts +2 -2
- package/dist/agent/model-config.d.ts.map +1 -1
- package/dist/agent/model-config.js +0 -2
- package/dist/agent/model-config.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts +13 -0
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +44 -0
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/changelog/parse.d.ts +70 -0
- package/dist/changelog/parse.d.ts.map +1 -0
- package/dist/changelog/parse.js +200 -0
- package/dist/changelog/parse.js.map +1 -0
- package/dist/cli/changelog.d.ts +4 -0
- package/dist/cli/changelog.d.ts.map +1 -0
- package/dist/cli/changelog.js +166 -0
- package/dist/cli/changelog.js.map +1 -0
- package/dist/cli/index.js +18 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +22 -1
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills.d.ts +3 -3
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +74 -47
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +5 -3
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +6 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +2 -2
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/CommandMenu.d.ts +17 -1
- package/dist/client/CommandMenu.d.ts.map +1 -1
- package/dist/client/CommandMenu.js +49 -13
- package/dist/client/CommandMenu.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +43 -6
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/analytics.d.ts +18 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +177 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/changelog/Changelog.d.ts +47 -0
- package/dist/client/changelog/Changelog.d.ts.map +1 -0
- package/dist/client/changelog/Changelog.js +138 -0
- package/dist/client/changelog/Changelog.js.map +1 -0
- package/dist/client/client-surface.d.ts +17 -0
- package/dist/client/client-surface.d.ts.map +1 -0
- package/dist/client/client-surface.js +24 -0
- package/dist/client/client-surface.js.map +1 -0
- package/dist/client/composer/TiptapComposer.d.ts +26 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +27 -5
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/feedback-context.d.ts +3 -0
- package/dist/client/feedback-context.d.ts.map +1 -1
- package/dist/client/feedback-context.js +2 -0
- package/dist/client/feedback-context.js.map +1 -1
- package/dist/client/index.d.ts +3 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.d.ts +1 -0
- package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.js +42 -1
- package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts +2 -0
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +58 -10
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +7 -1
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/mcp/build-server.d.ts +21 -0
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +43 -1
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/embed-app.d.ts.map +1 -1
- package/dist/mcp/embed-app.js +197 -7
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/mcp/oauth-route.d.ts.map +1 -1
- package/dist/mcp/oauth-route.js +95 -12
- package/dist/mcp/oauth-route.js.map +1 -1
- package/dist/server/attribution.d.ts +83 -0
- package/dist/server/attribution.d.ts.map +1 -0
- package/dist/server/attribution.js +178 -0
- package/dist/server/attribution.js.map +1 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +7 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts +9 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +32 -2
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/builder-browser.d.ts +4 -0
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +20 -1
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +25 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +101 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/google-oauth.d.ts.map +1 -1
- package/dist/server/google-oauth.js +16 -2
- package/dist/server/google-oauth.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +35 -0
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/shared/mcp-embed-headers.js +1 -1
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/styles/agent-conversation.css +21 -0
- package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
- package/dist/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
- package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
- package/docs/design/durable-agent-runs.md +217 -0
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
- package/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
- package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
- package/corpus/templates/analytics/app/pages/About.tsx +0 -108
- package/corpus/templates/analytics/app/routes/about.tsx +0 -9
- /package/corpus/templates/analytics/app/routes/{dashboards.tsx → dashboards._index.tsx} +0 -0
|
@@ -1191,6 +1191,7 @@ ${
|
|
|
1191
1191
|
}
|
|
1192
1192
|
}
|
|
1193
1193
|
function __anFinishOAuthExchange(ret, flowId, sessionToken) {
|
|
1194
|
+
__anGoogleSignInInFlight = false;
|
|
1194
1195
|
if (__anIsBuilderPreview()) {
|
|
1195
1196
|
if (sessionToken) {
|
|
1196
1197
|
__anSetOAuthDebug('OAuth exchange redeemed; applying session bridge to embedded app', flowId);
|
|
@@ -1361,6 +1362,8 @@ ${identitySsoScript}
|
|
|
1361
1362
|
}
|
|
1362
1363
|
var __anOAuthPollTimer = null;
|
|
1363
1364
|
var __anOAuthPollCount = 0;
|
|
1365
|
+
var __anGoogleSignInInFlight = false;
|
|
1366
|
+
var __anGoogleRecoverBound = false;
|
|
1364
1367
|
function __anNewOAuthFlowId() {
|
|
1365
1368
|
try {
|
|
1366
1369
|
if (window.crypto && typeof window.crypto.randomUUID === 'function') {
|
|
@@ -1401,6 +1404,34 @@ ${identitySsoScript}
|
|
|
1401
1404
|
err.textContent = message;
|
|
1402
1405
|
err.classList.add('show');
|
|
1403
1406
|
btn.disabled = false;
|
|
1407
|
+
__anGoogleSignInInFlight = false;
|
|
1408
|
+
}
|
|
1409
|
+
function __anRecoverGoogleSignInAfterReturn() {
|
|
1410
|
+
// The user left for the Google sign-in window and came back. If the flow
|
|
1411
|
+
// never completed (e.g. they closed the window to switch profiles), the
|
|
1412
|
+
// button is stuck disabled with no error path firing for up to 5 minutes.
|
|
1413
|
+
// Re-enable it so they can retry. Wait briefly first so a genuinely
|
|
1414
|
+
// in-flight exchange can still finish and navigate without a flicker.
|
|
1415
|
+
if (!__anGoogleSignInInFlight) return;
|
|
1416
|
+
setTimeout(function() {
|
|
1417
|
+
if (!__anGoogleSignInInFlight) return;
|
|
1418
|
+
var btn = document.getElementById('google-btn');
|
|
1419
|
+
if (!btn || !btn.disabled) return;
|
|
1420
|
+
if (__anOAuthPollTimer) {
|
|
1421
|
+
clearInterval(__anOAuthPollTimer);
|
|
1422
|
+
__anOAuthPollTimer = null;
|
|
1423
|
+
}
|
|
1424
|
+
btn.disabled = false;
|
|
1425
|
+
__anGoogleSignInInFlight = false;
|
|
1426
|
+
}, 1200);
|
|
1427
|
+
}
|
|
1428
|
+
function __anBindGoogleRecover() {
|
|
1429
|
+
if (__anGoogleRecoverBound) return;
|
|
1430
|
+
__anGoogleRecoverBound = true;
|
|
1431
|
+
window.addEventListener('focus', __anRecoverGoogleSignInAfterReturn);
|
|
1432
|
+
document.addEventListener('visibilitychange', function() {
|
|
1433
|
+
if (document.visibilityState === 'visible') __anRecoverGoogleSignInAfterReturn();
|
|
1434
|
+
});
|
|
1404
1435
|
}
|
|
1405
1436
|
function __anHandlePopupOAuthFailure(ret, btn, err, flowId, redirectReason, builderFrameMessage) {
|
|
1406
1437
|
if (__anIsBuilderPreview() && __anIsInFrame()) {
|
|
@@ -2013,6 +2044,8 @@ ${
|
|
|
2013
2044
|
var err = document.getElementById('google-err');
|
|
2014
2045
|
var ret = __anGetReturnPath();
|
|
2015
2046
|
btn.disabled = true;
|
|
2047
|
+
__anGoogleSignInInFlight = true;
|
|
2048
|
+
__anBindGoogleRecover();
|
|
2016
2049
|
err.classList.remove('show');
|
|
2017
2050
|
if (__anResolveAuthFlow() === 'popup') {
|
|
2018
2051
|
__anStartPopupOAuth(ret, btn, err);
|
|
@@ -2037,11 +2070,13 @@ ${
|
|
|
2037
2070
|
err.textContent = data.message || 'Google OAuth is not configured.';
|
|
2038
2071
|
err.classList.add('show');
|
|
2039
2072
|
btn.disabled = false;
|
|
2073
|
+
__anGoogleSignInInFlight = false;
|
|
2040
2074
|
}
|
|
2041
2075
|
} catch (e) {
|
|
2042
2076
|
err.textContent = 'Failed to connect. Please try again.';
|
|
2043
2077
|
err.classList.add('show');
|
|
2044
2078
|
btn.disabled = false;
|
|
2079
|
+
__anGoogleSignInInFlight = false;
|
|
2045
2080
|
}
|
|
2046
2081
|
}`
|
|
2047
2082
|
: ""
|
|
@@ -4,7 +4,7 @@ export const EMBED_TRANSPLANT_HEADER = "x-agent-native-embed-transplant";
|
|
|
4
4
|
|
|
5
5
|
const CLAUDE_MCP_CONTENT_HOST_RE = /^[a-f0-9]{32}\.claudemcpcontent\.com$/i;
|
|
6
6
|
const CHATGPT_MCP_SANDBOX_HOST_RE =
|
|
7
|
-
/^[^.]+\.web-sandbox\.oaiusercontent\.com$/i;
|
|
7
|
+
/^(?:[^.]+\.)?web-sandbox\.oaiusercontent\.com$/i;
|
|
8
8
|
|
|
9
9
|
export function isLocalMcpEmbedOrigin(
|
|
10
10
|
origin: string | null | undefined,
|
|
@@ -325,6 +325,27 @@
|
|
|
325
325
|
font-size: 12px;
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
+
.agent-mcp-app__error {
|
|
329
|
+
flex-direction: column;
|
|
330
|
+
text-align: center;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.agent-mcp-app__open {
|
|
334
|
+
min-height: 28px;
|
|
335
|
+
border: 1px solid hsl(var(--destructive) / 0.35);
|
|
336
|
+
border-radius: calc(var(--radius) - 2px);
|
|
337
|
+
background: hsl(var(--background));
|
|
338
|
+
color: hsl(var(--foreground));
|
|
339
|
+
cursor: pointer;
|
|
340
|
+
font: inherit;
|
|
341
|
+
font-weight: 600;
|
|
342
|
+
padding: 0 10px;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.agent-mcp-app__open:hover {
|
|
346
|
+
background: hsl(var(--muted));
|
|
347
|
+
}
|
|
348
|
+
|
|
328
349
|
.agent-mcp-app__error,
|
|
329
350
|
.agent-mcp-app--error {
|
|
330
351
|
color: hsl(var(--destructive));
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: changelog
|
|
3
|
+
description: >-
|
|
4
|
+
How to keep each app's user-facing changelog. Use when you ship a change a
|
|
5
|
+
user would notice (a new feature, a visible improvement, a bug fix), when
|
|
6
|
+
wiring the in-app "What's new" surface into a template, or when releasing
|
|
7
|
+
pending changelog entries.
|
|
8
|
+
scope: dev
|
|
9
|
+
metadata:
|
|
10
|
+
internal: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Changelog — user-facing "What's new"
|
|
14
|
+
|
|
15
|
+
Every template app keeps a `CHANGELOG.md` of **user-facing** changes that
|
|
16
|
+
renders in-app via the command menu (Cmd+K → "What's new") and on the settings
|
|
17
|
+
page. The flow mirrors changesets so it survives many agents working in
|
|
18
|
+
parallel: each change drops a small **pending entry file**, and a later
|
|
19
|
+
**release** rolls all pending files into a dated `CHANGELOG.md` section.
|
|
20
|
+
|
|
21
|
+
## When to add an entry
|
|
22
|
+
|
|
23
|
+
Add an entry whenever you ship something a user of that app would notice:
|
|
24
|
+
|
|
25
|
+
- a new capability or surface,
|
|
26
|
+
- a visible improvement (speed, layout, copy, defaults),
|
|
27
|
+
- a bug fix that affects behavior they'd see.
|
|
28
|
+
|
|
29
|
+
Do **not** add entries for refactors, internal tooling, tests, dependency
|
|
30
|
+
bumps, or anything invisible to the end user. The changelog is product notes,
|
|
31
|
+
not a commit log — write it the way you'd describe the change to a customer.
|
|
32
|
+
|
|
33
|
+
## How to add an entry
|
|
34
|
+
|
|
35
|
+
From the app directory (the template you changed):
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
agent-native changelog add "Recordings can be trimmed before sharing" --type added
|
|
39
|
+
agent-native changelog add "Faster transcript search" --type improved
|
|
40
|
+
agent-native changelog add "Fixed a crash when opening an empty folder" --type fixed
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`--type` is one of `added`, `improved`, `fixed`, `changed`, `removed`,
|
|
44
|
+
`security` (aliases like `feature`, `bugfix`, `enhancement` are accepted). This
|
|
45
|
+
writes `changelog/<date>-<slug>.md` — one file per change, so parallel work
|
|
46
|
+
never conflicts. You can also hand-write that file; the frontmatter is just:
|
|
47
|
+
|
|
48
|
+
```md
|
|
49
|
+
---
|
|
50
|
+
type: added
|
|
51
|
+
date: 2026-06-23
|
|
52
|
+
---
|
|
53
|
+
Recordings can be trimmed before sharing.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Writing good entries
|
|
57
|
+
|
|
58
|
+
- One user-facing sentence, present tense, no internal jargon or file names.
|
|
59
|
+
- Lead with the benefit ("Recordings can be trimmed…"), not the mechanism.
|
|
60
|
+
- Markdown is allowed (bold, links) but keep it short — it renders as a bullet.
|
|
61
|
+
|
|
62
|
+
## Releasing
|
|
63
|
+
|
|
64
|
+
`release` stamps every pending entry into `CHANGELOG.md` under a dated
|
|
65
|
+
`## <date>` section (grouped by type) and deletes the pending files:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
agent-native changelog release # uses today's date
|
|
69
|
+
agent-native changelog list # preview pending + released
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Releasing is usually done at deploy/merge time. The in-app surface reads
|
|
73
|
+
`CHANGELOG.md`, so only released entries are visible to users — pending entries
|
|
74
|
+
stay invisible until rolled up.
|
|
75
|
+
|
|
76
|
+
## Wiring the in-app surface (once per template)
|
|
77
|
+
|
|
78
|
+
Templates already get the rendering for free from `@agent-native/core`. To
|
|
79
|
+
expose it in an app:
|
|
80
|
+
|
|
81
|
+
1. **Command menu** — pass the app's own changelog to `CommandMenu`:
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import changelog from "../CHANGELOG.md?raw";
|
|
85
|
+
// ...
|
|
86
|
+
<CommandMenu open={cmdkOpen} onOpenChange={setCmdkOpen} changelog={changelog}>
|
|
87
|
+
{/* existing groups */}
|
|
88
|
+
</CommandMenu>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
This adds a "What's new" entry with an unseen-release dot and an in-app
|
|
92
|
+
dialog — no other wiring needed.
|
|
93
|
+
|
|
94
|
+
2. **Settings** (optional) — drop the card on the settings page:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import { ChangelogSettingsCard } from "@agent-native/core/client";
|
|
98
|
+
import changelog from "../CHANGELOG.md?raw";
|
|
99
|
+
// ...
|
|
100
|
+
<ChangelogSettingsCard markdown={changelog} />
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`CHANGELOG.md?raw` is inlined by Vite at build time, so this works on every
|
|
104
|
+
host with no server route or runtime file access.
|
|
105
|
+
|
|
106
|
+
## Checklist
|
|
107
|
+
|
|
108
|
+
- [ ] Shipped a user-visible change? Run `agent-native changelog add "…"`.
|
|
109
|
+
- [ ] New template UI? Pass `changelog` to its `CommandMenu` and seed a
|
|
110
|
+
`CHANGELOG.md`.
|
|
111
|
+
- [ ] Releasing/deploying? `agent-native changelog release` rolls pending → dated.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reliable-mutations
|
|
3
|
+
description: >-
|
|
4
|
+
How the agent must perform writes so they actually persist under the hosted
|
|
5
|
+
~40s run budget. Use whenever you create, update, delete, or batch-write app
|
|
6
|
+
data — especially "do this for many items" loops, or any task where the user
|
|
7
|
+
expects N things to end up saved.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Reliable Mutations
|
|
11
|
+
|
|
12
|
+
## Rule
|
|
13
|
+
|
|
14
|
+
Make a change in **one atomic call** when the action supports it, then **verify
|
|
15
|
+
the persisted end state and report concrete proof** (counts/ids). Never drive a
|
|
16
|
+
multi-step change by looping many small writes, and never report success from a
|
|
17
|
+
tool ✓ alone.
|
|
18
|
+
|
|
19
|
+
## Why
|
|
20
|
+
|
|
21
|
+
Hosted agent runs have a ~40s soft budget (it exists to hand off cleanly under
|
|
22
|
+
the upstream gateway/function walls — it is correct and is not raisable; see the
|
|
23
|
+
durable-agent-runs design doc). When you loop many sequential writes inside one
|
|
24
|
+
turn, the budget can cut you off mid-loop. The run resumes in a new chunk, but
|
|
25
|
+
the resume often re-does earlier steps instead of advancing, so the loop churns
|
|
26
|
+
and the *saved* result ends up partial — or empty — even though each individual
|
|
27
|
+
tool call appeared to succeed. The user gets told "done" while the data says
|
|
28
|
+
otherwise. One atomic call commits or fails as a unit; verification turns a
|
|
29
|
+
hopeful ✓ into a fact.
|
|
30
|
+
|
|
31
|
+
## How
|
|
32
|
+
|
|
33
|
+
1. **Prefer a single atomic call.** If an action accepts the whole set (add
|
|
34
|
+
many, set all, bulk update), pass the full batch in one call so it commits
|
|
35
|
+
atomically. Check the action surface for a batch/plural form before reaching
|
|
36
|
+
for a loop.
|
|
37
|
+
2. **Do not loop many small writes under the run budget.** A sequence of N
|
|
38
|
+
per-item writes in one turn will race the ~40s cutoff and can leave partial
|
|
39
|
+
or no state. If no batch action exists, that is a gap in the action layer —
|
|
40
|
+
add or extend an action that accepts the batch (see the `actions` skill)
|
|
41
|
+
rather than papering over it with a loop.
|
|
42
|
+
3. **Verify the end state after writing.** Re-read the data (a list/read action,
|
|
43
|
+
a count query) and confirm the result matches intent — the right number of
|
|
44
|
+
rows, the expected ids/fields. Do this before you tell the user it worked.
|
|
45
|
+
4. **Report proof-of-done, not vibes.** State concrete evidence: "saved 12 of 12
|
|
46
|
+
panels (ids …)" or "updated 5 rows". Do not infer success from the presence
|
|
47
|
+
of a tool ✓ on an individual call.
|
|
48
|
+
5. **On a time-budget cutoff, fail loud.** If the turn is cut before the change
|
|
49
|
+
is fully committed and verified, say so explicitly and report what *did*
|
|
50
|
+
persist (M of N) and what remains. Never round a partial or unverified write
|
|
51
|
+
up to "done".
|
|
52
|
+
|
|
53
|
+
## Don't
|
|
54
|
+
|
|
55
|
+
- Don't loop `for each item: write(item)` for a large set in a single hosted
|
|
56
|
+
turn.
|
|
57
|
+
- Don't claim completion because every tool call returned ✓ — a ✓ on an aborted
|
|
58
|
+
chunk does not mean the row was committed.
|
|
59
|
+
- Don't silently shrink the scope ("I added a few of them") and present it as the
|
|
60
|
+
finished task.
|
|
61
|
+
- Don't try to "fix" this by asking for a longer run timeout — the budget is
|
|
62
|
+
correct; restructure the write instead.
|
|
63
|
+
|
|
64
|
+
## Related
|
|
65
|
+
|
|
66
|
+
- `actions` — define or extend a batch/atomic action when only per-item writes
|
|
67
|
+
exist.
|
|
68
|
+
- `storing-data` — where app data lives and how reads/writes are scoped.
|
|
69
|
+
- `performance` — avoid query waterfalls when verifying end state.
|
|
70
|
+
- Design doc: `packages/core/docs/design/durable-agent-runs.md` — the real
|
|
71
|
+
ceiling fix (checkpointed and durable runs); this skill is the agent-facing
|
|
72
|
+
mitigation that reduces how often the ceiling is hit.
|
|
@@ -31,7 +31,11 @@ Fire an analytics event.
|
|
|
31
31
|
```ts
|
|
32
32
|
import { track } from "@agent-native/core/tracking";
|
|
33
33
|
|
|
34
|
-
track(
|
|
34
|
+
track(
|
|
35
|
+
"meal.logged",
|
|
36
|
+
{ mealName: "Salad", calories: 350 },
|
|
37
|
+
{ userId: "user@example.com" },
|
|
38
|
+
);
|
|
35
39
|
```
|
|
36
40
|
|
|
37
41
|
### `identify(userId, traits?)`
|
|
@@ -73,13 +77,13 @@ Flush all providers (call before process exit).
|
|
|
73
77
|
|
|
74
78
|
Set the env var and the provider auto-registers at startup. No SDK dependencies -- all providers use raw HTTP.
|
|
75
79
|
|
|
76
|
-
| Provider
|
|
77
|
-
|
|
|
78
|
-
| PostHog
|
|
79
|
-
| Mixpanel
|
|
80
|
-
| Amplitude
|
|
80
|
+
| Provider | Env vars |
|
|
81
|
+
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
82
|
+
| PostHog | `POSTHOG_API_KEY` (required), `POSTHOG_HOST` (optional, defaults to `https://us.i.posthog.com`) |
|
|
83
|
+
| Mixpanel | `MIXPANEL_TOKEN` |
|
|
84
|
+
| Amplitude | `AMPLITUDE_API_KEY` |
|
|
81
85
|
| Agent Native Analytics | `AGENT_NATIVE_ANALYTICS_PUBLIC_KEY` (server), `AGENT_NATIVE_ANALYTICS_ENDPOINT` (optional, defaults to `https://analytics.agent-native.com/track`) |
|
|
82
|
-
| Webhook
|
|
86
|
+
| Webhook | `TRACKING_WEBHOOK_URL` (required), `TRACKING_WEBHOOK_AUTH` (optional, sent as `Authorization` header) |
|
|
83
87
|
|
|
84
88
|
Multiple providers can be active simultaneously. All receive every event.
|
|
85
89
|
|
|
@@ -106,10 +110,35 @@ Every browser-side `trackEvent()` POST to the Agent Native Analytics `/track` en
|
|
|
106
110
|
|
|
107
111
|
These fields land in the `analytics_events.anonymous_id`, `analytics_events.session_id`, and `analytics_events.user_id` columns in the analytics template. Storage access is wrapped in try/catch — private-browsing / blocked-storage clients silently degrade to NULL rather than crashing the page.
|
|
108
112
|
|
|
113
|
+
### Referral / viral attribution (first-touch)
|
|
114
|
+
|
|
115
|
+
`configureTracking()` also captures an anonymous visitor's **first-touch** referral context once, on first page load, and persists it across the signup boundary so the server-side `signup` event records where the user came from. This powers virality metrics for every template (Clips share links, Plans public pages, etc.).
|
|
116
|
+
|
|
117
|
+
**Share-link params** (set by whatever generates the link; read client-side only):
|
|
118
|
+
|
|
119
|
+
- `ref` — referral source bucket, e.g. `clip_share`, `plan_share`
|
|
120
|
+
- `via` — the referrer's stable user id (the clip/plan owner)
|
|
121
|
+
- `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term`
|
|
122
|
+
|
|
123
|
+
**Client persistence** (first-write-wins — an existing value is never overwritten):
|
|
124
|
+
|
|
125
|
+
- `localStorage` key `an_attribution` and first-party cookie `an_ft` (`path=/; max-age=2592000; SameSite=Lax`, not HttpOnly — non-sensitive, written by client JS).
|
|
126
|
+
- Both store the same URL-encoded compact JSON (empty fields omitted, each value capped at 120 chars): `{ ref, via, utm_source, utm_medium, utm_campaign, utm_content, utm_term, landing_path, landing_referrer, landed_at }`. `landing_referrer` is the **host only** of `document.referrer` (scrubbed; same-origin referrers are dropped).
|
|
127
|
+
- `getFirstTouchAttribution()` (from `@agent-native/core/client`) returns the parsed object or `null`.
|
|
128
|
+
|
|
129
|
+
**Signup event enrichment** (server-side, from the `an_ft` cookie on the signup/OAuth-callback request, derived in `packages/core/src/server/attribution.ts`):
|
|
130
|
+
|
|
131
|
+
- `referral_source` — `ref` if present, else derived: `/share/…` → `clip_share`; a plan public path (`/p/`, `/plan/`, `/share-plan/`) → `plan_share`; a non-empty external referring host → `external`; otherwise `direct`.
|
|
132
|
+
- `referrer_user` (= `via`), `referral_medium` (= `utm_medium`), `referral_campaign` (= `utm_campaign`)
|
|
133
|
+
- `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term` (raw passthrough)
|
|
134
|
+
- `first_touch_path` (= `landing_path`), `landing_referrer`
|
|
135
|
+
|
|
136
|
+
Attribution parsing is fully defensive and never blocks signup — a missing/malformed cookie falls back to `referral_source: "direct"`.
|
|
137
|
+
|
|
109
138
|
Other framework-level baseline events:
|
|
110
139
|
|
|
111
140
|
- `session status` from `useSession()`, with `signed_in`
|
|
112
|
-
- `signup` from Better Auth user creation, with `auth_provider` and `
|
|
141
|
+
- `signup` from Better Auth user creation, with `auth_provider`, `auth_user_id`, and first-touch referral attribution (`referral_source`, `referrer_user`, `referral_medium`, `referral_campaign`, `utm_*`, `first_touch_path`, `landing_referrer` — see "Referral / viral attribution" above)
|
|
113
142
|
- `builder connect clicked` and `builder connect popup blocked` from browser Connect Builder CTAs
|
|
114
143
|
- `builder connect started`, `builder connect succeeded`, `builder connect failed`, `builder disconnect succeeded`, and `builder disconnect failed` from the Builder connection routes, with LLM connection context when resolvable
|
|
115
144
|
|
|
@@ -121,7 +150,10 @@ For new lifecycle events, call `track()` server-side when the server is the sour
|
|
|
121
150
|
interface TrackingProvider {
|
|
122
151
|
name: string;
|
|
123
152
|
track(event: TrackingEvent): void | Promise<void>;
|
|
124
|
-
identify?(
|
|
153
|
+
identify?(
|
|
154
|
+
userId: string,
|
|
155
|
+
traits?: Record<string, unknown>,
|
|
156
|
+
): void | Promise<void>;
|
|
125
157
|
flush?(): void | Promise<void>;
|
|
126
158
|
}
|
|
127
159
|
|
|
@@ -142,11 +174,11 @@ interface TrackingEvent {
|
|
|
142
174
|
|
|
143
175
|
## Key Files
|
|
144
176
|
|
|
145
|
-
| File
|
|
146
|
-
|
|
|
147
|
-
| `packages/core/src/tracking/registry.ts`
|
|
148
|
-
| `packages/core/src/tracking/providers.ts`
|
|
149
|
-
| `packages/core/src/tracking/types.ts`
|
|
177
|
+
| File | Purpose |
|
|
178
|
+
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
179
|
+
| `packages/core/src/tracking/registry.ts` | `track()`, `identify()`, `registerTrackingProvider()`, `flushTracking()` |
|
|
180
|
+
| `packages/core/src/tracking/providers.ts` | Built-in providers (PostHog, Mixpanel, Amplitude, Agent Native Analytics, Webhook) and `registerBuiltinProviders()` |
|
|
181
|
+
| `packages/core/src/tracking/types.ts` | `TrackingEvent` and `TrackingProvider` interfaces |
|
|
150
182
|
|
|
151
183
|
## Related Skills
|
|
152
184
|
|
|
@@ -174,6 +174,28 @@ pnpm action update-dashboard --dashboardId weekly-metrics --config '<full json>'
|
|
|
174
174
|
|
|
175
175
|
After a mutation, navigate to the dashboard if the user is elsewhere. The app syncs through the framework's polling/query invalidation path.
|
|
176
176
|
|
|
177
|
+
## Reliable Bulk Edits
|
|
178
|
+
|
|
179
|
+
This is the dashboard-specific application of the framework-wide `reliable-mutations` skill — read that for the general rule (one atomic write, verify end state, report proof-of-done).
|
|
180
|
+
|
|
181
|
+
Hosted agent runs have a **~40s budget**. Many sequential `update-dashboard` calls (one per panel, plus schema-discovery calls) will blow that budget and leave the dashboard in a partial state — earlier inserts looked like they succeeded (✓), but nothing actually persisted. Avoid this:
|
|
182
|
+
|
|
183
|
+
- **Batch ALL changes into ONE `update-dashboard` call.** A single `update-dashboard` is atomic: it applies every op to an in-memory config, validates all panel SQL, then upserts once. Never loop the action.
|
|
184
|
+
- To add N panels, pass N ops in one call: `ops: [{op:"insert", path:"/panels/-", value:<panel>}, … ]` (`/panels/-` appends to the end).
|
|
185
|
+
- The `ops` format needs no discovery: each op is `{ op, path, from?, value? }`, `op ∈ set | replace | remove | insert | move | move-before`, and `path` is a JSON Pointer (e.g. `/panels/3`, `/panels/3/title`, `/name`).
|
|
186
|
+
- **To add a shipped template's panels, prefer `install-dashboard-template` with `mergePanels: true`** and the existing `dashboardId`. It appends only the template panels whose id is not already present (preserving existing panels and order) in one atomic save — you don't author each panel yourself.
|
|
187
|
+
- **Always verify the returned proof-of-done and report it.** `update-dashboard` returns `panelCount`, `appliedOps`, and a `summary` string; `install-dashboard-template --mergePanels` returns `addedPanelIds`, `skippedExistingIds`, and `panelCount`. Tell the user the resulting panel count instead of assuming success.
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# Add several panels in ONE atomic call (never one call per panel)
|
|
191
|
+
pnpm action update-dashboard --dashboardId weekly-metrics \
|
|
192
|
+
--ops '[{"op":"insert","path":"/panels/-","value":{"id":"p1","title":"A","source":"first-party","chartType":"metric","width":1,"sql":"SELECT COUNT(*) AS value FROM analytics_events"}},
|
|
193
|
+
{"op":"insert","path":"/panels/-","value":{"id":"p2","title":"B","source":"first-party","chartType":"metric","width":1,"sql":"SELECT COUNT(DISTINCT user_id) AS value FROM analytics_events"}}]'
|
|
194
|
+
|
|
195
|
+
# Append a template's panels to an existing dashboard in one call
|
|
196
|
+
pnpm action install-dashboard-template --templateId skills-cli-funnel --dashboardId weekly-metrics --mergePanels true
|
|
197
|
+
```
|
|
198
|
+
|
|
177
199
|
## Archiving vs deleting
|
|
178
200
|
|
|
179
201
|
Dashboards have a soft-delete state. The default user-facing destructive action is **Archive** (recoverable). Hard delete still exists, but lives behind a "Delete permanently" confirm in both the page header and the sidebar dropdown — and in the agent surface, behind the older `delete-dashboard` action. Archived rows stay in the `dashboards` table with `archived_at` set, are hidden from the default sidebar list, and remain accessible by id (so deep links in chat history keep working) until explicitly purged.
|
|
@@ -87,7 +87,14 @@ details live in `.agents/skills/`.
|
|
|
87
87
|
`id`, category, data sources, panel count, and installed dashboard IDs.
|
|
88
88
|
- `install-dashboard-template` installs a catalog template into normal
|
|
89
89
|
SQL-backed dashboards. Required: `templateId`. Optional: `dashboardId`,
|
|
90
|
-
`name`, `overwrite`, and `
|
|
90
|
+
`name`, `overwrite`, `forceNew`, and `mergePanels`.
|
|
91
|
+
- To add a template's panels to an existing dashboard, call
|
|
92
|
+
`install-dashboard-template` with `mergePanels: true` and the existing
|
|
93
|
+
`dashboardId`. It appends only the template panels whose id is not already
|
|
94
|
+
present (preserving existing panels and order) in one atomic save and returns
|
|
95
|
+
`{ addedPanelIds, skippedExistingIds, panelCount }`. Prefer this over looping
|
|
96
|
+
`update-dashboard` to add many panels — sequential calls time out on the ~40s
|
|
97
|
+
hosted run budget.
|
|
91
98
|
- Node Exporter ships as `node-exporter-macos` for Darwin/Homebrew
|
|
92
99
|
`node_exporter` scrapes and `node-exporter-full` for the Linux-focused
|
|
93
100
|
Grafana 1860 revision 45 full dashboard converted into native Analytics
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable user-facing changes to Agent-Native Analytics are documented here. Open it any
|
|
4
|
+
time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
|
+
|
|
6
|
+
## 2026-06-23
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- See what's new right inside Agent-Native Analytics — a changelog now lives in the command menu (Cmd+K) and in Settings.
|
|
@@ -43,7 +43,8 @@ function uniqueConstraintMessage(err: unknown): boolean {
|
|
|
43
43
|
|
|
44
44
|
export default defineAction({
|
|
45
45
|
description:
|
|
46
|
-
"Install a dashboard template from the Analytics catalog into the user's SQL-backed dashboards. Use list-dashboard-templates first when choosing a template."
|
|
46
|
+
"Install a dashboard template from the Analytics catalog into the user's SQL-backed dashboards. Use list-dashboard-templates first when choosing a template. " +
|
|
47
|
+
"To ADD a template's panels to an EXISTING dashboard in ONE call (the preferred way to bulk-add panels), pass `mergePanels: true` with the `dashboardId` of the existing dashboard: it appends every template panel whose id is not already present, preserves all existing panels and their order, and saves once. This avoids looping update-dashboard, which times out on the ~40s hosted run budget.",
|
|
47
48
|
schema: z.object({
|
|
48
49
|
templateId: z
|
|
49
50
|
.string()
|
|
@@ -52,7 +53,7 @@ export default defineAction({
|
|
|
52
53
|
.string()
|
|
53
54
|
.optional()
|
|
54
55
|
.describe(
|
|
55
|
-
"Optional dashboard id to write. Omit to reuse an existing installed copy or create a unique id.",
|
|
56
|
+
"Optional dashboard id to write. Omit to reuse an existing installed copy or create a unique id. Required when mergePanels is true.",
|
|
56
57
|
),
|
|
57
58
|
name: z
|
|
58
59
|
.string()
|
|
@@ -70,6 +71,12 @@ export default defineAction({
|
|
|
70
71
|
.describe(
|
|
71
72
|
"If true, create another copy even when this template is installed.",
|
|
72
73
|
),
|
|
74
|
+
mergePanels: z
|
|
75
|
+
.boolean()
|
|
76
|
+
.optional()
|
|
77
|
+
.describe(
|
|
78
|
+
"If true AND a dashboard already exists at dashboardId, APPEND this template's panels (only the ones whose id is not already present) to the existing dashboard in one atomic save, preserving all existing panels and their order. Returns { addedPanelIds, skippedExistingIds, panelCount }. Non-destructive; does not change overwrite/forceNew behavior.",
|
|
79
|
+
),
|
|
73
80
|
}),
|
|
74
81
|
mcpApp: {
|
|
75
82
|
compactCatalog: true,
|
|
@@ -90,6 +97,94 @@ export default defineAction({
|
|
|
90
97
|
if (!entry)
|
|
91
98
|
throw new Error(`Unknown dashboard template: ${args.templateId}`);
|
|
92
99
|
|
|
100
|
+
// Append/merge mode: add this template's panels to an existing dashboard
|
|
101
|
+
// in ONE atomic save instead of looping update-dashboard (which times out
|
|
102
|
+
// on the ~40s hosted run budget). Non-destructive: existing panels and
|
|
103
|
+
// their order are preserved; only template panels with a new id are added.
|
|
104
|
+
if (args.mergePanels) {
|
|
105
|
+
const targetId = args.dashboardId?.trim();
|
|
106
|
+
if (!targetId) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
"mergePanels=true requires dashboardId (the existing dashboard to append the template's panels to).",
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
const target = await getDashboard(targetId, ctx);
|
|
112
|
+
if (!target) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
`Dashboard "${targetId}" not found (or you don't have access). mergePanels appends to an existing dashboard — install the template normally first, or omit mergePanels to create a new copy.`,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const targetConfig = target.config as Record<string, unknown>;
|
|
119
|
+
const existingPanels = Array.isArray(targetConfig.panels)
|
|
120
|
+
? (targetConfig.panels as Array<Record<string, unknown>>)
|
|
121
|
+
: [];
|
|
122
|
+
const existingIds = new Set(
|
|
123
|
+
existingPanels
|
|
124
|
+
.map((panel) => (typeof panel?.id === "string" ? panel.id : null))
|
|
125
|
+
.filter((id): id is string => !!id),
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const seedConfig = cloneDashboardConfig(entry);
|
|
129
|
+
const seedPanels = Array.isArray(seedConfig.panels)
|
|
130
|
+
? (seedConfig.panels as unknown as Array<Record<string, unknown>>)
|
|
131
|
+
: [];
|
|
132
|
+
|
|
133
|
+
const addedPanelIds: string[] = [];
|
|
134
|
+
const skippedExistingIds: string[] = [];
|
|
135
|
+
const appended: Array<Record<string, unknown>> = [];
|
|
136
|
+
for (const panel of seedPanels) {
|
|
137
|
+
const id = typeof panel?.id === "string" ? panel.id : null;
|
|
138
|
+
if (id && existingIds.has(id)) {
|
|
139
|
+
skippedExistingIds.push(id);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
appended.push(panel);
|
|
143
|
+
if (id) {
|
|
144
|
+
addedPanelIds.push(id);
|
|
145
|
+
existingIds.add(id);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const mergedConfig: Record<string, unknown> = {
|
|
150
|
+
...targetConfig,
|
|
151
|
+
panels: [...existingPanels, ...appended],
|
|
152
|
+
};
|
|
153
|
+
const panelCount = (mergedConfig.panels as unknown[]).length;
|
|
154
|
+
|
|
155
|
+
if (appended.length > 0) {
|
|
156
|
+
const saved = await upsertDashboard(
|
|
157
|
+
targetId,
|
|
158
|
+
target.kind,
|
|
159
|
+
mergedConfig,
|
|
160
|
+
ctx,
|
|
161
|
+
);
|
|
162
|
+
await syncToCollab(targetId, mergedConfig);
|
|
163
|
+
targetConfig.name = saved.title;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
templateId: entry.id,
|
|
168
|
+
templateName: entry.name,
|
|
169
|
+
dashboardId: targetId,
|
|
170
|
+
name: target.title,
|
|
171
|
+
merged: true,
|
|
172
|
+
addedPanelIds,
|
|
173
|
+
skippedExistingIds,
|
|
174
|
+
panelCount,
|
|
175
|
+
urlPath: `/dashboards/${targetId}`,
|
|
176
|
+
deepLink: buildDeepLink({
|
|
177
|
+
app: "analytics",
|
|
178
|
+
view: "adhoc",
|
|
179
|
+
params: { dashboardId: targetId },
|
|
180
|
+
}),
|
|
181
|
+
message:
|
|
182
|
+
appended.length > 0
|
|
183
|
+
? `Added ${addedPanelIds.length} panel(s) from "${entry.name}" to "${target.title}"; ${skippedExistingIds.length} already present. Dashboard now has ${panelCount} panel(s).`
|
|
184
|
+
: `No new panels to add from "${entry.name}" — all ${skippedExistingIds.length} template panel id(s) already present. Dashboard has ${panelCount} panel(s).`,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
93
188
|
const installed = (await listDashboardCatalog(ctx)).find(
|
|
94
189
|
(template) => template.id === entry.id,
|
|
95
190
|
);
|
|
@@ -100,7 +195,7 @@ export default defineAction({
|
|
|
100
195
|
dashboardId: existingInstall.id,
|
|
101
196
|
name: existingInstall.name,
|
|
102
197
|
alreadyInstalled: true,
|
|
103
|
-
urlPath: `/
|
|
198
|
+
urlPath: `/dashboards/${existingInstall.id}`,
|
|
104
199
|
deepLink: buildDeepLink({
|
|
105
200
|
app: "analytics",
|
|
106
201
|
view: "adhoc",
|
|
@@ -144,7 +239,7 @@ export default defineAction({
|
|
|
144
239
|
name: dashboard.title,
|
|
145
240
|
alreadyInstalled: false,
|
|
146
241
|
overwritten: !!existing,
|
|
147
|
-
urlPath: `/
|
|
242
|
+
urlPath: `/dashboards/${dashboardId}`,
|
|
148
243
|
deepLink: buildDeepLink({
|
|
149
244
|
app: "analytics",
|
|
150
245
|
view: "adhoc",
|
|
@@ -2,7 +2,7 @@ import { defineAction, embedApp } from "@agent-native/core";
|
|
|
2
2
|
import { buildDeepLink } from "@agent-native/core/server";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
|
-
const TRAFFIC_DASHBOARD_PATH = "/
|
|
5
|
+
const TRAFFIC_DASHBOARD_PATH = "/dashboards/agent-native-templates-first-party";
|
|
6
6
|
const TRAFFIC_DASHBOARD_ID = "agent-native-templates-first-party";
|
|
7
7
|
|
|
8
8
|
function trafficDashboardDeepLink(): string {
|