@agent-native/core 0.145.5 → 0.145.6
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-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/gong.ts +139 -78
- 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/collab/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/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 +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/resources/handlers.d.ts +1 -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/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
|
@@ -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,19 +1,14 @@
|
|
|
1
1
|
// Gong sales call intelligence API helper
|
|
2
2
|
// Fetches calls, transcripts, and users
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
requireRequestCredentialContext,
|
|
7
|
-
scopedCredentialCacheKey,
|
|
8
|
-
} from "./credentials-context";
|
|
4
|
+
import { scopedCredentialCacheKey } from "./credentials-context";
|
|
9
5
|
import {
|
|
10
6
|
DEFAULT_GONG_CALL_LIMIT,
|
|
11
7
|
limitGongCalls,
|
|
12
8
|
normalizeGongCallLimit,
|
|
13
9
|
} from "./gong-limits";
|
|
14
|
-
import {
|
|
10
|
+
import { executeProviderApiRequest } from "./provider-api";
|
|
15
11
|
|
|
16
|
-
const DEFAULT_API_BASE = "https://api.gong.io/v2";
|
|
17
12
|
const MAX_GONG_SEARCH_PAGES = 50;
|
|
18
13
|
const MAX_GONG_CALL_LIST_PAGES = 50;
|
|
19
14
|
const MAX_GONG_EXHAUSTIVE_RECORDS = 500;
|
|
@@ -24,38 +19,101 @@ const cache = new Map<string, { data: unknown; ts: number }>();
|
|
|
24
19
|
const CACHE_TTL_MS = 10 * 60 * 1000;
|
|
25
20
|
const MAX_CACHE = 120;
|
|
26
21
|
|
|
27
|
-
async function getAuthHeader(): Promise<string> {
|
|
28
|
-
const ctx = requireRequestCredentialContext("GONG_ACCESS_KEY");
|
|
29
|
-
const credentials = await resolveAnalyticsGongCredentials({ ctx });
|
|
30
|
-
if (!credentials)
|
|
31
|
-
throw new Error("GONG_ACCESS_KEY and GONG_ACCESS_SECRET not configured");
|
|
32
|
-
return `Basic ${Buffer.from(
|
|
33
|
-
`${credentials.accessKey}:${credentials.accessSecret}`,
|
|
34
|
-
).toString("base64")}`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async function getApiBase(): Promise<string> {
|
|
38
|
-
const ctx = requireRequestCredentialContext("GONG_ACCESS_KEY");
|
|
39
|
-
const configured = await resolveCredential("GONG_API_BASE", ctx);
|
|
40
|
-
return (configured || DEFAULT_API_BASE).replace(/\/+$/, "");
|
|
41
|
-
}
|
|
42
|
-
|
|
43
22
|
export interface GongRequestOptions {
|
|
44
23
|
signal?: AbortSignal;
|
|
45
24
|
deadlineAt?: number;
|
|
46
25
|
}
|
|
47
26
|
|
|
48
|
-
function
|
|
49
|
-
|
|
27
|
+
function requestTimeoutMs(options?: GongRequestOptions): number {
|
|
28
|
+
return options?.deadlineAt
|
|
50
29
|
? Math.max(
|
|
51
30
|
1,
|
|
52
31
|
Math.min(GONG_API_REQUEST_TIMEOUT_MS, options.deadlineAt - Date.now()),
|
|
53
32
|
)
|
|
54
33
|
: GONG_API_REQUEST_TIMEOUT_MS;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface GongProviderResponse {
|
|
37
|
+
response: {
|
|
38
|
+
ok: boolean;
|
|
39
|
+
status: number;
|
|
40
|
+
headers?: Record<string, string>;
|
|
41
|
+
json?: unknown;
|
|
42
|
+
text?: string;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function splitGongPath(path: string): {
|
|
47
|
+
path: string;
|
|
48
|
+
query?: Record<string, string>;
|
|
49
|
+
} {
|
|
50
|
+
const separator = path.indexOf("?");
|
|
51
|
+
if (separator < 0) return { path };
|
|
52
|
+
const query = Object.fromEntries(
|
|
53
|
+
new URLSearchParams(path.slice(separator + 1)).entries(),
|
|
54
|
+
);
|
|
55
|
+
return {
|
|
56
|
+
path: path.slice(0, separator),
|
|
57
|
+
...(Object.keys(query).length > 0 ? { query } : {}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function responseHeader(
|
|
62
|
+
headers: Record<string, string> | undefined,
|
|
63
|
+
name: string,
|
|
64
|
+
): string | undefined {
|
|
65
|
+
const lowerName = name.toLowerCase();
|
|
66
|
+
return Object.entries(headers ?? {}).find(
|
|
67
|
+
([key]) => key.toLowerCase() === lowerName,
|
|
68
|
+
)?.[1];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function responseDetail(response: GongProviderResponse["response"]): string {
|
|
72
|
+
if (typeof response.text === "string" && response.text.trim()) {
|
|
73
|
+
return response.text.replace(/\s+/g, " ").trim().slice(0, 2_000);
|
|
74
|
+
}
|
|
75
|
+
if (response.json !== undefined) {
|
|
76
|
+
return JSON.stringify(response.json).slice(0, 2_000);
|
|
77
|
+
}
|
|
78
|
+
return "";
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function gongApiError(response: GongProviderResponse["response"]): Error {
|
|
82
|
+
const requestId =
|
|
83
|
+
responseHeader(response.headers, "x-request-id") ??
|
|
84
|
+
responseHeader(response.headers, "request-id");
|
|
85
|
+
const retryAfter = responseHeader(response.headers, "retry-after");
|
|
86
|
+
const metadata = [
|
|
87
|
+
requestId ? `requestId ${requestId}` : "",
|
|
88
|
+
response.status === 429 && retryAfter ? `retry-after ${retryAfter}` : "",
|
|
89
|
+
]
|
|
90
|
+
.filter(Boolean)
|
|
91
|
+
.join(", ");
|
|
92
|
+
const detail = responseDetail(response);
|
|
93
|
+
return new Error(
|
|
94
|
+
`Gong API error ${response.status}${metadata ? ` (${metadata})` : ""}${detail ? `: ${detail}` : ""}`,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function executeGongRequest<T>(options: {
|
|
99
|
+
method: "GET" | "POST";
|
|
100
|
+
path: string;
|
|
101
|
+
body?: unknown;
|
|
102
|
+
requestOptions?: GongRequestOptions;
|
|
103
|
+
}): Promise<T> {
|
|
104
|
+
const request = splitGongPath(options.path);
|
|
105
|
+
const result = (await executeProviderApiRequest({
|
|
106
|
+
provider: "gong",
|
|
107
|
+
method: options.method,
|
|
108
|
+
path: request.path,
|
|
109
|
+
...(request.query ? { query: request.query } : {}),
|
|
110
|
+
...(options.body !== undefined ? { body: options.body } : {}),
|
|
111
|
+
timeoutMs: requestTimeoutMs(options.requestOptions),
|
|
112
|
+
signal: options.requestOptions?.signal,
|
|
113
|
+
})) as GongProviderResponse;
|
|
114
|
+
|
|
115
|
+
if (!result.response.ok) throw gongApiError(result.response);
|
|
116
|
+
return result.response.json as T;
|
|
59
117
|
}
|
|
60
118
|
|
|
61
119
|
async function apiGet<T>(
|
|
@@ -69,21 +127,12 @@ async function apiGet<T>(
|
|
|
69
127
|
return cached.data as T;
|
|
70
128
|
}
|
|
71
129
|
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
},
|
|
77
|
-
signal: requestSignal(options),
|
|
130
|
+
const data = await executeGongRequest<T>({
|
|
131
|
+
method: "GET",
|
|
132
|
+
path,
|
|
133
|
+
requestOptions: options,
|
|
78
134
|
});
|
|
79
135
|
|
|
80
|
-
if (!res.ok) {
|
|
81
|
-
const text = await res.text();
|
|
82
|
-
throw new Error(`Gong API error ${res.status}: ${text}`);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const data = await res.json();
|
|
86
|
-
|
|
87
136
|
if (cache.size >= MAX_CACHE) {
|
|
88
137
|
const oldest = cache.keys().next().value;
|
|
89
138
|
if (oldest) cache.delete(oldest);
|
|
@@ -108,23 +157,13 @@ async function apiPost<T>(
|
|
|
108
157
|
return cached.data as T;
|
|
109
158
|
}
|
|
110
159
|
|
|
111
|
-
const
|
|
160
|
+
const data = await executeGongRequest<T>({
|
|
112
161
|
method: "POST",
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
},
|
|
117
|
-
body: JSON.stringify(body),
|
|
118
|
-
signal: requestSignal(options),
|
|
162
|
+
path,
|
|
163
|
+
body,
|
|
164
|
+
requestOptions: options,
|
|
119
165
|
});
|
|
120
166
|
|
|
121
|
-
if (!res.ok) {
|
|
122
|
-
const text = await res.text();
|
|
123
|
-
throw new Error(`Gong API error ${res.status}: ${text}`);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const data = await res.json();
|
|
127
|
-
|
|
128
167
|
if (cache.size >= MAX_CACHE) {
|
|
129
168
|
const oldest = cache.keys().next().value;
|
|
130
169
|
if (oldest) cache.delete(oldest);
|
|
@@ -298,29 +337,9 @@ export async function getCall(
|
|
|
298
337
|
return data.calls?.[0] ?? null;
|
|
299
338
|
}
|
|
300
339
|
|
|
301
|
-
|
|
302
|
-
callId: string,
|
|
303
|
-
options?: GongRequestOptions,
|
|
304
|
-
): Promise<GongCallDetail | null> {
|
|
305
|
-
const body = {
|
|
306
|
-
filter: { callIds: [callId] },
|
|
307
|
-
contentSelector: {
|
|
308
|
-
exposedFields: {
|
|
309
|
-
parties: true,
|
|
310
|
-
content: { brief: true, keyPoints: true, outline: true },
|
|
311
|
-
},
|
|
312
|
-
},
|
|
313
|
-
};
|
|
314
|
-
const data = await apiPost<{ calls?: any[] }>(
|
|
315
|
-
"/calls/extensive",
|
|
316
|
-
body,
|
|
317
|
-
`detail:${callId}`,
|
|
318
|
-
options,
|
|
319
|
-
);
|
|
320
|
-
const call = data.calls?.[0];
|
|
321
|
-
if (!call) return null;
|
|
340
|
+
function normalizeCallDetail(call: any, fallbackId: string): GongCallDetail {
|
|
322
341
|
return {
|
|
323
|
-
id: call.metaData?.id ??
|
|
342
|
+
id: call.metaData?.id ?? fallbackId,
|
|
324
343
|
title: call.metaData?.title || "Untitled",
|
|
325
344
|
url: call.metaData?.url || "",
|
|
326
345
|
started: call.metaData?.started || "",
|
|
@@ -340,6 +359,48 @@ export async function getCallDetail(
|
|
|
340
359
|
};
|
|
341
360
|
}
|
|
342
361
|
|
|
362
|
+
export async function getCallDetails(
|
|
363
|
+
callIds: string[],
|
|
364
|
+
options?: GongRequestOptions,
|
|
365
|
+
): Promise<GongCallDetail[]> {
|
|
366
|
+
const ids = Array.from(
|
|
367
|
+
new Set(
|
|
368
|
+
callIds
|
|
369
|
+
.map((id) => (typeof id === "string" ? id.trim() : ""))
|
|
370
|
+
.filter(Boolean),
|
|
371
|
+
),
|
|
372
|
+
);
|
|
373
|
+
if (!ids.length) return [];
|
|
374
|
+
|
|
375
|
+
const body = {
|
|
376
|
+
filter: { callIds: ids },
|
|
377
|
+
contentSelector: {
|
|
378
|
+
exposedFields: {
|
|
379
|
+
parties: true,
|
|
380
|
+
content: { brief: true, keyPoints: true, outline: true },
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
const data = await apiPost<{ calls?: any[] }>(
|
|
385
|
+
"/calls/extensive",
|
|
386
|
+
body,
|
|
387
|
+
`details:${ids.join(",")}`,
|
|
388
|
+
options,
|
|
389
|
+
);
|
|
390
|
+
return (data.calls ?? []).map((call, index) =>
|
|
391
|
+
normalizeCallDetail(call, ids[index] ?? ""),
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export async function getCallDetail(
|
|
396
|
+
callId: string,
|
|
397
|
+
options?: GongRequestOptions,
|
|
398
|
+
): Promise<GongCallDetail | null> {
|
|
399
|
+
const details = await getCallDetails([callId], options);
|
|
400
|
+
const detail = details[0];
|
|
401
|
+
return detail === undefined ? null : detail;
|
|
402
|
+
}
|
|
403
|
+
|
|
343
404
|
export async function getCallTranscripts(
|
|
344
405
|
callIds: string[],
|
|
345
406
|
options?: GongRequestOptions,
|