@agent-native/toolkit 0.228.0-nightly-20261111212500 → 0.228.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/agent-native.eject.json +2 -0
  2. package/dist/app/agentkit/react/approval-card.d.ts.map +1 -1
  3. package/dist/app/agentkit/react/approval-card.js +5 -3
  4. package/dist/app/agentkit/react/approval-card.js.map +1 -1
  5. package/dist/app/agentkit/react/code-block.d.ts +32 -0
  6. package/dist/app/agentkit/react/code-block.d.ts.map +1 -0
  7. package/dist/app/agentkit/react/code-block.js +125 -0
  8. package/dist/app/agentkit/react/code-block.js.map +1 -0
  9. package/dist/app/agentkit/react/components.d.ts +33 -14
  10. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  11. package/dist/app/agentkit/react/components.js +843 -168
  12. package/dist/app/agentkit/react/components.js.map +1 -1
  13. package/dist/app/agentkit/react/context-usage.d.ts +45 -0
  14. package/dist/app/agentkit/react/context-usage.d.ts.map +1 -0
  15. package/dist/app/agentkit/react/context-usage.js +93 -0
  16. package/dist/app/agentkit/react/context-usage.js.map +1 -0
  17. package/dist/app/agentkit/react/context.d.ts +42 -3
  18. package/dist/app/agentkit/react/context.d.ts.map +1 -1
  19. package/dist/app/agentkit/react/context.js +46 -1
  20. package/dist/app/agentkit/react/context.js.map +1 -1
  21. package/dist/app/agentkit/react/disclosure-content.d.ts +12 -0
  22. package/dist/app/agentkit/react/disclosure-content.d.ts.map +1 -0
  23. package/dist/app/agentkit/react/disclosure-content.js +33 -0
  24. package/dist/app/agentkit/react/disclosure-content.js.map +1 -0
  25. package/dist/app/agentkit/react/duration.d.ts +6 -0
  26. package/dist/app/agentkit/react/duration.d.ts.map +1 -0
  27. package/dist/app/agentkit/react/duration.js +21 -0
  28. package/dist/app/agentkit/react/duration.js.map +1 -0
  29. package/dist/app/agentkit/react/file-change.d.ts +33 -0
  30. package/dist/app/agentkit/react/file-change.d.ts.map +1 -0
  31. package/dist/app/agentkit/react/file-change.js +83 -0
  32. package/dist/app/agentkit/react/file-change.js.map +1 -0
  33. package/dist/app/agentkit/react/file-diff.d.ts +17 -0
  34. package/dist/app/agentkit/react/file-diff.d.ts.map +1 -0
  35. package/dist/app/agentkit/react/file-diff.js +94 -0
  36. package/dist/app/agentkit/react/file-diff.js.map +1 -0
  37. package/dist/app/agentkit/react/index.d.ts +7 -0
  38. package/dist/app/agentkit/react/index.d.ts.map +1 -1
  39. package/dist/app/agentkit/react/index.js +7 -0
  40. package/dist/app/agentkit/react/index.js.map +1 -1
  41. package/dist/app/agentkit/react/question-card.d.ts +67 -0
  42. package/dist/app/agentkit/react/question-card.d.ts.map +1 -0
  43. package/dist/app/agentkit/react/question-card.js +198 -0
  44. package/dist/app/agentkit/react/question-card.js.map +1 -0
  45. package/dist/app/agentkit/react/root.d.ts +3 -2
  46. package/dist/app/agentkit/react/root.d.ts.map +1 -1
  47. package/dist/app/agentkit/react/root.js +2 -2
  48. package/dist/app/agentkit/react/root.js.map +1 -1
  49. package/dist/app/agentkit/react/roving-focus.d.ts +4 -0
  50. package/dist/app/agentkit/react/roving-focus.d.ts.map +1 -0
  51. package/dist/app/agentkit/react/roving-focus.js +75 -0
  52. package/dist/app/agentkit/react/roving-focus.js.map +1 -0
  53. package/dist/app/agentkit/react/stack-trace.d.ts +34 -0
  54. package/dist/app/agentkit/react/stack-trace.d.ts.map +1 -0
  55. package/dist/app/agentkit/react/stack-trace.js +121 -0
  56. package/dist/app/agentkit/react/stack-trace.js.map +1 -0
  57. package/dist/app/agentkit/react/stop-button.d.ts.map +1 -1
  58. package/dist/app/agentkit/react/stop-button.js +22 -6
  59. package/dist/app/agentkit/react/stop-button.js.map +1 -1
  60. package/dist/app/agentkit/react/styles.css +1306 -395
  61. package/dist/app/agentkit/react/terminal.d.ts +28 -0
  62. package/dist/app/agentkit/react/terminal.d.ts.map +1 -0
  63. package/dist/app/agentkit/react/terminal.js +84 -0
  64. package/dist/app/agentkit/react/terminal.js.map +1 -0
  65. package/dist/app/agentkit/react/trace.d.ts +31 -0
  66. package/dist/app/agentkit/react/trace.d.ts.map +1 -0
  67. package/dist/app/agentkit/react/trace.js +73 -0
  68. package/dist/app/agentkit/react/trace.js.map +1 -0
  69. package/dist/app/blocks/library/HighlightedCode.d.ts +2 -1
  70. package/dist/app/blocks/library/HighlightedCode.d.ts.map +1 -1
  71. package/dist/app/blocks/library/HighlightedCode.js +8 -111
  72. package/dist/app/blocks/library/HighlightedCode.js.map +1 -1
  73. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  74. package/dist/app/chat/AgentKitAssistantChat.js +23 -245
  75. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  76. package/dist/app/chat/agentkit-chat/guided-questions.d.ts +15 -1
  77. package/dist/app/chat/agentkit-chat/guided-questions.d.ts.map +1 -1
  78. package/dist/app/chat/agentkit-chat/guided-questions.js +142 -2
  79. package/dist/app/chat/agentkit-chat/guided-questions.js.map +1 -1
  80. package/dist/app/chat/agentkit-chat/history.js +1 -1
  81. package/dist/app/chat/agentkit-chat/history.js.map +1 -1
  82. package/dist/app/chat/agentkit-chat/index.d.ts +1 -1
  83. package/dist/app/chat/agentkit-chat/index.d.ts.map +1 -1
  84. package/dist/app/chat/agentkit-chat/index.js +1 -1
  85. package/dist/app/chat/agentkit-chat/index.js.map +1 -1
  86. package/dist/app/chat/agentkit-chat/labels.d.ts +5 -0
  87. package/dist/app/chat/agentkit-chat/labels.d.ts.map +1 -0
  88. package/dist/app/chat/agentkit-chat/labels.js +245 -0
  89. package/dist/app/chat/agentkit-chat/labels.js.map +1 -0
  90. package/dist/app/chat/agentkit-chat/questions.d.ts +1 -1
  91. package/dist/app/chat/agentkit-chat/questions.d.ts.map +1 -1
  92. package/dist/app/chat/agentkit-chat/questions.js +1 -1
  93. package/dist/app/chat/agentkit-chat/questions.js.map +1 -1
  94. package/dist/app/chat/agentkit-chat/root.d.ts.map +1 -1
  95. package/dist/app/chat/agentkit-chat/root.js +5 -64
  96. package/dist/app/chat/agentkit-chat/root.js.map +1 -1
  97. package/dist/app/chat/agentkit-chat/work-step-labels.d.ts +2 -0
  98. package/dist/app/chat/agentkit-chat/work-step-labels.d.ts.map +1 -1
  99. package/dist/app/chat/agentkit-chat/work-step-labels.js +31 -0
  100. package/dist/app/chat/agentkit-chat/work-step-labels.js.map +1 -1
  101. package/dist/app/chat/chat/markdown-renderer.d.ts +2 -12
  102. package/dist/app/chat/chat/markdown-renderer.d.ts.map +1 -1
  103. package/dist/app/chat/chat/markdown-renderer.js +2 -41
  104. package/dist/app/chat/chat/markdown-renderer.js.map +1 -1
  105. package/dist/app/chat/chat/tool-call-display.d.ts.map +1 -1
  106. package/dist/app/chat/chat/tool-call-display.js +2 -2
  107. package/dist/app/chat/chat/tool-call-display.js.map +1 -1
  108. package/dist/app/chat/conversation/AgentConversation.d.ts.map +1 -1
  109. package/dist/app/chat/conversation/AgentConversation.js +2 -37
  110. package/dist/app/chat/conversation/AgentConversation.js.map +1 -1
  111. package/dist/app/chat/tool-cells/BashCell.d.ts +3 -1
  112. package/dist/app/chat/tool-cells/BashCell.d.ts.map +1 -1
  113. package/dist/app/chat/tool-cells/BashCell.js +4 -40
  114. package/dist/app/chat/tool-cells/BashCell.js.map +1 -1
  115. package/dist/app/chat/tool-cells/EditCell.d.ts.map +1 -1
  116. package/dist/app/chat/tool-cells/EditCell.js +5 -108
  117. package/dist/app/chat/tool-cells/EditCell.js.map +1 -1
  118. package/dist/app/chat/tool-cells/FilesChangedSummary.d.ts.map +1 -1
  119. package/dist/app/chat/tool-cells/FilesChangedSummary.js +23 -81
  120. package/dist/app/chat/tool-cells/FilesChangedSummary.js.map +1 -1
  121. package/dist/app/chat/tool-cells/WriteCell.d.ts.map +1 -1
  122. package/dist/app/chat/tool-cells/WriteCell.js +5 -24
  123. package/dist/app/chat/tool-cells/WriteCell.js.map +1 -1
  124. package/dist/app/code-highlighter.d.ts +11 -0
  125. package/dist/app/code-highlighter.d.ts.map +1 -0
  126. package/dist/app/code-highlighter.js +122 -0
  127. package/dist/app/code-highlighter.js.map +1 -0
  128. package/dist/app/context-xray/ThreadContextRing.js +3 -3
  129. package/dist/app/context-xray/ThreadContextRing.js.map +1 -1
  130. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  131. package/dist/app/i18n/catalogs/ar-SA.js +22 -0
  132. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  133. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  134. package/dist/app/i18n/catalogs/de-DE.js +22 -0
  135. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  136. package/dist/app/i18n/catalogs/en-US.d.ts +22 -0
  137. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  138. package/dist/app/i18n/catalogs/en-US.js +22 -0
  139. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  140. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  141. package/dist/app/i18n/catalogs/es-ES.js +22 -0
  142. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  143. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  144. package/dist/app/i18n/catalogs/fr-FR.js +22 -0
  145. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  146. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  147. package/dist/app/i18n/catalogs/hi-IN.js +22 -0
  148. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  149. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  150. package/dist/app/i18n/catalogs/ja-JP.js +22 -0
  151. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  152. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  153. package/dist/app/i18n/catalogs/ko-KR.js +22 -0
  154. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  155. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  156. package/dist/app/i18n/catalogs/pt-BR.js +22 -0
  157. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  158. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  159. package/dist/app/i18n/catalogs/zh-CN.js +22 -0
  160. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  161. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  162. package/dist/app/i18n/catalogs/zh-TW.js +22 -0
  163. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  164. package/dist/app/onboarding/first-run-first-paint.d.ts +10 -0
  165. package/dist/app/onboarding/first-run-first-paint.d.ts.map +1 -0
  166. package/dist/app/onboarding/first-run-first-paint.js +22 -0
  167. package/dist/app/onboarding/first-run-first-paint.js.map +1 -0
  168. package/dist/app/onboarding/first-run-startup-gate.d.ts +3 -1
  169. package/dist/app/onboarding/first-run-startup-gate.d.ts.map +1 -1
  170. package/dist/app/onboarding/first-run-startup-gate.js +30 -6
  171. package/dist/app/onboarding/first-run-startup-gate.js.map +1 -1
  172. package/dist/app/providers/AppProviders.d.ts.map +1 -1
  173. package/dist/app/providers/AppProviders.js +9 -2
  174. package/dist/app/providers/AppProviders.js.map +1 -1
  175. package/dist/app/providers/BuilderSignupActivation.d.ts +2 -1
  176. package/dist/app/providers/BuilderSignupActivation.d.ts.map +1 -1
  177. package/dist/app/providers/BuilderSignupActivation.js +6 -3
  178. package/dist/app/providers/BuilderSignupActivation.js.map +1 -1
  179. package/dist/app/shared/AppShellSkeleton.d.ts.map +1 -1
  180. package/dist/app/shared/AppShellSkeleton.js +11 -1
  181. package/dist/app/shared/AppShellSkeleton.js.map +1 -1
  182. package/dist/app/styles/agent-native.css +2 -2
  183. package/dist/app/styles/tokens/agent-kit.css +20 -3
  184. package/dist/composer/AgentSuggestionBar.d.ts.map +1 -1
  185. package/dist/composer/AgentSuggestionBar.js +2 -2
  186. package/dist/composer/AgentSuggestionBar.js.map +1 -1
  187. package/dist/composer/ComposerContextMenu.js +4 -4
  188. package/dist/composer/ComposerContextMenu.js.map +1 -1
  189. package/dist/composer/ComposerContextPicker.d.ts.map +1 -1
  190. package/dist/composer/ComposerContextPicker.js +2 -2
  191. package/dist/composer/ComposerContextPicker.js.map +1 -1
  192. package/dist/composer/ComposerContextPickerDialog.d.ts.map +1 -1
  193. package/dist/composer/ComposerContextPickerDialog.js +2 -2
  194. package/dist/composer/ComposerContextPickerDialog.js.map +1 -1
  195. package/dist/composer/ComposerModePicker.d.ts.map +1 -1
  196. package/dist/composer/ComposerModePicker.js +2 -1
  197. package/dist/composer/ComposerModePicker.js.map +1 -1
  198. package/dist/composer/ComposerPlusMenu.js +1 -1
  199. package/dist/composer/ComposerPlusMenu.js.map +1 -1
  200. package/dist/composer/MentionChip.js +1 -1
  201. package/dist/composer/MentionChip.js.map +1 -1
  202. package/dist/composer/MentionPopover.d.ts +3 -0
  203. package/dist/composer/MentionPopover.d.ts.map +1 -1
  204. package/dist/composer/MentionPopover.js +34 -15
  205. package/dist/composer/MentionPopover.js.map +1 -1
  206. package/dist/composer/MessageQueueDrawer.d.ts.map +1 -1
  207. package/dist/composer/MessageQueueDrawer.js +14 -9
  208. package/dist/composer/MessageQueueDrawer.js.map +1 -1
  209. package/dist/composer/PastedTextChip.d.ts.map +1 -1
  210. package/dist/composer/PastedTextChip.js +14 -18
  211. package/dist/composer/PastedTextChip.js.map +1 -1
  212. package/dist/composer/PromptBar.js +1 -1
  213. package/dist/composer/PromptBar.js.map +1 -1
  214. package/dist/composer/PromptComposer.d.ts.map +1 -1
  215. package/dist/composer/PromptComposer.js +11 -9
  216. package/dist/composer/PromptComposer.js.map +1 -1
  217. package/dist/composer/RealtimeVoiceMode.js +2 -2
  218. package/dist/composer/RealtimeVoiceMode.js.map +1 -1
  219. package/dist/composer/TiptapComposer.d.ts.map +1 -1
  220. package/dist/composer/TiptapComposer.js +52 -89
  221. package/dist/composer/TiptapComposer.js.map +1 -1
  222. package/dist/composer/VoiceButton.d.ts +3 -1
  223. package/dist/composer/VoiceButton.d.ts.map +1 -1
  224. package/dist/composer/VoiceButton.js +10 -8
  225. package/dist/composer/VoiceButton.js.map +1 -1
  226. package/dist/composer/composer-notice.js +3 -3
  227. package/dist/composer/composer-notice.js.map +1 -1
  228. package/dist/composer/extensions/FileReference.js +1 -1
  229. package/dist/composer/extensions/FileReference.js.map +1 -1
  230. package/dist/composer/extensions/SkillReference.js +1 -1
  231. package/dist/composer/extensions/SkillReference.js.map +1 -1
  232. package/dist/composer/popover-surface.d.ts +1 -1
  233. package/dist/composer/popover-surface.d.ts.map +1 -1
  234. package/dist/composer/popover-surface.js +1 -1
  235. package/dist/composer/popover-surface.js.map +1 -1
  236. package/dist/context-ui/ContextUsageRing.d.ts +1 -45
  237. package/dist/context-ui/ContextUsageRing.d.ts.map +1 -1
  238. package/dist/context-ui/ContextUsageRing.js +2 -87
  239. package/dist/context-ui/ContextUsageRing.js.map +1 -1
  240. package/dist/context-ui/index.d.ts +2 -2
  241. package/dist/context-ui/index.d.ts.map +1 -1
  242. package/dist/context-ui/index.js +2 -2
  243. package/dist/context-ui/index.js.map +1 -1
  244. package/package.json +4 -4
  245. package/src/app/agentkit/react/approval-card.tsx +14 -2
  246. package/src/app/agentkit/react/code-block.spec.tsx +154 -0
  247. package/src/app/agentkit/react/code-block.tsx +317 -0
  248. package/src/app/agentkit/react/components.interaction.spec.tsx +7 -0
  249. package/src/app/agentkit/react/components.papercuts.spec.tsx +143 -2
  250. package/src/app/agentkit/react/components.spec.tsx +40 -47
  251. package/src/app/agentkit/react/components.tsx +1533 -413
  252. package/src/app/agentkit/react/composer-context.spec.tsx +35 -0
  253. package/src/app/agentkit/react/context-usage.tsx +353 -0
  254. package/src/app/agentkit/react/context.tsx +93 -1
  255. package/src/app/agentkit/react/disclosure-content.ts +42 -0
  256. package/src/app/agentkit/react/disclosures.spec.tsx +62 -4
  257. package/src/app/agentkit/react/duration.ts +22 -0
  258. package/src/app/agentkit/react/file-change.spec.tsx +124 -0
  259. package/src/app/agentkit/react/file-change.tsx +228 -0
  260. package/src/app/agentkit/react/file-diff.ts +110 -0
  261. package/src/app/agentkit/react/index.ts +7 -0
  262. package/src/app/agentkit/react/lifecycle.spec.tsx +565 -20
  263. package/src/app/agentkit/react/markdown.spec.tsx +18 -8
  264. package/src/app/agentkit/react/message-actions.spec.tsx +55 -1
  265. package/src/app/agentkit/react/notices.spec.tsx +4 -4
  266. package/src/app/agentkit/react/optimistic-send.spec.tsx +43 -0
  267. package/src/app/agentkit/react/question-card.spec.tsx +276 -0
  268. package/src/app/agentkit/react/question-card.tsx +533 -0
  269. package/src/app/agentkit/react/root.tsx +4 -0
  270. package/src/app/agentkit/react/roving-focus.spec.tsx +114 -0
  271. package/src/app/agentkit/react/roving-focus.ts +82 -0
  272. package/src/app/agentkit/react/stack-trace.spec.tsx +177 -0
  273. package/src/app/agentkit/react/stack-trace.tsx +281 -0
  274. package/src/app/agentkit/react/stop-button.spec.tsx +40 -0
  275. package/src/app/agentkit/react/stop-button.tsx +22 -5
  276. package/src/app/agentkit/react/styles.css +1306 -395
  277. package/src/app/agentkit/react/subagent-step.spec.tsx +554 -0
  278. package/src/app/agentkit/react/terminal.spec.tsx +228 -0
  279. package/src/app/agentkit/react/terminal.tsx +228 -0
  280. package/src/app/agentkit/react/trace.spec.tsx +120 -0
  281. package/src/app/agentkit/react/trace.tsx +239 -0
  282. package/src/app/blocks/library/HighlightedCode.tsx +14 -126
  283. package/src/app/chat/AgentKitAssistantChat.spec.tsx +28 -12
  284. package/src/app/chat/AgentKitAssistantChat.tsx +27 -253
  285. package/src/app/chat/agentkit-chat/approval-card.spec.tsx +1 -0
  286. package/src/app/chat/agentkit-chat/guided-questions.flow.spec.tsx +381 -0
  287. package/src/app/chat/agentkit-chat/guided-questions.tsx +236 -3
  288. package/src/app/chat/agentkit-chat/history.tsx +1 -1
  289. package/src/app/chat/agentkit-chat/index.ts +2 -0
  290. package/src/app/chat/agentkit-chat/labels.ts +259 -0
  291. package/src/app/chat/agentkit-chat/questions.ts +2 -0
  292. package/src/app/chat/agentkit-chat/root.spec.tsx +18 -0
  293. package/src/app/chat/agentkit-chat/root.tsx +5 -64
  294. package/src/app/chat/agentkit-chat/work-step-labels.ts +42 -0
  295. package/src/app/chat/chat/markdown-renderer.tsx +2 -59
  296. package/src/app/chat/chat/tool-call-display.spec.tsx +26 -14
  297. package/src/app/chat/chat/tool-call-display.tsx +2 -1
  298. package/src/app/chat/conversation/AgentConversation.tsx +2 -50
  299. package/src/app/chat/tool-cells/BashCell.tsx +14 -136
  300. package/src/app/chat/tool-cells/EditCell.tsx +11 -248
  301. package/src/app/chat/tool-cells/FilesChangedSummary.spec.tsx +62 -5
  302. package/src/app/chat/tool-cells/FilesChangedSummary.tsx +31 -162
  303. package/src/app/chat/tool-cells/WriteCell.tsx +11 -121
  304. package/src/app/code-highlighter.ts +131 -0
  305. package/src/app/context-xray/ThreadContextRing.tsx +7 -7
  306. package/src/app/i18n/catalogs/ar-SA.ts +22 -0
  307. package/src/app/i18n/catalogs/de-DE.ts +22 -0
  308. package/src/app/i18n/catalogs/en-US.ts +22 -0
  309. package/src/app/i18n/catalogs/es-ES.ts +22 -0
  310. package/src/app/i18n/catalogs/fr-FR.ts +22 -0
  311. package/src/app/i18n/catalogs/hi-IN.ts +22 -0
  312. package/src/app/i18n/catalogs/ja-JP.ts +22 -0
  313. package/src/app/i18n/catalogs/ko-KR.ts +22 -0
  314. package/src/app/i18n/catalogs/pt-BR.ts +22 -0
  315. package/src/app/i18n/catalogs/zh-CN.ts +22 -0
  316. package/src/app/i18n/catalogs/zh-TW.ts +22 -0
  317. package/src/app/onboarding/first-run-first-paint.spec.ts +39 -0
  318. package/src/app/onboarding/first-run-first-paint.ts +24 -0
  319. package/src/app/onboarding/first-run-startup-gate.spec.tsx +125 -13
  320. package/src/app/onboarding/first-run-startup-gate.tsx +48 -5
  321. package/src/app/providers/AppProviders.tsx +18 -0
  322. package/src/app/providers/BuilderSignupActivation.tsx +8 -2
  323. package/src/app/shared/AppShellSkeleton.spec.tsx +60 -1
  324. package/src/app/shared/AppShellSkeleton.tsx +31 -1
  325. package/src/app/styles/agent-native.css +2 -2
  326. package/src/app/styles/agent-native.spec.ts +2 -2
  327. package/src/app/styles/tokens/agent-kit.css +20 -3
  328. package/src/composer/AgentSuggestionBar.spec.tsx +3 -1
  329. package/src/composer/AgentSuggestionBar.tsx +5 -2
  330. package/src/composer/ComposerContextMenu.tsx +4 -4
  331. package/src/composer/ComposerContextPicker.tsx +8 -2
  332. package/src/composer/ComposerContextPickerDialog.tsx +5 -2
  333. package/src/composer/ComposerModePicker.tsx +2 -1
  334. package/src/composer/ComposerPlusMenu.tsx +1 -1
  335. package/src/composer/MentionChip.tsx +1 -1
  336. package/src/composer/MentionPopover.spec.tsx +108 -2
  337. package/src/composer/MentionPopover.tsx +93 -17
  338. package/src/composer/MessageQueueDrawer.spec.tsx +5 -5
  339. package/src/composer/MessageQueueDrawer.tsx +19 -12
  340. package/src/composer/PastedTextChip.spec.tsx +36 -0
  341. package/src/composer/PastedTextChip.tsx +52 -58
  342. package/src/composer/PromptBar.tsx +1 -1
  343. package/src/composer/PromptComposer.context.spec.tsx +2 -2
  344. package/src/composer/PromptComposer.submission.spec.tsx +27 -0
  345. package/src/composer/PromptComposer.tsx +17 -9
  346. package/src/composer/RealtimeVoiceMode.tsx +2 -2
  347. package/src/composer/TiptapComposer.model-picker.spec.tsx +23 -82
  348. package/src/composer/TiptapComposer.tsx +68 -145
  349. package/src/composer/VoiceButton.tsx +12 -7
  350. package/src/composer/composer-notice.tsx +3 -3
  351. package/src/composer/extensions/FileReference.tsx +1 -1
  352. package/src/composer/extensions/SkillReference.tsx +1 -1
  353. package/src/composer/popover-surface.ts +1 -1
  354. package/src/context-ui/ContextUsageRing.spec.tsx +33 -8
  355. package/src/context-ui/ContextUsageRing.tsx +13 -348
  356. package/src/context-ui/index.ts +7 -1
  357. package/dist/composer/ModelPickerParts.d.ts +0 -20
  358. package/dist/composer/ModelPickerParts.d.ts.map +0 -1
  359. package/dist/composer/ModelPickerParts.js +0 -77
  360. package/dist/composer/ModelPickerParts.js.map +0 -1
  361. package/src/composer/ModelPickerParts.tsx +0 -188
