@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
|
@@ -35,6 +35,8 @@ export default defineAction({
|
|
|
35
35
|
id: r.id,
|
|
36
36
|
submittedAt: r.submittedAt,
|
|
37
37
|
submitterEmail: r.submitterEmail ?? null,
|
|
38
|
+
pageUrl: r.pageUrl ?? null,
|
|
39
|
+
clientSurface: r.clientSurface ?? null,
|
|
38
40
|
...JSON.parse(r.data),
|
|
39
41
|
}));
|
|
40
42
|
fs.writeFileSync(outputPath, JSON.stringify(data, null, 2));
|
|
@@ -43,6 +45,8 @@ export default defineAction({
|
|
|
43
45
|
"ID",
|
|
44
46
|
"Submitted At",
|
|
45
47
|
"Submitter Email",
|
|
48
|
+
"Page URL",
|
|
49
|
+
"Source",
|
|
46
50
|
...fields.map((f: any) => f.label),
|
|
47
51
|
];
|
|
48
52
|
const rows = responses.map((r) => {
|
|
@@ -51,6 +55,8 @@ export default defineAction({
|
|
|
51
55
|
r.id,
|
|
52
56
|
r.submittedAt,
|
|
53
57
|
r.submitterEmail ?? "",
|
|
58
|
+
r.pageUrl ?? "",
|
|
59
|
+
r.clientSurface ?? "",
|
|
54
60
|
...fields.map((f: any) => {
|
|
55
61
|
const val = data[f.id];
|
|
56
62
|
if (Array.isArray(val)) return val.join("; ");
|
|
@@ -49,6 +49,8 @@ export default defineAction({
|
|
|
49
49
|
data: JSON.parse(r.data),
|
|
50
50
|
submittedAt: r.submittedAt,
|
|
51
51
|
submitterEmail: r.submitterEmail ?? null,
|
|
52
|
+
pageUrl: r.pageUrl ?? null,
|
|
53
|
+
clientSurface: r.clientSurface ?? null,
|
|
52
54
|
})) as FormResponse[],
|
|
53
55
|
total: (total as any)?.count ?? 0,
|
|
54
56
|
fields: JSON.parse(form.fields),
|
|
@@ -318,6 +318,8 @@ export default defineAction({
|
|
|
318
318
|
submittedAt: schema.responses.submittedAt,
|
|
319
319
|
ip: schema.responses.ip,
|
|
320
320
|
submitterEmail: schema.responses.submitterEmail,
|
|
321
|
+
pageUrl: schema.responses.pageUrl,
|
|
322
|
+
clientSurface: schema.responses.clientSurface,
|
|
321
323
|
})
|
|
322
324
|
.from(schema.responses)
|
|
323
325
|
.where(responseFilter)
|
|
@@ -29,6 +29,39 @@ function valueAsString(val: unknown): string {
|
|
|
29
29
|
return String(val);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/** Drop the protocol for a cleaner table cell; the full URL stays the link href. */
|
|
33
|
+
function formatPageUrl(url: string): string {
|
|
34
|
+
return url.replace(/^https?:\/\//, "");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Only http(s) URLs are safe to use as an anchor href. Page URLs arrive from
|
|
39
|
+
* client `_meta` and could be spoofed by a direct POST, so reject other schemes
|
|
40
|
+
* (e.g. `javascript:`) to avoid a self-XSS when the owner clicks the cell.
|
|
41
|
+
*/
|
|
42
|
+
function safeHttpUrl(value: string): string | null {
|
|
43
|
+
try {
|
|
44
|
+
const u = new URL(value);
|
|
45
|
+
return u.protocol === "http:" || u.protocol === "https:" ? u.href : null;
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Friendly label for the client-surface token forwarded by feedback embeds. */
|
|
52
|
+
function formatClientSurface(surface: string): string {
|
|
53
|
+
switch (surface) {
|
|
54
|
+
case "electron":
|
|
55
|
+
return "Desktop (Electron)";
|
|
56
|
+
case "tauri":
|
|
57
|
+
return "Desktop (Tauri)";
|
|
58
|
+
case "web":
|
|
59
|
+
return "Web";
|
|
60
|
+
default:
|
|
61
|
+
return surface;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
32
65
|
function compareValues(a: unknown, b: unknown): number {
|
|
33
66
|
// Empty values sort last regardless of direction.
|
|
34
67
|
const aEmpty = a === undefined || a === null || a === "";
|
|
@@ -66,8 +99,21 @@ export function ResponsesPage() {
|
|
|
66
99
|
() => responses.some((r: any) => valueAsString(r.submitterEmail).trim()),
|
|
67
100
|
[responses],
|
|
68
101
|
);
|
|
102
|
+
const hasPageUrl = useMemo(
|
|
103
|
+
() => responses.some((r: any) => valueAsString(r.pageUrl).trim()),
|
|
104
|
+
[responses],
|
|
105
|
+
);
|
|
106
|
+
const hasClientSurface = useMemo(
|
|
107
|
+
() => responses.some((r: any) => valueAsString(r.clientSurface).trim()),
|
|
108
|
+
[responses],
|
|
109
|
+
);
|
|
69
110
|
const responseTableMinWidth =
|
|
70
|
-
64 +
|
|
111
|
+
64 +
|
|
112
|
+
160 +
|
|
113
|
+
(hasSubmitterEmail ? 224 : 0) +
|
|
114
|
+
(hasPageUrl ? 256 : 0) +
|
|
115
|
+
(hasClientSurface ? 160 : 0) +
|
|
116
|
+
Math.max(fields.length, 1) * 320;
|
|
71
117
|
|
|
72
118
|
function toggleSort(key: SortKey) {
|
|
73
119
|
if (sortKey === key) {
|
|
@@ -86,6 +132,16 @@ export function ResponsesPage() {
|
|
|
86
132
|
if (valueAsString(r.submitterEmail).toLowerCase().includes(q)) {
|
|
87
133
|
return true;
|
|
88
134
|
}
|
|
135
|
+
if (valueAsString(r.pageUrl).toLowerCase().includes(q)) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
if (
|
|
139
|
+
formatClientSurface(valueAsString(r.clientSurface))
|
|
140
|
+
.toLowerCase()
|
|
141
|
+
.includes(q)
|
|
142
|
+
) {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
89
145
|
for (const f of fields) {
|
|
90
146
|
if (valueAsString(r.data[f.id]).toLowerCase().includes(q))
|
|
91
147
|
return true;
|
|
@@ -100,6 +156,10 @@ export function ResponsesPage() {
|
|
|
100
156
|
new Date(a.submittedAt).getTime() - new Date(b.submittedAt).getTime();
|
|
101
157
|
} else if (sortKey === "_email") {
|
|
102
158
|
cmp = compareValues(a.submitterEmail, b.submitterEmail);
|
|
159
|
+
} else if (sortKey === "_page") {
|
|
160
|
+
cmp = compareValues(a.pageUrl, b.pageUrl);
|
|
161
|
+
} else if (sortKey === "_source") {
|
|
162
|
+
cmp = compareValues(a.clientSurface, b.clientSurface);
|
|
103
163
|
} else {
|
|
104
164
|
cmp = compareValues(a.data[sortKey], b.data[sortKey]);
|
|
105
165
|
}
|
|
@@ -113,11 +173,21 @@ export function ResponsesPage() {
|
|
|
113
173
|
const headers = [
|
|
114
174
|
"Submitted At",
|
|
115
175
|
...(hasSubmitterEmail ? ["Submitter Email"] : []),
|
|
176
|
+
...(hasPageUrl ? ["Page URL"] : []),
|
|
177
|
+
...(hasClientSurface ? ["Source"] : []),
|
|
116
178
|
...fields.map((f) => f.label),
|
|
117
179
|
];
|
|
118
180
|
const rows = filteredSorted.map((r) => [
|
|
119
181
|
r.submittedAt,
|
|
120
182
|
...(hasSubmitterEmail ? [valueAsString(r.submitterEmail)] : []),
|
|
183
|
+
...(hasPageUrl ? [valueAsString(r.pageUrl)] : []),
|
|
184
|
+
...(hasClientSurface
|
|
185
|
+
? [
|
|
186
|
+
valueAsString(r.clientSurface)
|
|
187
|
+
? formatClientSurface(valueAsString(r.clientSurface))
|
|
188
|
+
: "",
|
|
189
|
+
]
|
|
190
|
+
: []),
|
|
121
191
|
...fields.map((f) => valueAsString(r.data[f.id])),
|
|
122
192
|
]);
|
|
123
193
|
|
|
@@ -282,6 +352,8 @@ export function ResponsesPage() {
|
|
|
282
352
|
<col className="w-16" />
|
|
283
353
|
<col className="w-40" />
|
|
284
354
|
{hasSubmitterEmail ? <col className="w-56" /> : null}
|
|
355
|
+
{hasPageUrl ? <col className="w-64" /> : null}
|
|
356
|
+
{hasClientSurface ? <col className="w-40" /> : null}
|
|
285
357
|
{fields.map((f) => (
|
|
286
358
|
<col key={f.id} className="w-80" />
|
|
287
359
|
))}
|
|
@@ -308,6 +380,22 @@ export function ResponsesPage() {
|
|
|
308
380
|
onClick={() => toggleSort("_email")}
|
|
309
381
|
/>
|
|
310
382
|
) : null}
|
|
383
|
+
{hasPageUrl ? (
|
|
384
|
+
<SortableHeader
|
|
385
|
+
label="Page"
|
|
386
|
+
active={sortKey === "_page"}
|
|
387
|
+
dir={sortDir}
|
|
388
|
+
onClick={() => toggleSort("_page")}
|
|
389
|
+
/>
|
|
390
|
+
) : null}
|
|
391
|
+
{hasClientSurface ? (
|
|
392
|
+
<SortableHeader
|
|
393
|
+
label="Source"
|
|
394
|
+
active={sortKey === "_source"}
|
|
395
|
+
dir={sortDir}
|
|
396
|
+
onClick={() => toggleSort("_source")}
|
|
397
|
+
/>
|
|
398
|
+
) : null}
|
|
311
399
|
{fields.map((f) => (
|
|
312
400
|
<SortableHeader
|
|
313
401
|
key={f.id}
|
|
@@ -336,6 +424,55 @@ export function ResponsesPage() {
|
|
|
336
424
|
{valueAsString(response.submitterEmail) || "-"}
|
|
337
425
|
</td>
|
|
338
426
|
) : null}
|
|
427
|
+
{hasPageUrl ? (
|
|
428
|
+
<td className="w-64 px-4 py-3 align-top text-xs whitespace-normal break-words">
|
|
429
|
+
{(() => {
|
|
430
|
+
const raw = valueAsString(response.pageUrl);
|
|
431
|
+
if (!raw)
|
|
432
|
+
return (
|
|
433
|
+
<span className="text-muted-foreground">-</span>
|
|
434
|
+
);
|
|
435
|
+
const safe = safeHttpUrl(raw);
|
|
436
|
+
return safe ? (
|
|
437
|
+
<a
|
|
438
|
+
href={safe}
|
|
439
|
+
target="_blank"
|
|
440
|
+
rel="noopener noreferrer nofollow"
|
|
441
|
+
title={raw}
|
|
442
|
+
className="text-primary hover:underline"
|
|
443
|
+
>
|
|
444
|
+
{formatPageUrl(raw)}
|
|
445
|
+
</a>
|
|
446
|
+
) : (
|
|
447
|
+
<span title={raw} className="text-muted-foreground">
|
|
448
|
+
{formatPageUrl(raw)}
|
|
449
|
+
</span>
|
|
450
|
+
);
|
|
451
|
+
})()}
|
|
452
|
+
</td>
|
|
453
|
+
) : null}
|
|
454
|
+
{hasClientSurface ? (
|
|
455
|
+
<td className="w-40 px-4 py-3 align-top text-xs whitespace-nowrap">
|
|
456
|
+
{(() => {
|
|
457
|
+
const surface = valueAsString(response.clientSurface);
|
|
458
|
+
if (!surface)
|
|
459
|
+
return (
|
|
460
|
+
<span className="text-muted-foreground">-</span>
|
|
461
|
+
);
|
|
462
|
+
const label = formatClientSurface(surface);
|
|
463
|
+
// Make desktop submissions pop; web stays muted text.
|
|
464
|
+
return surface === "web" ? (
|
|
465
|
+
<span className="text-muted-foreground">
|
|
466
|
+
{label}
|
|
467
|
+
</span>
|
|
468
|
+
) : (
|
|
469
|
+
<Badge variant="secondary" className="font-normal">
|
|
470
|
+
{label}
|
|
471
|
+
</Badge>
|
|
472
|
+
);
|
|
473
|
+
})()}
|
|
474
|
+
</td>
|
|
475
|
+
) : null}
|
|
339
476
|
{fields.map((f) => {
|
|
340
477
|
const val = response.data[f.id];
|
|
341
478
|
const display =
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
setClientAppState,
|
|
28
28
|
} from "@agent-native/core/client";
|
|
29
29
|
import type { LinksFunction } from "react-router";
|
|
30
|
+
import changelog from "../CHANGELOG.md?raw";
|
|
30
31
|
import stylesheet from "./global.css?url";
|
|
31
32
|
import { TAB_ID } from "@/lib/tab-id";
|
|
32
33
|
|
|
@@ -198,7 +199,12 @@ export default function Root() {
|
|
|
198
199
|
<NavigationStateSync />
|
|
199
200
|
<UrlStateSync />
|
|
200
201
|
<OpenLinkInterceptor />
|
|
201
|
-
<CommandMenu
|
|
202
|
+
<CommandMenu
|
|
203
|
+
open={cmdkOpen}
|
|
204
|
+
onOpenChange={setCmdkOpen}
|
|
205
|
+
changelog={changelog}
|
|
206
|
+
changelogKey="forms"
|
|
207
|
+
>
|
|
202
208
|
<CommandMenu.Group heading="Forms">
|
|
203
209
|
<CommandMenu.Item onSelect={() => {}}>Search forms</CommandMenu.Item>
|
|
204
210
|
</CommandMenu.Group>
|
|
@@ -32,6 +32,13 @@ export const responses = table("responses", {
|
|
|
32
32
|
submittedAt: text("submitted_at").notNull(),
|
|
33
33
|
ip: text("ip"),
|
|
34
34
|
submitterEmail: text("submitter_email"),
|
|
35
|
+
// URL of the page the respondent was on, forwarded by trusted embeds (e.g.
|
|
36
|
+
// the framework FeedbackButton) as a hidden pass-through field. Client-scrubbed
|
|
37
|
+
// of sensitive query params. NULL for direct fills that send no page context.
|
|
38
|
+
pageUrl: text("page_url"),
|
|
39
|
+
// Runtime shell the feedback was sent from: "web", "electron", or "tauri".
|
|
40
|
+
// Hidden pass-through field forwarded by trusted embeds. NULL when unknown.
|
|
41
|
+
clientSurface: text("client_surface"),
|
|
35
42
|
});
|
|
36
43
|
|
|
37
44
|
export const formShares = createSharesTable("form_shares");
|
|
@@ -49,6 +49,15 @@ function cleanSubmitterEmail(value: unknown): string | null {
|
|
|
49
49
|
return trimmed;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
// Allowlist the client-surface hint so only known values are stored. Anything
|
|
53
|
+
// else (including spoofed direct POSTs) is dropped to NULL.
|
|
54
|
+
const KNOWN_CLIENT_SURFACES = new Set(["web", "electron", "tauri"]);
|
|
55
|
+
function cleanClientSurface(value: unknown): string | null {
|
|
56
|
+
if (typeof value !== "string") return null;
|
|
57
|
+
const normalized = value.trim().toLowerCase();
|
|
58
|
+
return KNOWN_CLIENT_SURFACES.has(normalized) ? normalized : null;
|
|
59
|
+
}
|
|
60
|
+
|
|
52
61
|
function cleanChatSessionIds(value: unknown): string[] {
|
|
53
62
|
const ids: string[] = [];
|
|
54
63
|
const visit = (item: unknown) => {
|
|
@@ -219,6 +228,7 @@ export const submitForm = defineEventHandler(async (event: H3Event) => {
|
|
|
219
228
|
chatSessionIds?: unknown;
|
|
220
229
|
activeRunId?: unknown;
|
|
221
230
|
pageUrl?: unknown;
|
|
231
|
+
clientSurface?: unknown;
|
|
222
232
|
})
|
|
223
233
|
: null;
|
|
224
234
|
const session = await getSession(event).catch(() => null);
|
|
@@ -231,6 +241,7 @@ export const submitForm = defineEventHandler(async (event: H3Event) => {
|
|
|
231
241
|
]);
|
|
232
242
|
const activeRunId = cleanMetaText(meta?.activeRunId);
|
|
233
243
|
const pageUrl = cleanMetaText(meta?.pageUrl);
|
|
244
|
+
const clientSurface = cleanClientSurface(meta?.clientSurface);
|
|
234
245
|
|
|
235
246
|
await db.insert(schema.responses).values({
|
|
236
247
|
id: responseId,
|
|
@@ -239,6 +250,8 @@ export const submitForm = defineEventHandler(async (event: H3Event) => {
|
|
|
239
250
|
submittedAt: now,
|
|
240
251
|
ip,
|
|
241
252
|
submitterEmail,
|
|
253
|
+
pageUrl,
|
|
254
|
+
clientSurface,
|
|
242
255
|
});
|
|
243
256
|
|
|
244
257
|
// Write submission notification to application state (SQL-backed)
|
|
@@ -257,8 +270,9 @@ export const submitForm = defineEventHandler(async (event: H3Event) => {
|
|
|
257
270
|
// Fire integrations best-effort and never fail the submission. Keep this
|
|
258
271
|
// awaited: serverless hosts can freeze fire-and-forget work as soon as the
|
|
259
272
|
// HTTP response returns, which silently drops Slack/webhook delivery.
|
|
260
|
-
//
|
|
261
|
-
//
|
|
273
|
+
// pageUrl and clientSurface are persisted on the response (above) so owners
|
|
274
|
+
// can see which screen and which app feedback came from; chat session ids and
|
|
275
|
+
// run ids remain integration-only debug breadcrumbs we don't retain in SQL.
|
|
262
276
|
try {
|
|
263
277
|
const integrations: FormIntegration[] = settings.integrations ?? [];
|
|
264
278
|
if (integrations.length > 0) {
|
|
@@ -273,6 +287,7 @@ export const submitForm = defineEventHandler(async (event: H3Event) => {
|
|
|
273
287
|
chatSessionIds,
|
|
274
288
|
activeRunId,
|
|
275
289
|
pageUrl,
|
|
290
|
+
clientSurface,
|
|
276
291
|
});
|
|
277
292
|
}
|
|
278
293
|
} catch {
|
|
@@ -326,6 +341,8 @@ export const listResponses = defineEventHandler(async (event: H3Event) => {
|
|
|
326
341
|
data: JSON.parse(r.data),
|
|
327
342
|
submittedAt: r.submittedAt,
|
|
328
343
|
submitterEmail: r.submitterEmail,
|
|
344
|
+
pageUrl: r.pageUrl ?? null,
|
|
345
|
+
clientSurface: r.clientSurface ?? null,
|
|
329
346
|
})) as FormResponse[],
|
|
330
347
|
total: total?.count ?? 0,
|
|
331
348
|
fields: JSON.parse(access.resource.fields),
|
|
@@ -48,6 +48,64 @@ interface SubmissionPayload {
|
|
|
48
48
|
activeRunId?: string | null;
|
|
49
49
|
/** Page URL where the feedback was submitted, when available. */
|
|
50
50
|
pageUrl?: string | null;
|
|
51
|
+
/** Client surface (web/electron/tauri) the feedback came from, when known. */
|
|
52
|
+
clientSurface?: string | null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Human-readable label for a client-surface token. */
|
|
56
|
+
function clientSurfaceLabel(surface: string): string {
|
|
57
|
+
switch (surface) {
|
|
58
|
+
case "electron":
|
|
59
|
+
return "Desktop (Electron)";
|
|
60
|
+
case "tauri":
|
|
61
|
+
return "Desktop (Tauri)";
|
|
62
|
+
case "web":
|
|
63
|
+
return "Web";
|
|
64
|
+
default:
|
|
65
|
+
return surface;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Friendly app name derived from a feedback page URL, so a reviewer can tell at
|
|
71
|
+
* a glance which app the feedback came from. `plan.agent-native.com` → "Plan",
|
|
72
|
+
* `analytics.agent-native.com` → "Analytics". Returns null when the host isn't a
|
|
73
|
+
* recognizable per-app subdomain (the full URL still carries the page).
|
|
74
|
+
*/
|
|
75
|
+
function appLabelFromUrl(pageUrl: string): string | null {
|
|
76
|
+
try {
|
|
77
|
+
const { hostname } = new URL(pageUrl);
|
|
78
|
+
const match = hostname.match(/^([a-z0-9-]+)\.agent-native\.com$/i);
|
|
79
|
+
const sub = match?.[1];
|
|
80
|
+
if (!sub || sub === "www") return null;
|
|
81
|
+
return sub
|
|
82
|
+
.split("-")
|
|
83
|
+
.map((part) => (part ? part[0].toUpperCase() + part.slice(1) : part))
|
|
84
|
+
.join(" ");
|
|
85
|
+
} catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Readable host+path label for a feedback page URL, used as the visible text of
|
|
92
|
+
* the Slack link so the app/page is legible inline instead of hidden behind a
|
|
93
|
+
* bare "open". The full (already client-scrubbed) URL stays the link target.
|
|
94
|
+
*/
|
|
95
|
+
function pageLabelFromUrl(pageUrl: string): string {
|
|
96
|
+
let label = pageUrl;
|
|
97
|
+
try {
|
|
98
|
+
const url = new URL(pageUrl);
|
|
99
|
+
label = `${url.hostname}${url.pathname}`.replace(/\/$/, "") || url.hostname;
|
|
100
|
+
} catch {
|
|
101
|
+
// fall back to the raw string below
|
|
102
|
+
}
|
|
103
|
+
if (label.length > 80) label = `${label.slice(0, 79)}…`;
|
|
104
|
+
// Escape Slack mrkdwn link-text control characters.
|
|
105
|
+
return label
|
|
106
|
+
.replace(/&/g, "&")
|
|
107
|
+
.replace(/</g, "<")
|
|
108
|
+
.replace(/>/g, ">");
|
|
51
109
|
}
|
|
52
110
|
|
|
53
111
|
// ---------------------------------------------------------------------------
|
|
@@ -82,13 +140,20 @@ function formatDebugContext(submission: SubmissionPayload): string[] {
|
|
|
82
140
|
lines.push(`Run: \`${submission.activeRunId}\``);
|
|
83
141
|
}
|
|
84
142
|
if (submission.pageUrl) {
|
|
85
|
-
|
|
143
|
+
const appLabel = appLabelFromUrl(submission.pageUrl);
|
|
144
|
+
if (appLabel) lines.push(`App: ${appLabel}`);
|
|
145
|
+
lines.push(
|
|
146
|
+
`Page: <${submission.pageUrl}|${pageLabelFromUrl(submission.pageUrl)}>`,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
if (submission.clientSurface) {
|
|
150
|
+
lines.push(`Source: ${clientSurfaceLabel(submission.clientSurface)}`);
|
|
86
151
|
}
|
|
87
152
|
return lines;
|
|
88
153
|
}
|
|
89
154
|
|
|
90
155
|
/** Slack Block Kit message */
|
|
91
|
-
function buildSlackPayload(submission: SubmissionPayload) {
|
|
156
|
+
export function buildSlackPayload(submission: SubmissionPayload) {
|
|
92
157
|
const fieldLines = submission.fields
|
|
93
158
|
.filter((f) => submission.data[f.id] !== undefined)
|
|
94
159
|
.map((f) => {
|
|
@@ -170,6 +235,13 @@ function buildDiscordPayload(submission: SubmissionPayload) {
|
|
|
170
235
|
inline: false,
|
|
171
236
|
});
|
|
172
237
|
}
|
|
238
|
+
if (submission.clientSurface) {
|
|
239
|
+
discordFields.push({
|
|
240
|
+
name: "Source",
|
|
241
|
+
value: clientSurfaceLabel(submission.clientSurface),
|
|
242
|
+
inline: true,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
173
245
|
|
|
174
246
|
return {
|
|
175
247
|
embeds: [
|
|
@@ -192,6 +264,7 @@ function buildGoogleSheetsPayload(submission: SubmissionPayload) {
|
|
|
192
264
|
chatSessionIds: (submission.chatSessionIds ?? []).join(", "),
|
|
193
265
|
activeRunId: submission.activeRunId ?? "",
|
|
194
266
|
pageUrl: submission.pageUrl ?? "",
|
|
267
|
+
clientSurface: submission.clientSurface ?? "",
|
|
195
268
|
...formatFields(submission.fields, submission.data),
|
|
196
269
|
};
|
|
197
270
|
}
|
|
@@ -208,6 +281,7 @@ function buildWebhookPayload(submission: SubmissionPayload) {
|
|
|
208
281
|
chatSessionIds: submission.chatSessionIds ?? [],
|
|
209
282
|
activeRunId: submission.activeRunId ?? null,
|
|
210
283
|
pageUrl: submission.pageUrl ?? null,
|
|
284
|
+
clientSurface: submission.clientSurface ?? null,
|
|
211
285
|
data: formatFields(submission.fields, submission.data),
|
|
212
286
|
rawData: submission.data,
|
|
213
287
|
};
|
|
@@ -102,6 +102,26 @@ CREATE TABLE IF NOT EXISTS form_shares (
|
|
|
102
102
|
CREATE INDEX IF NOT EXISTS responses_form_id_idx ON responses (form_id, submitted_at);
|
|
103
103
|
CREATE INDEX IF NOT EXISTS form_shares_resource_idx ON form_shares (resource_id, principal_type, principal_id)`,
|
|
104
104
|
},
|
|
105
|
+
{
|
|
106
|
+
// Page URL the respondent was on, forwarded by trusted embeds (e.g. the
|
|
107
|
+
// framework FeedbackButton) as a hidden pass-through field so owners can
|
|
108
|
+
// see which screen feedback came from in the responses table.
|
|
109
|
+
version: 11,
|
|
110
|
+
sql: {
|
|
111
|
+
postgres: `ALTER TABLE responses ADD COLUMN IF NOT EXISTS page_url TEXT`,
|
|
112
|
+
sqlite: `ALTER TABLE responses ADD COLUMN IF NOT EXISTS page_url TEXT`,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
// Client surface (web/electron/tauri) the respondent submitted from,
|
|
117
|
+
// forwarded by trusted embeds as a hidden pass-through field so owners can
|
|
118
|
+
// see whether feedback came from a desktop app or the browser.
|
|
119
|
+
version: 12,
|
|
120
|
+
sql: {
|
|
121
|
+
postgres: `ALTER TABLE responses ADD COLUMN IF NOT EXISTS client_surface TEXT`,
|
|
122
|
+
sqlite: `ALTER TABLE responses ADD COLUMN IF NOT EXISTS client_surface TEXT`,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
105
125
|
],
|
|
106
126
|
{ table: "forms_migrations" },
|
|
107
127
|
);
|
|
@@ -147,6 +147,18 @@ export interface FormResponse {
|
|
|
147
147
|
submittedAt: string;
|
|
148
148
|
/** Email of the submitter when known (claimed by the client; not verified). */
|
|
149
149
|
submitterEmail?: string | null;
|
|
150
|
+
/**
|
|
151
|
+
* URL of the page the respondent was on, forwarded by trusted embeds (e.g.
|
|
152
|
+
* the framework FeedbackButton) as a hidden pass-through field. Null when the
|
|
153
|
+
* submission carried no page context (e.g. a direct fill on the public page).
|
|
154
|
+
*/
|
|
155
|
+
pageUrl?: string | null;
|
|
156
|
+
/**
|
|
157
|
+
* Runtime shell the feedback was sent from — "web", "electron", or "tauri" —
|
|
158
|
+
* forwarded by trusted embeds as a hidden pass-through field. Null when
|
|
159
|
+
* unknown (e.g. a direct fill on the public page).
|
|
160
|
+
*/
|
|
161
|
+
clientSurface?: string | null;
|
|
150
162
|
}
|
|
151
163
|
|
|
152
164
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable user-facing changes to Agent-Native Macros are documented here. Open it any
|
|
4
|
+
time from the command menu (Cmd+K → "What's new").
|
|
5
|
+
|
|
6
|
+
## 2026-06-23
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- See what's new right inside Agent-Native Macros — a changelog now lives in the command menu (Cmd+K).
|
|
@@ -17,6 +17,7 @@ import { IconSun, IconMoon } from "@tabler/icons-react";
|
|
|
17
17
|
import { TAB_ID } from "@/lib/tab-id";
|
|
18
18
|
import { AppLayout } from "@/components/layout/AppLayout";
|
|
19
19
|
import type { LinksFunction } from "react-router";
|
|
20
|
+
import changelog from "../CHANGELOG.md?raw";
|
|
20
21
|
import stylesheet from "./global.css?url";
|
|
21
22
|
|
|
22
23
|
configureTracking({
|
|
@@ -124,7 +125,12 @@ export default function Root() {
|
|
|
124
125
|
toaster={<Toaster richColors position="bottom-left" />}
|
|
125
126
|
>
|
|
126
127
|
<DbSyncSetup />
|
|
127
|
-
<CommandMenu
|
|
128
|
+
<CommandMenu
|
|
129
|
+
open={cmdkOpen}
|
|
130
|
+
onOpenChange={setCmdkOpen}
|
|
131
|
+
changelog={changelog}
|
|
132
|
+
changelogKey="macros"
|
|
133
|
+
>
|
|
128
134
|
<CommandMenu.Group heading="Actions">
|
|
129
135
|
<CommandMenu.Item onSelect={() => {}}>Search</CommandMenu.Item>
|
|
130
136
|
</CommandMenu.Group>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable user-facing changes to Agent-Native Mail 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 Mail — a changelog now lives in the command menu (Cmd+K) and in Settings.
|
|
@@ -25,6 +25,7 @@ import { CommandMenu } from "@agent-native/core/client";
|
|
|
25
25
|
import { useTheme } from "next-themes";
|
|
26
26
|
import { useSettings, useUpdateSettings } from "@/hooks/use-emails";
|
|
27
27
|
import { getResolvedTheme } from "@/lib/theme";
|
|
28
|
+
import changelog from "../../../CHANGELOG.md?raw";
|
|
28
29
|
|
|
29
30
|
interface CommandPaletteProps {
|
|
30
31
|
open: boolean;
|
|
@@ -91,6 +92,8 @@ export function CommandPalette({
|
|
|
91
92
|
open={open}
|
|
92
93
|
onOpenChange={onOpenChange}
|
|
93
94
|
placeholder="Type a command or ask AI..."
|
|
95
|
+
changelog={changelog}
|
|
96
|
+
changelogKey="mail"
|
|
94
97
|
>
|
|
95
98
|
<CommandMenu.Group heading="Actions">
|
|
96
99
|
<CommandMenu.Item
|
|
@@ -6,8 +6,10 @@ import {
|
|
|
6
6
|
useActionMutation,
|
|
7
7
|
useChatModels,
|
|
8
8
|
useChangeVersions,
|
|
9
|
+
ChangelogSettingsCard,
|
|
9
10
|
} from "@agent-native/core/client";
|
|
10
11
|
import { appApiPath } from "@agent-native/core/client";
|
|
12
|
+
import changelog from "../../CHANGELOG.md?raw";
|
|
11
13
|
import {
|
|
12
14
|
IconUsers,
|
|
13
15
|
IconPlus,
|
|
@@ -24,6 +26,7 @@ import {
|
|
|
24
26
|
IconSignature,
|
|
25
27
|
IconFilter,
|
|
26
28
|
IconInfoCircle,
|
|
29
|
+
IconHistory,
|
|
27
30
|
} from "@tabler/icons-react";
|
|
28
31
|
import { cn } from "@/lib/utils";
|
|
29
32
|
import { Button } from "@/components/ui/button";
|
|
@@ -1379,9 +1382,31 @@ function SlackIntakeSection() {
|
|
|
1379
1382
|
);
|
|
1380
1383
|
}
|
|
1381
1384
|
|
|
1385
|
+
// ─── What's New Section ──────────────────────────────────────────────────────
|
|
1386
|
+
|
|
1387
|
+
function WhatsNewSection() {
|
|
1388
|
+
return (
|
|
1389
|
+
<div className="flex-1 overflow-y-auto p-4 sm:p-8">
|
|
1390
|
+
<div className="mb-6">
|
|
1391
|
+
<h2 className="text-[16px] font-semibold text-foreground">
|
|
1392
|
+
What's new
|
|
1393
|
+
</h2>
|
|
1394
|
+
<p className="mt-0.5 text-[13px] text-muted-foreground">
|
|
1395
|
+
Recent user-facing changes to Agent-Native Mail.
|
|
1396
|
+
</p>
|
|
1397
|
+
</div>
|
|
1398
|
+
|
|
1399
|
+
<div className="max-w-2xl">
|
|
1400
|
+
<ChangelogSettingsCard markdown={changelog} />
|
|
1401
|
+
</div>
|
|
1402
|
+
</div>
|
|
1403
|
+
);
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1382
1406
|
// ─── Settings Page ────────────────────────────────────────────────────────────
|
|
1383
1407
|
|
|
1384
1408
|
type SettingsSection =
|
|
1409
|
+
| "whats-new"
|
|
1385
1410
|
| "drafting"
|
|
1386
1411
|
| "automations"
|
|
1387
1412
|
| "gmail-filters"
|
|
@@ -1395,6 +1420,7 @@ const navItems: {
|
|
|
1395
1420
|
label: string;
|
|
1396
1421
|
icon: React.ComponentType<{ className?: string }>;
|
|
1397
1422
|
}[] = [
|
|
1423
|
+
{ id: "whats-new", label: "What's new", icon: IconHistory },
|
|
1398
1424
|
{ id: "drafting", label: "Drafting", icon: IconSignature },
|
|
1399
1425
|
{ id: "automations", label: "Automations", icon: IconBolt },
|
|
1400
1426
|
{ id: "gmail-filters", label: "Gmail Filters", icon: IconFilter },
|
|
@@ -1464,6 +1490,7 @@ export function SettingsPage() {
|
|
|
1464
1490
|
|
|
1465
1491
|
{/* Right content panel */}
|
|
1466
1492
|
<div className="flex flex-1 overflow-hidden bg-background">
|
|
1493
|
+
{activeSection === "whats-new" && <WhatsNewSection />}
|
|
1467
1494
|
{activeSection === "drafting" && <DraftingSection />}
|
|
1468
1495
|
{activeSection === "automations" && <AutomationsSection />}
|
|
1469
1496
|
{activeSection === "gmail-filters" && <GmailFiltersSection />}
|