@stigmer/react 3.12.4 → 3.12.6

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 (369) hide show
  1. package/agent/AgentDetailView.js +2 -2
  2. package/agent/AgentDetailView.js.map +1 -1
  3. package/agent/index.d.ts +0 -1
  4. package/agent/index.d.ts.map +1 -1
  5. package/agent/index.js +0 -1
  6. package/agent/index.js.map +1 -1
  7. package/agent/useUpdateAgent.d.ts +3 -3
  8. package/agent/useUpdateAgent.js +3 -3
  9. package/agent-instance/AgentInstanceDetailPanel.d.ts.map +1 -1
  10. package/agent-instance/AgentInstanceDetailPanel.js +5 -7
  11. package/agent-instance/AgentInstanceDetailPanel.js.map +1 -1
  12. package/agent-instance/useUpdateAgentInstance.d.ts +1 -1
  13. package/agent-instance/useUpdateAgentInstance.js +1 -1
  14. package/attachment/AttachmentChipList.js +16 -6
  15. package/attachment/AttachmentChipList.js.map +1 -1
  16. package/attachment/index.d.ts +1 -1
  17. package/attachment/index.d.ts.map +1 -1
  18. package/attachment/index.js.map +1 -1
  19. package/attachment/useAttachments.d.ts +51 -8
  20. package/attachment/useAttachments.d.ts.map +1 -1
  21. package/attachment/useAttachments.js +74 -3
  22. package/attachment/useAttachments.js.map +1 -1
  23. package/channel/AgentChannelsPanel.d.ts.map +1 -1
  24. package/channel/AgentChannelsPanel.js +10 -5
  25. package/channel/AgentChannelsPanel.js.map +1 -1
  26. package/channel/ChannelRunConfigDialog.d.ts +51 -0
  27. package/channel/ChannelRunConfigDialog.d.ts.map +1 -0
  28. package/channel/ChannelRunConfigDialog.js +121 -0
  29. package/channel/ChannelRunConfigDialog.js.map +1 -0
  30. package/channel/index.d.ts +2 -0
  31. package/channel/index.d.ts.map +1 -1
  32. package/channel/index.js +1 -0
  33. package/channel/index.js.map +1 -1
  34. package/channel/useSaveAgentChannel.d.ts.map +1 -1
  35. package/channel/useSaveAgentChannel.js +6 -3
  36. package/channel/useSaveAgentChannel.js.map +1 -1
  37. package/channel-app/ChannelAppDetailPanel.js +9 -9
  38. package/channel-app/ChannelAppDetailPanel.js.map +1 -1
  39. package/composer/ComposerToolbar.d.ts +6 -1
  40. package/composer/ComposerToolbar.d.ts.map +1 -1
  41. package/composer/ComposerToolbar.js +2 -2
  42. package/composer/ComposerToolbar.js.map +1 -1
  43. package/composer/SessionComposer.d.ts +9 -0
  44. package/composer/SessionComposer.d.ts.map +1 -1
  45. package/composer/SessionComposer.js +39 -13
  46. package/composer/SessionComposer.js.map +1 -1
  47. package/conversation/ConversationComposer.d.ts +19 -3
  48. package/conversation/ConversationComposer.d.ts.map +1 -1
  49. package/conversation/ConversationComposer.js +4 -4
  50. package/conversation/ConversationComposer.js.map +1 -1
  51. package/conversation/ConversationTemplatePickerDialog.d.ts +63 -0
  52. package/conversation/ConversationTemplatePickerDialog.d.ts.map +1 -0
  53. package/conversation/ConversationTemplatePickerDialog.js +151 -0
  54. package/conversation/ConversationTemplatePickerDialog.js.map +1 -0
  55. package/conversation/ConversationsWorkbench.d.ts.map +1 -1
  56. package/conversation/ConversationsWorkbench.js +16 -5
  57. package/conversation/ConversationsWorkbench.js.map +1 -1
  58. package/conversation/index.d.ts +3 -1
  59. package/conversation/index.d.ts.map +1 -1
  60. package/conversation/index.js +1 -0
  61. package/conversation/index.js.map +1 -1
  62. package/conversation/useConversationParticipation.d.ts +41 -4
  63. package/conversation/useConversationParticipation.d.ts.map +1 -1
  64. package/conversation/useConversationParticipation.js +13 -2
  65. package/conversation/useConversationParticipation.js.map +1 -1
  66. package/cursor-accounts/CursorAccountsConsole.d.ts.map +1 -1
  67. package/cursor-accounts/CursorAccountsConsole.js +12 -3
  68. package/cursor-accounts/CursorAccountsConsole.js.map +1 -1
  69. package/cursor-accounts/cursor-account-coverage.d.ts +30 -1
  70. package/cursor-accounts/cursor-account-coverage.d.ts.map +1 -1
  71. package/cursor-accounts/cursor-account-coverage.js +21 -0
  72. package/cursor-accounts/cursor-account-coverage.js.map +1 -1
  73. package/execution/useCreateAgentExecution.d.ts +15 -0
  74. package/execution/useCreateAgentExecution.d.ts.map +1 -1
  75. package/execution/useCreateAgentExecution.js +5 -0
  76. package/execution/useCreateAgentExecution.js.map +1 -1
  77. package/identity-account/AccountPreferencesPanel.d.ts +36 -0
  78. package/identity-account/AccountPreferencesPanel.d.ts.map +1 -0
  79. package/identity-account/AccountPreferencesPanel.js +202 -0
  80. package/identity-account/AccountPreferencesPanel.js.map +1 -0
  81. package/identity-account/index.d.ts +8 -0
  82. package/identity-account/index.d.ts.map +1 -1
  83. package/identity-account/index.js +4 -0
  84. package/identity-account/index.js.map +1 -1
  85. package/identity-account/useAccountExecutionDefaults.d.ts +36 -0
  86. package/identity-account/useAccountExecutionDefaults.d.ts.map +1 -0
  87. package/identity-account/useAccountExecutionDefaults.js +46 -0
  88. package/identity-account/useAccountExecutionDefaults.js.map +1 -0
  89. package/identity-account/useMyIdentityAccount.d.ts +55 -0
  90. package/identity-account/useMyIdentityAccount.d.ts.map +1 -0
  91. package/identity-account/useMyIdentityAccount.js +37 -0
  92. package/identity-account/useMyIdentityAccount.js.map +1 -0
  93. package/identity-account/useUpdateIdentityAccount.d.ts +42 -0
  94. package/identity-account/useUpdateIdentityAccount.d.ts.map +1 -0
  95. package/identity-account/useUpdateIdentityAccount.js +53 -0
  96. package/identity-account/useUpdateIdentityAccount.js.map +1 -0
  97. package/identity-provider/IdentityProviderDetailPanel.d.ts.map +1 -1
  98. package/identity-provider/IdentityProviderDetailPanel.js +16 -15
  99. package/identity-provider/IdentityProviderDetailPanel.js.map +1 -1
  100. package/index.d.ts +15 -13
  101. package/index.d.ts.map +1 -1
  102. package/index.js +11 -8
  103. package/index.js.map +1 -1
  104. package/internal/StandingContextField.d.ts +37 -0
  105. package/internal/StandingContextField.d.ts.map +1 -0
  106. package/internal/StandingContextField.js +24 -0
  107. package/internal/StandingContextField.js.map +1 -0
  108. package/library/InstanceVisibilitySelector.d.ts.map +1 -1
  109. package/library/InstanceVisibilitySelector.js +9 -2
  110. package/library/InstanceVisibilitySelector.js.map +1 -1
  111. package/library/ResourceVisibilityControl.d.ts +13 -3
  112. package/library/ResourceVisibilityControl.d.ts.map +1 -1
  113. package/library/ResourceVisibilityControl.js +33 -5
  114. package/library/ResourceVisibilityControl.js.map +1 -1
  115. package/library/VisibilityOptionRow.d.ts +6 -0
  116. package/library/VisibilityOptionRow.d.ts.map +1 -1
  117. package/library/VisibilityOptionRow.js +11 -1
  118. package/library/VisibilityOptionRow.js.map +1 -1
  119. package/library/VisibilitySelector.d.ts.map +1 -1
  120. package/library/VisibilitySelector.js +14 -2
  121. package/library/VisibilitySelector.js.map +1 -1
  122. package/library/index.d.ts +4 -2
  123. package/library/index.d.ts.map +1 -1
  124. package/library/index.js +2 -1
  125. package/library/index.js.map +1 -1
  126. package/library/useCanSetPublicVisibility.d.ts +30 -0
  127. package/library/useCanSetPublicVisibility.d.ts.map +1 -0
  128. package/library/useCanSetPublicVisibility.js +41 -0
  129. package/library/useCanSetPublicVisibility.js.map +1 -0
  130. package/library/visibilityLevels.d.ts +32 -1
  131. package/library/visibilityLevels.d.ts.map +1 -1
  132. package/library/visibilityLevels.js +34 -14
  133. package/library/visibilityLevels.js.map +1 -1
  134. package/mcp-server/McpServerDetailView.js +2 -2
  135. package/mcp-server/McpServerDetailView.js.map +1 -1
  136. package/mcp-server/index.d.ts +0 -1
  137. package/mcp-server/index.d.ts.map +1 -1
  138. package/mcp-server/index.js +0 -1
  139. package/mcp-server/index.js.map +1 -1
  140. package/mcp-server/internal/definitionDrift.d.ts +14 -12
  141. package/mcp-server/internal/definitionDrift.d.ts.map +1 -1
  142. package/mcp-server/internal/definitionDrift.js +22 -19
  143. package/mcp-server/internal/definitionDrift.js.map +1 -1
  144. package/mcp-server/useMcpServerConnect.d.ts +8 -5
  145. package/mcp-server/useMcpServerConnect.d.ts.map +1 -1
  146. package/mcp-server/useMcpServerConnect.js +2 -1
  147. package/mcp-server/useMcpServerConnect.js.map +1 -1
  148. package/mcp-server/useMcpServerOAuthConnect.d.ts.map +1 -1
  149. package/mcp-server/useMcpServerOAuthConnect.js +7 -2
  150. package/mcp-server/useMcpServerOAuthConnect.js.map +1 -1
  151. package/mcp-server/useUpdateMcpServer.d.ts +3 -3
  152. package/mcp-server/useUpdateMcpServer.js +3 -3
  153. package/models/ModelSelector.d.ts +33 -1
  154. package/models/ModelSelector.d.ts.map +1 -1
  155. package/models/ModelSelector.js +37 -4
  156. package/models/ModelSelector.js.map +1 -1
  157. package/models/index.d.ts +2 -0
  158. package/models/index.d.ts.map +1 -1
  159. package/models/index.js +1 -0
  160. package/models/index.js.map +1 -1
  161. package/models/registry.d.ts +16 -0
  162. package/models/registry.d.ts.map +1 -1
  163. package/models/registry.js +13 -0
  164. package/models/registry.js.map +1 -1
  165. package/models/thinking-mode.d.ts +27 -0
  166. package/models/thinking-mode.d.ts.map +1 -0
  167. package/models/thinking-mode.js +32 -0
  168. package/models/thinking-mode.js.map +1 -0
  169. package/oauth-app/CreateOAuthAppForm.d.ts +2 -2
  170. package/oauth-app/CreateOAuthAppForm.d.ts.map +1 -1
  171. package/oauth-app/CreateOAuthAppForm.js +13 -4
  172. package/oauth-app/CreateOAuthAppForm.js.map +1 -1
  173. package/oauth-app/OAuthAppDetailPanel.d.ts.map +1 -1
  174. package/oauth-app/OAuthAppDetailPanel.js +50 -22
  175. package/oauth-app/OAuthAppDetailPanel.js.map +1 -1
  176. package/organization/OrgPreferencesPanel.d.ts +32 -0
  177. package/organization/OrgPreferencesPanel.d.ts.map +1 -0
  178. package/organization/OrgPreferencesPanel.js +90 -0
  179. package/organization/OrgPreferencesPanel.js.map +1 -0
  180. package/organization/OrgProfilePanel.d.ts.map +1 -1
  181. package/organization/OrgProfilePanel.js +5 -4
  182. package/organization/OrgProfilePanel.js.map +1 -1
  183. package/organization/index.d.ts +2 -0
  184. package/organization/index.d.ts.map +1 -1
  185. package/organization/index.js +1 -0
  186. package/organization/index.js.map +1 -1
  187. package/package.json +4 -4
  188. package/platform-client/PlatformClientDetailPanel.d.ts.map +1 -1
  189. package/platform-client/PlatformClientDetailPanel.js +12 -13
  190. package/platform-client/PlatformClientDetailPanel.js.map +1 -1
  191. package/schedule/ScheduleDetailView.d.ts.map +1 -1
  192. package/schedule/ScheduleDetailView.js +21 -10
  193. package/schedule/ScheduleDetailView.js.map +1 -1
  194. package/schedule/ScheduleForm.d.ts.map +1 -1
  195. package/schedule/ScheduleForm.js +13 -3
  196. package/schedule/ScheduleForm.js.map +1 -1
  197. package/session/NewSessionViewer.d.ts +10 -1
  198. package/session/NewSessionViewer.d.ts.map +1 -1
  199. package/session/NewSessionViewer.js +2 -1
  200. package/session/NewSessionViewer.js.map +1 -1
  201. package/session/run-config.d.ts +9 -0
  202. package/session/run-config.d.ts.map +1 -1
  203. package/session/run-config.js +5 -0
  204. package/session/run-config.js.map +1 -1
  205. package/session/useNewSessionFlow.d.ts +27 -1
  206. package/session/useNewSessionFlow.d.ts.map +1 -1
  207. package/session/useNewSessionFlow.js +51 -8
  208. package/session/useNewSessionFlow.js.map +1 -1
  209. package/session/useSessionConversation.d.ts +12 -1
  210. package/session/useSessionConversation.d.ts.map +1 -1
  211. package/session/useSessionConversation.js +15 -24
  212. package/session/useSessionConversation.js.map +1 -1
  213. package/session/useSessionPageFlow.d.ts.map +1 -1
  214. package/session/useSessionPageFlow.js +14 -10
  215. package/session/useSessionPageFlow.js.map +1 -1
  216. package/session/useUpdateSession.d.ts +18 -24
  217. package/session/useUpdateSession.d.ts.map +1 -1
  218. package/session/useUpdateSession.js +18 -24
  219. package/session/useUpdateSession.js.map +1 -1
  220. package/settings/AccountPreferencesSection.d.ts +3 -0
  221. package/settings/AccountPreferencesSection.d.ts.map +1 -0
  222. package/settings/AccountPreferencesSection.js +10 -0
  223. package/settings/AccountPreferencesSection.js.map +1 -0
  224. package/settings/OrgPreferencesSection.d.ts +3 -0
  225. package/settings/OrgPreferencesSection.d.ts.map +1 -0
  226. package/settings/OrgPreferencesSection.js +13 -0
  227. package/settings/OrgPreferencesSection.js.map +1 -0
  228. package/settings/index.d.ts +2 -0
  229. package/settings/index.d.ts.map +1 -1
  230. package/settings/index.js +2 -0
  231. package/settings/index.js.map +1 -1
  232. package/settings/settings-nav.d.ts.map +1 -1
  233. package/settings/settings-nav.js +17 -1
  234. package/settings/settings-nav.js.map +1 -1
  235. package/src/agent/AgentDetailView.tsx +2 -2
  236. package/src/agent/index.ts +0 -2
  237. package/src/agent/useUpdateAgent.ts +3 -3
  238. package/src/agent-instance/AgentInstanceDetailPanel.tsx +5 -7
  239. package/src/agent-instance/__tests__/AgentInstanceDetailPanel.test.tsx +75 -0
  240. package/src/agent-instance/useUpdateAgentInstance.ts +1 -1
  241. package/src/attachment/AttachmentChipList.tsx +19 -8
  242. package/src/attachment/__tests__/AttachmentChipList.test.tsx +12 -0
  243. package/src/attachment/__tests__/useAttachments.test.ts +293 -0
  244. package/src/attachment/index.ts +1 -0
  245. package/src/attachment/useAttachments.ts +143 -11
  246. package/src/channel/AgentChannelsPanel.tsx +26 -1
  247. package/src/channel/ChannelRunConfigDialog.tsx +351 -0
  248. package/src/channel/__tests__/ChannelRunConfigDialog.test.tsx +210 -0
  249. package/src/channel/index.ts +2 -0
  250. package/src/channel/useSaveAgentChannel.ts +6 -3
  251. package/src/channel-app/ChannelAppDetailPanel.tsx +9 -9
  252. package/src/channel-app/__tests__/channelAppWhatsApp.test.tsx +2 -0
  253. package/src/channel-app/__tests__/channelAppWipeSafety.test.tsx +87 -0
  254. package/src/composer/ComposerToolbar.tsx +9 -0
  255. package/src/composer/SessionComposer.tsx +59 -16
  256. package/src/composer/__tests__/SessionComposer-thinkingMode.test.tsx +176 -0
  257. package/src/conversation/ConversationComposer.tsx +38 -4
  258. package/src/conversation/ConversationTemplatePickerDialog.tsx +441 -0
  259. package/src/conversation/ConversationsWorkbench.tsx +40 -4
  260. package/src/conversation/__tests__/ConversationComposer.test.tsx +56 -1
  261. package/src/conversation/__tests__/ConversationTemplatePickerDialog.test.tsx +224 -0
  262. package/src/conversation/__tests__/useConversationParticipation.test.tsx +45 -4
  263. package/src/conversation/index.ts +4 -0
  264. package/src/conversation/useConversationParticipation.ts +58 -6
  265. package/src/cursor-accounts/CursorAccountsConsole.tsx +40 -5
  266. package/src/cursor-accounts/__tests__/CursorAccountsConsole.test.tsx +32 -0
  267. package/src/cursor-accounts/__tests__/cursor-account-coverage.test.ts +58 -1
  268. package/src/cursor-accounts/cursor-account-coverage.ts +55 -0
  269. package/src/execution/useCreateAgentExecution.ts +19 -0
  270. package/src/identity-account/AccountPreferencesPanel.tsx +532 -0
  271. package/src/identity-account/__tests__/AccountPreferencesPanel.test.tsx +267 -0
  272. package/src/identity-account/__tests__/useAccountExecutionDefaults.test.tsx +116 -0
  273. package/src/identity-account/__tests__/useMyIdentityAccount.test.tsx +121 -0
  274. package/src/identity-account/index.ts +11 -0
  275. package/src/identity-account/useAccountExecutionDefaults.ts +63 -0
  276. package/src/identity-account/useMyIdentityAccount.ts +75 -0
  277. package/src/identity-account/useUpdateIdentityAccount.ts +73 -0
  278. package/src/identity-provider/IdentityProviderDetailPanel.tsx +18 -15
  279. package/src/identity-provider/__tests__/IdentityProviderDetailPanel.test.tsx +80 -0
  280. package/src/index.ts +26 -4
  281. package/src/internal/StandingContextField.tsx +92 -0
  282. package/src/library/InstanceVisibilitySelector.tsx +9 -2
  283. package/src/library/ResourceVisibilityControl.tsx +46 -13
  284. package/src/library/VisibilityOptionRow.tsx +28 -6
  285. package/src/library/VisibilitySelector.tsx +14 -2
  286. package/src/library/__tests__/VisibilitySelector.test.tsx +48 -1
  287. package/src/library/__tests__/visibilityLevels.test.ts +67 -1
  288. package/src/library/index.ts +6 -1
  289. package/src/library/useCanSetPublicVisibility.ts +56 -0
  290. package/src/library/visibilityLevels.ts +65 -14
  291. package/src/mcp-server/McpServerDetailView.tsx +2 -2
  292. package/src/mcp-server/__tests__/useMcpServerConnect.asyncLane.test.tsx +117 -0
  293. package/src/mcp-server/index.ts +0 -2
  294. package/src/mcp-server/internal/definitionDrift.ts +22 -20
  295. package/src/mcp-server/useMcpServerConnect.ts +9 -6
  296. package/src/mcp-server/useMcpServerOAuthConnect.ts +7 -2
  297. package/src/mcp-server/useUpdateMcpServer.ts +3 -3
  298. package/src/models/ModelSelector.tsx +94 -1
  299. package/src/models/index.ts +2 -0
  300. package/src/models/registry.ts +29 -0
  301. package/src/models/thinking-mode.ts +48 -0
  302. package/src/oauth-app/CreateOAuthAppForm.tsx +58 -3
  303. package/src/oauth-app/OAuthAppDetailPanel.tsx +103 -20
  304. package/src/oauth-app/__tests__/OAuthAppDetailPanel.test.tsx +94 -0
  305. package/src/organization/OrgPreferencesPanel.tsx +221 -0
  306. package/src/organization/OrgProfilePanel.tsx +5 -4
  307. package/src/organization/__tests__/OrgPreferencesPanel.test.tsx +145 -0
  308. package/src/organization/__tests__/OrgProfilePanel.test.tsx +108 -0
  309. package/src/organization/index.ts +2 -0
  310. package/src/platform-client/PlatformClientDetailPanel.tsx +14 -13
  311. package/src/platform-client/__tests__/PlatformClientDetailPanel.test.tsx +82 -0
  312. package/src/schedule/ScheduleDetailView.tsx +29 -4
  313. package/src/schedule/ScheduleForm.tsx +14 -1
  314. package/src/session/NewSessionViewer.tsx +12 -0
  315. package/src/session/__tests__/useNewSessionFlow.test.tsx +151 -0
  316. package/src/session/run-config.ts +16 -0
  317. package/src/session/useNewSessionFlow.ts +82 -9
  318. package/src/session/useSessionConversation.ts +32 -40
  319. package/src/session/useSessionPageFlow.ts +14 -11
  320. package/src/session/useUpdateSession.ts +18 -24
  321. package/src/settings/AccountPreferencesSection.tsx +25 -0
  322. package/src/settings/OrgPreferencesSection.tsx +35 -0
  323. package/src/settings/__tests__/settings-nav.test.ts +27 -0
  324. package/src/settings/index.ts +2 -0
  325. package/src/settings/settings-nav.ts +18 -0
  326. package/src/workflow/ApprovalFormBuilder.tsx +20 -27
  327. package/src/workflow/WorkflowDetailView.tsx +2 -2
  328. package/src/workflow/__tests__/WorkflowInstanceDetailPanel.test.tsx +83 -0
  329. package/src/workflow/index.ts +0 -2
  330. package/src/workflow/instance/WorkflowInstanceDetailPanel.tsx +6 -7
  331. package/src/workflow/useUpdateWorkflow.ts +3 -3
  332. package/styles.css +1 -1
  333. package/workflow/ApprovalFormBuilder.d.ts.map +1 -1
  334. package/workflow/ApprovalFormBuilder.js +10 -5
  335. package/workflow/ApprovalFormBuilder.js.map +1 -1
  336. package/workflow/WorkflowDetailView.js +2 -2
  337. package/workflow/WorkflowDetailView.js.map +1 -1
  338. package/workflow/index.d.ts +0 -1
  339. package/workflow/index.d.ts.map +1 -1
  340. package/workflow/index.js +0 -1
  341. package/workflow/index.js.map +1 -1
  342. package/workflow/instance/WorkflowInstanceDetailPanel.d.ts.map +1 -1
  343. package/workflow/instance/WorkflowInstanceDetailPanel.js +6 -7
  344. package/workflow/instance/WorkflowInstanceDetailPanel.js.map +1 -1
  345. package/workflow/useUpdateWorkflow.d.ts +3 -3
  346. package/workflow/useUpdateWorkflow.js +3 -3
  347. package/agent/internal/agentToInput.d.ts +0 -15
  348. package/agent/internal/agentToInput.d.ts.map +0 -1
  349. package/agent/internal/agentToInput.js +0 -84
  350. package/agent/internal/agentToInput.js.map +0 -1
  351. package/mcp-server/internal/mcpServerToInput.d.ts +0 -12
  352. package/mcp-server/internal/mcpServerToInput.d.ts.map +0 -1
  353. package/mcp-server/internal/mcpServerToInput.js +0 -84
  354. package/mcp-server/internal/mcpServerToInput.js.map +0 -1
  355. package/session/session-spec-converters.d.ts +0 -24
  356. package/session/session-spec-converters.d.ts.map +0 -1
  357. package/session/session-spec-converters.js +0 -72
  358. package/session/session-spec-converters.js.map +0 -1
  359. package/src/agent/internal/__tests__/agentToInput.test.ts +0 -145
  360. package/src/agent/internal/agentToInput.ts +0 -102
  361. package/src/mcp-server/__tests__/mcpServerToInput.test.ts +0 -201
  362. package/src/mcp-server/internal/mcpServerToInput.ts +0 -98
  363. package/src/session/__tests__/session-spec-converters.test.ts +0 -183
  364. package/src/session/session-spec-converters.ts +0 -86
  365. package/src/workflow/internal/workflowToInput.ts +0 -96
  366. package/workflow/internal/workflowToInput.d.ts +0 -12
  367. package/workflow/internal/workflowToInput.d.ts.map +0 -1
  368. package/workflow/internal/workflowToInput.js +0 -73
  369. package/workflow/internal/workflowToInput.js.map +0 -1
