@agent-native/core 0.145.8 → 0.146.0

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 (118) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +37 -11
  3. package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  4. package/corpus/templates/analytics/actions/get-sql-dashboard.ts +20 -4
  5. package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +59 -24
  6. package/corpus/templates/analytics/changelog/2026-08-07-analytics-migrations-now-use-bounded-pressure-aware-backgrou.md +6 -0
  7. package/corpus/templates/analytics/changelog/2026-08-07-template-activity-charts-now-show-only-core-agent-native-app.md +6 -0
  8. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +110 -0
  9. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +13 -13
  10. package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +448 -0
  11. package/corpus/templates/analytics/server/jobs/analytics-rollup-backfill.ts +2 -2
  12. package/corpus/templates/analytics/server/lib/analytics-rollup-lock.ts +4 -5
  13. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +35 -0
  14. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +3 -5
  15. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +10 -4
  16. package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +4 -11
  17. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +74 -28
  18. package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +2 -5
  19. package/corpus/templates/analytics/server/plugins/db.ts +42 -0
  20. package/corpus/templates/analytics/server/routes/api/analytics-bigquery/backfill.post.ts +55 -0
  21. package/corpus/templates/analytics/server/routes/api/dashboard-agent-context.json.get.ts +22 -4
  22. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +37 -11
  23. package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  24. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +37 -11
  25. package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  26. package/corpus/templates/brain/server/lib/connectors.ts +38 -14
  27. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +37 -11
  28. package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  29. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +37 -11
  30. package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  31. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +37 -11
  32. package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  33. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +37 -11
  34. package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  35. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +37 -11
  36. package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  37. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +37 -11
  38. package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  39. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +37 -11
  40. package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  41. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +37 -11
  42. package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  43. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +37 -11
  44. package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  45. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +37 -11
  46. package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  47. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +37 -11
  48. package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  49. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +37 -11
  50. package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  51. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +37 -11
  52. package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  53. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +13 -0
  54. package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +5 -0
  55. package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +5 -0
  56. package/corpus/templates/slides/app/components/presentation/PresenterView.tsx +5 -0
  57. package/corpus/templates/slides/app/pages/DeckEditor.tsx +3 -0
  58. package/corpus/templates/slides/app/pages/Presentation.tsx +3 -0
  59. package/corpus/templates/slides/app/pages/SharedPresentation.tsx +5 -0
  60. package/corpus/templates/slides/app/routes/slide.tsx +10 -5
  61. package/corpus/templates/slides/changelog/2026-08-07-slide-previews-and-present-now-keep-deck-colors-consistent.md +6 -0
  62. package/corpus/templates/slides/server/db/schema.ts +1 -0
  63. package/corpus/templates/slides/server/handlers/share.ts +51 -3
  64. package/corpus/templates/slides/server/plugins/db.ts +5 -0
  65. package/corpus/templates/slides/shared/api.ts +2 -0
  66. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +37 -11
  67. package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  68. package/dist/cli/code-agent-executor.js +8 -3
  69. package/dist/client/ConnectBuilderCard.d.ts +7 -7
  70. package/dist/client/ConnectBuilderCard.js +45 -20
  71. package/dist/collab/struct-routes.d.ts +1 -1
  72. package/dist/config.d.ts +9 -2
  73. package/dist/config.js +38 -2
  74. package/dist/db/client.d.ts +13 -1
  75. package/dist/db/client.js +76 -2
  76. package/dist/db/create-get-db.js +2 -2
  77. package/dist/deploy/build.js +5 -1
  78. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  79. package/dist/notifications/routes.d.ts +2 -2
  80. package/dist/observability/routes.d.ts +1 -1
  81. package/dist/progress/routes.d.ts +1 -1
  82. package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
  83. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  84. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  85. package/dist/resources/handlers.d.ts +1 -1
  86. package/dist/scripts/docs/search.js +3 -2
  87. package/dist/server/agent-chat/prompt-resources.js +4 -3
  88. package/dist/server/agents-bundle.d.ts +20 -3
  89. package/dist/server/agents-bundle.js +57 -30
  90. package/dist/server/better-auth-instance.js +2 -2
  91. package/dist/shared/runtime-config.js +1 -1
  92. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +37 -11
  93. package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  94. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +37 -11
  95. package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  96. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +37 -11
  97. package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  98. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +37 -11
  99. package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  100. package/dist/vite/agent-native-config-loader.d.ts +10 -0
  101. package/dist/vite/agent-native-config-loader.js +56 -0
  102. package/dist/vite/agents-bundle-plugin.d.ts +5 -1
  103. package/dist/vite/agents-bundle-plugin.js +29 -6
  104. package/dist/vite/client.d.ts +4 -2
  105. package/dist/vite/client.js +4 -49
  106. package/dist/vite/index.d.ts +2 -2
  107. package/dist/vite/index.js +1 -1
  108. package/docs/content/agent-native-config.mdx +43 -17
  109. package/docs/content/environment-variables.mdx +1 -1
  110. package/package.json +3 -3
  111. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +37 -11
  112. package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  113. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +37 -11
  114. package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  115. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +37 -11
  116. package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
  117. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +37 -11
  118. package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
@@ -82,6 +82,8 @@ export interface SharedDeckResponse {
82
82
  title: string;
83
83
  slides: SharedDeckSlide[];
84
84
  aspectRatio?: import("./aspect-ratios").AspectRatio;
85
+ /** Resolved at share creation so public links keep the deck's styling. */
86
+ designSystem?: DesignSystemData;
85
87
  }
86
88
 
87
89
  export type SharedSlideTransition =
@@ -4,7 +4,7 @@ description: >-
4
4
  Turn visible project context, a proven thread, skill, or workflow into a
5
5
  runnable Agent-Native app with simple buttons, visible agent steps, preview,
6
6
  and deployment handoff. Use when a user invokes `/turn-into-app` or asks to
7
- make a workflow into an app.
7
+ make a workflow into an app, including from Claude or ChatGPT on the web.
8
8
  user-invocable: true
9
9
  scope: both
