@agent-native/core 0.107.0 → 0.107.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +10 -0
  3. package/corpus/core/docs/content/integrations.mdx +27 -27
  4. package/corpus/core/package.json +1 -1
  5. package/corpus/core/src/agent/production-agent.ts +19 -0
  6. package/corpus/core/src/agent/run-store.ts +98 -2
  7. package/corpus/core/src/client/AssistantChat.tsx +13 -0
  8. package/corpus/core/src/client/CommandMenu.tsx +5 -0
  9. package/corpus/core/src/client/active-run-state.ts +34 -0
  10. package/corpus/core/src/client/agent-chat-adapter.ts +4 -0
  11. package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +41 -11
  12. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +27 -9
  13. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +45 -0
  14. package/corpus/core/src/client/sharing/ShareButton.tsx +30 -9
  15. package/corpus/core/src/client/use-agent-chat-home-handoff.ts +2 -2
  16. package/corpus/core/src/localization/default-messages.ts +4 -1
  17. package/corpus/core/src/secrets/register-framework-secrets.ts +28 -0
  18. package/corpus/core/src/server/agent-chat-plugin.ts +29 -1
  19. package/corpus/core/src/vite/client.ts +24 -0
  20. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -21
  21. package/corpus/templates/analytics/AGENTS.md +8 -0
  22. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +1 -1
  23. package/corpus/templates/analytics/actions/update-dashboard.ts +6 -2
  24. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +35 -7
  25. package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -3
  26. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +11 -1
  27. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/extension-slot.ts +11 -0
  28. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +27 -0
  29. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +6 -0
  30. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extension-boxes.md +6 -0
  31. package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +8 -0
  32. package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -0
  33. package/corpus/templates/assets/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  34. package/corpus/templates/brain/app/hooks/use-navigation-state.ts +6 -1
  35. package/corpus/templates/brain/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  36. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +1 -1
  37. package/corpus/templates/calendar/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  38. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +4 -1
  39. package/corpus/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  40. package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
  41. package/corpus/templates/clips/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  42. package/corpus/templates/content/actions/_content-space-access.ts +45 -2
  43. package/corpus/templates/content/actions/create-content-database.ts +41 -7
  44. package/corpus/templates/content/app/components/layout/Layout.tsx +1 -1
  45. package/corpus/templates/content/app/root.tsx +1 -10
  46. package/corpus/templates/content/changelog/2026-07-17-creating-a-database-now-completes-reliably-in-hosted-workspa.md +6 -0
  47. package/corpus/templates/content/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  48. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +4 -1
  49. package/corpus/templates/dispatch/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  50. package/corpus/templates/forms/app/components/layout/Layout.tsx +2 -4
  51. package/corpus/templates/forms/app/components/ui/popover.tsx +25 -1
  52. package/corpus/templates/forms/app/hooks/use-navigation-state.ts +6 -1
  53. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +13 -10
  54. package/corpus/templates/forms/app/root.tsx +6 -1
  55. package/corpus/templates/forms/changelog/2026-07-17-form-builder-popovers-stay-within-the-viewport.md +6 -0
  56. package/corpus/templates/forms/changelog/2026-07-17-form-editor-loading-matches-current-sidebar-free-layout.md +6 -0
  57. package/corpus/templates/forms/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  58. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +1 -1
  59. package/corpus/templates/mail/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  60. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +14 -3
  61. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +8 -1
  62. package/corpus/templates/plan/app/root.tsx +0 -2
  63. package/corpus/templates/plan/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  64. package/corpus/templates/slides/app/components/layout/Layout.tsx +1 -1
  65. package/corpus/templates/slides/app/context/DeckContext.tsx +23 -23
  66. package/corpus/templates/slides/changelog/2026-07-17-duplicated-slides-now-stay-in-the-deck.md +6 -0
  67. package/corpus/templates/slides/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  68. package/corpus/templates/tasks/app/components/layout/Layout.tsx +2 -13
  69. package/corpus/templates/tasks/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it.md +6 -0
  70. package/dist/agent/production-agent.d.ts.map +1 -1
  71. package/dist/agent/production-agent.js +13 -1
  72. package/dist/agent/production-agent.js.map +1 -1
  73. package/dist/agent/run-store.d.ts +17 -0
  74. package/dist/agent/run-store.d.ts.map +1 -1
  75. package/dist/agent/run-store.js +84 -2
  76. package/dist/agent/run-store.js.map +1 -1
  77. package/dist/client/AssistantChat.d.ts.map +1 -1
  78. package/dist/client/AssistantChat.js +10 -1
  79. package/dist/client/AssistantChat.js.map +1 -1
  80. package/dist/client/CommandMenu.d.ts.map +1 -1
  81. package/dist/client/CommandMenu.js +4 -0
  82. package/dist/client/CommandMenu.js.map +1 -1
  83. package/dist/client/active-run-state.d.ts +7 -0
  84. package/dist/client/active-run-state.d.ts.map +1 -1
  85. package/dist/client/active-run-state.js +28 -0
  86. package/dist/client/active-run-state.js.map +1 -1
  87. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  88. package/dist/client/agent-chat-adapter.js +4 -1
  89. package/dist/client/agent-chat-adapter.js.map +1 -1
  90. package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
  91. package/dist/client/resources/McpConnectionSuggestion.js +27 -8
  92. package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
  93. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  94. package/dist/client/resources/McpIntegrationDialog.js +4 -2
  95. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  96. package/dist/client/resources/mcp-integration-catalog.d.ts +6 -0
  97. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  98. package/dist/client/resources/mcp-integration-catalog.js +33 -0
  99. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  100. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  101. package/dist/client/sharing/ShareButton.js +15 -12
  102. package/dist/client/sharing/ShareButton.js.map +1 -1
  103. package/dist/client/use-agent-chat-home-handoff.d.ts +1 -1
  104. package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
  105. package/dist/client/use-agent-chat-home-handoff.js +1 -1
  106. package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
  107. package/dist/collab/awareness.d.ts +2 -2
  108. package/dist/collab/awareness.d.ts.map +1 -1
  109. package/dist/collab/routes.d.ts +1 -1
  110. package/dist/collab/struct-routes.d.ts +1 -1
  111. package/dist/localization/default-messages.d.ts +2 -0
  112. package/dist/localization/default-messages.d.ts.map +1 -1
  113. package/dist/localization/default-messages.js +3 -1
  114. package/dist/localization/default-messages.js.map +1 -1
  115. package/dist/observability/routes.d.ts +5 -5
  116. package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
  117. package/dist/secrets/register-framework-secrets.js +25 -0
  118. package/dist/secrets/register-framework-secrets.js.map +1 -1
  119. package/dist/secrets/routes.d.ts +9 -9
  120. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  121. package/dist/server/agent-chat-plugin.js +23 -1
  122. package/dist/server/agent-chat-plugin.js.map +1 -1
  123. package/dist/templates/chat/app/hooks/use-navigation-state.ts +4 -1
  124. package/dist/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  125. package/dist/vite/client.d.ts.map +1 -1
  126. package/dist/vite/client.js +20 -0
  127. package/dist/vite/client.js.map +1 -1
  128. package/docs/content/integrations.mdx +27 -27
  129. package/package.json +1 -1
  130. package/src/templates/chat/app/hooks/use-navigation-state.ts +4 -1
  131. package/src/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
