@stigmer/react 3.12.2 → 3.12.4

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 (429) hide show
  1. package/access/ManageAccessDialog.d.ts.map +1 -1
  2. package/access/ManageAccessDialog.js +3 -19
  3. package/access/ManageAccessDialog.js.map +1 -1
  4. package/agent/steps/IdentityStep.d.ts.map +1 -1
  5. package/agent/steps/IdentityStep.js +2 -1
  6. package/agent/steps/IdentityStep.js.map +1 -1
  7. package/agent-instance/AgentInstanceDetailPanel.d.ts.map +1 -1
  8. package/agent-instance/AgentInstanceDetailPanel.js +2 -1
  9. package/agent-instance/AgentInstanceDetailPanel.js.map +1 -1
  10. package/agent-instance/CreateAgentInstanceDialog.d.ts.map +1 -1
  11. package/agent-instance/CreateAgentInstanceDialog.js +7 -20
  12. package/agent-instance/CreateAgentInstanceDialog.js.map +1 -1
  13. package/api-key/CreateApiKeyForm.d.ts.map +1 -1
  14. package/api-key/CreateApiKeyForm.js +2 -1
  15. package/api-key/CreateApiKeyForm.js.map +1 -1
  16. package/attachment/AttachmentImageLightbox.d.ts.map +1 -1
  17. package/attachment/AttachmentImageLightbox.js +8 -23
  18. package/attachment/AttachmentImageLightbox.js.map +1 -1
  19. package/channel/ChannelConversationsDialog.d.ts.map +1 -1
  20. package/channel/ChannelConversationsDialog.js +5 -20
  21. package/channel/ChannelConversationsDialog.js.map +1 -1
  22. package/channel/ChannelCredentialsDialog.d.ts.map +1 -1
  23. package/channel/ChannelCredentialsDialog.js +3 -19
  24. package/channel/ChannelCredentialsDialog.js.map +1 -1
  25. package/channel/ChannelTemplatesDialog.d.ts.map +1 -1
  26. package/channel/ChannelTemplatesDialog.js +6 -21
  27. package/channel/ChannelTemplatesDialog.js.map +1 -1
  28. package/channel/ConnectSlackDialog.d.ts.map +1 -1
  29. package/channel/ConnectSlackDialog.js +5 -22
  30. package/channel/ConnectSlackDialog.js.map +1 -1
  31. package/channel/ConnectWhatsAppDialog.d.ts.map +1 -1
  32. package/channel/ConnectWhatsAppDialog.js +3 -21
  33. package/channel/ConnectWhatsAppDialog.js.map +1 -1
  34. package/channel/connect/ServingAppSection.d.ts.map +1 -1
  35. package/channel/connect/ServingAppSection.js +2 -1
  36. package/channel/connect/ServingAppSection.js.map +1 -1
  37. package/channel-app/CreateChannelAppForm.d.ts.map +1 -1
  38. package/channel-app/CreateChannelAppForm.js +2 -1
  39. package/channel-app/CreateChannelAppForm.js.map +1 -1
  40. package/conversation/ConversationAttentionBanner.d.ts +23 -6
  41. package/conversation/ConversationAttentionBanner.d.ts.map +1 -1
  42. package/conversation/ConversationAttentionBanner.js +25 -10
  43. package/conversation/ConversationAttentionBanner.js.map +1 -1
  44. package/conversation/ConversationListPane.d.ts.map +1 -1
  45. package/conversation/ConversationListPane.js +26 -6
  46. package/conversation/ConversationListPane.js.map +1 -1
  47. package/conversation/ConversationTimelineView.d.ts.map +1 -1
  48. package/conversation/ConversationTimelineView.js +2 -1
  49. package/conversation/ConversationTimelineView.js.map +1 -1
  50. package/conversation/ConversationsWorkbench.d.ts.map +1 -1
  51. package/conversation/ConversationsWorkbench.js +1 -1
  52. package/conversation/ConversationsWorkbench.js.map +1 -1
  53. package/cursor-accounts/CursorAccountsConsole.d.ts.map +1 -1
  54. package/cursor-accounts/CursorAccountsConsole.js +2 -1
  55. package/cursor-accounts/CursorAccountsConsole.js.map +1 -1
  56. package/cursor-accounts/MemberKeysPanel.d.ts.map +1 -1
  57. package/cursor-accounts/MemberKeysPanel.js +2 -1
  58. package/cursor-accounts/MemberKeysPanel.js.map +1 -1
  59. package/dashboard/DashboardFailedRuns.d.ts.map +1 -1
  60. package/dashboard/DashboardFailedRuns.js +2 -1
  61. package/dashboard/DashboardFailedRuns.js.map +1 -1
  62. package/dependency-graph/DependencyGraph.d.ts.map +1 -1
  63. package/dependency-graph/DependencyGraph.js +2 -1
  64. package/dependency-graph/DependencyGraph.js.map +1 -1
  65. package/dependency-graph/DependencyTreeNode.d.ts.map +1 -1
  66. package/dependency-graph/DependencyTreeNode.js +2 -1
  67. package/dependency-graph/DependencyTreeNode.js.map +1 -1
  68. package/environment/EnvironmentPicker.d.ts.map +1 -1
  69. package/environment/EnvironmentPicker.js +2 -1
  70. package/environment/EnvironmentPicker.js.map +1 -1
  71. package/error/SecretFlowErrorGuide.d.ts.map +1 -1
  72. package/error/SecretFlowErrorGuide.js +2 -1
  73. package/error/SecretFlowErrorGuide.js.map +1 -1
  74. package/execution/ApprovalCard.d.ts.map +1 -1
  75. package/execution/ApprovalCard.js +13 -3
  76. package/execution/ApprovalCard.js.map +1 -1
  77. package/execution/ArtifactContentBody.d.ts.map +1 -1
  78. package/execution/ArtifactContentBody.js +2 -1
  79. package/execution/ArtifactContentBody.js.map +1 -1
  80. package/execution/ArtifactPreviewModal.d.ts.map +1 -1
  81. package/execution/ArtifactPreviewModal.js +11 -17
  82. package/execution/ArtifactPreviewModal.js.map +1 -1
  83. package/execution/ArtifactsWidget.d.ts.map +1 -1
  84. package/execution/ArtifactsWidget.js +2 -1
  85. package/execution/ArtifactsWidget.js.map +1 -1
  86. package/execution/FileChangeProgressBar.d.ts.map +1 -1
  87. package/execution/FileChangeProgressBar.js +2 -1
  88. package/execution/FileChangeProgressBar.js.map +1 -1
  89. package/execution/TodoList.d.ts.map +1 -1
  90. package/execution/TodoList.js +2 -1
  91. package/execution/TodoList.js.map +1 -1
  92. package/execution/ToolCallItem.d.ts +3 -1
  93. package/execution/ToolCallItem.d.ts.map +1 -1
  94. package/execution/ToolCallItem.js +19 -7
  95. package/execution/ToolCallItem.js.map +1 -1
  96. package/execution/WriteBacksWidget.d.ts.map +1 -1
  97. package/execution/WriteBacksWidget.js +2 -1
  98. package/execution/WriteBacksWidget.js.map +1 -1
  99. package/execution/index.d.ts +1 -1
  100. package/execution/index.d.ts.map +1 -1
  101. package/execution/index.js +1 -1
  102. package/execution/index.js.map +1 -1
  103. package/execution/tool-categories.d.ts +37 -3
  104. package/execution/tool-categories.d.ts.map +1 -1
  105. package/execution/tool-categories.js +74 -2
  106. package/execution/tool-categories.js.map +1 -1
  107. package/execution/tool-presenter.d.ts +15 -0
  108. package/execution/tool-presenter.d.ts.map +1 -1
  109. package/execution/tool-presenter.js +7 -2
  110. package/execution/tool-presenter.js.map +1 -1
  111. package/iam-policy/PeopleWithAccess.d.ts.map +1 -1
  112. package/iam-policy/PeopleWithAccess.js +2 -1
  113. package/iam-policy/PeopleWithAccess.js.map +1 -1
  114. package/iam-policy/PrincipalPicker.d.ts.map +1 -1
  115. package/iam-policy/PrincipalPicker.js +2 -1
  116. package/iam-policy/PrincipalPicker.js.map +1 -1
  117. package/iam-policy/RoleSelector.d.ts.map +1 -1
  118. package/iam-policy/RoleSelector.js +2 -1
  119. package/iam-policy/RoleSelector.js.map +1 -1
  120. package/identity-provider/CreateIdentityProviderForm.d.ts.map +1 -1
  121. package/identity-provider/CreateIdentityProviderForm.js +2 -1
  122. package/identity-provider/CreateIdentityProviderForm.js.map +1 -1
  123. package/identity-provider/IdentityProviderDetailPanel.d.ts.map +1 -1
  124. package/identity-provider/IdentityProviderDetailPanel.js +2 -1
  125. package/identity-provider/IdentityProviderDetailPanel.js.map +1 -1
  126. package/identity-provider/IdentityProviderWizard.d.ts.map +1 -1
  127. package/identity-provider/IdentityProviderWizard.js +2 -1
  128. package/identity-provider/IdentityProviderWizard.js.map +1 -1
  129. package/index.d.ts +4 -2
  130. package/index.d.ts.map +1 -1
  131. package/index.js +4 -1
  132. package/index.js.map +1 -1
  133. package/internal/DialogShell.d.ts +77 -0
  134. package/internal/DialogShell.d.ts.map +1 -0
  135. package/internal/DialogShell.js +77 -0
  136. package/internal/DialogShell.js.map +1 -0
  137. package/internal/element-resets.d.ts +17 -0
  138. package/internal/element-resets.d.ts.map +1 -0
  139. package/internal/element-resets.js +32 -0
  140. package/internal/element-resets.js.map +1 -0
  141. package/internal/file-tree/FileTreeNode.d.ts.map +1 -1
  142. package/internal/file-tree/FileTreeNode.js +2 -1
  143. package/internal/file-tree/FileTreeNode.js.map +1 -1
  144. package/internal/markdown-components.d.ts +7 -0
  145. package/internal/markdown-components.d.ts.map +1 -1
  146. package/internal/markdown-components.js +15 -5
  147. package/internal/markdown-components.js.map +1 -1
  148. package/invitation/InvitationManager.d.ts.map +1 -1
  149. package/invitation/InvitationManager.js +2 -1
  150. package/invitation/InvitationManager.js.map +1 -1
  151. package/manifest/ApplyManifestDialog.d.ts.map +1 -1
  152. package/manifest/ApplyManifestDialog.js +8 -17
  153. package/manifest/ApplyManifestDialog.js.map +1 -1
  154. package/manifest/EditResourceYamlDialog.d.ts.map +1 -1
  155. package/manifest/EditResourceYamlDialog.js +3 -19
  156. package/manifest/EditResourceYamlDialog.js.map +1 -1
  157. package/mcp-server/McpServerConnectDialog.d.ts.map +1 -1
  158. package/mcp-server/McpServerConnectDialog.js +8 -20
  159. package/mcp-server/McpServerConnectDialog.js.map +1 -1
  160. package/mcp-server/McpServerDetailView.d.ts.map +1 -1
  161. package/mcp-server/McpServerDetailView.js +4 -15
  162. package/mcp-server/McpServerDetailView.js.map +1 -1
  163. package/mcp-server/steps/IdentityTransportStep.d.ts.map +1 -1
  164. package/mcp-server/steps/IdentityTransportStep.js +2 -1
  165. package/mcp-server/steps/IdentityTransportStep.js.map +1 -1
  166. package/package.json +4 -4
  167. package/platform-client/CreatePlatformClientForm.d.ts.map +1 -1
  168. package/platform-client/CreatePlatformClientForm.js +2 -1
  169. package/platform-client/CreatePlatformClientForm.js.map +1 -1
  170. package/platform-client/PlatformClientDetailPanel.d.ts.map +1 -1
  171. package/platform-client/PlatformClientDetailPanel.js +2 -1
  172. package/platform-client/PlatformClientDetailPanel.js.map +1 -1
  173. package/pricing-governance/BaselineEditor.d.ts.map +1 -1
  174. package/pricing-governance/BaselineEditor.js +2 -1
  175. package/pricing-governance/BaselineEditor.js.map +1 -1
  176. package/pricing-governance/PricingGovernanceConsole.d.ts.map +1 -1
  177. package/pricing-governance/PricingGovernanceConsole.js +2 -1
  178. package/pricing-governance/PricingGovernanceConsole.js.map +1 -1
  179. package/provider-standing/ProviderStandingAccessNotice.d.ts +11 -0
  180. package/provider-standing/ProviderStandingAccessNotice.d.ts.map +1 -0
  181. package/provider-standing/ProviderStandingAccessNotice.js +14 -0
  182. package/provider-standing/ProviderStandingAccessNotice.js.map +1 -0
  183. package/provider-standing/ProviderStandingConsole.d.ts +24 -0
  184. package/provider-standing/ProviderStandingConsole.d.ts.map +1 -0
  185. package/provider-standing/ProviderStandingConsole.js +98 -0
  186. package/provider-standing/ProviderStandingConsole.js.map +1 -0
  187. package/provider-standing/index.d.ts +6 -0
  188. package/provider-standing/index.d.ts.map +1 -0
  189. package/provider-standing/index.js +6 -0
  190. package/provider-standing/index.js.map +1 -0
  191. package/provider-standing/useProviderStanding.d.ts +34 -0
  192. package/provider-standing/useProviderStanding.d.ts.map +1 -0
  193. package/provider-standing/useProviderStanding.js +26 -0
  194. package/provider-standing/useProviderStanding.js.map +1 -0
  195. package/provider.d.ts +12 -0
  196. package/provider.d.ts.map +1 -1
  197. package/provider.js +12 -0
  198. package/provider.js.map +1 -1
  199. package/resource-creation/StepIndicator.d.ts.map +1 -1
  200. package/resource-creation/StepIndicator.js +2 -1
  201. package/resource-creation/StepIndicator.js.map +1 -1
  202. package/resource-detail/ConfirmDialog.d.ts +2 -3
  203. package/resource-detail/ConfirmDialog.d.ts.map +1 -1
  204. package/resource-detail/ConfirmDialog.js +8 -20
  205. package/resource-detail/ConfirmDialog.js.map +1 -1
  206. package/schedule/ScheduleDetailView.d.ts.map +1 -1
  207. package/schedule/ScheduleDetailView.js +3 -2
  208. package/schedule/ScheduleDetailView.js.map +1 -1
  209. package/schedule/ScheduleRunsTable.d.ts.map +1 -1
  210. package/schedule/ScheduleRunsTable.js +2 -1
  211. package/schedule/ScheduleRunsTable.js.map +1 -1
  212. package/session/facets/ArtifactsTab.d.ts.map +1 -1
  213. package/session/facets/ArtifactsTab.js +2 -1
  214. package/session/facets/ArtifactsTab.js.map +1 -1
  215. package/session/facets/ChangesTab.d.ts.map +1 -1
  216. package/session/facets/ChangesTab.js +2 -1
  217. package/session/facets/ChangesTab.js.map +1 -1
  218. package/session/facets/UsageTab.d.ts +10 -3
  219. package/session/facets/UsageTab.d.ts.map +1 -1
  220. package/session/facets/UsageTab.js +42 -6
  221. package/session/facets/UsageTab.js.map +1 -1
  222. package/session/index.d.ts +1 -1
  223. package/session/index.d.ts.map +1 -1
  224. package/session/index.js.map +1 -1
  225. package/session/useSessionUsage.d.ts +25 -0
  226. package/session/useSessionUsage.d.ts.map +1 -1
  227. package/session/useSessionUsage.js +11 -0
  228. package/session/useSessionUsage.js.map +1 -1
  229. package/settings/settings-nav.d.ts.map +1 -1
  230. package/settings/settings-nav.js +7 -1
  231. package/settings/settings-nav.js.map +1 -1
  232. package/settings/useSettingsNavGroups.d.ts.map +1 -1
  233. package/settings/useSettingsNavGroups.js +4 -1
  234. package/settings/useSettingsNavGroups.js.map +1 -1
  235. package/sharing/ShareAgentDialog.d.ts.map +1 -1
  236. package/sharing/ShareAgentDialog.js +4 -21
  237. package/sharing/ShareAgentDialog.js.map +1 -1
  238. package/sidebar/WorkspaceSidebar.d.ts.map +1 -1
  239. package/sidebar/WorkspaceSidebar.js +2 -1
  240. package/sidebar/WorkspaceSidebar.js.map +1 -1
  241. package/skill/SkillDiffDialog.d.ts.map +1 -1
  242. package/skill/SkillDiffDialog.js +5 -21
  243. package/skill/SkillDiffDialog.js.map +1 -1
  244. package/skill/SkillFileBrowser.d.ts.map +1 -1
  245. package/skill/SkillFileBrowser.js +2 -1
  246. package/skill/SkillFileBrowser.js.map +1 -1
  247. package/skill/internal/fetchAndUnpackArtifact.d.ts +1 -1
  248. package/skill/internal/fetchAndUnpackArtifact.d.ts.map +1 -1
  249. package/skill/internal/fetchAndUnpackArtifact.js +47 -3
  250. package/skill/internal/fetchAndUnpackArtifact.js.map +1 -1
  251. package/skill/useSkillDiff.d.ts.map +1 -1
  252. package/skill/useSkillDiff.js +7 -1
  253. package/skill/useSkillDiff.js.map +1 -1
  254. package/skill/useSkillUpload.d.ts.map +1 -1
  255. package/skill/useSkillUpload.js +22 -4
  256. package/skill/useSkillUpload.js.map +1 -1
  257. package/src/__tests__/bare-host-resets.layout.test.tsx +184 -0
  258. package/src/access/ManageAccessDialog.tsx +7 -27
  259. package/src/agent/steps/IdentityStep.tsx +2 -1
  260. package/src/agent-instance/AgentInstanceDetailPanel.tsx +2 -1
  261. package/src/agent-instance/CreateAgentInstanceDialog.tsx +14 -27
  262. package/src/api-key/CreateApiKeyForm.tsx +2 -1
  263. package/src/attachment/AttachmentImageLightbox.tsx +13 -36
  264. package/src/channel/ChannelConversationsDialog.tsx +10 -28
  265. package/src/channel/ChannelCredentialsDialog.tsx +8 -28
  266. package/src/channel/ChannelTemplatesDialog.tsx +12 -30
  267. package/src/channel/ConnectSlackDialog.tsx +10 -31
  268. package/src/channel/ConnectWhatsAppDialog.tsx +8 -30
  269. package/src/channel/connect/ServingAppSection.tsx +2 -1
  270. package/src/channel-app/CreateChannelAppForm.tsx +2 -1
  271. package/src/conversation/ConversationAttentionBanner.tsx +64 -19
  272. package/src/conversation/ConversationListPane.tsx +39 -17
  273. package/src/conversation/ConversationTimelineView.tsx +2 -1
  274. package/src/conversation/ConversationsWorkbench.tsx +1 -0
  275. package/src/conversation/__tests__/ConversationAttentionBanner.test.tsx +76 -2
  276. package/src/conversation/__tests__/ConversationListPane.test.tsx +15 -4
  277. package/src/cursor-accounts/CursorAccountsConsole.tsx +2 -1
  278. package/src/cursor-accounts/MemberKeysPanel.tsx +2 -1
  279. package/src/dashboard/DashboardFailedRuns.tsx +2 -1
  280. package/src/dependency-graph/DependencyGraph.tsx +2 -1
  281. package/src/dependency-graph/DependencyTreeNode.tsx +2 -1
  282. package/src/environment/EnvironmentPicker.tsx +2 -1
  283. package/src/error/SecretFlowErrorGuide.tsx +3 -2
  284. package/src/execution/ApprovalCard.tsx +23 -2
  285. package/src/execution/ArtifactContentBody.tsx +2 -1
  286. package/src/execution/ArtifactPreviewModal.tsx +15 -27
  287. package/src/execution/ArtifactsWidget.tsx +2 -1
  288. package/src/execution/FileChangeProgressBar.tsx +2 -1
  289. package/src/execution/TodoList.tsx +2 -1
  290. package/src/execution/ToolCallItem.tsx +19 -8
  291. package/src/execution/WriteBacksWidget.tsx +2 -1
  292. package/src/execution/__tests__/intent-title.test.tsx +221 -0
  293. package/src/execution/index.ts +3 -0
  294. package/src/execution/tool-categories.ts +103 -5
  295. package/src/execution/tool-presenter.ts +22 -1
  296. package/src/iam-policy/PeopleWithAccess.tsx +2 -1
  297. package/src/iam-policy/PrincipalPicker.tsx +2 -0
  298. package/src/iam-policy/RoleSelector.tsx +2 -1
  299. package/src/identity-provider/CreateIdentityProviderForm.tsx +2 -1
  300. package/src/identity-provider/IdentityProviderDetailPanel.tsx +2 -1
  301. package/src/identity-provider/IdentityProviderWizard.tsx +2 -1
  302. package/src/index.ts +16 -0
  303. package/src/internal/DialogShell.tsx +169 -0
  304. package/src/internal/__tests__/DialogShell.test.tsx +223 -0
  305. package/src/internal/element-resets.ts +33 -0
  306. package/src/internal/file-tree/FileTreeNode.tsx +2 -1
  307. package/src/internal/markdown-components.tsx +15 -5
  308. package/src/invitation/InvitationManager.tsx +3 -2
  309. package/src/manifest/ApplyManifestDialog.tsx +10 -27
  310. package/src/manifest/EditResourceYamlDialog.tsx +4 -31
  311. package/src/mcp-server/McpServerConnectDialog.tsx +15 -29
  312. package/src/mcp-server/McpServerDetailView.tsx +12 -24
  313. package/src/mcp-server/steps/IdentityTransportStep.tsx +3 -2
  314. package/src/platform-client/CreatePlatformClientForm.tsx +4 -3
  315. package/src/platform-client/PlatformClientDetailPanel.tsx +4 -3
  316. package/src/pricing-governance/BaselineEditor.tsx +3 -2
  317. package/src/pricing-governance/PricingGovernanceConsole.tsx +2 -1
  318. package/src/provider-standing/ProviderStandingAccessNotice.tsx +36 -0
  319. package/src/provider-standing/ProviderStandingConsole.tsx +216 -0
  320. package/src/provider-standing/__tests__/ProviderStandingConsole.test.tsx +143 -0
  321. package/src/provider-standing/index.ts +8 -0
  322. package/src/provider-standing/useProviderStanding.ts +50 -0
  323. package/src/provider.tsx +12 -0
  324. package/src/resource-creation/StepIndicator.tsx +2 -1
  325. package/src/resource-detail/ConfirmDialog.tsx +9 -30
  326. package/src/schedule/ScheduleDetailView.tsx +3 -2
  327. package/src/schedule/ScheduleRunsTable.tsx +2 -1
  328. package/src/session/__tests__/UsageTab.test.tsx +136 -0
  329. package/src/session/__tests__/useSessionUsage.test.ts +19 -0
  330. package/src/session/facets/ArtifactsTab.tsx +2 -1
  331. package/src/session/facets/ChangesTab.tsx +2 -1
  332. package/src/session/facets/UsageTab.tsx +98 -6
  333. package/src/session/index.ts +1 -0
  334. package/src/session/useSessionUsage.ts +37 -0
  335. package/src/settings/__tests__/useSettingsNavGroups.test.tsx +11 -1
  336. package/src/settings/settings-nav.ts +7 -0
  337. package/src/settings/useSettingsNavGroups.ts +8 -1
  338. package/src/sharing/ShareAgentDialog.tsx +9 -30
  339. package/src/sidebar/WorkspaceSidebar.tsx +2 -1
  340. package/src/skill/SkillDiffDialog.tsx +13 -36
  341. package/src/skill/SkillFileBrowser.tsx +2 -1
  342. package/src/skill/__tests__/SkillFileBrowser.test.tsx +10 -2
  343. package/src/skill/__tests__/fetchAndUnpackArtifact.test.ts +90 -0
  344. package/src/skill/__tests__/useSkillUpload.test.ts +69 -0
  345. package/src/skill/internal/fetchAndUnpackArtifact.ts +54 -4
  346. package/src/skill/useSkillDiff.ts +7 -1
  347. package/src/skill/useSkillUpload.ts +25 -6
  348. package/src/workflow/FailedRunsWidget.tsx +2 -1
  349. package/src/workflow/PendingApprovalsWidget.tsx +2 -1
  350. package/src/workflow/ViewYamlDialog.tsx +18 -37
  351. package/src/workflow/WorkflowArchitectDialog.tsx +11 -43
  352. package/src/workflow/WorkflowExplainDialog.tsx +11 -37
  353. package/src/workflow/WorkflowGraphFullscreenDialog.tsx +14 -26
  354. package/src/workflow/WorkflowRunDialog.tsx +21 -48
  355. package/src/workflow/execution-comparison/ExecutionComparisonPicker.tsx +14 -31
  356. package/src/workflow/facets/WorkflowArtifactsTab.tsx +2 -1
  357. package/src/workflow/facets/WorkflowUsageTab.tsx +2 -1
  358. package/src/workflow/inspector/WorkflowSummaryPanel.tsx +2 -1
  359. package/src/workflow/inspector/tabs/BranchesTab.tsx +2 -1
  360. package/src/workflow/inspector/tabs/IterationTab.tsx +2 -1
  361. package/src/workflow/instance/CreateWorkflowInstanceDialog.tsx +14 -27
  362. package/src/workflow/instance/WorkflowInstanceDetailPanel.tsx +2 -1
  363. package/src/workflow/templates/WorkflowTemplatePreview.tsx +18 -28
  364. package/src/workspace/ExplorerTree.tsx +2 -1
  365. package/src/workspace/WorkspaceContentSearch.tsx +2 -1
  366. package/src/workspace/WorkspaceFileSearch.tsx +2 -1
  367. package/src/workspace/WorkspaceSummary.tsx +2 -1
  368. package/styles.css +1 -1
  369. package/workflow/FailedRunsWidget.d.ts.map +1 -1
  370. package/workflow/FailedRunsWidget.js +2 -1
  371. package/workflow/FailedRunsWidget.js.map +1 -1
  372. package/workflow/PendingApprovalsWidget.d.ts.map +1 -1
  373. package/workflow/PendingApprovalsWidget.js +2 -1
  374. package/workflow/PendingApprovalsWidget.js.map +1 -1
  375. package/workflow/ViewYamlDialog.d.ts.map +1 -1
  376. package/workflow/ViewYamlDialog.js +10 -29
  377. package/workflow/ViewYamlDialog.js.map +1 -1
  378. package/workflow/WorkflowArchitectDialog.d.ts.map +1 -1
  379. package/workflow/WorkflowArchitectDialog.js +5 -24
  380. package/workflow/WorkflowArchitectDialog.js.map +1 -1
  381. package/workflow/WorkflowExplainDialog.d.ts.map +1 -1
  382. package/workflow/WorkflowExplainDialog.js +5 -21
  383. package/workflow/WorkflowExplainDialog.js.map +1 -1
  384. package/workflow/WorkflowGraphFullscreenDialog.d.ts.map +1 -1
  385. package/workflow/WorkflowGraphFullscreenDialog.js +11 -17
  386. package/workflow/WorkflowGraphFullscreenDialog.js.map +1 -1
  387. package/workflow/WorkflowRunDialog.d.ts.map +1 -1
  388. package/workflow/WorkflowRunDialog.js +13 -29
  389. package/workflow/WorkflowRunDialog.js.map +1 -1
  390. package/workflow/execution-comparison/ExecutionComparisonPicker.d.ts.map +1 -1
  391. package/workflow/execution-comparison/ExecutionComparisonPicker.js +8 -26
  392. package/workflow/execution-comparison/ExecutionComparisonPicker.js.map +1 -1
  393. package/workflow/facets/WorkflowArtifactsTab.d.ts.map +1 -1
  394. package/workflow/facets/WorkflowArtifactsTab.js +2 -1
  395. package/workflow/facets/WorkflowArtifactsTab.js.map +1 -1
  396. package/workflow/facets/WorkflowUsageTab.d.ts.map +1 -1
  397. package/workflow/facets/WorkflowUsageTab.js +2 -1
  398. package/workflow/facets/WorkflowUsageTab.js.map +1 -1
  399. package/workflow/inspector/WorkflowSummaryPanel.d.ts.map +1 -1
  400. package/workflow/inspector/WorkflowSummaryPanel.js +2 -1
  401. package/workflow/inspector/WorkflowSummaryPanel.js.map +1 -1
  402. package/workflow/inspector/tabs/BranchesTab.d.ts.map +1 -1
  403. package/workflow/inspector/tabs/BranchesTab.js +2 -1
  404. package/workflow/inspector/tabs/BranchesTab.js.map +1 -1
  405. package/workflow/inspector/tabs/IterationTab.d.ts.map +1 -1
  406. package/workflow/inspector/tabs/IterationTab.js +2 -1
  407. package/workflow/inspector/tabs/IterationTab.js.map +1 -1
  408. package/workflow/instance/CreateWorkflowInstanceDialog.d.ts.map +1 -1
  409. package/workflow/instance/CreateWorkflowInstanceDialog.js +7 -20
  410. package/workflow/instance/CreateWorkflowInstanceDialog.js.map +1 -1
  411. package/workflow/instance/WorkflowInstanceDetailPanel.d.ts.map +1 -1
  412. package/workflow/instance/WorkflowInstanceDetailPanel.js +2 -1
  413. package/workflow/instance/WorkflowInstanceDetailPanel.js.map +1 -1
  414. package/workflow/templates/WorkflowTemplatePreview.d.ts +1 -1
  415. package/workflow/templates/WorkflowTemplatePreview.d.ts.map +1 -1
  416. package/workflow/templates/WorkflowTemplatePreview.js +10 -22
  417. package/workflow/templates/WorkflowTemplatePreview.js.map +1 -1
  418. package/workspace/ExplorerTree.d.ts.map +1 -1
  419. package/workspace/ExplorerTree.js +2 -1
  420. package/workspace/ExplorerTree.js.map +1 -1
  421. package/workspace/WorkspaceContentSearch.d.ts.map +1 -1
  422. package/workspace/WorkspaceContentSearch.js +2 -1
  423. package/workspace/WorkspaceContentSearch.js.map +1 -1
  424. package/workspace/WorkspaceFileSearch.d.ts.map +1 -1
  425. package/workspace/WorkspaceFileSearch.js +2 -1
  426. package/workspace/WorkspaceFileSearch.js.map +1 -1
  427. package/workspace/WorkspaceSummary.d.ts.map +1 -1
  428. package/workspace/WorkspaceSummary.js +2 -1
  429. package/workspace/WorkspaceSummary.js.map +1 -1
