@agent-native/core 0.114.16 → 0.115.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-native.eject.json +2 -0
- package/corpus/README.md +3 -3
- package/corpus/core/CHANGELOG.md +41 -0
- package/corpus/core/agent-native.eject.json +2 -0
- package/corpus/core/docs/content/agent-native-toolkit.mdx +16 -0
- package/corpus/core/docs/content/recurring-jobs.mdx +35 -6
- package/corpus/core/export-snapshot.json +4 -0
- package/corpus/core/package.json +5 -1
- package/corpus/core/src/action.ts +22 -1
- package/corpus/core/src/agent/production-agent.ts +122 -3
- package/corpus/core/src/cli/skills-content/visual-plan-skill.ts +19 -2
- package/corpus/core/src/cli/templates-meta.ts +12 -0
- package/corpus/core/src/client/AssistantChat.tsx +53 -26
- package/corpus/core/src/client/agent-page/AgentJobsTab.tsx +19 -0
- package/corpus/core/src/client/agent-page/use-jobs.ts +1 -0
- package/corpus/core/src/client/blocks/library/wireframe.tsx +3 -1
- package/corpus/core/src/client/chat/message-components.tsx +35 -1
- package/corpus/core/src/client/chat/tool-call-display.tsx +38 -3
- package/corpus/core/src/connections/catalog.ts +20 -1
- package/corpus/core/src/connections/reader.ts +65 -0
- package/corpus/core/src/dashboard-storage/index.ts +27 -0
- package/corpus/core/src/dashboard-storage/panel-source.ts +168 -0
- package/corpus/core/src/dashboard-storage/schema.ts +62 -0
- package/corpus/core/src/dashboard-storage/store.ts +333 -0
- package/corpus/core/src/deploy/build.ts +95 -16
- package/corpus/core/src/eject/provider-api-definitions.ts +1 -0
- package/corpus/core/src/eject/workspace-connections.ts +1 -0
- package/corpus/core/src/extensions/actions.ts +199 -73
- package/corpus/core/src/jobs/actions/list-recurring-jobs.ts +2 -0
- package/corpus/core/src/jobs/scheduler.ts +71 -4
- package/corpus/core/src/jobs/tools.ts +31 -1
- package/corpus/core/src/localization/default-messages.ts +1 -0
- package/corpus/core/src/mcp-client/index.ts +6 -0
- package/corpus/core/src/provider-api/actions/provider-api.ts +1 -1
- package/corpus/core/src/provider-api/index.ts +190 -5
- package/corpus/core/src/secrets/register-framework-secrets.ts +8 -0
- package/corpus/core/src/server/agent-chat/context-tools.ts +9 -0
- package/corpus/core/src/server/agent-chat/framework-prompts.ts +2 -2
- package/corpus/core/src/server/agent-chat-plugin.ts +22 -2
- package/corpus/core/src/server/core-routes-plugin.ts +1 -0
- package/corpus/core/src/server/credential-provider.ts +9 -3
- package/corpus/core/src/server/workspace-provider-oauth.ts +181 -4
- package/corpus/core/src/styles/agent-native.css +45 -2
- package/corpus/core/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
- package/corpus/core/src/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
- package/corpus/core/src/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
- package/corpus/core/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
- package/corpus/core/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
- package/corpus/core/src/triggers/actions.ts +11 -2
- package/corpus/core/src/triggers/dispatcher.ts +20 -1
- package/corpus/core/src/triggers/types.ts +5 -0
- package/corpus/core/src/vite/action-types-plugin.ts +9 -1
- package/corpus/templates/analytics/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/analytics/AGENTS.md +11 -11
- package/corpus/templates/analytics/_gitignore +39 -0
- package/corpus/templates/analytics/actions/query-dashboard-panel.ts +30 -0
- package/corpus/templates/analytics/actions/update-dashboard.ts +2 -1
- package/corpus/templates/analytics/app/lib/sql-query.ts +11 -25
- package/corpus/templates/analytics/changelog/2026-07-21-fixed-extension-updates-failing-before-changes-could-be-appl.md +6 -0
- package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +1 -0
- package/corpus/templates/analytics/server/lib/dashboard-panel-source-resolver.ts +51 -0
- package/corpus/templates/analytics/server/lib/prometheus.ts +1 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/assets/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/brain/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/calendar/_gitignore +39 -0
- package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
- package/corpus/templates/chat/AGENTS.md +1 -1
- package/corpus/templates/clips/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/clips/AGENTS.md +7 -0
- package/corpus/templates/clips/actions/prepare-crm-call-evidence.ts +58 -0
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +88 -11
- package/corpus/templates/clips/changelog/2026-07-21-crm-call-evidence-handoff.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-21-recording-retries-and-restarts-keep-their-upload-session-so-.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/background.ts +20 -5
- package/corpus/templates/clips/chrome-extension/src/native-recording-state.ts +19 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +8 -0
- package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +9 -0
- package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +54 -28
- package/corpus/templates/clips/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/content/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/content/_gitignore +39 -0
- package/corpus/templates/content/learnings.defaults.md +5 -0
- package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/crm/.agents/skills/crm/SKILL.md +128 -0
- package/corpus/templates/crm/.agents/skills/customizing-agent-native/SKILL.md +145 -0
- package/corpus/templates/crm/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/crm/.agents/skills/upgrade-agent-native/SKILL.md +100 -0
- package/corpus/templates/crm/.env.example +5 -0
- package/corpus/templates/crm/AGENTS.md +120 -0
- package/corpus/templates/crm/CHANGELOG.md +1 -0
- package/corpus/templates/crm/DEVELOPING.md +66 -0
- package/corpus/templates/crm/README.md +106 -0
- package/corpus/templates/crm/_gitignore +12 -0
- package/corpus/templates/crm/actions/_crm-action-utils.ts +87 -0
- package/corpus/templates/crm/actions/_crm-dashboard.ts +69 -0
- package/corpus/templates/crm/actions/_crm-signal-utils.ts +79 -0
- package/corpus/templates/crm/actions/apply-crm-proposals.ts +203 -0
- package/corpus/templates/crm/actions/attach-call-evidence.ts +170 -0
- package/corpus/templates/crm/actions/configure-crm-connection.ts +126 -0
- package/corpus/templates/crm/actions/configure-native-crm.ts +44 -0
- package/corpus/templates/crm/actions/create-crm-record.ts +148 -0
- package/corpus/templates/crm/actions/create-crm-signal-tracker.ts +58 -0
- package/corpus/templates/crm/actions/delete-staged-dataset.ts +14 -0
- package/corpus/templates/crm/actions/get-crm-automation-recipe.ts +36 -0
- package/corpus/templates/crm/actions/get-crm-dashboard-panel.ts +33 -0
- package/corpus/templates/crm/actions/get-crm-dashboard.ts +14 -0
- package/corpus/templates/crm/actions/get-crm-overview.ts +13 -0
- package/corpus/templates/crm/actions/get-crm-pipeline-data.ts +61 -0
- package/corpus/templates/crm/actions/get-crm-record.ts +75 -0
- package/corpus/templates/crm/actions/install-crm-pipeline-dashboard.ts +81 -0
- package/corpus/templates/crm/actions/list-crm-dashboard-revisions.ts +15 -0
- package/corpus/templates/crm/actions/list-crm-dashboards.ts +15 -0
- package/corpus/templates/crm/actions/list-crm-proposals.ts +31 -0
- package/corpus/templates/crm/actions/list-crm-records.ts +79 -0
- package/corpus/templates/crm/actions/list-crm-saved-views.ts +15 -0
- package/corpus/templates/crm/actions/list-crm-signal-hits.ts +43 -0
- package/corpus/templates/crm/actions/list-crm-signal-trackers.ts +32 -0
- package/corpus/templates/crm/actions/list-crm-tasks.ts +22 -0
- package/corpus/templates/crm/actions/list-staged-datasets.ts +14 -0
- package/corpus/templates/crm/actions/list-workspace-connections.ts +47 -0
- package/corpus/templates/crm/actions/manage-crm-signal-tracker.ts +87 -0
- package/corpus/templates/crm/actions/manage-crm-task.ts +132 -0
- package/corpus/templates/crm/actions/navigate.ts +63 -0
- package/corpus/templates/crm/actions/provider-api-catalog.ts +22 -0
- package/corpus/templates/crm/actions/provider-api-docs.ts +54 -0
- package/corpus/templates/crm/actions/provider-api-request.ts +92 -0
- package/corpus/templates/crm/actions/query-staged-dataset.ts +44 -0
- package/corpus/templates/crm/actions/record-crm-call-insight.ts +160 -0
- package/corpus/templates/crm/actions/record-crm-smart-signal.ts +150 -0
- package/corpus/templates/crm/actions/restore-crm-dashboard-revision.ts +23 -0
- package/corpus/templates/crm/actions/review-crm-signal.ts +31 -0
- package/corpus/templates/crm/actions/run-crm-saved-view-program.ts +103 -0
- package/corpus/templates/crm/actions/run-crm-signal-trackers.ts +275 -0
- package/corpus/templates/crm/actions/run.ts +11 -0
- package/corpus/templates/crm/actions/save-crm-dashboard.ts +51 -0
- package/corpus/templates/crm/actions/save-crm-saved-view.ts +119 -0
- package/corpus/templates/crm/actions/sync-crm.ts +146 -0
- package/corpus/templates/crm/actions/update-crm-record.ts +508 -0
- package/corpus/templates/crm/actions/view-screen.ts +218 -0
- package/corpus/templates/crm/agent-native.app-skill.json +58 -0
- package/corpus/templates/crm/app/components/crm/CreateCrmRecordDialog.tsx +158 -0
- package/corpus/templates/crm/app/components/crm/CrmDashboardPanel.tsx +83 -0
- package/corpus/templates/crm/app/components/crm/CrmSignalsPanel.tsx +225 -0
- package/corpus/templates/crm/app/components/crm/IntelligenceSettings.tsx +413 -0
- package/corpus/templates/crm/app/components/crm/RecordActions.tsx +510 -0
- package/corpus/templates/crm/app/components/crm/RecordGrid.tsx +134 -0
- package/corpus/templates/crm/app/components/crm/RecordWorkspace.tsx +367 -0
- package/corpus/templates/crm/app/components/crm/SavedViewDataProgram.tsx +92 -0
- package/corpus/templates/crm/app/components/crm/Surface.tsx +96 -0
- package/corpus/templates/crm/app/components/crm/WorkOverview.tsx +180 -0
- package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +106 -0
- package/corpus/templates/crm/app/components/layout/CrmSidebar.tsx +84 -0
- package/corpus/templates/crm/app/entry.client.tsx +16 -0
- package/corpus/templates/crm/app/entry.server.tsx +10 -0
- package/corpus/templates/crm/app/global.css +167 -0
- package/corpus/templates/crm/app/hooks/use-navigation-state.ts +60 -0
- package/corpus/templates/crm/app/i18n/en-US.ts +89 -0
- package/corpus/templates/crm/app/i18n/index.ts +34 -0
- package/corpus/templates/crm/app/lib/dashboard.ts +13 -0
- package/corpus/templates/crm/app/lib/navigation.ts +54 -0
- package/corpus/templates/crm/app/lib/tab-id.ts +1 -0
- package/corpus/templates/crm/app/lib/types.ts +172 -0
- package/corpus/templates/crm/app/lib/utils.ts +1 -0
- package/corpus/templates/crm/app/root.tsx +88 -0
- package/corpus/templates/crm/app/routes/_index.tsx +26 -0
- package/corpus/templates/crm/app/routes/accounts.tsx +41 -0
- package/corpus/templates/crm/app/routes/agent.tsx +5 -0
- package/corpus/templates/crm/app/routes/ask.tsx +53 -0
- package/corpus/templates/crm/app/routes/dashboard.tsx +118 -0
- package/corpus/templates/crm/app/routes/opportunities.tsx +41 -0
- package/corpus/templates/crm/app/routes/people.tsx +41 -0
- package/corpus/templates/crm/app/routes/proposals.tsx +266 -0
- package/corpus/templates/crm/app/routes/records.$recordId.tsx +35 -0
- package/corpus/templates/crm/app/routes/settings.tsx +63 -0
- package/corpus/templates/crm/app/routes/setup.tsx +308 -0
- package/corpus/templates/crm/app/routes/tasks.tsx +252 -0
- package/corpus/templates/crm/app/routes/views.tsx +333 -0
- package/corpus/templates/crm/app/routes.ts +17 -0
- package/corpus/templates/crm/app/vite-env.d.ts +6 -0
- package/corpus/templates/crm/changelog/2026-07-21-agent-native-crm.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-21-clips-call-evidence-review-recipe.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-find-and-review-evidence-grounded-call-signals-w.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-manage-keyword-and-smart-call-signal-trackers-fr.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-21-delegated-local-crm-automation.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-21-native-sql.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboard.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboards-now-install-correctly-from-the-crm-actio.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-21-salesforce-connection.md +6 -0
- package/corpus/templates/crm/components.json +20 -0
- package/corpus/templates/crm/docs/architecture/crm-contract.md +180 -0
- package/corpus/templates/crm/learnings.defaults.md +5 -0
- package/corpus/templates/crm/package.json +59 -0
- package/corpus/templates/crm/public/favicon.svg +1 -0
- package/corpus/templates/crm/public/icon-180.svg +1 -0
- package/corpus/templates/crm/public/manifest.json +11 -0
- package/corpus/templates/crm/react-router.config.ts +7 -0
- package/corpus/templates/crm/server/crm/adapter.ts +32 -0
- package/corpus/templates/crm/server/crm/crm-field-firewall.ts +64 -0
- package/corpus/templates/crm/server/crm/crm-mirror.ts +711 -0
- package/corpus/templates/crm/server/crm/hubspot-adapter.ts +1143 -0
- package/corpus/templates/crm/server/crm/native-adapter.ts +1715 -0
- package/corpus/templates/crm/server/crm/read-through.ts +207 -0
- package/corpus/templates/crm/server/crm/salesforce-adapter.ts +1255 -0
- package/corpus/templates/crm/server/db/crm-store.ts +1170 -0
- package/corpus/templates/crm/server/db/index.ts +169 -0
- package/corpus/templates/crm/server/db/schema.ts +441 -0
- package/corpus/templates/crm/server/lib/intelligence/default-detectors.ts +65 -0
- package/corpus/templates/crm/server/lib/intelligence/evidence.ts +105 -0
- package/corpus/templates/crm/server/lib/intelligence/keyword-detector.ts +100 -0
- package/corpus/templates/crm/server/lib/intelligence/smart-detector.ts +144 -0
- package/corpus/templates/crm/server/lib/intelligence/summary.ts +141 -0
- package/corpus/templates/crm/server/lib/provider-api.ts +64 -0
- package/corpus/templates/crm/server/middleware/auth.ts +4 -0
- package/corpus/templates/crm/server/plugins/agent-chat.ts +68 -0
- package/corpus/templates/crm/server/plugins/auth.ts +14 -0
- package/corpus/templates/crm/server/plugins/core-routes.ts +17 -0
- package/corpus/templates/crm/server/plugins/db.ts +454 -0
- package/corpus/templates/crm/server/routes/[...page].get.ts +5 -0
- package/corpus/templates/crm/shared/crm-automation-recipes.ts +132 -0
- package/corpus/templates/crm/shared/crm-contract.ts +254 -0
- package/corpus/templates/crm/shared/crm-sales-config.ts +63 -0
- package/corpus/templates/crm/ssr-entry.ts +11 -0
- package/corpus/templates/crm/tsconfig.json +24 -0
- package/corpus/templates/crm/vite.config.ts +15 -0
- package/corpus/templates/crm/vitest.config.ts +5 -0
- package/corpus/templates/design/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/dispatch/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/forms/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/forms/_gitignore +39 -0
- package/corpus/templates/forms/learnings.defaults.md +5 -0
- package/corpus/templates/macros/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/macros/_gitignore +39 -0
- package/corpus/templates/macros/learnings.defaults.md +5 -0
- package/corpus/templates/mail/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/mail/_gitignore +39 -0
- package/corpus/templates/plan/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +19 -2
- package/corpus/templates/plan/AGENTS.md +10 -0
- package/corpus/templates/plan/actions/create-prototype-plan.ts +27 -3
- package/corpus/templates/plan/actions/get-plan-blocks.ts +1 -1
- package/corpus/templates/plan/actions/update-visual-plan.ts +3 -2
- package/corpus/templates/plan/app/components/plan/PlanContentRenderer.tsx +18 -4
- package/corpus/templates/plan/app/components/plan/PlanVisualSurface.tsx +10 -3
- package/corpus/templates/plan/app/components/plan/wireframe/Wireframe.tsx +3 -1
- package/corpus/templates/plan/app/i18n/en-US.ts +6 -0
- package/corpus/templates/plan/app/lib/create-plan-routing.ts +39 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +31 -107
- package/corpus/templates/plan/changelog/2026-07-22-high-fidelity-mockup-requests-now-preserve-branded-css-use-d.md +6 -0
- package/corpus/templates/plan/shared/plan-content.ts +110 -2
- package/corpus/templates/slides/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/slides/_gitignore +39 -0
- package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +27 -0
- package/corpus/templates/tasks/_gitignore +39 -0
- package/corpus/toolkit/CHANGELOG.md +12 -0
- package/corpus/toolkit/README.md +30 -0
- package/corpus/toolkit/agent-native.eject.json +33 -0
- package/corpus/toolkit/package.json +15 -1
- package/corpus/toolkit/src/dashboard/DataTable.tsx +273 -0
- package/corpus/toolkit/src/dashboard/DateRangePicker.tsx +57 -0
- package/corpus/toolkit/src/dashboard/GenericChartPanel.tsx +461 -0
- package/corpus/toolkit/src/dashboard/MetricCard.tsx +54 -0
- package/corpus/toolkit/src/dashboard/StatsCard.tsx +49 -0
- package/corpus/toolkit/src/dashboard/dashboard-layout.ts +329 -0
- package/corpus/toolkit/src/dashboard/index.ts +6 -0
- package/corpus/toolkit/src/index.ts +1 -0
- package/corpus/toolkit/src/ui/calendar.tsx +8 -8
- package/corpus/toolkit/src/ui/date-picker.tsx +4 -1
- package/dist/action.d.ts +14 -1
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js.map +1 -1
- package/dist/agent/production-agent.d.ts +3 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +97 -3
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
- package/dist/cli/skills-content/visual-plan-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/visual-plan-skill.js +19 -2
- package/dist/cli/skills-content/visual-plan-skill.js.map +1 -1
- package/dist/cli/templates-meta.d.ts.map +1 -1
- package/dist/cli/templates-meta.js +12 -0
- package/dist/cli/templates-meta.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +4 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +30 -17
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-page/AgentJobsTab.d.ts.map +1 -1
- package/dist/client/agent-page/AgentJobsTab.js +3 -1
- package/dist/client/agent-page/AgentJobsTab.js.map +1 -1
- package/dist/client/agent-page/use-jobs.d.ts +1 -0
- package/dist/client/agent-page/use-jobs.d.ts.map +1 -1
- package/dist/client/agent-page/use-jobs.js.map +1 -1
- package/dist/client/blocks/library/wireframe.d.ts.map +1 -1
- package/dist/client/blocks/library/wireframe.js +3 -2
- package/dist/client/blocks/library/wireframe.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +5 -0
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +17 -1
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +3 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +17 -7
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +17 -3
- package/dist/connections/catalog.d.ts.map +1 -1
- package/dist/connections/catalog.js +16 -1
- package/dist/connections/catalog.js.map +1 -1
- package/dist/connections/reader.d.ts +18 -0
- package/dist/connections/reader.d.ts.map +1 -1
- package/dist/connections/reader.js +41 -0
- package/dist/connections/reader.js.map +1 -1
- package/dist/dashboard-storage/index.d.ts +4 -0
- package/dist/dashboard-storage/index.d.ts.map +1 -0
- package/dist/dashboard-storage/index.js +4 -0
- package/dist/dashboard-storage/index.js.map +1 -0
- package/dist/dashboard-storage/panel-source.d.ts +68 -0
- package/dist/dashboard-storage/panel-source.d.ts.map +1 -0
- package/dist/dashboard-storage/panel-source.js +76 -0
- package/dist/dashboard-storage/panel-source.js.map +1 -0
- package/dist/dashboard-storage/schema.d.ts +562 -0
- package/dist/dashboard-storage/schema.d.ts.map +1 -0
- package/dist/dashboard-storage/schema.js +32 -0
- package/dist/dashboard-storage/schema.js.map +1 -0
- package/dist/dashboard-storage/store.d.ts +62 -0
- package/dist/dashboard-storage/store.d.ts.map +1 -0
- package/dist/dashboard-storage/store.js +227 -0
- package/dist/dashboard-storage/store.js.map +1 -0
- package/dist/deploy/build.d.ts +7 -0
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +78 -14
- package/dist/deploy/build.js.map +1 -1
- package/dist/eject/provider-api-definitions.d.ts +2 -1
- package/dist/eject/provider-api-definitions.d.ts.map +1 -1
- package/dist/eject/provider-api-definitions.js +1 -0
- package/dist/eject/provider-api-definitions.js.map +1 -1
- package/dist/eject/workspace-connections.d.ts.map +1 -1
- package/dist/eject/workspace-connections.js +1 -0
- package/dist/eject/workspace-connections.js.map +1 -1
- package/dist/extensions/actions.d.ts.map +1 -1
- package/dist/extensions/actions.js +165 -67
- package/dist/extensions/actions.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/jobs/actions/list-recurring-jobs.d.ts +1 -0
- package/dist/jobs/actions/list-recurring-jobs.d.ts.map +1 -1
- package/dist/jobs/actions/list-recurring-jobs.js +1 -0
- package/dist/jobs/actions/list-recurring-jobs.js.map +1 -1
- package/dist/jobs/scheduler.d.ts +17 -2
- package/dist/jobs/scheduler.d.ts.map +1 -1
- package/dist/jobs/scheduler.js +51 -2
- package/dist/jobs/scheduler.js.map +1 -1
- package/dist/jobs/tools.d.ts.map +1 -1
- package/dist/jobs/tools.js +32 -2
- package/dist/jobs/tools.js.map +1 -1
- package/dist/localization/default-messages.d.ts +1 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +1 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp-client/index.d.ts +2 -0
- package/dist/mcp-client/index.d.ts.map +1 -1
- package/dist/mcp-client/index.js +5 -0
- package/dist/mcp-client/index.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
- package/dist/provider-api/actions/provider-api.d.ts +8 -6
- package/dist/provider-api/actions/provider-api.d.ts.map +1 -1
- package/dist/provider-api/actions/provider-api.js +1 -1
- package/dist/provider-api/actions/provider-api.js.map +1 -1
- package/dist/provider-api/index.d.ts +11 -7
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +143 -5
- package/dist/provider-api/index.js.map +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
- package/dist/secrets/register-framework-secrets.js +7 -0
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
- package/dist/server/agent-chat/context-tools.js +9 -0
- package/dist/server/agent-chat/context-tools.js.map +1 -1
- package/dist/server/agent-chat/framework-prompts.js +2 -2
- package/dist/server/agent-chat/framework-prompts.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +18 -2
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +1 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +4 -3
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +9 -3
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/workspace-provider-oauth.d.ts +6 -1
- package/dist/server/workspace-provider-oauth.d.ts.map +1 -1
- package/dist/server/workspace-provider-oauth.js +141 -4
- package/dist/server/workspace-provider-oauth.js.map +1 -1
- package/dist/styles/agent-native.css +45 -2
- package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
- package/dist/templates/chat/AGENTS.md +1 -1
- package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
- package/dist/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
- package/dist/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
- package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
- package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
- package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
- package/dist/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
- package/dist/triggers/actions.d.ts.map +1 -1
- package/dist/triggers/actions.js +10 -2
- package/dist/triggers/actions.js.map +1 -1
- package/dist/triggers/dispatcher.d.ts.map +1 -1
- package/dist/triggers/dispatcher.js +15 -0
- package/dist/triggers/dispatcher.js.map +1 -1
- package/dist/triggers/types.d.ts +5 -0
- package/dist/triggers/types.d.ts.map +1 -1
- package/dist/triggers/types.js.map +1 -1
- package/dist/vite/action-types-plugin.d.ts.map +1 -1
- package/dist/vite/action-types-plugin.js +4 -1
- package/dist/vite/action-types-plugin.js.map +1 -1
- package/docs/content/agent-native-toolkit.mdx +16 -0
- package/docs/content/recurring-jobs.mdx +35 -6
- package/package.json +7 -3
- package/src/action.ts +22 -1
- package/src/agent/production-agent.ts +122 -3
- package/src/cli/skills-content/visual-plan-skill.ts +19 -2
- package/src/cli/templates-meta.ts +12 -0
- package/src/client/AssistantChat.tsx +53 -26
- package/src/client/agent-page/AgentJobsTab.tsx +19 -0
- package/src/client/agent-page/use-jobs.ts +1 -0
- package/src/client/blocks/library/wireframe.tsx +3 -1
- package/src/client/chat/message-components.tsx +35 -1
- package/src/client/chat/tool-call-display.tsx +38 -3
- package/src/connections/catalog.ts +20 -1
- package/src/connections/reader.ts +65 -0
- package/src/dashboard-storage/index.ts +27 -0
- package/src/dashboard-storage/panel-source.ts +168 -0
- package/src/dashboard-storage/schema.ts +62 -0
- package/src/dashboard-storage/store.ts +333 -0
- package/src/deploy/build.ts +95 -16
- package/src/eject/provider-api-definitions.ts +1 -0
- package/src/eject/workspace-connections.ts +1 -0
- package/src/extensions/actions.ts +199 -73
- package/src/jobs/actions/list-recurring-jobs.ts +2 -0
- package/src/jobs/scheduler.ts +71 -4
- package/src/jobs/tools.ts +31 -1
- package/src/localization/default-messages.ts +1 -0
- package/src/mcp-client/index.ts +6 -0
- package/src/provider-api/actions/provider-api.ts +1 -1
- package/src/provider-api/index.ts +190 -5
- package/src/secrets/register-framework-secrets.ts +8 -0
- package/src/server/agent-chat/context-tools.ts +9 -0
- package/src/server/agent-chat/framework-prompts.ts +2 -2
- package/src/server/agent-chat-plugin.ts +22 -2
- package/src/server/core-routes-plugin.ts +1 -0
- package/src/server/credential-provider.ts +9 -3
- package/src/server/workspace-provider-oauth.ts +181 -4
- package/src/styles/agent-native.css +45 -2
- package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
- package/src/templates/chat/AGENTS.md +1 -1
- package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
- package/src/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
- package/src/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
- package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
- package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
- package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
- package/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
- package/src/triggers/actions.ts +11 -2
- package/src/triggers/dispatcher.ts +20 -1
- package/src/triggers/types.ts +5 -0
- package/src/vite/action-types-plugin.ts +9 -1
- package/corpus/templates/analytics/server/handlers/sql-query.ts +0 -36
- package/corpus/templates/analytics/server/routes/api/sql-query.post.ts +0 -1
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# CRM
|
|
2
|
+
|
|
3
|
+
CRM is an agent-native CRM that runs either as a standalone Native SQL system
|
|
4
|
+
or as a scoped companion for connected HubSpot and Salesforce workspaces. It
|
|
5
|
+
provides fast record work, saved views, tasks, cadence, evidence, reviewable
|
|
6
|
+
call signals, and agent workflows without forcing a provider choice.
|
|
7
|
+
|
|
8
|
+
Native SQL is local-authoritative and portable across SQLite, Postgres, and D1.
|
|
9
|
+
The connected modes support scoped Connected and Hybrid behavior: HubSpot maps
|
|
10
|
+
companies, contacts, and deals; Salesforce maps Accounts, Contacts, and
|
|
11
|
+
Opportunities.
|
|
12
|
+
|
|
13
|
+
## Guardrails
|
|
14
|
+
|
|
15
|
+
- Native SQL requires no external connection or provider credential.
|
|
16
|
+
- Provider credentials are workspace Connections only.
|
|
17
|
+
- The mirror contains configured cohorts and allow-listed fields, not raw
|
|
18
|
+
provider exports.
|
|
19
|
+
- Sensitive fields default to redacted and unknown fields are remote-only.
|
|
20
|
+
- Evidence stores a bounded quote and source reference, never transcripts or
|
|
21
|
+
media.
|
|
22
|
+
- Signal detectors produce timestamped evidence citations. Keyword matching is
|
|
23
|
+
local; smart moments and summaries are delegated through agent chat and saved
|
|
24
|
+
only after grounding validation.
|
|
25
|
+
- Provider mutations are revision-aware, audited, and proposed when agent risk
|
|
26
|
+
requires approval.
|
|
27
|
+
|
|
28
|
+
## Start or connect CRM
|
|
29
|
+
|
|
30
|
+
1. Open **Set up CRM** and select **Start with Native SQL** to use CRM without
|
|
31
|
+
HubSpot or Salesforce. Native records and fields are local-authoritative.
|
|
32
|
+
2. To use CRM as a companion, in shared **Settings → Connections**, authorize
|
|
33
|
+
HubSpot or Salesforce and
|
|
34
|
+
grant the connection to CRM. OAuth and refresh tokens stay in workspace
|
|
35
|
+
Connections; CRM never accepts a token or key. Salesforce production is the
|
|
36
|
+
default. For a sandbox, use **Authorize the sandbox directly** on Set up CRM;
|
|
37
|
+
the selected login environment is retained for token refresh.
|
|
38
|
+
3. Choose the granted connection and select a recent
|
|
39
|
+
history window. HubSpot may be narrowed to deal pipeline IDs; Salesforce
|
|
40
|
+
starts with recently updated Accounts, Contacts, and Opportunities.
|
|
41
|
+
4. CRM mirrors the selected cohort and allow-listed fields only. Confirm the
|
|
42
|
+
connection actor's access before relying on a record in the local mirror.
|
|
43
|
+
|
|
44
|
+
## Operating model
|
|
45
|
+
|
|
46
|
+
- **Connected**: the source CRM is authoritative. CRM is a scoped companion
|
|
47
|
+
for record work, saved views, tasks, call evidence, and analysis.
|
|
48
|
+
- **Hybrid**: the source CRM remains authoritative for remote fields; CRM may
|
|
49
|
+
own explicitly configured derived-local and local-authoritative fields.
|
|
50
|
+
- **Native SQL**: CRM is the system of record for its accounts, people,
|
|
51
|
+
opportunities, relationships, saved views, tasks, cadence, and local fields.
|
|
52
|
+
It has no upstream provider, sync job, or provider token.
|
|
53
|
+
- **Signals**: attach one Clips call-evidence artifact to one or more CRM
|
|
54
|
+
records, run the default Pricing, Competitors, Objections, Next steps,
|
|
55
|
+
Budget, and Timing detectors, then confirm or dismiss the grounded results.
|
|
56
|
+
Clips remains the owner of recording, transcript, consent, and media access.
|
|
57
|
+
- **Clips review recipe**: from a chosen CRM record, prepare a default-off
|
|
58
|
+
`clip.created` recipe. After explicit activation, its Clips-owned trigger
|
|
59
|
+
ignores the event media URL, resolves the clip through an access-checked
|
|
60
|
+
read action, and attaches only its opaque ID, durable HTTPS `/r/<id>` page,
|
|
61
|
+
and capture time to that exact CRM record. It never copies media or a
|
|
62
|
+
transcript, infers another record, or authorizes a provider write.
|
|
63
|
+
- **Pipeline dashboard**: install the CRM-owned Pipeline dashboard to get
|
|
64
|
+
action-backed stage, amount, and close-date panels. Its data program and
|
|
65
|
+
dashboard revisions are access-scoped CRM records; the reusable chart and
|
|
66
|
+
table presentation comes from the Toolkit dashboard kit.
|
|
67
|
+
- **Read and write safety**: provider reads use the connection's effective
|
|
68
|
+
permissions. Upstream changes are revision-aware, access-checked proposals
|
|
69
|
+
in this release; finish the approved change in HubSpot or Salesforce and do
|
|
70
|
+
not claim a provider write completed from CRM.
|
|
71
|
+
|
|
72
|
+
## Review and delegation policy
|
|
73
|
+
|
|
74
|
+
CRM records the actor, expected remote revision, idempotency key, field-level
|
|
75
|
+
provenance, and an audit event for each mutation request. Local, reversible
|
|
76
|
+
routine work can execute in CRM. Agent-initiated provider changes become
|
|
77
|
+
reviewable proposals; destructive, bulk, and named-risk changes remain gated.
|
|
78
|
+
Delegated authority is narrow and stored as policy—it never expands record or
|
|
79
|
+
field access, bypasses the write firewall, or turns a provider result into an
|
|
80
|
+
unverified success.
|
|
81
|
+
|
|
82
|
+
Salesforce reads are validated against the current connection actor and field
|
|
83
|
+
permissions before mirrored data is returned. A service-account mirror never
|
|
84
|
+
proves a user's access; ambiguous or changed access fails closed until refresh.
|
|
85
|
+
|
|
86
|
+
## Live testing
|
|
87
|
+
|
|
88
|
+
Use a shared, already-authorized workspace Connection—never copy its secret
|
|
89
|
+
into an environment file. Choose a small recent cohort, verify the resulting
|
|
90
|
+
records and access scope in CRM, then test a proposal without applying a
|
|
91
|
+
provider change. Record only connection labels, counts, and non-sensitive
|
|
92
|
+
results in test evidence.
|
|
93
|
+
|
|
94
|
+
See [the CRM contract](docs/architecture/crm-contract.md) for field policies,
|
|
95
|
+
identity, access scope, and write decisions.
|
|
96
|
+
|
|
97
|
+
## Local development
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pnpm install
|
|
101
|
+
pnpm dev
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Set `DATABASE_URL` for persistent deployment storage. Native SQL works without
|
|
105
|
+
external credentials. Connect HubSpot or Salesforce from the workspace
|
|
106
|
+
Connections surface; do not add provider secrets to `.env`.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { ActionRunContext } from "@agent-native/core/action";
|
|
2
|
+
import {
|
|
3
|
+
getRequestOrgId,
|
|
4
|
+
getRequestUserEmail,
|
|
5
|
+
} from "@agent-native/core/server";
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
isBoundedCrmValue,
|
|
9
|
+
isSafeCrmMutationFieldName,
|
|
10
|
+
isSafeCrmMutationFields,
|
|
11
|
+
} from "../server/crm/crm-field-firewall.js";
|
|
12
|
+
|
|
13
|
+
export const MAX_CRM_FIELDS_PER_MUTATION = 20;
|
|
14
|
+
|
|
15
|
+
export function requireCrmScope(ctx?: ActionRunContext) {
|
|
16
|
+
const ownerEmail = ctx?.userEmail ?? getRequestUserEmail();
|
|
17
|
+
if (!ownerEmail) throw new Error("Sign in is required to manage CRM data.");
|
|
18
|
+
const orgId = ctx?.orgId ?? getRequestOrgId() ?? null;
|
|
19
|
+
return {
|
|
20
|
+
ownerEmail,
|
|
21
|
+
orgId,
|
|
22
|
+
visibility: orgId ? ("org" as const) : ("private" as const),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function crmInitiatedBy(ctx?: ActionRunContext) {
|
|
27
|
+
if (ctx?.caller === "automation") return "automation" as const;
|
|
28
|
+
return ctx?.caller === "tool" ||
|
|
29
|
+
ctx?.caller === "mcp" ||
|
|
30
|
+
ctx?.caller === "a2a"
|
|
31
|
+
? ("agent" as const)
|
|
32
|
+
: ("human" as const);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function crmWriteRisk(fieldNames: string[]) {
|
|
36
|
+
const names = fieldNames.map((field) => field.toLowerCase());
|
|
37
|
+
if (names.some((field) => field.includes("owner")))
|
|
38
|
+
return "ownership" as const;
|
|
39
|
+
if (names.some((field) => field === "amount" || field.includes("amount"))) {
|
|
40
|
+
return "amount" as const;
|
|
41
|
+
}
|
|
42
|
+
if (
|
|
43
|
+
names.some((field) => field.includes("stage") || field.includes("pipeline"))
|
|
44
|
+
) {
|
|
45
|
+
return "stage" as const;
|
|
46
|
+
}
|
|
47
|
+
return "routine" as const;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function scopedCrmIdempotencyKey(input: {
|
|
51
|
+
ownerEmail: string;
|
|
52
|
+
orgId: string | null;
|
|
53
|
+
recordId: string;
|
|
54
|
+
key: string;
|
|
55
|
+
}): Promise<string> {
|
|
56
|
+
const value = [
|
|
57
|
+
"crm-mutation-v1",
|
|
58
|
+
input.ownerEmail.toLowerCase(),
|
|
59
|
+
input.orgId ?? "",
|
|
60
|
+
input.recordId,
|
|
61
|
+
input.key,
|
|
62
|
+
].join("\u0000");
|
|
63
|
+
const bytes = new TextEncoder().encode(value);
|
|
64
|
+
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
|
65
|
+
return `crm:v1:${Array.from(new Uint8Array(digest), (byte) =>
|
|
66
|
+
byte.toString(16).padStart(2, "0"),
|
|
67
|
+
).join("")}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function toJson(value: unknown, maxChars: number) {
|
|
71
|
+
const encoded = JSON.stringify(value);
|
|
72
|
+
if (encoded.length > maxChars) {
|
|
73
|
+
throw new Error(`CRM payload exceeds the ${maxChars}-character limit.`);
|
|
74
|
+
}
|
|
75
|
+
return encoded;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function parseJsonRecord(value: string): Record<string, unknown> {
|
|
79
|
+
try {
|
|
80
|
+
const parsed = JSON.parse(value) as unknown;
|
|
81
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
82
|
+
? (parsed as Record<string, unknown>)
|
|
83
|
+
: {};
|
|
84
|
+
} catch {
|
|
85
|
+
return {};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
import type { ActionRunContext } from "@agent-native/core/action";
|
|
4
|
+
import type { AccessContext } from "@agent-native/core/sharing";
|
|
5
|
+
|
|
6
|
+
import type { CrmDashboardConfig } from "../server/db/index.js";
|
|
7
|
+
|
|
8
|
+
export const CRM_PIPELINE_DASHBOARD_TITLE = "Pipeline";
|
|
9
|
+
export const CRM_PIPELINE_PROGRAM_NAME = "crm-pipeline-by-stage";
|
|
10
|
+
export const CRM_PIPELINE_PROGRAM_TITLE = "CRM pipeline by stage";
|
|
11
|
+
export const CRM_PIPELINE_REFRESH_TTL_MS = 5 * 60_000;
|
|
12
|
+
|
|
13
|
+
export const CRM_PIPELINE_PROGRAM_COLUMNS = [
|
|
14
|
+
{ name: "stage", type: "string" },
|
|
15
|
+
{ name: "pipelineValue", type: "number" },
|
|
16
|
+
{ name: "opportunities", type: "number" },
|
|
17
|
+
] as const;
|
|
18
|
+
|
|
19
|
+
export const CRM_PIPELINE_PROGRAM_CODE = `const result = await appAction("get-crm-pipeline-data");
|
|
20
|
+
emit(result.rows, ${JSON.stringify(CRM_PIPELINE_PROGRAM_COLUMNS, null, 2)});`;
|
|
21
|
+
|
|
22
|
+
export function requireDashboardAccess(
|
|
23
|
+
ctx?: ActionRunContext,
|
|
24
|
+
): AccessContext & { userEmail: string } {
|
|
25
|
+
const userEmail = ctx?.userEmail?.trim().toLowerCase();
|
|
26
|
+
if (!userEmail) {
|
|
27
|
+
throw new Error("CRM dashboards require an authenticated user.");
|
|
28
|
+
}
|
|
29
|
+
return { userEmail, orgId: ctx?.orgId ?? undefined };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function crmPipelineDashboardId(ctx: AccessContext): string {
|
|
33
|
+
const owner = ctx.userEmail?.trim().toLowerCase();
|
|
34
|
+
if (!owner) throw new Error("CRM dashboards require an authenticated user.");
|
|
35
|
+
const scope = `${ctx.orgId ?? "personal"}:${owner}`;
|
|
36
|
+
return `crm-pipeline-${createHash("sha256").update(scope).digest("hex").slice(0, 24)}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function createPipelineDashboardConfig(
|
|
40
|
+
programId: string,
|
|
41
|
+
): CrmDashboardConfig {
|
|
42
|
+
const query = JSON.stringify({ programId });
|
|
43
|
+
return {
|
|
44
|
+
version: 1,
|
|
45
|
+
panels: [
|
|
46
|
+
{
|
|
47
|
+
id: "pipeline-total",
|
|
48
|
+
title: "Pipeline value",
|
|
49
|
+
source: "program",
|
|
50
|
+
query,
|
|
51
|
+
chartType: "metric",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "pipeline-by-stage",
|
|
55
|
+
title: "Pipeline by stage",
|
|
56
|
+
source: "program",
|
|
57
|
+
query,
|
|
58
|
+
chartType: "bar",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: "pipeline-table",
|
|
62
|
+
title: "Stage detail",
|
|
63
|
+
source: "program",
|
|
64
|
+
query,
|
|
65
|
+
chartType: "table",
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { ActionRunContext } from "@agent-native/core/action";
|
|
2
|
+
import { accessFilter, assertAccess } from "@agent-native/core/sharing";
|
|
3
|
+
import { and, eq, inArray } from "drizzle-orm";
|
|
4
|
+
|
|
5
|
+
import { getDb, schema } from "../server/db/index.js";
|
|
6
|
+
import type { CallEvidenceExcerpt } from "../server/lib/intelligence/evidence.js";
|
|
7
|
+
import {
|
|
8
|
+
requireCrmScope,
|
|
9
|
+
scopedCrmIdempotencyKey,
|
|
10
|
+
} from "./_crm-action-utils.js";
|
|
11
|
+
|
|
12
|
+
export async function loadCrmSignalEvidence(args: {
|
|
13
|
+
recordId: string;
|
|
14
|
+
evidenceIds?: string[];
|
|
15
|
+
role?: "viewer" | "editor";
|
|
16
|
+
}) {
|
|
17
|
+
await assertAccess("crm-record", args.recordId, args.role ?? "viewer");
|
|
18
|
+
const db = getDb();
|
|
19
|
+
const predicates = [
|
|
20
|
+
eq(schema.crmCallEvidence.recordId, args.recordId),
|
|
21
|
+
accessFilter(schema.crmCallEvidence, schema.crmCallEvidenceShares),
|
|
22
|
+
];
|
|
23
|
+
if (args.evidenceIds?.length) {
|
|
24
|
+
predicates.push(inArray(schema.crmCallEvidence.id, args.evidenceIds));
|
|
25
|
+
}
|
|
26
|
+
const rows = await db
|
|
27
|
+
.select()
|
|
28
|
+
.from(schema.crmCallEvidence)
|
|
29
|
+
.where(and(...predicates))
|
|
30
|
+
.limit(20);
|
|
31
|
+
if (
|
|
32
|
+
args.evidenceIds?.length &&
|
|
33
|
+
rows.length !== new Set(args.evidenceIds).size
|
|
34
|
+
) {
|
|
35
|
+
throw new Error("One or more call-evidence references are unavailable.");
|
|
36
|
+
}
|
|
37
|
+
return rows;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function evidenceExcerpts(
|
|
41
|
+
rows: Awaited<ReturnType<typeof loadCrmSignalEvidence>>,
|
|
42
|
+
): CallEvidenceExcerpt[] {
|
|
43
|
+
return rows.flatMap((row) => {
|
|
44
|
+
const quote = row.quote.trim() || row.summary.trim();
|
|
45
|
+
if (!quote) return [];
|
|
46
|
+
return [
|
|
47
|
+
{
|
|
48
|
+
evidenceRef: row.id,
|
|
49
|
+
quote,
|
|
50
|
+
...(row.speaker ? { speaker: row.speaker } : {}),
|
|
51
|
+
startSeconds: row.startSeconds ?? 0,
|
|
52
|
+
...(row.endSeconds !== null ? { endSeconds: row.endSeconds } : {}),
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function crmSignalIdempotencyKey(
|
|
59
|
+
ctx: ActionRunContext | undefined,
|
|
60
|
+
recordId: string,
|
|
61
|
+
key: string,
|
|
62
|
+
) {
|
|
63
|
+
const scope = requireCrmScope(ctx);
|
|
64
|
+
return {
|
|
65
|
+
scope,
|
|
66
|
+
key: await scopedCrmIdempotencyKey({
|
|
67
|
+
ownerEmail: scope.ownerEmail,
|
|
68
|
+
orgId: scope.orgId,
|
|
69
|
+
recordId,
|
|
70
|
+
key: `signal:${key}`,
|
|
71
|
+
}),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function signalTupleError(message: string): never {
|
|
76
|
+
const error = new Error(message) as Error & { statusCode?: number };
|
|
77
|
+
error.statusCode = 404;
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { defineAction, type ActionRunContext } from "@agent-native/core/action";
|
|
2
|
+
import { accessFilter, assertAccess } from "@agent-native/core/sharing";
|
|
3
|
+
import { and, eq } from "drizzle-orm";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
import { isConnectedCrmProvider } from "../server/crm/adapter.js";
|
|
7
|
+
import { getDb, schema } from "../server/db/index.js";
|
|
8
|
+
import {
|
|
9
|
+
isSafeCrmMutationFields,
|
|
10
|
+
parseJsonRecord,
|
|
11
|
+
requireCrmScope,
|
|
12
|
+
} from "./_crm-action-utils.js";
|
|
13
|
+
|
|
14
|
+
function conditionalMutationMessage(provider: "hubspot" | "salesforce") {
|
|
15
|
+
const label = provider === "hubspot" ? "HubSpot" : "Salesforce";
|
|
16
|
+
return `${label} did not apply this update because this connection has not proved an atomic expected-revision write path. Refresh the record and make this change in ${label}.`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function updateAffectedRows(result: unknown): number {
|
|
20
|
+
if (!result || typeof result !== "object") return 0;
|
|
21
|
+
const value = result as {
|
|
22
|
+
rowsAffected?: unknown;
|
|
23
|
+
rowCount?: unknown;
|
|
24
|
+
count?: unknown;
|
|
25
|
+
changes?: unknown;
|
|
26
|
+
meta?: { changes?: unknown };
|
|
27
|
+
};
|
|
28
|
+
for (const count of [
|
|
29
|
+
value.rowsAffected,
|
|
30
|
+
value.rowCount,
|
|
31
|
+
value.count,
|
|
32
|
+
value.changes,
|
|
33
|
+
value.meta?.changes,
|
|
34
|
+
]) {
|
|
35
|
+
if (typeof count === "number") return count;
|
|
36
|
+
}
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default defineAction({
|
|
41
|
+
description:
|
|
42
|
+
"Review one pending HubSpot or Salesforce provider proposal. The initial release records approval and fails closed unless the connection proves an atomic expected-revision write path; otherwise make the change upstream after review.",
|
|
43
|
+
schema: z.object({
|
|
44
|
+
proposalId: z.string().trim().min(1).max(128),
|
|
45
|
+
}),
|
|
46
|
+
needsApproval: true,
|
|
47
|
+
audit: {
|
|
48
|
+
target: (_args, result) => {
|
|
49
|
+
const response = result as {
|
|
50
|
+
recordId: string;
|
|
51
|
+
ownerEmail: string;
|
|
52
|
+
orgId: string | null;
|
|
53
|
+
visibility: "private" | "org";
|
|
54
|
+
};
|
|
55
|
+
return {
|
|
56
|
+
type: "crm-record",
|
|
57
|
+
id: response.recordId,
|
|
58
|
+
ownerEmail: response.ownerEmail,
|
|
59
|
+
orgId: response.orgId,
|
|
60
|
+
visibility: response.visibility,
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
summary: (args) => `Reviewed CRM proposal ${args.proposalId}`,
|
|
64
|
+
recordInputs: false,
|
|
65
|
+
},
|
|
66
|
+
run: async (args, ctx?: ActionRunContext) => {
|
|
67
|
+
await assertAccess("crm-mutation", args.proposalId, "editor");
|
|
68
|
+
const db = getDb();
|
|
69
|
+
const [proposal] = await db
|
|
70
|
+
.select()
|
|
71
|
+
.from(schema.crmMutations)
|
|
72
|
+
.where(
|
|
73
|
+
and(
|
|
74
|
+
eq(schema.crmMutations.id, args.proposalId),
|
|
75
|
+
accessFilter(
|
|
76
|
+
schema.crmMutations,
|
|
77
|
+
schema.crmMutationShares,
|
|
78
|
+
undefined,
|
|
79
|
+
"editor",
|
|
80
|
+
),
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
.limit(1);
|
|
84
|
+
if (!proposal) throw new Error("CRM proposal was not found.");
|
|
85
|
+
if (proposal.target !== "provider" || proposal.operation !== "update") {
|
|
86
|
+
throw new Error(
|
|
87
|
+
"Only pending provider update proposals can be reviewed in this phase.",
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
if (proposal.status !== "pending") {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`CRM proposal is ${proposal.status} and cannot be reviewed.`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (!proposal.recordId || !proposal.connectionId) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
"CRM proposal is missing its record or connection reference.",
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
await assertAccess("crm-record", proposal.recordId, "editor");
|
|
101
|
+
await assertAccess("crm-connection", proposal.connectionId, "editor");
|
|
102
|
+
const [[record], [connection]] = await Promise.all([
|
|
103
|
+
db
|
|
104
|
+
.select()
|
|
105
|
+
.from(schema.crmRecords)
|
|
106
|
+
.where(
|
|
107
|
+
and(
|
|
108
|
+
eq(schema.crmRecords.id, proposal.recordId),
|
|
109
|
+
accessFilter(
|
|
110
|
+
schema.crmRecords,
|
|
111
|
+
schema.crmRecordShares,
|
|
112
|
+
undefined,
|
|
113
|
+
"editor",
|
|
114
|
+
),
|
|
115
|
+
),
|
|
116
|
+
)
|
|
117
|
+
.limit(1),
|
|
118
|
+
db
|
|
119
|
+
.select()
|
|
120
|
+
.from(schema.crmConnections)
|
|
121
|
+
.where(
|
|
122
|
+
and(
|
|
123
|
+
eq(schema.crmConnections.id, proposal.connectionId),
|
|
124
|
+
accessFilter(
|
|
125
|
+
schema.crmConnections,
|
|
126
|
+
schema.crmConnectionShares,
|
|
127
|
+
undefined,
|
|
128
|
+
"editor",
|
|
129
|
+
),
|
|
130
|
+
),
|
|
131
|
+
)
|
|
132
|
+
.limit(1),
|
|
133
|
+
]);
|
|
134
|
+
if (!record || record.tombstone || !connection) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
"CRM proposal no longer has an available record and connection.",
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
if (!isConnectedCrmProvider(connection.provider)) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
"Only HubSpot and Salesforce provider proposals are enabled in this release.",
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
if (!connection.workspaceConnectionId) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
"CRM connection is missing its workspace connection reference.",
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
if (!proposal.expectedRemoteRevision) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
"CRM proposal has no remote revision and must be recreated from a refreshed record.",
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
const patch = parseJsonRecord(proposal.patchJson);
|
|
155
|
+
const fields = patch.fields;
|
|
156
|
+
if (!fields || typeof fields !== "object" || Array.isArray(fields)) {
|
|
157
|
+
throw new Error("CRM proposal has an invalid field patch.");
|
|
158
|
+
}
|
|
159
|
+
const fieldPatch = fields as Record<string, unknown>;
|
|
160
|
+
if (!isSafeCrmMutationFields(fieldPatch)) {
|
|
161
|
+
throw new Error("CRM proposal contains an unsafe field patch.");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const scope = requireCrmScope(ctx);
|
|
165
|
+
const now = new Date().toISOString();
|
|
166
|
+
const message = conditionalMutationMessage(connection.provider);
|
|
167
|
+
const claim = await db
|
|
168
|
+
.update(schema.crmMutations)
|
|
169
|
+
.set({
|
|
170
|
+
status: "rejected",
|
|
171
|
+
approvedBy: scope.ownerEmail,
|
|
172
|
+
approvedAt: now,
|
|
173
|
+
error: message,
|
|
174
|
+
updatedAt: now,
|
|
175
|
+
})
|
|
176
|
+
.where(
|
|
177
|
+
and(
|
|
178
|
+
eq(schema.crmMutations.id, proposal.id),
|
|
179
|
+
eq(schema.crmMutations.status, "pending"),
|
|
180
|
+
accessFilter(
|
|
181
|
+
schema.crmMutations,
|
|
182
|
+
schema.crmMutationShares,
|
|
183
|
+
undefined,
|
|
184
|
+
"editor",
|
|
185
|
+
),
|
|
186
|
+
),
|
|
187
|
+
);
|
|
188
|
+
if (updateAffectedRows(claim) !== 1) {
|
|
189
|
+
throw new Error(
|
|
190
|
+
"CRM proposal was already claimed by another application attempt.",
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
proposalId: proposal.id,
|
|
195
|
+
recordId: record.id,
|
|
196
|
+
status: "rejected" as const,
|
|
197
|
+
message,
|
|
198
|
+
ownerEmail: record.ownerEmail,
|
|
199
|
+
orgId: record.orgId,
|
|
200
|
+
visibility: record.visibility,
|
|
201
|
+
};
|
|
202
|
+
},
|
|
203
|
+
});
|