10
10
  metadata:
@@ -13,9 +13,32 @@ metadata:
13
13
 
14
14
  # Turn Into App
15
15
 
16
+ ## Host execution boundary
17
+
18
+ The build location depends on the host. Treat this as a hard routing rule:
19
+
20
+ - In Claude Web, ChatGPT Web, or a Claude/ChatGPT Project on the web, you are
21
+ the source analyst and handoff orchestrator. You must not build the app in
22
+ the host sandbox. Do not run `npm`, `pnpm`, `npx`, `agent-native create`, or
23
+ `add-app`; do not edit files, create artifacts, or start a local dev server.
24
+ After writing the bounded source brief, call the connected Dispatch action
25
+ `start-workspace-app-creation`. Pass the brief and repeatable workflow in
26
+ `prompt`, plus the inferred `appId`, `description`, `template`, and selected
27
+ `resourceIds` when available. This is the Builder handoff.
28
+ - Do not substitute the generic `create_workspace_app` MCP tool in an online
29
+ host. That tool is a local workspace scaffolder, not the Builder handoff.
30
+ - If `start-workspace-app-creation` is not available or Dispatch is not
31
+ authenticated, stop with the connector setup needed. Do not fall back to a
32
+ local build or claim that the app exists.
33
+ - In Claude Code, Codex Code, or another local code-agent runtime with a target
34
+ workspace, follow the local implementation steps below. The local agent may
35
+ scaffold, edit, run, and verify the app there.
36
+
16
37
  ## Default behavior
17
38
 
18
- This is an end-to-end build skill, not a request for an app proposal.
39
+ For a local code-agent runtime this is an end-to-end build skill, not a request
40
+ for an app proposal. For an online host, the end-to-end result is a verified
41
+ Builder handoff and the resulting workspace app, not code written in the host.
19
42
 
20
43
  - With no argument, choose the source in this order: visible project context,
21
44
  then the current thread. A fresh Claude or ChatGPT Project is a valid source
@@ -47,9 +70,12 @@ private web access, invent an importer, add fake OAuth, or scrape a logged-in
47
70
  page. If the needed context is not visible, ask for an export, transcript, or
48
71
  attachment and treat that artifact as imported source material.
49
72
 
50
- Deliver a fresh app in a new directory, implement the repeatable workflow with
51
- buttons and agent handoffs, start its dev server, verify the main path, and
52
- continue through build/deployment handoff. Do not stop at a plan.
73
+ For local code-agent runtimes, deliver a fresh app in a new directory,
74
+ implement the repeatable workflow with buttons and agent handoffs, start its dev
75
+ server, verify the main path, and continue through build/deployment handoff. Do
76
+ not stop at a plan. For online hosts, call Dispatch first after the source brief,
77
+ then report the returned Builder branch/path and verify the workspace app through
78
+ Dispatch when it becomes available.
53
79
 
54
80
  ## Fresh project context mode
55
81
 
@@ -190,12 +216,12 @@ Do not use `create` for an existing workspace; it scaffolds a new standalone
190
216
  workspace rather than adding an app to the current one.
191
217
 
192
218
  When the source came from a fresh external Project and the target is a Builder
193
- workspace, prefer the available Dispatch MCP workspace handoff after writing
194
- the source brief. Call `start-workspace-app-creation` with a concise prompt,
195
- the inferred app id, and the brief's repeatable workflow. Pass selected
196
- workspace resource IDs when they are available, rather than pasting entire
197
- knowledge files. Continue from the returned workspace path or Builder handoff
198
- and report the actual verification result.
219
+ workspace, the online host path is mandatory: after writing the source brief,
220
+ call `start-workspace-app-creation` with a concise prompt, the inferred app id,
221
+ and the brief's repeatable workflow. Pass selected workspace resource IDs when
222
+ they are available, rather than pasting entire knowledge files. Continue from
223
+ the returned workspace path or Builder branch handoff and report the actual
224
+ verification result. Do not run the local scaffold commands in this host mode.
199
225
 
200
226
  Use a first-party template only when it materially fits the workflow. Keep the
201
227
  new app independent from the source thread's working tree unless the user
@@ -51,13 +51,24 @@ also place the skill instructions or this reference in the Project
51
51
  instructions/knowledge files. Then add and authenticate the Dispatch MCP
52
52
  connector from the packaged `adapters/chatgpt-mcp/connector.json`.
53
53
 
54
+ For Claude Web, ChatGPT Web, and their web Projects, the host is an
55
+ orchestrator, not the build environment. After forming the source brief, call
56
+ the Dispatch `start-workspace-app-creation` action so Builder creates the app
57
+ in the connected workspace. Do not use the host's code interpreter, shell,
58
+ artifact editor, `create_workspace_app`, or local `pnpm`/`npm` commands. If the
59
+ handoff action is unavailable, stop and ask the user to authenticate Dispatch;
60
+ do not fall back to a local sandbox build. Claude Code and Codex Code are the
61
+ local-agent exception and may follow the implementation steps in the main
62
+ skill.
63
+
54
64
  In a new Project chat, say:
55
65
 
56
66
  ```text
57
67
  Turn this project into an app. Use the visible Project instructions,
58
68
  knowledge files, and any selected successful runs as the source. Create the
59
- app in the connected Agent-Native workspace, keep the source brief bounded,
60
- and report the real path and verification result.
69
+ app in the connected Agent-Native workspace through Dispatch and Builder, keep
70
+ the source brief bounded, and report the real Builder branch/path and
71
+ verification result. Do not build it in this chat's sandbox.
61
72
  ```
62
73
 
63
74
  If the host does not show the Project instructions or files to the model, stop
@@ -13,6 +13,7 @@ import { buildMergedConfig, McpClientManager, mcpToolsToActionEntries, } from ".
13
13
  import { readAgentsBundleFromFs, generateDevelopmentSkillsPromptBlock, } from "../server/agents-bundle.js";
14
14
  import { getAmbientOrgId, getAmbientUserEmail, runWithRequestContext, } from "../server/request-context.js";