@@ -0,0 +1,267 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
3
+ import { create } from "@bufbuild/protobuf";
4
+ import {
5
+ IdentityAccountSchema,
6
+ type IdentityAccount,
7
+ } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/api_pb";
8
+ import type { IdentityAccountInput } from "@stigmer/sdk";
9
+ import type { DeploymentMode } from "@stigmer/sdk";
10
+ import { StigmerContext } from "../../context";
11
+ import { DeploymentModeContext } from "../../deployment-mode";
12
+ import { ModelRegistryContext, type ModelRegistryState } from "../../models/ModelRegistryContext";
13
+ import { parseRegistryJson } from "../../models/registry";
14
+ import { AccountPreferencesPanel } from "../AccountPreferencesPanel";
15
+
16
+ const ACCOUNT: IdentityAccount = create(IdentityAccountSchema, {
17
+ metadata: { id: "ia-1", name: "Ada Lovelace", slug: "ada", org: "acme" },
18
+ spec: {
19
+ idpId: "auth0|abc",
20
+ email: "ada@acme.example",
21
+ preferences: { standingContext: "Keep answers terse." },
22
+ },
23
+ });
24
+
25
+ const TEST_MODELS = parseRegistryJson({
26
+ models: [
27
+ { id: "claude-sonnet-4.6", displayName: "Claude Sonnet 4.6", shortDescription: "", speedTier: "fast", provider: "anthropic", harness: "native", costTier: "standard", featured: true, pricing: { inputPricePerMillion: 3, outputPricePerMillion: 15, cacheWritePricePerMillion: 3.75, cacheReadPricePerMillion: 0.3 } },
28
+ { id: "default", displayName: "Cursor Auto", shortDescription: "", speedTier: "fast", provider: "cursor", harness: "cursor", costTier: "standard", featured: true, pricing: { inputPricePerMillion: 1.25, outputPricePerMillion: 6, cacheWritePricePerMillion: 1.25, cacheReadPricePerMillion: 0.25 } },
29
+ ],
30
+ });
31
+
32
+ const REGISTRY_STATE: ModelRegistryState = {
33
+ models: TEST_MODELS,
34
+ isLoading: false,
35
+ error: null,
36
+ refetch: () => {},
37
+ };
38
+
39
+ function createMockStigmer(overrides?: {
40
+ whoAmI?: ReturnType<typeof vi.fn>;
41
+ update?: ReturnType<typeof vi.fn>;
42
+ }) {
43
+ return {
44
+ identityAccount: {
45
+ whoAmI: overrides?.whoAmI ?? vi.fn(async () => ACCOUNT),
46
+ update: overrides?.update ?? vi.fn(async () => ACCOUNT),
47
+ },
48
+ } as never;
49
+ }
50
+
51
+ function renderPanel(client: unknown, mode: DeploymentMode = "cloud") {
52
+ return render(
53
+ <StigmerContext.Provider value={client as never}>
54
+ <DeploymentModeContext.Provider value={mode}>
55
+ <ModelRegistryContext.Provider value={REGISTRY_STATE}>
56
+ <AccountPreferencesPanel />
57
+ </ModelRegistryContext.Provider>
58
+ </DeploymentModeContext.Provider>
59
+ </StigmerContext.Provider>,
60
+ );
61
+ }
62
+
63
+ afterEach(cleanup);
64
+
65
+ /**
66
+ * Waits until the form has synced from server data (the panel copies the
67
+ * fetched value into local state in a passive effect, one flush after the
68
+ * field first renders) — interacting earlier races the sync.
69
+ */
70
+ async function findSyncedField(value: string) {
71
+ const field = await screen.findByLabelText("Standing context");
72
+ await waitFor(() => expect(field).toHaveProperty("value", value));
73
+ return field;
74
+ }
75
+
76
+ describe("AccountPreferencesPanel", () => {
77
+ it("renders the cloud notice in local mode without issuing any RPCs", () => {
78
+ const whoAmI = vi.fn(async () => ACCOUNT);
79
+ renderPanel(createMockStigmer({ whoAmI }), "local");
80
+
81
+ expect(screen.getByRole("status")).toBeTruthy();
82
+ expect(screen.queryByLabelText("Standing context")).toBeNull();
83
+ // The inner form must not mount — no doomed whoAmI against a local server.
84
+ expect(whoAmI).not.toHaveBeenCalled();
85
+ });
86
+
87
+ it("loads and displays the caller's declared standing context", async () => {
88
+ renderPanel(createMockStigmer());
89
+
90
+ await findSyncedField("Keep answers terse.");
91
+ });
92
+
93
+ it("saves the full mapped input — identity fields survive (wipe-bug guard)", async () => {
94
+ const update = vi.fn(async (_input: IdentityAccountInput) => ACCOUNT);
95
+ renderPanel(createMockStigmer({ update }));
96
+
97
+ const field = await findSyncedField("Keep answers terse.");
98
+ fireEvent.change(field, { target: { value: "Prefer bullet points." } });
99
+ fireEvent.click(screen.getByRole("button", { name: "Save changes" }));
100
+
101
+ await waitFor(() => expect(update).toHaveBeenCalledTimes(1));
102
+ const input = update.mock.calls[0]![0];
103
+
104
+ expect(input.preferences).toEqual({
105
+ standingContext: "Prefer bullet points.",
106
+ });
107
+ // Fields this form never renders must round-trip untouched.
108
+ expect(input.idpId).toBe("auth0|abc");
109
+ expect(input.email).toBe("ada@acme.example");
110
+ // The update pipeline addresses id-first — the id is REQUIRED here:
111
+ // identity accounts are org-less, so the org+slug fallback can never
112
+ // match one (the save-path bug this pin guards against).
113
+ expect(input.id).toBe("ia-1");
114
+ expect(input.org).toBe("acme");
115
+ expect(input.slug).toBe("ada");
116
+ });
117
+
118
+ it("refetches the account after a successful save", async () => {
119
+ const whoAmI = vi.fn(async () => ACCOUNT);
120
+ renderPanel(createMockStigmer({ whoAmI }));
121
+
122
+ const field = await findSyncedField("Keep answers terse.");
123
+ fireEvent.change(field, { target: { value: "New context" } });
124
+ fireEvent.click(screen.getByRole("button", { name: "Save changes" }));
125
+
126
+ // Initial load + post-save refetch.
127
+ await waitFor(() => expect(whoAmI).toHaveBeenCalledTimes(2));
128
+ });
129
+
130
+ it("shows the fetch error with a retry action when whoAmI fails", async () => {
131
+ const whoAmI = vi.fn(async () => {
132
+ throw new Error("boom");
133
+ });
134
+ renderPanel(createMockStigmer({ whoAmI }));
135
+
136
+ expect(await screen.findByRole("alert")).toBeTruthy();
137
+ expect(screen.getByRole("button", { name: "Retry" })).toBeTruthy();
138
+ });
139
+
140
+ describe("execution defaults (oss#293 Phase 1.5)", () => {
141
+ const ACCOUNT_WITH_DEFAULTS: IdentityAccount = create(IdentityAccountSchema, {
142
+ metadata: { id: "ia-1", name: "Ada Lovelace", slug: "ada", org: "acme" },
143
+ spec: {
144
+ idpId: "auth0|abc",
145
+ email: "ada@acme.example",
146
+ preferences: {
147
+ standingContext: "Keep answers terse.",
148
+ defaultHarness: "cursor",
149
+ defaultNativeModel: "claude-sonnet-4.6",
150
+ defaultCursorModel: "default",
151
+ },
152
+ },
153
+ });
154
+
155
+ it("renders the harness option rows and registry-fed model selects", async () => {
156
+ renderPanel(createMockStigmer());
157
+ await findSyncedField("Keep answers terse.");
158
+
159
+ expect(screen.getByRole("radio", { name: "Platform default" })).toBeTruthy();
160
+ expect(screen.getByRole("radio", { name: "Stigmer" })).toBeTruthy();
161
+ expect(screen.getByRole("radio", { name: "Cursor" })).toBeTruthy();
162
+ expect(screen.getByLabelText("Default model — Stigmer")).toBeTruthy();
163
+ expect(screen.getByLabelText("Default model — Cursor")).toBeTruthy();
164
+ });
165
+
166
+ it("pairs each harness row with its description (the row IS the context)", async () => {
167
+ renderPanel(createMockStigmer());
168
+ await findSyncedField("Keep answers terse.");
169
+
170
+ // Row subtitles come from HARNESS_META — the single source of harness
171
+ // display copy — plus the platform-default explainer.
172
+ expect(screen.getByText("Stigmer picks the harness for new sessions.")).toBeTruthy();
173
+ expect(screen.getByText("Stigmer's native agent runtime")).toBeTruthy();
174
+ expect(screen.getByText("Cursor IDE agent with codebase indexing")).toBeTruthy();
175
+ // The radios' accessible descriptions are wired via aria-describedby.
176
+ expect(
177
+ screen.getByRole("radio", { name: "Stigmer" }).getAttribute("aria-describedby"),
178
+ ).toBeTruthy();
179
+ });
180
+
181
+ it("keeps the non-selected harness's model select editable (per-harness models are independent of the default harness)", async () => {
182
+ renderPanel(createMockStigmer({ whoAmI: vi.fn(async () => ACCOUNT_WITH_DEFAULTS) }));
183
+ await findSyncedField("Keep answers terse.");
184
+
185
+ // Default harness is cursor, yet the Stigmer model stays settable:
186
+ // the launcher applies the model of the session's ACTIVE harness, so
187
+ // hiding or disabling it would remove a real capability.
188
+ await waitFor(() => {
189
+ expect(screen.getByRole("radio", { name: "Cursor" })).toHaveProperty("checked", true);
190
+ });
191
+ const nativeSelect = screen.getByLabelText("Default model — Stigmer") as HTMLSelectElement;
192
+ expect(nativeSelect.disabled).toBe(false);
193
+ fireEvent.change(nativeSelect, { target: { value: "claude-sonnet-4.6" } });
194
+ expect(nativeSelect.value).toBe("claude-sonnet-4.6");
195
+ });
196
+
197
+ it("reflects the saved defaults in the form", async () => {
198
+ renderPanel(createMockStigmer({ whoAmI: vi.fn(async () => ACCOUNT_WITH_DEFAULTS) }));
199
+ await findSyncedField("Keep answers terse.");
200
+
201
+ await waitFor(() => {
202
+ expect(screen.getByRole("radio", { name: "Cursor" })).toHaveProperty("checked", true);
203
+ expect(screen.getByLabelText("Default model — Stigmer")).toHaveProperty("value", "claude-sonnet-4.6");
204
+ expect(screen.getByLabelText("Default model — Cursor")).toHaveProperty("value", "default");
205
+ });
206
+ });
207
+
208
+ it("saves the complete preferences object — all default fields in one write", async () => {
209
+ const update = vi.fn(async (_input: IdentityAccountInput) => ACCOUNT);
210
+ renderPanel(createMockStigmer({ update }));
211
+ await findSyncedField("Keep answers terse.");
212
+
213
+ fireEvent.click(screen.getByRole("radio", { name: "Cursor" }));
214
+ fireEvent.change(screen.getByLabelText("Default model — Stigmer"), {
215
+ target: { value: "claude-sonnet-4.6" },
216
+ });
217
+ fireEvent.click(screen.getByRole("button", { name: "Save changes" }));
218
+
219
+ await waitFor(() => expect(update).toHaveBeenCalledTimes(1));
220
+ expect(update.mock.calls[0]![0].preferences).toEqual({
221
+ standingContext: "Keep answers terse.",
222
+ defaultHarness: "cursor",
223
+ defaultNativeModel: "claude-sonnet-4.6",
224
+ defaultCursorModel: undefined,
225
+ });
226
+ });
227
+
228
+ it("editing only standing context preserves the structured defaults (nested wipe-bug guard)", async () => {
229
+ const update = vi.fn(async (_input: IdentityAccountInput) => ACCOUNT_WITH_DEFAULTS);
230
+ renderPanel(
231
+ createMockStigmer({ whoAmI: vi.fn(async () => ACCOUNT_WITH_DEFAULTS), update }),
232
+ );
233
+
234
+ const field = await findSyncedField("Keep answers terse.");
235
+ fireEvent.change(field, { target: { value: "Terser still." } });
236
+ fireEvent.click(screen.getByRole("button", { name: "Save changes" }));
237
+
238
+ await waitFor(() => expect(update).toHaveBeenCalledTimes(1));
239
+ expect(update.mock.calls[0]![0].preferences).toEqual({
240
+ standingContext: "Terser still.",
241
+ defaultHarness: "cursor",
242
+ defaultNativeModel: "claude-sonnet-4.6",
243
+ defaultCursorModel: "default",
244
+ });
245
+ });
246
+
247
+ it("keeps a stale saved model legible as an unavailable option", async () => {
248
+ const stale = create(IdentityAccountSchema, {
249
+ metadata: { id: "ia-1", name: "Ada", slug: "ada", org: "acme" },
250
+ spec: {
251
+ idpId: "auth0|abc",
252
+ preferences: { defaultNativeModel: "retired-model" },
253
+ },
254
+ });
255
+ renderPanel(createMockStigmer({ whoAmI: vi.fn(async () => stale) }));
256
+ await findSyncedField("");
257
+
258
+ await waitFor(() => {
259
+ const select = screen.getByLabelText("Default model — Stigmer") as HTMLSelectElement;
260
+ expect(select.value).toBe("retired-model");
261
+ expect(
262
+ Array.from(select.options).some((o) => o.text === "retired-model (unavailable)"),
263
+ ).toBe(true);
264
+ });
265
+ });
266
+ });
267
+ });
@@ -0,0 +1,116 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { cleanup, renderHook, waitFor } from "@testing-library/react";
3
+ import type { ReactNode } from "react";
4
+ import { create } from "@bufbuild/protobuf";
5
+ import {
6
+ IdentityAccountSchema,
7
+ type IdentityAccount,
8
+ } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/api_pb";
9
+ import type { DeploymentMode } from "@stigmer/sdk";
10
+ import { StigmerContext } from "../../context";
11
+ import { DeploymentModeContext } from "../../deployment-mode";
12
+ import { useAccountExecutionDefaults } from "../useAccountExecutionDefaults";
13
+
14
+ function accountWithPreferences(
15
+ preferences: Record<string, string>,
16
+ ): IdentityAccount {
17
+ return create(IdentityAccountSchema, {
18
+ metadata: { id: "ia-1", name: "Ada", slug: "ada", org: "acme" },
19
+ spec: { idpId: "auth0|abc", preferences },
20
+ });
21
+ }
22
+
23
+ function createWrapper(whoAmI: ReturnType<typeof vi.fn>, mode: DeploymentMode = "cloud") {
24
+ const client = { identityAccount: { whoAmI } } as never;
25
+ return function Wrapper({ children }: { children: ReactNode }) {
26
+ return (
27
+ <StigmerContext.Provider value={client}>
28
+ <DeploymentModeContext.Provider value={mode}>
29
+ {children}
30
+ </DeploymentModeContext.Provider>
31
+ </StigmerContext.Provider>
32
+ );
33
+ };
34
+ }
35
+
36
+ afterEach(cleanup);
37
+
38
+ describe("useAccountExecutionDefaults", () => {
39
+ it("returns undefined in local mode without issuing any RPC", async () => {
40
+ const whoAmI = vi.fn();
41
+ const { result } = renderHook(() => useAccountExecutionDefaults(), {
42
+ wrapper: createWrapper(whoAmI, "local"),
43
+ });
44
+
45
+ // Settle any pending effects before asserting the no-RPC invariant.
46
+ await waitFor(() => expect(result.current).toBeUndefined());
47
+ expect(whoAmI).not.toHaveBeenCalled();
48
+ });
49
+
50
+ it("shapes declared defaults for the launcher's accountDefaults prop", async () => {
51
+ const whoAmI = vi.fn(async () =>
52
+ accountWithPreferences({
53
+ defaultHarness: "cursor",
54
+ defaultNativeModel: "claude-sonnet-4.6",
55
+ defaultCursorModel: "composer-2.5",
56
+ }),
57
+ );
58
+ const { result } = renderHook(() => useAccountExecutionDefaults(), {
59
+ wrapper: createWrapper(whoAmI),
60
+ });
61
+
62
+ await waitFor(() =>
63
+ expect(result.current).toEqual({
64
+ harness: "cursor",
65
+ nativeModel: "claude-sonnet-4.6",
66
+ cursorModel: "composer-2.5",
67
+ }),
68
+ );
69
+ });
70
+
71
+ it("returns undefined while loading and when nothing is declared", async () => {
72
+ const whoAmI = vi.fn(async () =>
73
+ accountWithPreferences({ standingContext: "Keep answers terse." }),
74
+ );
75
+ const { result } = renderHook(() => useAccountExecutionDefaults(), {
76
+ wrapper: createWrapper(whoAmI),
77
+ });
78
+
79
+ expect(result.current).toBeUndefined();
80
+ await waitFor(() => expect(whoAmI).toHaveBeenCalled());
81
+ // standing_context alone declares no execution default.
82
+ expect(result.current).toBeUndefined();
83
+ });
84
+
85
+ it("treats an unknown persisted harness value as undeclared", async () => {
86
+ const whoAmI = vi.fn(async () =>
87
+ accountWithPreferences({
88
+ defaultHarness: "devin",
89
+ defaultNativeModel: "claude-sonnet-4.6",
90
+ }),
91
+ );
92
+ const { result } = renderHook(() => useAccountExecutionDefaults(), {
93
+ wrapper: createWrapper(whoAmI),
94
+ });
95
+
96
+ await waitFor(() =>
97
+ expect(result.current).toEqual({
98
+ harness: undefined,
99
+ nativeModel: "claude-sonnet-4.6",
100
+ cursorModel: undefined,
101
+ }),
102
+ );
103
+ });
104
+
105
+ it("returns undefined on a whoAmI failure — degrades to platform defaults", async () => {
106
+ const whoAmI = vi.fn(async () => {
107
+ throw new Error("boom");
108
+ });
109
+ const { result } = renderHook(() => useAccountExecutionDefaults(), {
110
+ wrapper: createWrapper(whoAmI),
111
+ });
112
+
113
+ await waitFor(() => expect(whoAmI).toHaveBeenCalled());
114
+ expect(result.current).toBeUndefined();
115
+ });
116
+ });
@@ -0,0 +1,121 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
3
+ import { create } from "@bufbuild/protobuf";
4
+ import {
5
+ IdentityAccountSchema,
6
+ type IdentityAccount,
7
+ } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/api_pb";
8
+ import type { IdentityAccountInput } from "@stigmer/sdk";
9
+ import { StigmerContext } from "../../context";
10
+ import { useMyIdentityAccount } from "../useMyIdentityAccount";
11
+ import { useUpdateIdentityAccount } from "../useUpdateIdentityAccount";
12
+
13
+ const ACCOUNT: IdentityAccount = create(IdentityAccountSchema, {
14
+ metadata: { id: "ia-1", name: "Ada", slug: "ada", org: "acme" },
15
+ spec: { preferences: { standingContext: "Keep answers terse." } },
16
+ });
17
+
18
+ /** Renders the data hook and exposes its state via data attributes. */
19
+ function FetchProbe() {
20
+ const { account, isLoading, error, refetch } = useMyIdentityAccount();
21
+ return (
22
+ <button
23
+ type="button"
24
+ data-testid="probe"
25
+ data-loading={String(isLoading)}
26
+ data-error={String(error !== null)}
27
+ data-context={account?.spec?.preferences?.standingContext ?? ""}
28
+ onClick={refetch}
29
+ />
30
+ );
31
+ }
32
+
33
+ function UpdateProbe({ input }: { input: IdentityAccountInput }) {
34
+ const { update, isUpdating, error } = useUpdateIdentityAccount();
35
+ return (
36
+ <button
37
+ type="button"
38
+ data-testid="probe"
39
+ data-updating={String(isUpdating)}
40
+ data-error={String(error !== null)}
41
+ onClick={() => void update(input).catch(() => undefined)}
42
+ />
43
+ );
44
+ }
45
+
46
+ function withClient(client: unknown, ui: React.ReactNode) {
47
+ return render(
48
+ <StigmerContext.Provider value={client as never}>
49
+ {ui}
50
+ </StigmerContext.Provider>,
51
+ );
52
+ }
53
+
54
+ afterEach(cleanup);
55
+
56
+ describe("useMyIdentityAccount", () => {
57
+ it("fetches the caller's account via whoAmI and supports refetch", async () => {
58
+ const whoAmI = vi.fn(async () => ACCOUNT);
59
+ withClient({ identityAccount: { whoAmI } }, <FetchProbe />);
60
+
61
+ await waitFor(() =>
62
+ expect(screen.getByTestId("probe").getAttribute("data-context")).toBe(
63
+ "Keep answers terse.",
64
+ ),
65
+ );
66
+ expect(whoAmI).toHaveBeenCalledTimes(1);
67
+
68
+ fireEvent.click(screen.getByTestId("probe"));
69
+ await waitFor(() => expect(whoAmI).toHaveBeenCalledTimes(2));
70
+ });
71
+
72
+ it("surfaces errors as state", async () => {
73
+ const whoAmI = vi.fn(async () => {
74
+ throw new Error("boom");
75
+ });
76
+ withClient({ identityAccount: { whoAmI } }, <FetchProbe />);
77
+
78
+ await waitFor(() =>
79
+ expect(screen.getByTestId("probe").getAttribute("data-error")).toBe(
80
+ "true",
81
+ ),
82
+ );
83
+ });
84
+ });
85
+
86
+ describe("useUpdateIdentityAccount", () => {
87
+ it("submits the input through identityAccount.update", async () => {
88
+ const update = vi.fn(async (_input: IdentityAccountInput) => ACCOUNT);
89
+ const input: IdentityAccountInput = {
90
+ name: "Ada",
91
+ org: "acme",
92
+ slug: "ada",
93
+ idpId: "auth0|abc",
94
+ preferences: { standingContext: "New" },
95
+ };
96
+ withClient({ identityAccount: { update } }, <UpdateProbe input={input} />);
97
+
98
+ fireEvent.click(screen.getByTestId("probe"));
99
+
100
+ await waitFor(() => expect(update).toHaveBeenCalledTimes(1));
101
+ expect(update.mock.calls[0]![0]).toEqual(input);
102
+ });
103
+
104
+ it("captures update failures in error state", async () => {
105
+ const update = vi.fn(async () => {
106
+ throw new Error("denied");
107
+ });
108
+ withClient(
109
+ { identityAccount: { update } },
110
+ <UpdateProbe input={{ name: "Ada", org: "acme", idpId: "x" }} />,
111
+ );
112
+
113
+ fireEvent.click(screen.getByTestId("probe"));
114
+
115
+ await waitFor(() =>
116
+ expect(screen.getByTestId("probe").getAttribute("data-error")).toBe(
117
+ "true",
118
+ ),
119
+ );
120
+ });
121
+ });
@@ -3,3 +3,14 @@ export {
3
3
  type IdentityAccountGateState,
4
4
  type UseIdentityAccountGateReturn,
5
5
  } from "./useIdentityAccountGate.js";
