@agent-native/core 0.121.2 → 0.122.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 (588) hide show
  1. package/README.md +4 -12
  2. package/corpus/README.md +2 -2
  3. package/corpus/core/CHANGELOG.md +148 -0
  4. package/corpus/core/docs/content/actions.mdx +2 -2
  5. package/corpus/core/docs/content/agent-surfaces.mdx +1 -1
  6. package/corpus/core/docs/content/authentication.mdx +2 -0
  7. package/corpus/core/docs/content/deployment.mdx +36 -0
  8. package/corpus/core/docs/content/http-api.mdx +266 -0
  9. package/corpus/core/docs/content/syncing-template-changes.mdx +159 -0
  10. package/corpus/core/package.json +2 -1
  11. package/corpus/core/src/a2a/activity.ts +38 -27
  12. package/corpus/core/src/a2a/client.ts +57 -4
  13. package/corpus/core/src/agent/engine/builder-engine.ts +35 -4
  14. package/corpus/core/src/agent/run-manager.ts +20 -1
  15. package/corpus/core/src/agent/run-store.ts +4 -1
  16. package/corpus/core/src/agent/types.ts +28 -8
  17. package/corpus/core/src/chat-threads/store.ts +45 -0
  18. package/corpus/core/src/checkpoints/index.ts +2 -0
  19. package/corpus/core/src/checkpoints/route-match.ts +13 -0
  20. package/corpus/core/src/cli/create.ts +105 -17
  21. package/corpus/core/src/cli/index.ts +20 -0
  22. package/corpus/core/src/cli/template-baseline.ts +410 -0
  23. package/corpus/core/src/cli/template-sync.ts +1004 -0
  24. package/corpus/core/src/cli/templates-meta.ts +1 -0
  25. package/corpus/core/src/client/AssistantChat.tsx +38 -12
  26. package/corpus/core/src/client/NewWorkspaceAppFlow.tsx +75 -10
  27. package/corpus/core/src/client/chat/message-components.tsx +127 -66
  28. package/corpus/core/src/client/chat/tool-call-display.tsx +29 -5
  29. package/corpus/core/src/client/error-format.ts +18 -0
  30. package/corpus/core/src/client/org/OrgSwitcher.tsx +30 -8
  31. package/corpus/core/src/client/org/TeamPage.tsx +7 -6
  32. package/corpus/core/src/client/settings/SettingsPanel.tsx +9 -9
  33. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +12 -2
  34. package/corpus/core/src/client/sse-event-processor.ts +3 -0
  35. package/corpus/core/src/data-widgets/index.ts +41 -0
  36. package/corpus/core/src/deploy/build.ts +11 -9
  37. package/corpus/core/src/extensions/url-safety.ts +67 -4
  38. package/corpus/core/src/integrations/webhook-handler.ts +63 -9
  39. package/corpus/core/src/org/auto-join-domain.ts +4 -3
  40. package/corpus/core/src/org/context.ts +108 -39
  41. package/corpus/core/src/org/index.ts +5 -0
  42. package/corpus/core/src/org/service-identity.ts +60 -0
  43. package/corpus/core/src/provider-api/index.ts +22 -1
  44. package/corpus/core/src/scripts/docs/search.ts +12 -1
  45. package/corpus/core/src/server/agent-chat/context-tools.ts +9 -4
  46. package/corpus/core/src/server/agent-chat/framework-prompts.ts +38 -66
  47. package/corpus/core/src/server/agent-chat-plugin.ts +17 -10
  48. package/corpus/core/src/server/agents-bundle.ts +84 -5
  49. package/corpus/core/src/server/auth.ts +4 -3
  50. package/corpus/core/src/server/builder-browser.ts +47 -19
  51. package/corpus/core/src/server/core-routes-plugin.ts +2 -2
  52. package/corpus/core/src/server/credential-provider.ts +209 -68
  53. package/corpus/core/src/server/index.ts +3 -0
  54. package/corpus/core/src/server/prompts/framework-core-compact.ts +6 -13
  55. package/corpus/core/src/server/prompts/framework-core.ts +9 -21
  56. package/corpus/core/src/server/prompts/index.ts +0 -1
  57. package/corpus/core/src/server/prompts/shared-rules.ts +19 -11
  58. package/corpus/core/src/server/ssr-handler.ts +13 -2
  59. package/corpus/core/src/settings/user-settings.ts +13 -1
  60. package/corpus/core/src/shared/cache-control.ts +141 -0
  61. package/corpus/core/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  62. package/corpus/core/src/templates/chat/_gitignore +1 -0
  63. package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +0 -7
  64. package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  65. package/corpus/core/src/templates/default/app/root.tsx +1 -1
  66. package/corpus/core/src/templates/default/public/manifest.json +2 -2
  67. package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  68. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
  69. package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  70. package/corpus/core/src/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
  71. package/corpus/core/src/vite/agents-bundle-plugin.ts +7 -6
  72. package/corpus/core/src/vite/client.ts +69 -3
  73. package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +4 -5
  74. package/corpus/templates/analytics/.agents/skills/admin-surfaces/SKILL.md +55 -0
  75. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +10 -0
  76. package/corpus/templates/analytics/.agents/skills/dashboard-management/references/template-catalog-and-demo.md +62 -0
  77. package/corpus/templates/analytics/.agents/skills/dashboard-ops/SKILL.md +85 -0
  78. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +27 -2
  79. package/corpus/templates/analytics/.agents/skills/data-querying/references/inline-chart-embeds.md +139 -0
  80. package/corpus/templates/analytics/.agents/skills/monitoring/SKILL.md +77 -0
  81. package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  82. package/corpus/templates/analytics/AGENTS.md +91 -563
  83. package/corpus/templates/analytics/_gitignore +1 -0
  84. package/corpus/templates/analytics/actions/bigquery.ts +12 -4
  85. package/corpus/templates/analytics/actions/generate-chart.ts +5 -5
  86. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +30 -1
  87. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -23
  88. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +3 -0
  89. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +1 -1
  90. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +1 -0
  91. package/corpus/templates/analytics/app/routes/_index.tsx +1 -1
  92. package/corpus/templates/analytics/changelog/2026-07-24-analytics-finds-saved-dashboards-and-queries-far-more-reliab.md +6 -0
  93. package/corpus/templates/analytics/changelog/2026-07-24-notion-access-errors-now-explain-that-a-page-needs-sharing-w.md +6 -0
  94. package/corpus/templates/analytics/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  95. package/corpus/templates/analytics/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  96. package/corpus/templates/analytics/package.json +1 -1
  97. package/corpus/templates/analytics/public/manifest.json +1 -1
  98. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +7 -0
  99. package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +191 -30
  100. package/corpus/templates/analytics/server/lib/bigquery.ts +11 -1
  101. package/corpus/templates/analytics/server/lib/notion.ts +15 -4
  102. package/corpus/templates/analytics/server/plugins/agent-chat.ts +10 -0
  103. package/corpus/templates/analytics/server/plugins/auth.ts +1 -1
  104. package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  105. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +0 -2
  106. package/corpus/templates/assets/app/routes/_index.tsx +1 -1
  107. package/corpus/templates/assets/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  108. package/corpus/templates/assets/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  109. package/corpus/templates/assets/server/plugins/auth.ts +1 -1
  110. package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  111. package/corpus/templates/brain/_gitignore +1 -0
  112. package/corpus/templates/brain/app/lib/brain.ts +0 -7
  113. package/corpus/templates/brain/app/routes/_index.tsx +1 -2
  114. package/corpus/templates/brain/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  115. package/corpus/templates/brain/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  116. package/corpus/templates/brain/package.json +1 -1
  117. package/corpus/templates/brain/public/manifest.json +1 -1
  118. package/corpus/templates/brain/server/plugins/auth.ts +1 -1
  119. package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  120. package/corpus/templates/calendar/_gitignore +1 -0
  121. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +0 -6
  122. package/corpus/templates/calendar/app/routes/_app._index.tsx +1 -1
  123. package/corpus/templates/calendar/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  124. package/corpus/templates/calendar/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  125. package/corpus/templates/calendar/package.json +1 -1
  126. package/corpus/templates/calendar/public/manifest.json +1 -1
  127. package/corpus/templates/calendar/server/plugins/auth.ts +1 -1
  128. package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  129. package/corpus/templates/chat/_gitignore +1 -0
  130. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +0 -7
  131. package/corpus/templates/chat/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  132. package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  133. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +34 -0
  134. package/corpus/templates/clips/AGENTS.md +5 -4
  135. package/corpus/templates/clips/_gitignore +1 -0
  136. package/corpus/templates/clips/actions/cleanup-transcript.ts +5 -0
  137. package/corpus/templates/clips/actions/get-recording-insights.ts +44 -8
  138. package/corpus/templates/clips/actions/get-recording-player-data.ts +39 -70
  139. package/corpus/templates/clips/actions/import-loom-recording.ts +53 -98
  140. package/corpus/templates/clips/actions/lib/loom-import-job.ts +260 -0
  141. package/corpus/templates/clips/actions/list-clip-views.ts +2 -4
  142. package/corpus/templates/clips/actions/list-recordings.ts +69 -19
  143. package/corpus/templates/clips/actions/list-viewers.ts +5 -2
  144. package/corpus/templates/clips/actions/regenerate-summary.ts +5 -1
  145. package/corpus/templates/clips/actions/request-transcript.ts +28 -1
  146. package/corpus/templates/clips/app/components/editor/stitch-manager.tsx +21 -1
  147. package/corpus/templates/clips/app/components/library/library-layout.tsx +0 -7
  148. package/corpus/templates/clips/app/components/meetings/quick-ask-sidebar.tsx +14 -1
  149. package/corpus/templates/clips/app/components/player/insights-panel.tsx +8 -20
  150. package/corpus/templates/clips/app/components/player/recording-views-badge.tsx +335 -0
  151. package/corpus/templates/clips/app/components/player/video-player.tsx +13 -8
  152. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +2 -1
  153. package/corpus/templates/clips/app/i18n/en-US.ts +13 -2
  154. package/corpus/templates/clips/app/lib/capture-permissions.ts +110 -0
  155. package/corpus/templates/clips/app/lib/recording-link.ts +32 -0
  156. package/corpus/templates/clips/app/routes/_app.library._index.tsx +1 -1
  157. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +27 -0
  158. package/corpus/templates/clips/app/routes/_index.tsx +1 -1
  159. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +52 -15
  160. package/corpus/templates/clips/app/routes/record.tsx +82 -31
  161. package/corpus/templates/clips/app/routes/share.$shareId.tsx +42 -31
  162. package/corpus/templates/clips/changelog/2026-07-24-clip-pages-now-show-a-view-count-with-viewer-avatars-next-to.md +6 -0
  163. package/corpus/templates/clips/changelog/2026-07-24-clip-summaries-read-like-a-description-you-d-write-yourself-.md +6 -0
  164. package/corpus/templates/clips/changelog/2026-07-24-clip-view-counts-now-separate-human-views-from-agent-views-s.md +6 -0
  165. package/corpus/templates/clips/changelog/2026-07-24-clips-actions-can-now-be-called-by-org-service-tokens-so-ext.md +6 -0
  166. package/corpus/templates/clips/changelog/2026-07-24-clips-no-longer-briefly-shows-a-dock-icon-while-launching.md +6 -0
  167. package/corpus/templates/clips/changelog/2026-07-24-fixed-owner-and-editor-share-links-redirecting-to-the-record.md +6 -0
  168. package/corpus/templates/clips/changelog/2026-07-24-meeting-and-note-recordings-now-start-as-a-compact-pill-on-t.md +6 -0
  169. package/corpus/templates/clips/changelog/2026-07-24-new-clips-now-copy-a-shareable-link-instead-of-the-owner-onl.md +6 -0
  170. package/corpus/templates/clips/changelog/2026-07-24-opening-a-share-link-as-the-clip-s-owner-now-goes-straight-t.md +6 -0
  171. package/corpus/templates/clips/changelog/2026-07-24-permissions-and-rewind-controls-now-use-compact-consistent-h.md +6 -0
  172. package/corpus/templates/clips/changelog/2026-07-24-quitting-the-desktop-app-no-longer-shows-a-false-macos-crash.md +6 -0
  173. package/corpus/templates/clips/changelog/2026-07-24-screen-recording-permission-errors-now-name-the-exact-app-to.md +6 -0
  174. package/corpus/templates/clips/changelog/2026-07-24-the-desktop-app-now-copies-a-new-clip-s-share-link-to-your-c.md +6 -0
  175. package/corpus/templates/clips/changelog/2026-07-24-the-recording-toolbar-now-stays-above-other-apps-including-o.md +6 -0
  176. package/corpus/templates/clips/changelog/2026-07-24-transcript-captions-now-use-real-speech-timings-instead-of-a.md +6 -0
  177. package/corpus/templates/clips/changelog/2026-07-24-video-playback-no-longer-stutters-and-replays-the-last-momen.md +6 -0
  178. package/corpus/templates/clips/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  179. package/corpus/templates/clips/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  180. package/corpus/templates/clips/chrome-extension/src/background.ts +17 -1
  181. package/corpus/templates/clips/desktop/package.json +2 -0
  182. package/corpus/templates/clips/desktop/src/app.tsx +89 -0
  183. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +9 -3
  184. package/corpus/templates/clips/desktop/src/lib/audio-meter.ts +51 -0
  185. package/corpus/templates/clips/desktop/src/lib/native-notification.ts +44 -0
  186. package/corpus/templates/clips/desktop/src/lib/recording-link.ts +67 -0
  187. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +35 -35
  188. package/corpus/templates/clips/desktop/src/overlays/live-transcript.tsx +3 -2
  189. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +47 -46
  190. package/corpus/templates/clips/desktop/src/styles.css +127 -78
  191. package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +7 -0
  192. package/corpus/templates/clips/desktop/src-tauri/Info.plist +6 -0
  193. package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +1 -0
  194. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +7 -3
  195. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +4 -1
  196. package/corpus/templates/clips/desktop/src-tauri/src/main.rs +8 -0
  197. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +21 -10
  198. package/corpus/templates/clips/desktop/src-tauri/src/util.rs +40 -0
  199. package/corpus/templates/clips/server/db/schema.ts +27 -0
  200. package/corpus/templates/clips/server/lib/agent-views.ts +145 -0
  201. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +2 -1
  202. package/corpus/templates/clips/server/lib/public-agent-context.ts +7 -0
  203. package/corpus/templates/clips/server/lib/recording-share-grant.ts +79 -0
  204. package/corpus/templates/clips/server/lib/recordings.ts +51 -3
  205. package/corpus/templates/clips/server/plugins/auth.ts +1 -1
  206. package/corpus/templates/clips/server/plugins/db.ts +31 -0
  207. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +56 -3
  208. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +49 -17
  209. package/corpus/templates/clips/shared/recording-link.ts +43 -0
  210. package/corpus/templates/clips/shared/share-attribution.ts +4 -0
  211. package/corpus/templates/clips/shared/share-dashboard-redirect.ts +42 -0
  212. package/corpus/templates/clips/shared/view-analytics.ts +26 -0
  213. package/corpus/templates/content/.agents/skills/content/SKILL.md +5 -0
  214. package/corpus/templates/content/.agents/skills/content/references/local-file-mode.md +135 -0
  215. package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +12 -0
  216. package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +238 -0
  217. package/corpus/templates/content/.agents/skills/document-editing/references/document-behavior.md +91 -0
  218. package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  219. package/corpus/templates/content/AGENTS.md +62 -583
  220. package/corpus/templates/content/_gitignore +1 -0
  221. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +1 -39
  222. package/corpus/templates/content/app/routes/_app._index.tsx +1 -2
  223. package/corpus/templates/content/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  224. package/corpus/templates/content/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  225. package/corpus/templates/content/package.json +1 -1
  226. package/corpus/templates/content/public/manifest.json +1 -1
  227. package/corpus/templates/content/server/plugins/auth.ts +1 -1
  228. package/corpus/templates/design/.agents/skills/creative-context/SKILL.md +11 -0
  229. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +50 -8
  230. package/corpus/templates/design/.agents/skills/design-generation/references/code-layers.md +81 -0
  231. package/corpus/templates/design/.agents/skills/design-generation/references/code-workspace.md +42 -0
  232. package/corpus/templates/design/.agents/skills/design-generation/references/editor-extensions.md +34 -0
  233. package/corpus/templates/design/.agents/skills/responsive-breakpoints/SKILL.md +4 -1
  234. package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  235. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +17 -0
  236. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +8196 -0
  237. package/corpus/templates/design/.generated/bridge/embedded-wheel.generated.ts +265 -0
  238. package/corpus/templates/design/.generated/bridge/hit-test.generated.ts +642 -0
  239. package/corpus/templates/design/.generated/bridge/motion-preview.generated.ts +571 -0
  240. package/corpus/templates/design/.generated/bridge/nav.generated.ts +91 -0
  241. package/corpus/templates/design/.generated/bridge/sample.generated.ts +23 -0
  242. package/corpus/templates/design/.generated/bridge/shader-fill-preview.generated.ts +263 -0
  243. package/corpus/templates/design/.generated/bridge/shader-runtime.generated.ts +518 -0
  244. package/corpus/templates/design/.generated/bridge/tweak.generated.ts +20 -0
  245. package/corpus/templates/design/.generated/bridge/zoom.generated.ts +32 -0
  246. package/corpus/templates/design/AGENTS.md +88 -503
  247. package/corpus/templates/design/_gitignore +1 -0
  248. package/corpus/templates/design/app/components/layout/Sidebar.tsx +0 -2
  249. package/corpus/templates/design/app/routes/_index.tsx +1 -1
  250. package/corpus/templates/design/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  251. package/corpus/templates/design/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  252. package/corpus/templates/design/server/plugins/auth.ts +1 -1
  253. package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  254. package/corpus/templates/dispatch/_gitignore +1 -0
  255. package/corpus/templates/dispatch/app/dispatch-extensions.tsx +1 -10
  256. package/corpus/templates/dispatch/app/routes/overview.tsx +1 -1
  257. package/corpus/templates/dispatch/changelog/2026-07-24-signing-in-now-puts-you-in-your-companys-workspace.md +6 -0
  258. package/corpus/templates/dispatch/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  259. package/corpus/templates/dispatch/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  260. package/corpus/templates/dispatch/package.json +1 -1
  261. package/corpus/templates/dispatch/public/manifest.json +1 -1
  262. package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  263. package/corpus/templates/forms/_gitignore +1 -0
  264. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +0 -35
  265. package/corpus/templates/forms/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  266. package/corpus/templates/forms/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  267. package/corpus/templates/forms/package.json +1 -1
  268. package/corpus/templates/forms/public/manifest.json +1 -1
  269. package/corpus/templates/forms/server/lib/public-form-ssr.ts +2 -2
  270. package/corpus/templates/forms/server/plugins/auth.ts +1 -1
  271. package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  272. package/corpus/templates/macros/_gitignore +1 -0
  273. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +0 -2
  274. package/corpus/templates/macros/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  275. package/corpus/templates/macros/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  276. package/corpus/templates/macros/package.json +1 -1
  277. package/corpus/templates/macros/server/plugins/auth.ts +2 -2
  278. package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  279. package/corpus/templates/mail/_gitignore +1 -0
  280. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +0 -39
  281. package/corpus/templates/mail/app/routes/$view.$threadId.tsx +1 -1
  282. package/corpus/templates/mail/app/routes/$view.tsx +1 -1
  283. package/corpus/templates/mail/app/routes/_index.tsx +1 -1
  284. package/corpus/templates/mail/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  285. package/corpus/templates/mail/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  286. package/corpus/templates/mail/package.json +1 -1
  287. package/corpus/templates/mail/public/manifest.json +1 -1
  288. package/corpus/templates/mail/server/plugins/auth.ts +1 -1
  289. package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  290. package/corpus/templates/plan/_gitignore +1 -0
  291. package/corpus/templates/plan/agent-native.app-skill.json +1 -1
  292. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +4 -9
  293. package/corpus/templates/plan/app/lib/app-config.ts +1 -1
  294. package/corpus/templates/plan/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  295. package/corpus/templates/plan/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  296. package/corpus/templates/plan/package.json +1 -1
  297. package/corpus/templates/plan/public/manifest.json +1 -1
  298. package/corpus/templates/plan/server/plugins/auth.ts +1 -1
  299. package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  300. package/corpus/templates/slides/_gitignore +1 -0
  301. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +0 -2
  302. package/corpus/templates/slides/app/routes/_index.tsx +1 -1
  303. package/corpus/templates/slides/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  304. package/corpus/templates/slides/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  305. package/corpus/templates/slides/package.json +1 -1
  306. package/corpus/templates/slides/public/manifest.json +1 -1
  307. package/corpus/templates/slides/server/plugins/auth.ts +1 -1
  308. package/corpus/templates/slides/server/plugins/db.ts +4 -0
  309. package/corpus/templates/tasks/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  310. package/corpus/templates/tasks/AGENTS.md +1 -1
  311. package/corpus/templates/tasks/_gitignore +1 -0
  312. package/dist/a2a/activity.d.ts +4 -1
  313. package/dist/a2a/activity.d.ts.map +1 -1
  314. package/dist/a2a/activity.js +27 -16
  315. package/dist/a2a/activity.js.map +1 -1
  316. package/dist/a2a/client.d.ts.map +1 -1
  317. package/dist/a2a/client.js +58 -4
  318. package/dist/a2a/client.js.map +1 -1
  319. package/dist/agent/engine/builder-engine.d.ts +1 -0
  320. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  321. package/dist/agent/engine/builder-engine.js +31 -4
  322. package/dist/agent/engine/builder-engine.js.map +1 -1
  323. package/dist/agent/run-manager.d.ts.map +1 -1
  324. package/dist/agent/run-manager.js +18 -1
  325. package/dist/agent/run-manager.js.map +1 -1
  326. package/dist/agent/run-store.d.ts +1 -0
  327. package/dist/agent/run-store.d.ts.map +1 -1
  328. package/dist/agent/run-store.js +2 -1
  329. package/dist/agent/run-store.js.map +1 -1
  330. package/dist/agent/types.d.ts +12 -1
  331. package/dist/agent/types.d.ts.map +1 -1
  332. package/dist/agent/types.js +21 -1
  333. package/dist/agent/types.js.map +1 -1
  334. package/dist/chat-threads/store.d.ts +10 -0
  335. package/dist/chat-threads/store.d.ts.map +1 -1
  336. package/dist/chat-threads/store.js +41 -0
  337. package/dist/chat-threads/store.js.map +1 -1
  338. package/dist/checkpoints/index.d.ts +1 -0
  339. package/dist/checkpoints/index.d.ts.map +1 -1
  340. package/dist/checkpoints/index.js +1 -0
  341. package/dist/checkpoints/index.js.map +1 -1
  342. package/dist/checkpoints/route-match.d.ts +8 -0
  343. package/dist/checkpoints/route-match.d.ts.map +1 -0
  344. package/dist/checkpoints/route-match.js +13 -0
  345. package/dist/checkpoints/route-match.js.map +1 -0
  346. package/dist/cli/create.d.ts +35 -4
  347. package/dist/cli/create.d.ts.map +1 -1
  348. package/dist/cli/create.js +69 -19
  349. package/dist/cli/create.js.map +1 -1
  350. package/dist/cli/index.js +19 -0
  351. package/dist/cli/index.js.map +1 -1
  352. package/dist/cli/template-baseline.d.ts +54 -0
  353. package/dist/cli/template-baseline.d.ts.map +1 -0
  354. package/dist/cli/template-baseline.js +334 -0
  355. package/dist/cli/template-baseline.js.map +1 -0
  356. package/dist/cli/template-sync.d.ts +57 -0
  357. package/dist/cli/template-sync.d.ts.map +1 -0
  358. package/dist/cli/template-sync.js +787 -0
  359. package/dist/cli/template-sync.js.map +1 -0
  360. package/dist/cli/templates-meta.d.ts.map +1 -1
  361. package/dist/cli/templates-meta.js +1 -0
  362. package/dist/cli/templates-meta.js.map +1 -1
  363. package/dist/client/AssistantChat.d.ts +2 -1
  364. package/dist/client/AssistantChat.d.ts.map +1 -1
  365. package/dist/client/AssistantChat.js +38 -10
  366. package/dist/client/AssistantChat.js.map +1 -1
  367. package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -1
  368. package/dist/client/NewWorkspaceAppFlow.js +32 -2
  369. package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
  370. package/dist/client/chat/message-components.d.ts +20 -0
  371. package/dist/client/chat/message-components.d.ts.map +1 -1
  372. package/dist/client/chat/message-components.js +81 -46
  373. package/dist/client/chat/message-components.js.map +1 -1
  374. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  375. package/dist/client/chat/tool-call-display.js +14 -6
  376. package/dist/client/chat/tool-call-display.js.map +1 -1
  377. package/dist/client/error-format.d.ts.map +1 -1
  378. package/dist/client/error-format.js +13 -0
  379. package/dist/client/error-format.js.map +1 -1
  380. package/dist/client/org/OrgSwitcher.d.ts +8 -1
  381. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  382. package/dist/client/org/OrgSwitcher.js +3 -2
  383. package/dist/client/org/OrgSwitcher.js.map +1 -1
  384. package/dist/client/org/TeamPage.d.ts.map +1 -1
  385. package/dist/client/org/TeamPage.js +1 -1
  386. package/dist/client/org/TeamPage.js.map +1 -1
  387. package/dist/client/settings/SettingsPanel.js +9 -9
  388. package/dist/client/settings/SettingsPanel.js.map +1 -1
  389. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  390. package/dist/client/settings/SettingsTabsPage.js +7 -4
  391. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  392. package/dist/client/sse-event-processor.d.ts.map +1 -1
  393. package/dist/client/sse-event-processor.js +3 -0
  394. package/dist/client/sse-event-processor.js.map +1 -1
  395. package/dist/collab/awareness.d.ts +2 -2
  396. package/dist/collab/awareness.d.ts.map +1 -1
  397. package/dist/collab/struct-routes.d.ts +1 -1
  398. package/dist/data-widgets/index.d.ts +3 -0
  399. package/dist/data-widgets/index.d.ts.map +1 -1
  400. package/dist/data-widgets/index.js +33 -0
  401. package/dist/data-widgets/index.js.map +1 -1
  402. package/dist/deploy/build.d.ts.map +1 -1
  403. package/dist/deploy/build.js +11 -7
  404. package/dist/deploy/build.js.map +1 -1
  405. package/dist/eject/provider-api-definitions.d.ts +1 -0
  406. package/dist/eject/provider-api-definitions.d.ts.map +1 -1
  407. package/dist/extensions/url-safety.d.ts +9 -16
  408. package/dist/extensions/url-safety.d.ts.map +1 -1
  409. package/dist/extensions/url-safety.js +48 -4
  410. package/dist/extensions/url-safety.js.map +1 -1
  411. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  412. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  413. package/dist/integrations/webhook-handler.js +46 -9
  414. package/dist/integrations/webhook-handler.js.map +1 -1
  415. package/dist/notifications/routes.d.ts +2 -2
  416. package/dist/observability/routes.d.ts +3 -3
  417. package/dist/org/auto-join-domain.d.ts +3 -2
  418. package/dist/org/auto-join-domain.d.ts.map +1 -1
  419. package/dist/org/auto-join-domain.js +1 -1
  420. package/dist/org/auto-join-domain.js.map +1 -1
  421. package/dist/org/context.d.ts.map +1 -1
  422. package/dist/org/context.js +84 -28
  423. package/dist/org/context.js.map +1 -1
  424. package/dist/org/index.d.ts +1 -0
  425. package/dist/org/index.d.ts.map +1 -1
  426. package/dist/org/index.js +1 -0
  427. package/dist/org/index.js.map +1 -1
  428. package/dist/org/service-identity.d.ts +43 -0
  429. package/dist/org/service-identity.d.ts.map +1 -0
  430. package/dist/org/service-identity.js +34 -0
  431. package/dist/org/service-identity.js.map +1 -0
  432. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  433. package/dist/provider-api/actions/provider-api.d.ts +13 -11
  434. package/dist/provider-api/actions/provider-api.d.ts.map +1 -1
  435. package/dist/provider-api/index.d.ts +4 -0
  436. package/dist/provider-api/index.d.ts.map +1 -1
  437. package/dist/provider-api/index.js +17 -1
  438. package/dist/provider-api/index.js.map +1 -1
  439. package/dist/scripts/docs/search.d.ts.map +1 -1
  440. package/dist/scripts/docs/search.js +12 -1
  441. package/dist/scripts/docs/search.js.map +1 -1
  442. package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
  443. package/dist/server/agent-chat/context-tools.js +3 -3
  444. package/dist/server/agent-chat/context-tools.js.map +1 -1
  445. package/dist/server/agent-chat/framework-prompts.d.ts +8 -3
  446. package/dist/server/agent-chat/framework-prompts.d.ts.map +1 -1
  447. package/dist/server/agent-chat/framework-prompts.js +33 -62
  448. package/dist/server/agent-chat/framework-prompts.js.map +1 -1
  449. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  450. package/dist/server/agent-chat-plugin.js +16 -10
  451. package/dist/server/agent-chat-plugin.js.map +1 -1
  452. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  453. package/dist/server/agents-bundle.d.ts +18 -0
  454. package/dist/server/agents-bundle.d.ts.map +1 -1
  455. package/dist/server/agents-bundle.js +70 -4
  456. package/dist/server/agents-bundle.js.map +1 -1
  457. package/dist/server/auth.d.ts.map +1 -1
  458. package/dist/server/auth.js +4 -3
  459. package/dist/server/auth.js.map +1 -1
  460. package/dist/server/builder-browser.d.ts.map +1 -1
  461. package/dist/server/builder-browser.js +43 -19
  462. package/dist/server/builder-browser.js.map +1 -1
  463. package/dist/server/core-routes-plugin.js +2 -2
  464. package/dist/server/core-routes-plugin.js.map +1 -1
  465. package/dist/server/credential-provider.d.ts +38 -2
  466. package/dist/server/credential-provider.d.ts.map +1 -1
  467. package/dist/server/credential-provider.js +142 -64
  468. package/dist/server/credential-provider.js.map +1 -1
  469. package/dist/server/index.d.ts +1 -1
  470. package/dist/server/index.d.ts.map +1 -1
  471. package/dist/server/index.js +1 -1
  472. package/dist/server/index.js.map +1 -1
  473. package/dist/server/prompts/framework-core-compact.d.ts +1 -1
  474. package/dist/server/prompts/framework-core-compact.d.ts.map +1 -1
  475. package/dist/server/prompts/framework-core-compact.js +7 -13
  476. package/dist/server/prompts/framework-core-compact.js.map +1 -1
  477. package/dist/server/prompts/framework-core.d.ts +1 -1
  478. package/dist/server/prompts/framework-core.d.ts.map +1 -1
  479. package/dist/server/prompts/framework-core.js +10 -21
  480. package/dist/server/prompts/framework-core.js.map +1 -1
  481. package/dist/server/prompts/index.d.ts +1 -1
  482. package/dist/server/prompts/index.d.ts.map +1 -1
  483. package/dist/server/prompts/index.js +1 -1
  484. package/dist/server/prompts/index.js.map +1 -1
  485. package/dist/server/prompts/shared-rules.d.ts +16 -10
  486. package/dist/server/prompts/shared-rules.d.ts.map +1 -1
  487. package/dist/server/prompts/shared-rules.js +19 -10
  488. package/dist/server/prompts/shared-rules.js.map +1 -1
  489. package/dist/server/ssr-handler.d.ts +1 -1
  490. package/dist/server/ssr-handler.d.ts.map +1 -1
  491. package/dist/server/ssr-handler.js +10 -3
  492. package/dist/server/ssr-handler.js.map +1 -1
  493. package/dist/server/transcribe-voice.d.ts +1 -1
  494. package/dist/settings/user-settings.d.ts.map +1 -1
  495. package/dist/settings/user-settings.js +13 -1
  496. package/dist/settings/user-settings.js.map +1 -1
  497. package/dist/shared/cache-control.d.ts +52 -0
  498. package/dist/shared/cache-control.d.ts.map +1 -1
  499. package/dist/shared/cache-control.js +107 -0
  500. package/dist/shared/cache-control.js.map +1 -1
  501. package/dist/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  502. package/dist/templates/chat/_gitignore +1 -0
  503. package/dist/templates/chat/app/components/layout/Sidebar.tsx +0 -7
  504. package/dist/templates/chat/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  505. package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  506. package/dist/templates/default/app/root.tsx +1 -1
  507. package/dist/templates/default/public/manifest.json +2 -2
  508. package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  509. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
  510. package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  511. package/dist/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
  512. package/dist/vite/agents-bundle-plugin.d.ts.map +1 -1
  513. package/dist/vite/agents-bundle-plugin.js +8 -7
  514. package/dist/vite/agents-bundle-plugin.js.map +1 -1
  515. package/dist/vite/client.d.ts.map +1 -1
  516. package/dist/vite/client.js +66 -1
  517. package/dist/vite/client.js.map +1 -1
  518. package/docs/content/actions.mdx +2 -2
  519. package/docs/content/agent-surfaces.mdx +1 -1
  520. package/docs/content/authentication.mdx +2 -0
  521. package/docs/content/deployment.mdx +36 -0
  522. package/docs/content/http-api.mdx +266 -0
  523. package/docs/content/syncing-template-changes.mdx +159 -0
  524. package/package.json +4 -3
  525. package/src/a2a/activity.ts +38 -27
  526. package/src/a2a/client.ts +57 -4
  527. package/src/agent/engine/builder-engine.ts +35 -4
  528. package/src/agent/run-manager.ts +20 -1
  529. package/src/agent/run-store.ts +4 -1
  530. package/src/agent/types.ts +28 -8
  531. package/src/chat-threads/store.ts +45 -0
  532. package/src/checkpoints/index.ts +2 -0
  533. package/src/checkpoints/route-match.ts +13 -0
  534. package/src/cli/create.ts +105 -17
  535. package/src/cli/index.ts +20 -0
  536. package/src/cli/template-baseline.ts +410 -0
  537. package/src/cli/template-sync.ts +1004 -0
  538. package/src/cli/templates-meta.ts +1 -0
  539. package/src/client/AssistantChat.tsx +38 -12
  540. package/src/client/NewWorkspaceAppFlow.tsx +75 -10
  541. package/src/client/chat/message-components.tsx +127 -66
  542. package/src/client/chat/tool-call-display.tsx +29 -5
  543. package/src/client/error-format.ts +18 -0
  544. package/src/client/org/OrgSwitcher.tsx +30 -8
  545. package/src/client/org/TeamPage.tsx +7 -6
  546. package/src/client/settings/SettingsPanel.tsx +9 -9
  547. package/src/client/settings/SettingsTabsPage.tsx +12 -2
  548. package/src/client/sse-event-processor.ts +3 -0
  549. package/src/data-widgets/index.ts +41 -0
  550. package/src/deploy/build.ts +11 -9
  551. package/src/extensions/url-safety.ts +67 -4
  552. package/src/integrations/webhook-handler.ts +63 -9
  553. package/src/org/auto-join-domain.ts +4 -3
  554. package/src/org/context.ts +108 -39
  555. package/src/org/index.ts +5 -0
  556. package/src/org/service-identity.ts +60 -0
  557. package/src/provider-api/index.ts +22 -1
  558. package/src/scripts/docs/search.ts +12 -1
  559. package/src/server/__snapshots__/agent-chat-plugin.surface.spec.ts.snap +25 -36
  560. package/src/server/agent-chat/context-tools.ts +9 -4
  561. package/src/server/agent-chat/framework-prompts.ts +38 -66
  562. package/src/server/agent-chat-plugin.ts +17 -10
  563. package/src/server/agents-bundle.ts +84 -5
  564. package/src/server/auth.ts +4 -3
  565. package/src/server/builder-browser.ts +47 -19
  566. package/src/server/core-routes-plugin.ts +2 -2
  567. package/src/server/credential-provider.ts +209 -68
  568. package/src/server/index.ts +3 -0
  569. package/src/server/prompts/framework-core-compact.ts +6 -13
  570. package/src/server/prompts/framework-core.ts +9 -21
  571. package/src/server/prompts/index.ts +0 -1
  572. package/src/server/prompts/shared-rules.ts +19 -11
  573. package/src/server/ssr-handler.ts +13 -2
  574. package/src/settings/user-settings.ts +13 -1
  575. package/src/shared/cache-control.ts +141 -0
  576. package/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  577. package/src/templates/chat/_gitignore +1 -0
  578. package/src/templates/chat/app/components/layout/Sidebar.tsx +0 -7
  579. package/src/templates/chat/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  580. package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  581. package/src/templates/default/app/root.tsx +1 -1
  582. package/src/templates/default/public/manifest.json +2 -2
  583. package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  584. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
  585. package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  586. package/src/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
  587. package/src/vite/agents-bundle-plugin.ts +7 -6
  588. package/src/vite/client.ts +69 -3
