@stigmer/react 3.12.3 → 3.12.5

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 (493) hide show
  1. package/agent/steps/IdentityStep.d.ts.map +1 -1
  2. package/agent/steps/IdentityStep.js +2 -1
  3. package/agent/steps/IdentityStep.js.map +1 -1
  4. package/agent-instance/AgentInstanceDetailPanel.d.ts.map +1 -1
  5. package/agent-instance/AgentInstanceDetailPanel.js +2 -1
  6. package/agent-instance/AgentInstanceDetailPanel.js.map +1 -1
  7. package/api-key/CreateApiKeyForm.d.ts.map +1 -1
  8. package/api-key/CreateApiKeyForm.js +2 -1
  9. package/api-key/CreateApiKeyForm.js.map +1 -1
  10. package/attachment/AttachmentChipList.js +16 -6
  11. package/attachment/AttachmentChipList.js.map +1 -1
  12. package/attachment/index.d.ts +1 -1
  13. package/attachment/index.d.ts.map +1 -1
  14. package/attachment/index.js.map +1 -1
  15. package/attachment/useAttachments.d.ts +51 -8
  16. package/attachment/useAttachments.d.ts.map +1 -1
  17. package/attachment/useAttachments.js +74 -3
  18. package/attachment/useAttachments.js.map +1 -1
  19. package/channel/ChannelConversationsDialog.d.ts.map +1 -1
  20. package/channel/ChannelConversationsDialog.js +2 -1
  21. package/channel/ChannelConversationsDialog.js.map +1 -1
  22. package/channel/ChannelTemplatesDialog.d.ts.map +1 -1
  23. package/channel/ChannelTemplatesDialog.js +2 -1
  24. package/channel/ChannelTemplatesDialog.js.map +1 -1
  25. package/channel/ConnectSlackDialog.d.ts.map +1 -1
  26. package/channel/ConnectSlackDialog.js +2 -1
  27. package/channel/ConnectSlackDialog.js.map +1 -1
  28. package/channel/connect/ServingAppSection.d.ts.map +1 -1
  29. package/channel/connect/ServingAppSection.js +2 -1
  30. package/channel/connect/ServingAppSection.js.map +1 -1
  31. package/channel-app/CreateChannelAppForm.d.ts.map +1 -1
  32. package/channel-app/CreateChannelAppForm.js +2 -1
  33. package/channel-app/CreateChannelAppForm.js.map +1 -1
  34. package/composer/SessionComposer.d.ts.map +1 -1
  35. package/composer/SessionComposer.js +17 -10
  36. package/composer/SessionComposer.js.map +1 -1
  37. package/conversation/ConversationComposer.d.ts +19 -3
  38. package/conversation/ConversationComposer.d.ts.map +1 -1
  39. package/conversation/ConversationComposer.js +4 -4
  40. package/conversation/ConversationComposer.js.map +1 -1
  41. package/conversation/ConversationListPane.d.ts.map +1 -1
  42. package/conversation/ConversationListPane.js +2 -1
  43. package/conversation/ConversationListPane.js.map +1 -1
  44. package/conversation/ConversationTemplatePickerDialog.d.ts +63 -0
  45. package/conversation/ConversationTemplatePickerDialog.d.ts.map +1 -0
  46. package/conversation/ConversationTemplatePickerDialog.js +151 -0
  47. package/conversation/ConversationTemplatePickerDialog.js.map +1 -0
  48. package/conversation/ConversationTimelineView.d.ts.map +1 -1
  49. package/conversation/ConversationTimelineView.js +2 -1
  50. package/conversation/ConversationTimelineView.js.map +1 -1
  51. package/conversation/ConversationsWorkbench.d.ts.map +1 -1
  52. package/conversation/ConversationsWorkbench.js +16 -5
  53. package/conversation/ConversationsWorkbench.js.map +1 -1
  54. package/conversation/index.d.ts +3 -1
  55. package/conversation/index.d.ts.map +1 -1
  56. package/conversation/index.js +1 -0
  57. package/conversation/index.js.map +1 -1
  58. package/conversation/useConversationParticipation.d.ts +41 -4
  59. package/conversation/useConversationParticipation.d.ts.map +1 -1
  60. package/conversation/useConversationParticipation.js +13 -2
  61. package/conversation/useConversationParticipation.js.map +1 -1
  62. package/cursor-accounts/CursorAccountsConsole.d.ts.map +1 -1
  63. package/cursor-accounts/CursorAccountsConsole.js +2 -1
  64. package/cursor-accounts/CursorAccountsConsole.js.map +1 -1
  65. package/cursor-accounts/MemberKeysPanel.d.ts.map +1 -1
  66. package/cursor-accounts/MemberKeysPanel.js +2 -1
  67. package/cursor-accounts/MemberKeysPanel.js.map +1 -1
  68. package/dashboard/DashboardFailedRuns.d.ts.map +1 -1
  69. package/dashboard/DashboardFailedRuns.js +2 -1
  70. package/dashboard/DashboardFailedRuns.js.map +1 -1
  71. package/dependency-graph/DependencyGraph.d.ts.map +1 -1
  72. package/dependency-graph/DependencyGraph.js +2 -1
  73. package/dependency-graph/DependencyGraph.js.map +1 -1
  74. package/dependency-graph/DependencyTreeNode.d.ts.map +1 -1
  75. package/dependency-graph/DependencyTreeNode.js +2 -1
  76. package/dependency-graph/DependencyTreeNode.js.map +1 -1
  77. package/environment/EnvironmentPicker.d.ts.map +1 -1
  78. package/environment/EnvironmentPicker.js +2 -1
  79. package/environment/EnvironmentPicker.js.map +1 -1
  80. package/error/SecretFlowErrorGuide.d.ts.map +1 -1
  81. package/error/SecretFlowErrorGuide.js +2 -1
  82. package/error/SecretFlowErrorGuide.js.map +1 -1
  83. package/execution/ArtifactContentBody.d.ts.map +1 -1
  84. package/execution/ArtifactContentBody.js +2 -1
  85. package/execution/ArtifactContentBody.js.map +1 -1
  86. package/execution/ArtifactsWidget.d.ts.map +1 -1
  87. package/execution/ArtifactsWidget.js +2 -1
  88. package/execution/ArtifactsWidget.js.map +1 -1
  89. package/execution/FileChangeProgressBar.d.ts.map +1 -1
  90. package/execution/FileChangeProgressBar.js +2 -1
  91. package/execution/FileChangeProgressBar.js.map +1 -1
  92. package/execution/TodoList.d.ts.map +1 -1
  93. package/execution/TodoList.js +2 -1
  94. package/execution/TodoList.js.map +1 -1
  95. package/execution/WriteBacksWidget.d.ts.map +1 -1
  96. package/execution/WriteBacksWidget.js +2 -1
  97. package/execution/WriteBacksWidget.js.map +1 -1
  98. package/execution/tool-categories.d.ts +5 -22
  99. package/execution/tool-categories.d.ts.map +1 -1
  100. package/execution/tool-categories.js +8 -38
  101. package/execution/tool-categories.js.map +1 -1
  102. package/iam-policy/PeopleWithAccess.d.ts.map +1 -1
  103. package/iam-policy/PeopleWithAccess.js +2 -1
  104. package/iam-policy/PeopleWithAccess.js.map +1 -1
  105. package/iam-policy/PrincipalPicker.d.ts.map +1 -1
  106. package/iam-policy/PrincipalPicker.js +2 -1
  107. package/iam-policy/PrincipalPicker.js.map +1 -1
  108. package/iam-policy/RoleSelector.d.ts.map +1 -1
  109. package/iam-policy/RoleSelector.js +2 -1
  110. package/iam-policy/RoleSelector.js.map +1 -1
  111. package/identity-account/AccountPreferencesPanel.d.ts +35 -0
  112. package/identity-account/AccountPreferencesPanel.d.ts.map +1 -0
  113. package/identity-account/AccountPreferencesPanel.js +187 -0
  114. package/identity-account/AccountPreferencesPanel.js.map +1 -0
  115. package/identity-account/index.d.ts +8 -0
  116. package/identity-account/index.d.ts.map +1 -1
  117. package/identity-account/index.js +4 -0
  118. package/identity-account/index.js.map +1 -1
  119. package/identity-account/useAccountExecutionDefaults.d.ts +36 -0
  120. package/identity-account/useAccountExecutionDefaults.d.ts.map +1 -0
  121. package/identity-account/useAccountExecutionDefaults.js +46 -0
  122. package/identity-account/useAccountExecutionDefaults.js.map +1 -0
  123. package/identity-account/useMyIdentityAccount.d.ts +55 -0
  124. package/identity-account/useMyIdentityAccount.d.ts.map +1 -0
  125. package/identity-account/useMyIdentityAccount.js +37 -0
  126. package/identity-account/useMyIdentityAccount.js.map +1 -0
  127. package/identity-account/useUpdateIdentityAccount.d.ts +42 -0
  128. package/identity-account/useUpdateIdentityAccount.d.ts.map +1 -0
  129. package/identity-account/useUpdateIdentityAccount.js +53 -0
  130. package/identity-account/useUpdateIdentityAccount.js.map +1 -0
  131. package/identity-provider/CreateIdentityProviderForm.d.ts.map +1 -1
  132. package/identity-provider/CreateIdentityProviderForm.js +2 -1
  133. package/identity-provider/CreateIdentityProviderForm.js.map +1 -1
  134. package/identity-provider/IdentityProviderDetailPanel.d.ts.map +1 -1
  135. package/identity-provider/IdentityProviderDetailPanel.js +2 -1
  136. package/identity-provider/IdentityProviderDetailPanel.js.map +1 -1
  137. package/identity-provider/IdentityProviderWizard.d.ts.map +1 -1
  138. package/identity-provider/IdentityProviderWizard.js +2 -1
  139. package/identity-provider/IdentityProviderWizard.js.map +1 -1
  140. package/index.d.ts +14 -10
  141. package/index.d.ts.map +1 -1
  142. package/index.js +11 -5
  143. package/index.js.map +1 -1
  144. package/internal/StandingContextField.d.ts +37 -0
  145. package/internal/StandingContextField.d.ts.map +1 -0
  146. package/internal/StandingContextField.js +24 -0
  147. package/internal/StandingContextField.js.map +1 -0
  148. package/internal/element-resets.d.ts +17 -0
  149. package/internal/element-resets.d.ts.map +1 -0
  150. package/internal/element-resets.js +32 -0
  151. package/internal/element-resets.js.map +1 -0
  152. package/internal/file-tree/FileTreeNode.d.ts.map +1 -1
  153. package/internal/file-tree/FileTreeNode.js +2 -1
  154. package/internal/file-tree/FileTreeNode.js.map +1 -1
  155. package/internal/markdown-components.d.ts +7 -0
  156. package/internal/markdown-components.d.ts.map +1 -1
  157. package/internal/markdown-components.js +15 -5
  158. package/internal/markdown-components.js.map +1 -1
  159. package/invitation/InvitationManager.d.ts.map +1 -1
  160. package/invitation/InvitationManager.js +2 -1
  161. package/invitation/InvitationManager.js.map +1 -1
  162. package/library/InstanceVisibilitySelector.d.ts.map +1 -1
  163. package/library/InstanceVisibilitySelector.js +9 -2
  164. package/library/InstanceVisibilitySelector.js.map +1 -1
  165. package/library/ResourceVisibilityControl.d.ts +13 -3
  166. package/library/ResourceVisibilityControl.d.ts.map +1 -1
  167. package/library/ResourceVisibilityControl.js +33 -5
  168. package/library/ResourceVisibilityControl.js.map +1 -1
  169. package/library/VisibilityOptionRow.d.ts +6 -0
  170. package/library/VisibilityOptionRow.d.ts.map +1 -1
  171. package/library/VisibilityOptionRow.js +11 -1
  172. package/library/VisibilityOptionRow.js.map +1 -1
  173. package/library/VisibilitySelector.d.ts.map +1 -1
  174. package/library/VisibilitySelector.js +14 -2
  175. package/library/VisibilitySelector.js.map +1 -1
  176. package/library/index.d.ts +4 -2
  177. package/library/index.d.ts.map +1 -1
  178. package/library/index.js +2 -1
  179. package/library/index.js.map +1 -1
  180. package/library/useCanSetPublicVisibility.d.ts +30 -0
  181. package/library/useCanSetPublicVisibility.d.ts.map +1 -0
  182. package/library/useCanSetPublicVisibility.js +41 -0
  183. package/library/useCanSetPublicVisibility.js.map +1 -0
  184. package/library/visibilityLevels.d.ts +32 -1
  185. package/library/visibilityLevels.d.ts.map +1 -1
  186. package/library/visibilityLevels.js +34 -14
  187. package/library/visibilityLevels.js.map +1 -1
  188. package/manifest/ApplyManifestDialog.d.ts.map +1 -1
  189. package/manifest/ApplyManifestDialog.js +2 -1
  190. package/manifest/ApplyManifestDialog.js.map +1 -1
  191. package/mcp-server/steps/IdentityTransportStep.d.ts.map +1 -1
  192. package/mcp-server/steps/IdentityTransportStep.js +2 -1
  193. package/mcp-server/steps/IdentityTransportStep.js.map +1 -1
  194. package/mcp-server/useMcpServerConnect.d.ts +8 -5
  195. package/mcp-server/useMcpServerConnect.d.ts.map +1 -1
  196. package/mcp-server/useMcpServerConnect.js +2 -1
  197. package/mcp-server/useMcpServerConnect.js.map +1 -1
  198. package/mcp-server/useMcpServerOAuthConnect.d.ts.map +1 -1
  199. package/mcp-server/useMcpServerOAuthConnect.js +7 -2
  200. package/mcp-server/useMcpServerOAuthConnect.js.map +1 -1
  201. package/oauth-app/CreateOAuthAppForm.d.ts +2 -2
  202. package/oauth-app/CreateOAuthAppForm.d.ts.map +1 -1
  203. package/oauth-app/CreateOAuthAppForm.js +13 -4
  204. package/oauth-app/CreateOAuthAppForm.js.map +1 -1
  205. package/oauth-app/OAuthAppDetailPanel.d.ts.map +1 -1
  206. package/oauth-app/OAuthAppDetailPanel.js +32 -5
  207. package/oauth-app/OAuthAppDetailPanel.js.map +1 -1
  208. package/organization/OrgPreferencesPanel.d.ts +32 -0
  209. package/organization/OrgPreferencesPanel.d.ts.map +1 -0
  210. package/organization/OrgPreferencesPanel.js +90 -0
  211. package/organization/OrgPreferencesPanel.js.map +1 -0
  212. package/organization/OrgProfilePanel.d.ts.map +1 -1
  213. package/organization/OrgProfilePanel.js +5 -4
  214. package/organization/OrgProfilePanel.js.map +1 -1
  215. package/organization/index.d.ts +2 -0
  216. package/organization/index.d.ts.map +1 -1
  217. package/organization/index.js +1 -0
  218. package/organization/index.js.map +1 -1
  219. package/package.json +4 -4
  220. package/platform-client/CreatePlatformClientForm.d.ts.map +1 -1
  221. package/platform-client/CreatePlatformClientForm.js +2 -1
  222. package/platform-client/CreatePlatformClientForm.js.map +1 -1
  223. package/platform-client/PlatformClientDetailPanel.d.ts.map +1 -1
  224. package/platform-client/PlatformClientDetailPanel.js +2 -1
  225. package/platform-client/PlatformClientDetailPanel.js.map +1 -1
  226. package/pricing-governance/BaselineEditor.d.ts.map +1 -1
  227. package/pricing-governance/BaselineEditor.js +2 -1
  228. package/pricing-governance/BaselineEditor.js.map +1 -1
  229. package/pricing-governance/PricingGovernanceConsole.d.ts.map +1 -1
  230. package/pricing-governance/PricingGovernanceConsole.js +2 -1
  231. package/pricing-governance/PricingGovernanceConsole.js.map +1 -1
  232. package/provider-standing/ProviderStandingAccessNotice.d.ts +11 -0
  233. package/provider-standing/ProviderStandingAccessNotice.d.ts.map +1 -0
  234. package/provider-standing/ProviderStandingAccessNotice.js +14 -0
  235. package/provider-standing/ProviderStandingAccessNotice.js.map +1 -0
  236. package/provider-standing/ProviderStandingConsole.d.ts +24 -0
  237. package/provider-standing/ProviderStandingConsole.d.ts.map +1 -0
  238. package/provider-standing/ProviderStandingConsole.js +98 -0
  239. package/provider-standing/ProviderStandingConsole.js.map +1 -0
  240. package/provider-standing/index.d.ts +6 -0
  241. package/provider-standing/index.d.ts.map +1 -0
  242. package/provider-standing/index.js +6 -0
  243. package/provider-standing/index.js.map +1 -0
  244. package/provider-standing/useProviderStanding.d.ts +34 -0
  245. package/provider-standing/useProviderStanding.d.ts.map +1 -0
  246. package/provider-standing/useProviderStanding.js +26 -0
  247. package/provider-standing/useProviderStanding.js.map +1 -0
  248. package/provider.d.ts +12 -0
  249. package/provider.d.ts.map +1 -1
  250. package/provider.js +12 -0
  251. package/provider.js.map +1 -1
  252. package/resource-creation/StepIndicator.d.ts.map +1 -1
  253. package/resource-creation/StepIndicator.js +2 -1
  254. package/resource-creation/StepIndicator.js.map +1 -1
  255. package/schedule/ScheduleDetailView.d.ts.map +1 -1
  256. package/schedule/ScheduleDetailView.js +3 -2
  257. package/schedule/ScheduleDetailView.js.map +1 -1
  258. package/schedule/ScheduleRunsTable.d.ts.map +1 -1
  259. package/schedule/ScheduleRunsTable.js +2 -1
  260. package/schedule/ScheduleRunsTable.js.map +1 -1
  261. package/session/NewSessionViewer.d.ts +10 -1
  262. package/session/NewSessionViewer.d.ts.map +1 -1
  263. package/session/NewSessionViewer.js +2 -1
  264. package/session/NewSessionViewer.js.map +1 -1
  265. package/session/facets/ArtifactsTab.d.ts.map +1 -1
  266. package/session/facets/ArtifactsTab.js +2 -1
  267. package/session/facets/ArtifactsTab.js.map +1 -1
  268. package/session/facets/ChangesTab.d.ts.map +1 -1
  269. package/session/facets/ChangesTab.js +2 -1
  270. package/session/facets/ChangesTab.js.map +1 -1
  271. package/session/facets/UsageTab.d.ts +10 -3
  272. package/session/facets/UsageTab.d.ts.map +1 -1
  273. package/session/facets/UsageTab.js +42 -6
  274. package/session/facets/UsageTab.js.map +1 -1
  275. package/session/index.d.ts +1 -1
  276. package/session/index.d.ts.map +1 -1
  277. package/session/index.js.map +1 -1
  278. package/session/useNewSessionFlow.d.ts +27 -1
  279. package/session/useNewSessionFlow.d.ts.map +1 -1
  280. package/session/useNewSessionFlow.js +45 -8
  281. package/session/useNewSessionFlow.js.map +1 -1
  282. package/session/useSessionUsage.d.ts +25 -0
  283. package/session/useSessionUsage.d.ts.map +1 -1
  284. package/session/useSessionUsage.js +11 -0
  285. package/session/useSessionUsage.js.map +1 -1
  286. package/settings/AccountPreferencesSection.d.ts +3 -0
  287. package/settings/AccountPreferencesSection.d.ts.map +1 -0
  288. package/settings/AccountPreferencesSection.js +10 -0
  289. package/settings/AccountPreferencesSection.js.map +1 -0
  290. package/settings/OrgPreferencesSection.d.ts +3 -0
  291. package/settings/OrgPreferencesSection.d.ts.map +1 -0
  292. package/settings/OrgPreferencesSection.js +13 -0
  293. package/settings/OrgPreferencesSection.js.map +1 -0
  294. package/settings/index.d.ts +2 -0
  295. package/settings/index.d.ts.map +1 -1
  296. package/settings/index.js +2 -0
  297. package/settings/index.js.map +1 -1
  298. package/settings/settings-nav.d.ts.map +1 -1
  299. package/settings/settings-nav.js +23 -1
  300. package/settings/settings-nav.js.map +1 -1
  301. package/settings/useSettingsNavGroups.d.ts.map +1 -1
  302. package/settings/useSettingsNavGroups.js +4 -1
  303. package/settings/useSettingsNavGroups.js.map +1 -1
  304. package/sharing/ShareAgentDialog.d.ts.map +1 -1
  305. package/sharing/ShareAgentDialog.js +2 -1
  306. package/sharing/ShareAgentDialog.js.map +1 -1
  307. package/sidebar/WorkspaceSidebar.d.ts.map +1 -1
  308. package/sidebar/WorkspaceSidebar.js +2 -1
  309. package/sidebar/WorkspaceSidebar.js.map +1 -1
  310. package/skill/SkillFileBrowser.d.ts.map +1 -1
  311. package/skill/SkillFileBrowser.js +2 -1
  312. package/skill/SkillFileBrowser.js.map +1 -1
  313. package/skill/internal/fetchAndUnpackArtifact.d.ts +1 -1
  314. package/skill/internal/fetchAndUnpackArtifact.d.ts.map +1 -1
  315. package/skill/internal/fetchAndUnpackArtifact.js +47 -3
  316. package/skill/internal/fetchAndUnpackArtifact.js.map +1 -1
  317. package/skill/useSkillDiff.d.ts.map +1 -1
  318. package/skill/useSkillDiff.js +7 -1
  319. package/skill/useSkillDiff.js.map +1 -1
  320. package/skill/useSkillUpload.d.ts.map +1 -1
  321. package/skill/useSkillUpload.js +22 -4
  322. package/skill/useSkillUpload.js.map +1 -1
  323. package/src/__tests__/bare-host-resets.layout.test.tsx +184 -0
  324. package/src/agent/steps/IdentityStep.tsx +2 -1
  325. package/src/agent-instance/AgentInstanceDetailPanel.tsx +2 -1
  326. package/src/api-key/CreateApiKeyForm.tsx +2 -1
  327. package/src/attachment/AttachmentChipList.tsx +19 -8
  328. package/src/attachment/__tests__/AttachmentChipList.test.tsx +12 -0
  329. package/src/attachment/__tests__/useAttachments.test.ts +293 -0
  330. package/src/attachment/index.ts +1 -0
  331. package/src/attachment/useAttachments.ts +143 -11
  332. package/src/channel/ChannelConversationsDialog.tsx +2 -1
  333. package/src/channel/ChannelTemplatesDialog.tsx +2 -1
  334. package/src/channel/ConnectSlackDialog.tsx +2 -1
  335. package/src/channel/connect/ServingAppSection.tsx +2 -1
  336. package/src/channel-app/CreateChannelAppForm.tsx +2 -1
  337. package/src/composer/SessionComposer.tsx +23 -14
  338. package/src/conversation/ConversationComposer.tsx +38 -4
  339. package/src/conversation/ConversationListPane.tsx +2 -5
  340. package/src/conversation/ConversationTemplatePickerDialog.tsx +441 -0
  341. package/src/conversation/ConversationTimelineView.tsx +2 -1
  342. package/src/conversation/ConversationsWorkbench.tsx +40 -4
  343. package/src/conversation/__tests__/ConversationComposer.test.tsx +56 -1
  344. package/src/conversation/__tests__/ConversationTemplatePickerDialog.test.tsx +224 -0
  345. package/src/conversation/__tests__/useConversationParticipation.test.tsx +45 -4
  346. package/src/conversation/index.ts +4 -0
  347. package/src/conversation/useConversationParticipation.ts +58 -6
  348. package/src/cursor-accounts/CursorAccountsConsole.tsx +2 -1
  349. package/src/cursor-accounts/MemberKeysPanel.tsx +2 -1
  350. package/src/dashboard/DashboardFailedRuns.tsx +2 -1
  351. package/src/dependency-graph/DependencyGraph.tsx +2 -1
  352. package/src/dependency-graph/DependencyTreeNode.tsx +2 -1
  353. package/src/environment/EnvironmentPicker.tsx +2 -1
  354. package/src/error/SecretFlowErrorGuide.tsx +3 -2
  355. package/src/execution/ArtifactContentBody.tsx +2 -1
  356. package/src/execution/ArtifactsWidget.tsx +2 -1
  357. package/src/execution/FileChangeProgressBar.tsx +2 -1
  358. package/src/execution/TodoList.tsx +2 -1
  359. package/src/execution/WriteBacksWidget.tsx +2 -1
  360. package/src/execution/tool-categories.ts +17 -41
  361. package/src/iam-policy/PeopleWithAccess.tsx +2 -1
  362. package/src/iam-policy/PrincipalPicker.tsx +2 -0
  363. package/src/iam-policy/RoleSelector.tsx +2 -1
  364. package/src/identity-account/AccountPreferencesPanel.tsx +446 -0
  365. package/src/identity-account/__tests__/AccountPreferencesPanel.test.tsx +233 -0
  366. package/src/identity-account/__tests__/useAccountExecutionDefaults.test.tsx +116 -0
  367. package/src/identity-account/__tests__/useMyIdentityAccount.test.tsx +121 -0
  368. package/src/identity-account/index.ts +11 -0
  369. package/src/identity-account/useAccountExecutionDefaults.ts +63 -0
  370. package/src/identity-account/useMyIdentityAccount.ts +75 -0
  371. package/src/identity-account/useUpdateIdentityAccount.ts +73 -0
  372. package/src/identity-provider/CreateIdentityProviderForm.tsx +2 -1
  373. package/src/identity-provider/IdentityProviderDetailPanel.tsx +2 -1
  374. package/src/identity-provider/IdentityProviderWizard.tsx +2 -1
  375. package/src/index.ts +37 -2
  376. package/src/internal/StandingContextField.tsx +92 -0
  377. package/src/internal/element-resets.ts +33 -0
  378. package/src/internal/file-tree/FileTreeNode.tsx +2 -1
  379. package/src/internal/markdown-components.tsx +15 -5
  380. package/src/invitation/InvitationManager.tsx +3 -2
  381. package/src/library/InstanceVisibilitySelector.tsx +9 -2
  382. package/src/library/ResourceVisibilityControl.tsx +46 -13
  383. package/src/library/VisibilityOptionRow.tsx +28 -6
  384. package/src/library/VisibilitySelector.tsx +14 -2
  385. package/src/library/__tests__/VisibilitySelector.test.tsx +48 -1
  386. package/src/library/__tests__/visibilityLevels.test.ts +67 -1
  387. package/src/library/index.ts +6 -1
  388. package/src/library/useCanSetPublicVisibility.ts +56 -0
  389. package/src/library/visibilityLevels.ts +65 -14
  390. package/src/manifest/ApplyManifestDialog.tsx +2 -1
  391. package/src/mcp-server/__tests__/useMcpServerConnect.asyncLane.test.tsx +117 -0
  392. package/src/mcp-server/steps/IdentityTransportStep.tsx +3 -2
  393. package/src/mcp-server/useMcpServerConnect.ts +9 -6
  394. package/src/mcp-server/useMcpServerOAuthConnect.ts +7 -2
  395. package/src/oauth-app/CreateOAuthAppForm.tsx +58 -3
  396. package/src/oauth-app/OAuthAppDetailPanel.tsx +84 -3
  397. package/src/organization/OrgPreferencesPanel.tsx +221 -0
  398. package/src/organization/OrgProfilePanel.tsx +5 -4
  399. package/src/organization/__tests__/OrgPreferencesPanel.test.tsx +145 -0
  400. package/src/organization/__tests__/OrgProfilePanel.test.tsx +108 -0
  401. package/src/organization/index.ts +2 -0
  402. package/src/platform-client/CreatePlatformClientForm.tsx +4 -3
  403. package/src/platform-client/PlatformClientDetailPanel.tsx +4 -3
  404. package/src/pricing-governance/BaselineEditor.tsx +3 -2
  405. package/src/pricing-governance/PricingGovernanceConsole.tsx +2 -1
  406. package/src/provider-standing/ProviderStandingAccessNotice.tsx +36 -0
  407. package/src/provider-standing/ProviderStandingConsole.tsx +216 -0
  408. package/src/provider-standing/__tests__/ProviderStandingConsole.test.tsx +143 -0
  409. package/src/provider-standing/index.ts +8 -0
  410. package/src/provider-standing/useProviderStanding.ts +50 -0
  411. package/src/provider.tsx +12 -0
  412. package/src/resource-creation/StepIndicator.tsx +2 -1
  413. package/src/schedule/ScheduleDetailView.tsx +3 -2
  414. package/src/schedule/ScheduleRunsTable.tsx +2 -1
  415. package/src/session/NewSessionViewer.tsx +12 -0
  416. package/src/session/__tests__/UsageTab.test.tsx +136 -0
  417. package/src/session/__tests__/useNewSessionFlow.test.tsx +151 -0
  418. package/src/session/__tests__/useSessionUsage.test.ts +19 -0
  419. package/src/session/facets/ArtifactsTab.tsx +2 -1
  420. package/src/session/facets/ChangesTab.tsx +2 -1
  421. package/src/session/facets/UsageTab.tsx +98 -6
  422. package/src/session/index.ts +1 -0
  423. package/src/session/useNewSessionFlow.ts +76 -9
  424. package/src/session/useSessionUsage.ts +37 -0
  425. package/src/settings/AccountPreferencesSection.tsx +25 -0
  426. package/src/settings/OrgPreferencesSection.tsx +35 -0
  427. package/src/settings/__tests__/settings-nav.test.ts +27 -0
  428. package/src/settings/__tests__/useSettingsNavGroups.test.tsx +11 -1
  429. package/src/settings/index.ts +2 -0
  430. package/src/settings/settings-nav.ts +25 -0
  431. package/src/settings/useSettingsNavGroups.ts +8 -1
  432. package/src/sharing/ShareAgentDialog.tsx +2 -1
  433. package/src/sidebar/WorkspaceSidebar.tsx +2 -1
  434. package/src/skill/SkillFileBrowser.tsx +2 -1
  435. package/src/skill/__tests__/SkillFileBrowser.test.tsx +10 -2
  436. package/src/skill/__tests__/fetchAndUnpackArtifact.test.ts +90 -0
  437. package/src/skill/__tests__/useSkillUpload.test.ts +69 -0
  438. package/src/skill/internal/fetchAndUnpackArtifact.ts +54 -4
  439. package/src/skill/useSkillDiff.ts +7 -1
  440. package/src/skill/useSkillUpload.ts +25 -6
  441. package/src/workflow/ApprovalFormBuilder.tsx +5 -27
  442. package/src/workflow/FailedRunsWidget.tsx +2 -1
  443. package/src/workflow/PendingApprovalsWidget.tsx +2 -1
  444. package/src/workflow/facets/WorkflowArtifactsTab.tsx +2 -1
  445. package/src/workflow/facets/WorkflowUsageTab.tsx +2 -1
  446. package/src/workflow/inspector/WorkflowSummaryPanel.tsx +2 -1
  447. package/src/workflow/inspector/tabs/BranchesTab.tsx +2 -1
  448. package/src/workflow/inspector/tabs/IterationTab.tsx +2 -1
  449. package/src/workflow/instance/WorkflowInstanceDetailPanel.tsx +2 -1
  450. package/src/workspace/ExplorerTree.tsx +2 -1
  451. package/src/workspace/WorkspaceContentSearch.tsx +2 -1
  452. package/src/workspace/WorkspaceFileSearch.tsx +2 -1
  453. package/src/workspace/WorkspaceSummary.tsx +2 -1
  454. package/styles.css +1 -1
  455. package/workflow/ApprovalFormBuilder.d.ts.map +1 -1
  456. package/workflow/ApprovalFormBuilder.js +8 -5
  457. package/workflow/ApprovalFormBuilder.js.map +1 -1
  458. package/workflow/FailedRunsWidget.d.ts.map +1 -1
  459. package/workflow/FailedRunsWidget.js +2 -1
  460. package/workflow/FailedRunsWidget.js.map +1 -1
  461. package/workflow/PendingApprovalsWidget.d.ts.map +1 -1
  462. package/workflow/PendingApprovalsWidget.js +2 -1
  463. package/workflow/PendingApprovalsWidget.js.map +1 -1
  464. package/workflow/facets/WorkflowArtifactsTab.d.ts.map +1 -1
  465. package/workflow/facets/WorkflowArtifactsTab.js +2 -1
  466. package/workflow/facets/WorkflowArtifactsTab.js.map +1 -1
  467. package/workflow/facets/WorkflowUsageTab.d.ts.map +1 -1
  468. package/workflow/facets/WorkflowUsageTab.js +2 -1
  469. package/workflow/facets/WorkflowUsageTab.js.map +1 -1
  470. package/workflow/inspector/WorkflowSummaryPanel.d.ts.map +1 -1
  471. package/workflow/inspector/WorkflowSummaryPanel.js +2 -1
  472. package/workflow/inspector/WorkflowSummaryPanel.js.map +1 -1
  473. package/workflow/inspector/tabs/BranchesTab.d.ts.map +1 -1
  474. package/workflow/inspector/tabs/BranchesTab.js +2 -1
  475. package/workflow/inspector/tabs/BranchesTab.js.map +1 -1
  476. package/workflow/inspector/tabs/IterationTab.d.ts.map +1 -1
  477. package/workflow/inspector/tabs/IterationTab.js +2 -1
  478. package/workflow/inspector/tabs/IterationTab.js.map +1 -1
  479. package/workflow/instance/WorkflowInstanceDetailPanel.d.ts.map +1 -1
  480. package/workflow/instance/WorkflowInstanceDetailPanel.js +2 -1
  481. package/workflow/instance/WorkflowInstanceDetailPanel.js.map +1 -1
  482. package/workspace/ExplorerTree.d.ts.map +1 -1
  483. package/workspace/ExplorerTree.js +2 -1
  484. package/workspace/ExplorerTree.js.map +1 -1
  485. package/workspace/WorkspaceContentSearch.d.ts.map +1 -1
  486. package/workspace/WorkspaceContentSearch.js +2 -1
  487. package/workspace/WorkspaceContentSearch.js.map +1 -1
  488. package/workspace/WorkspaceFileSearch.d.ts.map +1 -1
  489. package/workspace/WorkspaceFileSearch.js +2 -1
  490. package/workspace/WorkspaceFileSearch.js.map +1 -1
  491. package/workspace/WorkspaceSummary.d.ts.map +1 -1
  492. package/workspace/WorkspaceSummary.js +2 -1
  493. package/workspace/WorkspaceSummary.js.map +1 -1
