@agent-native/core 0.145.8 → 0.146.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 (155) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +41 -11
  3. package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  4. package/corpus/templates/analytics/actions/compose-dashboard.ts +2 -27
  5. package/corpus/templates/analytics/actions/get-sql-dashboard.ts +18 -3
  6. package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +75 -24
  7. package/corpus/templates/analytics/actions/mutate-dashboard.ts +16 -24
  8. package/corpus/templates/analytics/actions/rename-dashboard.ts +2 -24
  9. package/corpus/templates/analytics/actions/reorder-dashboard-panels.ts +2 -24
  10. package/corpus/templates/analytics/actions/restore-dashboard-revision.ts +2 -25
  11. package/corpus/templates/analytics/actions/update-dashboard.ts +4 -32
  12. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +1 -40
  13. package/corpus/templates/analytics/changelog/2026-08-07-analytics-migrations-now-use-bounded-pressure-aware-backgrou.md +6 -0
  14. package/corpus/templates/analytics/changelog/2026-08-07-language-selection-now-lives-in-settings-instead-of-the-comm.md +6 -0
  15. package/corpus/templates/analytics/changelog/2026-08-07-template-activity-charts-now-show-only-core-agent-native-app.md +6 -0
  16. package/corpus/templates/analytics/netlify.toml +7 -0
  17. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +110 -0
  18. package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +450 -0
  19. package/corpus/templates/analytics/server/jobs/analytics-rollup-backfill.ts +2 -2
  20. package/corpus/templates/analytics/server/lib/analytics-rollup-lock.ts +4 -5
  21. package/corpus/templates/analytics/server/lib/dashboard-collab-sync.ts +77 -0
  22. package/corpus/templates/analytics/server/lib/demo-dashboards.ts +2 -23
  23. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +10 -4
  24. package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +4 -11
  25. package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +2 -5
  26. package/corpus/templates/analytics/server/plugins/db.ts +42 -0
  27. package/corpus/templates/analytics/server/routes/api/analytics-bigquery/backfill.post.ts +55 -0
  28. package/corpus/templates/analytics/server/routes/api/dashboard-agent-context.json.get.ts +18 -4
  29. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +41 -11
  30. package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  31. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +41 -11
  32. package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  33. package/corpus/templates/brain/server/lib/connectors.ts +38 -14
  34. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +41 -11
  35. package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  36. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +41 -11
  37. package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  38. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +41 -11
  39. package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  40. package/corpus/templates/clips/app/components/player/video-player.tsx +1 -1
  41. package/corpus/templates/clips/changelog/2026-08-07-fixed-trimmed-clips-durations-so-the-main-player-display-mat.md +6 -0
  42. package/corpus/templates/clips/chrome-extension/STORE_DRAFT.md +1 -1
  43. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
  44. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +41 -11
  45. package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  46. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +41 -11
  47. package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  48. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +41 -11
  49. package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  50. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +41 -11
  51. package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  52. package/corpus/templates/dispatch/changelog/2026-08-07-language-selection-now-lives-in-settings-instead-of-the-disp.md +6 -0
  53. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +41 -11
  54. package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  55. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +59 -22
  56. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +41 -11
  57. package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  58. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +41 -11
  59. package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  60. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +41 -11
  61. package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  62. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +41 -11
  63. package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  64. package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +10 -1
  65. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +10 -3
  66. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +41 -11
  67. package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  68. package/corpus/templates/slides/actions/generate-image-api.ts +123 -0
  69. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +10 -2
  70. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +13 -0
  71. package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +5 -0
  72. package/corpus/templates/slides/app/components/editor/ImageGenPanel.tsx +1 -1
  73. package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +5 -0
  74. package/corpus/templates/slides/app/components/presentation/PresenterView.tsx +5 -0
  75. package/corpus/templates/slides/app/pages/DeckEditor.tsx +3 -0
  76. package/corpus/templates/slides/app/pages/Presentation.tsx +3 -0
  77. package/corpus/templates/slides/app/pages/SharedPresentation.tsx +5 -0
  78. package/corpus/templates/slides/app/routes/slide.tsx +10 -5
  79. package/corpus/templates/slides/changelog/2026-08-07-deleting-a-deck-no-longer-freezes-the-slides-browser.md +6 -0
  80. package/corpus/templates/slides/changelog/2026-08-07-slide-previews-and-present-now-keep-deck-colors-consistent.md +6 -0
  81. package/corpus/templates/slides/changelog/2026-08-07-slides-verify-generated-images-are-persisted-on-the-target-s.md +6 -0
  82. package/corpus/templates/slides/server/db/schema.ts +1 -0
  83. package/corpus/templates/slides/server/handlers/share.ts +51 -3
  84. package/corpus/templates/slides/server/lib/slide-image-insertion.ts +141 -0
  85. package/corpus/templates/slides/server/plugins/agent-chat.ts +2 -0
  86. package/corpus/templates/slides/server/plugins/db.ts +5 -0
  87. package/corpus/templates/slides/shared/api.ts +2 -0
  88. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +41 -11
  89. package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  90. package/dist/cli/code-agent-executor.js +8 -3
  91. package/dist/client/AgentPanel.d.ts +10 -4
  92. package/dist/client/AgentPanel.js +29 -82
  93. package/dist/client/ConnectBuilderCard.d.ts +7 -7
  94. package/dist/client/ConnectBuilderCard.js +45 -20
  95. package/dist/collab/awareness.d.ts +2 -2
  96. package/dist/config.d.ts +9 -2
  97. package/dist/config.js +38 -2
  98. package/dist/db/client.d.ts +13 -1
  99. package/dist/db/client.js +76 -2
  100. package/dist/db/create-get-db.js +2 -2
  101. package/dist/db/migrations.js +22 -4
  102. package/dist/deploy/build.d.ts +1 -0
  103. package/dist/deploy/build.js +32 -23
  104. package/dist/notifications/routes.d.ts +3 -3
  105. package/dist/progress/routes.d.ts +1 -1
  106. package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
  107. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  108. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  109. package/dist/scripts/docs/search.js +3 -2
  110. package/dist/server/agent-chat/prompt-resources.js +4 -3
  111. package/dist/server/agents-bundle.d.ts +20 -3
  112. package/dist/server/agents-bundle.js +57 -30
  113. package/dist/server/better-auth-instance.js +2 -2
  114. package/dist/server/builder-browser.d.ts +34 -0
  115. package/dist/server/builder-browser.js +179 -0
  116. package/dist/server/core-routes-plugin.d.ts +5 -0
  117. package/dist/server/core-routes-plugin.js +24 -8
  118. package/dist/server/index.d.ts +1 -1
  119. package/dist/server/index.js +1 -1
  120. package/dist/shared/cache-control.d.ts +2 -2
  121. package/dist/shared/cache-control.js +2 -2
  122. package/dist/shared/runtime-config.js +1 -1
  123. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +41 -11
  124. package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  125. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +41 -11
  126. package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  127. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +41 -11
  128. package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  129. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +41 -11
  130. package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  131. package/dist/vite/agent-native-config-loader.d.ts +10 -0
  132. package/dist/vite/agent-native-config-loader.js +56 -0
  133. package/dist/vite/agents-bundle-plugin.d.ts +5 -1
  134. package/dist/vite/agents-bundle-plugin.js +29 -6
  135. package/dist/vite/client.d.ts +4 -2
  136. package/dist/vite/client.js +17 -50
  137. package/dist/vite/index.d.ts +2 -2
  138. package/dist/vite/index.js +1 -1
  139. package/docs/content/agent-native-config.mdx +43 -17
  140. package/docs/content/drop-in-agent.mdx +3 -3
  141. package/docs/content/environment-variables.mdx +1 -1
  142. package/docs/content/getting-started-actions.mdx +1 -2
  143. package/docs/content/getting-started-pages.mdx +1 -2
  144. package/docs/content/getting-started.mdx +0 -4
  145. package/docs/content/what-is-agent-native.mdx +4 -4
  146. package/package.json +1 -1
  147. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +41 -11
  148. package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  149. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +41 -11
  150. package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  151. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +41 -11
  152. package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  153. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +41 -11
  154. package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +21 -2
  155. package/docs/content/getting-started-database.mdx +0 -173
