@agent-native/core 0.80.0 → 0.80.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 (220) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +8 -0
  3. package/corpus/core/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
  4. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +14 -1
  5. package/corpus/core/docs/content/locales/de-DE/skills-guide.mdx +5 -0
  6. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +15 -1
  7. package/corpus/core/docs/content/locales/es-ES/skills-guide.mdx +5 -0
  8. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +15 -1
  9. package/corpus/core/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
  10. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +15 -1
  11. package/corpus/core/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
  12. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +15 -1
  13. package/corpus/core/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
  14. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +16 -1
  15. package/corpus/core/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
  16. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +14 -1
  17. package/corpus/core/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
  18. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +14 -1
  19. package/corpus/core/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
  20. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +14 -1
  21. package/corpus/core/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
  22. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +14 -1
  23. package/corpus/core/docs/content/skills-guide.mdx +5 -0
  24. package/corpus/core/docs/content/template-design.mdx +14 -1
  25. package/corpus/core/package.json +1 -1
  26. package/corpus/core/src/application-state/handlers.ts +1 -1
  27. package/corpus/core/src/brand-kit/index.ts +1 -1
  28. package/corpus/core/src/cli/skills.ts +18 -0
  29. package/corpus/core/src/client/AgentPanel.tsx +1 -1
  30. package/corpus/core/src/client/MultiTabAssistantChat.tsx +1 -1
  31. package/corpus/core/src/client/extensions/portable-extension.ts +1 -1
  32. package/corpus/core/src/code-agents/transcript-normalizer.ts +1 -1
  33. package/corpus/core/src/extensions/path.ts +1 -4
  34. package/corpus/core/src/integrations/a2a-continuation-processor.ts +1 -1
  35. package/corpus/core/src/mcp/build-server.ts +1 -1
  36. package/corpus/core/src/org/handlers.ts +5 -5
  37. package/corpus/core/src/org/plugin.ts +2 -2
  38. package/corpus/core/src/scripts/call-agent.ts +1 -1
  39. package/corpus/core/src/scripts/db/safety.ts +1 -1
  40. package/corpus/core/src/server/auth.ts +3 -0
  41. package/corpus/core/src/server/builder-design-systems.ts +308 -0
  42. package/corpus/core/src/server/core-routes-plugin.ts +29 -3
  43. package/corpus/core/src/server/index.ts +8 -0
  44. package/corpus/core/src/styles/agent-native.css +14 -7
  45. package/corpus/core/src/usage/store.ts +2 -2
  46. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +298 -15
  47. package/corpus/templates/analytics/actions/get-sql-dashboard.ts +9 -4
  48. package/corpus/templates/analytics/actions/mutate-dashboard.ts +18 -2
  49. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +12 -2
  50. package/corpus/templates/analytics/app/hooks/use-replay-storage-status.ts +66 -0
  51. package/corpus/templates/analytics/app/i18n/zh-TW.ts +37 -0
  52. package/corpus/templates/analytics/app/i18n-data.ts +404 -0
  53. package/corpus/templates/analytics/app/pages/Settings.tsx +333 -0
  54. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +2 -1
  55. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +121 -3
  56. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +49 -26
  57. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +137 -36
  58. package/corpus/templates/analytics/changelog/2026-06-29-analytics-agents-can-now-place-new-charts-into-requested-das.md +6 -0
  59. package/corpus/templates/analytics/changelog/2026-06-29-analytics-queries-now-report-failed-source-query-errors-inst.md +6 -0
  60. package/corpus/templates/analytics/changelog/2026-06-29-charts-can-now-be-dropped-between-full-dashboard-rows-to-cre.md +6 -0
  61. package/corpus/templates/analytics/changelog/2026-06-29-dashboard-email-reports-include-the-full-dashboard-image-wit.md +6 -0
  62. package/corpus/templates/analytics/changelog/2026-06-29-main-surface-border-reaches-the-top.md +6 -0
  63. package/corpus/templates/analytics/changelog/2026-06-29-session-replay-now-records-playable-sessions-in-production-a.md +6 -0
  64. package/corpus/templates/analytics/changelog/2026-06-29-set-up-session-replay-storage-from-settings-connect-builder-.md +6 -0
  65. package/corpus/templates/analytics/scripts/cleanup-empty-session-recordings.ts +102 -0
  66. package/corpus/templates/analytics/server/lib/dashboard-report.ts +49 -26
  67. package/corpus/templates/analytics/server/lib/real-data-actions.ts +81 -20
  68. package/corpus/templates/analytics/server/lib/replay-storage.ts +79 -0
  69. package/corpus/templates/analytics/server/lib/s3-upload-provider.ts +255 -0
  70. package/corpus/templates/analytics/server/lib/session-replay.ts +29 -8
  71. package/corpus/templates/analytics/server/plugins/agent-chat.ts +11 -2
  72. package/corpus/templates/analytics/server/plugins/onboarding.ts +97 -0
  73. package/corpus/templates/clips/desktop/src/lib/recorder.ts +24 -0
  74. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +105 -5
  75. package/corpus/templates/content/actions/set-image-alt-text.ts +1 -1
  76. package/corpus/templates/content/shared/document-export.ts +1 -1
  77. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +8 -18
  78. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +17 -0
  79. package/corpus/templates/design/actions/add-localhost-screens.ts +32 -5
  80. package/corpus/templates/design/actions/index-design-system-with-builder.ts +259 -0
  81. package/corpus/templates/design/actions/update-file.ts +9 -2
  82. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +33 -75
  83. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +72 -9
  84. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +41 -39
  85. package/corpus/templates/design/app/components/design/EditPanel.tsx +1029 -249
  86. package/corpus/templates/design/app/components/design/LayersPanel.tsx +450 -101
  87. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +978 -154
  88. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +7 -9
  89. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +133 -66
  90. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +1234 -344
  91. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +144 -94
  92. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +301 -72
  93. package/corpus/templates/design/app/components/design/inspector/FigmaColorPicker.tsx +876 -286
  94. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +601 -0
  95. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +242 -0
  96. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +30 -7
  97. package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +212 -155
  98. package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +423 -0
  99. package/corpus/templates/design/app/components/design/inspector/figma-icons.tsx +487 -107
  100. package/corpus/templates/design/app/components/design/inspector/index.ts +27 -0
  101. package/corpus/templates/design/app/global.css +29 -3
  102. package/corpus/templates/design/app/i18n/zh-TW.ts +13 -0
  103. package/corpus/templates/design/app/i18n-data.ts +239 -1
  104. package/corpus/templates/design/app/pages/DesignEditor.tsx +1023 -353
  105. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +57 -221
  106. package/corpus/templates/design/changelog/2026-06-29-canvas-selection-no-longer-flashes-broken-prototype-html-whe.md +6 -0
  107. package/corpus/templates/design/changelog/2026-06-29-command-menu-selections-are-clearer-in-dark-mode.md +6 -0
  108. package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +6 -0
  109. package/corpus/templates/design/changelog/2026-06-29-element-selection-now-stays-on-the-intended-layer-after-sele.md +6 -0
  110. package/corpus/templates/design/changelog/2026-06-29-screen-overview-full-view-controls-now-sit-above-frames-inst.md +6 -0
  111. package/corpus/templates/design/changelog/2026-06-29-screen-overview-tools-can-draw-shapes-create-screens-and-kee.md +6 -0
  112. package/corpus/templates/design/changelog/2026-06-29-the-pen-tool-now-creates-anchor-based-bezier-vectors-with-ha.md +6 -0
  113. package/corpus/templates/design/server/handlers/import-figma-system.ts +38 -85
  114. package/corpus/templates/design/server/lib/design-snapshot.ts +9 -1
  115. package/corpus/templates/design/shared/code-layer.ts +209 -9
  116. package/corpus/templates/design/shared/html-content.ts +21 -0
  117. package/corpus/templates/design/shared/pen-path.ts +207 -0
  118. package/corpus/templates/mail/app/lib/utils.ts +2 -2
  119. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +9 -10
  120. package/corpus/templates/slides/AGENTS.md +3 -2
  121. package/corpus/templates/slides/actions/import-file.ts +26 -17
  122. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +259 -0
  123. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +35 -167
  124. package/corpus/templates/slides/app/components/design-system/fig-import-response.ts +9 -13
  125. package/corpus/templates/slides/app/context/DeckContext.tsx +1 -1
  126. package/corpus/templates/slides/app/i18n/ar-SA.ts +9 -37
  127. package/corpus/templates/slides/app/i18n/de-DE.ts +10 -25
  128. package/corpus/templates/slides/app/i18n/en-US.ts +9 -26
  129. package/corpus/templates/slides/app/i18n/es-ES.ts +10 -28
  130. package/corpus/templates/slides/app/i18n/fr-FR.ts +10 -28
  131. package/corpus/templates/slides/app/i18n/hi-IN.ts +9 -26
  132. package/corpus/templates/slides/app/i18n/ja-JP.ts +10 -22
  133. package/corpus/templates/slides/app/i18n/ko-KR.ts +9 -23
  134. package/corpus/templates/slides/app/i18n/pt-BR.ts +10 -28
  135. package/corpus/templates/slides/app/i18n/zh-CN.ts +9 -22
  136. package/corpus/templates/slides/app/i18n/zh-TW.ts +9 -22
  137. package/corpus/templates/slides/server/handlers/import-figma-system.ts +44 -12
  138. package/corpus/templates/slides/server/lib/chat-attachments.ts +1 -1
  139. package/corpus/templates/videos/app/components/NewCompositionPopover.tsx +1 -1
  140. package/dist/application-state/handlers.js +1 -1
  141. package/dist/application-state/handlers.js.map +1 -1
  142. package/dist/brand-kit/index.d.ts +1 -1
  143. package/dist/brand-kit/index.js +1 -1
  144. package/dist/brand-kit/index.js.map +1 -1
  145. package/dist/cli/skills.d.ts.map +1 -1
  146. package/dist/cli/skills.js +18 -0
  147. package/dist/cli/skills.js.map +1 -1
  148. package/dist/client/AgentPanel.js +1 -1
  149. package/dist/client/AgentPanel.js.map +1 -1
  150. package/dist/client/MultiTabAssistantChat.js +1 -1
  151. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  152. package/dist/client/extensions/portable-extension.d.ts +1 -1
  153. package/dist/client/extensions/portable-extension.d.ts.map +1 -1
  154. package/dist/client/extensions/portable-extension.js.map +1 -1
  155. package/dist/code-agents/transcript-normalizer.js +1 -1
  156. package/dist/code-agents/transcript-normalizer.js.map +1 -1
  157. package/dist/collab/awareness.d.ts +2 -2
  158. package/dist/collab/awareness.d.ts.map +1 -1
  159. package/dist/extensions/path.d.ts +1 -1
  160. package/dist/extensions/path.d.ts.map +1 -1
  161. package/dist/extensions/path.js.map +1 -1
  162. package/dist/integrations/a2a-continuation-processor.js +1 -1
  163. package/dist/integrations/a2a-continuation-processor.js.map +1 -1
  164. package/dist/mcp/build-server.d.ts +1 -1
  165. package/dist/mcp/build-server.d.ts.map +1 -1
  166. package/dist/mcp/build-server.js.map +1 -1
  167. package/dist/observability/routes.d.ts +3 -3
  168. package/dist/org/handlers.js +5 -5
  169. package/dist/org/handlers.js.map +1 -1
  170. package/dist/org/plugin.js +2 -2
  171. package/dist/org/plugin.js.map +1 -1
  172. package/dist/progress/routes.d.ts +1 -1
  173. package/dist/scripts/call-agent.js +1 -1
  174. package/dist/scripts/call-agent.js.map +1 -1
  175. package/dist/scripts/db/safety.js +1 -1
  176. package/dist/scripts/db/safety.js.map +1 -1
  177. package/dist/server/auth.d.ts.map +1 -1
  178. package/dist/server/auth.js +3 -0
  179. package/dist/server/auth.js.map +1 -1
  180. package/dist/server/builder-design-systems.d.ts +28 -0
  181. package/dist/server/builder-design-systems.d.ts.map +1 -0
  182. package/dist/server/builder-design-systems.js +217 -0
  183. package/dist/server/builder-design-systems.js.map +1 -0
  184. package/dist/server/core-routes-plugin.d.ts +1 -0
  185. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  186. package/dist/server/core-routes-plugin.js +20 -3
  187. package/dist/server/core-routes-plugin.js.map +1 -1
  188. package/dist/server/index.d.ts +1 -0
  189. package/dist/server/index.d.ts.map +1 -1
  190. package/dist/server/index.js +1 -0
  191. package/dist/server/index.js.map +1 -1
  192. package/dist/server/transcribe-voice.d.ts +1 -1
  193. package/dist/styles/agent-native.css +14 -7
  194. package/dist/usage/store.js +2 -2
  195. package/dist/usage/store.js.map +1 -1
  196. package/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
  197. package/docs/content/locales/ar-SA/template-design.mdx +14 -1
  198. package/docs/content/locales/de-DE/skills-guide.mdx +5 -0
  199. package/docs/content/locales/de-DE/template-design.mdx +15 -1
  200. package/docs/content/locales/es-ES/skills-guide.mdx +5 -0
  201. package/docs/content/locales/es-ES/template-design.mdx +15 -1
  202. package/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
  203. package/docs/content/locales/fr-FR/template-design.mdx +15 -1
  204. package/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
  205. package/docs/content/locales/hi-IN/template-design.mdx +15 -1
  206. package/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
  207. package/docs/content/locales/ja-JP/template-design.mdx +16 -1
  208. package/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
  209. package/docs/content/locales/ko-KR/template-design.mdx +14 -1
  210. package/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
  211. package/docs/content/locales/pt-BR/template-design.mdx +14 -1
  212. package/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
  213. package/docs/content/locales/zh-CN/template-design.mdx +14 -1
  214. package/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
  215. package/docs/content/locales/zh-TW/template-design.mdx +14 -1
  216. package/docs/content/skills-guide.mdx +5 -0
  217. package/docs/content/template-design.mdx +14 -1
  218. package/package.json +1 -1
  219. package/corpus/templates/design/actions/import-figma-file.ts +0 -166
  220. package/corpus/templates/slides/server/lib/fig-design-system.ts +0 -110
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * The shared, template-agnostic Brand Kit surface. A Brand Kit unifies what
5
5
  * `design` and `slides` previously copy-pasted as a "design system": design
