@agent-native/core 0.157.0 → 0.157.2

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 (114) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +19 -4
  3. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +7 -2
  4. package/corpus/templates/assets/app/global.css +4 -0
  5. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +1 -2
  6. package/corpus/templates/brain/app/routes/sources.tsx +1 -2
  7. package/corpus/templates/calendar/app/hooks/use-bookings.ts +12 -2
  8. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +64 -2
  9. package/corpus/templates/calendar/server/handlers/bookings.ts +224 -93
  10. package/corpus/templates/calendar/server/plugins/auth.ts +0 -2
  11. package/corpus/templates/clips/actions/create-folder.ts +7 -1
  12. package/corpus/templates/clips/actions/create-meeting.ts +6 -2
  13. package/corpus/templates/clips/actions/create-recording.ts +5 -3
  14. package/corpus/templates/clips/actions/finalize-recording.ts +97 -65
  15. package/corpus/templates/clips/actions/import-loom-recording.ts +5 -3
  16. package/corpus/templates/clips/actions/request-recording-access.ts +305 -0
  17. package/corpus/templates/clips/actions/stitch-recordings.ts +5 -3
  18. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +38 -63
  19. package/corpus/templates/clips/app/components/player/share-dialog.tsx +75 -75
  20. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +3 -21
  21. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +13 -30
  22. package/corpus/templates/clips/app/i18n/en-US.ts +10 -0
  23. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +5 -5
  24. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +9 -16
  25. package/corpus/templates/clips/app/routes/share.$shareId.tsx +135 -18
  26. package/corpus/templates/clips/changelog/2026-08-14-long-resumable-uploads-now-abort-cleanly-and-show-errors.md +6 -0
  27. package/corpus/templates/clips/changelog/2026-08-14-standardized-share-popovers.md +6 -0
  28. package/corpus/templates/clips/chrome-extension/public/manifest.json +11 -3
  29. package/corpus/templates/clips/chrome-extension/src/github-preview-content.ts +37 -8
  30. package/corpus/templates/clips/chrome-extension/src/github-preview.ts +3 -3
  31. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +8 -25
  32. package/corpus/templates/clips/desktop/src/app.tsx +24 -0
  33. package/corpus/templates/clips/desktop/src/lib/media-capture-constraints.ts +42 -13
  34. package/corpus/templates/clips/desktop/src/lib/recorder.ts +11 -18
  35. package/corpus/templates/clips/desktop/src/overlays/onboarding.tsx +1 -0
  36. package/corpus/templates/clips/desktop/src/shared/config.ts +1 -0
  37. package/corpus/templates/clips/desktop/src/styles.css +24 -9
  38. package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +3 -0
  39. package/corpus/templates/clips/desktop/src-tauri/src/config.rs +8 -0
  40. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +154 -176
  41. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +115 -31
  42. package/corpus/templates/clips/desktop/src-tauri/src/rewind_clip.rs +7 -0
  43. package/corpus/templates/clips/server/db/index.ts +1 -0
  44. package/corpus/templates/clips/server/db/schema.ts +1 -0
  45. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +6 -1
  46. package/corpus/templates/clips/server/lib/emails.ts +23 -0
  47. package/corpus/templates/clips/server/lib/public-agent-context.ts +55 -0
  48. package/corpus/templates/clips/server/lib/recordings.ts +2 -1
  49. package/corpus/templates/clips/server/lib/resumable-upload-cleanup.ts +49 -0
  50. package/corpus/templates/clips/server/lib/s3-upload-provider.ts +34 -7
  51. package/corpus/templates/clips/server/lib/upload-interruption.ts +15 -1
  52. package/corpus/templates/clips/server/lib/upload-lease.ts +94 -9
  53. package/corpus/templates/clips/server/routes/api/agent-context.json.get.ts +82 -7
  54. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +1 -0
  55. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +71 -12
  56. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/interrupt.post.ts +4 -3
  57. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +133 -4
  58. package/corpus/templates/clips/server/routes/api/uploads/reap.post.ts +8 -1
  59. package/corpus/templates/clips/shared/recording-link.ts +4 -0
  60. package/corpus/templates/clips/shared/share-loader-response.ts +2 -1
  61. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +7 -16
  62. package/corpus/templates/factory/AGENTS.md +5 -1
  63. package/corpus/templates/factory/README.md +6 -2
  64. package/corpus/templates/factory/actions/view-screen.ts +15 -0
  65. package/corpus/templates/factory/app/components/factory/FactoryAgentsView.tsx +58 -189
  66. package/corpus/templates/factory/app/components/layout/Header.tsx +1 -0
  67. package/corpus/templates/factory/app/components/layout/Layout.tsx +1 -1
  68. package/corpus/templates/factory/app/components/layout/Sidebar.tsx +7 -0
  69. package/corpus/templates/factory/app/hooks/use-navigation-state.ts +3 -0
  70. package/corpus/templates/factory/app/i18n/en-US.ts +3 -1
  71. package/corpus/templates/factory/app/routes/agents.tsx +9 -0
  72. package/corpus/templates/mail/server/plugins/auth.ts +0 -2
  73. package/corpus/templates/plan/app/components/plan/LocalCodebasePicker.tsx +50 -14
  74. package/corpus/templates/plan/app/pages/PlansPage.tsx +9 -19
  75. package/corpus/templates/slides/app/components/editor/HistoryPanel.tsx +7 -1
  76. package/corpus/templates/slides/app/context/DeckContext.tsx +71 -22
  77. package/corpus/templates/slides/app/lib/editor-shortcuts.ts +46 -0
  78. package/corpus/templates/slides/app/pages/DeckEditor.tsx +13 -0
  79. package/dist/client/AgentPanel.d.ts +13 -1
  80. package/dist/client/AgentPanel.js +12 -10
  81. package/dist/client/AssistantChat.js +25 -5
  82. package/dist/client/HighlightedCodeBlock.js +12 -2
  83. package/dist/client/agent-chat/index.d.ts +1 -0
  84. package/dist/client/agent-chat/index.js +1 -0
  85. package/dist/client/chat/markdown-renderer.js +16 -3
  86. package/dist/client/chat-first/apps-rail.js +1 -1
  87. package/dist/client/components/ui/message-scroller.js +1 -1
  88. package/dist/client/settings/AccountSettingsCard.js +48 -19
  89. package/dist/client/sharing/ShareButton.d.ts +1 -2
  90. package/dist/client/sharing/ShareButton.js +5 -41
  91. package/dist/client/sharing/ShareDialog.js +5 -4
  92. package/dist/client/use-chat-threads.js +10 -14
  93. package/dist/collab/awareness.d.ts +2 -2
  94. package/dist/collab/routes.d.ts +1 -1
  95. package/dist/collab/struct-routes.d.ts +1 -1
  96. package/dist/localization/default-messages.d.ts +1 -0
  97. package/dist/localization/default-messages.js +1 -0
  98. package/dist/notifications/routes.d.ts +3 -3
  99. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  100. package/dist/provider-api/actions/provider-api.d.ts +15 -15
  101. package/dist/server/auth-marketing.d.ts +1 -0
  102. package/dist/server/auth-marketing.js +0 -2
  103. package/dist/server/auth.d.ts +1 -0
  104. package/dist/server/auth.js +18 -0
  105. package/dist/server/onboarding-html.d.ts +1 -0
  106. package/dist/server/onboarding-html.js +2 -88
  107. package/dist/server/realtime-token.d.ts +1 -1
  108. package/dist/shared/markdown-block-split.d.ts +16 -0
  109. package/dist/shared/markdown-block-split.js +81 -5
  110. package/dist/styles/agent-native.css +13 -0
  111. package/dist/voice/voice-cleanup-prompt.js +1 -0
  112. package/docs/content/cloneable-saas.mdx +24 -26
  113. package/package.json +3 -3
  114. package/corpus/templates/clips/shared/mic-audio-cleanup.ts +0 -350