@@ -45,10 +45,13 @@ const messages: ToolkitAgentChatTranslation = {
45
45
  "activity.groupLabel": "智能体活动",
46
46
  "activity.agents": "智能体协作",
47
47
  "activity.tasks": "智能体任务",
48
+ "activity.tasksProgress": "{{total}} 项中已完成 {{completed}} 项",
48
49
  "agent.started": "开始工作了",
49
50
  "agent.resumed": "恢复了工作",
50
51
  "agent.messaged": "发送了消息",
51
52
  "agent.delegated": "委派了工作",
53
+ "agent.working": "正在工作",
54
+ "agent.workedFor": "工作了 {{duration}}",
52
55
  "agent.paused": "暂停了工作",
53
56
  "agent.queued": "排队中",
54
57
  "agent.completed": "已完成",
@@ -422,6 +425,7 @@ const messages: ToolkitAgentChatTranslation = {
422
425
  "composer.attachmentTooLarge": "文件超过 8 MB",
423
426
  "composer.attachmentNotUtf8": "文件不是 UTF-8 文本",
424
427
  "composer.scrollToBottom": "滚动到底部",
428
+ "composer.skipToMessageBox": "跳到消息输入框",
425
429
  "composer.suggestedPrompts": "推荐提示",
426
430
  "composer.stopResponse": "停止响应",
427
431
  "composer.subAgentReadOnly":
@@ -577,6 +581,7 @@ const messages: ToolkitAgentChatTranslation = {
577
581
  "pastedText.remove": "移除粘贴的文本",
578
582
  "pastedText.title": "粘贴的文本",
579
583
  "voice.dictation.start": "听写({{shortcut}})",
584
+ "voice.dictation.startPlain": "听写",
580
585
  "voice.dictation.stopRecording": "停止录音",
581
586
  "voice.dictation.transcribing": "正在转写…",
582
587
  "voiceMode.errors.channelDisconnected": "实时语音控制通道已断开。",
@@ -3137,6 +3142,14 @@ const messages: ToolkitAgentChatTranslation = {
3137
3142
  "guided.other": "其他…",
3138
3143
  "guided.otherDescription": "准确告诉智能体你的意思。",
3139
3144
  "guided.recommended": "推荐",
3145
+ "guided.question": "问题",
3146
+ "guided.questionProgress": "{{current}}/{{total}}",
3147
+ "guided.questionProgressLabel": "第 {{current}} 个,共 {{total}} 个",
3148
+ "guided.ownResponse": "或者输入你自己的回答",
3149
+ "guided.next": "下一个",
3150
+ "guided.send": "发送",
3151
+ "guided.dismiss": "关闭问题",
3152
+ "guided.chooseFiles": "选择文件…",
3140
3153
  "guided.typeAnswer": "输入你的回答…",
3141
3154
  "guided.typeCustomAnswer": "输入自定义回答…",
3142
3155
  "guided.dropFiles": "将文件拖到此处,或",
@@ -3174,6 +3187,10 @@ const messages: ToolkitAgentChatTranslation = {
3174
3187
  "toolCells.showMoreLines": "再显示 {{count}} 行",
3175
3188
  "toolCells.partial": "部分",
3176
3189
  "toolCells.timedOut": "已超时",
3190
+ "toolCells.exitCode": "退出码 {{code}}",
3191
+ "toolCells.copyOutput": "复制输出",
3192
+ "toolCells.lineAdded": "已添加",
3193
+ "toolCells.lineRemoved": "已删除",
3177
3194
  "codeRequired.requestFailed": "请求失败({{status}})",
3178
3195
  "chatFirst.chats": "聊天",
3179
3196
  "chatFirst.noChats": "还没有聊天。",
@@ -3287,6 +3304,7 @@ const messages: ToolkitAgentChatTranslation = {
3287
3304
  "mentions.noCommands": "没有命令",
3288
3305
  "mentions.noMatches": "没有匹配项",
3289
3306
  "queue.dragToReorder": "拖动以重新排序",
3307
+ "queue.attachedImage": "附加的图片",
3290
3308
  "queue.moveUp": "上移",
3291
3309
  "queue.moveDown": "下移",
3292
3310
  "queue.movedToPosition": "已移到第 {{position}} 位,共 {{count}} 位",
@@ -3340,6 +3358,10 @@ const messages: ToolkitAgentChatTranslation = {
3340
3358
  "workSteps.readPagesOther": "阅读了 {{count}} 个网页",
3341
3359
  "workSteps.fetchedOne": "获取了 1 个 URL",
3342
3360
  "workSteps.fetchedOther": "获取了 {{count}} 个 URL",
3361
+ "workSteps.sourcesOne": "使用了 1 个来源",
3362
+ "workSteps.sourcesOther": "使用了 {{count}} 个来源",
3363
+ "workSteps.frameworkFrames": "{{count}} 个框架帧",
3364
+ "workSteps.copyStackTrace": "复制堆栈跟踪",
3343
3365
  "workSteps.readFilesOne": "读取了 1 个文件",
3344
3366
  "workSteps.readFilesOther": "读取了 {{count}} 个文件",
3345
3367
  "workSteps.editedOne": "编辑了 1 个文件",
@@ -46,10 +46,13 @@ const messages: ToolkitAgentChatTranslation = {
46
46
  "activity.groupLabel": "代理活動",
47
47
  "activity.agents": "代理協作",
48
48
  "activity.tasks": "代理任務",
49
+ "activity.tasksProgress": "{{total}} 項中已完成 {{completed}} 項",
49
50
  "agent.started": "開始工作",
50
51
  "agent.resumed": "恢復工作",
51
52
  "agent.messaged": "傳送了訊息",
52
53
  "agent.delegated": "已委派工作",
54
+ "agent.working": "正在工作",
55
+ "agent.workedFor": "工作了 {{duration}}",
53
56
  "agent.paused": "已暫停工作",
54
57
  "agent.queued": "排隊中",
55
58
  "agent.completed": "已完成",
@@ -423,6 +426,7 @@ const messages: ToolkitAgentChatTranslation = {
423
426
  "composer.attachmentTooLarge": "檔案超過 8 MB",
424
427
  "composer.attachmentNotUtf8": "檔案不是 UTF-8 文字",
425
428
  "composer.scrollToBottom": "捲動到底部",
429
+ "composer.skipToMessageBox": "跳至訊息輸入框",
426
430
  "composer.suggestedPrompts": "建議提示",
427
431
  "composer.stopResponse": "停止回應",
428
432
  "composer.subAgentReadOnly":
@@ -578,6 +582,7 @@ const messages: ToolkitAgentChatTranslation = {
578
582
  "pastedText.remove": "移除貼上的文字",
579
583
  "pastedText.title": "貼上的文字",
580
584
  "voice.dictation.start": "聽寫({{shortcut}})",
585
+ "voice.dictation.startPlain": "聽寫",
581
586
  "voice.dictation.stopRecording": "停止錄音",
582
587
  "voice.dictation.transcribing": "正在轉錄…",
583
588
  "voiceMode.errors.channelDisconnected": "即時語音控制頻道已中斷連線。",
@@ -3154,6 +3159,14 @@ const messages: ToolkitAgentChatTranslation = {
3154
3159
  "guided.other": "其他…",
3155
3160
  "guided.otherDescription": "明確告訴代理你的意思。",
3156
3161
  "guided.recommended": "推薦",
3162
+ "guided.question": "問題",
3163
+ "guided.questionProgress": "{{current}}/{{total}}",
3164
+ "guided.questionProgressLabel": "第 {{current}} 個,共 {{total}} 個",
3165
+ "guided.ownResponse": "或輸入你自己的回答",
3166
+ "guided.next": "下一個",
3167
+ "guided.send": "傳送",
3168
+ "guided.dismiss": "關閉問題",
3169
+ "guided.chooseFiles": "選擇檔案…",
3157
3170
  "guided.typeAnswer": "輸入你的回答…",
3158
3171
  "guided.typeCustomAnswer": "輸入自訂回答…",
3159
3172
  "guided.dropFiles": "將檔案拖曳到這裡,或",
@@ -3191,6 +3204,10 @@ const messages: ToolkitAgentChatTranslation = {
3191
3204
  "toolCells.showMoreLines": "再顯示 {{count}} 行",
3192
3205
  "toolCells.partial": "部分",
3193
3206
  "toolCells.timedOut": "已逾時",
3207
+ "toolCells.exitCode": "結束代碼 {{code}}",
3208
+ "toolCells.copyOutput": "複製輸出",
3209
+ "toolCells.lineAdded": "已新增",
3210
+ "toolCells.lineRemoved": "已刪除",
3194
3211
  "codeRequired.requestFailed": "要求失敗({{status}})",
3195
3212
  "chatFirst.chats": "聊天",
3196
3213
  "chatFirst.noChats": "還沒有聊天。",
@@ -3304,6 +3321,7 @@ const messages: ToolkitAgentChatTranslation = {
3304
3321
  "mentions.noCommands": "沒有指令",
3305
3322
  "mentions.noMatches": "沒有相符項目",
3306
3323
  "queue.dragToReorder": "拖曳以重新排序",
3324
+ "queue.attachedImage": "附加的圖片",
3307
3325
  "queue.moveUp": "上移",
3308
3326
  "queue.moveDown": "下移",
3309
3327
  "queue.movedToPosition": "已移到第 {{position}} 位,共 {{count}} 位",
@@ -3358,6 +3376,10 @@ const messages: ToolkitAgentChatTranslation = {
3358
3376
  "workSteps.readPagesOther": "閱讀了 {{count}} 個網頁",
3359
3377
  "workSteps.fetchedOne": "擷取了 1 個 URL",
3360
3378
  "workSteps.fetchedOther": "擷取了 {{count}} 個 URL",
3379
+ "workSteps.sourcesOne": "使用了 1 個來源",
3380
+ "workSteps.sourcesOther": "使用了 {{count}} 個來源",
3381
+ "workSteps.frameworkFrames": "{{count}} 個框架堆疊框",
3382
+ "workSteps.copyStackTrace": "複製堆疊追蹤",
3361
3383
  "workSteps.readFilesOne": "讀取了 1 個檔案",
3362
3384
  "workSteps.readFilesOther": "讀取了 {{count}} 個檔案",
3363
3385
  "workSteps.editedOne": "編輯了 1 個檔案",
@@ -0,0 +1,39 @@
1
+ // @vitest-environment happy-dom
2
+
3
+ import { FIRST_RUN_ONBOARDING_COOKIE } from "@agent-native/core/shared/first-run-onboarding";
4
+ import { afterEach, describe, expect, it } from "vitest";
5
+
6
+ import {
7
+ FIRST_RUN_PENDING_ATTRIBUTE,
8
+ getFirstRunFirstPaintScriptBody,
9
+ } from "./first-run-first-paint.js";
10
+
11
+ function runBootScript() {
12
+ // The body is inlined into the SSR shell as a classic script.
13
+ new Function(getFirstRunFirstPaintScriptBody())();
14
+ }
15
+
16
+ describe("first-run first-paint boot script", () => {
17
+ afterEach(() => {
18
+ document.documentElement.removeAttribute(FIRST_RUN_PENDING_ATTRIBUTE);
19
+ document.cookie = `${FIRST_RUN_ONBOARDING_COOKIE}=; Max-Age=0; path=/`;
20
+ document.cookie = "other=; Max-Age=0; path=/";
21
+ });
22
+
23
+ it("marks the document while the first-run cookie is present", () => {
24
+ document.cookie = "other=1; path=/";
25
+ document.cookie = `${FIRST_RUN_ONBOARDING_COOKIE}=1; path=/`;
26
+ runBootScript();
27
+ expect(
28
+ document.documentElement.hasAttribute(FIRST_RUN_PENDING_ATTRIBUTE),
29
+ ).toBe(true);
30
+ });
31
+
32
+ it("leaves the document unmarked without the cookie", () => {
33
+ document.cookie = "other=1; path=/";
34
+ runBootScript();
35
+ expect(
36
+ document.documentElement.hasAttribute(FIRST_RUN_PENDING_ATTRIBUTE),
37
+ ).toBe(false);
38
+ });
39
+ });
@@ -0,0 +1,24 @@
1
+ import { FIRST_RUN_ONBOARDING_COOKIE } from "@agent-native/core/shared/first-run-onboarding";
2
+
3
+ /**
4
+ * Set on <html> before the first paint while the first-run cookie says
5
+ * onboarding may start. The SSR shell is shared by every visitor, so a
6
+ * first-paint home is swapped for a plain skeleton by CSS keyed to this
7
+ * attribute, never by rendering a different tree.
8
+ */
9
+ export const FIRST_RUN_PENDING_ATTRIBUTE =
10
+ "data-agent-native-first-run-pending";
11
+
12
+ export function getFirstRunFirstPaintScriptBody(): string {
13
+ const entry = JSON.stringify(`${FIRST_RUN_ONBOARDING_COOKIE}=1`);
14
+ const attribute = JSON.stringify(FIRST_RUN_PENDING_ATTRIBUTE);
15
+ // An unreadable cookie leaves the attribute unset, which is what the startup
16
+ // gate does with one too: it skips first run (and logs why).
17
+ // coercion-ok: an inline pre-paint script has no caller to report to.
18
+ return `(function(){try{if(document.cookie.split(";").some(function(c){return c.trim()===${entry}}))document.documentElement.setAttribute(${attribute},"")}catch(_){}})();`;
19
+ }
20
+
21
+ export function clearFirstRunFirstPaint(): void {
22
+ if (typeof document === "undefined") return;
23
+ document.documentElement.removeAttribute(FIRST_RUN_PENDING_ATTRIBUTE);
24
+ }
@@ -29,17 +29,24 @@ vi.mock("@agent-native/core/client/onboarding/use-preview-mode", () => ({
29
29
  }));
30
30
 
31
31
  vi.mock("./FirstRunOnboarding.js", () => ({
32
- FirstRunOnboarding: ({ initialFirstRun }: { initialFirstRun?: boolean }) => (
33
- <div
34
- data-testid="first-run-onboarding"
35
- data-initial-first-run={String(initialFirstRun === true)}
36
- />
37
- ),
32
+ FirstRunOnboarding: ({ initialFirstRun }: { initialFirstRun?: boolean }) => {
33
+ const [mountId] = React.useState(() => ++nextOnboardingMountId);
34
+ return (
35
+ <div
36
+ data-testid="first-run-onboarding"
37
+ data-initial-first-run={String(initialFirstRun === true)}
38
+ data-mount-id={mountId}
39
+ />
40
+ );
41
+ },
38
42
  }));
39
43
 
44
+ let nextOnboardingMountId = 0;
45
+
40
46
  import { SessionPreloadContext } from "@agent-native/core/client/use-session";
41
47
  import { FIRST_RUN_ONBOARDING_COOKIE } from "@agent-native/core/shared/first-run-onboarding";
42
48
 
49
+ import { FIRST_RUN_PENDING_ATTRIBUTE } from "./first-run-first-paint.js";
43
50
  import {
44
51
  FirstRunOnboardingStartupGate,
45
52
  useFirstRunOnboardingGateOwnsSurface,
@@ -97,13 +104,17 @@ describe("FirstRunOnboardingStartupGate", () => {
97
104
  container.remove();
98
105
  vi.unstubAllGlobals();
99
106
  document.cookie = `${FIRST_RUN_ONBOARDING_COOKIE}=; Max-Age=0; path=/`;
107
+ document.documentElement.removeAttribute(FIRST_RUN_PENDING_ATTRIBUTE);
100
108
  });
101
109
 
102
- it("reserves onboarding ownership while Builder setup runs without mounting the onboarding surface", async () => {
110
+ it("covers the app while Builder setup defers an eligible first run, without mounting the onboarding surface", async () => {
103
111
  mocks.fetchStatus.mockResolvedValue(true);
104
112
  await act(async () => {
105
113
  root.render(
106
- <FirstRunOnboardingStartupGate deferSurface>
114
+ <FirstRunOnboardingStartupGate
115
+ deferSurface
116
+ cover={<div data-testid="startup-skeleton" />}
117
+ >
107
118
  <GateOwnershipProbe />
108
119
  </FirstRunOnboardingStartupGate>,
109
120
  );
@@ -111,20 +122,118 @@ describe("FirstRunOnboardingStartupGate", () => {
111
122
  expect(
112
123
  container.querySelector('[data-testid="gate-ownership"]')?.textContent,
113
124
  ).toBe("true");
125
+ // oracle-change: an eligible first run under deferral used to leave the
126
+ // home painted and usable, so it flashed before the role question.
127
+ expect(
128
+ container.querySelector(
129
+ "[data-first-run-cover] [data-testid='startup-skeleton']",
130
+ ),
131
+ ).not.toBeNull();
114
132
  expect(
115
133
  container.querySelector('[data-first-run-app-inert="true"]'),
116
- ).toBeNull();
117
- expect(container.querySelector("[aria-hidden='true']")).toBeNull();
134
+ ).not.toBeNull();
118
135
  expect(
119
136
  container
120
137
  .querySelector("[data-testid='gate-ownership']")
121
138
  ?.getAttribute("data-blocked"),
122
- ).toBe("false");
139
+ ).toBe("true");
123
140
  expect(
124
141
  container.querySelector('[data-testid="first-run-onboarding"]'),
125
142
  ).toBeNull();
126
143
  });
127
144
 
145
+ it("lifts the first-paint stand-in once first run is ruled out", async () => {
146
+ const status = deferred<boolean>();
147
+ mocks.fetchStatus.mockReturnValue(status.promise);
148
+ document.documentElement.setAttribute(FIRST_RUN_PENDING_ATTRIBUTE, "");
149
+
150
+ act(() => {
151
+ root.render(
152
+ <FirstRunOnboardingStartupGate>
153
+ <div data-testid="app-content">app</div>
154
+ </FirstRunOnboardingStartupGate>,
155
+ );
156
+ });
157
+ expect(
158
+ document.documentElement.hasAttribute(FIRST_RUN_PENDING_ATTRIBUTE),
159
+ ).toBe(true);
160
+
161
+ await act(async () => {
162
+ status.resolve(false);
163
+ await status.promise;
164
+ });
165
+ expect(
166
+ document.documentElement.hasAttribute(FIRST_RUN_PENDING_ATTRIBUTE),
167
+ ).toBe(false);
168
+ });
169
+
170
+ it("keeps an ineligible user's app usable while Builder setup defers onboarding", async () => {
171
+ mocks.fetchStatus.mockResolvedValue(false);
172
+ await act(async () => {
173
+ root.render(
174
+ <FirstRunOnboardingStartupGate deferSurface>
175
+ <GateOwnershipProbe />
176
+ </FirstRunOnboardingStartupGate>,
177
+ );
178
+ });
179
+ expect(container.querySelector("[data-first-run-cover]")).toBeNull();
180
+ expect(container.querySelector("[data-first-run-app-inert]")).toBeNull();
181
+ expect(
182
+ container
183
+ .querySelector("[data-testid='gate-ownership']")
184
+ ?.getAttribute("data-blocked"),
185
+ ).toBe("false");
186
+ });
187
+
188
+ it("keeps onboarding on screen when a deferral starts after it appears", async () => {
189
+ mocks.fetchStatus.mockResolvedValue(true);
190
+ const renderGate = (deferSurface: boolean) =>
191
+ act(async () => {
192
+ root.render(
193
+ <FirstRunOnboardingStartupGate deferSurface={deferSurface}>
194
+ <div data-testid="app-content">app</div>
195
+ </FirstRunOnboardingStartupGate>,
196
+ );
197
+ });
198
+ await renderGate(false);
199
+ await vi.waitFor(() => {
200
+ expect(
201
+ container.querySelector("[data-testid='first-run-onboarding']"),
202
+ ).not.toBeNull();
203
+ });
204
+ const mountId = container
205
+ .querySelector("[data-testid='first-run-onboarding']")
206
+ ?.getAttribute("data-mount-id");
207
+
208
+ await renderGate(true);
209
+
210
+ expect(
211
+ container
212
+ .querySelector("[data-testid='first-run-onboarding']")
213
+ ?.getAttribute("data-mount-id"),
214
+ ).toBe(mountId);
215
+ expect(container.querySelector("[data-first-run-cover]")).toBeNull();
216
+ expect(
217
+ container
218
+ .querySelector("[data-testid='app-content']")
219
+ ?.closest("[inert]"),
220
+ ).not.toBeNull();
221
+ });
222
+
223
+ it("paints a skeleton, not a blank screen, when the caller passes no cover", async () => {
224
+ mocks.fetchStatus.mockReturnValue(new Promise(() => {}));
225
+ await act(async () => {
226
+ root.render(
227
+ <FirstRunOnboardingStartupGate>
228
+ <div data-testid="app-content">app</div>
229
+ </FirstRunOnboardingStartupGate>,
230
+ );
231
+ });
232
+ expect(
233
+ container.querySelector("[data-first-run-cover] .skeleton-shimmer"),
234
+ ).not.toBeNull();
235
+ });
236
+
128
237
  it("holds the status read while the session preloads, then reads once it resolves", async () => {
129
238
  mocks.fetchStatus.mockResolvedValue(false);
130
239
  const renderGate = (preloading: boolean) =>
@@ -201,7 +310,7 @@ describe("FirstRunOnboardingStartupGate", () => {
201
310
  ).not.toBeNull();
202
311
  });
203
312
 
204
- it("keeps the app visible but inert while eligibility is unresolved", async () => {
313
+ it("keeps the app mounted, inert and covered while eligibility is unresolved", async () => {
205
314
  const status = deferred<boolean>();
206
315
  mocks.fetchStatus.mockReturnValue(status.promise);
207
316
 
@@ -218,7 +327,7 @@ describe("FirstRunOnboardingStartupGate", () => {
218
327
  expect(
219
328
  container.querySelector("[data-first-run-startup-loading]"),
220
329
  ).toBeNull();
221
- // oracle-change: the app paints behind onboarding while first-run eligibility resolves.
330
+ // oracle-change: the app stays mounted under the startup cover while first-run eligibility resolves.
222
331
  expect(
223
332
  container.querySelector("[data-testid='app-content']"),
224
333
  ).not.toBeNull();
@@ -226,6 +335,7 @@ describe("FirstRunOnboardingStartupGate", () => {
226
335
  expect(
227
336
  container.querySelector("[data-first-run-app-inert]"),
228
337
  ).not.toBeNull();
338
+ expect(container.querySelector("[data-first-run-cover]")).not.toBeNull();
229
339
  expect(
230
340
  container.querySelector("[data-testid='gate-ownership']")?.textContent,
231
341
  ).toBe("true");
@@ -235,6 +345,7 @@ describe("FirstRunOnboardingStartupGate", () => {
235
345
  await status.promise;
236
346
  });
237
347
  expect(container.querySelector("[data-first-run-app-inert]")).toBeNull();
348
+ expect(container.querySelector("[data-first-run-cover]")).toBeNull();
238
349
  });
239
350
 
240
351
  it("retries a failed status read before revealing a first-run app", async () => {
@@ -538,6 +649,7 @@ describe("FirstRunOnboardingStartupGate", () => {
538
649
  container.querySelector("[data-testid='first-run-onboarding']"),
539
650
  ).not.toBeNull();
540
651
  });
652
+ expect(container.querySelector("[data-first-run-cover]")).toBeNull();
541
653
  expect(container.querySelector("[data-first-run-app-hidden]")).toBeNull();
542
654
  expect(
543
655
  container.querySelector("[data-testid='app-content']"),
@@ -6,8 +6,10 @@ import { useOnboardingPreviewMode } from "@agent-native/core/client/onboarding/u
6
6
  import { useSessionPreloading } from "@agent-native/core/client/use-session";
7
7
  import { FIRST_RUN_ONBOARDING_COOKIE } from "@agent-native/core/shared/first-run-onboarding";
8
8
  import { Button } from "@agent-native/toolkit/ui/button";
9
+ import { Skeleton } from "@agent-native/toolkit/ui/skeleton";
9
10
  import React, { Suspense, lazy, useEffect, useState } from "react";
10
11
 
12
+ import { clearFirstRunFirstPaint } from "./first-run-first-paint.js";
11
13
  import {
12
14
  FirstRunOnboardingGateContext,
13
15
  StartupInteractionContext,
@@ -53,15 +55,27 @@ function readFirstRunOnboardingCookieState(): FirstRunCookieState {
53
55
  }
54
56
  }
55
57
 
58
+ function DefaultStartupCover() {
59
+ return (
60
+ <div className="flex h-full gap-4 p-4">
61
+ <Skeleton className="h-full w-60" />
62
+ <Skeleton className="h-full flex-1" />
63
+ </div>
64
+ );
65
+ }
66
+
56
67
  export function FirstRunOnboardingStartupGate({
57
68
  children,
58
69
  suppressSurface = false,
59
70
  deferSurface = false,
71
+ cover = <DefaultStartupCover />,
60
72
  }: {
61
73
  children: React.ReactNode;
62
74
  suppressSurface?: boolean;
63
75
  /** Another startup operation owns onboarding until it settles. */
64
76
  deferSurface?: boolean;
77
+ /** Fills the screen while first run is possible but not yet on screen. */
78
+ cover?: React.ReactNode;
65
79
  }) {
66
80
  const t = useT();
67
81
  const inheritedInteractionBlock = useStartupInteractionBlocked();
@@ -138,14 +152,42 @@ export function FirstRunOnboardingStartupGate({
138
152
  };
139
153
  }, [retryNumber, shouldResolve, preloading]);
140
154
 
155
+ useEffect(() => {
156
+ if (decision === "ineligible") clearFirstRunFirstPaint();
157
+ }, [decision]);
158
+
159
+ // A deferral that starts once onboarding is on screen must not unmount it:
160
+ // that drops the user's answers and shows the app between two dialogs.
161
+ const [surfaceShown, setSurfaceShown] = useState(false);
141
162
  const ownsSurface =
142
- !suppressSurface && !deferSurface && decision === "eligible";
163
+ !suppressSurface &&
164
+ decision === "eligible" &&
165
+ (!deferSurface || surfaceShown);
166
+ useEffect(() => {
167
+ if (ownsSurface) setSurfaceShown(true);
168
+ }, [ownsSurface]);
143
169
  const gateOwnsSurface =
144
170
  deferSurface || (!suppressSurface && decision !== "ineligible");
171
+ // Until first run is ruled out, the app must not paint: a frame of it
172
+ // before (or between) onboarding screens reads as a flash of the home.
173
+ const coversApp =
174
+ !suppressSurface &&
175
+ !ownsSurface &&
176
+ (decision === "pending" || decision === "eligible");
145
177
 
146
- // Deferral only reserves onboarding ownership. The operation deferring it
147
- // owns any cover; unknown eligibility must not disable unrelated app content.
148
- const appIsInert = gateOwnsSurface && !deferSurface;
178
+ // Deferral alone does not block the app: an ineligible user keeps using it
179
+ // while another startup operation settles.
180
+ const appIsInert =
181
+ coversApp || ownsSurface || (gateOwnsSurface && !deferSurface);
182
+ const coverElement = (
183
+ <div
184
+ aria-busy="true"
185
+ data-first-run-cover="true"
186
+ className="fixed inset-0 z-[100] bg-background"
187
+ >
188
+ {cover}
189
+ </div>
190
+ );
149
191
 
150
192
  return (
151
193
  <FirstRunOnboardingGateContext.Provider value={gateOwnsSurface}>
@@ -179,8 +221,9 @@ export function FirstRunOnboardingStartupGate({
179
221
  </Button>
180
222
  </div>
181
223
  )}
224
+ {coversApp && coverElement}
182
225
  {ownsSurface && (
183
- <Suspense fallback={null}>
226
+ <Suspense fallback={coverElement}>
184
227
  <FirstRunOnboarding initialFirstRun />
185
228
  </Suspense>
186
229
  )}
@@ -9,6 +9,7 @@ import {
9
9
  AgentNativeI18nProvider,
10
10
  type AgentNativeI18nProviderProps,
11
11
  } from "@agent-native/core/client/i18n";
12
+ import { isFirstRunOnboardingEnabled } from "@agent-native/core/client/onboarding/first-run-enabled";
12
13
  import { AgentNativeRouteWarmup } from "@agent-native/core/client/route-warmup";
13
14
  import {
14
15
  EMBEDDED_THEME_CHANGE_EVENT,
@@ -39,6 +40,7 @@ import {
39
40
  McpApprovalReviewGate,
40
41
  McpApprovalReviewSkeleton,
41
42
  } from "../mcp-approval/McpApprovalReview.js";
43
+ import { getFirstRunFirstPaintScriptBody } from "../onboarding/first-run-first-paint.js";
42
44
  import { FirstRunOnboardingStartupGate } from "../onboarding/first-run-startup-gate.js";
43
45
  import {
44
46
  AppShellSkeleton,
@@ -158,6 +160,17 @@ function McpAppWidgetBootScript() {
158
160
  );
159
161
  }
160
162
 
163
+ // Before the server-rendered skeleton paints, so a first-paint home never
164
+ // shows to someone about to see the role question.
165
+ function FirstRunFirstPaintScript() {
166
+ return (
167
+ <script
168
+ data-agent-native-first-run-first-paint="1"
169
+ dangerouslySetInnerHTML={{ __html: getFirstRunFirstPaintScriptBody() }}
170
+ />
171
+ );
172
+ }
173
+
161
174
  function EarlySessionBootstrapScript() {
162
175
  const sessionPath = agentNativePath("/_agent-native/auth/session");
163
176
  // The document handler starts this read again from the top of <head>, where
@@ -653,12 +666,14 @@ export function AppProviders({
653
666
  <BuilderSignupStartupGate
654
667
  experimentId={builderSignupExperiment}
655
668
  suppressSurface={skipFirstRunOnboarding}
669
+ cover={fallback}
656
670
  >
657
671
  {children}
658
672
  </BuilderSignupStartupGate>
659
673
  ) : (
660
674
  <FirstRunOnboardingStartupGate
661
675
  suppressSurface={skipFirstRunOnboarding}
676
+ cover={fallback}
662
677
  >
663
678
  {children}
664
679
  </FirstRunOnboardingStartupGate>
@@ -697,6 +712,9 @@ export function AppProviders({
697
712
  <>
698
713
  <EarlySessionBootstrapScript />
699
714
  <EarlyBetaRedirectScript />
715
+ {isFirstRunOnboardingEnabled() && !skipFirstRunOnboarding ? (
716
+ <FirstRunFirstPaintScript />
717
+ ) : null}
700
718
  </>
701
719
  )}
702
720
  <ClientOnly fallback={fallback}>
@@ -218,7 +218,8 @@ export function BuilderSignupActivationCover({
218
218
  {children}
219
219
  </div>
220
220
  {activating ? (
221
- <div className="fixed inset-0 z-50 flex gap-4 bg-background p-4">
221
+ // Above the first-run gate's cover, which waits under this one.
222
+ <div className="fixed inset-0 z-[110] flex gap-4 bg-background p-4">
222
223
  <span role="status" className="sr-only">
223
224
  {t("agentChat.common.loading")}
224
225
  </span>
@@ -239,7 +240,9 @@ export function BuilderSignupActivationCover({
239
240
  ) : statusError ? (
240
241
  <div
241
242
  role="alert"
242
- className="fixed bottom-4 right-4 z-50 flex max-w-sm flex-col items-start gap-3 rounded-lg border bg-background p-4 shadow-lg"
243
+ // Above the first-run gate's cover, which stays up while an unknown
244
+ // eligibility defers onboarding.
245
+ className="fixed bottom-4 right-4 z-[110] flex max-w-sm flex-col items-start gap-3 rounded-lg border bg-background p-4 shadow-lg"
243
246
  >
244
247
  {retryContent}
245
248
  </div>
@@ -251,10 +254,12 @@ export function BuilderSignupActivationCover({
251
254
  export function BuilderSignupStartupGate({
252
255
  experimentId,
253
256
  suppressSurface,
257
+ cover,
254
258
  children,
255
259
  }: {
256
260
  experimentId?: string;
257
261
  suppressSurface: boolean;
262
+ cover?: ReactNode;
258
263
  children: ReactNode;
259
264
  }) {
260
265
  const { session } = useSession();
@@ -274,6 +279,7 @@ export function BuilderSignupStartupGate({
274
279
  <FirstRunOnboardingStartupGate
275
280
  suppressSurface={suppressSurface}
276
281
  deferSurface={resolving || activating}
282
+ cover={cover}
277
283
  >
278
284
  {children}
279
285
  </FirstRunOnboardingStartupGate>