6
- * tokens + brand assets + custom instructions, extractable from Figma, code,
6
+ * tokens + brand assets + custom instructions, extractable from code,
7
7
  * GitHub, a URL, or documents, and used to generate on-brand content.
8
8
  *
9
9
  * This module is pure (no `defineAction`, no DB, no template imports). Templates
@@ -404,6 +404,10 @@ iframe-backed screens on the infinite canvas.
404
404
  iframe frame and URL metadata; change the copy's path/query for a new state.
405
405
  - Flow visualization is multiple URL states: \`/checkout?step=shipping\`,
406
406
  \`/checkout?step=payment\`, \`/checkout?step=done\`, etc.
407
+ - When the user gives a named flow or numbered screen list, preserve that order
408
+ and create one screen per URL/path. Shorthand like
409
+ \`localhost:1234/onboarding/1\` means
410
+ \`http://localhost:1234/onboarding/1\`.
407
411
 
408
412
  ## Required Local Bridge
409
413
 
@@ -439,6 +443,20 @@ pnpm action add-localhost-screens '{
439
443
  }'
440
444
  \`\`\`
441
445
 
446
+ For a numbered flow the user describes in chat, keep the labels and order:
447
+
448
+ \`\`\`bash
449
+ pnpm action add-localhost-screens '{
450
+ "designId": "<design-id>",
451
+ "connectionId": "<connection-id>",
452
+ "routes": [
453
+ { "url": "localhost:1234/onboarding/1", "title": "Screen 1" },
454
+ { "url": "localhost:1234/onboarding/2", "title": "Screen 2" },
455
+ { "url": "localhost:1234/onboarding/3", "title": "Screen 3" }
456
+ ]
457
+ }'
458
+ \`\`\`
459
+
442
460
  If no \`routes\` or \`paths\` are supplied, \`add-localhost-screens\` uses every
443
461
  route from the latest localhost manifest.
444
462
 
@@ -1318,7 +1318,7 @@ function AgentPanelInner({
1318
1318
  data-agent-page-new-chat=""
1319
1319
  aria-label={t("agentPanel.newChat")}
1320
1320
  onClick={() => {
1321
- void addTab();
1321
+ addTab();
1322
1322
  }}
1323
1323
  className="pointer-events-auto inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background/95 px-2.5 text-xs font-medium text-foreground shadow-sm backdrop-blur transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
1324
1324
  >
@@ -1625,7 +1625,7 @@ export function MultiTabAssistantChat({
1625
1625
  return next;
1626
1626
  });
1627
1627
  if (shouldRefreshThreads) {
1628
- void refreshThreads();
1628
+ refreshThreads();
1629
1629
  }
1630
1630
  }
1631
1631
  }
@@ -47,7 +47,7 @@ export interface AgentNativeExtensionStorageOptions {
47
47
  export interface AgentNativeExtensionStorageContext {
48
48
  extensionId: string;
49
49
  slotId?: string;
50
- scope?: Exclude<AgentNativeExtensionStorageScope, "all"> | string;
50
+ scope?: Exclude<AgentNativeExtensionStorageScope, "all">;
51
51
  userId?: string;
52
52
  organizationId?: string;
53
53
  [key: string]: unknown;
@@ -576,7 +576,7 @@ function joinAssistantChunks(previous: string, next: string): string {
576
576
  if (!next) return previous;
577
577
  if (/\s$/.test(previous) || /^\s/.test(next)) return `${previous}${next}`;
578
578
  if (/^[.,!?;:)\]}'"`]/.test(next)) return `${previous}${next}`;