@@ -75,9 +75,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
75
75
  user: "user";
76
76
  }>>;
77
77
  }, z.core.$strip>>, {
78
- message?: undefined;
78
+ id?: undefined;
79
79
  deleted?: undefined;
80
- found?: undefined;
81
80
  providers: {
82
81
  id: string;
83
82
  label: string;
@@ -89,21 +88,21 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
89
88
  }[];
90
89
  count: number;
91
90
  provider?: undefined;
91
+ found?: undefined;
92
92
  registered?: undefined;
93
- id?: undefined;
94
93
  label?: undefined;
95
- } | {
96
94
  message?: undefined;
95
+ } | {
96
+ id?: undefined;
97
97
  deleted?: undefined;
98
98
  providers?: undefined;
99
99
  count?: undefined;
100
100
  found: boolean;
101
101
  provider: import("../custom-registry.js").CustomProviderConfig;
102
102
  registered?: undefined;
103
- id?: undefined;
104
103
  label?: undefined;
105
- } | {
106
104
  message?: undefined;
105
+ } | {
107
106
  deleted?: undefined;
108
107
  providers?: undefined;
109
108
  count?: undefined;
@@ -112,22 +111,23 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
112
111
  id: string;
113
112
  registered?: undefined;
114
113
  label?: undefined;
115
- } | {
116
114
  message?: undefined;
117
- found?: undefined;
115
+ } | {
118
116
  providers?: undefined;
119
117
  count?: undefined;
120
118
  provider?: undefined;
119
+ found?: undefined;
121
120
  deleted: boolean;
122
121
  id: string;
123
122
  registered?: undefined;
124
123
  label?: undefined;
124
+ message?: undefined;
125
125
  } | {
126
126
  deleted?: undefined;
127
- found?: undefined;
128
127
  providers?: undefined;
129
128
  count?: undefined;
130
129
  provider?: undefined;
130
+ found?: undefined;
131
131
  registered: boolean;
132
132
  id: string;
133
133
  label: string;
@@ -311,10 +311,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
311
311
  notes?: string | undefined;
312
312
  scope?: "org" | "user" | undefined;
313
313
  }, {
314
- deleted?: undefined;
315
314
  id?: undefined;
316
315
  provider?: undefined;
317
- found?: undefined;
316
+ deleted?: undefined;
318
317
  message?: undefined;
319
318
  providers: {
320
319
  id: string;
@@ -326,12 +325,13 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
326
325
  updatedAt: number;
327
326
  }[];
328
327
  count: number;
328
+ found?: undefined;
329
329
  registered?: undefined;
330
330
  label?: undefined;
331
331
  } | {
332
- deleted?: undefined;
333
- count?: undefined;
334
332
  id?: undefined;
333
+ count?: undefined;
334
+ deleted?: undefined;
335
335
  message?: undefined;
336
336
  providers?: undefined;
337
337
  found: boolean;
@@ -339,9 +339,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
339
339
  registered?: undefined;
340
340
  label?: undefined;
341
341
  } | {
342
- deleted?: undefined;
343
342
  count?: undefined;
344
343
  provider?: undefined;
344
+ deleted?: undefined;
345
345
  message?: undefined;
346
346
  providers?: undefined;
347
347
  found: boolean;
@@ -351,19 +351,19 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
351
351
  } | {
352
352
  count?: undefined;
353
353
  provider?: undefined;
354
- found?: undefined;
355
354
  message?: undefined;
356
355
  providers?: undefined;
356
+ found?: undefined;
357
357
  deleted: boolean;
358
358
  id: string;
359
359
  registered?: undefined;
360
360
  label?: undefined;
361
361
  } | {
362
- deleted?: undefined;
363
362
  count?: undefined;
364
363
  provider?: undefined;
365
- found?: undefined;
364
+ deleted?: undefined;
366
365
  providers?: undefined;
366
+ found?: undefined;
367
367
  registered: boolean;
368
368
  id: string;
369
369
  label: string;
@@ -73,7 +73,6 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
73
73
  offset?: unknown;
74
74
  limit?: unknown;
75
75
  }, {
76
- deleted?: undefined;
77
76
  jobs: {
78
77
  id: string;
79
78
  name: string;
@@ -84,6 +83,7 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
84
83
  updatedAt: string;
85
84
  }[];
86
85
  total: number;
86
+ deleted?: undefined;
87
87
  jobId?: undefined;
88
88
  } | {
89
89
  jobs?: undefined;
@@ -91,9 +91,9 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
91
91
  deleted: boolean;
92
92
  jobId: string;
93
93
  } | {
94
- deleted?: undefined;
95
94
  jobs?: undefined;
96
95
  total?: undefined;
96
+ deleted?: undefined;
97
97
  jobId?: undefined;
98
98
  hits: Record<string, unknown>[];
99
99
  offset: number;
@@ -127,12 +127,13 @@ async function loadAgentBundleDocs() {
127
127
  body: bundle.workspaceAgentsMd,
128
128
  });
