@agent-native/core 0.145.5 → 0.145.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +17 -1
- package/corpus/templates/analytics/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +22 -3
- package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/analytics/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/analytics/AGENTS.md +2 -1
- package/corpus/templates/analytics/actions/account-deep-dive.ts +83 -47
- package/corpus/templates/analytics/actions/create-dashboard-folder.ts +27 -0
- package/corpus/templates/analytics/actions/gong-calls.ts +3 -3
- package/corpus/templates/analytics/actions/list-dashboard-folders.ts +26 -0
- package/corpus/templates/analytics/actions/list-sql-dashboards.ts +1 -0
- package/corpus/templates/analytics/actions/set-dashboard-folder.ts +26 -0
- package/corpus/templates/analytics/app/components/ProviderCorpusJobNotifier.tsx +18 -3
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +6 -4
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
- package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +12 -2
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +35 -20
- package/corpus/templates/analytics/app/global.css +17 -0
- package/corpus/templates/analytics/app/hooks/use-dashboard-revisions.ts +29 -15
- package/corpus/templates/analytics/app/hooks/use-dashboard-views.ts +15 -3
- package/corpus/templates/analytics/app/i18n-data.ts +296 -0
- package/corpus/templates/analytics/app/lib/prefetch-keys.ts +23 -2
- package/corpus/templates/analytics/app/pages/DashboardOverview.tsx +642 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +66 -31
- package/corpus/templates/analytics/app/root.tsx +4 -0
- package/corpus/templates/analytics/app/routes/dashboards._index.tsx +5 -1
- package/corpus/templates/analytics/changelog/2026-08-07-added-a-dashboards-overview-with-personal-and-shared-folders.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-07-analytics-no-longer-stalls-under-bursts-of-event-ingest-key-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-07-analytics-tracking-and-chat-startup-no-longer-emit-avoidable.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-07-dashboard-panels-now-load-custom-api-data-programs-reliably.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-07-gong-searches-conserve-api-quota-and-report-incomplete-coverage.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-07-searchable-dashboards-make-personal-and-shared-folders-easie.md +6 -0
- package/corpus/templates/analytics/netlify.toml +3 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +112 -0
- package/corpus/templates/analytics/server/db/index.ts +12 -0
- package/corpus/templates/analytics/server/db/schema.ts +14 -0
- package/corpus/templates/analytics/server/jobs/analytics-rollup-backfill.ts +4 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +1 -0
- package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +85 -15
- package/corpus/templates/analytics/server/lib/dashboard-folders-store.ts +168 -0
- package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +9 -4
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +116 -1
- package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +4 -8
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +65 -10
- package/corpus/templates/analytics/server/lib/gong.ts +139 -78
- package/corpus/templates/analytics/server/lib/session-replay.ts +5 -5
- package/corpus/templates/analytics/server/plugins/db.ts +55 -15
- package/corpus/templates/analytics/server/plugins/session-replay-retention-jobs.ts +6 -2
- package/corpus/templates/analytics/server/routes/api/session-replay/retention.post.ts +65 -0
- package/corpus/templates/assets/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/assets/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/assets/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/brain/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/brain/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/brain/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/calendar/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/calendar/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/chat/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/chat/.env.example +3 -0
- package/corpus/templates/chat/AGENTS.md +4 -0
- package/corpus/templates/clips/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/clips/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/clips/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +4 -0
- package/corpus/templates/clips/actions/request-transcript.ts +52 -3
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +3 -10
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -0
- package/corpus/templates/clips/changelog/2026-08-07-screen-recordings-now-capture-tab-and-system-audio-even-when.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-07-transcription-now-retries-transient-cloud-failures-automatic.md +6 -0
- package/corpus/templates/clips/server/db/schema.ts +7 -0
- package/corpus/templates/clips/server/plugins/db.ts +8 -0
- package/corpus/templates/clips/shared/recording-capture.ts +38 -0
- package/corpus/templates/clips/shared/transcript-failure.ts +89 -0
- package/corpus/templates/content/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/content/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/content/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/content/.env.example +9 -3
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +1 -0
- package/corpus/templates/content/changelog/2026-08-07-collapsed-sidebar-utility-buttons-stay-anchored-at-the-botto.md +6 -0
- package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/crm/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/design/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/design/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/design/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/dispatch/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/factory/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/factory/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/factory/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/factory/actions/babysit-agent-native-pull-request.ts +279 -0
- package/corpus/templates/factory/actions/get-factory-automation-health.ts +23 -4
- package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +1 -1
- package/corpus/templates/factory/app/routes/factory.tsx +21 -3
- package/corpus/templates/factory/changelog/2026-08-07-factory-can-keep-builder-bot-pull-requests-moving-by-request.md +6 -0
- package/corpus/templates/factory/server/lib/require-factory-automation.ts +1 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +4 -1
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +81 -12
- package/corpus/templates/factory/server/triage/github-client.ts +31 -0
- package/corpus/templates/factory/server/triage/pr-babysit.ts +75 -1
- package/corpus/templates/forms/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/forms/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/forms/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/macros/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/mail/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/mail/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/mail/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/plan/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/plan/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/plan/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +2 -1
- package/corpus/templates/plan/changelog/2026-08-07-inline-help-icons-now-stay-visually-balanced-with-nearby-tex.md +6 -0
- package/corpus/templates/slides/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/slides/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/slides/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/slides/.env.example +5 -0
- package/corpus/templates/slides/changelog/2026-08-07-fixed-generated-slides-briefly-disappearing-while-they-are-b.md +6 -0
- package/corpus/templates/slides/server/plugins/collab.ts +20 -8
- package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +18 -0
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/corpus/templates/tasks/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/corpus/templates/tasks/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/corpus/templates/tasks/.env.example +3 -0
- package/dist/agent/production-agent.js +24 -3
- package/dist/client/AgentPanel.d.ts +6 -0
- package/dist/client/AgentPanel.js +176 -30
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.js +4 -1
- package/dist/client/ConnectBuilderCard.js +6 -11
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/RuntimeConfigNotice.d.ts +1 -0
- package/dist/client/RuntimeConfigNotice.js +94 -0
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/agent-chat/index.js +1 -1
- package/dist/client/agent-chat-adapter.js +85 -4
- package/dist/client/agent-page/AgentTabsPage.js +1 -1
- package/dist/client/agent-sidebar-state.d.ts +6 -0
- package/dist/client/agent-sidebar-state.js +25 -0
- package/dist/client/app-providers.js +2 -1
- package/dist/client/assistant-ui-recovery.js +1 -1
- package/dist/client/chat/index.d.ts +1 -1
- package/dist/client/chat/index.js +1 -1
- package/dist/client/chat/markdown-renderer.d.ts +2 -1
- package/dist/client/chat/markdown-renderer.js +48 -2
- package/dist/client/chat/message-components.d.ts +6 -0
- package/dist/client/chat/message-components.js +182 -53
- package/dist/client/chat/tool-call-display.d.ts +16 -4
- package/dist/client/chat/tool-call-display.js +225 -18
- package/dist/client/extensions/ExtensionsSidebarSection.js +1 -1
- package/dist/client/frame-protocol.d.ts +4 -0
- package/dist/client/i18n.js +9 -0
- package/dist/client/integrations/IntegrationsPanel.js +2 -5
- package/dist/client/onboarding/FirstRunOnboarding.js +2 -3
- package/dist/client/org/TeamPage.js +49 -6
- package/dist/client/org/hooks.d.ts +7 -2
- package/dist/client/org/hooks.js +11 -4
- package/dist/client/resources/McpConnectionSuggestion.js +2 -3
- package/dist/client/resources/McpIntegrationDialog.js +2 -16
- package/dist/client/resources/McpIntegrationLogo.d.ts +11 -0
- package/dist/client/resources/McpIntegrationLogo.js +14 -0
- package/dist/client/resources/ResourceTree.js +1 -1
- package/dist/client/resources/mcp-integration-logos.d.ts +1 -0
- package/dist/client/resources/mcp-integration-logos.js +47 -18
- package/dist/client/settings/useBuilderStatus.js +6 -0
- package/dist/client/ui/index.d.ts +1 -0
- package/dist/client/ui/index.js +1 -0
- package/dist/client/use-db-sync.js +4 -0
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/config.d.ts +26 -3
- package/dist/config.js +106 -14
- package/dist/db/ddl-guard.d.ts +15 -2
- package/dist/db/ddl-guard.js +53 -5
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/jobs/scheduler.js +7 -0
- package/dist/localization/default-messages.d.ts +17 -0
- package/dist/localization/default-messages.js +17 -0
- package/dist/mcp/oauth-client-metadata.js +5 -1
- package/dist/mcp/oauth-route.d.ts +5 -4
- package/dist/mcp/oauth-route.js +25 -9
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +9 -10
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +3 -3
- package/dist/org/handlers.d.ts +1 -0
- package/dist/org/handlers.js +17 -2
- package/dist/provider-api/actions/custom-provider-registration.d.ts +5 -5
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/provider-api/corpus-jobs.d.ts +12 -2
- package/dist/provider-api/corpus-jobs.js +31 -1
- package/dist/provider-api/index.d.ts +2 -0
- package/dist/provider-api/index.js +7 -1
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/agent-chat/recurring-jobs-runtime.d.ts +1 -1
- package/dist/server/agent-chat/recurring-jobs-runtime.js +14 -2
- package/dist/server/agent-chat/script-entries.js +12 -1
- package/dist/server/agent-chat-plugin.js +2 -2
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.d.ts +1 -0
- package/dist/server/auth.js +85 -1
- package/dist/server/better-auth-instance.d.ts +9 -0
- package/dist/server/better-auth-instance.js +25 -11
- package/dist/server/core-routes-plugin.d.ts +7 -0
- package/dist/server/core-routes-plugin.js +51 -5
- package/dist/server/create-server.js +23 -2
- package/dist/server/db-pressure.d.ts +38 -0
- package/dist/server/db-pressure.js +147 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/legacy-auth-migration.d.ts +10 -0
- package/dist/server/legacy-auth-migration.js +37 -0
- package/dist/server/onboarding-html.js +206 -2
- package/dist/server/poll.d.ts +26 -0
- package/dist/server/poll.js +108 -13
- package/dist/server/ssr-handler.js +4 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/shared/runtime-config.d.ts +44 -0
- package/dist/shared/runtime-config.js +284 -0
- package/dist/styles/agent-native.css +48 -1
- package/dist/templates/chat/.agents/skills/actions/SKILL.md +18 -0
- package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/dist/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -0
- package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/dist/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/dist/templates/chat/.env.example +3 -0
- package/dist/templates/chat/AGENTS.md +4 -0
- package/dist/templates/default/.agents/skills/actions/SKILL.md +18 -0
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/dist/templates/default/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +1 -0
- package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/dist/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/dist/templates/default/AGENTS.md +6 -1
- package/dist/templates/default/app/i18n/ar-SA.ts +6 -0
- package/dist/templates/default/app/i18n/de-DE.ts +6 -0
- package/dist/templates/default/app/i18n/en-US.ts +6 -0
- package/dist/templates/default/app/i18n/es-ES.ts +6 -0
- package/dist/templates/default/app/i18n/fr-FR.ts +6 -0
- package/dist/templates/default/app/i18n/hi-IN.ts +6 -0
- package/dist/templates/default/app/i18n/ja-JP.ts +6 -0
- package/dist/templates/default/app/i18n/ko-KR.ts +6 -0
- package/dist/templates/default/app/i18n/pt-BR.ts +6 -0
- package/dist/templates/default/app/i18n/zh-CN.ts +6 -0
- package/dist/templates/default/app/i18n/zh-TW.ts +6 -0
- package/dist/templates/headless/.agents/skills/actions/SKILL.md +18 -0
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/dist/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +18 -0
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/dist/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +4 -0
- package/dist/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +8 -0
- package/dist/templates/workspace-core/AGENTS.md +7 -2
- package/dist/templates/workspace-root/AGENTS.md +5 -0
- package/dist/vite/client.d.ts +3 -3
- package/dist/vite/client.js +47 -1
- package/dist/vite/index.d.ts +1 -1
- package/docs/content/agent-native-config.mdx +240 -139
- package/docs/content/authentication.mdx +17 -0
- package/docs/content/deployment.mdx +19 -14
- package/docs/content/drop-in-agent.mdx +19 -2
- package/docs/content/environment-variables.mdx +63 -38
- package/docs/content/getting-started-actions.mdx +15 -6
- package/docs/content/getting-started-database.mdx +14 -10
- package/docs/content/getting-started-pages.mdx +32 -35
- package/docs/content/getting-started.mdx +7 -6
- package/package.json +1 -1
- package/src/templates/chat/.agents/skills/actions/SKILL.md +18 -0
- package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -0
- package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/src/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/src/templates/chat/.env.example +3 -0
- package/src/templates/chat/AGENTS.md +4 -0
- package/src/templates/default/.agents/skills/actions/SKILL.md +18 -0
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/src/templates/default/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +1 -0
- package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/src/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/src/templates/default/AGENTS.md +6 -1
- package/src/templates/default/app/i18n/ar-SA.ts +6 -0
- package/src/templates/default/app/i18n/de-DE.ts +6 -0
- package/src/templates/default/app/i18n/en-US.ts +6 -0
- package/src/templates/default/app/i18n/es-ES.ts +6 -0
- package/src/templates/default/app/i18n/fr-FR.ts +6 -0
- package/src/templates/default/app/i18n/hi-IN.ts +6 -0
- package/src/templates/default/app/i18n/ja-JP.ts +6 -0
- package/src/templates/default/app/i18n/ko-KR.ts +6 -0
- package/src/templates/default/app/i18n/pt-BR.ts +6 -0
- package/src/templates/default/app/i18n/zh-CN.ts +6 -0
- package/src/templates/default/app/i18n/zh-TW.ts +6 -0
- package/src/templates/headless/.agents/skills/actions/SKILL.md +18 -0
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/src/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +18 -0
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +45 -47
- package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +76 -23
- package/src/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +2 -2
- package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +64 -0
- package/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +4 -0
- package/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +8 -0
- package/src/templates/workspace-core/AGENTS.md +7 -2
- package/src/templates/workspace-root/AGENTS.md +5 -0
- package/corpus/templates/dispatch/app/routes/admin.apps.$appId.tsx +0 -1
- package/corpus/templates/dispatch/app/routes/admin.apps.tsx +0 -1
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { getAllSettings, listOrgSettings } from "@agent-native/core/settings";
|
|
2
2
|
|
|
3
3
|
import { dashboardCatalogEntries } from "./dashboard-catalog";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
listDashboardSummaries,
|
|
6
|
+
loadDashboardCatalogDashboards,
|
|
7
|
+
type DashboardCatalogRecord,
|
|
8
|
+
type DashboardSummaryRecord,
|
|
9
|
+
} from "./dashboards-store";
|
|
5
10
|
|
|
6
11
|
const DATA_DICTIONARY_KEY_PREFIX = "data-dict-";
|
|
7
12
|
const MAX_QUERY_LENGTH = 12_000;
|
|
13
|
+
const MAX_CATALOG_DASHBOARD_HYDRATION = 24;
|
|
8
14
|
const STOP_WORDS = new Set([
|
|
9
15
|
"a",
|
|
10
16
|
"all",
|
|
@@ -106,6 +112,44 @@ function compactQuery(value: unknown): string | Record<string, unknown> | null {
|
|
|
106
112
|
return null;
|
|
107
113
|
}
|
|
108
114
|
|
|
115
|
+
function summaryScore(
|
|
116
|
+
search: string,
|
|
117
|
+
dashboard: DashboardSummaryRecord,
|
|
118
|
+
): number {
|
|
119
|
+
const { score } = matchScore(search, [
|
|
120
|
+
{ value: dashboard.name, weight: 24 },
|
|
121
|
+
{ value: dashboard.description, weight: 12 },
|
|
122
|
+
{ value: dashboard.configName, weight: 10 },
|
|
123
|
+
{ value: dashboard.catalogTemplateId, weight: 6 },
|
|
124
|
+
{ value: dashboard.demoId, weight: 6 },
|
|
125
|
+
]);
|
|
126
|
+
return score;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function shortlistDashboardSummaries(
|
|
130
|
+
search: string,
|
|
131
|
+
dashboards: DashboardSummaryRecord[],
|
|
132
|
+
limit: number,
|
|
133
|
+
): DashboardSummaryRecord[] {
|
|
134
|
+
const maxHydration = Math.min(
|
|
135
|
+
Math.max(limit * 4, 12),
|
|
136
|
+
MAX_CATALOG_DASHBOARD_HYDRATION,
|
|
137
|
+
);
|
|
138
|
+
return dashboards
|
|
139
|
+
.map((dashboard) => ({
|
|
140
|
+
dashboard,
|
|
141
|
+
score: summaryScore(search, dashboard),
|
|
142
|
+
}))
|
|
143
|
+
.sort((a, b) => {
|
|
144
|
+
if (b.score !== a.score) return b.score - a.score;
|
|
145
|
+
return JSON.stringify(a.dashboard).localeCompare(
|
|
146
|
+
JSON.stringify(b.dashboard),
|
|
147
|
+
);
|
|
148
|
+
})
|
|
149
|
+
.slice(0, maxHydration)
|
|
150
|
+
.map(({ dashboard }) => dashboard);
|
|
151
|
+
}
|
|
152
|
+
|
|
109
153
|
// Analytics vocabulary the corpus spells out but users abbreviate (or vice versa).
|
|
110
154
|
// Expansions match at reduced weight so they break ties without outranking a literal hit.
|
|
111
155
|
const SYNONYM_EXPANSIONS: Record<string, string[]> = {
|
|
@@ -497,13 +541,15 @@ async function listDictionaryEntries(args: {
|
|
|
497
541
|
return entries;
|
|
498
542
|
}
|
|
499
543
|
|
|
500
|
-
function savedDashboardInput(
|
|
501
|
-
|
|
544
|
+
function savedDashboardInput(
|
|
545
|
+
summary: DashboardSummaryRecord,
|
|
546
|
+
dashboard: DashboardCatalogRecord,
|
|
547
|
+
) {
|
|
502
548
|
return {
|
|
503
549
|
id: dashboard.id,
|
|
504
|
-
title:
|
|
505
|
-
description:
|
|
506
|
-
config,
|
|
550
|
+
title: summary.name,
|
|
551
|
+
description: summary.description ?? undefined,
|
|
552
|
+
config: dashboard.config,
|
|
507
553
|
origin: "saved-dashboard" as const,
|
|
508
554
|
};
|
|
509
555
|
}
|
|
@@ -514,26 +560,46 @@ export async function searchAnalyticsQueryCatalog(args: {
|
|
|
514
560
|
orgId: string | null;
|
|
515
561
|
limit: number;
|
|
516
562
|
}): Promise<AnalyticsQueryCatalogCandidate[]> {
|
|
517
|
-
const [
|
|
563
|
+
const [savedSummariesResult, dictionaryEntriesResult] =
|
|
518
564
|
await Promise.allSettled([
|
|
519
|
-
|
|
565
|
+
listDashboardSummaries(
|
|
520
566
|
{ email: args.email, orgId: args.orgId },
|
|
521
|
-
{
|
|
567
|
+
{
|
|
568
|
+
kind: "sql",
|
|
569
|
+
archived: "active",
|
|
570
|
+
hidden: "visible",
|
|
571
|
+
includeCatalogMetadata: true,
|
|
572
|
+
},
|
|
522
573
|
),
|
|
523
574
|
listDictionaryEntries({ email: args.email, orgId: args.orgId }),
|
|
524
575
|
]);
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
?
|
|
576
|
+
const savedSummaries =
|
|
577
|
+
savedSummariesResult.status === "fulfilled"
|
|
578
|
+
? savedSummariesResult.value
|
|
528
579
|
: [];
|
|
529
580
|
const dictionaryEntries =
|
|
530
581
|
dictionaryEntriesResult.status === "fulfilled"
|
|
531
582
|
? dictionaryEntriesResult.value
|
|
532
583
|
: [];
|
|
584
|
+
const savedSummaryIds = new Set(
|
|
585
|
+
savedSummaries.map((dashboard) => dashboard.id),
|
|
586
|
+
);
|
|
533
587
|
|
|
534
|
-
const
|
|
588
|
+
const shortlistedSummaries = shortlistDashboardSummaries(
|
|
589
|
+
args.search,
|
|
590
|
+
savedSummaries,
|
|
591
|
+
args.limit,
|
|
592
|
+
);
|
|
593
|
+
const shortlistedIds = shortlistedSummaries.map((dashboard) => dashboard.id);
|
|
594
|
+
const savedDashboardsResult = await loadDashboardCatalogDashboards(
|
|
595
|
+
{ email: args.email, orgId: args.orgId },
|
|
596
|
+
shortlistedIds,
|
|
597
|
+
);
|
|
598
|
+
const savedDashboards = new Map(
|
|
599
|
+
savedDashboardsResult.map((dashboard) => [dashboard.id, dashboard]),
|
|
600
|
+
);
|
|
535
601
|
const templateDashboards = dashboardCatalogEntries
|
|
536
|
-
.filter((entry) => !
|
|
602
|
+
.filter((entry) => !savedSummaryIds.has(entry.defaultDashboardId))
|
|
537
603
|
.flatMap((entry) => {
|
|
538
604
|
try {
|
|
539
605
|
const config = entry.buildConfig() as unknown as Record<
|
|
@@ -557,7 +623,11 @@ export async function searchAnalyticsQueryCatalog(args: {
|
|
|
557
623
|
return rankAnalyticsQueryCatalog({
|
|
558
624
|
search: args.search,
|
|
559
625
|
dashboards: [
|
|
560
|
-
...
|
|
626
|
+
...shortlistedSummaries.flatMap((summary) => {
|
|
627
|
+
const dashboard = savedDashboards.get(summary.id);
|
|
628
|
+
if (!dashboard) return [];
|
|
629
|
+
return [savedDashboardInput(summary, dashboard)];
|
|
630
|
+
}),
|
|
561
631
|
...templateDashboards,
|
|
562
632
|
],
|
|
563
633
|
dictionaryEntries,
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { recordChange } from "@agent-native/core/server";
|
|
2
|
+
import { accessFilter, assertAccess } from "@agent-native/core/sharing";
|
|
3
|
+
import { desc, eq } from "drizzle-orm";
|
|
4
|
+
|
|
5
|
+
import { getDb, schema } from "../db/index.js";
|
|
6
|
+
import { type DashboardRecord, getDashboard } from "./dashboards-store.js";
|
|
7
|
+
|
|
8
|
+
export type DashboardFolderScope = "personal" | "shared";
|
|
9
|
+
|
|
10
|
+
export interface DashboardFolderContext {
|
|
11
|
+
email: string;
|
|
12
|
+
orgId: string | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface DashboardFolderRecord {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
scope: DashboardFolderScope;
|
|
19
|
+
ownerEmail: string;
|
|
20
|
+
orgId: string | null;
|
|
21
|
+
visibility: "private" | "org" | "public";
|
|
22
|
+
createdAt: string;
|
|
23
|
+
updatedAt: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function nowIso(): string {
|
|
27
|
+
return new Date().toISOString();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function toFolder(row: any): DashboardFolderRecord {
|
|
31
|
+
return {
|
|
32
|
+
id: row.id,
|
|
33
|
+
name: row.name,
|
|
34
|
+
scope: row.scope,
|
|
35
|
+
ownerEmail: row.ownerEmail,
|
|
36
|
+
orgId: row.orgId ?? null,
|
|
37
|
+
visibility: row.visibility,
|
|
38
|
+
createdAt: row.createdAt,
|
|
39
|
+
updatedAt: row.updatedAt,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function listDashboardFolders(
|
|
44
|
+
ctx: DashboardFolderContext,
|
|
45
|
+
): Promise<DashboardFolderRecord[]> {
|
|
46
|
+
const rows = await (getDb() as any)
|
|
47
|
+
.select()
|
|
48
|
+
.from(schema.dashboardFolders)
|
|
49
|
+
.where(
|
|
50
|
+
accessFilter(schema.dashboardFolders, schema.dashboardFolderShares, {
|
|
51
|
+
userEmail: ctx.email,
|
|
52
|
+
orgId: ctx.orgId ?? undefined,
|
|
53
|
+
}),
|
|
54
|
+
)
|
|
55
|
+
.orderBy(desc(schema.dashboardFolders.updatedAt));
|
|
56
|
+
return rows.map(toFolder);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function createDashboardFolder(
|
|
60
|
+
name: string,
|
|
61
|
+
scope: DashboardFolderScope,
|
|
62
|
+
ctx: DashboardFolderContext,
|
|
63
|
+
): Promise<DashboardFolderRecord> {
|
|
64
|
+
const trimmedName = name.trim();
|
|
65
|
+
if (!trimmedName) throw new Error("folder name is required");
|
|
66
|
+
if (scope === "shared" && !ctx.orgId) {
|
|
67
|
+
throw new Error("an active organization is required for shared folders");
|
|
68
|
+
}
|
|
69
|
+
const id = crypto.randomUUID();
|
|
70
|
+
const now = nowIso();
|
|
71
|
+
const folderOrgId = scope === "shared" ? ctx.orgId : null;
|
|
72
|
+
await (getDb() as any).insert(schema.dashboardFolders).values({
|
|
73
|
+
id,
|
|
74
|
+
name: trimmedName,
|
|
75
|
+
scope,
|
|
76
|
+
createdAt: now,
|
|
77
|
+
updatedAt: now,
|
|
78
|
+
ownerEmail: ctx.email,
|
|
79
|
+
orgId: folderOrgId,
|
|
80
|
+
visibility: scope === "shared" ? "org" : "private",
|
|
81
|
+
});
|
|
82
|
+
recordChange({
|
|
83
|
+
source: "dashboard-folders",
|
|
84
|
+
type: "change",
|
|
85
|
+
key: id,
|
|
86
|
+
...(scope === "shared" && ctx.orgId
|
|
87
|
+
? { orgId: ctx.orgId }
|
|
88
|
+
: { owner: ctx.email }),
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
id,
|
|
92
|
+
name: trimmedName,
|
|
93
|
+
scope,
|
|
94
|
+
ownerEmail: ctx.email,
|
|
95
|
+
orgId: folderOrgId,
|
|
96
|
+
visibility: scope === "shared" ? "org" : "private",
|
|
97
|
+
createdAt: now,
|
|
98
|
+
updatedAt: now,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function getFolder(
|
|
103
|
+
id: string,
|
|
104
|
+
ctx: DashboardFolderContext,
|
|
105
|
+
): Promise<DashboardFolderRecord> {
|
|
106
|
+
await assertAccess("dashboard-folder", id, "viewer", {
|
|
107
|
+
userEmail: ctx.email,
|
|
108
|
+
orgId: ctx.orgId ?? undefined,
|
|
109
|
+
});
|
|
110
|
+
const [row] = await (getDb() as any)
|
|
111
|
+
.select()
|
|
112
|
+
.from(schema.dashboardFolders)
|
|
113
|
+
.where(eq(schema.dashboardFolders.id, id))
|
|
114
|
+
.limit(1);
|
|
115
|
+
if (!row) throw new Error("dashboard folder not found");
|
|
116
|
+
return toFolder(row);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function assignDashboardToFolder(
|
|
120
|
+
dashboardId: string,
|
|
121
|
+
folderId: string | null,
|
|
122
|
+
ctx: DashboardFolderContext,
|
|
123
|
+
): Promise<DashboardRecord> {
|
|
124
|
+
const dashboard = await getDashboard(dashboardId, ctx);
|
|
125
|
+
if (!dashboard) throw new Error("dashboard not found or inaccessible");
|
|
126
|
+
await assertAccess("dashboard", dashboardId, "editor", {
|
|
127
|
+
userEmail: ctx.email,
|
|
128
|
+
orgId: ctx.orgId ?? undefined,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (folderId) {
|
|
132
|
+
const folder = await getFolder(folderId, ctx);
|
|
133
|
+
if (folder.scope === "personal") {
|
|
134
|
+
if (
|
|
135
|
+
dashboard.visibility !== "private" ||
|
|
136
|
+
dashboard.ownerEmail.toLowerCase() !== ctx.email.toLowerCase()
|
|
137
|
+
) {
|
|
138
|
+
throw new Error("personal folders require an owned private dashboard");
|
|
139
|
+
}
|
|
140
|
+
} else if (
|
|
141
|
+
dashboard.visibility !== "org" ||
|
|
142
|
+
!ctx.orgId ||
|
|
143
|
+
dashboard.orgId !== ctx.orgId ||
|
|
144
|
+
folder.orgId !== ctx.orgId
|
|
145
|
+
) {
|
|
146
|
+
throw new Error("shared folders require an org-visible dashboard");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
await (getDb() as any)
|
|
151
|
+
.update(schema.dashboards)
|
|
152
|
+
.set({ folderId, updatedAt: nowIso(), updatedBy: ctx.email })
|
|
153
|
+
.where(eq(schema.dashboards.id, dashboardId));
|
|
154
|
+
recordChange({
|
|
155
|
+
source: "dashboards",
|
|
156
|
+
type: "change",
|
|
157
|
+
key: dashboardId,
|
|
158
|
+
...((dashboard.visibility === "org" && dashboard.orgId
|
|
159
|
+
? { orgId: dashboard.orgId }
|
|
160
|
+
: { owner: dashboard.ownerEmail }) as {
|
|
161
|
+
owner?: string;
|
|
162
|
+
orgId?: string;
|
|
163
|
+
}),
|
|
164
|
+
});
|
|
165
|
+
const updated = await getDashboard(dashboardId, ctx);
|
|
166
|
+
if (!updated) throw new Error("dashboard disappeared after folder update");
|
|
167
|
+
return updated;
|
|
168
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { CredentialContext } from "@agent-native/core/credentials";
|
|
2
2
|
import { resolveCredential } from "@agent-native/core/credentials";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getInitializedDataProgramsAppId,
|
|
5
|
+
runDataProgram,
|
|
6
|
+
} from "@agent-native/core/data-programs";
|
|
4
7
|
import type { MissingKeyResponse } from "@agent-native/core/server";
|
|
5
8
|
|
|
6
9
|
import { getUserSegmentation, queryEvents } from "./amplitude";
|
|
@@ -12,6 +15,7 @@ import {
|
|
|
12
15
|
runPrometheusPanel,
|
|
13
16
|
serializePanelDescriptorInput,
|
|
14
17
|
} from "./prometheus";
|
|
18
|
+
import { ANALYTICS_APP_ID } from "./provider-credentials";
|
|
15
19
|
|
|
16
20
|
export const DASHBOARD_PANEL_SOURCES = [
|
|
17
21
|
"bigquery",
|
|
@@ -25,8 +29,6 @@ export const DASHBOARD_PANEL_SOURCES = [
|
|
|
25
29
|
|
|
26
30
|
export type DashboardPanelSource = (typeof DASHBOARD_PANEL_SOURCES)[number];
|
|
27
31
|
|
|
28
|
-
const ANALYTICS_DATA_PROGRAM_APP_ID = "analytics";
|
|
29
|
-
|
|
30
32
|
export interface DashboardPanelQueryResult {
|
|
31
33
|
rows: Record<string, unknown>[];
|
|
32
34
|
schema: { name: string; type: string }[];
|
|
@@ -360,7 +362,10 @@ async function runProgramPanel(
|
|
|
360
362
|
const descriptor = parseProgramDescriptor(raw);
|
|
361
363
|
const result = await runDataProgram({
|
|
362
364
|
programId: descriptor.programId,
|
|
363
|
-
|
|
365
|
+
// Use the same app scope that registered the agent's data-program actions.
|
|
366
|
+
// Standalone template dev can derive that scope from the runtime package
|
|
367
|
+
// even when APP_NAME is not explicitly set.
|
|
368
|
+
appId: getInitializedDataProgramsAppId() ?? ANALYTICS_APP_ID,
|
|
364
369
|
params: descriptor.params,
|
|
365
370
|
ctx: { userEmail: ctx.userEmail, orgId: ctx.orgId ?? null },
|
|
366
371
|
triggeredBy: "panel_view",
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
resolveAccess,
|
|
29
29
|
type ShareRole,
|
|
30
30
|
} from "@agent-native/core/sharing";
|
|
31
|
-
import { and, desc, eq, isNotNull, isNull, sql } from "drizzle-orm";
|
|
31
|
+
import { and, desc, eq, inArray, isNotNull, isNull, sql } from "drizzle-orm";
|
|
32
32
|
|
|
33
33
|
import { getDb, schema } from "../db/index.js";
|
|
34
34
|
|
|
@@ -62,10 +62,12 @@ export interface DashboardSummaryRecord {
|
|
|
62
62
|
id: string;
|
|
63
63
|
kind: DashboardKind;
|
|
64
64
|
name: string;
|
|
65
|
+
description: string | null;
|
|
65
66
|
configName: string | null;
|
|
66
67
|
catalogTemplateId: string | null;
|
|
67
68
|
demoId: string | null;
|
|
68
69
|
parentId: string | null;
|
|
70
|
+
folderId: string | null;
|
|
69
71
|
ownerEmail: string;
|
|
70
72
|
orgId: string | null;
|
|
71
73
|
visibility: "private" | "org" | "public";
|
|
@@ -76,6 +78,17 @@ export interface DashboardSummaryRecord {
|
|
|
76
78
|
hiddenBy: string | null;
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
/** Hydrated dashboard row for catalog ranking only. */
|
|
82
|
+
export interface DashboardCatalogRecord {
|
|
83
|
+
id: string;
|
|
84
|
+
kind: DashboardKind;
|
|
85
|
+
title: string;
|
|
86
|
+
description: string | null;
|
|
87
|
+
config: Record<string, unknown>;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const MAX_CATALOG_DASHBOARD_HYDRATION = 24;
|
|
91
|
+
|
|
79
92
|
export interface DashboardRevisionRecord {
|
|
80
93
|
id: string;
|
|
81
94
|
dashboardId: string;
|
|
@@ -281,6 +294,13 @@ function rowToDashboardRevision(row: any): DashboardRevisionRecord {
|
|
|
281
294
|
};
|
|
282
295
|
}
|
|
283
296
|
|
|
297
|
+
function configDescriptionFromValue(
|
|
298
|
+
value: Record<string, unknown>,
|
|
299
|
+
): string | null {
|
|
300
|
+
const description = value["description"];
|
|
301
|
+
return typeof description === "string" ? description : null;
|
|
302
|
+
}
|
|
303
|
+
|
|
284
304
|
function configFromSettings(data: Record<string, unknown>): {
|
|
285
305
|
title: string;
|
|
286
306
|
config: Record<string, unknown>;
|
|
@@ -564,6 +584,11 @@ export async function listDashboardSummaries(
|
|
|
564
584
|
: sql<
|
|
565
585
|
string | null
|
|
566
586
|
>`json_extract(${schema.dashboards.config}, '$.parentId')`;
|
|
587
|
+
const description = isPostgres()
|
|
588
|
+
? sql<string | null>`(${schema.dashboards.config}::jsonb ->> 'description')`
|
|
589
|
+
: sql<
|
|
590
|
+
string | null
|
|
591
|
+
>`json_extract(${schema.dashboards.config}, '$.description')`;
|
|
567
592
|
const configName = isPostgres()
|
|
568
593
|
? sql<string | null>`(${schema.dashboards.config}::jsonb ->> 'name')`
|
|
569
594
|
: sql<string | null>`json_extract(${schema.dashboards.config}, '$.name')`;
|
|
@@ -586,10 +611,12 @@ export async function listDashboardSummaries(
|
|
|
586
611
|
id: schema.dashboards.id,
|
|
587
612
|
kind: schema.dashboards.kind,
|
|
588
613
|
name: schema.dashboards.title,
|
|
614
|
+
description,
|
|
589
615
|
...(includeCatalogMetadata
|
|
590
616
|
? { configName, catalogTemplateId, demoId }
|
|
591
617
|
: {}),
|
|
592
618
|
parentId,
|
|
619
|
+
folderId: schema.dashboards.folderId,
|
|
593
620
|
ownerEmail: schema.dashboards.ownerEmail,
|
|
594
621
|
orgId: schema.dashboards.orgId,
|
|
595
622
|
visibility: schema.dashboards.visibility,
|
|
@@ -603,11 +630,13 @@ export async function listDashboardSummaries(
|
|
|
603
630
|
.where(where);
|
|
604
631
|
const out: DashboardSummaryRecord[] = rows.map((row: any) => ({
|
|
605
632
|
...row,
|
|
633
|
+
description: typeof row.description === "string" ? row.description : null,
|
|
606
634
|
configName: typeof row.configName === "string" ? row.configName : null,
|
|
607
635
|
catalogTemplateId:
|
|
608
636
|
typeof row.catalogTemplateId === "string" ? row.catalogTemplateId : null,
|
|
609
637
|
demoId: typeof row.demoId === "string" ? row.demoId : null,
|
|
610
638
|
parentId: typeof row.parentId === "string" ? row.parentId : null,
|
|
639
|
+
folderId: typeof row.folderId === "string" ? row.folderId : null,
|
|
611
640
|
orgId: row.orgId ?? null,
|
|
612
641
|
archivedAt: row.archivedAt ?? null,
|
|
613
642
|
hiddenAt: row.hiddenAt ?? null,
|
|
@@ -656,8 +685,10 @@ export async function listDashboardSummaries(
|
|
|
656
685
|
id,
|
|
657
686
|
kind,
|
|
658
687
|
name: title,
|
|
688
|
+
description: configDescriptionFromValue(config),
|
|
659
689
|
...catalogMetadata,
|
|
660
690
|
parentId: typeof config.parentId === "string" ? config.parentId : null,
|
|
691
|
+
folderId: null,
|
|
661
692
|
ownerEmail: ctx.email,
|
|
662
693
|
orgId,
|
|
663
694
|
visibility,
|
|
@@ -676,6 +707,90 @@ export async function listDashboardSummaries(
|
|
|
676
707
|
return out;
|
|
677
708
|
}
|
|
678
709
|
|
|
710
|
+
/**
|
|
711
|
+
* Hydrate a bounded set of dashboard ids for catalog ranking.
|
|
712
|
+
*
|
|
713
|
+
* This is the catalog-specific path: it reads only the id, kind, title,
|
|
714
|
+
* description, and config needed for ranking, and only for explicit ids that
|
|
715
|
+
* were already shortlisted from the metadata path.
|
|
716
|
+
*/
|
|
717
|
+
export async function loadDashboardCatalogDashboards(
|
|
718
|
+
ctx: AccessCtx,
|
|
719
|
+
ids: readonly string[],
|
|
720
|
+
dbOverride?: any,
|
|
721
|
+
): Promise<DashboardCatalogRecord[]> {
|
|
722
|
+
const db = (dbOverride ?? getDb()) as any;
|
|
723
|
+
const uniqueIds = [
|
|
724
|
+
...new Set(ids.map((id) => id.trim()).filter(Boolean)),
|
|
725
|
+
].slice(0, MAX_CATALOG_DASHBOARD_HYDRATION);
|
|
726
|
+
if (!uniqueIds.length) return [];
|
|
727
|
+
|
|
728
|
+
const description = isPostgres()
|
|
729
|
+
? sql<string | null>`(${schema.dashboards.config}::jsonb ->> 'description')`
|
|
730
|
+
: sql<
|
|
731
|
+
string | null
|
|
732
|
+
>`json_extract(${schema.dashboards.config}, '$.description')`;
|
|
733
|
+
const archived = isNull(schema.dashboards.archivedAt);
|
|
734
|
+
const visible = isNull(schema.dashboards.hiddenAt);
|
|
735
|
+
const where = and(
|
|
736
|
+
accessFilter(schema.dashboards, schema.dashboardShares, {
|
|
737
|
+
userEmail: ctx.email,
|
|
738
|
+
orgId: ctx.orgId ?? undefined,
|
|
739
|
+
}),
|
|
740
|
+
inArray(schema.dashboards.id, uniqueIds),
|
|
741
|
+
archived,
|
|
742
|
+
visible,
|
|
743
|
+
);
|
|
744
|
+
|
|
745
|
+
// guard:allow-heavy-dashboard-list-read - bounded explicit ids shortlisted from metadata
|
|
746
|
+
const sqlRows = await db
|
|
747
|
+
.select({
|
|
748
|
+
id: schema.dashboards.id,
|
|
749
|
+
kind: schema.dashboards.kind,
|
|
750
|
+
title: schema.dashboards.title,
|
|
751
|
+
description,
|
|
752
|
+
config: schema.dashboards.config,
|
|
753
|
+
})
|
|
754
|
+
.from(schema.dashboards)
|
|
755
|
+
.where(where);
|
|
756
|
+
|
|
757
|
+
const byId = new Map<string, DashboardCatalogRecord>(
|
|
758
|
+
sqlRows.map((row: any) => {
|
|
759
|
+
const catalogRow: DashboardCatalogRecord = {
|
|
760
|
+
id: row.id,
|
|
761
|
+
kind: row.kind,
|
|
762
|
+
title: row.title,
|
|
763
|
+
description:
|
|
764
|
+
typeof row.description === "string" ? row.description : null,
|
|
765
|
+
config:
|
|
766
|
+
typeof row.config === "string" ? JSON.parse(row.config) : row.config,
|
|
767
|
+
};
|
|
768
|
+
return [row.id, catalogRow];
|
|
769
|
+
}),
|
|
770
|
+
);
|
|
771
|
+
|
|
772
|
+
const out: DashboardCatalogRecord[] = [];
|
|
773
|
+
for (const id of uniqueIds) {
|
|
774
|
+
const row = byId.get(id);
|
|
775
|
+
if (row) {
|
|
776
|
+
out.push(row);
|
|
777
|
+
continue;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
const legacy = await findLegacyDashboard(id, ctx);
|
|
781
|
+
if (!legacy) continue;
|
|
782
|
+
const { title, config } = configFromSettings(legacy.data);
|
|
783
|
+
out.push({
|
|
784
|
+
id,
|
|
785
|
+
kind: legacy.kind,
|
|
786
|
+
title,
|
|
787
|
+
description: configDescriptionFromValue(config),
|
|
788
|
+
config,
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
return out;
|
|
792
|
+
}
|
|
793
|
+
|
|
679
794
|
/**
|
|
680
795
|
* Reject a name that would collide with another dashboard visible to the
|
|
681
796
|
* caller. Archived and hidden dashboards are intentionally excluded because
|
|
@@ -2,10 +2,7 @@ import { isPostgres } from "@agent-native/core/db";
|
|
|
2
2
|
import { sql } from "@agent-native/core/db/schema";
|
|
3
3
|
|
|
4
4
|
import { getDb, schema } from "../db/index.js";
|
|
5
|
-
import {
|
|
6
|
-
FIRST_PARTY_ANALYTICS_ROLLUP_LOCK_KEY,
|
|
7
|
-
FIRST_PARTY_ANALYTICS_ROLLUP_LOCK_SQL,
|
|
8
|
-
} from "./analytics-rollup-lock.js";
|
|
5
|
+
import { FIRST_PARTY_ANALYTICS_ROLLUP_LOCK_KEY } from "./analytics-rollup-lock.js";
|
|
9
6
|
|
|
10
7
|
/**
|
|
11
8
|
* The normalized subset emitted by first-party analytics ingest. Keeping this
|
|
@@ -151,10 +148,9 @@ export async function upsertFirstPartyAnalyticsRollups(
|
|
|
151
148
|
// snapshot. Holding it through ingest's rollup increment prevents the
|
|
152
149
|
// backfill's monotonic upsert from losing a concurrently committed
|
|
153
150
|
// event.
|
|
154
|
-
await tx.execute(
|
|
155
|
-
sql
|
|
156
|
-
|
|
157
|
-
});
|
|
151
|
+
await tx.execute(
|
|
152
|
+
sql`SELECT pg_advisory_xact_lock(hashtextextended(${FIRST_PARTY_ANALYTICS_ROLLUP_LOCK_KEY}, 0::bigint))`,
|
|
153
|
+
);
|
|
158
154
|
}
|
|
159
155
|
const dailyRows = [...dailyRollups.values()];
|
|
160
156
|
await tx
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getDbExec } from "@agent-native/core/db";
|
|
2
2
|
import { runWithRequestContext } from "@agent-native/core/server";
|
|
3
|
-
import { and, eq, isNull, or } from "drizzle-orm";
|
|
3
|
+
import { and, eq, isNull, lt, or } from "drizzle-orm";
|
|
4
4
|
|
|
5
5
|
import { FIRST_PARTY_ANALYTICS_QUERY_TIMEOUT_MS } from "../../shared/dashboard-report-timeouts.js";
|
|
6
6
|
import { getDb, schema } from "../db/index.js";
|
|
@@ -181,6 +181,68 @@ export async function listAnalyticsPublicKeys(
|
|
|
181
181
|
}));
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
/** How stale the last-used stamp must be before a request pays to refresh it. */
|
|
185
|
+
const LAST_USED_AT_REFRESH_MS = 60_000;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Refresh a public key's last-used stamp without serializing ingest behind it.
|
|
189
|
+
*
|
|
190
|
+
* This UPDATE used to sit inside the ingest transaction, so every concurrent
|
|
191
|
+
* request for one public key took an exclusive row lock on that key's row and
|
|
192
|
+
* held it until the transaction committed — which meant through the rollup
|
|
193
|
+
* upsert. Production stacked 36 writers on three hot rows waiting 38-57s each;
|
|
194
|
+
* that exhausted the connection pool, and the whole app stopped loading while
|
|
195
|
+
* Postgres reported "no server connection available, client being queued". The
|
|
196
|
+
* stamp is bookkeeping: it needs neither atomicity with the events nor
|
|
197
|
+
* second-precision, and losing one is harmless.
|
|
198
|
+
*
|
|
199
|
+
* The staleness predicate throttles in SQL rather than in the caller, because
|
|
200
|
+
* Postgres only locks rows an UPDATE actually matches — a request whose key was
|
|
201
|
+
* stamped seconds ago matches nothing and takes no lock at all. Doing the same
|
|
202
|
+
* check in JS would reintroduce the convoy, since every racing request would
|
|
203
|
+
* still issue its own unconditional write.
|
|
204
|
+
*
|
|
205
|
+
* `last_used_at` is TEXT holding ISO-8601 UTC (always `Z`-suffixed), so `lt` is
|
|
206
|
+
* a lexicographic comparison that happens to be chronological. Storing a local
|
|
207
|
+
* or offset-bearing timestamp here would silently break this ordering.
|
|
208
|
+
*/
|
|
209
|
+
export async function touchPublicKeyLastUsedAt(
|
|
210
|
+
keyId: string,
|
|
211
|
+
receivedAt: string,
|
|
212
|
+
): Promise<void> {
|
|
213
|
+
const parsed = Date.parse(receivedAt);
|
|
214
|
+
if (!Number.isFinite(parsed)) {
|
|
215
|
+
console.warn(
|
|
216
|
+
"[first-party-analytics] Skipping last-used stamp: unparseable receivedAt",
|
|
217
|
+
receivedAt,
|
|
218
|
+
);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const staleBefore = new Date(parsed - LAST_USED_AT_REFRESH_MS).toISOString();
|
|
222
|
+
try {
|
|
223
|
+
const db = await getDb();
|
|
224
|
+
await db
|
|
225
|
+
.update(schema.analyticsPublicKeys)
|
|
226
|
+
.set({ lastUsedAt: receivedAt })
|
|
227
|
+
.where(
|
|
228
|
+
and(
|
|
229
|
+
eq(schema.analyticsPublicKeys.id, keyId),
|
|
230
|
+
or(
|
|
231
|
+
isNull(schema.analyticsPublicKeys.lastUsedAt),
|
|
232
|
+
lt(schema.analyticsPublicKeys.lastUsedAt, staleBefore),
|
|
233
|
+
),
|
|
234
|
+
),
|
|
235
|
+
);
|
|
236
|
+
} catch (error) {
|
|
237
|
+
// Best-effort by design: a failed stamp must not reject an ingest whose
|
|
238
|
+
// events already committed. Loud enough to see if it starts failing always.
|
|
239
|
+
console.warn(
|
|
240
|
+
"[first-party-analytics] Failed to refresh key last-used stamp:",
|
|
241
|
+
error,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
184
246
|
function parseReplayAllowedOrigins(value: unknown): string[] {
|
|
185
247
|
if (Array.isArray(value)) {
|
|
186
248
|
return value.filter((item): item is string => typeof item === "string");
|
|
@@ -539,18 +601,11 @@ export async function recordAnalyticsEvents(
|
|
|
539
601
|
if (rows.length && backend.sink !== "bigquery") {
|
|
540
602
|
await db.transaction(async (tx: any) => {
|
|
541
603
|
await tx.insert(schema.analyticsEvents).values(rows);
|
|
542
|
-
await tx
|
|
543
|
-
.update(schema.analyticsPublicKeys)
|
|
544
|
-
.set({ lastUsedAt: receivedAt })
|
|
545
|
-
.where(eq(schema.analyticsPublicKeys.id, key.id));
|
|
546
604
|
await upsertFirstPartyAnalyticsRollups(rows, tx);
|
|
547
605
|
});
|
|
548
606
|
}
|
|
549
|
-
if (rows.length
|
|
550
|
-
await
|
|
551
|
-
.update(schema.analyticsPublicKeys)
|
|
552
|
-
.set({ lastUsedAt: receivedAt })
|
|
553
|
-
.where(eq(schema.analyticsPublicKeys.id, key.id));
|
|
607
|
+
if (rows.length) {
|
|
608
|
+
await touchPublicKeyLastUsedAt(key.id, receivedAt);
|
|
554
609
|
}
|
|
555
610
|
|
|
556
611
|
// Fork captured exceptions into the dedicated error-capture tables. This is
|