@@ -0,0 +1,1004 @@
1
+ /**
2
+ * `agent-native template` — pull later upstream template changes into an app
3
+ * that was generated from a first-party template.
4
+ *
5
+ * The model is a real 3-way merge:
6
+ *
7
+ * base = the pristine upstream tree the app was generated from
8
+ * (stored as a git ref, see template-baseline.ts)
9
+ * theirs = the same template re-materialized at a newer ref, through the
10
+ * exact transform pipeline `create` runs
11
+ * ours = the app's working tree
12
+ *
13
+ * Materialization fidelity is the whole feature: any divergence from what
14
+ * `create` produced turns into phantom conflicts on every sync, so this file
15
+ * reuses `create.ts`'s own transforms rather than reimplementing them.
16
+ */
17
+ import { spawnSync } from "node:child_process";
18
+ import fs from "node:fs";
19
+ import os from "node:os";
20
+ import path from "node:path";
21
+
22
+ import {
23
+ detectWorkspace,
24
+ _REPO,
25
+ _TEMPLATES_DIR,
26
+ _appTitleForScaffold,
27
+ _copyDir,
28
+ _downloadGitHubSubdir,
29
+ _findLocalTemplate,
30
+ _fixPackageJsonName,
31
+ _fixWebManifestName,
32
+ _getCoreDependencyVersion,
33
+ _getCorePackageVersion,
34
+ _getDispatchDependencyVersion,
35
+ _getGitHubTemplateRefCandidates,
36
+ _getToolkitDependencyVersion,
37
+ _localTemplateSourceKind,
38
+ _normalizeTemplateName,
39
+ _postProcessStandalone,
40
+ _renameGitignore,
41
+ _replacePlaceholders,
42
+ _rewriteNetlifyToml,
43
+ _rewriteTrackingAppId,
44
+ _shouldSkipScaffoldEntry,
45
+ _templateSourceName,
46
+ } from "./create.js";
47
+ import {
48
+ appDirtyPaths,
49
+ baselineDescription,
50
+ baselineExists,
51
+ clearBaseline,
52
+ materializeBaseline,
53
+ promoteBaseline,
54
+ resolveBaselineStore,
55
+ writeBaseline,
56
+ } from "./template-baseline.js";
57
+ import { workspacifyApp } from "./workspacify.js";
58
+
59
+ export interface TemplateIO {
60
+ out: (message: string) => void;
61
+ err: (message: string) => void;
62
+ }
63
+
64
+ const defaultIO: TemplateIO = {
65
+ out: (message) => console.log(message),
66
+ err: (message) => console.error(message),
67
+ };
68
+
69
+ const CONFLICT_MARKER = "<<<<<<<";
70
+
71
+ /** Never merged: user secrets, lockfiles, generated output, personal memory. */
72
+ const NEVER_TOUCH_NAMES = new Set([
73
+ ".git",
74
+ "learnings.md",
75
+ "pnpm-lock.yaml",
76
+ "package-lock.json",
77
+ "yarn.lock",
78
+ "bun.lockb",
79
+ ]);
80
+
81
+ export interface TemplateProvenance {
82
+ template?: string;
83
+ frameworkSkills?: string;
84
+ templateRef?: string;
85
+ templateSource?: "github" | "bundled" | "local-checkout";
86
+ coreVersion?: string;
87
+ shape?: "workspace" | "standalone";
88
+ }
89
+
90
+ export interface AppTarget {
91
+ appDir: string;
92
+ appName: string;
93
+ shape: "workspace" | "standalone";
94
+ workspaceRoot?: string;
95
+ workspaceCoreName?: string;
96
+ provenance: TemplateProvenance;
97
+ }
98
+
99
+ export interface MaterializeOptions {
100
+ appName: string;
101
+ template: string;
102
+ /** Git ref to fetch from, or null to use the bundled/local template copy. */
103
+ ref: string | null;
104
+ shape: "workspace" | "standalone";
105
+ workspaceRoot?: string;
106
+ workspaceCoreName?: string;
107
+ destDir?: string;
108
+ }
109
+
110
+ export interface MaterializeResult {
111
+ dir: string;
112
+ ref: string;
113
+ source: "github" | "bundled" | "local-checkout";
114
+ }
115
+
116
+ export interface TemplateMergeResult {
117
+ added: string[];
118
+ updated: string[];
119
+ deleted: string[];
120
+ conflicted: string[];
121
+ manual: string[];
122
+ keptLocal: string[];
123
+ }
124
+
125
+ /* ─────────────────────────────────────────────────────────────────────────
126
+ * Materialization
127
+ * ───────────────────────────────────────────────────────────────────────── */
128
+
129
+ /**
130
+ * Reproduce, in a temp directory, the exact bytes `create` would have written
131
+ * for this (template, ref, app name, shape, workspace scope).
132
+ */
133
+ export async function materializeTemplate(
134
+ opts: MaterializeOptions,
135
+ ): Promise<MaterializeResult> {
136
+ const dest =
137
+ opts.destDir ?? fs.mkdtempSync(path.join(os.tmpdir(), "an-template-new-"));
138
+ fs.mkdirSync(dest, { recursive: true });
139
+
140
+ const resolved = _normalizeTemplateName(opts.template);
141
+ const sourceTemplate = _templateSourceName(resolved);
142
+ const fallbackRef = _getGitHubTemplateRefCandidates()[0];
143
+
144
+ let usedRef: string;
145
+ let source: MaterializeResult["source"];
146
+ if (opts.ref === null || resolved === "headless") {
147
+ const local = _findLocalTemplate(
148
+ resolved === "headless" ? "headless" : sourceTemplate,
149
+ );
150
+ if (!local) {
151
+ throw new Error(
152
+ `No local copy of the "${resolved}" template is available. Pass --to <ref> to fetch it from GitHub.`,
153
+ );
154
+ }
155
+ _copyDir(local, dest);
156
+ usedRef = opts.ref ?? fallbackRef ?? "unknown";
157
+ source = _localTemplateSourceKind(local);
158
+ } else {
159
+ usedRef = await _downloadGitHubSubdir(
160
+ _REPO,
161
+ `${_TEMPLATES_DIR}/${sourceTemplate}`,
162
+ dest,
163
+ [opts.ref],
164
+ );
165
+ source = "github";
166
+ }
167
+
168
+ const provenance = { templateRef: usedRef, templateSource: source };
169
+
170
+ if (opts.shape === "workspace") {
171
+ if (!opts.workspaceRoot || !opts.workspaceCoreName) {
172
+ throw new Error(
173
+ "Workspace apps need a workspace root and shared package name to materialize.",
174
+ );
175
+ }
176
+ _replacePlaceholders(
177
+ dest,
178
+ opts.appName,
179
+ _appTitleForScaffold(opts.appName),
180
+ path.basename(opts.workspaceRoot),
181
+ );
182
+ _rewriteTrackingAppId(dest, opts.appName, opts.template);
183
+ workspacifyApp({
184
+ appDir: dest,
185
+ appName: opts.appName,
186
+ templateName: opts.template,
187
+ workspaceRoot: opts.workspaceRoot,
188
+ workspaceCoreName: opts.workspaceCoreName,
189
+ coreDependencyVersion: _getCoreDependencyVersion(),
190
+ dispatchDependencyVersion: _getDispatchDependencyVersion(),
191
+ toolkitDependencyVersion: _getToolkitDependencyVersion(),
192
+ });
193
+ _fixPackageJsonName(dest, opts.appName, opts.template, {
194
+ ...provenance,
195
+ shape: "workspace",
196
+ });
197
+ _fixWebManifestName(dest, opts.appName, opts.template);
198
+ _rewriteNetlifyToml(dest, opts.appName, "workspace");
199
+ _renameGitignore(dest);
200
+ } else {
201
+ _postProcessStandalone(opts.appName, dest, opts.template, provenance);
202
+ }
203
+
204
+ return { dir: dest, ref: usedRef, source };
205
+ }
206
+
207
+ /* ─────────────────────────────────────────────────────────────────────────
208
+ * Merge
209
+ * ───────────────────────────────────────────────────────────────────────── */
210
+
211
+ export function isMergeExcluded(rel: string): boolean {
212
+ const segments = rel.split("/");
213
+ if (segments[0] === "changelog") return true;
214
+ for (const name of segments) {
215
+ if (!name || name === "." || name === "..") return true;
216
+ if (NEVER_TOUCH_NAMES.has(name)) return true;
217
+ if (name.startsWith(".env")) return true;
218
+ if (_shouldSkipScaffoldEntry(name)) return true;
219
+ }
220
+ return false;
221
+ }
222
+
223
+ export function listMergeableFiles(root: string): Set<string> {
224
+ const found = new Set<string>();
225
+ const walk = (dir: string, prefix: string): void => {
226
+ let entries: fs.Dirent[];
227
+ try {
228
+ entries = fs.readdirSync(dir, { withFileTypes: true });
229
+ } catch {
230
+ return;
231
+ }
232
+ for (const entry of entries) {
233
+ const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
234
+ if (isMergeExcluded(rel)) continue;
235
+ if (entry.isSymbolicLink()) continue;
236
+ if (entry.isDirectory()) walk(path.join(dir, entry.name), rel);
237
+ else if (entry.isFile()) found.add(rel);
238
+ }
239
+ };
240
+ walk(root, "");
241
+ return found;
242
+ }
243
+
244
+ export function mergeTemplateTrees(
245
+ appDir: string,
246
+ baseDir: string,
247
+ theirsDir: string,
248
+ options: { dryRun?: boolean } = {},
249
+ ): TemplateMergeResult {
250
+ const result: TemplateMergeResult = {
251
+ added: [],
252
+ updated: [],
253
+ deleted: [],
254
+ conflicted: [],
255
+ manual: [],
256
+ keptLocal: [],
257
+ };
258
+ const paths = new Set<string>([
259
+ ...listMergeableFiles(baseDir),
260
+ ...listMergeableFiles(theirsDir),
261
+ ...listMergeableFiles(appDir),
262
+ ]);
263
+
264
+ for (const rel of Array.from(paths).sort()) {
265
+ const oursPath = path.join(appDir, rel);
266
+ if (isLocalSymlink(oursPath)) {
267
+ result.manual.push(`${rel} (local symlink)`);
268
+ continue;
269
+ }
270
+ const base = readFileOrNull(path.join(baseDir, rel));
271
+ const theirs = readFileOrNull(path.join(theirsDir, rel));
272
+ const ours = readFileOrNull(oursPath);
273
+
274
+ if (equalBuffers(base, theirs)) continue;
275
+
276
+ if (theirs === null) {
277
+ if (ours === null) continue;
278
+ if (equalBuffers(ours, base)) {
279
+ if (!options.dryRun) removeFile(oursPath);
280
+ result.deleted.push(rel);
281
+ } else {
282
+ result.keptLocal.push(rel);
283
+ }
284
+ continue;
285
+ }
286
+
287
+ if (ours === null) {
288
+ if (base === null) {
289
+ if (!options.dryRun) writeFile(oursPath, theirs);
290
+ result.added.push(rel);
291
+ } else {
292
+ result.manual.push(`${rel} (deleted locally, changed upstream)`);
293
+ }
294
+ continue;
295
+ }
296
+
297
+ if (equalBuffers(ours, theirs)) continue;
298
+ if (equalBuffers(ours, base)) {
299
+ if (!options.dryRun) writeFile(oursPath, theirs);
300
+ result.updated.push(rel);
301
+ continue;
302
+ }
303
+
304
+ if (!isTextBuffer(ours) || !isTextBuffer(theirs) || !isTextBuffer(base)) {
305
+ result.manual.push(`${rel} (binary changed on both sides)`);
306
+ continue;
307
+ }
308
+
309
+ const merged = gitMergeFile(ours, base ?? Buffer.alloc(0), theirs);
310
+ if (!merged) {
311
+ result.manual.push(`${rel} (merge failed)`);
312
+ continue;
313
+ }
314
+ if (!options.dryRun) writeFile(oursPath, merged.content);
315
+ if (merged.conflicts > 0) result.conflicted.push(rel);
316
+ else result.updated.push(rel);
317
+ }
318
+
319
+ return result;
320
+ }
321
+
322
+ function gitMergeFile(
323
+ ours: Buffer,
324
+ base: Buffer,
325
+ theirs: Buffer,
326
+ ): { content: Buffer; conflicts: number } | null {
327
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "an-template-merge-"));
328
+ try {
329
+ const oursFile = path.join(dir, "ours");
330
+ const baseFile = path.join(dir, "base");
331
+ const theirsFile = path.join(dir, "theirs");
332
+ fs.writeFileSync(oursFile, ours);
333
+ fs.writeFileSync(baseFile, base);
334
+ fs.writeFileSync(theirsFile, theirs);
335
+ const res = spawnSync(
336
+ "git",
337
+ [
338
+ "merge-file",
339
+ "-p",
340
+ "-L",
341
+ "ours",
342
+ "-L",
343
+ "base",
344
+ "-L",
345
+ "theirs",
346
+ oursFile,
347
+ baseFile,
348
+ theirsFile,
349
+ ],
350
+ { maxBuffer: 64 * 1024 * 1024 },
351
+ );
352
+ if (res.status === null || res.status < 0) return null;
353
+ return { content: res.stdout as Buffer, conflicts: res.status };
354
+ } finally {
355
+ fs.rmSync(dir, { recursive: true, force: true });
356
+ }
357
+ }
358
+
359
+ /* ─────────────────────────────────────────────────────────────────────────
360
+ * Target resolution
361
+ * ───────────────────────────────────────────────────────────────────────── */
362
+
363
+ export function readProvenance(appDir: string): TemplateProvenance {
364
+ const pkg = readJson(path.join(appDir, "package.json"));
365
+ const scaffold = (
366
+ pkg?.["agent-native"] as Record<string, unknown> | undefined
367
+ )?.scaffold;
368
+ if (!scaffold || typeof scaffold !== "object") return {};
369
+ return scaffold as TemplateProvenance;
370
+ }
371
+
372
+ export function resolveTargets(cwd: string, appArg?: string): AppTarget[] {
373
+ const workspace = detectWorkspace(cwd);
374
+
375
+ if (appArg) {
376
+ const candidates = [path.resolve(cwd, appArg)];
377
+ if (workspace)
378
+ candidates.push(path.join(workspace.workspaceRoot, "apps", appArg));
379
+ for (const candidate of candidates) {
380
+ if (fs.existsSync(path.join(candidate, "package.json"))) {
381
+ return [toTarget(candidate)];
382
+ }
383
+ }
384
+ throw new Error(`No app found for "${appArg}".`);
385
+ }
386
+
387
+ const appDir = findAppDir(cwd);
388
+ if (appDir) return [toTarget(appDir)];
389
+
390
+ if (workspace && path.resolve(cwd) === workspace.workspaceRoot) {
391
+ const appsDir = path.join(workspace.workspaceRoot, "apps");
392
+ if (fs.existsSync(appsDir)) {
393
+ const targets = fs
394
+ .readdirSync(appsDir, { withFileTypes: true })
395
+ .filter((entry) => entry.isDirectory())
396
+ .map((entry) => path.join(appsDir, entry.name))
397
+ .filter((dir) => fs.existsSync(path.join(dir, "package.json")))
398
+ .map((dir) => toTarget(dir));
399
+ if (targets.length > 0) return targets;
400
+ }
401
+ }
402
+
403
+ throw new Error(
404
+ "No Agent Native app found. Run from an app directory, or pass an app name from a workspace root.",
405
+ );
406
+ }
407
+
408
+ function toTarget(appDir: string): AppTarget {
409
+ const resolved = path.resolve(appDir);
410
+ const provenance = readProvenance(resolved);
411
+ const workspace = detectWorkspace(resolved);
412
+ const insideWorkspaceApps =
413
+ !!workspace &&
414
+ path.dirname(resolved) === path.join(workspace.workspaceRoot, "apps");
415
+ const shape =
416
+ provenance.shape ?? (insideWorkspaceApps ? "workspace" : "standalone");
417
+ return {
418
+ appDir: resolved,
419
+ appName: readAppName(resolved),
420
+ shape,
421
+ workspaceRoot: workspace?.workspaceRoot,
422
+ workspaceCoreName: workspace?.workspaceCoreName,
423
+ provenance,
424
+ };
425
+ }
426
+
427
+ function readAppName(appDir: string): string {
428
+ const pkg = readJson(path.join(appDir, "package.json"));
429
+ const name = typeof pkg?.name === "string" ? pkg.name : "";
430
+ return name || path.basename(appDir);
431
+ }
432
+
433
+ function findAppDir(cwd: string): string | null {
434
+ let dir = path.resolve(cwd);
435
+ for (let i = 0; i < 20; i++) {
436
+ const pkg = readJson(path.join(dir, "package.json"));
437
+ if (pkg) {
438
+ const agentNative = pkg["agent-native"] as
439
+ | Record<string, unknown>
440
+ | undefined;
441
+ if (agentNative?.workspaceCore) return null;
442
+ const deps = (pkg.dependencies ?? {}) as Record<string, string>;
443
+ const devDeps = (pkg.devDependencies ?? {}) as Record<string, string>;
444
+ if (
445
+ agentNative?.scaffold ||
446
+ deps["@agent-native/core"] ||
447
+ devDeps["@agent-native/core"]
448
+ ) {
449
+ return dir;
450
+ }
451
+ }
452
+ const parent = path.dirname(dir);
453
+ if (parent === dir) break;
454
+ dir = parent;
455
+ }
456
+ return null;
457
+ }
458
+
459
+ /* ─────────────────────────────────────────────────────────────────────────
460
+ * Commands
461
+ * ───────────────────────────────────────────────────────────────────────── */
462
+
463
+ export async function runTemplate(
464
+ args: string[],
465
+ io: TemplateIO = defaultIO,
466
+ ): Promise<number> {
467
+ const command = args[0];
468
+ if (
469
+ !command ||
470
+ command === "help" ||
471
+ command === "--help" ||
472
+ command === "-h"
473
+ ) {
474
+ io.out(templateUsage());
475
+ return command ? 0 : 1;
476
+ }
477
+
478
+ const rest = args.slice(1);
479
+ const appArg = positionalArgs(rest)[0];
480
+ const flags = {
481
+ to: flagValue(rest, "--to"),
482
+ ref: flagValue(rest, "--ref"),
483
+ template: flagValue(rest, "--template"),
484
+ dryRun: rest.includes("--dry-run"),
485
+ force: rest.includes("--force"),
486
+ };
487
+
488
+ let targets: AppTarget[];
489
+ try {
490
+ targets = resolveTargets(process.cwd(), appArg);
491
+ } catch (err) {
492
+ io.err(err instanceof Error ? err.message : String(err));
493
+ return 1;
494
+ }
495
+
496
+ let exitCode = 0;
497
+ for (const target of targets) {
498
+ try {
499
+ const code = await runForTarget(command, target, flags, io);
500
+ if (code !== 0) exitCode = code;
501
+ } catch (err) {
502
+ io.err(
503
+ `${target.appName}: ${err instanceof Error ? err.message : String(err)}`,
504
+ );
505
+ exitCode = 1;
506
+ }
507
+ }
508
+ return exitCode;
509
+ }
510
+
511
+ interface TemplateFlags {
512
+ to?: string;
513
+ ref?: string;
514
+ template?: string;
515
+ dryRun: boolean;
516
+ force: boolean;
517
+ }
518
+
519
+ async function runForTarget(
520
+ command: string,
521
+ target: AppTarget,
522
+ flags: TemplateFlags,
523
+ io: TemplateIO,
524
+ ): Promise<number> {
525
+ switch (command) {
526
+ case "status":
527
+ return statusCommand(target, flags, io);
528
+ case "diff":
529
+ return diffCommand(target, flags, io);
530
+ case "sync":
531
+ return syncCommand(target, flags, io);
532
+ case "baseline":
533
+ return baselineCommand(target, flags, io);
534
+ case "accept":
535
+ return acceptCommand(target, io);
536
+ default:
537
+ io.err(`Unknown template command "${command}".`);
538
+ io.err(templateUsage());
539
+ return 1;
540
+ }
541
+ }
542
+
543
+ function templateName(target: AppTarget, flags: TemplateFlags): string {
544
+ const name = flags.template ?? target.provenance.template;
545
+ if (!name) {
546
+ throw new Error(
547
+ `${target.appName} has no recorded template. Pass --template <name> to record one.`,
548
+ );
549
+ }
550
+ return name;
551
+ }
552
+
553
+ async function statusCommand(
554
+ target: AppTarget,
555
+ flags: TemplateFlags,
556
+ io: TemplateIO,
557
+ ): Promise<number> {
558
+ const store = resolveBaselineStore(target.appDir);
559
+ const latest = _getGitHubTemplateRefCandidates()[0] ?? "(unknown)";
560
+ const lines = [
561
+ `${target.appName} (${target.shape})`,
562
+ ` template: ${target.provenance.template ?? "(unrecorded)"}`,
563
+ ` recorded ref: ${target.provenance.templateRef ?? "(unrecorded)"}`,
564
+ ` recorded source:${target.provenance.templateSource ? ` ${target.provenance.templateSource}` : " (unrecorded)"}`,
565
+ ` latest ref: ${flags.to ?? latest}`,
566
+ ` baseline: ${baselineDescription(store, "baseline") ?? "missing — run `agent-native template baseline`"}`,
567
+ ];
568
+ const pending = baselineDescription(store, "pending");
569
+ if (pending) lines.push(` pending accept: ${pending}`);
570
+
571
+ const baseDir = materializeBaseline(store, "baseline");
572
+ if (baseDir) {
573
+ try {
574
+ const local = countLocallyModified(target.appDir, baseDir);
575
+ lines.push(` locally modified files: ${local}`);
576
+ const targetRef = flags.to ?? target.provenance.templateRef ?? latest;
577
+ const theirs = await materializeForTarget(target, flags, targetRef);
578
+ try {
579
+ const changed = countUpstreamChanged(baseDir, theirs.dir);
580
+ lines.push(` upstream-changed files: ${changed} (at ${theirs.ref})`);
581
+ } finally {
582
+ fs.rmSync(theirs.dir, { recursive: true, force: true });
583
+ }
584
+ } catch (err) {
585
+ lines.push(
586
+ ` upstream-changed files: unavailable (${err instanceof Error ? err.message.split("\n")[0] : String(err)})`,
587
+ );
588
+ } finally {
589
+ fs.rmSync(baseDir, { recursive: true, force: true });
590
+ }
591
+ }
592
+
593
+ io.out(lines.join("\n"));
594
+ return 0;
595
+ }
596
+
597
+ async function diffCommand(
598
+ target: AppTarget,
599
+ flags: TemplateFlags,
600
+ io: TemplateIO,
601
+ ): Promise<number> {
602
+ const store = resolveBaselineStore(target.appDir);
603
+ const baseDir = materializeBaseline(store, "baseline");
604
+ if (!baseDir) {
605
+ io.err(
606
+ `${target.appName}: no baseline recorded. Run \`agent-native template baseline ${target.appName}\` first.`,
607
+ );
608
+ return 1;
609
+ }
610
+ const theirs = await materializeForTarget(
611
+ target,
612
+ flags,
613
+ flags.to ?? _getGitHubTemplateRefCandidates()[0] ?? null,
614
+ );
615
+ try {
616
+ io.out(renderTreeDiff(baseDir, theirs.dir));
617
+ return 0;
618
+ } finally {
619
+ fs.rmSync(baseDir, { recursive: true, force: true });
620
+ fs.rmSync(theirs.dir, { recursive: true, force: true });
621
+ }
622
+ }
623
+
624
+ async function syncCommand(
625
+ target: AppTarget,
626
+ flags: TemplateFlags,
627
+ io: TemplateIO,
628
+ ): Promise<number> {
629
+ const store = resolveBaselineStore(target.appDir);
630
+ const baseDir = materializeBaseline(store, "baseline");
631
+ if (!baseDir) {
632
+ io.err(
633
+ `${target.appName}: no baseline recorded. Run \`agent-native template baseline ${target.appName}\` first.`,
634
+ );
635
+ return 1;
636
+ }
637
+
638
+ const dirty = appDirtyPaths(store);
639
+ if (dirty.length > 0 && !flags.force && !flags.dryRun) {
640
+ fs.rmSync(baseDir, { recursive: true, force: true });
641
+ io.err(
642
+ "Sync refused because the app directory has uncommitted changes. Review this diff and preserve your edits before syncing, or pass --force.",
643
+ );
644
+ for (const line of dirty.slice(0, 20)) io.err(` ${line}`);
645
+ if (dirty.length > 20) io.err(` … ${dirty.length - 20} more`);
646
+ return 1;
647
+ }
648
+
649
+ const theirs = await materializeForTarget(
650
+ target,
651
+ flags,
652
+ flags.to ?? _getGitHubTemplateRefCandidates()[0] ?? null,
653
+ );
654
+ try {
655
+ const result = mergeTemplateTrees(target.appDir, baseDir, theirs.dir, {
656
+ dryRun: flags.dryRun,
657
+ });
658
+ io.out(formatMergeResult(target, theirs.ref, result, flags.dryRun));
659
+
660
+ if (flags.dryRun) return 0;
661
+
662
+ const meta = {
663
+ template: templateName(target, flags),
664
+ templateRef: theirs.ref,
665
+ coreVersion: _getCorePackageVersion(),
666
+ };
667
+ if (result.conflicted.length === 0 && result.manual.length === 0) {
668
+ const written = writeBaseline(store, theirs.dir, "baseline", meta);
669
+ clearBaseline(store, "pending");
670
+ io.out(`Baseline advanced to ${written.location}.`);
671
+ reportRefspecs(written.configuredRefspecs, io);
672
+ return 0;
673
+ }
674
+
675
+ const written = writeBaseline(store, theirs.dir, "pending", meta);
676
+ reportRefspecs(written.configuredRefspecs, io);
677
+ io.out("");
678
+ io.out(
679
+ `Baseline not advanced — resolve the items above, then run:\n agent-native template accept ${target.appName}`,
680
+ );
681
+ return 1;
682
+ } finally {
683
+ fs.rmSync(baseDir, { recursive: true, force: true });
684
+ fs.rmSync(theirs.dir, { recursive: true, force: true });
685
+ }
686
+ }
687
+
688
+ async function baselineCommand(
689
+ target: AppTarget,
690
+ flags: TemplateFlags,
691
+ io: TemplateIO,
692
+ ): Promise<number> {
693
+ const store = resolveBaselineStore(target.appDir);
694
+ const name = templateName(target, flags);
695
+ const ref =
696
+ flags.ref ??
697
+ target.provenance.templateRef ??
698
+ _getGitHubTemplateRefCandidates()[0] ??
699
+ null;
700
+ const materialized = await materializeTemplate({
701
+ appName: target.appName,
702
+ template: name,
703
+ ref: useLocalTemplate(target, ref) ? null : ref,
704
+ shape: target.shape,
705
+ workspaceRoot: target.workspaceRoot,
706
+ workspaceCoreName: target.workspaceCoreName,
707
+ });
708
+ try {
709
+ const written = writeBaseline(store, materialized.dir, "baseline", {
710
+ template: name,
711
+ templateRef: materialized.ref,
712
+ coreVersion: _getCorePackageVersion(),
713
+ });
714
+ backfillProvenance(target, name, materialized);
715
+ io.out(
716
+ `${target.appName}: baseline recorded at ${written.location} (${name} @ ${materialized.ref}).`,
717
+ );
718
+ reportRefspecs(written.configuredRefspecs, io);
719
+ return 0;
720
+ } finally {
721
+ fs.rmSync(materialized.dir, { recursive: true, force: true });
722
+ }
723
+ }
724
+
725
+ function acceptCommand(target: AppTarget, io: TemplateIO): number {
726
+ const store = resolveBaselineStore(target.appDir);
727
+ if (!baselineExists(store, "pending")) {
728
+ io.err(`${target.appName}: nothing to accept — no pending sync recorded.`);
729
+ return 1;
730
+ }
731
+ const markers = findConflictMarkers(target.appDir);
732
+ if (markers.length > 0) {
733
+ io.err(
734
+ `${target.appName}: accept refused because conflict markers remain. Resolve them first:`,
735
+ );
736
+ for (const file of markers.slice(0, 20)) io.err(` ${file}`);
737
+ if (markers.length > 20) io.err(` … ${markers.length - 20} more`);
738
+ return 1;
739
+ }
740
+ promoteBaseline(store, "pending", "baseline");
741
+ io.out(
742
+ `${target.appName}: baseline advanced to the last synced template tree.`,
743
+ );
744
+ return 0;
745
+ }
746
+
747
+ /* ─────────────────────────────────────────────────────────────────────────
748
+ * Helpers
749
+ * ───────────────────────────────────────────────────────────────────────── */
750
+
751
+ function useLocalTemplate(target: AppTarget, ref: string | null): boolean {
752
+ if (!ref) return true;
753
+ const source = target.provenance.templateSource;
754
+ if (source !== "bundled" && source !== "local-checkout") return false;
755
+ return ref === target.provenance.templateRef;
756
+ }
757
+
758
+ async function materializeForTarget(
759
+ target: AppTarget,
760
+ flags: TemplateFlags,
761
+ ref: string | null,
762
+ ): Promise<MaterializeResult> {
763
+ return materializeTemplate({
764
+ appName: target.appName,
765
+ template: templateName(target, flags),
766
+ ref: useLocalTemplate(target, ref) ? null : ref,
767
+ shape: target.shape,
768
+ workspaceRoot: target.workspaceRoot,
769
+ workspaceCoreName: target.workspaceCoreName,
770
+ });
771
+ }
772
+
773
+ function backfillProvenance(
774
+ target: AppTarget,
775
+ template: string,
776
+ materialized: MaterializeResult,
777
+ ): void {
778
+ const pkgPath = path.join(target.appDir, "package.json");
779
+ const pkg = readJson(pkgPath);
780
+ if (!pkg) return;
781
+ const agentNative =
782
+ pkg["agent-native"] && typeof pkg["agent-native"] === "object"
783
+ ? (pkg["agent-native"] as Record<string, unknown>)
784
+ : {};
785
+ const scaffold =
786
+ agentNative.scaffold && typeof agentNative.scaffold === "object"
787
+ ? (agentNative.scaffold as Record<string, unknown>)
788
+ : {};
789
+ agentNative.scaffold = {
790
+ ...scaffold,
791
+ template: scaffold.template ?? template,
792
+ templateRef: materialized.ref,
793
+ templateSource: materialized.source,
794
+ coreVersion: _getCorePackageVersion(),
795
+ shape: target.shape,
796
+ };
797
+ pkg["agent-native"] = agentNative;
798
+ fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
799
+ }
800
+
801
+ function countLocallyModified(appDir: string, baseDir: string): number {
802
+ let count = 0;
803
+ for (const rel of listMergeableFiles(baseDir)) {
804
+ const base = readFileOrNull(path.join(baseDir, rel));
805
+ const ours = readFileOrNull(path.join(appDir, rel));
806
+ if (!equalBuffers(base, ours)) count++;
807
+ }
808
+ return count;
809
+ }
810
+
811
+ function countUpstreamChanged(baseDir: string, theirsDir: string): number {
812
+ const paths = new Set([
813
+ ...listMergeableFiles(baseDir),
814
+ ...listMergeableFiles(theirsDir),
815
+ ]);
816
+ let count = 0;
817
+ for (const rel of paths) {
818
+ const base = readFileOrNull(path.join(baseDir, rel));
819
+ const theirs = readFileOrNull(path.join(theirsDir, rel));
820
+ if (!equalBuffers(base, theirs)) count++;
821
+ }
822
+ return count;
823
+ }
824
+
825
+ function renderTreeDiff(baseDir: string, theirsDir: string): string {
826
+ const staging = fs.mkdtempSync(path.join(os.tmpdir(), "an-template-diff-"));
827
+ try {
828
+ const a = path.join(staging, "a");
829
+ const b = path.join(staging, "b");
830
+ copyMergeable(baseDir, a);
831
+ copyMergeable(theirsDir, b);
832
+ const res = spawnSync(
833
+ "git",
834
+ [
835
+ "diff",
836
+ "--no-index",
837
+ "--src-prefix=upstream-base/",
838
+ "--dst-prefix=upstream-new/",
839
+ "--",
840
+ "a",
841
+ "b",
842
+ ],
843
+ { cwd: staging, encoding: "utf-8", maxBuffer: 128 * 1024 * 1024 },
844
+ );
845
+ const output = (res.stdout ?? "").toString();
846
+ // Only the staging dir names leak into headers; content lines cannot
847
+ // contain the prefixed form, so this rewrite is safe.
848
+ return output.trim()
849
+ ? output
850
+ .replaceAll("upstream-base/a/", "upstream-base/")
851
+ .replaceAll("upstream-new/b/", "upstream-new/")
852
+ : "No upstream changes.";
853
+ } finally {
854
+ fs.rmSync(staging, { recursive: true, force: true });
855
+ }
856
+ }
857
+
858
+ function copyMergeable(from: string, to: string): void {
859
+ fs.mkdirSync(to, { recursive: true });
860
+ for (const rel of listMergeableFiles(from)) {
861
+ const dest = path.join(to, rel);
862
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
863
+ fs.copyFileSync(path.join(from, rel), dest);
864
+ }
865
+ }
866
+
867
+ function findConflictMarkers(appDir: string): string[] {
868
+ const hits: string[] = [];
869
+ for (const rel of listMergeableFiles(appDir)) {
870
+ const buf = readFileOrNull(path.join(appDir, rel));
871
+ if (!buf || !isTextBuffer(buf)) continue;
872
+ if (buf.toString("utf-8").includes(`${CONFLICT_MARKER} `)) hits.push(rel);
873
+ }
874
+ return hits;
875
+ }
876
+
877
+ function formatMergeResult(
878
+ target: AppTarget,
879
+ ref: string,
880
+ result: TemplateMergeResult,
881
+ dryRun: boolean,
882
+ ): string {
883
+ const lines = [
884
+ `${target.appName}: ${dryRun ? "would sync" : "synced"} template at ${ref}`,
885
+ ` added: ${result.added.length}`,
886
+ ` updated: ${result.updated.length}`,
887
+ ` deleted: ${result.deleted.length}`,
888
+ ` conflicted: ${result.conflicted.length}`,
889
+ ];
890
+ for (const [label, items] of [
891
+ ["added", result.added],
892
+ ["updated", result.updated],
893
+ ["deleted", result.deleted],
894
+ ["conflicted", result.conflicted],
895
+ ["manual", result.manual],
896
+ ["kept local (deleted upstream)", result.keptLocal],
897
+ ] as const) {
898
+ if (items.length === 0) continue;
899
+ lines.push(` ${label}:`);
900
+ for (const item of items) lines.push(` ${item}`);
901
+ }
902
+ return lines.join("\n");
903
+ }
904
+
905
+ function reportRefspecs(configured: string[], io: TemplateIO): void {
906
+ if (configured.length === 0) return;
907
+ io.out(
908
+ `Configured ${configured.join(" and ")} to carry refs/agent-native/* so the baseline survives clone and push.`,
909
+ );
910
+ }
911
+
912
+ const VALUE_FLAGS = new Set(["--to", "--ref", "--template"]);
913
+
914
+ /** A flag's value must never be mistaken for the [app] positional. */
915
+ function positionalArgs(args: string[]): string[] {
916
+ const out: string[] = [];
917
+ for (let i = 0; i < args.length; i++) {
918
+ const arg = args[i]!;
919
+ if (arg.startsWith("-")) {
920
+ if (VALUE_FLAGS.has(arg)) i++;
921
+ continue;
922
+ }
923
+ out.push(arg);
924
+ }
925
+ return out;
926
+ }
927
+
928
+ function flagValue(args: string[], flag: string): string | undefined {
929
+ const index = args.indexOf(flag);
930
+ if (index >= 0 && args[index + 1]) return args[index + 1];
931
+ const inline = args.find((arg) => arg.startsWith(`${flag}=`));
932
+ return inline?.slice(flag.length + 1);
933
+ }
934
+
935
+ function readJson(file: string): Record<string, any> | null {
936
+ try {
937
+ return JSON.parse(fs.readFileSync(file, "utf-8"));
938
+ } catch {
939
+ return null;
940
+ }
941
+ }
942
+
943
+ function readFileOrNull(file: string): Buffer | null {
944
+ try {
945
+ const stat = fs.lstatSync(file);
946
+ if (!stat.isFile()) return null;
947
+ return fs.readFileSync(file);
948
+ } catch {
949
+ return null;
950
+ }
951
+ }
952
+
953
+ function isLocalSymlink(file: string): boolean {
954
+ try {
955
+ return fs.lstatSync(file).isSymbolicLink();
956
+ } catch {
957
+ return false;
958
+ }
959
+ }
960
+
961
+ function writeFile(file: string, content: Buffer): void {
962
+ fs.mkdirSync(path.dirname(file), { recursive: true });
963
+ fs.writeFileSync(file, content);
964
+ }
965
+
966
+ function removeFile(file: string): void {
967
+ fs.rmSync(file, { force: true });
968
+ }
969
+
970
+ function equalBuffers(a: Buffer | null, b: Buffer | null): boolean {
971
+ if (a === null || b === null) return a === b;
972
+ return a.equals(b);
973
+ }
974
+
975
+ function isTextBuffer(buf: Buffer | null): boolean {
976
+ if (buf === null) return true;
977
+ const isUtf8 = (Buffer as unknown as { isUtf8?: (b: Buffer) => boolean })
978
+ .isUtf8;
979
+ if (isUtf8) return isUtf8(buf) && !buf.includes(0);
980
+ return !buf.includes(0);
981
+ }
982
+
983
+ function templateUsage(): string {
984
+ return [
985
+ "agent-native template <command> [app] [options]",
986
+ "",
987
+ "Pull later upstream first-party template changes into a generated app",
988
+ "with a real 3-way merge against the tree it was scaffolded from.",
989
+ "",
990
+ "Commands:",
991
+ " status [app] Recorded ref, latest ref, baseline health, change counts",
992
+ " diff [app] [--to <ref>] Unified diff of what upstream changed (read-only)",
993
+ " sync [app] [--to <ref>] 3-way merge upstream changes into the app",
994
+ " [--dry-run] [--force]",
995
+ " baseline [app] Record a baseline for an app scaffolded before",
996
+ " provenance existed [--ref <ref>] [--template <name>]",
997
+ " accept [app] Advance the baseline after resolving conflicts",
998
+ "",
999
+ "With no [app], operates on the current app, or on every app in a workspace",
1000
+ "when run from the workspace root. --to defaults to the ref matching the",
1001
+ "installed @agent-native/core, so `agent-native upgrade` then",
1002
+ "`agent-native template sync` is the coherent story.",
1003
+ ].join("\n");
1004
+ }