579
- if (/[(\[{'"`]$/.test(previous)) return `${previous}${next}`;
579
+ if (/[([{'"`]$/.test(previous)) return `${previous}${next}`;
580
580
  return `${previous} ${next}`;
581
581
  }
582
582
 
@@ -19,10 +19,7 @@ export function extensionNameToSlug(
19
19
  return sliced || "extension";
20
20
  }
21
21
 
22
- export function extensionPath(
23
- id: string,
24
- name?: string | null | undefined,
25
- ): string {
22
+ export function extensionPath(id: string, name?: string | null): string {
26
23
  const encodedId = encodeURIComponent(id);
27
24
  if (name === undefined) return `/extensions/${encodedId}`;
28
25
  return `/extensions/${encodedId}/${extensionNameToSlug(name)}`;
@@ -528,7 +528,7 @@ function expandRelativeUrls(text: string, agentUrl: string): string {
528
528
  if (!text || !agentUrl) return text;
529
529
  const base = publicAgentBaseUrl(agentUrl);
530
530
  return text.replace(
531
- /(^|[\s(\[<"'`])(\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi,
531
+ /(^|[\s([<"'`])(\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi,
532
532
  (_match, lead, path) => `${lead}${base}${path}`,
533
533
  );
534
534
  }
@@ -1889,7 +1889,7 @@ async function isConnectTokenAllowed(
1889
1889
  */
1890
1890
  export async function verifyAuth(
1891
1891
  authHeader: string | undefined,
1892
- ownerEmailHeader?: string | undefined,
1892
+ ownerEmailHeader?: string,
1893
1893
  options: { allowDevOpen?: boolean; resourceUrl?: string | string[] } = {},
1894
1894
  ): Promise<{
1895
1895
  authed: boolean;
@@ -17,8 +17,8 @@ function extractInvitationId(event: H3Event): string | undefined {
17
17
  if (fromRouter) return fromRouter;
18
18
  const path = getRequestURL(event).pathname;
19
19
  const match =
20
- path.match(/^\/([^\/]+)\/accept\/?$/) ??
21
- path.match(/\/org\/invitations\/([^\/]+)\/accept\/?$/);
20
+ path.match(/^\/([^/]+)\/accept\/?$/) ??
21
+ path.match(/\/org\/invitations\/([^/]+)\/accept\/?$/);
22
22
  return match?.[1] ? decodeURIComponent(match[1]) : undefined;
23
23
  }
24
24
 
@@ -28,9 +28,9 @@ function extractMemberEmail(event: H3Event): string | undefined {
28
28
  if (fromRouter) return fromRouter;
29
29
  const path = getRequestURL(event).pathname;
30
30
  const match =
31
- path.match(/^\/([^\/]+)\/role\/?$/) ??
32
- path.match(/^\/([^\/]+)\/?$/) ??
33
- path.match(/\/org\/members\/([^\/]+)(?:\/role)?\/?$/);
31
+ path.match(/^\/([^/]+)\/role\/?$/) ??
32
+ path.match(/^\/([^/]+)\/?$/) ??
33
+ path.match(/\/org\/members\/([^/]+)(?:\/role)?\/?$/);
34
34
  return match?.[1] ? decodeURIComponent(match[1]) : undefined;
35
35
  }
36
36
  const nanoid = (): string =>
@@ -100,7 +100,7 @@ export function createOrgPlugin(): NitroPluginDef {
100
100
  return listMembersHandler(event);
101
101
  }
102
102
  // Tail is /:email/role
103
- if (/^\/[^\/]+\/role\/?$/.test(tail)) {
103
+ if (/^\/[^/]+\/role\/?$/.test(tail)) {
104
104
  if (method !== "PUT") {
105
105
  setResponseStatus(event, 405);
106
106
  return { error: "Method not allowed" };
@@ -129,7 +129,7 @@ export function createOrgPlugin(): NitroPluginDef {
129
129
  return { error: "Method not allowed" };
130
130
  }
131
131
  // Tail is /:id/accept
132
- if (/^\/[^\/]+\/accept\/?$/.test(tail)) {
132
+ if (/^\/[^/]+\/accept\/?$/.test(tail)) {
133
133
  if (method !== "POST") {
134
134
  setResponseStatus(event, 405);
135
135
  return { error: "Method not allowed" };
@@ -434,7 +434,7 @@ export function expandRelativeUrls(text: string, agentUrl: string): string {
434
434
  // Path must start at boundary (start, whitespace, or punctuation that isn't
435
435
  // ':' — to avoid mangling `https://example.com/foo` or markdown link bodies).
436
436
  return text.replace(
437
- /(^|[\s(\[<"'`])(\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi,
437
+ /(^|[\s([<"'`])(\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi,
438
438
  (_match, lead, path) => `${lead}${base}${path}`,
439
439
  );
440
440
  }
@@ -171,7 +171,7 @@ const ACCESS_CONTROL_COLUMN_TOKENS = new Set([
171
171
  function normalizeIdentifier(value: string): string {
172
172
  return value
173
173
  .trim()
174
- .replace(/^["'`\[]/, "")
174
+ .replace(/^["'`[]/, "")
175
175
  .replace(/["'`\]]$/, "")
176
176
  .toLowerCase();
177
177
  }
@@ -1855,6 +1855,9 @@ function createAuthGuardFn(): (
1855
1855
  // the gate below 401s anonymous /_agent-native/* requests before any DB
1856
1856
  // query, so the database would never get warmed.
1857
1857
  if (p === "/_agent-native/health") return;
1858
+ if (getMethod(event) === "GET" && p.startsWith("/_agent-native/avatar/")) {
1859
+ return;
1860
+ }
1858
1861
  if (isPublicPath(normalizedUrl, publicPaths)) return;
1859
1862
  if (shouldBypassAuthForBuilderConnect(event, p)) return;
1860
1863
  if (isPublicWorkspacePageRequest(event, p, config)) {
@@ -0,0 +1,308 @@
1
+ import { FeatureNotConfiguredError } from "./credential-provider.js";
2
+ import {
3
+ getBuilderProxyOrigin,
4
+ resolveBuilderCredentials,
5
+ } from "./credential-provider.js";
6
+
7
+ const DEFAULT_TIMEOUT_MS = 120_000;
8
+
9
+ export interface BuilderDesignSystemIndexFile {
10
+ name: string;
11
+ data: Uint8Array;
12
+ mimeType?: string;
13
+ }
14
+
15
+ export interface BuilderDesignSystemIndexOptions {
16
+ projectName?: string;
17
+ description?: string;
18
+ githubRepoUrl?: string;
19
+ connectedProjectId?: string;
20
+ files?: BuilderDesignSystemIndexFile[];
21
+ selection?: Record<string, string[]>;
22
+ devToolsVersion?: string;
23
+ }
24
+
25
+ export interface BuilderDesignSystemIndexResult {
26
+ ok: true;
27
+ source: "builder";
28
+ projectId: string;
29
+ jobId: string;
30
+ designSystemId: string;
31
+ suggestedTitle: string | null;
32
+ builderUrl: string;
33
+ status: "in-progress";
34
+ }
35
+
36
+ interface BuilderDesignSystemCredentials {
37
+ privateKey: string;
38
+ publicKey: string;
39
+ userId: string | null;
40
+ }
41
+
42
+ interface UploadStartResponse {
43
+ uploads?: Array<{ idx: number; uploadUrl: string; uploadToken: string }>;
44
+ }
45
+
46
+ interface GenerateResponse {
47
+ projectId?: string;
48
+ jobId?: string;
49
+ designSystemId?: string;
50
+ }
51
+
52
+ function trimTrailingSlash(value: string): string {
53
+ return value.replace(/\/+$/, "");
54
+ }
55
+
56
+ export function getBuilderDesignSystemsBaseUrl(): string {
57
+ return (
58
+ process.env.BUILDER_DESIGN_SYSTEMS_BASE_URL ||
59
+ `${trimTrailingSlash(getBuilderProxyOrigin())}/design-systems/v1`
60
+ );
61
+ }
62
+
63
+ function getBuilderAppHost(): string {
64
+ return (
65
+ process.env.BUILDER_APP_HOST ||
66
+ process.env.BUILDER_PUBLIC_APP_HOST ||
67
+ "https://builder.io"
68
+ );
69
+ }
70
+
71
+ function makeBuilderDesignSystemUrl(
72
+ path: string,
73
+ credentials: BuilderDesignSystemCredentials,
74
+ ): URL {
75
+ const base = `${trimTrailingSlash(getBuilderDesignSystemsBaseUrl())}/`;
76
+ const url = new URL(path.replace(/^\/+/, ""), base);
77
+ url.searchParams.set("apiKey", credentials.publicKey);
78
+ if (credentials.userId) url.searchParams.set("userId", credentials.userId);
79
+ return url;
80
+ }
81
+
82
+ function makeBuilderHeaders(
83
+ credentials: BuilderDesignSystemCredentials,
84
+ ): Record<string, string> {
85
+ return {
86
+ Authorization: `Bearer ${credentials.privateKey}`,
87
+ "x-builder-api-key": credentials.publicKey,
88
+ ...(credentials.userId ? { "x-builder-user-id": credentials.userId } : {}),
89
+ };
90
+ }
91
+
92
+ async function resolveBuilderDesignSystemCredentials(): Promise<BuilderDesignSystemCredentials> {
93
+ const credentials = await resolveBuilderCredentials();
94
+ if (!credentials.privateKey || !credentials.publicKey) {
95
+ throw new FeatureNotConfiguredError({
96
+ requiredCredential: "BUILDER_PRIVATE_KEY",
97
+ message:
98
+ "Connect Builder.io before indexing a design system from Figma or code.",
99
+ builderConnectUrl: "/_agent-native/builder/connect",
100
+ });
101
+ }
102
+ return {
103
+ privateKey: credentials.privateKey,
104
+ publicKey: credentials.publicKey,
105
+ userId: credentials.userId ?? null,
106
+ };
107
+ }
108
+
109
+ function mimeTypeForFile(file: BuilderDesignSystemIndexFile): string {
110
+ if (file.mimeType?.trim()) return file.mimeType.trim();
111
+ const lower = file.name.toLowerCase();
112
+ if (lower.endsWith(".fig")) return "application/octet-stream";
113
+ if (lower.endsWith(".pdf")) return "application/pdf";
114
+ if (lower.endsWith(".md") || lower.endsWith(".markdown"))
115
+ return "text/markdown";
116
+ if (lower.endsWith(".json")) return "application/json";
117
+ if (lower.endsWith(".css")) return "text/css";
118
+ return "text/plain";
119
+ }
120
+
121
+ function makeBody(bytes: Uint8Array, mimeType: string): BodyInit {
122
+ return typeof Blob !== "undefined"
123
+ ? new Blob([bytes as unknown as BlobPart], { type: mimeType })
124
+ : (bytes as unknown as BodyInit);
125
+ }
126
+
127
+ async function fetchWithTimeout(
128
+ url: string | URL,
129
+ init: RequestInit,
130
+ timeoutMs = DEFAULT_TIMEOUT_MS,
131
+ ): Promise<Response> {
132
+ const controller = new AbortController();
133
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
134
+ try {
135
+ return await fetch(url, { ...init, signal: controller.signal });
136
+ } finally {
137
+ clearTimeout(timer);
138
+ }
139
+ }
140
+
141
+ async function parseErrorBody(response: Response): Promise<string> {
142
+ const text = await response.text().catch(() => "");
143
+ if (!text) return response.statusText || `HTTP ${response.status}`;
144
+ try {
145
+ const json = JSON.parse(text) as { error?: unknown };
146
+ if (typeof json.error === "string") return json.error;
147
+ if (json.error && typeof json.error === "object") {
148
+ return JSON.stringify(json.error).slice(0, 500);
149
+ }
150
+ } catch {}
151
+ return text.replace(/\s+/g, " ").trim().slice(0, 500);
152
+ }
153
+
154
+ async function assertOk(response: Response, label: string): Promise<void> {
155
+ if (response.ok) return;
156
+ throw new Error(
157
+ `${label} (${response.status}): ${await parseErrorBody(response)}`,
158
+ );
159
+ }
160
+
161
+ async function uploadToResumableUrl(
162
+ slot: { uploadUrl: string },
163
+ file: BuilderDesignSystemIndexFile,
164
+ ): Promise<void> {
165
+ const mimeType = mimeTypeForFile(file);
166
+ const bytes = file.data;
167
+ const start = await fetchWithTimeout(slot.uploadUrl, {
168
+ method: "POST",
169
+ headers: {
170
+ "x-goog-resumable": "start",
171
+ "x-goog-content-length-range": `0,${bytes.byteLength}`,
172
+ "Content-Type": mimeType,
173
+ },
174
+ });
175
+ await assertOk(start, "Builder design-system upload session failed");
176
+ const sessionUrl = start.headers.get("Location");
177
+ if (!sessionUrl) {
178
+ throw new Error("Builder design-system upload session returned no URL.");
179
+ }
180
+
181
+ const response = await fetchWithTimeout(sessionUrl, {
182
+ method: "PUT",
183
+ headers: {
184
+ "Content-Range": `bytes 0-${bytes.byteLength - 1}/${bytes.byteLength}`,
185
+ "Content-Type": mimeType,
186
+ },
187
+ body: makeBody(bytes, mimeType),
188
+ });
189
+ await assertOk(response, "Builder design-system file upload failed");
190
+ }
191
+
192
+ function nonEmptyFiles(
193
+ files: BuilderDesignSystemIndexFile[] | undefined,
194
+ ): BuilderDesignSystemIndexFile[] {
195
+ return (files ?? []).filter((file) => file.data.byteLength > 0);
196
+ }
197
+
198
+ export function builderDesignSystemUrl(designSystemId?: string | null): string {
199
+ const host = trimTrailingSlash(getBuilderAppHost());
200
+ return designSystemId
201
+ ? `${host}/app/design-system-intelligence/${encodeURIComponent(
202
+ designSystemId,
203
+ )}`
204
+ : `${host}/app/design-system-intelligence`;
205
+ }
206
+
207
+ export async function startBuilderDesignSystemIndex(
208
+ options: BuilderDesignSystemIndexOptions,
209
+ ): Promise<BuilderDesignSystemIndexResult> {
210
+ const files = nonEmptyFiles(options.files);
211
+ const description = options.description?.trim();
212
+ if (description) {
213
+ files.unshift({
214
+ name: "additional-context.txt",
215
+ data: new TextEncoder().encode(description),
216
+ mimeType: "text/plain",
217
+ });
218
+ }
219
+ if (
220
+ files.length === 0 &&
221
+ !options.githubRepoUrl &&
222
+ !options.connectedProjectId
223
+ ) {
224
+ throw new Error(
225
+ "Provide at least one .fig/code/text file or a GitHub repository URL to index with Builder.",
226
+ );
227
+ }
228
+
229
+ const credentials = await resolveBuilderDesignSystemCredentials();
230
+ let uploadTokens: string[] = [];
231
+ if (files.length > 0) {
232
+ const uploadStart = await fetchWithTimeout(
233
+ makeBuilderDesignSystemUrl("upload/start", credentials),
234
+ {
235
+ method: "POST",
236
+ headers: {
237
+ ...makeBuilderHeaders(credentials),
238
+ "Content-Type": "application/json",
239
+ },
240
+ body: JSON.stringify({
241
+ attachments: files.map((file) => ({
242
+ name: file.name,
243
+ mimetype: mimeTypeForFile(file),
244
+ declaredSize: file.data.byteLength,
245
+ })),
246
+ }),
247
+ },
248
+ );
249
+ await assertOk(uploadStart, "Builder design-system upload start failed");
250
+ const uploadJson = (await uploadStart.json()) as UploadStartResponse;
251
+ const slots = [...(uploadJson.uploads ?? [])].sort((a, b) => a.idx - b.idx);
252
+ if (slots.length !== files.length) {
253
+ throw new Error("Builder did not return upload slots for all files.");
254
+ }
255
+ for (let i = 0; i < slots.length; i++) {
256
+ if (slots[i].idx !== i) {
257
+ throw new Error(`Builder upload slot mismatch: expected ${i}.`);
258
+ }
259
+ await uploadToResumableUrl(slots[i], files[i]);
260
+ }
261
+ uploadTokens = slots.map((slot) => slot.uploadToken);
262
+ }
263
+
264
+ const generate = await fetchWithTimeout(
265
+ makeBuilderDesignSystemUrl("generate", credentials),
266
+ {
267
+ method: "POST",
268
+ headers: {
269
+ ...makeBuilderHeaders(credentials),
270
+ "Content-Type": "application/json",
271
+ },
272
+ body: JSON.stringify({
273
+ uploads: uploadTokens,
274
+ ...(options.projectName?.trim()
275
+ ? { projectName: options.projectName.trim() }
276
+ : {}),
277
+ ...(options.githubRepoUrl?.trim()
278
+ ? { githubRepoUrl: options.githubRepoUrl.trim() }
279
+ : {}),
280
+ ...(options.connectedProjectId?.trim()
281
+ ? { connectedProjectId: options.connectedProjectId.trim() }
282
+ : {}),
283
+ ...(options.selection ? { selection: options.selection } : {}),
284
+ ...(options.devToolsVersion?.trim()
285
+ ? { devToolsVersion: options.devToolsVersion.trim() }
286
+ : {}),
287
+ }),
288
+ },
289
+ );
290
+ await assertOk(generate, "Builder design-system indexing failed");
291
+ const generated = (await generate.json()) as GenerateResponse;
292
+ if (!generated.projectId || !generated.jobId || !generated.designSystemId) {
293
+ throw new Error(
294
+ "Builder design-system indexing returned an incomplete response.",
295
+ );
296
+ }
297
+
298
+ return {
299
+ ok: true,
300
+ source: "builder",
301
+ projectId: generated.projectId,
302
+ jobId: generated.jobId,
303
+ designSystemId: generated.designSystemId,
304
+ suggestedTitle: options.projectName?.trim() || null,
305
+ builderUrl: builderDesignSystemUrl(generated.designSystemId),
306
+ status: "in-progress",
307
+ };
308
+ }
@@ -383,6 +383,31 @@ function parseBuilderCallbackBoolean(
383
383
  // inlines them in the DOM. Mirrors SAFE_DATA_IMAGE in sanitize-html.ts.
384
384
  export const AVATAR_RASTER_MIME = /^data:image\/(png|jpe?g|gif|webp);/i;
385
385
 
386
+ export function resolveAvatarEmailParam(
387
+ pathname: string,
388
+ appBasePath = "",
389
+ ): string {
390
+ const base = appBasePath.replace(/\/+$/, "");
391
+ const avatarPaths = Array.from(
392
+ new Set([`${base}/_agent-native/avatar/`, "/_agent-native/avatar/"]),
393
+ );
394
+
395
+ for (const avatarPath of avatarPaths) {
396
+ const avatarIndex = pathname.indexOf(avatarPath);
397
+ if (avatarIndex >= 0) {
398
+ return pathname
399
+ .slice(avatarIndex + avatarPath.length)
400
+ .replace(/^\/+/, "")
401
+ .split("/")[0];
402
+ }
403
+ }
404
+
405
+ const firstSegment = pathname.replace(/^\/+/, "").split("/")[0] ?? "";
406
+ if (!firstSegment || firstSegment === "_agent-native") return "";
407
+ if (base && firstSegment === base.replace(/^\/+/, "")) return "";
408
+ return firstSegment;
409
+ }
410
+
386
411
  async function detectUsageEngineName(
387
412
  event: H3Event,
388
413
  userEmail: string | undefined,
@@ -3010,9 +3035,10 @@ export function createCoreRoutesPlugin(
3010
3035
  `${P}/avatar`,
3011
3036
  defineEventHandler(async (event: H3Event) => {
3012
3037
  const method = getMethod(event);
3013
- const emailParam = (event.url?.pathname || "")
3014
- .replace(/^\/+/, "")
3015
- .split("/")[0];
3038
+ const emailParam = resolveAvatarEmailParam(
3039
+ event.url?.pathname || "",
3040
+ getConfiguredAppBasePath(),
3041
+ );
3016
3042
 
3017
3043
  if (method === "GET") {
3018
3044
  if (!emailParam) {
@@ -386,6 +386,14 @@ export {
386
386
  deleteBuilderCredentials,
387
387
  resolveSecret,
388
388
  } from "./credential-provider.js";
389
+ export {
390
+ builderDesignSystemUrl,
391
+ getBuilderDesignSystemsBaseUrl,
392
+ startBuilderDesignSystemIndex,
393
+ type BuilderDesignSystemIndexFile,
394
+ type BuilderDesignSystemIndexOptions,
395
+ type BuilderDesignSystemIndexResult,
396
+ } from "./builder-design-systems.js";
389
397
  export {
390
398
  getBuilderBranchProjectId,
391
399
  isBuilderBranchingEnabled,
@@ -162,6 +162,17 @@
162
162
  box-shadow 260ms cubic-bezier(0.32, 0.72, 0, 1);
163
163
  }
164
164
 
165
+ .agent-layout-main-surface::before,
166
+ .agent-sidebar-main-surface::before {
167
+ content: "";
168
+ position: absolute;
169
+ inset: 0;
170
+ z-index: 20;
171
+ pointer-events: none;
172
+ border-radius: inherit;
173
+ box-shadow: var(--agent-native-raised-outline);
174
+ }
175
+
165
176
  .agent-layout-shell
166
177
  :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
167
178
  > :first-child
@@ -213,23 +224,19 @@
213
224
  .agent-layout-shell > .agent-sidebar-shell > .agent-sidebar-main-surface {
214
225
  border-start-start-radius: var(--agent-native-raised-radius);
215
226
  border-end-start-radius: var(--agent-native-raised-radius);
216
- box-shadow:
217
- var(--agent-native-raised-outline), var(--agent-native-raised-shadow-left);
227
+ box-shadow: var(--agent-native-raised-shadow-left);
218
228
  }
219
229
 
220
230
  .agent-sidebar-main-surface[data-agent-sidebar-main-state="open"][data-agent-sidebar-main-position="right"] {
221
231
  border-start-end-radius: var(--agent-native-raised-radius);
222
232
  border-end-end-radius: var(--agent-native-raised-radius);
223
- box-shadow:
224
- var(--agent-native-raised-outline),
225
- var(--agent-native-raised-shadow-right);
233
+ box-shadow: var(--agent-native-raised-shadow-right);
226
234
  }
227
235
 
228
236
  .agent-sidebar-main-surface[data-agent-sidebar-main-state="open"][data-agent-sidebar-main-position="left"] {
229
237
  border-start-start-radius: var(--agent-native-raised-radius);
230
238
  border-end-start-radius: var(--agent-native-raised-radius);
231
- box-shadow:
232
- var(--agent-native-raised-outline), var(--agent-native-raised-shadow-left);
239
+ box-shadow: var(--agent-native-raised-shadow-left);
233
240
  }
234
241
  }
235
242
 
@@ -112,12 +112,12 @@ const PRICING: Array<{ match: RegExp; pricing: ModelPricing }> = [
112
112
  // ── Google Gemini ───────────────────────────────────────────────────────────
113
113
  // Gemini 3 Pro / 3.1 Pro: ~$1.25/$10 per MTok (approximate; verify on billing)
114
114
  {
115
- match: /gemini-3[\.\-]1-pro/i,
115
+ match: /gemini-3[.\-]1-pro/i,
116
116
  pricing: { input: 125, output: 1000, cacheRead: 31, cacheWrite: 0 },
117
117
  },
118
118
  // Gemini 3.5 Flash / 3 Flash: ~$0.15/$0.60 per MTok
119
119
  {
120
- match: /gemini-3[\.\-][0-9]+-flash/i,
120
+ match: /gemini-3[.\-][0-9]+-flash/i,
121
121
  pricing: { input: 15, output: 60, cacheRead: 4, cacheWrite: 0 },
122
122
  },
123
123
  // Gemini 2.5 Pro/Flash (catch-all for older 2.5)