@@ -1,8 +1,9 @@
1
1
  "use client";
2
2
 
3
3
  import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
4
- import { useSessionUsage } from "../useSessionUsage.js";
5
- import { UsageWidget } from "../../execution/UsageWidget.js";
4
+ import { ServiceTier } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
5
+ import { useSessionUsage, type ExecutionUsageEntry } from "../useSessionUsage.js";
6
+ import { UsageWidget, formatCost } from "../../execution/UsageWidget.js";
6
7
 
7
8
  export interface UsageTabProps {
8
9
  readonly executions: readonly AgentExecution[];
@@ -11,9 +12,16 @@ export interface UsageTabProps {
11
12
  /**
12
13
  * Usage facet for the session panel (a `useSessionRailViews` rail view).
13
14
  *
14
- * Uses `useSessionUsage` to determine if data exists, then delegates
15
- * rendering to the existing `UsageWidget`. Shows an empty state when
16
- * no usage data is available.
15
+ * Renders the session totals ({@link UsageWidget}) plus the #362 model
16
+ * provenance list: per execution, the billing-RESOLVED model with its
17
+ * cost for a Cursor Auto run, the only honest answer to "which model
18
+ * actually ran and what did it cost", since the requested model is empty
19
+ * by definition there — paired with the tier the runner REQUESTED (the
20
+ * streaming summary's audit record that the account default was never
21
+ * left in control). Requested-vs-billed divergence is a platform alarm
22
+ * (`stigmer.billing.service_tier.mismatch`), not a per-row UI concern.
23
+ *
24
+ * Shows an empty state when no usage data is available.
17
25
  */
18
26
  export function UsageTab({ executions }: UsageTabProps) {
19
27
  const usage = useSessionUsage(executions);
@@ -28,5 +36,89 @@ export function UsageTab({ executions }: UsageTabProps) {
28
36
  );
29
37
  }
30
38
 
31
- return <UsageWidget executions={executions} />;
39
+ return (
40
+ <div className="stg:flex stg:flex-col stg:gap-4">
41
+ <UsageWidget executions={executions} />
42
+ {usage.executionBreakdown.length > 0 && (
43
+ <ExecutionModelList
44
+ entries={usage.executionBreakdown}
45
+ executions={executions}
46
+ />
47
+ )}
48
+ </div>
49
+ );
50
+ }
51
+
52
+ /**
53
+ * Per-execution model provenance rows, in the report's chronological
54
+ * order: `#N resolved-model [tier requested] [Estimated] $cost`.
55
+ */
56
+ function ExecutionModelList({
57
+ entries,
58
+ executions,
59
+ }: {
60
+ readonly entries: readonly ExecutionUsageEntry[];
61
+ readonly executions: readonly AgentExecution[];
62
+ }) {
63
+ return (
64
+ <div
65
+ className="stg:flex stg:flex-col stg:gap-1"
66
+ role="list"
67
+ aria-label="Per-execution model and tier"
68
+ >
69
+ <div className="stg:text-xs stg:font-medium stg:text-foreground">
70
+ Models per run
71
+ </div>
72
+ {entries.map((entry, index) => {
73
+ const requestedTier = requestedTierLabel(executions, entry.executionId);
74
+ return (
75
+ <div
76
+ key={entry.executionId}
77
+ className="stg:flex stg:items-baseline stg:justify-between stg:gap-2 stg:text-xs stg:text-muted-foreground"
78
+ role="listitem"
79
+ >
80
+ <span className="stg:truncate">
81
+ <span className="stg:tabular-nums">#{index + 1}</span>{" "}
82
+ {entry.resolvedModel || "—"}
83
+ {requestedTier && (
84
+ <span className="stg:ml-1 stg:rounded stg:bg-muted stg:px-1 stg:py-0.5 stg:text-[10px] stg:font-medium stg:leading-none">
85
+ {requestedTier} requested
86
+ </span>
87
+ )}
88
+ {entry.isEstimated && (
89
+ <span className="stg:ml-1 stg:rounded stg:bg-muted stg:px-1 stg:py-0.5 stg:text-[10px] stg:font-medium stg:leading-none">
90
+ Estimated
91
+ </span>
92
+ )}
93
+ </span>
94
+ <span className="stg:shrink-0 stg:tabular-nums">
95
+ {formatCost(entry.billableCostUsd)}
96
+ </span>
97
+ </div>
98
+ );
99
+ })}
100
+ </div>
101
+ );
102
+ }
103
+
104
+ /**
105
+ * The tier the runner requested for one execution, from its streaming
106
+ * usage summary — present once the runner has translated the execution
107
+ * config, absent for executions that predate the tier attribute. Never
108
+ * "unspecified": the runner records the RESOLVED tier (#357's audit
109
+ * contract).
110
+ */
111
+ function requestedTierLabel(
112
+ executions: readonly AgentExecution[],
113
+ executionId: string,
114
+ ): string | null {
115
+ const match = executions.find((e) => e.metadata?.id === executionId);
116
+ switch (match?.status?.streamingUsage?.requestedServiceTier) {
117
+ case ServiceTier.FAST:
118
+ return "fast";
119
+ case ServiceTier.STANDARD:
120
+ return "standard";
121
+ default:
122
+ return null;
123
+ }
32
124
  }
@@ -58,6 +58,7 @@ export type { UseSessionFileChangesReturn } from "./useSessionFileChanges.js";
58
58
 
59
59
  export { useSessionUsage } from "./useSessionUsage.js";
60
60
  export type {
61
+ ExecutionUsageEntry,
61
62
  ModelCostEntry,
62
63
  UseSessionUsageReturn,
63
64
  } from "./useSessionUsage.js";
@@ -41,6 +41,25 @@ export interface ModelCostEntry {
41
41
  readonly callCount: number;
42
42
  }
43
43
 
44
+ /**
45
+ * Per-execution model provenance from billing records (stigmer/stigmer#362).
46
+ */
47
+ export interface ExecutionUsageEntry {
48
+ /** Execution identifier (`metadata.id`). */
49
+ readonly executionId: string;
50
+ /**
51
+ * Billing-resolved primary model — what the provider actually served.
52
+ * For a Cursor Auto execution this is the after-the-fact answer to
53
+ * "which model did Auto pick", which the requested model (empty by
54
+ * definition there) can never give.
55
+ */
56
+ readonly resolvedModel: string;
57
+ /** Billable cost in USD for this execution. */
58
+ readonly billableCostUsd: number;
59
+ /** `true` while this execution's records are still provisional. */
60
+ readonly isEstimated: boolean;
61
+ }
62
+
44
63
  /** Return value of {@link useSessionUsage}. */
45
64
  export interface UseSessionUsageReturn {
46
65
  /** Aggregate estimated cost in USD across all models. */
@@ -59,6 +78,13 @@ export interface UseSessionUsageReturn {
59
78
  readonly llmCallCount: number;
60
79
  /** Per-model cost and token breakdown. */
61
80
  readonly modelBreakdown: readonly ModelCostEntry[];
81
+ /**
82
+ * Per-execution resolved model + cost, chronological, from billing
83
+ * records (#362). Empty until the first authoritative record lands —
84
+ * the streaming fallback deliberately contributes none, because the
85
+ * runner only knows what it REQUESTED, never what the provider served.
86
+ */
87
+ readonly executionBreakdown: readonly ExecutionUsageEntry[];
62
88
  /** Model with the highest usage in this session. */
63
89
  readonly primaryModel: string;
64
90
  /** Provider of the primary model. */
@@ -82,6 +108,7 @@ const EMPTY: UseSessionUsageReturn = {
82
108
  cacheCreationTokens: 0,
83
109
  llmCallCount: 0,
84
110
  modelBreakdown: [],
111
+ executionBreakdown: [],
85
112
  primaryModel: "",
86
113
  primaryProvider: "",
87
114
  hasUsage: false,
@@ -122,6 +149,12 @@ function mapReport(report: GetSessionUsageReportOutput): UseSessionUsageReturn {
122
149
  cacheCreationTokens: Number(agg.cacheCreationInputTokens),
123
150
  llmCallCount,
124
151
  modelBreakdown: report.modelBreakdown.map(mapModelUsage),
152
+ executionBreakdown: report.executions.map((e) => ({
153
+ executionId: e.executionId,
154
+ resolvedModel: e.primaryModel,
155
+ billableCostUsd: microsToUsd(e.billableCostMicros),
156
+ isEstimated: e.isEstimated,
157
+ })),
125
158
  primaryModel: agg.primaryModel,
126
159
  primaryProvider: agg.primaryProvider,
127
160
  hasUsage: llmCallCount > 0 || totalTokens > 0 || billableCost > 0,
@@ -169,6 +202,10 @@ function aggregateStreamingUsage(
169
202
  cacheReadTokens,
170
203
  cacheCreationTokens,
171
204
  llmCallCount: turnCount,
205
+ // No executionBreakdown here on purpose: the runner only knows the
206
+ // REQUESTED model; resolved-model rows exist only once billing
207
+ // records land (#362).
208
+ executionBreakdown: [],
172
209
  modelBreakdown: model
173
210
  ? [
174
211
  {
@@ -48,6 +48,7 @@ describe("useSettingsNavGroups", () => {
48
48
  verdicts = {
49
49
  can_manage_model_pricing: true,
50
50
  can_manage_cursor_accounts: true,
51
+ can_view_provider_standing: true,
51
52
  };
52
53
  render(<GroupsProbe />);
53
54
 
@@ -56,7 +57,7 @@ describe("useSettingsNavGroups", () => {
56
57
  `${BASE_LABELS},${PLATFORM_SETTINGS_NAV_GROUP.label}`,
57
58
  );
58
59
  expect(el.getAttribute("data-platform-items")).toBe(
59
- "Pricing Governance,Cursor Accounts",
60
+ "Pricing Governance,Cursor Accounts,Provider Standing",
60
61
  );
61
62
  });
62
63
 
@@ -78,6 +79,15 @@ describe("useSettingsNavGroups", () => {
78
79
  );
79
80
  });
80
81
 
82
+ it("filters per item: standing-only operator sees only Provider Standing", () => {
83
+ verdicts = { can_view_provider_standing: true };
84
+ render(<GroupsProbe />);
85
+
86
+ expect(screen.getByTestId("groups").getAttribute("data-platform-items")).toBe(
87
+ "Provider Standing",
88
+ );
89
+ });
90
+
81
91
  it("returns exactly the base groups when not authorized", () => {
82
92
  function IdentityProbe() {
83
93
  const groups = useSettingsNavGroups();
@@ -1,5 +1,6 @@
1
1
  import type { ComponentType } from "react";
2
2
  import {
3
+ Activity,
3
4
  AppWindow,
4
5
  BarChart3,
5
6
  Box,
@@ -123,5 +124,11 @@ export const PLATFORM_SETTINGS_NAV_GROUP: SettingsNavGroup = {
123
124
  icon: MousePointerClick,
124
125
  requiredPermission: "can_manage_cursor_accounts",
125
126
  },
127
+ {
128
+ href: "/settings/provider-standing",
129
+ label: "Provider Standing",
130
+ icon: Activity,
131
+ requiredPermission: "can_view_provider_standing",
132
+ },
126
133
  ],
127
134
  };
@@ -52,14 +52,21 @@ export function useSettingsNavGroups(): readonly SettingsNavGroup[] {
52
52
  "can_manage_cursor_accounts",
53
53
  { fail: "closed" },
54
54
  );
55
+ const providerStanding = useCheckPermission(
56
+ PLATFORM_RESOURCE,
57
+ "can_view_provider_standing",
58
+ { fail: "closed" },
59
+ );
55
60
 
56
61
  const pricingAllowed = pricing.allowed;
57
62
  const cursorAccountsAllowed = cursorAccounts.allowed;
63
+ const providerStandingAllowed = providerStanding.allowed;
58
64
 
59
65
  return useMemo(() => {
60
66
  const verdicts: Record<string, boolean> = {
61
67
  can_manage_model_pricing: pricingAllowed,
62
68
  can_manage_cursor_accounts: cursorAccountsAllowed,
69
+ can_view_provider_standing: providerStandingAllowed,
63
70
  };
64
71
 
65
72
  const visibleItems = PLATFORM_SETTINGS_NAV_GROUP.items.filter(
@@ -77,5 +84,5 @@ export function useSettingsNavGroups(): readonly SettingsNavGroup[] {
77
84
  ...SETTINGS_NAV_GROUPS,
78
85
  { ...PLATFORM_SETTINGS_NAV_GROUP, items: visibleItems },
79
86
  ];
80
- }, [pricingAllowed, cursorAccountsAllowed]);
87
+ }, [pricingAllowed, cursorAccountsAllowed, providerStandingAllowed]);
81
88
  }
@@ -2,6 +2,8 @@
2
2
 
3
3
  import { useCallback, useId, useMemo, useRef, useState, type FormEvent } from "react";
4
4
  import { cn } from "@stigmer/theme";
5
+ import { DialogShell } from "../internal/DialogShell.js";
6
+ import { UNSTYLED_LIST } from "../internal/element-resets.js";
5
7
  import {
6
8
  MAX_ALLOWED_ORIGINS,
7
9
  StigmerError,
@@ -137,8 +139,6 @@ export function ShareAgentDialog({
137
139
  onSharingChanged,
138
140
  modal = true,
139
141
  }: ShareAgentDialogProps) {
140
- const dialogRef = useRef<HTMLDialogElement>(null);
141
-
142
142
  // Instance-scoped title id (oss#593): a reusable component must not
143
143
  // hardcode DOM ids — hosts legitimately mount this dialog more than once
144
144
  // per page (e.g. zone-cached detail pages), and duplicate ids break the
@@ -146,36 +146,15 @@ export function ShareAgentDialog({
146
146
  const titleId = useId();
147
147
 
148
148
  const handleClose = useCallback(() => {
149
- dialogRef.current?.close();
150
149
  onOpenChange(false);
151
150
  }, [onOpenChange]);
152
151
 
153
- // Sync native dialog open state (matches the SDK dialog convention).
154
- // Non-modal hosts pass `open` as a plain attribute instead — the dialog
155
- // renders in-flow with no top layer to manage.
156
- const prevOpenRef = useRef(false);
157
- if (modal && open !== prevOpenRef.current) {
158
- prevOpenRef.current = open;
159
- if (open) {
160
- requestAnimationFrame(() => {
161
- if (dialogRef.current && !dialogRef.current.open) {
162
- dialogRef.current.showModal();
163
- }
164
- });
165
- } else if (dialogRef.current?.open) {
166
- dialogRef.current.close();
167
- }
168
- }
169
-
170
152
  return (
171
- <dialog
172
- ref={dialogRef}
173
- open={modal ? undefined : open}
174
- onClose={handleClose}
175
- className={cn(
176
- "stg:w-full stg:max-w-lg stg:rounded-xl stg:border stg:border-border stg:bg-popover stg:p-0 stg:shadow-xl",
177
- modal ? "stg:fixed stg:inset-0 stg:m-auto stg:backdrop:bg-backdrop" : "stg:relative",
178
- )}
153
+ <DialogShell
154
+ open={open}
155
+ onOpenChange={onOpenChange}
156
+ modal={modal}
157
+ width="lg"
179
158
  aria-labelledby={titleId}
180
159
  >
181
160
  {/* Body mounts only while open so its draft state resets per
@@ -191,7 +170,7 @@ export function ShareAgentDialog({
191
170
  titleId={titleId}
192
171
  />
193
172
  )}
194
- </dialog>
173
+ </DialogShell>
195
174
  );
196
175
  }
197
176
 
@@ -1338,7 +1317,7 @@ function OriginsEditor({
1338
1317
  </p>
1339
1318
 
1340
1319
  {draft.allowedOrigins.length > 0 && (
1341
- <ul className="stg:mt-2 stg:flex stg:flex-col stg:divide-y stg:divide-border stg:rounded-md stg:border stg:border-border">
1320
+ <ul className={cn(UNSTYLED_LIST, "stg:mt-2 stg:flex stg:flex-col stg:divide-y stg:divide-border stg:rounded-md stg:border stg:border-border")}>
1342
1321
  {draft.allowedOrigins.map((origin) => (
1343
1322
  <li
1344
1323
  key={origin}
@@ -15,6 +15,7 @@ import type { RecentActivityEntry, RecentActivityGroup } from "../activity/types
15
15
  import { groupRecentActivityByTime } from "../activity/group-activity.js";
16
16
  import { formatRelativeTime } from "../activity/format-relative-time.js";
17
17
  import { recentActivityStatusBadge } from "../activity/entry-status-badge.js";
18
+ import { UNSTYLED_LIST } from "../internal/element-resets.js";
18
19
  import { ScrollArea } from "../internal/scroll-area.js";
19
20
  import {
20
21
  Tooltip,
@@ -313,7 +314,7 @@ function ActivityGroupList({
313
314
  <p className="stg:text-sidebar-muted-foreground stg:mb-1 stg:px-2 stg:text-[10px] stg:font-medium stg:tracking-wider stg:uppercase">
314
315
  {group.label}
315
316
  </p>
316
- <ul className="stg:space-y-0.5" role="list">
317
+ <ul className={`${UNSTYLED_LIST} stg:space-y-0.5`} role="list">
317
318
  {group.entries.map((entry) => (
318
319
  <ActivityEntry
319
320
  key={entry.id}
@@ -1,7 +1,8 @@
1
1
  "use client";
2
2
 
3
- import { useCallback, useEffect, useRef } from "react";
3
+ import { useCallback } from "react";
4
4
  import { cn } from "@stigmer/theme";
5
+ import { DialogShell } from "../internal/DialogShell.js";
5
6
  import { useSkillDiff } from "./useSkillDiff.js";
6
7
  import { MultiFileDiffView } from "../version-history/MultiFileDiffView.js";
7
8
  import { ErrorMessage } from "../error/ErrorMessage.js";
@@ -57,31 +58,9 @@ export interface SkillDiffDialogProps {
57
58
  * ```
58
59
  */
59
60
  export function SkillDiffDialog({ state, onClose }: SkillDiffDialogProps) {
60
- const dialogRef = useRef<HTMLDialogElement>(null);
61
-
62
- useEffect(() => {
63
- const dialog = dialogRef.current;
64
- if (!dialog) return;
65
- if (state && !dialog.open) {
66
- dialog.showModal();
67
- } else if (!state && dialog.open) {
68
- dialog.close();
69
- }
70
- }, [state]);
71
-
72
- const handleDialogCancel = useCallback(
73
- (e: React.SyntheticEvent) => {
74
- e.preventDefault();
75
- onClose();
76
- },
77
- [onClose],
78
- );
79
-
80
- const handleBackdropClick = useCallback(
81
- (e: React.MouseEvent<HTMLDialogElement>) => {
82
- if (e.target === e.currentTarget) {
83
- onClose();
84
- }
61
+ const handleOpenChange = useCallback(
62
+ (open: boolean) => {
63
+ if (!open) onClose();
85
64
  },
86
65
  [onClose],
87
66
  );
@@ -94,15 +73,13 @@ export function SkillDiffDialog({ state, onClose }: SkillDiffDialogProps) {
94
73
  if (!state) return null;
95
74
 
96
75
  return (
97
- <dialog
98
- ref={dialogRef}
99
- onCancel={handleDialogCancel}
100
- onClick={handleBackdropClick}
101
- className={cn(
102
- "stg:fixed stg:inset-0 stg:z-50 stg:m-auto stg:h-[85vh] stg:w-full stg:max-w-4xl stg:rounded-lg stg:border stg:border-border stg:bg-popover stg:p-0 stg:text-popover-foreground stg:shadow-lg",
103
- "stg:backdrop:bg-backdrop",
104
- "stg:open:animate-in stg:open:fade-in-0 stg:open:zoom-in-95",
105
- )}
76
+ <DialogShell
77
+ open
78
+ onOpenChange={handleOpenChange}
79
+ width="4xl"
80
+ dismissOnBackdrop
81
+ className="stg:h-[85vh]"
82
+ aria-label="Skill version diff"
106
83
  >
107
84
  <div className="stg:flex stg:h-full stg:flex-col">
108
85
  {/* Header */}
@@ -142,7 +119,7 @@ export function SkillDiffDialog({ state, onClose }: SkillDiffDialogProps) {
142
119
  ) : null}
143
120
  </div>
144
121
  </div>
145
- </dialog>
122
+ </DialogShell>
146
123
  );
147
124
  }
148
125
 
@@ -3,6 +3,7 @@
3
3
  import { useMemo, useState } from "react";
4
4
  import Markdown from "react-markdown";
5
5
  import { cn } from "@stigmer/theme";
6
+ import { UNSTYLED_LIST } from "../internal/element-resets.js";
6
7
  import { MARKDOWN_COMPONENTS, REMARK_PLUGINS, stripFrontmatter } from "../internal/markdown-components.js";
7
8
  import { buildFileTree, FileTreeNode } from "../internal/file-tree/index.js";
8
9
  import { useSkillArtifact } from "./useSkillArtifact.js";
@@ -132,7 +133,7 @@ export function SkillFileBrowser({
132
133
  className="stg:border-b stg:border-border stg:md:border-b-0 stg:md:border-r stg:overflow-y-auto"
133
134
  aria-label="Skill package file tree"
134
135
  >
135
- <ul className="stg:py-1" role="tree">
136
+ <ul className={cn(UNSTYLED_LIST, "stg:py-1")} role="tree">
136
137
  {treeNodes.map((node) => (
137
138
  <FileTreeNode
138
139
  key={node.path}
@@ -2,7 +2,7 @@ import { describe, it, expect, vi, afterEach } from "vitest";
2
2
  import { render, screen, fireEvent } from "@testing-library/react";
3
3
  import type { ReactNode } from "react";
4
4
  import { zipSync, strToU8 } from "fflate";
5
- import type { Stigmer } from "@stigmer/sdk";
5
+ import { StigmerError, type Stigmer } from "@stigmer/sdk";
6
6
  import { StigmerContext } from "../../context";
7
7
  import { SkillFileBrowser } from "../SkillFileBrowser";
8
8
 
@@ -12,14 +12,22 @@ function wrapperFor(stigmer: Stigmer) {
12
12
  );
13
13
  }
14
14
 
15
+ /** Connect's Unimplemented code — what a pre-transfer-lane server answers. */
16
+ const CODE_UNIMPLEMENTED = 12;
17
+
15
18
  /**
16
19
  * Builds a real ZIP (via fflate, the same library the unpacker uses) and a
17
20
  * Stigmer client whose `skill.getArtifact` serves it — so tests exercise the
18
21
  * genuine fetch → unzip → browse path instead of stubbing the unpacker.
22
+ * The download-URL mint answers Unimplemented (a pre-transfer-lane server),
23
+ * pinning that the browser degrades to the unary lane it always used.
19
24
  */
20
25
  function makeStigmerServing(files: Record<string, Uint8Array>) {
21
26
  const getArtifact = vi.fn().mockResolvedValue({ artifact: zipSync(files) });
22
- return { skill: { getArtifact } } as unknown as Stigmer;
27
+ const getArtifactDownloadUrl = vi
28
+ .fn()
29
+ .mockRejectedValue(new StigmerError("unknown", "unimplemented", CODE_UNIMPLEMENTED));
30
+ return { skill: { getArtifact, getArtifactDownloadUrl } } as unknown as Stigmer;
23
31
  }
24
32
 
25
33
  function renderBrowser(stigmer: Stigmer) {
@@ -0,0 +1,90 @@
1
+ // Pins for the artifact fetch lane selection (stigmer#701): URL-first via
2
+ // getArtifactDownloadUrl, with the two deliberate browser degrade arms —
3
+ // Unimplemented mint (pre-lane server) and a failed URL fetch (the shape a
4
+ // missing bucket CORS policy takes in a browser).
5
+ import { describe, expect, it, vi } from "vitest";
6
+ import { strToU8, zipSync } from "fflate";
7
+ import { StigmerError, type Stigmer } from "@stigmer/sdk";
8
+ import { fetchAndUnpackArtifact } from "../internal/fetchAndUnpackArtifact.js";
9
+
10
+ const CODE_UNIMPLEMENTED = 12;
11
+ const ZIP = zipSync({ "SKILL.md": strToU8("# hi") });
12
+
13
+ function stigmerWith(overrides: {
14
+ mint?: ReturnType<typeof vi.fn>;
15
+ unary?: ReturnType<typeof vi.fn>;
16
+ fetch?: unknown;
17
+ }): Stigmer {
18
+ return {
19
+ skill: {
20
+ getArtifactDownloadUrl: overrides.mint,
21
+ getArtifact: overrides.unary,
22
+ },
23
+ fetch: overrides.fetch,
24
+ } as unknown as Stigmer;
25
+ }
26
+
27
+ describe("fetchAndUnpackArtifact lane selection", () => {
28
+ it("fetches via the minted download URL, never the unary lane", async () => {
29
+ const mint = vi.fn().mockResolvedValue({ url: "https://r2.example/skills/get" });
30
+ const unary = vi.fn();
31
+ const fetchImpl = vi.fn(async () => new Response(new Uint8Array(ZIP).buffer, { status: 200 }));
32
+
33
+ const result = await fetchAndUnpackArtifact(
34
+ stigmerWith({ mint, unary, fetch: fetchImpl }),
35
+ "skills/org/skill/hash.zip",
36
+ );
37
+
38
+ expect(fetchImpl).toHaveBeenCalledWith("https://r2.example/skills/get");
39
+ expect(unary).not.toHaveBeenCalled();
40
+ expect(result.contentMap.get("SKILL.md")).toBe("# hi");
41
+ });
42
+
43
+ it("degrades to the unary lane when the mint answers Unimplemented (pre-lane server)", async () => {
44
+ const mint = vi
45
+ .fn()
46
+ .mockRejectedValue(new StigmerError("unknown", "unimplemented", CODE_UNIMPLEMENTED));
47
+ const unary = vi.fn().mockResolvedValue({ artifact: ZIP });
48
+
49
+ const result = await fetchAndUnpackArtifact(
50
+ stigmerWith({ mint, unary }),
51
+ "skills/org/skill/hash.zip",
52
+ );
53
+
54
+ expect(unary).toHaveBeenCalledTimes(1);
55
+ expect(result.contentMap.get("SKILL.md")).toBe("# hi");
56
+ });
57
+
58
+ it("degrades to the unary lane when the URL fetch itself fails (browser CORS shape), warning once", async () => {
59
+ const mint = vi.fn().mockResolvedValue({ url: "https://r2.example/skills/get" });
60
+ const unary = vi.fn().mockResolvedValue({ artifact: ZIP });
61
+ const fetchImpl = vi.fn(async () => {
62
+ throw new TypeError("Failed to fetch");
63
+ });
64
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
65
+
66
+ try {
67
+ const result = await fetchAndUnpackArtifact(
68
+ stigmerWith({ mint, unary, fetch: fetchImpl }),
69
+ "skills/org/skill/hash.zip",
70
+ );
71
+ expect(unary).toHaveBeenCalledTimes(1);
72
+ expect(warn).toHaveBeenCalledTimes(1);
73
+ expect(result.contentMap.get("SKILL.md")).toBe("# hi");
74
+ } finally {
75
+ warn.mockRestore();
76
+ }
77
+ });
78
+
79
+ it("propagates a non-Unimplemented mint failure — a real error must not be masked", async () => {
80
+ const mint = vi
81
+ .fn()
82
+ .mockRejectedValue(new StigmerError("not-found", "no such artifact", 5));
83
+ const unary = vi.fn();
84
+
85
+ await expect(
86
+ fetchAndUnpackArtifact(stigmerWith({ mint, unary }), "skills/org/skill/hash.zip"),
87
+ ).rejects.toThrow(/no such artifact/);
88
+ expect(unary).not.toHaveBeenCalled();
89
+ });
90
+ });
@@ -0,0 +1,69 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { renderHook, act } from "@testing-library/react";
3
+ import { zipSync, strToU8 } from "fflate";
4
+ import { useSkillUpload } from "../useSkillUpload";
5
+
6
+ const SKILL_MD = "---\nname: my-skill\ndescription: A test skill\n---\n# My Skill\n";
7
+
8
+ /** Build a real ZIP (fflate, the same library the hook unpacks with) as a File. */
9
+ function zipFile(files: Record<string, Uint8Array>): File {
10
+ return new File([zipSync(files)], "skill.zip", { type: "application/zip" });
11
+ }
12
+
13
+ async function process(files: Record<string, Uint8Array>) {
14
+ const { result } = renderHook(() => useSkillUpload());
15
+ await act(() => result.current.processFile(zipFile(files)));
16
+ return result;
17
+ }
18
+
19
+ describe("useSkillUpload", () => {
20
+ it("accepts a root SKILL.md and produces a preview", async () => {
21
+ const result = await process({
22
+ "SKILL.md": strToU8(SKILL_MD),
23
+ "references/schema.md": strToU8("# Schema"),
24
+ });
25
+
26
+ expect(result.current.validationError).toBeNull();
27
+ expect(result.current.preview?.name).toBe("my-skill");
28
+ expect(result.current.preview?.description).toBe("A test skill");
29
+ expect(result.current.artifact).not.toBeNull();
30
+ });
31
+
32
+ // The layout contract is root-only on both editions (DD-018, #452). The
33
+ // preview exists to catch the "zipped the folder instead of its contents"
34
+ // mistake BEFORE upload — accepting nested here and failing at push is the
35
+ // exact confusion issue #684 pins.
36
+ it("rejects a nested-only SKILL.md with the zip-the-contents hint", async () => {
37
+ const result = await process({
38
+ "my-skill/SKILL.md": strToU8(SKILL_MD),
39
+ "my-skill/references/schema.md": strToU8("# Schema"),
40
+ });
41
+
42
+ expect(result.current.preview).toBeNull();
43
+ expect(result.current.artifact).toBeNull();
44
+ expect(result.current.validationError).toBe(
45
+ "Found my-skill/SKILL.md — SKILL.md must be at the archive root. " +
46
+ "Zip the skill folder's contents, not the folder itself.",
47
+ );
48
+ });
49
+
50
+ it("detects a deeply nested SKILL.md for the hint (any depth, server parity)", async () => {
51
+ const result = await process({
52
+ "wrapper/my-skill/SKILL.md": strToU8(SKILL_MD),
53
+ });
54
+
55
+ expect(result.current.preview).toBeNull();
56
+ expect(result.current.validationError).toContain("Found wrapper/my-skill/SKILL.md");
57
+ });
58
+
59
+ it("rejects an archive with no SKILL.md anywhere with the plain root-level message", async () => {
60
+ const result = await process({
61
+ "README.md": strToU8("# Not a skill"),
62
+ });
63
+
64
+ expect(result.current.preview).toBeNull();
65
+ expect(result.current.validationError).toBe(
66
+ "ZIP must contain a SKILL.md file at the root level",
67
+ );
68
+ });
69
+ });