6
+ export { useMyIdentityAccount } from "./useMyIdentityAccount.js";
7
+ export type {
8
+ UseMyIdentityAccountOptions,
9
+ UseMyIdentityAccountReturn,
10
+ } from "./useMyIdentityAccount.js";
11
+ export { useAccountExecutionDefaults } from "./useAccountExecutionDefaults.js";
12
+ export type { AccountExecutionDefaults } from "./useAccountExecutionDefaults.js";
13
+ export { useUpdateIdentityAccount } from "./useUpdateIdentityAccount.js";
14
+ export type { UseUpdateIdentityAccountReturn } from "./useUpdateIdentityAccount.js";
15
+ export { AccountPreferencesPanel } from "./AccountPreferencesPanel.js";
16
+ export type { AccountPreferencesPanelProps } from "./AccountPreferencesPanel.js";
@@ -0,0 +1,63 @@
1
+ "use client";
2
+
3
+ import { useMemo } from "react";
4
+ import { useMyIdentityAccount } from "./useMyIdentityAccount.js";
5
+ import { useResourceAvailable, ApiResourceKind } from "../deployment-mode.js";
6
+ import type { HarnessOption } from "../models/harness.js";
7
+
8
+ /**
9
+ * The current user's account-level execution defaults, shaped for the
10
+ * session launcher's `accountDefaults` prop.
11
+ */
12
+ export interface AccountExecutionDefaults {
13
+ /** Preferred harness for new sessions, when declared. */
14
+ readonly harness?: HarnessOption;
15
+ /** Preferred model for native-harness sessions, when declared. */
16
+ readonly nativeModel?: string;
17
+ /** Preferred model for cursor-harness sessions, when declared. */
18
+ readonly cursorModel?: string;
19
+ }
20
+
21
+ /**
22
+ * Data hook that reads the current user's execution defaults
23
+ * (`IdentityAccountSpec.preferences.default_*`) for seeding new-session
24
+ * composers.
25
+ *
26
+ * Returns `undefined` in local mode (no IdentityAccount), while loading,
27
+ * on error, and when no default is declared — every one of those cases
28
+ * degrades to the platform's existing defaults, so consumers wire the
29
+ * result straight through:
30
+ *
31
+ * @example
32
+ * ```tsx
33
+ * <NewSessionViewer org={org} accountDefaults={useAccountExecutionDefaults()} />
34
+ * ```
35
+ *
36
+ * The defaults are a SEED, not an override: an explicit device-local pick
37
+ * outranks them (the layered precedence in `useNewSessionFlow`), and the
38
+ * chosen values ride the execution spec explicitly. Rides
39
+ * `useMyIdentityAccount`'s cross-mount cache, so the seed is available
40
+ * synchronously on every visit after the first.
41
+ */
42
+ export function useAccountExecutionDefaults(): AccountExecutionDefaults | undefined {
43
+ const available = useResourceAvailable(ApiResourceKind.identity_account);
44
+ const { account } = useMyIdentityAccount({ enabled: available });
45
+
46
+ return useMemo(() => {
47
+ const prefs = account?.spec?.preferences;
48
+ if (!prefs) return undefined;
49
+
50
+ // The proto validates default_harness to the shipped set, but a client
51
+ // must not trust persisted data it did not write — unknown values are
52
+ // treated as undeclared.
53
+ const harness =
54
+ prefs.defaultHarness === "native" || prefs.defaultHarness === "cursor"
55
+ ? (prefs.defaultHarness satisfies HarnessOption)
56
+ : undefined;
57
+ const nativeModel = prefs.defaultNativeModel || undefined;
58
+ const cursorModel = prefs.defaultCursorModel || undefined;
59
+
60
+ if (!harness && !nativeModel && !cursorModel) return undefined;
61
+ return { harness, nativeModel, cursorModel };
62
+ }, [account]);
63
+ }
@@ -0,0 +1,75 @@
1
+ "use client";
2
+
3
+ import type { IdentityAccount } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/api_pb";
4
+ import { useStigmer } from "../hooks.js";
5
+ import { useFetch } from "../internal/useFetch.js";
6
+
7
+ /** Options for {@link useMyIdentityAccount}. */
8
+ export interface UseMyIdentityAccountOptions {
9
+ /**
10
+ * When `false`, the hook is idle: no RPC is issued and `account` stays
11
+ * `null`. Lets always-called hooks (React's rules) skip the doomed
12
+ * whoAmI against a local server — pass
13
+ * `useResourceAvailable(ApiResourceKind.identity_account)` here.
14
+ *
15
+ * @default true
16
+ */
17
+ readonly enabled?: boolean;
18
+ }
19
+
20
+ /** Return value of {@link useMyIdentityAccount}. */
21
+ export interface UseMyIdentityAccountReturn {
22
+ /** The authenticated user's identity account, or `null` while loading / on error. */
23
+ readonly account: IdentityAccount | null;
24
+ /** `true` while the initial fetch is in flight. */
25
+ readonly isLoading: boolean;
26
+ /** `true` while a background refetch is in flight and stale data is shown. */
27
+ readonly isRefetching: boolean;
28
+ /** Error from the last failed request, or `null` when healthy. */
29
+ readonly error: Error | null;
30
+ /** Re-fetch the account from the server (e.g. after an update). */
31
+ readonly refetch: () => void;
32
+ }
33
+
34
+ /**
35
+ * Data hook that fetches the current authenticated user's full
36
+ * {@link IdentityAccount} via `identityAccount.whoAmI()`.
37
+ *
38
+ * Unlike {@link useWhoAmI} (a cached identity lookup for "is this me?"
39
+ * checks), this hook is a refetchable data source for editors of the
40
+ * caller's own account — after a mutation, call `refetch()` to re-sync.
41
+ * `whoAmI()` returns the complete resource, so no follow-up `get()` is
42
+ * needed.
43
+ *
44
+ * Cloud-only by nature: the OSS local server does not implement
45
+ * IdentityAccount. Gate consumers with
46
+ * `useResourceAvailable(ApiResourceKind.identity_account)` — either by
47
+ * conditional mounting or via {@link UseMyIdentityAccountOptions.enabled}.
48
+ *
49
+ * Cached across mounts under a {@link FetchCacheProvider} (DD-014): a
50
+ * revisit renders the previous result immediately and refetches in the
51
+ * background, so consumers that seed UI from the account (e.g. composer
52
+ * defaults) settle synchronously after the first visit.
53
+ *
54
+ * @example
55
+ * ```tsx
56
+ * const { account, refetch } = useMyIdentityAccount();
57
+ * const standingContext =
58
+ * account?.spec?.preferences?.standingContext ?? "";
59
+ * ```
60
+ */
61
+ export function useMyIdentityAccount(
62
+ options?: UseMyIdentityAccountOptions,
63
+ ): UseMyIdentityAccountReturn {
64
+ const stigmer = useStigmer();
65
+ const enabled = options?.enabled ?? true;
66
+
67
+ const { data: account, isLoading, isRefetching, error, refetch } = useFetch(
68
+ enabled ? () => stigmer.identityAccount.whoAmI() : null,
69
+ [stigmer, enabled],
70
+ null as IdentityAccount | null,
71
+ { cacheKey: enabled ? "identity-account:me" : undefined },
72
+ );
73
+
74
+ return { account, isLoading, isRefetching, error, refetch };
75
+ }