package/corpus/README.md CHANGED
@@ -28,4 +28,4 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
28
28
  ## Generated Counts
29
29
 
30
30
  - core files: 2288
31
- - template files: 6095
31
+ - template files: 6113
@@ -1,5 +1,15 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.107.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 8e0afec: Preserve chat continuation context after stale background workers and make Stop durable before a serverless run id exists.
8
+ - 8e0afec: Offer the Figma REST API personal access token fallback when Figma MCP links are restricted.
9
+ - 8e0afec: Add a practical guide for organization context, team roles, resource permissions, RBAC, and framework environment variables.
10
+ - 8e0afec: Keep empty full-page chat navigation from automatically opening the AgentSidebar.
11
+ - 8e0afec: Keep the share popover open while adding people and preserve unfinished invite emails when it is reopened.
12
+
3
13
  ## 0.107.0
4
14
 
5
15
  ### Minor Changes
@@ -488,33 +488,33 @@ endpoint is reachable or cataloged, but a live provider authorization or tool
488
488
  session still needs to be completed. **Restricted** entries remain discoverable
489
489
  but need provider or administrator setup before a generic connection can work.
490
490
 
491
- | Integration | Connection mode | Status | Endpoint | Setup and notes |
492
- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | ---------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
493
- | [Context7](https://context7.com/) | No auth | Ready · verified | `https://mcp.context7.com/mcp` | Fetch current library and framework docs. |
494
- | [Sentry](https://docs.sentry.io/product/sentry-mcp/) | Header / token | Ready · preflight only | `https://mcp.sentry.dev/mcp` | Add a Sentry bearer token as the `Authorization` header. |
495
- | [Notion](https://developers.notion.com/guides/mcp/get-started-with-mcp) | OAuth | Ready · preflight only | `https://mcp.notion.com/mcp` | User OAuth; enterprise admins can audit or restrict MCP clients. |
496
- | [Semgrep](https://github.com/semgrep/mcp#readme) | No auth | Ready · preflight only | `https://mcp.semgrep.ai/mcp` | Scan code for security findings. |
497
- | [Linear](https://linear.app/docs/mcp) | OAuth | Ready · preflight only | `https://mcp.linear.app/mcp` | Authorize the workspace and issue permissions required by the workflow. |
498
- | [Atlassian Rovo MCP](https://developer.atlassian.com/cloud/rovo-mcp/guides/getting-started/) | OAuth + provider setup | Restricted | `https://mcp.atlassian.com/v1/mcp/authv2` | Admins may need to trust the app origin and enable Rovo Read, Write, and Search permissions. |
499
- | [Supabase](https://www.builder.io/c/docs/fusion-connect-to-supabase) | OAuth | Ready · preflight only | `https://mcp.supabase.com/mcp` | Authorize the Supabase project and requested backend scopes. |
500
- | [Neon](https://www.builder.io/c/docs/fusion-connect-to-neon) | OAuth | Ready · preflight only | `https://mcp.neon.tech/sse` | Authorize access to the serverless Postgres projects needed by the app. |
501
- | [Stripe](https://docs.stripe.com/mcp) | OAuth | Ready · preflight only | `https://mcp.stripe.com` | Review payment, customer, and subscription permissions before authorizing. |
502
- | [Cloudflare](https://developers.cloudflare.com/agents/model-context-protocol/cloudflare/servers-for-cloudflare/) | OAuth | Ready · preflight only | `https://mcp.cloudflare.com/mcp` | Choose the narrowest Cloudflare server and review scopes. |
503
- | [GitLab](https://docs.gitlab.com/user/model_context_protocol/mcp_server/) | OAuth + provider setup | Beta · restricted | `https://gitlab.com/api/v4/mcp` | A top-level group admin, or the equivalent self-managed instance admin, must allow MCP. |
504
- | [Figma](https://developers.figma.com/docs/figma-mcp-server/) | Manual setup | Approved clients only · restricted | `https://mcp.figma.com/mcp` | Figma only allows clients in its MCP Catalog; use the Figma OAuth connector for app-owned workflows until approved. |
505
- | [Canva](https://www.canva.dev/docs/mcp/) | Manual setup | Approved domains · restricted | `https://mcp.canva.com/mcp` | Per-user OAuth; clients must allow Canva's canva.com and canva.ai domains and follow the current redirect setup. |
506
- | [Vercel](https://vercel.com/docs/agent-resources/vercel-mcp) | Manual setup | Approved clients only · restricted | `https://mcp.vercel.com` | Vercel must list the client as approved before a generic connection will work. |
507
- | [GitHub](https://github.com/github/github-mcp-server) | Manual setup | Provider setup · restricted | `https://api.githubcopilot.com/mcp/` | Use a registered OAuth app; organizations may also enforce OAuth App Access Policies. |
508
- | [Slack](https://docs.slack.dev/ai/slack-mcp-server/) | Manual setup | Approved clients only · restricted | `https://mcp.slack.com/mcp` | Requires a fixed registered Slack app; dynamic client registration is not supported. |
509
- | [Asana](https://developers.asana.com/docs/integrating-with-asanas-mcp-server) | Manual setup | Provider setup · restricted | `https://mcp.asana.com/v2/mcp` | Pre-register an Asana MCP OAuth app before connecting. |
510
- | [HubSpot](https://developers.hubspot.com/docs/apps/developer-platform/build-apps/integrate-with-the-remote-hubspot-mcp-server) | Manual setup | Provider setup · restricted | `https://mcp.hubspot.com` | Create a HubSpot MCP Auth App with PKCE; the existing HubSpot OAuth connector remains available to app actions. |
511
- | [Intercom](https://developers.intercom.com/docs/guides/mcp) | OAuth | Ready · preflight only | `https://mcp.intercom.com/mcp` | Available for US-hosted workspaces; confirm region and scopes during authorization. |
512
- | [monday.com](https://developer.monday.com/api-reference/docs/build-on-monday-with-ai) | OAuth | Ready · preflight only | `https://mcp.monday.com/mcp` | Choose the workspace and permissions to share during authorization. |
513
- | [Webflow](https://developers.webflow.com/mcp/reference/getting-started) | OAuth | Ready · preflight only | `https://mcp.webflow.com/mcp` | Designer capabilities may install Webflow's Bridge App; Data API access is separate. |
514
- | [PayPal](https://developer.paypal.com/ai-tools/mcp-server/) | OAuth | Ready · preflight only | `https://mcp.paypal.com/sse` | Review merchant permissions before authorizing the remote server. |
515
- | [Box](https://developer.box.com/guides/box-mcp) | Manual setup | Beta · restricted | `https://mcp.box.com` | An administrator must enable Box MCP; custom clients also need credentials, a redirect URI, and approved scopes. |
516
- | [Netlify](https://docs.netlify.com/build/build-with-ai/agent-setup-guides/agent-setup-overview/) | OAuth | Ready · preflight only | `https://netlify-mcp.netlify.app/mcp` | Review site and team permissions before completing OAuth. |
517
- | [Zapier MCP](https://help.zapier.com/hc/en-us/articles/36265392843917-Use-Zapier-MCP-with-your-client) | Header / token | User-created server · restricted | `https://mcp.zapier.com/api/v1/connect` | Create the MCP server in Zapier, then paste its generated bearer token into the header field. |
491
+ | Integration | Connection mode | Status | Endpoint | Setup and notes |
492
+ | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | ---------------------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
493
+ | [Context7](https://context7.com/) | No auth | Ready · verified | `https://mcp.context7.com/mcp` | Fetch current library and framework docs. |
494
+ | [Sentry](https://docs.sentry.io/product/sentry-mcp/) | Header / token | Ready · preflight only | `https://mcp.sentry.dev/mcp` | Add a Sentry bearer token as the `Authorization` header. |
495
+ | [Notion](https://developers.notion.com/guides/mcp/get-started-with-mcp) | OAuth | Ready · preflight only | `https://mcp.notion.com/mcp` | User OAuth; enterprise admins can audit or restrict MCP clients. |
496
+ | [Semgrep](https://github.com/semgrep/mcp#readme) | No auth | Ready · preflight only | `https://mcp.semgrep.ai/mcp` | Scan code for security findings. |
497
+ | [Linear](https://linear.app/docs/mcp) | OAuth | Ready · preflight only | `https://mcp.linear.app/mcp` | Authorize the workspace and issue permissions required by the workflow. |
498
+ | [Atlassian Rovo MCP](https://developer.atlassian.com/cloud/rovo-mcp/guides/getting-started/) | OAuth + provider setup | Restricted | `https://mcp.atlassian.com/v1/mcp/authv2` | Admins may need to trust the app origin and enable Rovo Read, Write, and Search permissions. |
499
+ | [Supabase](https://www.builder.io/c/docs/fusion-connect-to-supabase) | OAuth | Ready · preflight only | `https://mcp.supabase.com/mcp` | Authorize the Supabase project and requested backend scopes. |
500
+ | [Neon](https://www.builder.io/c/docs/fusion-connect-to-neon) | OAuth | Ready · preflight only | `https://mcp.neon.tech/sse` | Authorize access to the serverless Postgres projects needed by the app. |
501
+ | [Stripe](https://docs.stripe.com/mcp) | OAuth | Ready · preflight only | `https://mcp.stripe.com` | Review payment, customer, and subscription permissions before authorizing. |
502
+ | [Cloudflare](https://developers.cloudflare.com/agents/model-context-protocol/cloudflare/servers-for-cloudflare/) | OAuth | Ready · preflight only | `https://mcp.cloudflare.com/mcp` | Choose the narrowest Cloudflare server and review scopes. |
503
+ | [GitLab](https://docs.gitlab.com/user/model_context_protocol/mcp_server/) | OAuth + provider setup | Beta · restricted | `https://gitlab.com/api/v4/mcp` | A top-level group admin, or the equivalent self-managed instance admin, must allow MCP. |
504
+ | [Figma](https://developers.figma.com/docs/figma-mcp-server/) | Manual setup | Approved clients only · restricted | `https://mcp.figma.com/mcp` | Figma only allows clients in its MCP Catalog. Use the [Figma REST API personal access token fallback](https://developers.figma.com/docs/rest-api/personal-access-tokens/) for file and node reads until Agent Native is approved. |
505
+ | [Canva](https://www.canva.dev/docs/mcp/) | Manual setup | Approved domains · restricted | `https://mcp.canva.com/mcp` | Per-user OAuth; clients must allow Canva's canva.com and canva.ai domains and follow the current redirect setup. |
506
+ | [Vercel](https://vercel.com/docs/agent-resources/vercel-mcp) | Manual setup | Approved clients only · restricted | `https://mcp.vercel.com` | Vercel must list the client as approved before a generic connection will work. |
507
+ | [GitHub](https://github.com/github/github-mcp-server) | Manual setup | Provider setup · restricted | `https://api.githubcopilot.com/mcp/` | Use a registered OAuth app; organizations may also enforce OAuth App Access Policies. |
508
+ | [Slack](https://docs.slack.dev/ai/slack-mcp-server/) | Manual setup | Approved clients only · restricted | `https://mcp.slack.com/mcp` | Requires a fixed registered Slack app; dynamic client registration is not supported. |
509
+ | [Asana](https://developers.asana.com/docs/integrating-with-asanas-mcp-server) | Manual setup | Provider setup · restricted | `https://mcp.asana.com/v2/mcp` | Pre-register an Asana MCP OAuth app before connecting. |
510
+ | [HubSpot](https://developers.hubspot.com/docs/apps/developer-platform/build-apps/integrate-with-the-remote-hubspot-mcp-server) | Manual setup | Provider setup · restricted | `https://mcp.hubspot.com` | Create a HubSpot MCP Auth App with PKCE; the existing HubSpot OAuth connector remains available to app actions. |
511
+ | [Intercom](https://developers.intercom.com/docs/guides/mcp) | OAuth | Ready · preflight only | `https://mcp.intercom.com/mcp` | Available for US-hosted workspaces; confirm region and scopes during authorization. |
512
+ | [monday.com](https://developer.monday.com/api-reference/docs/build-on-monday-with-ai) | OAuth | Ready · preflight only | `https://mcp.monday.com/mcp` | Choose the workspace and permissions to share during authorization. |
513
+ | [Webflow](https://developers.webflow.com/mcp/reference/getting-started) | OAuth | Ready · preflight only | `https://mcp.webflow.com/mcp` | Designer capabilities may install Webflow's Bridge App; Data API access is separate. |
514
+ | [PayPal](https://developer.paypal.com/ai-tools/mcp-server/) | OAuth | Ready · preflight only | `https://mcp.paypal.com/sse` | Review merchant permissions before authorizing the remote server. |
515
+ | [Box](https://developer.box.com/guides/box-mcp) | Manual setup | Beta · restricted | `https://mcp.box.com` | An administrator must enable Box MCP; custom clients also need credentials, a redirect URI, and approved scopes. |
516
+ | [Netlify](https://docs.netlify.com/build/build-with-ai/agent-setup-guides/agent-setup-overview/) | OAuth | Ready · preflight only | `https://netlify-mcp.netlify.app/mcp` | Review site and team permissions before completing OAuth. |
517
+ | [Zapier MCP](https://help.zapier.com/hc/en-us/articles/36265392843917-Use-Zapier-MCP-with-your-client) | Header / token | User-created server · restricted | `https://mcp.zapier.com/api/v1/connect` | Create the MCP server in Zapier, then paste its generated bearer token into the header field. |
518
518
 
519
519
  ### Repeatable preflight verification
520
520
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.107.0",
3
+ "version": "0.107.1",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -136,6 +136,8 @@ import {
136
136
  readLedgerEntry,
137
137
  clearLedgerForThread,
138
138
  insertRun,
139
+ isTurnAborted,
140
+ markRunAborted,
139
141
  updateRunHeartbeat,
140
142
  updateRunStatusIfRunning,
141
143
  setRunError,
@@ -7058,6 +7060,13 @@ export function createProductionAgentHandler(
7058
7060
  // slot and inserted the run row before dispatching, so re-claiming here
7059
7061
  // would falsely 409 against the row the foreground holds.
7060
7062
  if (threadId && !isBackgroundWorker) {
7063
+ if (
7064
+ typeof requestTurnId === "string" &&
7065
+ requestTurnId &&
7066
+ (await isTurnAborted(threadId, requestTurnId))
7067
+ ) {
7068
+ return { ok: true, stopped: true };
7069
+ }
7061
7070
  const slot = await tryClaimRunSlot(threadId);
7062
7071
  if (!slot.claimed) {
7063
7072
  setResponseStatus(event, 409);
@@ -7186,6 +7195,16 @@ export function createProductionAgentHandler(
7186
7195
  );
7187
7196
  }
7188
7197
 
7198
+ // Stop may land after the pre-claim check but before the durable row was
7199
+ // inserted. Terminalize that row before it can be handed to a worker.
7200
+ if (
7201
+ backgroundRowInserted &&
7202
+ (await isTurnAborted(effectiveThreadId, effectiveTurnId))
7203
+ ) {
7204
+ await markRunAborted(runId, "user");
7205
+ return { ok: true, stopped: true };
7206
+ }
7207
+
7189
7208
  let dispatched = false;
7190
7209
  const backgroundDispatchPath = resolveAgentChatProcessRunDispatchPath();
7191
7210
  const expectsNetlifyBackgroundFunction =
@@ -42,6 +42,21 @@ export const RUN_STALE_MS = 15_000;
42
42
  */
43
43
  export const BACKGROUND_RUN_STALE_MS = 90_000;
44
44
 
45
+ /**
46
+ * A row is `background` only while the platform may still be cold-starting the
47
+ * worker, so it needs the full 90s handoff allowance above. Once that worker
48
+ * atomically claims the row (`background-processing`), it has already proved
49
+ * it started and should be reaped sooner if both heartbeat and real progress
50
+ * stop. This keeps a silent post-claim worker death from holding the client
51
+ * for the entire cold-start window before the durable successor is created.
52
+ *
53
+ * A real long-running tool or nested agent call still sets `in_flight_since`,
54
+ * which grants the bounded `IN_FLIGHT_RUN_STALE_GRACE_MS` below. Healthy model
55
+ * work keeps the normal heartbeat moving every 1.5s, so this is only a faster
56
+ * recovery path for a worker that has genuinely gone silent.
57
+ */
58
+ export const BACKGROUND_PROCESSING_RUN_STALE_MS = 45_000;
59
+
45
60
  export const STALE_RUN_ERROR_EVENT = {
46
61
  type: "error",
47
62
  error:
@@ -601,7 +616,7 @@ function backgroundAwareStaleCutoffSql(): string {
601
616
  // `CAST(? AS BIGINT)` is required: without it Postgres infers the param as
602
617
  // int4 from the int4 window literals, so the bound `Date.now()` ms epoch
603
618
  // overflows int4. The cast keeps the subtraction 64-bit; a no-op on SQLite.
604
- return `(CAST(? AS BIGINT) - CASE WHEN dispatch_mode LIKE 'background%' THEN ${BACKGROUND_RUN_STALE_MS} ELSE ${RUN_STALE_MS} END)`;
619
+ return `(CAST(? AS BIGINT) - CASE WHEN dispatch_mode = 'background-processing' THEN ${BACKGROUND_PROCESSING_RUN_STALE_MS} WHEN dispatch_mode LIKE 'background%' THEN ${BACKGROUND_RUN_STALE_MS} ELSE ${RUN_STALE_MS} END)`;
605
620
  }
606
621
 
607
622
  function terminalRunEventExclusionSql(runIdColumn = "id"): string {
@@ -1358,6 +1373,21 @@ function generateRecoveryRunId(): string {
1358
1373
  return `run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
1359
1374
  }
1360
1375
 
1376
+ function staleRecoveryDispatchPayload(payload: string): string {
1377
+ try {
1378
+ const parsed = JSON.parse(payload);
1379
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1380
+ return payload;
1381
+ }
1382
+ return JSON.stringify({
1383
+ ...(parsed as Record<string, unknown>),
1384
+ internalContinuation: true,
1385
+ });
1386
+ } catch {
1387
+ return payload;
1388
+ }
1389
+ }
1390
+
1361
1391
  /**
1362
1392
  * FIX 3 (durable-background incident): when a stale-run reaper is about to
1363
1393
  * flip a BACKGROUND chat-turn run to errored/stale_run, attempt to keep the
@@ -1451,7 +1481,15 @@ async function attemptStaleRunRecovery(
1451
1481
  const now = Date.now();
1452
1482
  await db.execute({
1453
1483
  sql: `INSERT INTO agent_runs (id, thread_id, status, started_at, heartbeat_at, last_progress_at, turn_id, dispatch_mode, dispatch_payload) VALUES (?, ?, 'running', ?, ?, ?, ?, 'background', ?) ON CONFLICT (id) DO NOTHING`,
1454
- args: [successorRunId, threadId, now, now, now, turnId, payload],
1484
+ args: [
1485
+ successorRunId,
1486
+ threadId,
1487
+ now,
1488
+ now,
1489
+ now,
1490
+ turnId,
1491
+ staleRecoveryDispatchPayload(payload),
1492
+ ],
1455
1493
  });
1456
1494
  return { outcome: "recovered", successorRunId, threadId, turnId };
1457
1495
  }
@@ -1759,6 +1797,64 @@ export async function markRunAborted(
1759
1797
  }
1760
1798
  }
1761
1799
 
1800
+ function turnAbortMarkerRunId(turnId: string): string {
1801
+ return `turn-abort-${turnId}`;
1802
+ }
1803
+
1804
+ /** Records Stop before a foreground request has created its real run row. */
1805
+ export async function markTurnAborted(
1806
+ threadId: string,
1807
+ turnId: string,
1808
+ reason: string = "user",
1809
+ ): Promise<void> {
1810
+ await ensureRunTables();
1811
+ const now = Date.now();
1812
+ const client = getDbExec();
1813
+ await client.execute({
1814
+ sql: `INSERT INTO agent_runs (id, thread_id, status, abort_reason, started_at, completed_at, heartbeat_at, last_progress_at, turn_id, terminal_reason, dispatch_mode) VALUES (?, ?, 'aborted', ?, ?, ?, ?, ?, ?, ?, 'turn-abort') ON CONFLICT (id) DO NOTHING`,
1815
+ args: [
1816
+ turnAbortMarkerRunId(turnId),
1817
+ threadId,
1818
+ reason,
1819
+ now,
1820
+ now,
1821
+ now,
1822
+ now,
1823
+ turnId,
1824
+ `aborted:${reason}`,
1825
+ ],
1826
+ });
1827
+ const { rows } = await client.execute({
1828
+ sql: `SELECT id FROM agent_runs WHERE thread_id = ? AND turn_id = ? AND status = 'running'`,
1829
+ args: [threadId, turnId],
1830
+ });
1831
+ const runIds = rows
1832
+ .map((row) => String((row as { id?: unknown }).id ?? ""))
1833
+ .filter(Boolean);
1834
+ if (runIds.length === 0) return;
1835
+ await client.execute({
1836
+ sql: `UPDATE agent_runs SET status = 'aborted', abort_reason = ?, completed_at = ?, terminal_reason = ? WHERE thread_id = ? AND turn_id = ? AND status = 'running'`,
1837
+ args: [reason, Date.now(), `aborted:${reason}`, threadId, turnId],
1838
+ });
1839
+ await Promise.all(
1840
+ runIds.map((runId) =>
1841
+ safeAppendTerminalRunEvent(runId, { type: "done" }, "mark-turn-aborted"),
1842
+ ),
1843
+ );
1844
+ }
1845
+
1846
+ export async function isTurnAborted(
1847
+ threadId: string,
1848
+ turnId: string,
1849
+ ): Promise<boolean> {
1850
+ await ensureRunTables();
1851
+ const { rows } = await getDbExec().execute({
1852
+ sql: `SELECT id FROM agent_runs WHERE id = ? AND thread_id = ? AND status = 'aborted' LIMIT 1`,
1853
+ args: [turnAbortMarkerRunId(turnId), threadId],
1854
+ });
1855
+ return rows.length > 0;
1856
+ }
1857
+
1762
1858
  export async function isRunAborted(runId: string): Promise<boolean> {
1763
1859
  return (await getRunAbortState(runId)).aborted;
1764
1860
  }
@@ -38,7 +38,9 @@ import React, {
38
38
  import type { ReasoningEffort } from "../shared/reasoning-effort.js";
39
39
  import {
40
40
  ACTIVE_RUN_STATE_EVENT,
41
+ clearPendingTurnIfMatches,
41
42
  clearActiveRunIfMatches,
43
+ getPendingTurn,
42
44
  getActiveRunActivityTool,
43
45
  getActiveRun,
44
46
  resolveReconnectAfterSeq,
@@ -4281,6 +4283,7 @@ const AssistantChatInner = forwardRef<
4281
4283
  }
4282
4284
  const activeRun = getActiveRun();
4283
4285
  const runIdToAbort = reconnectRunIdRef.current ?? activeRun?.runId;
4286
+ const pendingTurn = threadId ? getPendingTurn(threadId) : null;
4284
4287
  userStoppedRunRef.current = {
4285
4288
  at: Date.now(),
4286
4289
  ...(runIdToAbort ? { runId: runIdToAbort } : {}),
@@ -4292,6 +4295,16 @@ const AssistantChatInner = forwardRef<
4292
4295
  fetch(`${apiUrl}/runs/${encodeURIComponent(runIdToAbort)}/abort`, {
4293
4296
  method: "POST",
4294
4297
  }).catch(() => {});
4298
+ } else if (pendingTurn && threadId) {
4299
+ clearPendingTurnIfMatches(threadId, pendingTurn.turnId);
4300
+ fetch(
4301
+ `${apiUrl}/runs/turn/${encodeURIComponent(pendingTurn.turnId)}/abort`,
4302
+ {
4303
+ method: "POST",
4304
+ headers: { "Content-Type": "application/json" },
4305
+ body: JSON.stringify({ threadId }),
4306
+ },
4307
+ ).catch(() => {});
4295
4308
  }
4296
4309
  if (isReconnecting) {
4297
4310
  reconnectAbortRef.current?.abort();
@@ -72,6 +72,11 @@ export function openAgentSettings(
72
72
  const normalizedSection =
73
73
  typeof section === "string" ? section : section?.section;
74
74
 
75
+ const secretHash = normalizedSection?.replace(/^#/, "");
76
+ if (secretHash?.toLowerCase().startsWith("secrets:")) {
77
+ window.location.hash = `#${secretHash}`;
78
+ }
79
+
75
80
  openAgentSidebar();
76
81
  // Voice mode unmounts the chat surface while its dock is collapsed, so its
77
82
  // settings listener does not exist until opening the sidebar remounts it.
@@ -1,4 +1,5 @@
1
1
  const STORAGE_KEY = "agent-chat-active-run";
2
+ const PENDING_TURN_STORAGE_KEY = "agent-chat-pending-turn";
2
3
  export const ACTIVE_RUN_STATE_EVENT = "agent-chat:active-run-state-change";
3
4
 
4
5
  export interface ActiveRunState {
@@ -8,6 +9,11 @@ export interface ActiveRunState {
8
9
  activityTool?: string | null;
9
10
  }
10
11
 
12
+ export interface PendingTurnState {
13
+ threadId: string;
14
+ turnId: string;
15
+ }
16
+
11
17
  function notifyActiveRunStateChanged(state: ActiveRunState | null): void {
12
18
  if (
13
19
  typeof window === "undefined" ||
@@ -88,6 +94,34 @@ export function clearActiveRunIfMatches(threadId: string, runId: string): void {
88
94
  clearActiveRun();
89
95
  }
90
96
 
97
+ export function setPendingTurn(state: PendingTurnState): void {
98
+ try {
99
+ sessionStorage.setItem(PENDING_TURN_STORAGE_KEY, JSON.stringify(state));
100
+ } catch {}
101
+ }
102
+
103
+ export function getPendingTurn(threadId: string): PendingTurnState | null {
104
+ try {
105
+ const raw = sessionStorage.getItem(PENDING_TURN_STORAGE_KEY);
106
+ if (!raw) return null;
107
+ const state = JSON.parse(raw) as PendingTurnState;
108
+ return state.threadId === threadId && state.turnId ? state : null;
109
+ } catch {
110
+ return null;
111
+ }
112
+ }
113
+
114
+ export function clearPendingTurnIfMatches(
115
+ threadId: string,
116
+ turnId?: string,
117
+ ): void {
118
+ const state = getPendingTurn(threadId);
119
+ if (!state || (turnId && state.turnId !== turnId)) return;
120
+ try {
121
+ sessionStorage.removeItem(PENDING_TURN_STORAGE_KEY);
122
+ } catch {}
123
+ }
124
+
91
125
  /** Resume reconnect SSE after the last seen event (0 = replay from the start). */
92
126
  export function resolveReconnectAfterSeq(
93
127
  threadId: string,
@@ -11,9 +11,11 @@ import type {
11
11
  } from "../agent/types.js";
12
12
  import type { ReasoningEffort } from "../shared/reasoning-effort.js";
13
13
  import {
14
+ clearPendingTurnIfMatches,
14
15
  setActiveRun,
15
16
  updateActiveRunSeq,
16
17
  clearActiveRun,
18
+ setPendingTurn,
17
19
  } from "./active-run-state.js";
18
20
  import { captureError } from "./analytics.js";
19
21
  import { agentNativePath } from "./api-path.js";
@@ -1634,6 +1636,7 @@ export function createAgentChatAdapter(
1634
1636
  const content: ContentPart[] = [];
1635
1637
  const toolCallCounter = { value: 0 };
1636
1638
  const turnId = generateTurnId();
1639
+ if (threadId) setPendingTurn({ threadId, turnId });
1637
1640
  let runId: string | null = null;
1638
1641
  let lastSeq = -1;
1639
1642
  const seenRunSeqs = new Map<string, number>();
@@ -3279,6 +3282,7 @@ export function createAgentChatAdapter(
3279
3282
  attemptedRunIds.push(runId);
3280
3283
  }
3281
3284
  if (runId && threadId) {
3285
+ clearPendingTurnIfMatches(threadId, turnId);
3282
3286
  setActiveRun({ threadId, runId, lastSeq: -1 });
3283
3287
  }
3284
3288
 
@@ -7,10 +7,12 @@ import {
7
7
  import { useEffect, useMemo, useState } from "react";
8
8
 
9
9
  import { agentNativePath } from "../api-path.js";
10
+ import { openAgentSettings } from "../CommandMenu.js";
10
11
  import { useT } from "../i18n.js";
11
12
  import {
12
13
  buildMcpOAuthStartUrl,
13
14
  findMcpIntegrationForText,
15
+ getMcpIntegrationApiFallback,
14
16
  getDefaultMcpIntegrations,
15
17
  isMcpConnectionFailureText,
16
18
  type DefaultMcpIntegration,
@@ -67,6 +69,12 @@ function canStartOAuth(integration: DefaultMcpIntegration): boolean {
67
69
  );
68
70
  }
69
71
 
72
+ function hasApiFallback(
73
+ apiFallback: DefaultMcpIntegration["apiFallback"] | null,
74
+ ): boolean {
75
+ return Boolean(apiFallback);
76
+ }
77
+
70
78
  export function McpConnectionSuggestion({
71
79
  text,
72
80
  contextText = "",
@@ -96,6 +104,9 @@ export function McpConnectionSuggestion({
96
104
  textIntegration.id !== contextIntegration.id
97
105
  ? null
98
106
  : (textIntegration ?? contextIntegration);
107
+ const apiFallback = integration
108
+ ? getMcpIntegrationApiFallback(integration)
109
+ : null;
99
110
  const servers = useMemo(
100
111
  () => [
101
112
  ...(mcpServersQuery.data?.user ?? []),
@@ -122,6 +133,11 @@ export function McpConnectionSuggestion({
122
133
  if (!integration || connecting) return;
123
134
  setError(null);
124
135
 
136
+ if (apiFallback) {
137
+ openAgentSettings(`secrets:${apiFallback.secretKey}`);
138
+ return;
139
+ }
140
+
125
141
  if (canStartOAuth(integration)) {
126
142
  window.location.assign(
127
143
  agentNativePath(
@@ -163,12 +179,14 @@ export function McpConnectionSuggestion({
163
179
  setDialogOpen(true);
164
180
  };
165
181
 
166
- const actionLabel = canStartOAuth(integration)
167
- ? t("mcpIntegrations.connectWithOAuth")
168
- : integration.availability === "client-restricted" ||
169
- integration.availability === "provider-setup"
170
- ? t("mcpIntegrations.viewSetup")
171
- : t("mcpIntegrations.connect");
182
+ const actionLabel = hasApiFallback(apiFallback)
183
+ ? t("mcpIntegrations.useApiToken")
184
+ : canStartOAuth(integration)
185
+ ? t("mcpIntegrations.connectWithOAuth")
186
+ : integration.availability === "client-restricted" ||
187
+ integration.availability === "provider-setup"
188
+ ? t("mcpIntegrations.viewSetup")
189
+ : t("mcpIntegrations.connect");
172
190
 
173
191
  return (
174
192
  <>
@@ -194,7 +212,12 @@ export function McpConnectionSuggestion({
194
212
  )}
195
213
  </div>
196
214
  <span className="min-w-0 flex-1 leading-snug text-foreground">
197
- {t("mcpIntegrations.connectSuggestion", { name: integration.name })}
215
+ {t(
216
+ hasApiFallback(apiFallback)
217
+ ? "mcpIntegrations.connectSuggestionWithApiToken"
218
+ : "mcpIntegrations.connectSuggestion",
219
+ { name: integration.name },
220
+ )}
198
221
  </span>
199
222
  <button
200
223
  type="button"
@@ -203,13 +226,20 @@ export function McpConnectionSuggestion({
203
226
  className="inline-flex shrink-0 items-center gap-1 rounded-md bg-primary px-2.5 py-1.5 text-[11px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-60"
204
227
  >
205
228
  {connecting && <IconLoader2 className="h-3 w-3 animate-spin" />}
206
- {!connecting && canStartOAuth(integration) && (
229
+ {!connecting &&
230
+ canStartOAuth(integration) &&
231
+ !hasApiFallback(apiFallback) && (
232
+ <IconPlugConnected className="h-3 w-3" />
233
+ )}
234
+ {!connecting && hasApiFallback(apiFallback) && (
207
235
  <IconPlugConnected className="h-3 w-3" />
208
236
  )}
209
237
  {actionLabel}
210
- {!connecting && !canStartOAuth(integration) && (
211
- <IconArrowUpRight className="h-3 w-3" />
212
- )}
238
+ {!connecting &&
239
+ !canStartOAuth(integration) &&
240
+ !hasApiFallback(apiFallback) && (
241
+ <IconArrowUpRight className="h-3 w-3" />
242
+ )}
213
243
  </button>
214
244
  <button
215
245
  type="button"
@@ -9,6 +9,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
9
9
 
10
10
  import { AgentAskPopover } from "../AgentAskPopover.js";
11
11
  import { agentNativePath } from "../api-path.js";
12
+ import { openAgentSettings } from "../CommandMenu.js";
12
13
  import {
13
14
  Dialog,
14
15
  DialogContent,
@@ -27,6 +28,7 @@ import {
27
28
  buildMcpOAuthStartUrl,
28
29
  createMcpIntegrationFormDefaults,
29
30
  filterMcpIntegrations,
31
+ getMcpIntegrationApiFallback,
30
32
  getDefaultMcpIntegrations,
31
33
  isCustomMcpIntegrationEnabled,
32
34
  resolveMcpIntegrationScope,
@@ -445,6 +447,7 @@ export function McpIntegrationDialog({
445
447
  )}
446
448
  <div className="grid gap-3 sm:grid-cols-2">
447
449
  {filteredIntegrations.map((integration) => {
450
+ const apiFallback = getMcpIntegrationApiFallback(integration);
448
451
  const connected = connectedUrls.has(
449
452
  compareUrl(integration.url),
450
453
  );
@@ -515,15 +518,30 @@ export function McpIntegrationDialog({
515
518
  {t("mcpIntegrations.connected")}
516
519
  </button>
517
520
  ) : setupOnly ? (
518
- <a
519
- href={integration.docsUrl}
520
- target="_blank"
521
- rel="noopener noreferrer"
522
- className="inline-flex h-8 flex-1 items-center justify-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-[12px] font-medium text-foreground hover:bg-accent"
523
- >
524
- {t("mcpIntegrations.viewSetup")}
525
- <IconExternalLink className="h-3.5 w-3.5" />
526
- </a>
521
+ <>
522
+ {apiFallback && (
523
+ <button
524
+ type="button"
525
+ onClick={() =>
526
+ openAgentSettings(
527
+ `secrets:${apiFallback.secretKey}`,
528
+ )
529
+ }
530
+ className="inline-flex h-8 flex-1 items-center justify-center gap-1.5 rounded-md bg-primary px-2.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90"
531
+ >
532
+ {t("mcpIntegrations.useApiToken")}
533
+ </button>
534
+ )}
535
+ <a
536
+ href={integration.docsUrl}
537
+ target="_blank"
538
+ rel="noopener noreferrer"
539
+ className="inline-flex h-8 flex-1 items-center justify-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-[12px] font-medium text-foreground hover:bg-accent"
540
+ >
541
+ {t("mcpIntegrations.viewSetup")}
542
+ <IconExternalLink className="h-3.5 w-3.5" />
543
+ </a>
544
+ </>
527
545
  ) : (
528
546
  <button
529
547
  type="button"