@@ -115,8 +115,6 @@ const EN_AUTH_COPY = {
115
115
  localDevSigningIn: "Signing in locally…",
116
116
  localDevFailed: "Local development sign-in is unavailable.",
117
117
  localDevFullOptions: "Show full sign in options",
118
- runLocally: "Run Locally",
119
- runLocallySentence: "Run locally",
120
118
  openSource: "100% free and open source",
121
119
  useOwnGoogleClient: "Use your own Google OAuth client:",
122
120
  copyCommand: "Copy command",
@@ -218,8 +216,6 @@ const AUTH_LOCALE_COPY = {
218
216
  localDevSigningIn: "正在本地登录…",
219
217
  localDevFailed: "本地开发登录不可用。",
220
218
  localDevFullOptions: "显示完整登录选项",
221
- runLocally: "本地运行",
222
- runLocallySentence: "本地运行",
223
219
  openSource: "100% 免费且开源",
224
220
  useOwnGoogleClient: "使用你自己的 Google OAuth 客户端:",
225
221
  copyCommand: "复制命令",
@@ -319,8 +315,6 @@ const AUTH_LOCALE_COPY = {
319
315
  localDevSigningIn: "正在本機登入…",
320
316
  localDevFailed: "本機開發登入無法使用。",
321
317
  localDevFullOptions: "顯示完整登入選項",
322
- runLocally: "在本機執行",
323
- runLocallySentence: "在本機執行",
324
318
  openSource: "100% 免費且開源",
325
319
  useOwnGoogleClient: "使用你自己的 Google OAuth 用戶端:",
326
320
  copyCommand: "複製指令",
@@ -420,8 +414,6 @@ const AUTH_LOCALE_COPY = {
420
414
  localDevSigningIn: "Iniciando sesión localmente…",
421
415
  localDevFailed: "El inicio de sesión de desarrollo local no está disponible.",
422
416
  localDevFullOptions: "Mostrar todas las opciones de inicio de sesión",
423
- runLocally: "Ejecutar localmente",
424
- runLocallySentence: "Ejecutar localmente",
425
417
  openSource: "100% gratis y de código abierto",
426
418
  useOwnGoogleClient: "Usa tu propio cliente de Google OAuth:",
427
419
  copyCommand: "Copiar comando",
@@ -521,8 +513,6 @@ const AUTH_LOCALE_COPY = {
521
513
  localDevSigningIn: "Connexion locale…",
522
514
  localDevFailed: "La connexion de développement local est indisponible.",
523
515
  localDevFullOptions: "Afficher toutes les options de connexion",
524
- runLocally: "Exécuter localement",
525
- runLocallySentence: "Exécuter localement",
526
516
  openSource: "100 % gratuit et open source",
527
517
  useOwnGoogleClient: "Utilisez votre propre client Google OAuth :",
528
518
  copyCommand: "Copier la commande",
@@ -622,8 +612,6 @@ const AUTH_LOCALE_COPY = {
622
612
  localDevSigningIn: "Lokale Anmeldung…",
623
613
  localDevFailed: "Die lokale Entwicklungsanmeldung ist nicht verfügbar.",
624
614
  localDevFullOptions: "Alle Anmeldeoptionen anzeigen",
625
- runLocally: "Lokal ausführen",
626
- runLocallySentence: "Lokal ausführen",
627
615
  openSource: "100 % kostenlos und Open Source",
628
616
  useOwnGoogleClient: "Eigenen Google-OAuth-Client verwenden:",
629
617
  copyCommand: "Befehl kopieren",
@@ -723,8 +711,6 @@ const AUTH_LOCALE_COPY = {
723
711
  localDevSigningIn: "ローカルでサインイン中…",
724
712
  localDevFailed: "ローカル開発のサインインは利用できません。",
725
713
  localDevFullOptions: "完全なサインイン オプションを表示",
726
- runLocally: "ローカルで実行",
727
- runLocallySentence: "ローカルで実行",
728
714
  openSource: "100% 無料でオープンソース",
729
715
  useOwnGoogleClient: "自分の Google OAuth クライアントを使用:",
730
716
  copyCommand: "コマンドをコピー",
@@ -824,8 +810,6 @@ const AUTH_LOCALE_COPY = {
824
810
  localDevSigningIn: "로컬로 로그인하는 중…",
825
811
  localDevFailed: "로컬 개발 로그인을 사용할 수 없습니다.",
826
812
  localDevFullOptions: "전체 로그인 옵션 보기",
827
- runLocally: "로컬에서 실행",
828
- runLocallySentence: "로컬에서 실행",
829
813
  openSource: "100% 무료 오픈 소스",
830
814
  useOwnGoogleClient: "내 Google OAuth 클라이언트 사용:",
831
815
  copyCommand: "명령 복사",
@@ -925,8 +909,6 @@ const AUTH_LOCALE_COPY = {
925
909
  localDevSigningIn: "Entrando localmente…",
926
910
  localDevFailed: "O login de desenvolvimento local não está disponível.",
927
911
  localDevFullOptions: "Mostrar todas as opções de login",
928
- runLocally: "Executar localmente",
929
- runLocallySentence: "Executar localmente",
930
912
  openSource: "100% grátis e open source",
931
913
  useOwnGoogleClient: "Use seu próprio cliente Google OAuth:",
932
914
  copyCommand: "Copiar comando",
@@ -1026,8 +1008,6 @@ const AUTH_LOCALE_COPY = {
1026
1008
  localDevSigningIn: "स्थानीय रूप से साइन इन हो रहा है…",
1027
1009
  localDevFailed: "स्थानीय विकास साइन-इन उपलब्ध नहीं है।",
1028
1010
  localDevFullOptions: "साइन-इन के सभी विकल्प दिखाएं",
1029
- runLocally: "लोकल चलाएं",
1030
- runLocallySentence: "लोकल चलाएं",
1031
1011
  openSource: "100% मुफ्त और open source",
1032
1012
  useOwnGoogleClient: "अपना Google OAuth client उपयोग करें:",
1033
1013
  copyCommand: "कमांड कॉपी करें",
@@ -1127,8 +1107,6 @@ const AUTH_LOCALE_COPY = {
1127
1107
  localDevSigningIn: "جارٍ تسجيل الدخول محليًا…",
1128
1108
  localDevFailed: "تسجيل دخول التطوير المحلي غير متاح.",
1129
1109
  localDevFullOptions: "عرض خيارات تسجيل الدخول الكاملة",
1130
- runLocally: "تشغيل محليًا",
1131
- runLocallySentence: "تشغيل محليًا",
1132
1110
  openSource: "مجاني ومفتوح المصدر 100%",
1133
1111
  useOwnGoogleClient: "استخدم عميل Google OAuth الخاص بك:",
1134
1112
  copyCommand: "نسخ الأمر",
@@ -1335,7 +1313,6 @@ export function getOnboardingHtml(opts = {}) {
1335
1313
  features: marketing.features,
1336
1314
  }
1337
1315
  : undefined;
1338
- const runLocalCommand = marketing?.runLocalCommand?.trim();
1339
1316
  const signupLocalModeNote = isAgentNativeHostedHost(opts.requestHost) &&
1340
1317
  marketing?.signupLocalModeNote?.command.trim()
1341
1318
  ? {
@@ -1555,44 +1532,6 @@ ${localeMenuItemsHtml}
1555
1532
  gap: 0.75rem;
1556
1533
  margin-top: 2rem;
1557
1534
  }
1558
- .run-local-button {
1559
- display: inline-flex;
1560
- align-items: center;
1561
- justify-content: center;
1562
- min-height: 2.25rem;
1563
- padding: 0.5rem 0.875rem;
1564
- background: rgba(255,255,255,0.08);
1565
- color: #fff;
1566
- border: 1px solid rgba(255,255,255,0.14);
1567
- border-radius: 8px;
1568
- font-size: 0.8125rem;
1569
- font-weight: 500;
1570
- cursor: pointer;
1571
- }
1572
- .run-local-button:hover {
1573
- background: rgba(255,255,255,0.12);
1574
- border-color: rgba(255,255,255,0.24);
1575
- }
1576
- .run-local-panel {
1577
- max-width: 480px;
1578
- margin-top: 0.75rem;
1579
- padding: 0.75rem;
1580
- background: rgba(20,20,20,0.86);
1581
- border: 1px solid rgba(255,255,255,0.1);
1582
- border-radius: 10px;
1583
- box-shadow: 0 14px 36px rgba(0,0,0,0.28);
1584
- }
1585
- .run-local-panel[hidden] { display: none; }
1586
- .run-local-panel code {
1587
- display: block;
1588
- overflow-x: auto;
1589
- padding-bottom: 0.125rem;
1590
- color: #e5e5e5;
1591
- font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
1592
- font-size: 0.75rem;
1593
- line-height: 1.5;
1594
- white-space: nowrap;
1595
- }
1596
1535
  .copy-run-local {
1597
1536
  margin-top: 0.625rem;
1598
1537
  padding: 0.375rem 0.625rem;
@@ -1639,17 +1578,11 @@ ${localeMenuItemsHtml}
1639
1578
  ${marketing.description ? ` <p class="app-desc" data-marketing-field="description">${esc(marketing.description)}</p>\n` : ""}${marketing.features?.length
1640
1579
  ? ` <ul class="feature-list">\n${marketing.features.map((f, index) => ` <li data-marketing-feature-index="${index}">${esc(f)}</li>`).join("\n")}\n </ul>\n`
1641
1580
  : ""} <div class="marketing-actions">
1642
- ${runLocalCommand ? ` <button type="button" class="run-local-button" id="run-local-button" aria-expanded="false" aria-controls="run-local-panel" onclick="__anToggleRunLocalCommand()"${i18nAttr("runLocally")}>${esc(t("runLocally"))}</button>\n` : ""} <a class="oss-link" href="https://github.com/BuilderIO/agent-native" target="_blank" rel="noreferrer">
1581
+ <a class="oss-link" href="https://github.com/BuilderIO/agent-native" target="_blank" rel="noreferrer">
1643
1582
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-4.3 1.4-4.3-2.5-6-3m12 5v-3.5c0-1 .1-1.4-.5-2 2.8-.3 5.5-1.4 5.5-6a4.6 4.6 0 00-1.3-3.2 4.2 4.2 0 00-.1-3.2s-1.1-.3-3.5 1.3a12.3 12.3 0 00-6.2 0C6.5 2.8 5.4 3.1 5.4 3.1a4.2 4.2 0 00-.1 3.2A4.6 4.6 0 004 9.5c0 4.6 2.7 5.7 5.5 6-.6.6-.6 1.2-.5 2V21"/></svg>
1644
1583
  <span${i18nAttr("openSource")}>${esc(t("openSource"))}</span>
1645
1584
  </a>
1646
1585
  </div>
1647
- ${runLocalCommand
1648
- ? ` <div class="run-local-panel" id="run-local-panel" hidden data-command="${esc(runLocalCommand)}">
1649
- <code>${esc(runLocalCommand)}</code>
1650
- <button type="button" class="copy-run-local" id="copy-run-local" onclick="__anCopyRunLocalCommand()"${i18nAttr("copyCommand")}>${esc(t("copyCommand"))}</button>
1651
- </div>\n`
1652
- : ""}
1653
1586
  </div>
1654
1587
  </div>
1655
1588
  <div class="form-panel">`
@@ -4021,24 +3954,8 @@ ${renderGoogleButton
4021
3954
  }`
4022
3955
  : ""}
4023
3956
  ${starfieldScript}
4024
- ${runLocalCommand || signupLocalModeNote
3957
+ ${signupLocalModeNote
4025
3958
  ? `
4026
- function __anSetRunLocalCommandOpen(open) {
4027
- var panel = document.getElementById('run-local-panel');
4028
- var button = document.getElementById('run-local-button');
4029
- if (!panel || !button) return;
4030
- if (open) {
4031
- panel.removeAttribute('hidden');
4032
- } else {
4033
- panel.setAttribute('hidden', '');
4034
- }
4035
- button.setAttribute('aria-expanded', String(open));
4036
- }
4037
- function __anToggleRunLocalCommand() {
4038
- var panel = document.getElementById('run-local-panel');
4039
- if (!panel) return;
4040
- __anSetRunLocalCommandOpen(panel.hasAttribute('hidden'));
4041
- }
4042
3959
  function __anCopyCommandFromPanel(panelId, buttonId) {
4043
3960
  var panel = document.getElementById(panelId);
4044
3961
  var button = document.getElementById(buttonId);
@@ -4053,9 +3970,6 @@ ${runLocalCommand || signupLocalModeNote
4053
3970
  navigator.clipboard.writeText(command).then(markCopied).catch(function() {});
4054
3971
  }
4055
3972
  }
4056
- function __anCopyRunLocalCommand() {
4057
- __anCopyCommandFromPanel('run-local-panel', 'copy-run-local');
4058
- }
4059
3973
  function __anCopySignupLocalModeCommand() {
4060
3974
  __anCopyCommandFromPanel('signup-local-mode-note', 'copy-signup-local-mode');
4061
3975
  }
@@ -26,8 +26,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
26
26
  expiresAt?: undefined;
27
27
  ttlSeconds?: undefined;
28
28
  } | {
29
+ error?: undefined;
29
30
  token: string;
30
31
  expiresAt: string;
31
32
  ttlSeconds: number;
32
- error?: undefined;
33
33
  }>>;
@@ -12,6 +12,22 @@
12
12
  * it re-renders as the fence grows.
13
13
  * - Joining completedBlocks with "\n\n" + tail re-produces the original text
14
14
  * (modulo collapsed blank-line sequences, which don't affect rendered output).
15
+ *
16
+ * FIDELITY IS THE CONTRACT, not an optimization detail. Rendering the blocks
17
+ * separately must produce what rendering the whole document produces, because
18
+ * the same split drives both the streaming render and the final one. When the
19
+ * split was allowed to diverge, two things broke at once: the streamed text was
20
+ * visibly WRONG (a blank-line-separated list rendered as several one-item
21
+ * lists, a link whose reference definition landed in a later block rendered as
22
+ * literal `[text]`), and the end of the stream had to swap to a whole-document
23
+ * render to fix it — which rebuilt the message's entire DOM and produced the
24
+ * flash and scroll jump users reported. Two constructs reach across a blank
25
+ * line, so neither may be split:
26
+ * - lists, which continue across blank lines (and become "loose"), including
27
+ * indented fenced code blocks nested inside a list item
28
+ * - link-reference and footnote definitions, which resolve document-wide
29
+ * `markdown-block-split.spec.ts` asserts this parity construct by construct.
30
+ * Do not add a split rule without adding its parity case.
15
31
  */
16
32
  export interface MarkdownBlockSplit {
17
33
  /** Fully-terminated top-level blocks. Each element is the raw markdown for
@@ -1,3 +1,19 @@
1
+ /** A bullet or ordered list marker, at any indent depth. */
2
+ const LIST_MARKER = /^\s*(?:[-*+]|\d{1,9}[.)])\s/;
3
+ /** An indented continuation line — a paragraph or nested block inside a list item. */
4
+ const CONTINUATION_INDENT = /^\s{2,}\S/;
5
+ /**
6
+ * A link-reference or footnote definition (`[id]: url`, `[^1]: note`). These
7
+ * resolve across the whole document, so any block boundary can orphan a
8
+ * reference from its definition and render it as literal text.
9
+ */
10
+ const REFERENCE_DEFINITION = /^ {0,3}\[[^\]]+\]:\s*\S/;
11
+ /**
12
+ * An indented (4-space or tab) code block line. Like a list, an indented code
13
+ * block continues across blank lines, so splitting on one turns a single code
14
+ * block into several.
15
+ */
16
+ const INDENTED_CODE = /^(?: {4}|\t)/;
1
17
  /**
2
18
  * Split `text` into completed top-level markdown blocks and a trailing
3
19
  * in-progress tail.
@@ -15,6 +31,18 @@ export function splitMarkdownBlocks(text) {
15
31
  let fenceMarker = ""; // the opening marker: ``` or ~~~
16
32
  let currentBlockLines = [];
17
33
  let pendingBlanks = 0; // blank lines accumulated between blocks
34
+ // Whether the block being accumulated started as a list. A list swallows
35
+ // blank lines and keeps going, so its boundary is not decidable until a
36
+ // non-list, non-indented line arrives.
37
+ let currentBlockIsList = false;
38
+ // Same for an indented code block, which also swallows blank lines.
39
+ let currentBlockIsIndentedCode = false;
40
+ // Reference definitions are detected during the scan, NOT with a regex over
41
+ // the raw text: `[key: string]: string` inside a ```ts fence looks exactly
42
+ // like `[id]: url`, and this product emits TypeScript constantly. Testing the
43
+ // raw text disabled splitting for those whole messages, so every commit
44
+ // re-parsed the entire document — O(n²) rendering, which is its own jank.
45
+ let sawReferenceDefinition = false;
18
46
  for (let i = 0; i < lines.length; i++) {
19
47
  const line = lines[i];
20
48
  const trimmed = line.trimStart();
@@ -22,15 +50,30 @@ export function splitMarkdownBlocks(text) {
22
50
  // Detect a fence opening: line starts with ``` or ~~~ (3+ chars)
23
51
  const fenceMatch = /^(`{3,}|~{3,})/.exec(trimmed);
24
52
  if (fenceMatch) {
53
+ // An indented fence after a blank line is still a child of the active
54
+ // list item. Flushing here would render it as a top-level fence.
55
+ const continuesListWithIndentedFence = pendingBlanks > 0 &&
56
+ currentBlockLines.length > 0 &&
57
+ currentBlockIsList &&
58
+ CONTINUATION_INDENT.test(line);
25
59
  inFence = true;
26
60
  fenceMarker = fenceMatch[1].charAt(0).repeat(fenceMatch[1].length);
27
61
  // If there are pending blanks and existing content, flush the current
28
62
  // block before starting the fence block.
29
- if (pendingBlanks > 0 && currentBlockLines.length > 0) {
63
+ if (pendingBlanks > 0 &&
64
+ currentBlockLines.length > 0 &&
65
+ !continuesListWithIndentedFence) {
30
66
  completedBlocks.push(currentBlockLines.join("\n"));
31
67
  currentBlockLines = [];
32
68
  }
69
+ if (continuesListWithIndentedFence) {
70
+ for (let blank = 0; blank < pendingBlanks; blank++) {
71
+ currentBlockLines.push("");
72
+ }
73
+ }
33
74
  pendingBlanks = 0;
75
+ if (currentBlockLines.length === 0)
76
+ currentBlockIsList = false;
34
77
  currentBlockLines.push(line);
35
78
  continue;
36
79
  }
@@ -41,14 +84,36 @@ export function splitMarkdownBlocks(text) {
41
84
  }
42
85
  // Non-blank, non-fence line outside a fence
43
86
  if (pendingBlanks > 0 && currentBlockLines.length > 0) {
44
- // We have a completed block followed by blank lines
45
- completedBlocks.push(currentBlockLines.join("\n"));
46
- currentBlockLines = [];
87
+ // A list continues across blank lines: a following list marker is the
88
+ // next item, and an indented line is a continuation paragraph inside
89
+ // the current item. Splitting either one produces several separate
90
+ // lists instead of one, and drops continuation text out of its item.
91
+ const continuesList = currentBlockIsList &&
92
+ (LIST_MARKER.test(line) || CONTINUATION_INDENT.test(line));
93
+ const continuesIndentedCode = currentBlockIsIndentedCode && INDENTED_CODE.test(line);
94
+ if (continuesList || continuesIndentedCode) {
95
+ // Keep the blank lines: they are what makes the list "loose", which
96
+ // changes how it renders.
97
+ for (let blank = 0; blank < pendingBlanks; blank++) {
98
+ currentBlockLines.push("");
99
+ }
100
+ }
101
+ else {
102
+ completedBlocks.push(currentBlockLines.join("\n"));
103
+ currentBlockLines = [];
104
+ }
47
105
  pendingBlanks = 0;
48
106
  }
49
107
  else {
50
108
  pendingBlanks = 0;
51
109
  }
110
+ if (currentBlockLines.length === 0) {
111
+ currentBlockIsIndentedCode = INDENTED_CODE.test(line);
112
+ currentBlockIsList =
113
+ !currentBlockIsIndentedCode && LIST_MARKER.test(line);
114
+ }
115
+ if (REFERENCE_DEFINITION.test(line))
116
+ sawReferenceDefinition = true;
52
117
  currentBlockLines.push(line);
53
118
  }
54
119
  else {
@@ -72,8 +137,19 @@ export function splitMarkdownBlocks(text) {
72
137
  }
73
138
  // If we ended outside a fence with trailing blank lines, the last content
74
139
  // block is complete — flush it and return an empty tail.
140
+ // A definition makes every boundary unsafe: the reference may sit in any
141
+ // other block, and splitting orphans it into literal `[text]`.
142
+ if (sawReferenceDefinition) {
143
+ return { completedBlocks: [], tail: text };
144
+ }
75
145
  let tail;
76
- if (!inFence && pendingBlanks > 0 && currentBlockLines.length > 0) {
146
+ if (!inFence &&
147
+ !currentBlockIsList &&
148
+ !currentBlockIsIndentedCode &&
149
+ pendingBlanks > 0 &&
150
+ currentBlockLines.length > 0) {
151
+ // A trailing blank line does not end a list — the next streamed chunk may
152
+ // add another item. Leave it in the tail so it stays one list.
77
153
  completedBlocks.push(currentBlockLines.join("\n"));
78
154
  tail = "";
79
155
  }
@@ -213,6 +213,19 @@
213
213
  transition: none !important;
214
214
  }
215
215
 
216
+ .agent-sidebar-resize-overlay {
217
+ position: fixed;
218
+ inset: 0;
219
+ z-index: 90;
220
+ cursor: col-resize;
221
+ user-select: none;
222
+ }
223
+
224
+ .agent-sidebar-shell[data-agent-sidebar-resizing="true"] iframe,
225
+ .agent-sidebar-shell[data-agent-sidebar-resizing="true"] webview {
226
+ pointer-events: none !important;
227
+ }
228
+
216
229
  .agent-native-app-main {
217
230
  container: agent-native-main / inline-size;
218
231
  }
@@ -14,6 +14,7 @@ export function buildVoiceGuidanceBlock({ instructions, contextPack, }) {
14
14
  const sections = [
15
15
  "Use the following voice guidance only to improve transcription, cleanup, terminology, casing, punctuation, and formatting.",
16
16
  "Never add facts or content that are not present in the audio or transcript.",
17
+ "When audio input is available, treat it as the primary source of intent, names, and corrections.",
17
18
  ];
18
19
  if (customInstructions) {
19
20
  sections.push(`User instructions:\n${customInstructions}`);
@@ -1,19 +1,17 @@
1
1
  ---
2
2
  title: "Templates"
3
- description: "Start from a working SaaS product and make it yours — agent included."
3
+ description: "Start from a complete SaaS product with a UI, database, auth, and agent already built."
4
4
  ---
5
5
 
6
6
  # Templates
7
7
 
8
- Want to ship your own AI-powered analytics tool? Mail client? Forms builder? Pick a template, and you've got a working SaaS in minutes — agent, database, auth, and deploy pipeline already wired up.
8
+ Agent-Native apps come in two shapes: templates, which have a full browser UI, and automation-first apps, which don't — a Slack bot, a nightly report, a webhook responder. This doc covers templates; see [Automation-First Apps](/docs/pure-agent-apps) for the other shape.
9
9
 
10
- Most starter templates give you a blank scaffold and a long TODO list. Agent-native flips that. Each template is a **complete, SaaS-grade product** — already runnable on day one, already shippable, and entirely yours to customize, brand, and deploy. Think of them as Cloneable SaaS, not starter kits: you're starting from a finished product, not staring at boilerplate.
11
-
12
- Building a workflow with no browser UI at all — a Slack bot, a nightly report, a webhook responder? See [Automation-First Apps](/docs/pure-agent-apps) instead; the templates on this page all ship a full browser UI alongside the agent.
10
+ A template is a complete SaaS product: a UI, database, auth, and agent, already built and wired together. Pick one, brand it, and deploy it as your own product instead of starting from a blank scaffold. This model is called Cloneable SaaS: you start from a finished product, not a scaffold.
13
11
 
14
12
  ## Example apps {#catalog}
15
13
 
16
- Each one is a real app you could use today, and the launching pad for your own version of it.
14
+ Each app is a complete product you can run today and customize into your own.
17
15
 
18
16
  | App | What it is |
19
17
  | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
@@ -31,9 +29,9 @@ Each one is a real app you could use today, and the launching pad for your own v
31
29
  | [**Plan**](/docs/template-plan) | Visual plans and PR recaps with diagrams, wireframes, and annotations. |
32
30
  | [**Dispatch**](/docs/template-dispatch) | The workspace control plane: shared secrets, reusable integrations, Slack/Telegram, scheduled jobs. |
33
31
 
34
- Don't want a domain app? Use [Chat](/docs/template-chat) when you want a basic app users can talk to immediately and extend with actions, native results, and screens. Use [Automation-First Apps](/docs/pure-agent-apps) only when the workflow truly does not need a browser UI yet.
32
+ If none of these match your domain, start with [Chat](/docs/template-chat) and extend it with actions, native results, and screens. Use [Automation-First Apps](/docs/pure-agent-apps) if your workflow doesn't need a browser UI.
35
33
 
36
- See the full catalog under [Apps](/apps), or jump straight to one — for example, [Dispatch](/docs/template-dispatch) is a great place to start if you want a workspace-style app.
34
+ Each app has its own docs covering its architecture, actions, and customization. Browse live hosted versions at [agent-native.com/apps](/apps), or start with [Dispatch](/docs/template-dispatch) for a workspace-style app.
37
35
 
38
36
  ## Community templates {#community-templates}
39
37
 
@@ -151,20 +149,20 @@ details, the tested CLI command, and an optional hosted demo URL.
151
149
 
152
150
  ## What you get out of the box {#what-you-get}
153
151
 
154
- Every example app ships with the parts that normally take months to build:
152
+ Every example app includes:
155
153
 
156
- - **A working agent** — already wired into the app, already able to take actions on your data, already context-aware about what you're looking at. See [Messaging the agent](/docs/messaging) for how it works.
157
- - **Auth** — sign in, sessions, organizations, multi-tenant isolation. Already done.
158
- - **A database** — every example app has its schema, queries, and migrations ready to go. Bring your own SQL database (Postgres, SQLite, Turso, D1) — the framework adapts.
159
- - **A real-time UI** — the screen stays in sync with what the agent does. Click "draft an email" in chat, watch the draft appear in your inbox immediately.
160
- - **Deploy-ready** — push to Netlify, Vercel, Cloudflare, AWS, or anywhere else that runs Node. No vendor lock-in.
161
- - **Branding hooks** — name, colors, logo, copy are all easy to change.
154
+ - **A working agent** — wired into the app, able to take actions on your data, and aware of what you're looking at. See [Messaging the agent](/docs/messaging).
155
+ - **Auth** — sign-in, sessions, organizations, and multi-tenant isolation.
156
+ - **A database** — schema, queries, and migrations, ready to use. Bring your own SQL database (Postgres, SQLite, Turso, D1); the framework adapts.
157
+ - **A real-time UI** — the screen stays in sync with the agent. For example, drafting an email in chat updates the inbox immediately.
158
+ - **Deploy-ready** — deploy to Netlify, Vercel, Cloudflare, AWS, or any host that runs Node.
159
+ - **Branding hooks** — change the name, colors, logo, and copy.
162
160
 
163
- This isn't a theoretical claim. The framework's author runs his actual inbox on the Mail app, his actual calendar on the Calendar app, and his actual analytics on the Analytics app. These are daily-driver apps.
161
+ The framework's maintainer runs his email, calendar, and analytics on the Mail, Calendar, and Analytics apps.
164
162
 
165
163
  ## What you do {#what-you-do}
166
164
 
167
- The path from "I want my own SaaS" to "I have my own SaaS" is short:
165
+ Four steps take you from template to deployed app:
168
166
 
169
167
  <Diagram id="doc-block-1ab5jb9" title="Start from a working app" summary="Pick a finished product, brand it, evolve it in plain English, and ship it to your own domain.">
170
168
 
@@ -214,21 +212,21 @@ The path from "I want my own SaaS" to "I have my own SaaS" is short:
214
212
 
215
213
  </Diagram>
216
214
 
217
- 1. **Pick an example app.** Use the CLI picker, or browse the docs and pick one to start from.
215
+ 1. **Pick an app.** Use the CLI picker, or browse the docs.
218
216
  2. **Brand it.** Change the name, colors, logo, and copy. Most example apps expose this in a single config file.
219
217
  3. **Customize it.** Make source changes in your own repository and development workflow. An agent can help when its frame is intentionally granted workspace and write tooling; otherwise the embedded agent operates the resulting app through its actions, data, and configured integrations.
220
- 4. **Ship it.** Run the deploy command. You now have your own production SaaS at your own domain.
218
+ 4. **Ship it.** Run the deploy command. You now have a production app at your own domain.
221
219
 
222
- Steps 2–4 typically take days, not months. Step 3 is open-ended because the app is yours to evolve, while the embedded agent remains available to operate the deployed product and can assist with source changes when code access is explicitly enabled.
220
+ Steps 2–4 typically take a few days. Step 3 has no fixed end point — the app is yours to evolve, while the embedded agent remains available to operate the deployed product and can assist with source changes when code access is explicitly enabled.
223
221
 
224
222
  ## Why this is practical {#why}
225
223
 
226
- A separate-codebase-per-user model breaks down at scale: every user maintaining their own inbox sounds like a maintenance nightmare. Two framework decisions make it work:
224
+ A separate codebase per user doesn't scale — maintaining a fork of the app for every user becomes unmanageable. Two framework decisions avoid that:
227
225
 
228
226
  1. **The app keeps the framework contract.** Your source owns the domain behavior, while Core keeps actions, SQL, state, and sync consistent as the app evolves.
229
227
  2. **Per-user customization without per-user code.** Skills, memory, instructions, connected MCP servers, and sub-agents all live in SQL. Every user gets their own customization layer; the shared codebase hosts all of them at once.
230
228
 
231
- The result: Claude-Code-level flexibility for each user, with normal SaaS deployment economics.
229
+ The result: per-user customization without per-user deployments.
232
230
 
233
231
  <Diagram id="doc-block-bhg7mw" title="Why per-user customization scales" summary={"Two ideas keep the start-from-a-working-app model practical: the app keeps the framework contract, and per-user customization lives in SQL — not in per-user code."}>
234
232
 
@@ -275,11 +273,11 @@ The result: Claude-Code-level flexibility for each user, with normal SaaS deploy
275
273
 
276
274
  ## Don't want to customize? {#hosted}
277
275
 
278
- You don't have to. Every example app is also available as a hosted app on `agent-native.com` — `mail.agent-native.com`, `calendar.agent-native.com`, and so on. Use the hosted version for free or paid; create your own app from a template when you want to change something the hosted version doesn't expose.
276
+ Every example app is also available as a hosted product on `agent-native.com` — `mail.agent-native.com`, `calendar.agent-native.com`, and so on. Use the hosted version for free or paid; create your own app from a template when you want to change something the hosted version doesn't expose.
279
277
 
280
278
  ## Try it with a skill {#try-with-a-skill}
281
279
 
282
- Not ready to scaffold? You can add agent-native superpowers to a coding agent you already use with a single command — no app needed. See the [Skills Guide](/docs/skills-guide#app-backed-skills).
280
+ You can add Agent-Native capabilities to a coding agent you already use, without scaffolding an app. See the [Skills Guide](/docs/skills-guide#app-backed-skills).
283
281
 
284
282
  ## What's next
285
283
 
@@ -292,7 +290,7 @@ Not ready to scaffold? You can add agent-native superpowers to a coding agent yo
292
290
 
293
291
  ### For developers {#dev-details}
294
292
 
295
- If you're scaffolding now, the CLI command is:
293
+ To scaffold a new app:
296
294
 
297
295
  ```bash
298
296
  npx @agent-native/core@latest create my-platform
@@ -306,7 +304,7 @@ scaffolded into `apps/<name>/` with every file you need. For a no-browser
306
304
  automation instead of an app UI, use
307
305
  `npx @agent-native/core@latest create my-agent --headless`.
308
306
 
309
- Fill in `.env` (mostly `ANTHROPIC_API_KEY` and `DATABASE_URL`), `pnpm install`, `pnpm dev`, and it works. No "TODO: implement login," no placeholder routes.
307
+ Fill in `.env` (`ANTHROPIC_API_KEY` and `DATABASE_URL`), then run `pnpm install` and `pnpm dev`. There's no login to implement and no placeholder routes.
310
308
 
311
309
  Deploy targets: any Nitro-compatible host (Node, Cloudflare, Netlify, Vercel, Deno, Lambda, Bun) and any Drizzle-compatible SQL database (SQLite, Postgres, Turso, D1, Supabase, Neon). For workspaces, `npx @agent-native/core@latest deploy` builds every app at once and ships them behind a single origin. See [Deployment](/docs/deployment).
312
310
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.157.0",
3
+ "version": "0.157.2",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -423,8 +423,8 @@
423
423
  "y-protocols": "^1.0.7",
424
424
  "yjs": "^13.6.31",
425
425
  "zod": "^4.3.6",
426
- "@agent-native/recap-cli": "0.5.4",
427
- "@agent-native/toolkit": "^0.15.0"
426
+ "@agent-native/toolkit": "^0.15.1",
427
+ "@agent-native/recap-cli": "0.5.4"
428
428
  },
429
429
  "devDependencies": {
430
430
  "@ai-sdk/anthropic": "^3.0.71",