15
15
  import { isReasoningEffort, } from "../shared/reasoning-effort.js";
16
+ import { createAgentNativeConfigContext, loadResolvedAgentNativeConfig, } from "../vite/agent-native-config-loader.js";
16
17
  import { createCodeAgentOutputSmoother } from "./code-agent-output-smoother.js";
17
18
  import { addCodeAgentCommandToAllowlist, appendCodeAgentTranscriptEvent, dequeueCodeAgentFollowUp, getCodeAgentRunRecord, isCodeAgentCommandAllowed, listCodeAgentTranscriptEvents, updateCodeAgentRunRecord, } from "./code-agent-runs.js";
18
19
  const DEFAULT_COMMAND_TIMEOUT_MS = 120_000;
@@ -1295,11 +1296,15 @@ const AGENTS_MD_INLINE_CAP = 16_000;
1295
1296
  */
1296
1297
  /** @internal exported for unit tests */
1297
1298
  export async function buildCodeAgentSystemPrompt(cwd, permissionMode) {
1298
- const bundle = readAgentsBundleFromFs(cwd);
1299
+ const appConfig = await loadResolvedAgentNativeConfig(cwd, createAgentNativeConfigContext("serve", "development"));
1300
+ const bundle = readAgentsBundleFromFs(cwd, null, {
1301
+ instructions: appConfig.instructions,
1302
+ });
1299
1303
  // If the bundle has no AGENTS.md, try CLAUDE.md as a fallback — many repos
1300
1304
  // use that name for agent instructions (e.g. Claude Code projects).
1301
- let agentsMdContent = bundle.agentsMd;
1302
- if (!agentsMdContent.trim()) {
1305
+ let agentsMdContent = bundle.developmentAgentsMd ?? bundle.agentsMd;
1306
+ if (!agentsMdContent.trim() &&
1307
+ appConfig.instructions?.development === undefined) {
1303
1308
  try {
1304
1309
  const fs = await import("node:fs");
1305
1310
  const path = await import("node:path");
@@ -3,19 +3,19 @@ export interface ConnectBuilderCardProps {
3
3
  configured: boolean;
4
4
  /**
5
5
  * True when the server has a Builder branch project configured for this
6
- * request. When false, the card shows a waitlist CTA instead of a Send
7
- * button — the /builder/run endpoint would 403 anyway.
6
+ * request. When false, the card shows a hosted waitlist CTA or a local code
7
+ * external coding-agent handoff instead of a Send button.
8
8
  */
9
9
  builderEnabled?: boolean;
10
10
  connectUrl: string;
11
11
  orgName?: string | null;
12
- /** The user's feature/change request, forwarded to Builder's cloud agent
13
- * when they click Send. Empty for generic "connect Builder" prompts. */
12
+ /** The user's feature/change request, forwarded to the selected coding
13
+ * agent when they click Send. Empty for generic "connect Builder" prompts. */
14
14
  prompt?: string;
15
15
  }
16
16
  /**
17
- * Rich inline card rendered for the `connect-builder` tool call. Shows a
18
- * prominent Connect button that opens the Builder CLI auth flow and polls
19
- * /_agent-native/builder/status until credentials land.
17
+ * Rich inline card rendered for the `connect-builder` tool call. Shows the
18
+ * Builder handoff when available, or routes local development requests to the
19
+ * external coding agent.
20
20
  */
21
21
  export declare function ConnectBuilderCard({ configured: initialConfigured, builderEnabled: initialBuilderEnabled, connectUrl: initialConnectUrl, orgName: initialOrgName, prompt, }: ConnectBuilderCardProps): React.JSX.Element;
@@ -1,27 +1,27 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { IconExternalLink, IconLoader2 } from "@tabler/icons-react";
2
+ import { IconCheck, IconCode, IconCopy, IconExternalLink, IconLoader2, } from "@tabler/icons-react";
3
3
  import { useCallback, useEffect, useRef, useState } from "react";
4
4
  import { withBuilderUtmTrackingParams } from "../shared/builder-link-tracking.js";
5
5
  import { agentNativePath } from "./api-path.js";
6
6
  import { BuilderBMark } from "./builder-mark.js";
7
+ import { writeClipboardText } from "./clipboard.js";
7
8
  import { getCallbackOrigin } from "./frame.js";
8
9
  import { useBuilderConnectFlow } from "./settings/useBuilderStatus.js";
9
10
  import { cn } from "./utils.js";
10
11
  const DESKTOP_DOWNLOAD_URL = "https://www.agent-native.com/download";
11
12
  const CODE_CHANGE_FALLBACK_DETAIL = "Edit locally or use Builder.io to edit this code in the cloud and continue customizing the app any way you like.";
12
13
  const CODE_CHANGE_FALLBACK_TEXT = `This requires a code change. ${CODE_CHANGE_FALLBACK_DETAIL}`;
13
- function isLocalBrowserOutsideDesktop() {
14
- if (typeof window === "undefined" || typeof navigator === "undefined") {
14
+ function isLocalDevelopment() {
15
+ if (typeof window === "undefined") {
15
16
  return false;
16
17
  }
17
18
  const hostname = window.location.hostname;
18
- const local = hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
19
- return local && !/AgentNativeDesktop/i.test(navigator.userAgent || "");
19
+ return (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1");
20
20
  }
21
21
  /**
22
- * Rich inline card rendered for the `connect-builder` tool call. Shows a
23
- * prominent Connect button that opens the Builder CLI auth flow and polls
24
- * /_agent-native/builder/status until credentials land.
22
+ * Rich inline card rendered for the `connect-builder` tool call. Shows the
23
+ * Builder handoff when available, or routes local development requests to the
24
+ * external coding agent.
25
25
  */
26
26
  export function ConnectBuilderCard({ configured: initialConfigured, builderEnabled: initialBuilderEnabled = true, connectUrl: initialConnectUrl, orgName: initialOrgName, prompt = "", }) {
27
27
  // The connect-poll state machine is shared — the tool-call result is
@@ -46,8 +46,11 @@ export function ConnectBuilderCard({ configured: initialConfigured, builderEnabl
46
46
  const [sending, setSending] = useState(false);
47
47
  const [runResult, setRunResult] = useState(null);
48
48
  const [sendErr, setSendErr] = useState(null);
49
- const [localBrowser, setLocalBrowser] = useState(false);
49
+ const [copyErr, setCopyErr] = useState(null);
50
+ const [promptCopied, setPromptCopied] = useState(false);
51
+ const [localDevelopment] = useState(() => isLocalDevelopment());
50
52
  const mountedRef = useRef(true);
53
+ const copyResetRef = useRef(null);
51
54
  // Tracks whether the user clicked "Connect Builder" *this session*. When
52
55
  // the connect-then-poll round-trip lands `configured=true`, we use this
53
56
  // flag to decide whether to retry the user's pending prompt automatically
@@ -58,9 +61,10 @@ export function ConnectBuilderCard({ configured: initialConfigured, builderEnabl
58
61
  const wasConnectingRef = useRef(false);
59
62
  useEffect(() => {
60
63
  mountedRef.current = true;
61
- setLocalBrowser(isLocalBrowserOutsideDesktop());
62
64
  return () => {
63
65
  mountedRef.current = false;
66
+ if (copyResetRef.current)
67
+ clearTimeout(copyResetRef.current);
64
68
  };
65
69
  }, []);
66
70
  const handleSend = useCallback(async () => {
@@ -127,8 +131,27 @@ export function ConnectBuilderCard({ configured: initialConfigured, builderEnabl
127
131
  setJoiningWaitlist(false);
128
132
  }
129
133
  }, [orgName, prompt]);
130
- // Combine connect-flow errors, send errors, and waitlist errors.
131
- const err = sendErr ?? waitlistErr ?? flow.error;
134
+ const handleCopyPrompt = useCallback(async () => {
135
+ if (!prompt.trim())
136
+ return;
137
+ setCopyErr(null);
138
+ const copied = await writeClipboardText(prompt);
139
+ if (!mountedRef.current)
140
+ return;
141
+ if (!copied) {
142
+ setCopyErr("Couldn't copy the prompt");
143
+ return;
144
+ }
145
+ setPromptCopied(true);
146
+ if (copyResetRef.current)
147
+ clearTimeout(copyResetRef.current);
148
+ copyResetRef.current = setTimeout(() => {
149
+ if (mountedRef.current)
150
+ setPromptCopied(false);
151
+ }, 1600);
152
+ }, [prompt]);
153
+ // Combine connect-flow errors, send errors, waitlist errors, and copy errors.
154
+ const err = sendErr ?? waitlistErr ?? copyErr ?? flow.error;
132
155
  const hasPrompt = prompt.trim().length > 0;
133
156
  const canSend = configured && builderEnabled && hasPrompt;
134
157
  // Auto-send the user's pending prompt the moment connecting finishes
@@ -149,7 +172,8 @@ export function ConnectBuilderCard({ configured: initialConfigured, builderEnabl
149
172
  }, [flow.connecting, canSend, sending, runResult, sendErr, handleSend]);
150
173
  // Branch creation is gated by a server-side project id, which may come
151
174
  // from deployment config or org-scoped secrets.
152
- const showWaitlist = !builderEnabled && hasPrompt;
175
+ const showExternalAgentHandoff = localDevelopment && !builderEnabled && hasPrompt;
176
+ const showWaitlist = !localDevelopment && !builderEnabled && hasPrompt;
153
177
  // Title + subtitle depend on which mode we're in. We compute them up front
154
178
  // so the render tree below stays flat.
155
179
  const connectedCapabilityText = builderEnabled
@@ -161,13 +185,14 @@ export function ConnectBuilderCard({ configured: initialConfigured, builderEnabl
161
185
  title = "Builder is working on it";
162
186
  subtitle = (_jsxs(_Fragment, { children: ["Working on branch", " ", _jsx("span", { className: "font-mono text-foreground", children: runResult.branchName }), ". Click through to watch progress in the Visual Editor."] }));
163
187
  }
188
+ else if (showExternalAgentHandoff) {
189
+ title = "This requires a code change";
190
+ subtitle =
191
+ "Open your coding agent in this project, then paste this request.";
192
+ }
164
193
  else if (showWaitlist) {
165
194
  title = "This requires a code change";
166
- subtitle = waitlistJoined ? (_jsxs(_Fragment, { children: ["You're on the waitlist. ", CODE_CHANGE_FALLBACK_DETAIL, " ", localBrowser
167
- ? "Since this project is already running locally, open it in the desktop app for local coding tools or keep editing from your clone."
168
- : "You can still clone the project locally and use the desktop app for code changes."] })) : (_jsxs(_Fragment, { children: [CODE_CHANGE_FALLBACK_DETAIL, " ", localBrowser
169
- ? "Since this project is already running locally, open it in the desktop app for local coding tools or keep editing from your clone."
170
- : "You can still clone the project locally and use the desktop app for code changes."] }));
195
+ subtitle = waitlistJoined ? (_jsxs(_Fragment, { children: ["You're on the waitlist. ", CODE_CHANGE_FALLBACK_DETAIL, " You can still clone the project locally and use the desktop app for code changes."] })) : (_jsxs(_Fragment, { children: [CODE_CHANGE_FALLBACK_DETAIL, " You can still clone the project locally and use the desktop app for code changes."] }));
171
196
  }
172
197
  else if (canSend) {
173
198
  title = "Send this to Builder";
@@ -181,8 +206,8 @@ export function ConnectBuilderCard({ configured: initialConfigured, builderEnabl
181
206
  title = "Connect Builder.io";
182
207
  subtitle = _jsx(_Fragment, { children: "Builder.io's free tier includes AI credits." });
183
208
  }
184
- return (_jsx("div", { className: cn("my-2 rounded-lg border border-border overflow-hidden"), children: _jsxs("div", { className: "flex items-start gap-3 px-4 py-3.5 bg-gradient-to-br from-teal-500/5 via-transparent to-transparent", children: [_jsx("div", { className: cn("flex h-9 w-9 shrink-0 items-center justify-center rounded-lg", "bg-foreground text-background"), children: runResult ? (_jsx(IconLoader2, { className: "h-5 w-5 animate-spin" })) : (_jsx(BuilderBMark, { className: "h-5 w-5" })) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "flex items-center gap-2 flex-wrap", children: _jsx("span", { className: "text-sm font-semibold text-foreground", children: title }) }), _jsx("div", { className: "mt-0.5 text-xs text-muted-foreground leading-relaxed", children: subtitle }), showWaitlist && (_jsxs("a", { href: DESKTOP_DOWNLOAD_URL, target: "_blank", rel: "noopener noreferrer", className: "mt-2 inline-flex items-center gap-1 text-[11px] font-medium text-muted-foreground no-underline hover:text-foreground", children: ["Download desktop app", _jsx(IconExternalLink, { className: "h-3 w-3" })] })), err && _jsx("div", { className: "mt-2 text-xs text-destructive", children: err }), _jsx("div", { className: "mt-3", children: runResult ? (_jsxs("a", { href: withBuilderUtmTrackingParams(runResult.url, {
209
+ return (_jsx("div", { className: cn("my-2 rounded-lg border border-border overflow-hidden"), children: _jsxs("div", { className: "flex items-start gap-3 px-4 py-3.5 bg-gradient-to-br from-teal-500/5 via-transparent to-transparent", children: [_jsx("div", { className: cn("flex h-9 w-9 shrink-0 items-center justify-center rounded-lg", "bg-foreground text-background"), children: runResult ? (_jsx(IconLoader2, { className: "h-5 w-5 animate-spin" })) : showExternalAgentHandoff ? (_jsx(IconCode, { className: "h-5 w-5" })) : (_jsx(BuilderBMark, { className: "h-5 w-5" })) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "flex items-center gap-2 flex-wrap", children: _jsx("span", { className: "text-sm font-semibold text-foreground", children: title }) }), _jsx("div", { className: "mt-0.5 text-xs text-muted-foreground leading-relaxed", children: subtitle }), showWaitlist && (_jsxs("a", { href: DESKTOP_DOWNLOAD_URL, target: "_blank", rel: "noopener noreferrer", className: "mt-2 inline-flex items-center gap-1 text-[11px] font-medium text-muted-foreground no-underline hover:text-foreground", children: ["Download desktop app", _jsx(IconExternalLink, { className: "h-3 w-3" })] })), err && _jsx("div", { className: "mt-2 text-xs text-destructive", children: err }), _jsx("div", { className: "mt-3", children: runResult ? (_jsxs("a", { href: withBuilderUtmTrackingParams(runResult.url, {
185
210
  campaign: "product",
186
211
  content: "connect_builder_card_branch",
187
- }), target: "_blank", rel: "noopener noreferrer", className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors", "bg-foreground text-background hover:bg-foreground/90"), children: ["Open branch in Builder", _jsx(IconExternalLink, { className: "h-3.5 w-3.5" })] })) : canSend ? (_jsx("button", { type: "button", onClick: handleSend, disabled: sending, className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors", "bg-foreground text-background hover:bg-foreground/90", sending && "opacity-70 cursor-wait"), children: sending ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), "Sending to Builder\u2026"] })) : (_jsx(_Fragment, { children: "Send to Builder" })) })) : showWaitlist && !waitlistJoined ? (_jsx("button", { type: "button", onClick: handleJoinWaitlist, disabled: joiningWaitlist, className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors", "bg-foreground text-background hover:bg-foreground/90", joiningWaitlist && "opacity-70 cursor-wait"), children: joiningWaitlist ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), "Joining\u2026"] })) : (_jsx(_Fragment, { children: "Join the waitlist" })) })) : !configured ? (_jsx("button", { type: "button", onClick: () => flow.start(), disabled: connecting, className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors", "bg-foreground text-background hover:bg-foreground/90", connecting && "opacity-70 cursor-wait"), children: connecting ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), "Waiting for Builder\u2026"] })) : ("Connect Builder") })) : null })] })] }) }));
212
+ }), target: "_blank", rel: "noopener noreferrer", className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors", "bg-foreground text-background hover:bg-foreground/90"), children: ["Open branch in Builder", _jsx(IconExternalLink, { className: "h-3.5 w-3.5" })] })) : canSend ? (_jsx("button", { type: "button", onClick: handleSend, disabled: sending, className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors", "bg-foreground text-background hover:bg-foreground/90", sending && "opacity-70 cursor-wait"), children: sending ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), "Sending to Builder\u2026"] })) : (_jsx(_Fragment, { children: "Send to Builder" })) })) : showExternalAgentHandoff ? (_jsx("button", { type: "button", onClick: () => void handleCopyPrompt(), className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors", "bg-foreground text-background hover:bg-foreground/90"), children: promptCopied ? (_jsxs(_Fragment, { children: [_jsx(IconCheck, { className: "h-3.5 w-3.5" }), "Prompt copied"] })) : (_jsxs(_Fragment, { children: [_jsx(IconCopy, { className: "h-3.5 w-3.5" }), "Copy prompt"] })) })) : showWaitlist && !waitlistJoined ? (_jsx("button", { type: "button", onClick: handleJoinWaitlist, disabled: joiningWaitlist, className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors", "bg-foreground text-background hover:bg-foreground/90", joiningWaitlist && "opacity-70 cursor-wait"), children: joiningWaitlist ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), "Joining\u2026"] })) : (_jsx(_Fragment, { children: "Join the waitlist" })) })) : !configured ? (_jsx("button", { type: "button", onClick: () => flow.start(), disabled: connecting, className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors", "bg-foreground text-background hover:bg-foreground/90", connecting && "opacity-70 cursor-wait"), children: connecting ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), "Waiting for Builder\u2026"] })) : ("Connect Builder") })) : null })] })] }) }));
188
213
  }
@@ -13,8 +13,8 @@
13
13
  * Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
14
14
  */
15
15
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- ok?: undefined;
17
16
  error: string;
17
+ ok?: undefined;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
package/dist/config.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Public, non-secret configuration for an Agent-Native app.
3
3
  *
4
4
  * This module is intentionally free of Node and framework imports so it can be
5
- * used from a typed `agent-native.ts` file and from browser code after Vite
5
+ * used from a typed `agent-native.config.ts` file and from browser code after Vite
6
6
  * serializes the resolved config into the client bundle.
7
7
  */
8
8
  export declare const AGENT_NATIVE_CONFIG_VERSION: 1;
@@ -42,11 +42,18 @@ export interface AgentNativeDiagnosticsConfig {
42
42
  /** Fail a production Vite build when runtime configuration has issues. */
43
43
  failOnBuild?: boolean;
44
44
  }
45
+ export interface AgentNativeInstructionsConfig {
46
+ /** Relative Markdown file loaded by the in-app runtime agent. */
47
+ runtime?: string;
48
+ /** Relative Markdown file loaded by development/coding agents. */
49
+ development?: string;
50
+ }
45
51
  export interface AgentNativeConfig {
46
52
  version?: typeof AGENT_NATIVE_CONFIG_VERSION;
47
53
  onboarding?: AgentNativeOnboardingConfig;
48
54
  runtime?: AgentNativeRuntimeConfig;
49
55
  diagnostics?: AgentNativeDiagnosticsConfig;
56
+ instructions?: AgentNativeInstructionsConfig;
50
57
  }
51
58
  export interface AgentNativeConfigContext {
52
59
  command: "serve" | "build";
@@ -57,7 +64,7 @@ export interface AgentNativeConfigContext {
57
64
  export type AgentNativeConfigFactory = (context: AgentNativeConfigContext) => AgentNativeConfig;
58
65
  export type AgentNativeConfigInput = AgentNativeConfig | AgentNativeConfigFactory;
59
66
  /**
60
- * Type-safe authoring helper for `agent-native.ts`.
67
+ * Type-safe authoring helper for `agent-native.config.ts`.
61
68
  *
62
69
  * Like Next's typed config file, this is deliberately identity-like: the
63
70
  * framework evaluates the exported object or factory in the Vite config
package/dist/config.js CHANGED
@@ -2,12 +2,12 @@
2
2
  * Public, non-secret configuration for an Agent-Native app.
3
3
  *
4
4
  * This module is intentionally free of Node and framework imports so it can be
5
- * used from a typed `agent-native.ts` file and from browser code after Vite
5
+ * used from a typed `agent-native.config.ts` file and from browser code after Vite
6
6
  * serializes the resolved config into the client bundle.
7
7
  */
8
8
  export const AGENT_NATIVE_CONFIG_VERSION = 1;
9
9
  /**
10
- * Type-safe authoring helper for `agent-native.ts`.
10
+ * Type-safe authoring helper for `agent-native.config.ts`.
11
11
  *
12
12
  * Like Next's typed config file, this is deliberately identity-like: the
13
13
  * framework evaluates the exported object or factory in the Vite config
@@ -27,6 +27,7 @@ export function normalizeAgentNativeConfig(input, source = "agent-native config"
27
27
  const onboardingValue = input.onboarding;
28
28
  const runtimeValue = input.runtime;
29
29
  const diagnosticsValue = input.diagnostics;
30
+ const instructionsValue = input.instructions;
30
31
  const normalized = {
31
32
  ...(input.version === undefined
32
33
  ? {}
@@ -45,6 +46,9 @@ export function normalizeAgentNativeConfig(input, source = "agent-native config"
45
46
  if (diagnosticsValue !== undefined) {
46
47
  normalized.diagnostics = normalizeDiagnosticsConfig(diagnosticsValue, `${source}.diagnostics`);
47
48
  }
49
+ if (instructionsValue !== undefined) {
50
+ normalized.instructions = normalizeInstructionsConfig(instructionsValue, `${source}.instructions`);
51
+ }
48
52
  return normalized;
49
53
  }
50
54
  export function mergeAgentNativeConfigs(base, override) {
@@ -91,6 +95,12 @@ export function mergeAgentNativeConfigs(base, override) {
91
95
  ...override.diagnostics,
92
96
  }
93
97
  : undefined,
98
+ instructions: base.instructions || override.instructions
99
+ ? {
100
+ ...base.instructions,
101
+ ...override.instructions,
102
+ }
103
+ : undefined,
94
104
  };
95
105
  }
96
106
  export function resolveAgentNativeConfig(input, context) {
@@ -175,6 +185,32 @@ function normalizeDiagnosticsConfig(value, source) {
175
185
  ? {}
176
186
  : { failOnBuild: value.failOnBuild };
177
187
  }
188
+ function normalizeInstructionsConfig(value, source) {
189
+ if (!isRecord(value)) {
190
+ throw new Error(`${source} must be an object`);
191
+ }
192
+ const result = {};
193
+ for (const audience of ["runtime", "development"]) {
194
+ const pathValue = value[audience];
195
+ if (pathValue === undefined)
196
+ continue;
197
+ if (typeof pathValue !== "string") {
198
+ throw new Error(`${source}.${audience} must be a relative file path`);
199
+ }
200
+ result[audience] = normalizeRelativeFilePath(pathValue, `${source}.${audience}`);
201
+ }
202
+ return result;
203
+ }
204
+ function normalizeRelativeFilePath(value, source) {
205
+ const normalized = value.trim().replaceAll("\\", "/");
206
+ if (!normalized ||
207
+ normalized.startsWith("/") ||
208
+ /^[A-Za-z]:\//.test(normalized) ||
209
+ normalized.split("/").some((segment) => segment === "..")) {
210
+ throw new Error(`${source} must be a non-empty relative file path inside the app root`);
211
+ }
212
+ return normalized;
213
+ }
178
214
  function normalizeRequiredEnvKeys(value, source) {
179
215
  if (value === undefined)
180
216
  return undefined;
@@ -227,7 +227,19 @@ export declare function isBackgroundFunctionPoolContext(): boolean;
227
227
  * actual context.
228
228
  */
229
229
  export declare function describeDbError(err: unknown): string;
230
- export declare function attachNeonPoolErrorLogger(pool: unknown, label?: string): void;
230
+ /**
231
+ * Thrown INSTEAD of attempting, while an endpoint is in cooldown.
232
+ *
233
+ * The refused attempt's error is described in the message and deliberately NOT
234
+ * attached as `cause`: isConnectionError() walks `cause.code`/`cause.message`,
235
+ * so a cause would reclassify this as retryable and retryOnConnectionError
236
+ * would drive the storm straight back.
237
+ */
238
+ export declare class DbConnectCooldownError extends Error {
239
+ code: string;
240
+ constructor(remainingMs: number, refusedBy: string);
241
+ }
242
+ export declare function guardNeonPool(pool: unknown, url: string, label?: string): void;
231
243
  interface ClosablePool {
232
244
  end(): Promise<unknown>;
233
245
  }
package/dist/db/client.js CHANGED
@@ -613,6 +613,9 @@ export function isTransientDatabaseError(err) {
613
613
  const error = err;
614
614
  const code = String(error?.code ?? error?.cause?.code ?? "");
615
615
  if (code === "ECHECKOUTTIMEOUT" ||
616
+ // Shed load during a connect cooldown is transient by construction — the
617
+ // endpoint refused, we chose not to re-ask yet. Surfaces as 503, not 500.
618
+ code === "DB_CONNECT_COOLDOWN" ||
616
619
  code === "EMAXCONN" ||
617
620
  code === "53300" ||
618
621
  code === "57014" ||
@@ -960,7 +963,77 @@ export function describeDbError(err) {
960
963
  }
961
964
  return String(err);
962
965
  }
963
- export function attachNeonPoolErrorLogger(pool, label = "db/neon") {
966
+ /**
967
+ * How long one endpoint stops ATTEMPTING to connect after an attempt failed.
968
+ * Jittered so concurrent function instances do not re-probe in lockstep.
969
+ */
970
+ function connectCooldownMs() {
971
+ const raw = Number(process.env.DB_CONNECT_COOLDOWN_MS);
972
+ const base = Number.isFinite(raw) && raw > 0 ? raw : 2_000;
973
+ return Math.round(base * (0.5 + Math.random()));
974
+ }
975
+ /**
976
+ * Thrown INSTEAD of attempting, while an endpoint is in cooldown.
977
+ *
978
+ * The refused attempt's error is described in the message and deliberately NOT
979
+ * attached as `cause`: isConnectionError() walks `cause.code`/`cause.message`,
980
+ * so a cause would reclassify this as retryable and retryOnConnectionError
981
+ * would drive the storm straight back.
982
+ */
983
+ export class DbConnectCooldownError extends Error {
984
+ code = "DB_CONNECT_COOLDOWN";
985
+ constructor(remainingMs, refusedBy) {
986
+ super(`Database is refusing connection attempts; not attempting again for ${remainingMs}ms. Last failure: ${refusedBy}`);
987
+ this.name = "DbConnectCooldownError";
988
+ }
989
+ }
990
+ const connectCooldowns = new Map();
991
+ /**
992
+ * Neon rejects a connection ATTEMPT, not a connection: "Failed to acquire
993
+ * permit to connect to the database. Too many database connection attempts are
994
+ * currently ongoing." A failed acquire leaves the pool with zero idle clients,
995
+ * so the next execute() calls connect() again — and retryOnConnectionError
996
+ * backs off only 100ms. The process answers a refusal by manufacturing the next
997
+ * attempt, which is what keeps the refusal true. Production sat in this loop
998
+ * until the compute was restarted by hand.
999
+ *
1000
+ * Hold a short cooldown per endpoint so a refused attempt cannot produce the
1001
+ * next one. Checking out an ALREADY-IDLE client is not an attempt and passes
1002
+ * through, so a cooldown degrades throughput instead of taking the process
1003
+ * offline.
1004
+ */
1005
+ function gateNeonConnect(pool, url, label) {
1006
+ const connect = pool.connect;
1007
+ if (typeof connect !== "function")
1008
+ return;
1009
+ const gated = function gatedConnect(...args) {
1010
+ const idle = typeof pool.idleCount === "number" ? pool.idleCount : 0;
1011
+ const gate = connectCooldowns.get(url);
1012
+ if (idle === 0 && gate && Date.now() < gate.until) {
1013
+ return Promise.reject(new DbConnectCooldownError(gate.until - Date.now(), gate.refusedBy));
1014
+ }
1015
+ return Promise.resolve(connect.apply(this, args)).then((client) => {
1016
+ connectCooldowns.delete(url);
1017
+ return client;
1018
+ }, (err) => {
1019
+ const refusedBy = describeDbError(err);
1020
+ const ms = connectCooldownMs();
1021
+ // One line per cooldown window, not per shed request.
1022
+ if (!gate || Date.now() >= gate.until) {
1023
+ console.warn(`[${label}] connection attempt refused; pausing attempts ${ms}ms:`, refusedBy);
1024
+ }
1025
+ connectCooldowns.set(url, { until: Date.now() + ms, refusedBy });
1026
+ throw err;
1027
+ });
1028
+ };
1029
+ // Carry the wrapped function's own properties onto the wrapper. A pool's
1030
+ // `connect` may be instrumented — metrics, tracing, a test spy — and
1031
+ // replacing it with a bare closure would silently drop that instrumentation
1032
+ // along with any assertions built on it.
1033
+ Object.assign(gated, connect);
1034
+ pool.connect = gated;
1035
+ }
1036
+ export function guardNeonPool(pool, url, label = "db/neon") {
964
1037
  if (!pool || typeof pool !== "object")
965
1038
  return;
966
1039
  if (loggedNeonPools.has(pool))
@@ -969,6 +1042,7 @@ export function attachNeonPoolErrorLogger(pool, label = "db/neon") {
969
1042
  if (typeof withEvents.on !== "function")
970
1043
  return;
971
1044
  loggedNeonPools.add(pool);
1045
+ gateNeonConnect(pool, url, label);
972
1046
  withEvents.on("error", (err) => {
973
1047
  console.warn(`[${label}] pool error (will reconnect on next query):`, describeDbError(err));
974
1048
  });
@@ -1177,7 +1251,7 @@ async function createDbExecInternal(config = {}, trackSingletonResources = false
1177
1251
  const pool = trackSingletonResources
1178
1252
  ? sharedDbPool("neon", url, makePool)
1179
1253
  : makePool();
1180
- attachNeonPoolErrorLogger(pool);
1254
+ guardNeonPool(pool, url);
1181
1255
  const httpSql = bgHttp ? neon(url, { fullResults: true }) : null;
1182
1256
  async function queryNeonClient(client, sql, timeoutOverrideMs) {
1183
1257
  const { rawSql, args } = sqlAndArgs(sql);
@@ -1,6 +1,6 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { drizzle as drizzleD1 } from "drizzle-orm/d1";
3
- import { getDialect, getCloudflareD1Binding, getDatabaseUrl, getDatabaseAuthToken, isLocalSqliteUrl, isPgliteUrl, isConnectionError, getPgliteClient, loadPgliteDrizzle, prepareLocalSqliteUrl, sqliteFilenameFromUrl, pgPoolOptions, neonPoolOptions, attachNeonPoolErrorLogger, withDbTimeout, retryOnConnectionError, dbOpTimeoutMs, sharedDbPool, onSharedDbPoolsClosed, onSharedDbPoolReplaced, } from "./client.js";
3
+ import { getDialect, getCloudflareD1Binding, getDatabaseUrl, getDatabaseAuthToken, isLocalSqliteUrl, isPgliteUrl, isConnectionError, getPgliteClient, loadPgliteDrizzle, prepareLocalSqliteUrl, sqliteFilenameFromUrl, pgPoolOptions, neonPoolOptions, guardNeonPool, withDbTimeout, retryOnConnectionError, dbOpTimeoutMs, sharedDbPool, onSharedDbPoolsClosed, onSharedDbPoolReplaced, } from "./client.js";
4
4
  // Lazy driver loaders — cached promises so dynamic import only runs once.
5
5
  let _pgDrizzle;
6
6
  function getPgDrizzle() {
@@ -408,7 +408,7 @@ export function createGetDb(schema) {
408
408
  // schema module. See `sharedDbPool` in client.ts.
409
409
  resetOnPoolClose("neon", url);
410
410
  const rawPool = sharedDbPool("neon", url, () => new Pool({ connectionString: url, ...neonPoolOptions() }));
411
- attachNeonPoolErrorLogger(rawPool);
411
+ guardNeonPool(rawPool, url);
412
412
  // Wrap the pool with the resilience layer so Drizzle queries get the
413
413
  // same withDbTimeout + retryOnConnectionError protection as the raw
414
414
  // DbExec path in client.ts. Reads retry freely; writes only retry on
@@ -27,6 +27,7 @@ import { DEFAULT_SPECULATION_RULES_PATH, resolveSsrCacheHeaders, } from "../shar
27
27
  import { mcpEmbedStaticAssetRouteRules } from "../shared/mcp-embed-headers.js";
28
28
  import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_CACHE_BUSTER, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, } from "../shared/social-meta.js";
29
29
  import { generateActionRegistryForProject } from "../vite/action-types-plugin.js";
30
+ import { createAgentNativeConfigContext, loadResolvedAgentNativeConfig, } from "../vite/agent-native-config-loader.js";
30
31
  import { cloneServerBundleForFunction, copyDir } from "./function-bundle.js";
31
32
  import { collectImmutableAssetPaths, IMMUTABLE_ASSET_CACHE_CONTROL, IMMUTABLE_ASSET_CACHE_HEADERS, prefixAssetPath, } from "./immutable-assets.js";
32
33
  import { discoverApiRoutes, discoverPlugins, discoverActionFiles, getMissingDefaultPlugins, DEFAULT_PLUGIN_REGISTRY, } from "./route-discovery.js";
@@ -3493,6 +3494,7 @@ async function buildWithNitro() {
3493
3494
  // own virtual module registration. Both paths reuse `readAgentsBundleFromFs`
3494
3495
  // from `server/agents-bundle.ts` to guarantee identical content.
3495
3496
  const { readAgentsBundleFromFs } = await import("../server/agents-bundle.js");
3497
+ const nitroAgentConfig = await loadResolvedAgentNativeConfig(cwd, createAgentNativeConfigContext("build", process.env.NODE_ENV === "development" ? "development" : "production"));
3496
3498
  // Resolve the workspace core (if present) up front so the bundle embeds
3497
3499
  // enterprise-wide AGENTS.md + skills alongside the template's.
3498
3500
  const nitroWorkspaceCore = await getWorkspaceCoreExports(cwd);
@@ -3504,7 +3506,9 @@ async function buildWithNitro() {
3504
3506
  }
3505
3507
  : null;
3506
3508
  const agentsBundleModuleSource = () => {
3507
- const bundle = readAgentsBundleFromFs(cwd, nitroWorkspaceSource);
3509
+ const bundle = readAgentsBundleFromFs(cwd, nitroWorkspaceSource, {
3510
+ instructions: nitroAgentConfig.instructions,
3511
+ });
3508
3512
  return `// AUTO-GENERATED by @agent-native/core deploy build (Nitro virtual)
3509
3513
  // Contains the inlined AGENTS.md + .agents/skills/ content from the template,
3510
3514
  // merged with the workspace core's AGENTS.md + skills/ when present.
@@ -17,11 +17,11 @@ declare const _default: import("../../action.js").ActionDefinition<{
17
17
  id?: undefined;
18
18
  provider?: undefined;
19
19
  } | {
20
- error?: undefined;
21
20
  configured?: undefined;
22
21
  connectPath?: undefined;
23
22
  url: string;
24
23
  id: string;
25
24
  provider: string;
25
+ error?: undefined;
26
26
  }>;
27
27
  export default _default;