129
129
  }
130
- if (bundle.agentsMd?.trim()) {
130
+ const runtimeAgentsMd = bundle.runtimeAgentsMd ?? bundle.agentsMd;
131
+ if (runtimeAgentsMd?.trim()) {
131
132
  docs.push({
132
133
  slug: "agents-template",
133
134
  title: "Template AGENTS.md",
134
135
  description: "Full bundled template/app agent instructions.",
135
- body: bundle.agentsMd,
136
+ body: runtimeAgentsMd,
136
137
  });
137
138
  }
138
139
  // Only runtime-visible skills are searchable/readable here — `scope: dev`
@@ -631,13 +631,14 @@ export async function loadResourcesForPrompt(owner, compact = false, selfAppId,
631
631
  });
632
632
  addSection(block, "required");
633
633
  }
634
- // 2. Template AGENTS.md — always included (critical template instructions).
635
- if (bundle.agentsMd.trim()) {
634
+ // 2. Runtime instruction file — always included when configured.
635
+ const runtimeAgentsMd = bundle.runtimeAgentsMd ?? bundle.agentsMd;
636
+ if (runtimeAgentsMd.trim()) {
636
637
  const block = promptResourceBlock({
637
638
  name: "AGENTS.md",
638
639
  scope: "template",
639
640
  path: "AGENTS.md",
640
- content: bundle.agentsMd,
641
+ content: runtimeAgentsMd,
641
642
  maxChars: promptResourceMaxChars,
642
643
  readHint: 'Use docs-search --slug "agents-template" to read the full template AGENTS.md.',
643
644
  });
@@ -15,7 +15,8 @@
15
15
  * 2. Filesystem fallback — `process.cwd()/AGENTS.md` +
16
16
  * `process.cwd()/.agents/skills/` (or legacy `.agent/skills/`). Only reliable in local dev and Node
17
17
  * production (`agent-native start`); not on Netlify/Vercel/CF at runtime.
18
- * 3. Empty bundle — everything silently returns empty strings.
18
+ * 3. Configuration and filesystem failures propagate so a broken bundle is
19
+ * visible instead of being mistaken for an app with no instructions.
19
20
  *
20
21
  * Result is cached in module scope so it's only computed once per cold start.
21
22
  */
@@ -68,8 +69,15 @@ export interface Skill {
68
69
  files: Record<string, string>;
69
70
  }
70
71
  export interface AgentsBundle {
71
- /** Contents of the template's AGENTS.md (empty string if missing). */
72
+ /**
73
+ * Legacy alias for the runtime instruction file. Empty when an explicitly
74
+ * configured runtime file is missing.
75
+ */
72
76
  agentsMd: string;
77
+ /** Contents of the runtime agent's selected instruction file. */
78
+ runtimeAgentsMd: string;
79
+ /** Contents of the development agent's selected instruction file. */
80
+ developmentAgentsMd: string;
73
81
  /**
74
82
  * Contents of the workspace core's AGENTS.md, if the app is inside an
75
83
  * enterprise monorepo with a `workspaceCore` configured. Empty string
@@ -86,6 +94,14 @@ export interface AgentsBundle {
86
94
  */
87
95
  skills: Record<string, Skill>;
88
96
  }
97
+ export interface AgentsBundleReadOptions {
98
+ instructions?: AgentNativeInstructionsConfig;
99
+ }
100
+ export interface AgentInstructionPaths {
101
+ runtime: string;
102
+ development: string;
103
+ }
104
+ export declare function resolveAgentInstructionPaths(instructions?: AgentNativeInstructionsConfig): AgentInstructionPaths;
89
105
  export declare function normalizeSkillScope(raw: string | undefined): SkillScope;
90
106
  /**
91
107
  * Parse the YAML frontmatter at the top of a skill file.
@@ -97,6 +113,7 @@ export declare function normalizeSkillScope(raw: string | undefined): SkillScope
97
113
  * - Literal scalar: `description: |\n multi\n line` → "multi\nline"
98
114
  */
99
115
  export declare function parseSkillFrontmatter(content: string): Partial<SkillMeta>;
116
+ import type { AgentNativeInstructionsConfig } from "../config.js";
100
117
  /**
101
118
  * Paths to a workspace-core's agent resources, for merging into a template's
102
119
  * bundle. All fields optional — pass null for any missing piece.
@@ -117,7 +134,7 @@ export interface WorkspaceAgentsSource {
117
134
  *
118
135
  * Synchronous — the Vite plugin's load hook calls it inline during the build.
119
136
  */
120
- export declare function readAgentsBundleFromFs(cwd: string, workspaceSource?: WorkspaceAgentsSource | null): AgentsBundle;
137
+ export declare function readAgentsBundleFromFs(cwd: string, workspaceSource?: WorkspaceAgentsSource | null, options?: AgentsBundleReadOptions): AgentsBundle;
121
138
  /**
122
139
  * Load the agents bundle. Returns a cached result on subsequent calls.
123
140
  * Tries the virtual module first (works everywhere, including edge), then
@@ -15,12 +15,19 @@
15
15
  * 2. Filesystem fallback — `process.cwd()/AGENTS.md` +
16
16
  * `process.cwd()/.agents/skills/` (or legacy `.agent/skills/`). Only reliable in local dev and Node
17
17
  * production (`agent-native start`); not on Netlify/Vercel/CF at runtime.
18
- * 3. Empty bundle — everything silently returns empty strings.
18
+ * 3. Configuration and filesystem failures propagate so a broken bundle is
19
+ * visible instead of being mistaken for an app with no instructions.
19
20
  *
20
21
  * Result is cached in module scope so it's only computed once per cold start.
21
22
  */
22
23
  export const DEFAULT_SKILL_SCOPE = "both";
23
- const EMPTY = { agentsMd: "", workspaceAgentsMd: "", skills: {} };
24
+ const DEFAULT_AGENT_INSTRUCTIONS_PATH = "AGENTS.md";
25
+ export function resolveAgentInstructionPaths(instructions) {
26
+ return {
27
+ runtime: instructions?.runtime ?? DEFAULT_AGENT_INSTRUCTIONS_PATH,
28
+ development: instructions?.development ?? DEFAULT_AGENT_INSTRUCTIONS_PATH,
29
+ };
30
+ }
24
31
  let cached = null;
25
32
  /**
26
33
  * Coerce a raw frontmatter `scope` value into a known `SkillScope`. Unknown,
@@ -125,6 +132,23 @@ const READABLE_SUBFILE_EXTENSIONS = new Set([".md", ".txt", ".json"]);
125
132
  */
126
133
  const MAX_SUBFILE_BYTES = 64 * 1024;
127
134
  const MAX_SKILL_FILES_BYTES = 256 * 1024;
135
+ function readInstructionFile(cwd, relativePath) {
136
+ const normalizedPath = relativePath.replaceAll("\\", "/");
137
+ const root = fs.realpathSync(path.resolve(cwd));
138
+ const absolutePath = path.resolve(root, normalizedPath);
139
+ if (absolutePath !== root && !absolutePath.startsWith(`${root}${path.sep}`)) {
140
+ throw new Error(`Agent instruction path must stay inside the app root: ${relativePath}`);
141
+ }
142
+ if (!fs.existsSync(absolutePath))
143
+ return "";
144
+ const realPath = fs.realpathSync(absolutePath);
145
+ if (realPath !== root && !realPath.startsWith(`${root}${path.sep}`)) {
146
+ throw new Error(`Agent instruction path must stay inside the app root: ${relativePath}`);
147
+ }
148
+ if (!fs.statSync(realPath).isFile())
149
+ return "";
150
+ return fs.readFileSync(realPath, "utf-8");
151
+ }
128
152
  /**
129
153
  * Read one skills directory into a `Record<string, Skill>`. Extracted so
130
154
  * both the template and workspace-core paths can reuse it. `dirPrefix` is
@@ -214,15 +238,10 @@ function readSkillsDir(skillsDir, rootForRelative, out, skipExistingNames) {
214
238
  *
215
239
  * Synchronous — the Vite plugin's load hook calls it inline during the build.
216
240
  */
217
- export function readAgentsBundleFromFs(cwd, workspaceSource = null) {
218
- let agentsMd = "";
219
- try {
220
- const agentsMdPath = path.join(cwd, "AGENTS.md");
221
- if (fs.existsSync(agentsMdPath)) {
222
- agentsMd = fs.readFileSync(agentsMdPath, "utf-8");
223
- }
224
- }
225
- catch { }
241
+ export function readAgentsBundleFromFs(cwd, workspaceSource = null, options = {}) {
242
+ const instructionPaths = resolveAgentInstructionPaths(options.instructions);
243
+ const runtimeAgentsMd = readInstructionFile(cwd, instructionPaths.runtime);
244
+ const developmentAgentsMd = readInstructionFile(cwd, instructionPaths.development);
226
245
  let workspaceAgentsMd = "";
227
246
  if (workspaceSource?.agentsMdPath) {
228
247
  try {
@@ -249,7 +268,15 @@ export function readAgentsBundleFromFs(cwd, workspaceSource = null) {
249
268
  }
250
269
  catch { }
251
270
  }
252
- return { agentsMd, workspaceAgentsMd, skills };
271
+ return {
272
+ // Keep the old field useful for callers that only know about the runtime
273
+ // bundle. Audience-aware consumers should use the explicit fields.
274
+ agentsMd: runtimeAgentsMd,
275
+ runtimeAgentsMd,
276
+ developmentAgentsMd,
277
+ workspaceAgentsMd,
278
+ skills,
279
+ };
253
280
  }
254
281
  /**
255
282
  * Load the agents bundle. Returns a cached result on subsequent calls.
@@ -279,29 +306,29 @@ export async function loadAgentsBundle() {
279
306
  }
280
307
  // 2. Filesystem fallback — works in dev / Node prod. If a workspace core
281
308
  // is present in the ancestor chain, merge its skills + AGENTS.md in.
309
+ let workspaceSource = null;
282
310
  try {
283
- let workspaceSource = null;
284
- try {
285
- const { getWorkspaceCoreExports } = await import("../deploy/workspace-core.js");
286
- const ws = await getWorkspaceCoreExports(process.cwd());
287
- if (ws) {
288
- workspaceSource = {
289
- skillsDir: ws.skillsDir,
290
- agentsMdPath: ws.agentsMdPath,
291
- rootDir: ws.packageDir,
292
- };
293
- }
294
- }
295
- catch {
296
- // workspace-core discovery isn't available (e.g. edge runtime).
311
+ const { getWorkspaceCoreExports } = await import("../deploy/workspace-core.js");
312
+ const ws = await getWorkspaceCoreExports(process.cwd());
313
+ if (ws) {
314
+ workspaceSource = {
315
+ skillsDir: ws.skillsDir,
316
+ agentsMdPath: ws.agentsMdPath,
317
+ rootDir: ws.packageDir,
318
+ };
297
319
  }
298
- cached = readAgentsBundleFromFs(process.cwd(), workspaceSource);
299
- return cached;
320
+ // coercion-ok: workspace-core discovery is optional in edge runtimes.
300
321
  }
301
322
  catch {
302
- cached = EMPTY;
303
- return cached;
323
+ // workspace-core discovery isn't available (e.g. edge runtime).
304
324
  }
325
+ const { createAgentNativeConfigContext, loadResolvedAgentNativeConfig } = await import("../vite/agent-native-config-loader.js");
326
+ const production = process.env.NODE_ENV === "production";
327
+ const config = await loadResolvedAgentNativeConfig(process.cwd(), createAgentNativeConfigContext(production ? "build" : "serve", production ? "production" : "development"));
328
+ cached = readAgentsBundleFromFs(process.cwd(), workspaceSource, {
329
+ instructions: config.instructions,
330
+ });
331
+ return cached;
305
332
  }
306
333
  /**
307
334
  * Generate the `<skills>` block to inject into the system prompt.
@@ -16,7 +16,7 @@ import { pgTable, text as pgText, timestamp as pgTimestamp, boolean as pgBoolean
16
16
  import { sqliteTable, text as sqliteText, integer as sqliteInteger, } from "drizzle-orm/sqlite-core";
17
17
  import { TEMPLATES } from "../cli/templates-meta.js";
18
18
  import { getDbExec, isPostgres } from "../db/client.js";
19
- import { getDialect, getDatabaseUrl, getDatabaseAuthToken, closePgliteClients, getPgliteClient, isPgliteUrl, loadPgliteDrizzle, pgPoolOptions, neonPoolOptions, attachNeonPoolErrorLogger, sharedDbPool, onSharedDbPoolsClosed, onSharedDbPoolReplaced, } from "../db/client.js";
19
+ import { getDialect, getDatabaseUrl, getDatabaseAuthToken, closePgliteClients, getPgliteClient, isPgliteUrl, loadPgliteDrizzle, pgPoolOptions, neonPoolOptions, guardNeonPool, sharedDbPool, onSharedDbPoolsClosed, onSharedDbPoolReplaced, } from "../db/client.js";
20
20
  import { CORE_RESET_PASSWORD_EMAIL_ID, CORE_VERIFY_SIGNUP_EMAIL_ID, } from "../email-catalog/system-emails.js";
21
21
  import { saveOAuthTokens } from "../oauth-tokens/store.js";
22
22
  import { acceptPendingInvitationsForEmail } from "../org/accept-pending.js";
@@ -1151,7 +1151,7 @@ async function buildDatabaseConfig(dialect) {
1151
1151
  // connections reached" across concurrent serverless instances.
1152
1152
  resetAuthOnPoolClose("neon", url);
1153
1153
  _neonAuthPool = sharedDbPool("neon", url, () => new Pool({ connectionString: url, ...neonPoolOptions() }));
1154
- attachNeonPoolErrorLogger(_neonAuthPool, "db/neon-auth");
1154
+ guardNeonPool(_neonAuthPool, url, "db/neon-auth");
1155
1155
  const { drizzle } = await import("drizzle-orm/neon-serverless");
1156
1156
  const db = drizzle(buildResilientNeonPool(_neonAuthPool), {
1157
1157
  schema: pgAuthSchema,
@@ -328,6 +328,40 @@ export interface RunBuilderAgentResult {
328
328
  url: string;
329
329
  status: string;
330
330
  }
331
+ export interface BuilderProjectLookupArgs {
332
+ repoUrl: string;
333
+ }
334
+ export interface BuilderProjectResult {
335
+ projectId: string;
336
+ name: string;
337
+ repoUrl: string;
338
+ browserUrl: string;
339
+ created: boolean;
340
+ }
341
+ /**
342
+ * Find an existing Builder project connected to a repository. Dispatch uses
343
+ * this before provisioning so a first app request cannot create a duplicate
344
+ * workspace project when the project id has not been saved yet.
345
+ */
346
+ export declare function findBuilderProjectForRepo(args: BuilderProjectLookupArgs): Promise<BuilderProjectResult | null>;
347
+ /**
348
+ * Create a Builder project connected to a repository through the public
349
+ * projects API. This is the server-side bridge used by Dispatch; online
350
+ * Claude and ChatGPT hosts do not need a separate Builder CMS MCP connector.
351
+ */
352
+ export declare function createBuilderProject(args: {
353
+ name: string;
354
+ repoUrl: string;
355
+ }): Promise<BuilderProjectResult>;
356
+ /**
357
+ * Reuse a connected Builder project or create it once when Dispatch is first
358
+ * used for a workspace. The lookup and create calls intentionally stay in
359
+ * this shared server helper so all callers use the same authenticated path.
360
+ */
361
+ export declare function ensureBuilderProject(args: {
362
+ name: string;
363
+ repoUrl: string;
364
+ }): Promise<BuilderProjectResult>;
331
365
  /**
332
366
  * POST a prompt to the Builder agents-run API. The Builder agent runs in a
333
367
  * cloud sandbox and writes code to a branch; the returned URL opens that
@@ -1283,6 +1283,185 @@ function normalizeBuilderApiString(value, fieldName) {
1283
1283
  }
1284
1284
  return trimmed;
1285
1285
  }
1286
+ function normalizeBuilderProjectString(value, fieldName) {
1287
+ if (typeof value !== "string" || !value.trim()) {
1288
+ throw new Error(`Builder project response returned a blank ${fieldName}`);
1289
+ }
1290
+ const trimmed = value.trim();
1291
+ if (/[\u0000-\u001f\u007f]/.test(trimmed)) {
1292
+ throw new Error(`Builder project response returned a malformed ${fieldName}`);
1293
+ }
1294
+ return trimmed;
1295
+ }
1296
+ function normalizeBuilderRepoUrl(value) {
1297
+ const trimmed = value.trim();
1298
+ let parsed;
1299
+ try {
1300
+ parsed = new URL(trimmed);
1301
+ }
1302
+ catch {
1303
+ throw new Error("Builder project repository URL is malformed");
1304
+ }
1305
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
1306
+ throw new Error("Builder project repository URL must use HTTP or HTTPS");
1307
+ }
1308
+ return trimmed;
1309
+ }
1310
+ function comparableBuilderRepoUrl(value) {
1311
+ try {
1312
+ const parsed = new URL(value);
1313
+ const pathname = parsed.pathname.replace(/\/+$/, "").replace(/\.git$/, "");
1314
+ return `${parsed.hostname.toLowerCase()}${pathname.toLowerCase()}`;
1315
+ }
1316
+ catch {
1317
+ return value
1318
+ .trim()
1319
+ .replace(/\/+$/, "")
1320
+ .replace(/\.git$/, "")
1321
+ .toLowerCase();
1322
+ }
1323
+ }
1324
+ function builderProjectBrowserUrl(projectId) {
1325
+ return `${getBuilderAppHost().replace(/\/$/, "")}/app/projects/${encodeURIComponent(projectId)}`;
1326
+ }
1327
+ function builderProjectFromRecord(value, fallbackRepoUrl, created) {
1328
+ if (!value || typeof value !== "object" || Array.isArray(value))
1329
+ return null;
1330
+ const record = value;
1331
+ const projectId = typeof record.id === "string" && record.id.trim() ? record.id.trim() : null;
1332
+ if (!projectId)
1333
+ return null;
1334
+ const name = typeof record.name === "string" && record.name.trim()
1335
+ ? record.name.trim()
1336
+ : "Agent-Native Workspace";
1337
+ const repoUrl = typeof record.repoUrl === "string" && record.repoUrl.trim()
1338
+ ? record.repoUrl.trim()
1339
+ : fallbackRepoUrl;
1340
+ if (!repoUrl)
1341
+ return null;
1342
+ return {
1343
+ projectId: normalizeBuilderProjectString(projectId, "project id"),
1344
+ name: normalizeBuilderProjectString(name, "project name"),
1345
+ repoUrl: normalizeBuilderRepoUrl(repoUrl),
1346
+ browserUrl: builderProjectBrowserUrl(projectId),
1347
+ created,
1348
+ };
1349
+ }
1350
+ async function resolveBuilderApiCredentials() {
1351
+ const { resolveBuilderCredentials } = await import("./credential-provider.js");
1352
+ const creds = await resolveBuilderCredentials();
1353
+ if (!creds.privateKey || !creds.publicKey) {
1354
+ throw new Error("Builder keys are not configured");
1355
+ }
1356
+ return {
1357
+ ...creds,
1358
+ privateKey: creds.privateKey,
1359
+ publicKey: creds.publicKey,
1360
+ };
1361
+ }
1362
+ async function readBuilderApiObject(response, operation) {
1363
+ let parsed;
1364
+ try {
1365
+ parsed = await response.json();
1366
+ }
1367
+ catch (error) {
1368
+ throw new Error("Builder " +
1369
+ operation +
1370
+ " returned an invalid JSON response (" +
1371
+ response.status +
1372
+ ")", { cause: error });
1373
+ }
1374
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1375
+ throw new Error("Builder " +
1376
+ operation +
1377
+ " returned an invalid JSON response (" +
1378
+ response.status +
1379
+ ")");
1380
+ }
1381
+ return parsed;
1382
+ }
1383
+ function builderApiErrorMessage(parsed, fallback) {
1384
+ if (typeof parsed.error === "string" && parsed.error.trim()) {
1385
+ return parsed.error.trim();
1386
+ }
1387
+ if (typeof parsed.message === "string" && parsed.message.trim()) {
1388
+ return parsed.message.trim();
1389
+ }
1390
+ return fallback;
1391
+ }
1392
+ /**
1393
+ * Find an existing Builder project connected to a repository. Dispatch uses
1394
+ * this before provisioning so a first app request cannot create a duplicate
1395
+ * workspace project when the project id has not been saved yet.
1396
+ */
1397
+ export async function findBuilderProjectForRepo(args) {
1398
+ const repoUrl = normalizeBuilderRepoUrl(args.repoUrl);
1399
+ const creds = await resolveBuilderApiCredentials();
1400
+ const url = new URL("/projects", getBuilderApiHost());
1401
+ url.searchParams.set("apiKey", creds.publicKey);
1402
+ url.searchParams.set("includeHidden", "true");
1403
+ const response = await fetch(url, {
1404
+ method: "GET",
1405
+ headers: { Authorization: `Bearer ${creds.privateKey}` },
1406
+ });
1407
+ const parsed = await readBuilderApiObject(response, "project lookup");
1408
+ if (!response.ok) {
1409
+ throw new Error(builderApiErrorMessage(parsed, `Builder project lookup failed (${response.status})`));
1410
+ }
1411
+ if (!Array.isArray(parsed.projects)) {
1412
+ throw new Error("Builder project lookup returned no projects list");
1413
+ }
1414
+ const comparableRepoUrl = comparableBuilderRepoUrl(repoUrl);
1415
+ for (const project of parsed.projects) {
1416
+ const normalized = builderProjectFromRecord(project, null, false);
1417
+ if (normalized &&
1418
+ comparableBuilderRepoUrl(normalized.repoUrl) === comparableRepoUrl) {
1419
+ return normalized;
1420
+ }
1421
+ }
1422
+ return null;
1423
+ }
1424
+ /**
1425
+ * Create a Builder project connected to a repository through the public
1426
+ * projects API. This is the server-side bridge used by Dispatch; online
1427
+ * Claude and ChatGPT hosts do not need a separate Builder CMS MCP connector.
1428
+ */
1429
+ export async function createBuilderProject(args) {
1430
+ const name = normalizeBuilderProjectString(args.name, "project name");
1431
+ const repoUrl = normalizeBuilderRepoUrl(args.repoUrl);
1432
+ const creds = await resolveBuilderApiCredentials();
1433
+ const url = new URL("/projects/create", getBuilderApiHost());
1434
+ url.searchParams.set("apiKey", creds.publicKey);
1435
+ const response = await fetch(url, {
1436
+ method: "POST",
1437
+ headers: {
1438
+ Authorization: `Bearer ${creds.privateKey}`,
1439
+ "Content-Type": "application/json",
1440
+ },
1441
+ body: JSON.stringify({
1442
+ source: { kind: "repo", repoUrl },
1443
+ name,
1444
+ }),
1445
+ });
1446
+ const parsed = await readBuilderApiObject(response, "project creation");
1447
+ if (!response.ok) {
1448
+ throw new Error(builderApiErrorMessage(parsed, `Builder project creation failed (${response.status})`));
1449
+ }
1450
+ const project = builderProjectFromRecord(parsed.project, repoUrl, true);
1451
+ if (!project) {
1452
+ throw new Error("Builder project creation returned no project id");
1453
+ }
1454
+ return project;
1455
+ }
1456
+ /**
1457
+ * Reuse a connected Builder project or create it once when Dispatch is first
1458
+ * used for a workspace. The lookup and create calls intentionally stay in
1459
+ * this shared server helper so all callers use the same authenticated path.
1460
+ */
1461
+ export async function ensureBuilderProject(args) {
1462
+ const existing = await findBuilderProjectForRepo({ repoUrl: args.repoUrl });
1463
+ return existing ?? createBuilderProject(args);
1464
+ }
1286
1465
  function normalizeBuilderBranchUrl(value) {
1287
1466
  const urlString = normalizeBuilderApiString(value, "url");
1288
1467
  let parsed;
@@ -288,6 +288,11 @@ interface LegacyCoreRouteInitSettings {
288
288
  }
289
289
  type CoreRouteSettingReader = (key: string) => Promise<Record<string, unknown> | null>;
290
290
  export declare function readLegacyCoreRouteInitSettings(readSetting?: CoreRouteSettingReader): Promise<LegacyCoreRouteInitSettings>;
291
+ /**
292
+ * Production release jobs own schema setup. Request functions must not spend
293
+ * their cold-start budget on legacy cleanup or best-effort table warmups.
294
+ */
295
+ export declare function shouldRunCoreRouteBootDatabaseWork(env?: NodeJS.ProcessEnv): boolean;
291
296
  export declare function createCoreRoutesPlugin(options?: CoreRoutesPluginOptions): NitroPluginDef;
292
297
  /**
293
298
  * Default core routes plugin — mount with no configuration needed.