@@ -0,0 +1,184 @@
1
+ // Bare-host regression suite for the per-element UA resets (#695).
2
+ //
3
+ // Runs in a real Chromium via `vitest.a11y.config.ts` — the defect under
4
+ // guard is the user agent's OWN default list/fieldset/flow-content styling
5
+ // (bullets, 40px indents, stacked margins), which only a real browser
6
+ // applies. happy-dom has no UA stylesheet, so it would pass vacuously.
7
+ //
8
+ // The contract: every SDK component is authored against a zeroed-margin
9
+ // baseline (our consoles ship a global reset). In a host WITHOUT one —
10
+ // third-party embeds, the SDK's stated audience — UI lists and fieldsets
11
+ // carry the `UNSTYLED_LIST`/`UNSTYLED_FIELDSET` per-component resets
12
+ // (`internal/element-resets.ts` records why this class of reset cannot live
13
+ // in styles.css), and the markdown map declares its own top/inline margins.
14
+ // Like the sibling #374 suite (preflight-parity.layout.test.tsx), this
15
+ // renders against the SHIPPED stylesheet (`dist/styles.css`, rebuilt by
16
+ // `npm run build:css`) and nothing else — the page IS the bare host.
17
+ //
18
+ // Three directions, all load-bearing:
19
+ // 1. A control proving the harness is genuinely bare (a raw <ul> DOES show
20
+ // UA bullets — if this fails, every other assertion here is vacuous).
21
+ // 2. The resets neutralize UA defaults on real, swept components.
22
+ // 3. Utilities and deliberate styling still win (markdown lists keep their
23
+ // explicit bullets; spacing utilities compose on top of the reset).
24
+
25
+ import "../../dist/styles.css";
26
+
27
+ import { describe, it, expect, afterEach } from "vitest";
28
+ import { render, cleanup } from "@testing-library/react";
29
+ import { create } from "@bufbuild/protobuf";
30
+ import Markdown from "react-markdown";
31
+ import type { Stigmer } from "@stigmer/sdk";
32
+ import { TodoItemSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/todo_pb";
33
+ import { TodoStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
34
+ import { StigmerProvider } from "../provider";
35
+ import { TodoList } from "../execution/TodoList.js";
36
+ import { UNSTYLED_FIELDSET, UNSTYLED_LIST } from "../internal/element-resets.js";
37
+ import { MARKDOWN_COMPONENTS } from "../internal/markdown-components.js";
38
+
39
+ afterEach(cleanup);
40
+
41
+ // A minimal client (the preflight-parity suite's idiom): a null credential
42
+ // keeps the provider's registry fetches non-blocking so rendering is
43
+ // synchronous and never touches the network.
44
+ function makeClient(): Stigmer {
45
+ return {
46
+ baseUrl: "https://example.test",
47
+ getAuthCredential: async () => null,
48
+ fetch: (async () => {
49
+ throw new Error("network disabled in test");
50
+ }) as unknown as typeof globalThis.fetch,
51
+ } as unknown as Stigmer;
52
+ }
53
+
54
+ function renderScoped(ui: React.ReactNode): HTMLElement {
55
+ render(
56
+ <StigmerProvider client={makeClient()}>
57
+ <div data-testid="probe">{ui}</div>
58
+ </StigmerProvider>,
59
+ );
60
+ return document.querySelector('[data-testid="probe"]') as HTMLElement;
61
+ }
62
+
63
+ function computed(el: Element): CSSStyleDeclaration {
64
+ return getComputedStyle(el);
65
+ }
66
+
67
+ const ZERO_MARGINS = ["0px", "0px", "0px", "0px"];
68
+
69
+ function margins(style: CSSStyleDeclaration): string[] {
70
+ return [style.marginTop, style.marginRight, style.marginBottom, style.marginLeft];
71
+ }
72
+
73
+ describe("bare-host per-element resets (#695)", () => {
74
+ it("CONTROL: the harness is genuinely bare — a raw <ul> wears UA bullets and indent", () => {
75
+ const probe = renderScoped(
76
+ <ul>
77
+ <li>raw</li>
78
+ </ul>,
79
+ );
80
+ const style = computed(probe.querySelector("ul")!);
81
+
82
+ expect(style.listStyleType, "no global reset may leak into this page").toBe("disc");
83
+ expect(style.paddingLeft, "UA padding-inline-start must be present").toBe("40px");
84
+ });
85
+
86
+ describe("UNSTYLED_LIST", () => {
87
+ it("neutralizes bullets, indent, and margins", () => {
88
+ const probe = renderScoped(
89
+ <ul className={UNSTYLED_LIST}>
90
+ <li>item</li>
91
+ </ul>,
92
+ );
93
+ const style = computed(probe.querySelector("ul")!);
94
+
95
+ expect(style.listStyleType).toBe("none");
96
+ expect(style.paddingLeft).toBe("0px");
97
+ expect(margins(style)).toEqual(ZERO_MARGINS);
98
+ });
99
+
100
+ it("spacing utilities still win over the reset (tailwind-merge + layer order)", () => {
101
+ const probe = renderScoped(
102
+ <ul className={`${UNSTYLED_LIST} stg:p-2`}>
103
+ <li>item</li>
104
+ </ul>,
105
+ );
106
+
107
+ expect(computed(probe.querySelector("ul")!).paddingLeft).toBe("8px");
108
+ });
109
+
110
+ it("a real swept organism (TodoList) renders without UA list styling", () => {
111
+ const probe = renderScoped(
112
+ <TodoList
113
+ todos={{
114
+ t1: create(TodoItemSchema, {
115
+ id: "t1",
116
+ content: "Scaffold the component",
117
+ status: TodoStatus.TODO_IN_PROGRESS,
118
+ }),
119
+ }}
120
+ />,
121
+ );
122
+ const style = computed(probe.querySelector('ul[aria-label="Tasks"]')!);
123
+
124
+ expect(style.listStyleType).toBe("none");
125
+ expect(style.paddingLeft).toBe("0px");
126
+ expect(margins(style)).toEqual(ZERO_MARGINS);
127
+ });
128
+ });
129
+
130
+ describe("UNSTYLED_FIELDSET", () => {
131
+ it("neutralizes UA fieldset margins, padding, and min-inline-size", () => {
132
+ const probe = renderScoped(
133
+ <>
134
+ <fieldset data-testid="raw">
135
+ <legend>raw</legend>
136
+ </fieldset>
137
+ <fieldset data-testid="reset" className={UNSTYLED_FIELDSET}>
138
+ <legend>reset</legend>
139
+ </fieldset>
140
+ </>,
141
+ );
142
+
143
+ // Control half: UA fieldset padding really is present in this page.
144
+ expect(computed(probe.querySelector('[data-testid="raw"]')!).paddingLeft).not.toBe("0px");
145
+
146
+ const style = computed(probe.querySelector('[data-testid="reset"]')!);
147
+ expect(margins(style)).toEqual(ZERO_MARGINS);
148
+ expect(style.paddingLeft).toBe("0px");
149
+ expect(style.minWidth, "min-inline-size: min-content breaks flex shrinking").toBe("0px");
150
+ });
151
+ });
152
+
153
+ describe("markdown map (content elements declare their own margins)", () => {
154
+ function renderMarkdown(md: string): HTMLElement {
155
+ return renderScoped(<Markdown components={MARKDOWN_COMPONENTS}>{md}</Markdown>);
156
+ }
157
+
158
+ it("paragraphs carry no UA top margin, so mb-* spacing is the whole rhythm", () => {
159
+ const probe = renderMarkdown("first\n\nsecond");
160
+ const [, second] = Array.from(probe.querySelectorAll("p"));
161
+
162
+ expect(computed(second).marginTop).toBe("0px");
163
+ });
164
+
165
+ it("blockquotes lose the UA 1em/40px box but keep the authored border+padding treatment", () => {
166
+ const probe = renderMarkdown("> quoted");
167
+ const style = computed(probe.querySelector("blockquote")!);
168
+
169
+ expect(style.marginTop).toBe("0px");
170
+ expect(style.marginLeft, "UA margin-inline: 40px must be cleared").toBe("0px");
171
+ expect(style.marginRight).toBe("0px");
172
+ expect(style.paddingLeft, "the authored pl-4 treatment stays").toBe("16px");
173
+ });
174
+
175
+ it("content lists KEEP their bullets — the reset is for UI lists only", () => {
176
+ const probe = renderMarkdown("- one\n- two");
177
+ const style = computed(probe.querySelector("ul")!);
178
+
179
+ expect(style.listStyleType).toBe("disc");
180
+ expect(style.marginTop, "stacked UA margin-top must be cleared").toBe("0px");
181
+ expect(style.paddingLeft, "authored pl-5 replaces the UA 40px").toBe("20px");
182
+ });
183
+ });
184
+ });
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { useCallback, useId } from "react";
4
4
  import { cn } from "@stigmer/theme";
5
+ import { UNSTYLED_FIELDSET } from "../../internal/element-resets.js";
5
6
  import { generateSlug } from "../../internal/slug.js";
6
7
  import type { AgentWizardData } from "./types.js";
7
8
 
@@ -173,7 +174,7 @@ export function IdentityStep({
173
174
  />
174
175
  </div>
175
176
 
176
- <fieldset className="stg:space-y-1.5">
177
+ <fieldset className={cn(UNSTYLED_FIELDSET, "stg:space-y-1.5")}>
177
178
  <legend className="stg:text-sm stg:font-medium stg:text-foreground">
178
179
  Visibility
179
180
  </legend>
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { useCallback, useState } from "react";
4
4
  import { cn } from "@stigmer/theme";
5
+ import { UNSTYLED_LIST } from "../internal/element-resets.js";
5
6
  import { timestampDate } from "@bufbuild/protobuf/wkt";
6
7
  import type { AgentInstance } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/api_pb";
7
8
  import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
@@ -233,7 +234,7 @@ export function AgentInstanceDetailPanel({
233
234
  {(spec?.environmentRefs?.length ?? 0) === 0 ? (
234
235
  <p className="stg:text-xs stg:text-muted-foreground">No environments bound.</p>
235
236
  ) : (
236
- <ol className="stg:space-y-1">
237
+ <ol className={cn(UNSTYLED_LIST, "stg:space-y-1")}>
237
238
  {spec!.environmentRefs.map((ref, idx) => (
238
239
  <li key={`${ref.slug}-${idx}`} className="stg:flex stg:items-center stg:gap-2 stg:text-sm">
239
240
  <span className="stg:text-xs stg:text-muted-foreground stg:w-4 stg:text-right">{idx + 1}.</span>
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { useCallback, useId, useState, type FormEvent } from "react";
4
4
  import { cn } from "@stigmer/theme";
5
+ import { UNSTYLED_FIELDSET } from "../internal/element-resets.js";
5
6
  import { getUserMessage } from "@stigmer/sdk";
6
7
  import type { ApiKey } from "@stigmer/protos/ai/stigmer/iam/apikey/v1/api_pb";
7
8
  import { useCreateApiKey } from "./useCreateApiKey.js";
@@ -122,7 +123,7 @@ export function CreateApiKeyForm({
122
123
  </div>
123
124
 
124
125
  {/* Expiry */}
125
- <fieldset className="stg:space-y-1.5">
126
+ <fieldset className={cn(UNSTYLED_FIELDSET, "stg:space-y-1.5")}>
126
127
  <legend className="stg:text-xs stg:font-medium stg:text-foreground">
127
128
  Expiration
128
129
  </legend>
@@ -154,9 +154,20 @@ function AttachmentChip({
154
154
 
155
155
  /** Shared accessible name: filename, size, and upload status. */
156
156
  function chipAriaLabel(entry: AttachmentEntry): string {
157
+ const isPreparing = entry.phase === "preparing";
157
158
  const isUploading = entry.phase === "uploading";
158
159
  const isError = entry.phase === "error";
159
- return `${entry.file.name}, ${formatFileSize(entry.file.size)}${isUploading ? ", uploading" : ""}${isError ? ", upload failed" : ""}`;
160
+ return `${entry.file.name}, ${formatFileSize(entry.file.size)}${isPreparing ? ", preparing" : ""}${isUploading ? ", uploading" : ""}${isError ? ", upload failed" : ""}`;
161
+ }
162
+
163
+ /**
164
+ * True while the entry has work in flight (`preparing` or `uploading`) —
165
+ * the chips render both identically (dimmed + spinner): to the user each
166
+ * means "your file is on its way", and the split is audible in the
167
+ * accessible label where it actually informs.
168
+ */
169
+ function isChipBusy(entry: AttachmentEntry): boolean {
170
+ return entry.phase === "preparing" || entry.phase === "uploading";
160
171
  }
161
172
 
162
173
  // ---------------------------------------------------------------------------
@@ -212,7 +223,7 @@ function ImageAttachmentChip({
212
223
  }
213
224
 
214
225
  const isError = entry.phase === "error";
215
- const isUploading = entry.phase === "uploading";
226
+ const isBusy = isChipBusy(entry);
216
227
 
217
228
  return (
218
229
  // The remove badge and retry pill are SIBLINGS of the preview button,
@@ -250,7 +261,7 @@ function ImageAttachmentChip({
250
261
  onError={() => setLoadFailed(true)}
251
262
  className={cn(
252
263
  "stg:h-full stg:w-full stg:object-cover",
253
- (isUploading || isError) && "stg:opacity-50",
264
+ (isBusy || isError) && "stg:opacity-50",
254
265
  )}
255
266
  />
256
267
  ) : (
@@ -261,7 +272,7 @@ function ImageAttachmentChip({
261
272
  aria-hidden="true"
262
273
  />
263
274
  )}
264
- {isUploading && (
275
+ {isBusy && (
265
276
  <span className="stg:absolute stg:inset-0 stg:flex stg:items-center stg:justify-center">
266
277
  <ChipSpinner size={16} />
267
278
  </span>
@@ -322,7 +333,7 @@ function FileAttachmentChip({
322
333
  readonly disabled?: boolean;
323
334
  }) {
324
335
  const isError = entry.phase === "error";
325
- const isUploading = entry.phase === "uploading";
336
+ const isBusy = isChipBusy(entry);
326
337
 
327
338
  return (
328
339
  <span
@@ -333,12 +344,12 @@ function FileAttachmentChip({
333
344
  isError
334
345
  ? "stg:border stg:border-destructive/30 stg:bg-destructive-subtle stg:text-destructive"
335
346
  : "stg:bg-muted-subtle stg:text-foreground",
336
- isUploading && "stg:opacity-70",
347
+ isBusy && "stg:opacity-70",
337
348
  )}
338
349
  >
339
- {isUploading && <ChipSpinner />}
350
+ {isBusy && <ChipSpinner />}
340
351
  {isError && <ErrorDot />}
341
- {!isUploading && !isError && <FileIcon />}
352
+ {!isBusy && !isError && <FileIcon />}
342
353
 
343
354
  <span className="stg:truncate">{entry.file.name}</span>
344
355
 
@@ -101,6 +101,18 @@ describe("AttachmentChipList — image miniature", () => {
101
101
  expect(container.querySelector("svg.stg\\:animate-spin")).toBeTruthy();
102
102
  });
103
103
 
104
+ it("treats the preparing phase as busy: spinner over the miniature, 'preparing' in the accessible label (#369)", async () => {
105
+ const preparing = entry({ id: "prep", phase: "preparing", storageKey: null });
106
+
107
+ const { container } = renderChips([preparing]);
108
+
109
+ await waitFor(() => expect(chipImage(container)).toBeTruthy());
110
+ expect(container.querySelector("svg.stg\\:animate-spin")).toBeTruthy();
111
+ expect(
112
+ screen.getByRole("listitem", { name: /shot\.png.*preparing/ }),
113
+ ).toBeTruthy();
114
+ });
115
+
104
116
  it("renders image chips preview-only: no visible filename or size text", async () => {
105
117
  const { container } = renderChips([entry()]);
106
118
 
@@ -0,0 +1,293 @@
1
+ /**
2
+ * useAttachments lifecycle tests, centered on the `preparing` phase
3
+ * (stigmer/stigmer#369): entries must exist from the instant a
4
+ * prepare-flagged file is added, transition through preparation to
5
+ * upload, and honor the deferred-validation and cancellation contracts
6
+ * documented on {@link AddFilesOptions.prepareImages}.
7
+ */
8
+ import { describe, it, expect, vi, afterEach } from "vitest";
9
+ import { renderHook, act, waitFor } from "@testing-library/react";
10
+
11
+ vi.mock("../../hooks", () => ({
12
+ useStigmer: vi.fn(),
13
+ }));
14
+ vi.mock("../prepare-image.js", () => ({
15
+ prepareImageForVision: vi.fn(),
16
+ }));
17
+
18
+ import { useStigmer } from "../../hooks";
19
+ import { prepareImageForVision } from "../prepare-image.js";
20
+ import { useAttachments } from "../useAttachments.js";
21
+ import { MAX_ATTACHMENT_BYTES } from "../attachment-utils.js";
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Helpers
25
+ // ---------------------------------------------------------------------------
26
+
27
+ function deferred<T>() {
28
+ let resolve!: (value: T) => void;
29
+ const promise = new Promise<T>((r) => {
30
+ resolve = r;
31
+ });
32
+ return { promise, resolve };
33
+ }
34
+
35
+ function makeFile(name: string, sizeBytes: number, type = "image/png"): File {
36
+ return new File([new Uint8Array(sizeBytes)], name, { type });
37
+ }
38
+
39
+ /** Wires useStigmer to an uploadAttachment mock that resolves immediately. */
40
+ function mockStigmer() {
41
+ const uploadAttachment = vi
42
+ .fn()
43
+ .mockResolvedValue({ storageKey: "attachments/test/key" });
44
+ vi.mocked(useStigmer).mockReturnValue({
45
+ agentExecution: { uploadAttachment },
46
+ } as unknown as ReturnType<typeof useStigmer>);
47
+ return { uploadAttachment };
48
+ }
49
+
50
+ const prepareMock = vi.mocked(prepareImageForVision);
51
+
52
+ afterEach(() => {
53
+ vi.restoreAllMocks();
54
+ });
55
+
56
+ // ---------------------------------------------------------------------------
57
+ // The preparing phase
58
+ // ---------------------------------------------------------------------------
59
+
60
+ describe("useAttachments — prepareImages lifecycle", () => {
61
+ it("shows the entry immediately in the preparing phase, gating submit", () => {
62
+ mockStigmer();
63
+ const gap = deferred<File>();
64
+ prepareMock.mockReturnValue(gap.promise);
65
+
66
+ const { result } = renderHook(() => useAttachments());
67
+
68
+ act(() => {
69
+ result.current.addFiles([makeFile("shot.png", 1024)], {
70
+ prepareImages: true,
71
+ });
72
+ });
73
+
74
+ expect(result.current.entries).toHaveLength(1);
75
+ expect(result.current.entries[0].phase).toBe("preparing");
76
+ expect(result.current.entries[0].file.name).toBe("shot.png");
77
+ expect(result.current.isPreparing).toBe(true);
78
+ // preparing gates exactly like uploading — the silent-drop guard.
79
+ expect(result.current.isUploading).toBe(true);
80
+ expect(result.current.allReady).toBe(false);
81
+ });
82
+
83
+ it("swaps to the prepared file (name, type) and proceeds to upload → ready", async () => {
84
+ const { uploadAttachment } = mockStigmer();
85
+ const gap = deferred<File>();
86
+ prepareMock.mockReturnValue(gap.promise);
87
+
88
+ const { result } = renderHook(() => useAttachments());
89
+
90
+ act(() => {
91
+ result.current.addFiles([makeFile("shot.png", 4096)], {
92
+ prepareImages: true,
93
+ });
94
+ });
95
+
96
+ // Preparation re-encoded to JPEG: name and MIME follow.
97
+ act(() => {
98
+ gap.resolve(makeFile("shot.jpg", 2048, "image/jpeg"));
99
+ });
100
+
101
+ await waitFor(() => {
102
+ expect(result.current.entries[0].phase).toBe("ready");
103
+ });
104
+ expect(result.current.entries[0].file.name).toBe("shot.jpg");
105
+ expect(result.current.entries[0].contentType).toBe("image/jpeg");
106
+ expect(uploadAttachment).toHaveBeenCalledTimes(1);
107
+ expect(result.current.toAttachmentInputs()).toEqual([
108
+ {
109
+ filename: "shot.jpg",
110
+ storageKey: "attachments/test/key",
111
+ contentType: "image/jpeg",
112
+ },
113
+ ]);
114
+ });
115
+
116
+ it("accepts a raw file over the size limit when preparation brings it under (the #369 paste contract)", async () => {
117
+ const { uploadAttachment } = mockStigmer();
118
+ const onValidationError = vi.fn();
119
+ const gap = deferred<File>();
120
+ prepareMock.mockReturnValue(gap.promise);
121
+
122
+ const { result } = renderHook(() =>
123
+ useAttachments({ onValidationError }),
124
+ );
125
+
126
+ // 10 MB + 1 raw screenshot — would be rejected by up-front validation.
127
+ act(() => {
128
+ result.current.addFiles(
129
+ [makeFile("huge-screenshot.png", MAX_ATTACHMENT_BYTES + 1)],
130
+ { prepareImages: true },
131
+ );
132
+ });
133
+ expect(result.current.entries[0].phase).toBe("preparing");
134
+
135
+ act(() => {
136
+ gap.resolve(makeFile("huge-screenshot.png", 512 * 1024));
137
+ });
138
+
139
+ await waitFor(() => {
140
+ expect(result.current.entries[0].phase).toBe("ready");
141
+ });
142
+ expect(onValidationError).not.toHaveBeenCalled();
143
+ expect(uploadAttachment).toHaveBeenCalledTimes(1);
144
+ });
145
+
146
+ it("removes the entry and reports via onValidationError when still oversized after preparation", async () => {
147
+ const { uploadAttachment } = mockStigmer();
148
+ const onValidationError = vi.fn();
149
+ const oversized = makeFile("giant.zip", MAX_ATTACHMENT_BYTES + 1, "application/zip");
150
+ // Non-image passthrough: preparation returns the original untouched.
151
+ prepareMock.mockResolvedValue(oversized);
152
+
153
+ const { result } = renderHook(() =>
154
+ useAttachments({ onValidationError }),
155
+ );
156
+
157
+ act(() => {
158
+ result.current.addFiles([oversized], { prepareImages: true });
159
+ });
160
+ expect(result.current.entries).toHaveLength(1);
161
+
162
+ await waitFor(() => {
163
+ expect(result.current.entries).toHaveLength(0);
164
+ });
165
+ expect(onValidationError).toHaveBeenCalledWith(
166
+ expect.stringContaining("giant.zip"),
167
+ );
168
+ expect(uploadAttachment).not.toHaveBeenCalled();
169
+ });
170
+
171
+ it("discards the preparation result when the entry is removed mid-preparation", async () => {
172
+ const { uploadAttachment } = mockStigmer();
173
+ const gap = deferred<File>();
174
+ prepareMock.mockReturnValue(gap.promise);
175
+
176
+ const { result } = renderHook(() => useAttachments());
177
+
178
+ act(() => {
179
+ result.current.addFiles([makeFile("shot.png", 1024)], {
180
+ prepareImages: true,
181
+ });
182
+ });
183
+ const id = result.current.entries[0].id;
184
+
185
+ act(() => {
186
+ result.current.removeEntry(id);
187
+ });
188
+ expect(result.current.entries).toHaveLength(0);
189
+
190
+ // Late completion must not resurrect the entry or start an upload.
191
+ await act(async () => {
192
+ gap.resolve(makeFile("shot.jpg", 512, "image/jpeg"));
193
+ await gap.promise;
194
+ });
195
+ expect(result.current.entries).toHaveLength(0);
196
+ expect(uploadAttachment).not.toHaveBeenCalled();
197
+ });
198
+
199
+ it("discards the preparation result on clear()", async () => {
200
+ const { uploadAttachment } = mockStigmer();
201
+ const gap = deferred<File>();
202
+ prepareMock.mockReturnValue(gap.promise);
203
+
204
+ const { result } = renderHook(() => useAttachments());
205
+
206
+ act(() => {
207
+ result.current.addFiles([makeFile("shot.png", 1024)], {
208
+ prepareImages: true,
209
+ });
210
+ });
211
+
212
+ act(() => {
213
+ result.current.clear();
214
+ });
215
+
216
+ await act(async () => {
217
+ gap.resolve(makeFile("shot.jpg", 512, "image/jpeg"));
218
+ await gap.promise;
219
+ });
220
+ expect(result.current.entries).toHaveLength(0);
221
+ expect(uploadAttachment).not.toHaveBeenCalled();
222
+ });
223
+
224
+ it("uniquifies the prepared name against other entries' settled names", async () => {
225
+ mockStigmer();
226
+ const gap = deferred<File>();
227
+ prepareMock.mockReturnValue(gap.promise);
228
+
229
+ const { result } = renderHook(() => useAttachments());
230
+
231
+ // A settled entry already owns "pasted-image.png".
232
+ act(() => {
233
+ result.current.addFiles([makeFile("pasted-image.png", 256)]);
234
+ });
235
+ // The prepared file lands on the same name.
236
+ act(() => {
237
+ result.current.addFiles([makeFile("other.png", 256)], {
238
+ prepareImages: true,
239
+ });
240
+ });
241
+ act(() => {
242
+ gap.resolve(makeFile("pasted-image.png", 128));
243
+ });
244
+
245
+ await waitFor(() => {
246
+ expect(result.current.entries[1].phase).toBe("ready");
247
+ });
248
+ expect(result.current.entries[1].file.name).toBe("pasted-image-2.png");
249
+ });
250
+ });
251
+
252
+ // ---------------------------------------------------------------------------
253
+ // The unflagged path — byte-identical to the pre-#369 behavior
254
+ // ---------------------------------------------------------------------------
255
+
256
+ describe("useAttachments — unflagged addFiles", () => {
257
+ it("never enters the preparing phase and never calls prepareImageForVision", async () => {
258
+ mockStigmer();
259
+
260
+ const { result } = renderHook(() => useAttachments());
261
+
262
+ act(() => {
263
+ result.current.addFiles([makeFile("picked.png", 1024)]);
264
+ });
265
+
266
+ expect(result.current.entries[0].phase).toBe("uploading");
267
+ expect(result.current.isPreparing).toBe(false);
268
+ expect(prepareMock).not.toHaveBeenCalled();
269
+
270
+ await waitFor(() => {
271
+ expect(result.current.entries[0].phase).toBe("ready");
272
+ });
273
+ });
274
+
275
+ it("still validates size up front and rejects without creating an entry", () => {
276
+ const { uploadAttachment } = mockStigmer();
277
+ const onValidationError = vi.fn();
278
+
279
+ const { result } = renderHook(() =>
280
+ useAttachments({ onValidationError }),
281
+ );
282
+
283
+ act(() => {
284
+ result.current.addFiles([
285
+ makeFile("too-big.png", MAX_ATTACHMENT_BYTES + 1),
286
+ ]);
287
+ });
288
+
289
+ expect(result.current.entries).toHaveLength(0);
290
+ expect(onValidationError).toHaveBeenCalledTimes(1);
291
+ expect(uploadAttachment).not.toHaveBeenCalled();
292
+ });
293
+ });
@@ -1,5 +1,6 @@
1
1
  export { useAttachments } from "./useAttachments.js";
2
2
  export type {
3
+ AddFilesOptions,
3
4
  AttachmentPhase,
4
5
  AttachmentEntry,
5
6
  UseAttachmentsOptions,