@stigmer/react 0.4.7 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (652) hide show
  1. package/action-menu/ActionMenu.d.ts +64 -0
  2. package/action-menu/ActionMenu.d.ts.map +1 -0
  3. package/action-menu/ActionMenu.js +78 -0
  4. package/action-menu/ActionMenu.js.map +1 -0
  5. package/action-menu/index.d.ts +3 -0
  6. package/action-menu/index.d.ts.map +1 -0
  7. package/action-menu/index.js +2 -0
  8. package/action-menu/index.js.map +1 -0
  9. package/action-menu/types.d.ts +65 -0
  10. package/action-menu/types.d.ts.map +1 -0
  11. package/action-menu/types.js +2 -0
  12. package/action-menu/types.js.map +1 -0
  13. package/agent/AgentCreationWizard.d.ts +55 -0
  14. package/agent/AgentCreationWizard.d.ts.map +1 -0
  15. package/agent/AgentCreationWizard.js +115 -0
  16. package/agent/AgentCreationWizard.js.map +1 -0
  17. package/agent/AgentDetailView.d.ts +77 -9
  18. package/agent/AgentDetailView.d.ts.map +1 -1
  19. package/agent/AgentDetailView.js +265 -87
  20. package/agent/AgentDetailView.js.map +1 -1
  21. package/agent/index.d.ts +8 -0
  22. package/agent/index.d.ts.map +1 -1
  23. package/agent/index.js +4 -0
  24. package/agent/index.js.map +1 -1
  25. package/agent/internal/agentToInput.d.ts +12 -0
  26. package/agent/internal/agentToInput.d.ts.map +1 -0
  27. package/agent/internal/agentToInput.js +72 -0
  28. package/agent/internal/agentToInput.js.map +1 -0
  29. package/agent/steps/CapabilitiesStep.d.ts +16 -0
  30. package/agent/steps/CapabilitiesStep.d.ts.map +1 -0
  31. package/agent/steps/CapabilitiesStep.js +80 -0
  32. package/agent/steps/CapabilitiesStep.js.map +1 -0
  33. package/agent/steps/IdentityStep.d.ts +18 -0
  34. package/agent/steps/IdentityStep.d.ts.map +1 -0
  35. package/agent/steps/IdentityStep.js +43 -0
  36. package/agent/steps/IdentityStep.js.map +1 -0
  37. package/agent/steps/ReviewStep.d.ts +23 -0
  38. package/agent/steps/ReviewStep.d.ts.map +1 -0
  39. package/agent/steps/ReviewStep.js +73 -0
  40. package/agent/steps/ReviewStep.js.map +1 -0
  41. package/agent/steps/types.d.ts +35 -0
  42. package/agent/steps/types.d.ts.map +1 -0
  43. package/agent/steps/types.js +16 -0
  44. package/agent/steps/types.js.map +1 -0
  45. package/agent/useCreateAgent.d.ts +45 -0
  46. package/agent/useCreateAgent.d.ts.map +1 -0
  47. package/agent/useCreateAgent.js +50 -0
  48. package/agent/useCreateAgent.js.map +1 -0
  49. package/agent/useUpdateAgent.d.ts +24 -0
  50. package/agent/useUpdateAgent.d.ts.map +1 -0
  51. package/agent/useUpdateAgent.js +35 -0
  52. package/agent/useUpdateAgent.js.map +1 -0
  53. package/dependency-graph/DependencyGraph.d.ts +37 -0
  54. package/dependency-graph/DependencyGraph.d.ts.map +1 -0
  55. package/dependency-graph/DependencyGraph.js +88 -0
  56. package/dependency-graph/DependencyGraph.js.map +1 -0
  57. package/dependency-graph/DependencyTreeNode.d.ts +23 -0
  58. package/dependency-graph/DependencyTreeNode.d.ts.map +1 -0
  59. package/dependency-graph/DependencyTreeNode.js +99 -0
  60. package/dependency-graph/DependencyTreeNode.js.map +1 -0
  61. package/dependency-graph/index.d.ts +4 -0
  62. package/dependency-graph/index.d.ts.map +1 -0
  63. package/dependency-graph/index.js +5 -0
  64. package/dependency-graph/index.js.map +1 -0
  65. package/dependency-graph/types.d.ts +130 -0
  66. package/dependency-graph/types.d.ts.map +1 -0
  67. package/dependency-graph/types.js +2 -0
  68. package/dependency-graph/types.js.map +1 -0
  69. package/dependency-graph/useDependencyGraph.d.ts +27 -0
  70. package/dependency-graph/useDependencyGraph.d.ts.map +1 -0
  71. package/dependency-graph/useDependencyGraph.js +129 -0
  72. package/dependency-graph/useDependencyGraph.js.map +1 -0
  73. package/empty-state/EmptyState.d.ts +29 -0
  74. package/empty-state/EmptyState.d.ts.map +1 -0
  75. package/empty-state/EmptyState.js +45 -0
  76. package/empty-state/EmptyState.js.map +1 -0
  77. package/empty-state/index.d.ts +4 -0
  78. package/empty-state/index.d.ts.map +1 -0
  79. package/empty-state/index.js +3 -0
  80. package/empty-state/index.js.map +1 -0
  81. package/empty-state/types.d.ts +73 -0
  82. package/empty-state/types.d.ts.map +1 -0
  83. package/empty-state/types.js +2 -0
  84. package/empty-state/types.js.map +1 -0
  85. package/empty-state/useEmptyState.d.ts +18 -0
  86. package/empty-state/useEmptyState.d.ts.map +1 -0
  87. package/empty-state/useEmptyState.js +72 -0
  88. package/empty-state/useEmptyState.js.map +1 -0
  89. package/execution/MessageThread.d.ts +1 -0
  90. package/execution/MessageThread.d.ts.map +1 -1
  91. package/execution/MessageThread.js +22 -12
  92. package/execution/MessageThread.js.map +1 -1
  93. package/execution/SetupProgress.d.ts +23 -9
  94. package/execution/SetupProgress.d.ts.map +1 -1
  95. package/execution/SetupProgress.js +30 -14
  96. package/execution/SetupProgress.js.map +1 -1
  97. package/execution/__tests__/thread-keys.test.js +82 -0
  98. package/execution/__tests__/thread-keys.test.js.map +1 -1
  99. package/feedback/StigmerToaster.d.ts +18 -0
  100. package/feedback/StigmerToaster.d.ts.map +1 -0
  101. package/feedback/StigmerToaster.js +31 -0
  102. package/feedback/StigmerToaster.js.map +1 -0
  103. package/feedback/index.d.ts +4 -0
  104. package/feedback/index.d.ts.map +1 -0
  105. package/feedback/index.js +3 -0
  106. package/feedback/index.js.map +1 -0
  107. package/feedback/toast.d.ts +14 -0
  108. package/feedback/toast.d.ts.map +1 -0
  109. package/feedback/toast.js +14 -0
  110. package/feedback/toast.js.map +1 -0
  111. package/feedback/types.d.ts +4 -0
  112. package/feedback/types.d.ts.map +1 -0
  113. package/feedback/types.js +2 -0
  114. package/feedback/types.js.map +1 -0
  115. package/index.d.ts +30 -10
  116. package/index.d.ts.map +1 -1
  117. package/index.js +29 -9
  118. package/index.js.map +1 -1
  119. package/inline-edit/InlineEditImage.d.ts +20 -0
  120. package/inline-edit/InlineEditImage.d.ts.map +1 -0
  121. package/inline-edit/InlineEditImage.js +85 -0
  122. package/inline-edit/InlineEditImage.js.map +1 -0
  123. package/inline-edit/InlineEditKeyValue.d.ts +29 -0
  124. package/inline-edit/InlineEditKeyValue.d.ts.map +1 -0
  125. package/inline-edit/InlineEditKeyValue.js +67 -0
  126. package/inline-edit/InlineEditKeyValue.js.map +1 -0
  127. package/inline-edit/InlineEditResourceList.d.ts +34 -0
  128. package/inline-edit/InlineEditResourceList.d.ts.map +1 -0
  129. package/inline-edit/InlineEditResourceList.js +99 -0
  130. package/inline-edit/InlineEditResourceList.js.map +1 -0
  131. package/inline-edit/InlineEditSelect.d.ts +18 -0
  132. package/inline-edit/InlineEditSelect.d.ts.map +1 -0
  133. package/inline-edit/InlineEditSelect.js +54 -0
  134. package/inline-edit/InlineEditSelect.js.map +1 -0
  135. package/inline-edit/InlineEditText.d.ts +23 -0
  136. package/inline-edit/InlineEditText.d.ts.map +1 -0
  137. package/inline-edit/InlineEditText.js +79 -0
  138. package/inline-edit/InlineEditText.js.map +1 -0
  139. package/inline-edit/InlineEditTextarea.d.ts +22 -0
  140. package/inline-edit/InlineEditTextarea.d.ts.map +1 -0
  141. package/inline-edit/InlineEditTextarea.js +83 -0
  142. package/inline-edit/InlineEditTextarea.js.map +1 -0
  143. package/inline-edit/index.d.ts +16 -0
  144. package/inline-edit/index.d.ts.map +1 -0
  145. package/inline-edit/index.js +8 -0
  146. package/inline-edit/index.js.map +1 -0
  147. package/inline-edit/types.d.ts +42 -0
  148. package/inline-edit/types.d.ts.map +1 -0
  149. package/inline-edit/types.js +2 -0
  150. package/inline-edit/types.js.map +1 -0
  151. package/inline-edit/useInlineFieldSave.d.ts +23 -0
  152. package/inline-edit/useInlineFieldSave.d.ts.map +1 -0
  153. package/inline-edit/useInlineFieldSave.js +44 -0
  154. package/inline-edit/useInlineFieldSave.js.map +1 -0
  155. package/internal/Tabs.d.ts +4 -38
  156. package/internal/Tabs.d.ts.map +1 -1
  157. package/internal/Tabs.js +3 -62
  158. package/internal/Tabs.js.map +1 -1
  159. package/library/ImportResourceDialog.d.ts +43 -0
  160. package/library/ImportResourceDialog.d.ts.map +1 -0
  161. package/library/ImportResourceDialog.js +90 -0
  162. package/library/ImportResourceDialog.js.map +1 -0
  163. package/library/index.d.ts +7 -4
  164. package/library/index.d.ts.map +1 -1
  165. package/library/index.js +4 -2
  166. package/library/index.js.map +1 -1
  167. package/library/serialize-resource-yaml.d.ts +53 -0
  168. package/library/serialize-resource-yaml.d.ts.map +1 -1
  169. package/library/serialize-resource-yaml.js +275 -0
  170. package/library/serialize-resource-yaml.js.map +1 -1
  171. package/library/useExportResource.d.ts +56 -0
  172. package/library/useExportResource.d.ts.map +1 -0
  173. package/library/useExportResource.js +137 -0
  174. package/library/useExportResource.js.map +1 -0
  175. package/library/useImportResource.d.ts +84 -0
  176. package/library/useImportResource.d.ts.map +1 -0
  177. package/library/useImportResource.js +188 -0
  178. package/library/useImportResource.js.map +1 -0
  179. package/mcp-server/McpServerCreationWizard.d.ts +55 -0
  180. package/mcp-server/McpServerCreationWizard.d.ts.map +1 -0
  181. package/mcp-server/McpServerCreationWizard.js +121 -0
  182. package/mcp-server/McpServerCreationWizard.js.map +1 -0
  183. package/mcp-server/McpServerDetailView.d.ts +21 -1
  184. package/mcp-server/McpServerDetailView.d.ts.map +1 -1
  185. package/mcp-server/McpServerDetailView.js +113 -20
  186. package/mcp-server/McpServerDetailView.js.map +1 -1
  187. package/mcp-server/index.d.ts +8 -0
  188. package/mcp-server/index.d.ts.map +1 -1
  189. package/mcp-server/index.js +4 -0
  190. package/mcp-server/index.js.map +1 -1
  191. package/mcp-server/internal/mcpServerToInput.d.ts +12 -0
  192. package/mcp-server/internal/mcpServerToInput.d.ts.map +1 -0
  193. package/mcp-server/internal/mcpServerToInput.js +81 -0
  194. package/mcp-server/internal/mcpServerToInput.js.map +1 -0
  195. package/mcp-server/steps/EnvironmentAuthStep.d.ts +15 -0
  196. package/mcp-server/steps/EnvironmentAuthStep.d.ts.map +1 -0
  197. package/mcp-server/steps/EnvironmentAuthStep.js +55 -0
  198. package/mcp-server/steps/EnvironmentAuthStep.js.map +1 -0
  199. package/mcp-server/steps/IdentityTransportStep.d.ts +19 -0
  200. package/mcp-server/steps/IdentityTransportStep.d.ts.map +1 -0
  201. package/mcp-server/steps/IdentityTransportStep.js +73 -0
  202. package/mcp-server/steps/IdentityTransportStep.js.map +1 -0
  203. package/mcp-server/steps/ReviewStep.d.ts +23 -0
  204. package/mcp-server/steps/ReviewStep.d.ts.map +1 -0
  205. package/mcp-server/steps/ReviewStep.js +137 -0
  206. package/mcp-server/steps/ReviewStep.js.map +1 -0
  207. package/mcp-server/steps/types.d.ts +56 -0
  208. package/mcp-server/steps/types.d.ts.map +1 -0
  209. package/mcp-server/steps/types.js +27 -0
  210. package/mcp-server/steps/types.js.map +1 -0
  211. package/mcp-server/useCreateMcpServer.d.ts +45 -0
  212. package/mcp-server/useCreateMcpServer.d.ts.map +1 -0
  213. package/mcp-server/useCreateMcpServer.js +50 -0
  214. package/mcp-server/useCreateMcpServer.js.map +1 -0
  215. package/mcp-server/useUpdateMcpServer.d.ts +24 -0
  216. package/mcp-server/useUpdateMcpServer.d.ts.map +1 -0
  217. package/mcp-server/useUpdateMcpServer.js +35 -0
  218. package/mcp-server/useUpdateMcpServer.js.map +1 -0
  219. package/models/registry.d.ts +4 -1
  220. package/models/registry.d.ts.map +1 -1
  221. package/models/registry.js +6 -2
  222. package/models/registry.js.map +1 -1
  223. package/package.json +8 -4
  224. package/provider.js +1 -1
  225. package/provider.js.map +1 -1
  226. package/resource-creation/CreationPicker.d.ts +60 -0
  227. package/resource-creation/CreationPicker.d.ts.map +1 -0
  228. package/resource-creation/CreationPicker.js +74 -0
  229. package/resource-creation/CreationPicker.js.map +1 -0
  230. package/resource-creation/StepIndicator.d.ts +28 -0
  231. package/resource-creation/StepIndicator.d.ts.map +1 -0
  232. package/resource-creation/StepIndicator.js +40 -0
  233. package/resource-creation/StepIndicator.js.map +1 -0
  234. package/resource-creation/TemplateCard.d.ts +24 -0
  235. package/resource-creation/TemplateCard.d.ts.map +1 -0
  236. package/resource-creation/TemplateCard.js +68 -0
  237. package/resource-creation/TemplateCard.js.map +1 -0
  238. package/resource-creation/TemplateGallery.d.ts +43 -0
  239. package/resource-creation/TemplateGallery.d.ts.map +1 -0
  240. package/resource-creation/TemplateGallery.js +78 -0
  241. package/resource-creation/TemplateGallery.js.map +1 -0
  242. package/resource-creation/WizardNav.d.ts +31 -0
  243. package/resource-creation/WizardNav.d.ts.map +1 -0
  244. package/resource-creation/WizardNav.js +29 -0
  245. package/resource-creation/WizardNav.js.map +1 -0
  246. package/resource-creation/WizardShell.d.ts +41 -0
  247. package/resource-creation/WizardShell.d.ts.map +1 -0
  248. package/resource-creation/WizardShell.js +55 -0
  249. package/resource-creation/WizardShell.js.map +1 -0
  250. package/resource-creation/index.d.ts +21 -0
  251. package/resource-creation/index.d.ts.map +1 -0
  252. package/resource-creation/index.js +14 -0
  253. package/resource-creation/index.js.map +1 -0
  254. package/resource-creation/templates/agent-templates.d.ts +15 -0
  255. package/resource-creation/templates/agent-templates.d.ts.map +1 -0
  256. package/resource-creation/templates/agent-templates.js +148 -0
  257. package/resource-creation/templates/agent-templates.js.map +1 -0
  258. package/resource-creation/templates/index.d.ts +5 -0
  259. package/resource-creation/templates/index.d.ts.map +1 -0
  260. package/resource-creation/templates/index.js +5 -0
  261. package/resource-creation/templates/index.js.map +1 -0
  262. package/resource-creation/templates/mcp-server-templates.d.ts +15 -0
  263. package/resource-creation/templates/mcp-server-templates.d.ts.map +1 -0
  264. package/resource-creation/templates/mcp-server-templates.js +92 -0
  265. package/resource-creation/templates/mcp-server-templates.js.map +1 -0
  266. package/resource-creation/templates/types.d.ts +48 -0
  267. package/resource-creation/templates/types.d.ts.map +1 -0
  268. package/resource-creation/templates/types.js +16 -0
  269. package/resource-creation/templates/types.js.map +1 -0
  270. package/resource-creation/types.d.ts +88 -0
  271. package/resource-creation/types.d.ts.map +1 -0
  272. package/resource-creation/types.js +2 -0
  273. package/resource-creation/types.js.map +1 -0
  274. package/resource-creation/useTemplateFilter.d.ts +43 -0
  275. package/resource-creation/useTemplateFilter.d.ts.map +1 -0
  276. package/resource-creation/useTemplateFilter.js +73 -0
  277. package/resource-creation/useTemplateFilter.js.map +1 -0
  278. package/resource-creation/useWizardState.d.ts +67 -0
  279. package/resource-creation/useWizardState.d.ts.map +1 -0
  280. package/resource-creation/useWizardState.js +143 -0
  281. package/resource-creation/useWizardState.js.map +1 -0
  282. package/resource-detail/ConfirmDialog.d.ts +44 -0
  283. package/resource-detail/ConfirmDialog.d.ts.map +1 -0
  284. package/resource-detail/ConfirmDialog.js +62 -0
  285. package/resource-detail/ConfirmDialog.js.map +1 -0
  286. package/resource-detail/ResourceActionBar.d.ts +42 -0
  287. package/resource-detail/ResourceActionBar.d.ts.map +1 -0
  288. package/resource-detail/ResourceActionBar.js +64 -0
  289. package/resource-detail/ResourceActionBar.js.map +1 -0
  290. package/resource-detail/ResourceDetailShell.d.ts +36 -0
  291. package/resource-detail/ResourceDetailShell.d.ts.map +1 -0
  292. package/resource-detail/ResourceDetailShell.js +65 -0
  293. package/resource-detail/ResourceDetailShell.js.map +1 -0
  294. package/resource-detail/Section.d.ts +18 -0
  295. package/resource-detail/Section.d.ts.map +1 -0
  296. package/resource-detail/Section.js +18 -0
  297. package/resource-detail/Section.js.map +1 -0
  298. package/resource-detail/index.d.ts +15 -0
  299. package/resource-detail/index.d.ts.map +1 -0
  300. package/resource-detail/index.js +10 -0
  301. package/resource-detail/index.js.map +1 -0
  302. package/resource-detail/types.d.ts +146 -0
  303. package/resource-detail/types.d.ts.map +1 -0
  304. package/resource-detail/types.js +2 -0
  305. package/resource-detail/types.js.map +1 -0
  306. package/resource-detail/useConfirmAction.d.ts +41 -0
  307. package/resource-detail/useConfirmAction.d.ts.map +1 -0
  308. package/resource-detail/useConfirmAction.js +30 -0
  309. package/resource-detail/useConfirmAction.js.map +1 -0
  310. package/resource-detail/useCopyResource.d.ts +28 -0
  311. package/resource-detail/useCopyResource.d.ts.map +1 -0
  312. package/resource-detail/useCopyResource.js +46 -0
  313. package/resource-detail/useCopyResource.js.map +1 -0
  314. package/resource-detail/useDeleteResource.d.ts +40 -0
  315. package/resource-detail/useDeleteResource.d.ts.map +1 -0
  316. package/resource-detail/useDeleteResource.js +83 -0
  317. package/resource-detail/useDeleteResource.js.map +1 -0
  318. package/resource-detail/useDetailTabs.d.ts +46 -0
  319. package/resource-detail/useDetailTabs.d.ts.map +1 -0
  320. package/resource-detail/useDetailTabs.js +47 -0
  321. package/resource-detail/useDetailTabs.js.map +1 -0
  322. package/resource-workbench/components/BulkActionBar.d.ts +36 -0
  323. package/resource-workbench/components/BulkActionBar.d.ts.map +1 -0
  324. package/resource-workbench/components/BulkActionBar.js +35 -0
  325. package/resource-workbench/components/BulkActionBar.js.map +1 -0
  326. package/resource-workbench/components/ColumnHeader.d.ts +23 -0
  327. package/resource-workbench/components/ColumnHeader.d.ts.map +1 -0
  328. package/resource-workbench/components/ColumnHeader.js +25 -0
  329. package/resource-workbench/components/ColumnHeader.js.map +1 -0
  330. package/resource-workbench/components/FilterBar.d.ts +33 -0
  331. package/resource-workbench/components/FilterBar.d.ts.map +1 -0
  332. package/resource-workbench/components/FilterBar.js +72 -0
  333. package/resource-workbench/components/FilterBar.js.map +1 -0
  334. package/resource-workbench/components/ResourceAvatar.d.ts +29 -0
  335. package/resource-workbench/components/ResourceAvatar.d.ts.map +1 -0
  336. package/resource-workbench/components/ResourceAvatar.js +51 -0
  337. package/resource-workbench/components/ResourceAvatar.js.map +1 -0
  338. package/resource-workbench/components/ResourceCards.d.ts +39 -0
  339. package/resource-workbench/components/ResourceCards.d.ts.map +1 -0
  340. package/resource-workbench/components/ResourceCards.js +41 -0
  341. package/resource-workbench/components/ResourceCards.js.map +1 -0
  342. package/resource-workbench/components/ResourceInspector.d.ts +26 -0
  343. package/resource-workbench/components/ResourceInspector.d.ts.map +1 -0
  344. package/resource-workbench/components/ResourceInspector.js +22 -0
  345. package/resource-workbench/components/ResourceInspector.js.map +1 -0
  346. package/resource-workbench/components/ResourceList.d.ts +39 -0
  347. package/resource-workbench/components/ResourceList.d.ts.map +1 -0
  348. package/resource-workbench/components/ResourceList.js +41 -0
  349. package/resource-workbench/components/ResourceList.js.map +1 -0
  350. package/resource-workbench/components/ResourceTable.d.ts +47 -0
  351. package/resource-workbench/components/ResourceTable.d.ts.map +1 -0
  352. package/resource-workbench/components/ResourceTable.js +78 -0
  353. package/resource-workbench/components/ResourceTable.js.map +1 -0
  354. package/resource-workbench/components/ResourceWorkbench.d.ts +131 -0
  355. package/resource-workbench/components/ResourceWorkbench.d.ts.map +1 -0
  356. package/resource-workbench/components/ResourceWorkbench.js +170 -0
  357. package/resource-workbench/components/ResourceWorkbench.js.map +1 -0
  358. package/resource-workbench/components/SelectionCheckbox.d.ts +24 -0
  359. package/resource-workbench/components/SelectionCheckbox.d.ts.map +1 -0
  360. package/resource-workbench/components/SelectionCheckbox.js +16 -0
  361. package/resource-workbench/components/SelectionCheckbox.js.map +1 -0
  362. package/resource-workbench/components/StatusBadge.d.ts +31 -0
  363. package/resource-workbench/components/StatusBadge.d.ts.map +1 -0
  364. package/resource-workbench/components/StatusBadge.js +75 -0
  365. package/resource-workbench/components/StatusBadge.js.map +1 -0
  366. package/resource-workbench/components/ViewSwitcher.d.ts +21 -0
  367. package/resource-workbench/components/ViewSwitcher.d.ts.map +1 -0
  368. package/resource-workbench/components/ViewSwitcher.js +37 -0
  369. package/resource-workbench/components/ViewSwitcher.js.map +1 -0
  370. package/resource-workbench/hooks/useResourceCollection.d.ts +93 -0
  371. package/resource-workbench/hooks/useResourceCollection.d.ts.map +1 -0
  372. package/resource-workbench/hooks/useResourceCollection.js +133 -0
  373. package/resource-workbench/hooks/useResourceCollection.js.map +1 -0
  374. package/resource-workbench/hooks/useResourceFilters.d.ts +73 -0
  375. package/resource-workbench/hooks/useResourceFilters.d.ts.map +1 -0
  376. package/resource-workbench/hooks/useResourceFilters.js +105 -0
  377. package/resource-workbench/hooks/useResourceFilters.js.map +1 -0
  378. package/resource-workbench/hooks/useResourceSelection.d.ts +44 -0
  379. package/resource-workbench/hooks/useResourceSelection.d.ts.map +1 -0
  380. package/resource-workbench/hooks/useResourceSelection.js +123 -0
  381. package/resource-workbench/hooks/useResourceSelection.js.map +1 -0
  382. package/resource-workbench/hooks/useViewPreference.d.ts +32 -0
  383. package/resource-workbench/hooks/useViewPreference.d.ts.map +1 -0
  384. package/resource-workbench/hooks/useViewPreference.js +60 -0
  385. package/resource-workbench/hooks/useViewPreference.js.map +1 -0
  386. package/resource-workbench/index.d.ts +34 -0
  387. package/resource-workbench/index.d.ts.map +1 -0
  388. package/resource-workbench/index.js +19 -0
  389. package/resource-workbench/index.js.map +1 -0
  390. package/resource-workbench/types.d.ts +165 -0
  391. package/resource-workbench/types.d.ts.map +1 -0
  392. package/resource-workbench/types.js +2 -0
  393. package/resource-workbench/types.js.map +1 -0
  394. package/runner/RunnerDetailView.d.ts +44 -0
  395. package/runner/RunnerDetailView.d.ts.map +1 -0
  396. package/runner/RunnerDetailView.js +154 -0
  397. package/runner/RunnerDetailView.js.map +1 -0
  398. package/runner/RunnerListPanel.d.ts +26 -1
  399. package/runner/RunnerListPanel.d.ts.map +1 -1
  400. package/runner/RunnerListPanel.js +68 -46
  401. package/runner/RunnerListPanel.js.map +1 -1
  402. package/runner/index.d.ts +7 -1
  403. package/runner/index.d.ts.map +1 -1
  404. package/runner/index.js +3 -0
  405. package/runner/index.js.map +1 -1
  406. package/runner/shared.d.ts +31 -0
  407. package/runner/shared.d.ts.map +1 -0
  408. package/runner/shared.js +55 -0
  409. package/runner/shared.js.map +1 -0
  410. package/runner/useRunner.d.ts +37 -0
  411. package/runner/useRunner.d.ts.map +1 -0
  412. package/runner/useRunner.js +24 -0
  413. package/runner/useRunner.js.map +1 -0
  414. package/session/__tests__/group-sessions.test.js +3 -3
  415. package/session/__tests__/group-sessions.test.js.map +1 -1
  416. package/skill/SkillDetailView.d.ts +70 -7
  417. package/skill/SkillDetailView.d.ts.map +1 -1
  418. package/skill/SkillDetailView.js +107 -39
  419. package/skill/SkillDetailView.js.map +1 -1
  420. package/skill/SkillDiffDialog.d.ts +42 -0
  421. package/skill/SkillDiffDialog.d.ts.map +1 -0
  422. package/skill/SkillDiffDialog.js +72 -0
  423. package/skill/SkillDiffDialog.js.map +1 -0
  424. package/skill/SkillFileBrowser.d.ts +31 -0
  425. package/skill/SkillFileBrowser.d.ts.map +1 -0
  426. package/skill/SkillFileBrowser.js +105 -0
  427. package/skill/SkillFileBrowser.js.map +1 -0
  428. package/skill/SkillUploader.d.ts +39 -0
  429. package/skill/SkillUploader.d.ts.map +1 -0
  430. package/skill/SkillUploader.js +141 -0
  431. package/skill/SkillUploader.js.map +1 -0
  432. package/skill/index.d.ts +18 -0
  433. package/skill/index.d.ts.map +1 -1
  434. package/skill/index.js +9 -0
  435. package/skill/index.js.map +1 -1
  436. package/skill/internal/computeArtifactHash.d.ts +9 -0
  437. package/skill/internal/computeArtifactHash.d.ts.map +1 -0
  438. package/skill/internal/computeArtifactHash.js +14 -0
  439. package/skill/internal/computeArtifactHash.js.map +1 -0
  440. package/skill/internal/fetchAndUnpackArtifact.d.ts +16 -0
  441. package/skill/internal/fetchAndUnpackArtifact.d.ts.map +1 -0
  442. package/skill/internal/fetchAndUnpackArtifact.js +34 -0
  443. package/skill/internal/fetchAndUnpackArtifact.js.map +1 -0
  444. package/skill/usePushSkill.d.ts +53 -0
  445. package/skill/usePushSkill.d.ts.map +1 -0
  446. package/skill/usePushSkill.js +57 -0
  447. package/skill/usePushSkill.js.map +1 -0
  448. package/skill/useSkillArtifact.d.ts +37 -0
  449. package/skill/useSkillArtifact.d.ts.map +1 -0
  450. package/skill/useSkillArtifact.js +76 -0
  451. package/skill/useSkillArtifact.js.map +1 -0
  452. package/skill/useSkillDiff.d.ts +31 -0
  453. package/skill/useSkillDiff.d.ts.map +1 -0
  454. package/skill/useSkillDiff.js +97 -0
  455. package/skill/useSkillDiff.js.map +1 -0
  456. package/skill/useSkillDuplicateCheck.d.ts +34 -0
  457. package/skill/useSkillDuplicateCheck.d.ts.map +1 -0
  458. package/skill/useSkillDuplicateCheck.js +58 -0
  459. package/skill/useSkillDuplicateCheck.js.map +1 -0
  460. package/skill/useSkillUpload.d.ts +69 -0
  461. package/skill/useSkillUpload.d.ts.map +1 -0
  462. package/skill/useSkillUpload.js +157 -0
  463. package/skill/useSkillUpload.js.map +1 -0
  464. package/skill/useSkillVersions.d.ts +46 -0
  465. package/skill/useSkillVersions.d.ts.map +1 -0
  466. package/skill/useSkillVersions.js +104 -0
  467. package/skill/useSkillVersions.js.map +1 -0
  468. package/src/action-menu/ActionMenu.tsx +151 -0
  469. package/src/action-menu/index.ts +9 -0
  470. package/src/action-menu/types.ts +70 -0
  471. package/src/agent/AgentCreationWizard.tsx +201 -0
  472. package/src/agent/AgentDetailView.tsx +817 -321
  473. package/src/agent/index.ts +16 -0
  474. package/src/agent/internal/agentToInput.ts +95 -0
  475. package/src/agent/steps/CapabilitiesStep.tsx +363 -0
  476. package/src/agent/steps/IdentityStep.tsx +259 -0
  477. package/src/agent/steps/ReviewStep.tsx +211 -0
  478. package/src/agent/steps/types.ts +53 -0
  479. package/src/agent/useCreateAgent.ts +76 -0
  480. package/src/agent/useUpdateAgent.ts +55 -0
  481. package/src/dependency-graph/DependencyGraph.tsx +153 -0
  482. package/src/dependency-graph/DependencyTreeNode.tsx +282 -0
  483. package/src/dependency-graph/index.ts +15 -0
  484. package/src/dependency-graph/types.ts +131 -0
  485. package/src/dependency-graph/useDependencyGraph.ts +158 -0
  486. package/src/empty-state/EmptyState.tsx +90 -0
  487. package/src/empty-state/index.ts +9 -0
  488. package/src/empty-state/types.ts +81 -0
  489. package/src/empty-state/useEmptyState.ts +85 -0
  490. package/src/execution/MessageThread.tsx +26 -15
  491. package/src/execution/SetupProgress.tsx +35 -14
  492. package/src/execution/__tests__/thread-keys.test.ts +101 -0
  493. package/src/feedback/StigmerToaster.tsx +45 -0
  494. package/src/feedback/index.ts +3 -0
  495. package/src/feedback/toast.ts +13 -0
  496. package/src/feedback/types.ts +7 -0
  497. package/src/index.ts +270 -8
  498. package/src/inline-edit/InlineEditImage.tsx +208 -0
  499. package/src/inline-edit/InlineEditKeyValue.tsx +278 -0
  500. package/src/inline-edit/InlineEditResourceList.tsx +325 -0
  501. package/src/inline-edit/InlineEditSelect.tsx +150 -0
  502. package/src/inline-edit/InlineEditText.tsx +211 -0
  503. package/src/inline-edit/InlineEditTextarea.tsx +209 -0
  504. package/src/inline-edit/index.ts +28 -0
  505. package/src/inline-edit/types.ts +47 -0
  506. package/src/inline-edit/useInlineFieldSave.ts +62 -0
  507. package/src/internal/Tabs.tsx +4 -164
  508. package/src/library/ImportResourceDialog.tsx +227 -0
  509. package/src/library/index.ts +18 -8
  510. package/src/library/serialize-resource-yaml.ts +356 -0
  511. package/src/library/useExportResource.ts +183 -0
  512. package/src/library/useImportResource.ts +253 -0
  513. package/src/mcp-server/McpServerCreationWizard.tsx +206 -0
  514. package/src/mcp-server/McpServerDetailView.tsx +392 -105
  515. package/src/mcp-server/index.ts +16 -0
  516. package/src/mcp-server/internal/mcpServerToInput.ts +95 -0
  517. package/src/mcp-server/steps/EnvironmentAuthStep.tsx +462 -0
  518. package/src/mcp-server/steps/IdentityTransportStep.tsx +531 -0
  519. package/src/mcp-server/steps/ReviewStep.tsx +297 -0
  520. package/src/mcp-server/steps/types.ts +85 -0
  521. package/src/mcp-server/useCreateMcpServer.ts +76 -0
  522. package/src/mcp-server/useUpdateMcpServer.ts +55 -0
  523. package/src/models/registry.ts +10 -2
  524. package/src/provider.tsx +1 -1
  525. package/src/resource-creation/CreationPicker.tsx +292 -0
  526. package/src/resource-creation/StepIndicator.tsx +156 -0
  527. package/src/resource-creation/TemplateCard.tsx +143 -0
  528. package/src/resource-creation/TemplateGallery.tsx +222 -0
  529. package/src/resource-creation/WizardNav.tsx +163 -0
  530. package/src/resource-creation/WizardShell.tsx +124 -0
  531. package/src/resource-creation/index.ts +45 -0
  532. package/src/resource-creation/templates/agent-templates.ts +160 -0
  533. package/src/resource-creation/templates/index.ts +7 -0
  534. package/src/resource-creation/templates/mcp-server-templates.ts +106 -0
  535. package/src/resource-creation/templates/types.ts +64 -0
  536. package/src/resource-creation/types.ts +105 -0
  537. package/src/resource-creation/useTemplateFilter.ts +117 -0
  538. package/src/resource-creation/useWizardState.ts +223 -0
  539. package/src/resource-detail/ConfirmDialog.tsx +127 -0
  540. package/src/resource-detail/ResourceActionBar.tsx +157 -0
  541. package/src/resource-detail/ResourceDetailShell.tsx +184 -0
  542. package/src/resource-detail/Section.tsx +78 -0
  543. package/src/resource-detail/index.ts +34 -0
  544. package/src/resource-detail/types.ts +177 -0
  545. package/src/resource-detail/useConfirmAction.ts +70 -0
  546. package/src/resource-detail/useCopyResource.ts +74 -0
  547. package/src/resource-detail/useDeleteResource.ts +110 -0
  548. package/src/resource-detail/useDetailTabs.ts +93 -0
  549. package/src/resource-workbench/components/BulkActionBar.tsx +122 -0
  550. package/src/resource-workbench/components/ColumnHeader.tsx +105 -0
  551. package/src/resource-workbench/components/FilterBar.tsx +173 -0
  552. package/src/resource-workbench/components/ResourceAvatar.tsx +109 -0
  553. package/src/resource-workbench/components/ResourceCards.tsx +126 -0
  554. package/src/resource-workbench/components/ResourceInspector.tsx +88 -0
  555. package/src/resource-workbench/components/ResourceList.tsx +121 -0
  556. package/src/resource-workbench/components/ResourceTable.tsx +222 -0
  557. package/src/resource-workbench/components/ResourceWorkbench.tsx +695 -0
  558. package/src/resource-workbench/components/SelectionCheckbox.tsx +52 -0
  559. package/src/resource-workbench/components/StatusBadge.tsx +119 -0
  560. package/src/resource-workbench/components/ViewSwitcher.tsx +135 -0
  561. package/src/resource-workbench/hooks/useResourceCollection.ts +261 -0
  562. package/src/resource-workbench/hooks/useResourceFilters.ts +216 -0
  563. package/src/resource-workbench/hooks/useResourceSelection.ts +178 -0
  564. package/src/resource-workbench/hooks/useViewPreference.ts +75 -0
  565. package/src/resource-workbench/index.ts +73 -0
  566. package/src/resource-workbench/types.ts +220 -0
  567. package/src/runner/RunnerDetailView.tsx +410 -0
  568. package/src/runner/RunnerListPanel.tsx +126 -111
  569. package/src/runner/index.ts +13 -1
  570. package/src/runner/shared.tsx +124 -0
  571. package/src/runner/useRunner.ts +59 -0
  572. package/src/session/__tests__/group-sessions.test.ts +5 -3
  573. package/src/skill/SkillDetailView.tsx +371 -165
  574. package/src/skill/SkillDiffDialog.tsx +213 -0
  575. package/src/skill/SkillFileBrowser.tsx +289 -0
  576. package/src/skill/SkillUploader.tsx +481 -0
  577. package/src/skill/index.ts +34 -0
  578. package/src/skill/internal/computeArtifactHash.ts +13 -0
  579. package/src/skill/internal/fetchAndUnpackArtifact.ts +48 -0
  580. package/src/skill/usePushSkill.ts +101 -0
  581. package/src/skill/useSkillArtifact.ts +107 -0
  582. package/src/skill/useSkillDiff.ts +128 -0
  583. package/src/skill/useSkillDuplicateCheck.ts +92 -0
  584. package/src/skill/useSkillUpload.ts +231 -0
  585. package/src/skill/useSkillVersions.ts +165 -0
  586. package/src/styles.css +28 -0
  587. package/src/tabs/Tabs.tsx +184 -0
  588. package/src/tabs/index.ts +2 -0
  589. package/src/version-history/DiffFileList.tsx +111 -0
  590. package/src/version-history/DiffSummary.tsx +61 -0
  591. package/src/version-history/DiffViewer.tsx +163 -0
  592. package/src/version-history/MultiFileDiffView.tsx +114 -0
  593. package/src/version-history/VersionTimeline.tsx +232 -0
  594. package/src/version-history/VersionTimelineEntry.tsx +254 -0
  595. package/src/version-history/computeDiff.ts +61 -0
  596. package/src/version-history/computeMultiFileDiff.ts +97 -0
  597. package/src/version-history/index.ts +22 -0
  598. package/src/version-history/types.ts +129 -0
  599. package/styles.css +1 -1
  600. package/tabs/Tabs.d.ts +58 -0
  601. package/tabs/Tabs.d.ts.map +1 -0
  602. package/tabs/Tabs.js +80 -0
  603. package/tabs/Tabs.js.map +1 -0
  604. package/tabs/index.d.ts +3 -0
  605. package/tabs/index.d.ts.map +1 -0
  606. package/tabs/index.js +2 -0
  607. package/tabs/index.js.map +1 -0
  608. package/version-history/DiffFileList.d.ts +22 -0
  609. package/version-history/DiffFileList.d.ts.map +1 -0
  610. package/version-history/DiffFileList.js +37 -0
  611. package/version-history/DiffFileList.js.map +1 -0
  612. package/version-history/DiffSummary.d.ts +21 -0
  613. package/version-history/DiffSummary.d.ts.map +1 -0
  614. package/version-history/DiffSummary.js +16 -0
  615. package/version-history/DiffSummary.js.map +1 -0
  616. package/version-history/DiffViewer.d.ts +31 -0
  617. package/version-history/DiffViewer.d.ts.map +1 -0
  618. package/version-history/DiffViewer.js +60 -0
  619. package/version-history/DiffViewer.js.map +1 -0
  620. package/version-history/MultiFileDiffView.d.ts +30 -0
  621. package/version-history/MultiFileDiffView.d.ts.map +1 -0
  622. package/version-history/MultiFileDiffView.js +40 -0
  623. package/version-history/MultiFileDiffView.js.map +1 -0
  624. package/version-history/VersionTimeline.d.ts +29 -0
  625. package/version-history/VersionTimeline.d.ts.map +1 -0
  626. package/version-history/VersionTimeline.js +87 -0
  627. package/version-history/VersionTimeline.js.map +1 -0
  628. package/version-history/VersionTimelineEntry.d.ts +22 -0
  629. package/version-history/VersionTimelineEntry.d.ts.map +1 -0
  630. package/version-history/VersionTimelineEntry.js +98 -0
  631. package/version-history/VersionTimelineEntry.js.map +1 -0
  632. package/version-history/computeDiff.d.ts +16 -0
  633. package/version-history/computeDiff.d.ts.map +1 -0
  634. package/version-history/computeDiff.js +54 -0
  635. package/version-history/computeDiff.js.map +1 -0
  636. package/version-history/computeMultiFileDiff.d.ts +15 -0
  637. package/version-history/computeMultiFileDiff.d.ts.map +1 -0
  638. package/version-history/computeMultiFileDiff.js +83 -0
  639. package/version-history/computeMultiFileDiff.js.map +1 -0
  640. package/version-history/index.d.ts +14 -0
  641. package/version-history/index.d.ts.map +1 -0
  642. package/version-history/index.js +9 -0
  643. package/version-history/index.js.map +1 -0
  644. package/version-history/types.d.ts +106 -0
  645. package/version-history/types.d.ts.map +1 -0
  646. package/version-history/types.js +2 -0
  647. package/version-history/types.js.map +1 -0
  648. package/library/ResourceListView.d.ts +0 -174
  649. package/library/ResourceListView.d.ts.map +0 -1
  650. package/library/ResourceListView.js +0 -318
  651. package/library/ResourceListView.js.map +0 -1
  652. package/src/library/ResourceListView.tsx +0 -956
@@ -1,9 +1,8 @@
1
1
  "use client";
2
2
 
3
- import { useEffect, useRef, useState } from "react";
3
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { cn } from "@stigmer/theme";
5
5
  import { timestampDate } from "@bufbuild/protobuf/wkt";
6
- import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
7
6
  import type {
8
7
  McpServerUsage,
9
8
  SubAgent,
@@ -12,10 +11,28 @@ import type { ApiResourceReference } from "@stigmer/protos/ai/stigmer/commons/ap
12
11
  import type { EnvVarDeclaration } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/spec_pb";
13
12
  import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
14
13
  import { useAgent } from "./useAgent";
14
+ import { useUpdateAgent } from "./useUpdateAgent";
15
+ import { agentToInput } from "./internal/agentToInput";
15
16
  import { ErrorMessage } from "../error/ErrorMessage";
16
17
  import { VisibilityToggle } from "../library/VisibilityToggle";
18
+ import { ResourceDetailShell } from "../resource-detail/ResourceDetailShell";
19
+ import { Section } from "../resource-detail/Section";
20
+ import { useDetailTabs } from "../resource-detail/useDetailTabs";
21
+ import type { AdditionalTab, DetailAction, ResourceHeaderMeta } from "../resource-detail/types";
22
+ import type { TabItem } from "../tabs/Tabs";
23
+ import { DependencyGraph } from "../dependency-graph/DependencyGraph";
24
+ import { useDependencyGraph } from "../dependency-graph/useDependencyGraph";
25
+ import type { DependencyNode } from "../dependency-graph/types";
26
+ import { InlineEditTextarea } from "../inline-edit/InlineEditTextarea";
27
+ import { InlineEditImage } from "../inline-edit/InlineEditImage";
28
+ import { InlineEditKeyValue } from "../inline-edit/InlineEditKeyValue";
29
+ import { InlineEditResourceList } from "../inline-edit/InlineEditResourceList";
30
+ import type { KeyValueRow, ResourceRefRow } from "../inline-edit/types";
17
31
 
18
- const INSTRUCTIONS_COLLAPSED_LINES = 8;
32
+ const INSTRUCTIONS_COLLAPSED_HEIGHT = "12rem";
33
+
34
+ const OVERVIEW_TAB: TabItem = { id: "overview", label: "Overview" };
35
+ const DEPENDENCIES_TAB: TabItem = { id: "dependencies", label: "Dependencies" };
19
36
 
20
37
  /** Props for {@link AgentDetailView}. */
21
38
  export interface AgentDetailViewProps {
@@ -53,18 +70,80 @@ export interface AgentDetailViewProps {
53
70
  readonly onVisibilityChange?: (v: ApiResourceVisibility) => void;
54
71
  /** `true` while a visibility update RPC is in flight. */
55
72
  readonly isVisibilityPending?: boolean;
73
+ /**
74
+ * Primary action rendered as a visible button in the header area.
75
+ * Typically "Edit" for agent detail pages.
76
+ */
77
+ readonly primaryAction?: DetailAction;
78
+ /**
79
+ * Secondary actions rendered in the kebab overflow menu.
80
+ * Typically: Copy ID, Copy slug, Export JSON, Duplicate, Delete.
81
+ */
82
+ readonly actions?: readonly DetailAction[];
83
+ /**
84
+ * Additional tabs to render alongside the built-in "Overview" tab.
85
+ * When provided (with at least one entry), a tab bar appears.
86
+ * When omitted or empty, no tab bar is shown (single-tab suppression).
87
+ *
88
+ * Each entry provides both the tab metadata and the content to render.
89
+ * The SDK manages the tab switching logic internally.
90
+ *
91
+ * @example
92
+ * ```tsx
93
+ * <AgentDetailView
94
+ * org="acme"
95
+ * slug="my-agent"
96
+ * additionalTabs={[
97
+ * { id: "dependencies", label: "Dependencies", content: <DependencyGraph /> },
98
+ * ]}
99
+ * />
100
+ * ```
101
+ */
102
+ readonly additionalTabs?: readonly AdditionalTab[];
103
+ /**
104
+ * Controlled active tab ID. When provided together with `onTabChange`,
105
+ * the component operates in controlled mode — the consumer owns tab state.
106
+ * When omitted, the component manages its own internal tab state.
107
+ */
108
+ readonly activeTab?: string;
109
+ /**
110
+ * Controlled tab change handler. When provided together with `activeTab`,
111
+ * the component operates in controlled mode.
112
+ */
113
+ readonly onTabChange?: (tabId: string) => void;
114
+ /**
115
+ * Default active tab ID when in uncontrolled mode.
116
+ * @default "overview"
117
+ */
118
+ readonly defaultTab?: string;
119
+ /**
120
+ * When `true`, fields on the detail view become click-to-edit.
121
+ * Each field saves independently via `stigmer.agent.update()`.
122
+ * @default false
123
+ */
124
+ readonly editable?: boolean;
125
+ /**
126
+ * Called after a successful inline field save with the updated agent.
127
+ * Consumers can use this to refresh breadcrumbs, sync URL state, etc.
128
+ */
129
+ readonly onResourceUpdated?: (agent: import("@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb").Agent) => void;
56
130
  /** Additional CSS classes for the root container. */
57
131
  readonly className?: string;
58
132
  }
59
133
 
60
134
  /**
61
- * Read-only detail view for an Agent blueprint.
135
+ * Operational detail hub for an Agent blueprint.
62
136
  *
63
137
  * Fetches the agent via {@link useAgent} internally and renders its
64
- * full configuration in structured sections: header, instructions,
65
- * MCP server usages, skills, sub-agents, and environment variables.
66
- * Sections with no data are omitted entirely — reducing visual noise
67
- * per the aesthetic-minimalist design heuristic (Nielsen #8).
138
+ * full configuration inside a {@link ResourceDetailShell}: a
139
+ * standardized header with action bar, followed by structured content
140
+ * sections (instructions, MCP server usages, skills, sub-agents, and
141
+ * environment variables). Sections with no data are omitted entirely
142
+ * — reducing visual noise per Nielsen heuristic #8.
143
+ *
144
+ * The action bar transforms this from a read-only view into an
145
+ * operational hub. Actions are provided by the consumer via
146
+ * `primaryAction` and `actions` props.
68
147
  *
69
148
  * Handles loading, error, and not-found states automatically.
70
149
  * Zero Console dependencies — safe for platform builder embedding.
@@ -78,12 +157,17 @@ export interface AgentDetailViewProps {
78
157
  *
79
158
  * @example
80
159
  * ```tsx
81
- * // With cross-resource linking in a Console page
160
+ * // Operational hub with actions in a Console page
82
161
  * <AgentDetailView
83
162
  * org={org}
84
163
  * slug={slug}
85
- * onMcpServerClick={({ org, slug }) => router.push(`/library/mcp-servers/${org}/${slug}`)}
86
- * onSkillClick={({ org, slug }) => router.push(`/library/skills/${org}/${slug}`)}
164
+ * primaryAction={{ id: "edit", label: "Edit", onAction: handleEdit }}
165
+ * actions={[
166
+ * { id: "copy-id", label: "Copy ID", onAction: () => copyId(id) },
167
+ * { id: "delete", label: "Delete", variant: "destructive", onAction: handleDelete },
168
+ * ]}
169
+ * onMcpServerClick={({ org, slug }) => navigateToDetail("mcp-servers", org, slug)}
170
+ * onSkillClick={({ org, slug }) => navigateToDetail("skills", org, slug)}
87
171
  * />
88
172
  * ```
89
173
  */
@@ -95,9 +179,74 @@ export function AgentDetailView({
95
179
  onResourceLoad,
96
180
  onVisibilityChange,
97
181
  isVisibilityPending,
182
+ primaryAction,
183
+ actions,
184
+ additionalTabs,
185
+ activeTab,
186
+ onTabChange,
187
+ defaultTab,
188
+ editable = false,
189
+ onResourceUpdated,
98
190
  className,
99
191
  }: AgentDetailViewProps) {
100
192
  const { agent, isLoading, error, refetch } = useAgent(org, slug);
193
+ const { update, isUpdating } = useUpdateAgent();
194
+
195
+ const saveField = useCallback(
196
+ async <K extends keyof import("@stigmer/sdk").AgentInput>(
197
+ field: K,
198
+ value: import("@stigmer/sdk").AgentInput[K],
199
+ ): Promise<boolean> => {
200
+ if (!agent) return false;
201
+ const input = agentToInput(agent);
202
+ (input as unknown as Record<string, unknown>)[field] = value;
203
+ try {
204
+ const updated = await update(input);
205
+ onResourceUpdated?.(updated);
206
+ refetch();
207
+ return true;
208
+ } catch {
209
+ return false;
210
+ }
211
+ },
212
+ [agent, update, onResourceUpdated, refetch],
213
+ );
214
+
215
+ const { tree, isEmpty: noDeps } = useDependencyGraph({
216
+ agentName: agent?.metadata?.name || agent?.metadata?.slug || slug,
217
+ agentOrg: agent?.metadata?.org || org,
218
+ spec: agent?.spec,
219
+ });
220
+
221
+ const builtInTabs = useMemo<readonly TabItem[]>(
222
+ () => (noDeps ? [OVERVIEW_TAB] : [OVERVIEW_TAB, DEPENDENCIES_TAB]),
223
+ [noDeps],
224
+ );
225
+
226
+ const {
227
+ effectiveTabs,
228
+ effectiveActiveTab,
229
+ effectiveOnTabChange,
230
+ activeAdditionalTab,
231
+ } = useDetailTabs({
232
+ builtInTabs,
233
+ additionalTabs,
234
+ activeTab,
235
+ onTabChange,
236
+ defaultTab,
237
+ });
238
+
239
+ const handleNodeClick = useCallback(
240
+ (node: DependencyNode) => {
241
+ if (!node.ref) return;
242
+ if (node.kind === "mcp-server") {
243
+ onMcpServerClick?.(node.ref);
244
+ } else if (node.kind === "skill") {
245
+ onSkillClick?.(node.ref);
246
+ }
247
+ },
248
+ [onMcpServerClick, onSkillClick],
249
+ );
101
250
 
102
251
  const onResourceLoadRef = useRef(onResourceLoad);
103
252
  onResourceLoadRef.current = onResourceLoad;
@@ -113,165 +262,374 @@ export function AgentDetailView({
113
262
  return <ErrorMessage error={error} retry={refetch} className={className} />;
114
263
  if (!agent) return <NotFoundState className={className} />;
115
264
 
265
+ const meta = agent.metadata;
116
266
  const spec = agent.spec;
117
267
  const specAudit = agent.status?.audit?.specAudit;
118
- const agentOrg = agent.metadata?.org || org;
268
+ const agentOrg = meta?.org || org;
119
269
 
120
- return (
121
- <div className={cn("flex flex-col gap-6", className)}>
122
- <Header
123
- agent={agent}
124
- createdAt={
125
- specAudit?.createdAt ? timestampDate(specAudit.createdAt) : null
126
- }
127
- updatedAt={
128
- specAudit?.updatedAt ? timestampDate(specAudit.updatedAt) : null
129
- }
130
- onVisibilityChange={onVisibilityChange}
131
- isVisibilityPending={isVisibilityPending}
132
- />
133
-
134
- {spec?.instructions && (
135
- <InstructionsSection text={spec.instructions} />
136
- )}
137
-
138
- {spec && spec.mcpServerUsages.length > 0 && (
139
- <McpUsagesSection
140
- usages={spec.mcpServerUsages}
141
- defaultOrg={agentOrg}
142
- onMcpServerClick={onMcpServerClick}
270
+ const headerMeta: ResourceHeaderMeta = {
271
+ name: meta?.name || meta?.slug || "Untitled",
272
+ id: meta?.id || "",
273
+ org: meta?.org,
274
+ slug: meta?.slug,
275
+ description: undefined,
276
+ iconUrl: editable ? undefined : spec?.iconUrl,
277
+ icon: editable
278
+ ? (
279
+ <InlineEditImage
280
+ value={spec?.iconUrl ?? ""}
281
+ onSave={(v) => saveField("iconUrl", v || undefined)}
282
+ isSaving={isUpdating}
283
+ fallback={<AgentIcon className="size-6 text-muted-foreground" />}
284
+ disabled={!editable}
143
285
  />
144
- )}
286
+ )
287
+ : spec?.iconUrl ? undefined : <AgentIcon className="size-6 text-muted-foreground" />,
288
+ createdAt: specAudit?.createdAt ? timestampDate(specAudit.createdAt) : null,
289
+ updatedAt: specAudit?.updatedAt ? timestampDate(specAudit.updatedAt) : null,
290
+ };
145
291
 
146
- {spec && spec.skillRefs.length > 0 && (
147
- <SkillsSection
148
- refs={spec.skillRefs}
149
- defaultOrg={agentOrg}
150
- onSkillClick={onSkillClick}
151
- />
152
- )}
292
+ const isPublic = meta?.visibility === ApiResourceVisibility.visibility_public;
293
+ const visibilityControl =
294
+ onVisibilityChange && meta ? (
295
+ <VisibilityToggle
296
+ visibility={meta.visibility}
297
+ onVisibilityChange={onVisibilityChange}
298
+ isPending={isVisibilityPending}
299
+ />
300
+ ) : isPublic ? (
301
+ <span className="shrink-0 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
302
+ Public
303
+ </span>
304
+ ) : undefined;
153
305
 
154
- {spec && spec.subAgents.length > 0 && (
155
- <SubAgentsSection subAgents={spec.subAgents} />
156
- )}
306
+ let tabContent: React.ReactNode;
307
+ if (activeAdditionalTab) {
308
+ tabContent = activeAdditionalTab.content;
309
+ } else if (effectiveActiveTab === "dependencies" && tree) {
310
+ tabContent = (
311
+ <DependencyGraph
312
+ tree={tree}
313
+ onNodeClick={handleNodeClick}
314
+ />
315
+ );
316
+ } else {
317
+ tabContent = (
318
+ <AgentOverview
319
+ spec={spec}
320
+ agentOrg={agentOrg}
321
+ description={spec?.description}
322
+ onMcpServerClick={onMcpServerClick}
323
+ onSkillClick={onSkillClick}
324
+ editable={editable}
325
+ isSaving={isUpdating}
326
+ saveField={saveField}
327
+ />
328
+ );
329
+ }
157
330
 
158
- {spec?.env && Object.keys(spec.env).length > 0 && (
159
- <EnvSection data={spec.env} />
160
- )}
161
- </div>
331
+ return (
332
+ <ResourceDetailShell
333
+ header={headerMeta}
334
+ visibilityControl={visibilityControl}
335
+ primaryAction={primaryAction}
336
+ actions={actions}
337
+ tabs={effectiveTabs}
338
+ activeTab={effectiveTabs ? effectiveActiveTab : undefined}
339
+ onTabChange={effectiveTabs ? effectiveOnTabChange : undefined}
340
+ tabsAriaLabel="Agent detail sections"
341
+ className={className}
342
+ >
343
+ {tabContent}
344
+ </ResourceDetailShell>
162
345
  );
163
346
  }
164
347
 
165
348
  // ---------------------------------------------------------------------------
166
- // Internal section components
349
+ // Overview content — the agent's configuration sections
167
350
  // ---------------------------------------------------------------------------
168
351
 
169
- function Header({
170
- agent,
171
- createdAt,
172
- updatedAt,
173
- onVisibilityChange,
174
- isVisibilityPending,
352
+ function AgentOverview({
353
+ spec,
354
+ agentOrg,
355
+ description,
356
+ onMcpServerClick,
357
+ onSkillClick,
358
+ editable,
359
+ isSaving,
360
+ saveField,
175
361
  }: {
176
- readonly agent: Agent;
177
- readonly createdAt: Date | null;
178
- readonly updatedAt: Date | null;
179
- readonly onVisibilityChange?: (v: ApiResourceVisibility) => void;
180
- readonly isVisibilityPending?: boolean;
362
+ readonly spec: NonNullable<ReturnType<typeof useAgent>["agent"]>["spec"];
363
+ readonly agentOrg: string;
364
+ readonly description?: string;
365
+ readonly onMcpServerClick?: (ref: { org: string; slug: string }) => void;
366
+ readonly onSkillClick?: (ref: { org: string; slug: string }) => void;
367
+ readonly editable?: boolean;
368
+ readonly isSaving?: boolean;
369
+ readonly saveField?: <K extends keyof import("@stigmer/sdk").AgentInput>(
370
+ field: K,
371
+ value: import("@stigmer/sdk").AgentInput[K],
372
+ ) => Promise<boolean>;
181
373
  }) {
182
- const meta = agent.metadata;
183
- const spec = agent.spec;
184
- const displayName = meta?.name || meta?.slug || "Untitled";
185
- const isPublic =
186
- meta?.visibility === ApiResourceVisibility.visibility_public;
374
+ const handleInstructionsSave = useCallback(
375
+ async (v: string) => saveField?.("instructions", v || undefined) ?? false,
376
+ [saveField],
377
+ );
378
+
379
+ const handleMcpServersSave = useCallback(
380
+ async (refs: ResourceRefRow[]) =>
381
+ saveField?.(
382
+ "mcpServerUsages",
383
+ refs.map((r) => ({
384
+ mcpServerRef: { org: r.org, slug: r.slug },
385
+ })),
386
+ ) ?? false,
387
+ [saveField],
388
+ );
389
+
390
+ const handleSkillsSave = useCallback(
391
+ async (refs: ResourceRefRow[]) =>
392
+ saveField?.(
393
+ "skillRefs",
394
+ refs.map((r) => ({ org: r.org, slug: r.slug })),
395
+ ) ?? false,
396
+ [saveField],
397
+ );
398
+
399
+ const handleEnvSave = useCallback(
400
+ async (rows: KeyValueRow[]) => {
401
+ const env: Record<string, { isSecret?: boolean; description?: string; optional?: boolean }> = {};
402
+ for (const row of rows) {
403
+ if (row.key.trim()) {
404
+ env[row.key.trim()] = {
405
+ isSecret: row.isSecret || undefined,
406
+ description: row.description || undefined,
407
+ optional: row.optional || undefined,
408
+ };
409
+ }
410
+ }
411
+ return saveField?.("env", Object.keys(env).length > 0 ? env : undefined) ?? false;
412
+ },
413
+ [saveField],
414
+ );
415
+
416
+ const mcpRefRows: ResourceRefRow[] = useMemo(
417
+ () =>
418
+ (spec?.mcpServerUsages ?? []).map((u) => ({
419
+ org: u.mcpServerRef?.org || agentOrg,
420
+ slug: u.mcpServerRef?.slug ?? "",
421
+ label:
422
+ u.mcpServerRef?.org && u.mcpServerRef.org !== agentOrg
423
+ ? `${u.mcpServerRef.org}/${u.mcpServerRef.slug}`
424
+ : u.mcpServerRef?.slug ?? "",
425
+ })),
426
+ [spec?.mcpServerUsages, agentOrg],
427
+ );
428
+
429
+ const skillRefRows: ResourceRefRow[] = useMemo(
430
+ () =>
431
+ (spec?.skillRefs ?? []).map((ref) => ({
432
+ org: ref.org || agentOrg,
433
+ slug: ref.slug,
434
+ label:
435
+ ref.org && ref.org !== agentOrg
436
+ ? `${ref.org}/${ref.slug}`
437
+ : ref.slug,
438
+ })),
439
+ [spec?.skillRefs, agentOrg],
440
+ );
441
+
442
+ const envRows: KeyValueRow[] = useMemo(
443
+ () =>
444
+ Object.entries(spec?.env ?? {})
445
+ .sort(([a], [b]) => a.localeCompare(b))
446
+ .map(([key, decl]) => ({
447
+ key,
448
+ value: "",
449
+ isSecret: decl.isSecret,
450
+ description: decl.description,
451
+ optional: decl.optional,
452
+ })),
453
+ [spec?.env],
454
+ );
455
+
456
+ const showDescription = editable || !!description;
457
+ const showInstructions = editable || !!spec?.instructions;
458
+ const showMcpServers = editable || (spec && spec.mcpServerUsages.length > 0);
459
+ const showSkills = editable || (spec && spec.skillRefs.length > 0);
460
+ const showSubAgents = editable || (spec && spec.subAgents.length > 0);
461
+ const showEnv = editable || (spec?.env && Object.keys(spec.env).length > 0);
462
+
463
+ const [mcpEditing, setMcpEditing] = useState(false);
464
+ const [skillsEditing, setSkillsEditing] = useState(false);
465
+ const [envEditing, setEnvEditing] = useState(false);
187
466
 
188
467
  return (
189
- <div className="flex items-start gap-3">
190
- {spec?.iconUrl ? (
191
- <img
192
- src={spec.iconUrl}
193
- alt=""
194
- className="mt-0.5 size-8 shrink-0 rounded object-cover"
195
- />
196
- ) : (
197
- <AgentIcon className="mt-1 size-6 shrink-0 text-muted-foreground" />
468
+ <div className="flex flex-col gap-6">
469
+ {showDescription && (
470
+ <Section title="Description">
471
+ {editable ? (
472
+ <div className="max-h-20 overflow-y-auto p-3">
473
+ <InlineEditTextarea
474
+ value={spec?.description || ""}
475
+ onSave={(v) => saveField?.("description", v || undefined) ?? Promise.resolve(false)}
476
+ isSaving={isSaving}
477
+ placeholder="Add a description"
478
+ minRows={2}
479
+ />
480
+ </div>
481
+ ) : (
482
+ <div className="p-3">
483
+ <pre className="whitespace-pre-wrap break-words text-sm text-foreground font-sans">
484
+ {description}
485
+ </pre>
486
+ </div>
487
+ )}
488
+ </Section>
198
489
  )}
199
- <div className="min-w-0 flex-1">
200
- <div className="flex items-center gap-2">
201
- <h2 className="truncate text-lg font-semibold text-foreground">
202
- {displayName}
203
- </h2>
204
- {onVisibilityChange && meta ? (
205
- <VisibilityToggle
206
- visibility={meta.visibility}
207
- onVisibilityChange={onVisibilityChange}
208
- isPending={isVisibilityPending}
490
+
491
+ {showInstructions && (
492
+ <Section title="Instructions">
493
+ {editable ? (
494
+ <div className="max-h-72 overflow-y-auto p-3">
495
+ <InlineEditTextarea
496
+ value={spec?.instructions ?? ""}
497
+ onSave={handleInstructionsSave}
498
+ isSaving={isSaving}
499
+ placeholder="Add instructions for the agent"
500
+ minRows={4}
501
+ />
502
+ </div>
503
+ ) : (
504
+ <InstructionsContent text={spec?.instructions ?? ""} />
505
+ )}
506
+ </Section>
507
+ )}
508
+
509
+ {showMcpServers && (
510
+ <Section title="MCP Servers" count={spec?.mcpServerUsages.length} onEdit={editable ? () => setMcpEditing((v) => !v) : undefined}>
511
+ {editable ? (
512
+ <InlineEditResourceList
513
+ value={mcpRefRows}
514
+ onSave={handleMcpServersSave}
515
+ isSaving={isSaving}
516
+ editing={mcpEditing}
517
+ onEditingChange={setMcpEditing}
518
+ onItemClick={onMcpServerClick ? (ref) => onMcpServerClick({ org: ref.org, slug: ref.slug }) : undefined}
519
+ itemIcon={<McpServerIcon className="size-4" />}
520
+ resourceLabel="MCP server"
521
+ defaultOrg={agentOrg}
209
522
  />
210
523
  ) : (
211
- isPublic && (
212
- <span className="shrink-0 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
213
- Public
214
- </span>
215
- )
524
+ <McpUsagesContent
525
+ usages={spec?.mcpServerUsages ?? []}
526
+ defaultOrg={agentOrg}
527
+ onMcpServerClick={onMcpServerClick}
528
+ />
216
529
  )}
217
- </div>
218
- <div className="mt-0.5 flex flex-wrap items-center gap-x-1.5 text-xs text-muted-foreground">
219
- {meta?.org && <span>{meta.org}</span>}
220
- {createdAt && (
221
- <>
222
- <Dot />
223
- <span>Created {formatDate(createdAt)}</span>
224
- </>
530
+ </Section>
531
+ )}
532
+
533
+ {showSkills && (
534
+ <Section title="Skills" count={spec?.skillRefs.length} onEdit={editable ? () => setSkillsEditing((v) => !v) : undefined}>
535
+ {editable ? (
536
+ <InlineEditResourceList
537
+ value={skillRefRows}
538
+ onSave={handleSkillsSave}
539
+ isSaving={isSaving}
540
+ editing={skillsEditing}
541
+ onEditingChange={setSkillsEditing}
542
+ onItemClick={onSkillClick ? (ref) => onSkillClick({ org: ref.org, slug: ref.slug }) : undefined}
543
+ itemIcon={<SkillIcon className="size-4" />}
544
+ resourceLabel="skill"
545
+ defaultOrg={agentOrg}
546
+ />
547
+ ) : (
548
+ <SkillsContent
549
+ refs={spec?.skillRefs ?? []}
550
+ defaultOrg={agentOrg}
551
+ onSkillClick={onSkillClick}
552
+ />
225
553
  )}
226
- {updatedAt && (
227
- <>
228
- <Dot />
229
- <span>Updated {formatDate(updatedAt)}</span>
230
- </>
554
+ </Section>
555
+ )}
556
+
557
+ {showSubAgents && (
558
+ <SubAgentsSection
559
+ subAgents={spec?.subAgents ?? []}
560
+ editable={editable}
561
+ isSaving={isSaving}
562
+ onSave={(subs) => saveField?.("subAgents", subs.length > 0 ? subs : undefined) ?? Promise.resolve(false)}
563
+ />
564
+ )}
565
+
566
+ {showEnv && (
567
+ <Section title="Environment Variables" count={Object.keys(spec?.env ?? {}).length} onEdit={editable ? () => setEnvEditing((v) => !v) : undefined}>
568
+ {editable ? (
569
+ <InlineEditKeyValue
570
+ value={envRows}
571
+ onSave={handleEnvSave}
572
+ isSaving={isSaving}
573
+ editing={envEditing}
574
+ onEditingChange={setEnvEditing}
575
+ showSecretToggle
576
+ showOptionalToggle
577
+ showDescription
578
+ keyLabel="Variable name"
579
+ />
580
+ ) : (
581
+ <EnvContent data={spec?.env ?? {}} />
231
582
  )}
232
- </div>
233
- {spec?.description && (
234
- <p className="mt-2 text-sm text-muted-foreground">
235
- {spec.description}
236
- </p>
237
- )}
238
- </div>
583
+ </Section>
584
+ )}
239
585
  </div>
240
586
  );
241
587
  }
242
588
 
243
- function InstructionsSection({ text }: { readonly text: string }) {
244
- const lines = text.split("\n");
245
- const needsCollapse = lines.length > INSTRUCTIONS_COLLAPSED_LINES;
589
+ // ---------------------------------------------------------------------------
590
+ // Internal section components
591
+ // ---------------------------------------------------------------------------
592
+
593
+ function InstructionsContent({ text }: { readonly text: string }) {
246
594
  const [expanded, setExpanded] = useState(false);
595
+ const contentRef = useRef<HTMLPreElement>(null);
596
+ const [overflows, setOverflows] = useState(false);
247
597
 
248
- const displayText =
249
- needsCollapse && !expanded
250
- ? lines.slice(0, INSTRUCTIONS_COLLAPSED_LINES).join("\n")
251
- : text;
598
+ useEffect(() => {
599
+ const el = contentRef.current;
600
+ if (!el) return;
601
+ setOverflows(el.scrollHeight > el.clientHeight);
602
+ }, [text]);
252
603
 
253
604
  return (
254
- <Section title="Instructions">
255
- <div className="p-3">
256
- <pre className="whitespace-pre-wrap break-words font-mono text-sm text-foreground">
257
- {displayText}
258
- {needsCollapse && !expanded && "\u2026"}
259
- </pre>
260
- {needsCollapse && (
261
- <button
262
- type="button"
263
- onClick={() => setExpanded((v) => !v)}
264
- className="mt-2 text-xs font-medium text-primary transition-colors hover:text-primary-muted"
265
- >
266
- {expanded ? "Show less" : "Show more"}
267
- </button>
605
+ <div className="relative p-3">
606
+ <pre
607
+ ref={contentRef}
608
+ className={cn(
609
+ "whitespace-pre-wrap break-words font-mono text-sm text-foreground overflow-y-auto transition-[max-height] duration-200",
610
+ !expanded && "overflow-hidden",
268
611
  )}
269
- </div>
270
- </Section>
612
+ style={{ maxHeight: expanded ? "none" : INSTRUCTIONS_COLLAPSED_HEIGHT }}
613
+ >
614
+ {text}
615
+ </pre>
616
+ {!expanded && overflows && (
617
+ <div className="pointer-events-none absolute inset-x-3 bottom-10 h-8 bg-gradient-to-t from-background to-transparent" />
618
+ )}
619
+ {overflows && (
620
+ <button
621
+ type="button"
622
+ onClick={() => setExpanded((v) => !v)}
623
+ className="mt-2 text-xs font-medium text-primary transition-colors hover:text-primary-muted"
624
+ >
625
+ {expanded ? "Show less" : "Show more"}
626
+ </button>
627
+ )}
628
+ </div>
271
629
  );
272
630
  }
273
631
 
274
- function McpUsagesSection({
632
+ function McpUsagesContent({
275
633
  usages,
276
634
  defaultOrg,
277
635
  onMcpServerClick,
@@ -281,68 +639,66 @@ function McpUsagesSection({
281
639
  readonly onMcpServerClick?: (ref: { org: string; slug: string }) => void;
282
640
  }) {
283
641
  return (
284
- <Section title={`MCP Servers (${usages.length})`}>
285
- <div className="flex flex-col">
286
- {usages.map((usage, index) => {
287
- const ref = usage.mcpServerRef;
288
- if (!ref) return null;
289
-
290
- const refOrg = ref.org || defaultOrg;
291
- const label =
292
- ref.org && ref.org !== defaultOrg
293
- ? `${ref.org}/${ref.slug}`
294
- : ref.slug;
295
- const toolCount = usage.enabledTools.length;
296
- const approvalCount = usage.toolApprovalOverrides.length;
297
-
298
- const summary = [
299
- toolCount > 0
300
- ? `${toolCount} ${toolCount === 1 ? "tool" : "tools"}`
301
- : "all tools",
302
- approvalCount > 0
303
- ? `${approvalCount} approval ${approvalCount === 1 ? "override" : "overrides"}`
304
- : "",
305
- ]
306
- .filter(Boolean)
307
- .join(" \u00B7 ");
308
-
309
- const row = (
310
- <div className="flex items-center gap-3">
311
- <McpServerIcon className="size-4 shrink-0 text-muted-foreground" />
312
- <span className="text-sm font-medium text-foreground">
313
- {label}
314
- </span>
315
- <span className="text-xs text-muted-foreground">{summary}</span>
316
- </div>
317
- );
642
+ <div className="flex flex-col">
643
+ {usages.map((usage, index) => {
644
+ const ref = usage.mcpServerRef;
645
+ if (!ref) return null;
318
646
 
319
- return onMcpServerClick ? (
320
- <button
321
- key={ref.slug || index}
322
- type="button"
323
- onClick={() =>
324
- onMcpServerClick({ org: refOrg, slug: ref.slug })
325
- }
326
- className={cn(
327
- "w-full rounded-md px-3 py-2 text-left transition-colors",
328
- "hover:bg-accent-hover",
329
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
330
- )}
331
- >
332
- {row}
333
- </button>
334
- ) : (
335
- <div key={ref.slug || index} className="px-3 py-2">
336
- {row}
337
- </div>
338
- );
339
- })}
340
- </div>
341
- </Section>
647
+ const refOrg = ref.org || defaultOrg;
648
+ const label =
649
+ ref.org && ref.org !== defaultOrg
650
+ ? `${ref.org}/${ref.slug}`
651
+ : ref.slug;
652
+ const toolCount = usage.enabledTools.length;
653
+ const approvalCount = usage.toolApprovalOverrides.length;
654
+
655
+ const summary = [
656
+ toolCount > 0
657
+ ? `${toolCount} ${toolCount === 1 ? "tool" : "tools"}`
658
+ : "all tools",
659
+ approvalCount > 0
660
+ ? `${approvalCount} approval ${approvalCount === 1 ? "override" : "overrides"}`
661
+ : "",
662
+ ]
663
+ .filter(Boolean)
664
+ .join(" \u00B7 ");
665
+
666
+ const row = (
667
+ <div className="flex items-center gap-3">
668
+ <McpServerIcon className="size-4 shrink-0 text-muted-foreground" />
669
+ <span className="text-sm font-medium text-foreground">
670
+ {label}
671
+ </span>
672
+ <span className="text-xs text-muted-foreground">{summary}</span>
673
+ </div>
674
+ );
675
+
676
+ return onMcpServerClick ? (
677
+ <button
678
+ key={ref.slug || index}
679
+ type="button"
680
+ onClick={() =>
681
+ onMcpServerClick({ org: refOrg, slug: ref.slug })
682
+ }
683
+ className={cn(
684
+ "w-full rounded-md px-3 py-2 text-left transition-colors",
685
+ "hover:bg-accent-hover",
686
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
687
+ )}
688
+ >
689
+ {row}
690
+ </button>
691
+ ) : (
692
+ <div key={ref.slug || index} className="px-3 py-2">
693
+ {row}
694
+ </div>
695
+ );
696
+ })}
697
+ </div>
342
698
  );
343
699
  }
344
700
 
345
- function SkillsSection({
701
+ function SkillsContent({
346
702
  refs,
347
703
  defaultOrg,
348
704
  onSkillClick,
@@ -352,54 +708,67 @@ function SkillsSection({
352
708
  readonly onSkillClick?: (ref: { org: string; slug: string }) => void;
353
709
  }) {
354
710
  return (
355
- <Section title={`Skills (${refs.length})`}>
356
- <div className="flex flex-col">
357
- {refs.map((ref, index) => {
358
- const refOrg = ref.org || defaultOrg;
359
- const label =
360
- ref.org && ref.org !== defaultOrg
361
- ? `${ref.org}/${ref.slug}`
362
- : ref.slug;
363
-
364
- const row = (
365
- <div className="flex items-center gap-3">
366
- <SkillIcon className="size-4 shrink-0 text-muted-foreground" />
367
- <span className="text-sm font-medium text-foreground">
368
- {label}
369
- </span>
370
- </div>
371
- );
711
+ <div className="flex flex-col">
712
+ {refs.map((ref, index) => {
713
+ const refOrg = ref.org || defaultOrg;
714
+ const label =
715
+ ref.org && ref.org !== defaultOrg
716
+ ? `${ref.org}/${ref.slug}`
717
+ : ref.slug;
372
718
 
373
- return onSkillClick ? (
374
- <button
375
- key={ref.slug || index}
376
- type="button"
377
- onClick={() => onSkillClick({ org: refOrg, slug: ref.slug })}
378
- className={cn(
379
- "w-full rounded-md px-3 py-2 text-left transition-colors",
380
- "hover:bg-accent-hover",
381
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
382
- )}
383
- >
384
- {row}
385
- </button>
386
- ) : (
387
- <div key={ref.slug || index} className="px-3 py-2">
388
- {row}
389
- </div>
390
- );
391
- })}
392
- </div>
393
- </Section>
719
+ const row = (
720
+ <div className="flex items-center gap-3">
721
+ <SkillIcon className="size-4 shrink-0 text-muted-foreground" />
722
+ <span className="text-sm font-medium text-foreground">
723
+ {label}
724
+ </span>
725
+ </div>
726
+ );
727
+
728
+ return onSkillClick ? (
729
+ <button
730
+ key={ref.slug || index}
731
+ type="button"
732
+ onClick={() => onSkillClick({ org: refOrg, slug: ref.slug })}
733
+ className={cn(
734
+ "w-full rounded-md px-3 py-2 text-left transition-colors",
735
+ "hover:bg-accent-hover",
736
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
737
+ )}
738
+ >
739
+ {row}
740
+ </button>
741
+ ) : (
742
+ <div key={ref.slug || index} className="px-3 py-2">
743
+ {row}
744
+ </div>
745
+ );
746
+ })}
747
+ </div>
394
748
  );
395
749
  }
396
750
 
751
+ interface SubAgentDraft {
752
+ name: string;
753
+ description: string;
754
+ instructions: string;
755
+ }
756
+
397
757
  function SubAgentsSection({
398
758
  subAgents,
759
+ editable,
760
+ isSaving,
761
+ onSave,
399
762
  }: {
400
763
  readonly subAgents: readonly SubAgent[];
764
+ readonly editable?: boolean;
765
+ readonly isSaving?: boolean;
766
+ readonly onSave?: (subs: import("@stigmer/sdk").SubAgentInput[]) => Promise<boolean>;
401
767
  }) {
402
768
  const [expanded, setExpanded] = useState<Set<number>>(new Set());
769
+ const [isEditing, setIsEditing] = useState(false);
770
+ const [showAddForm, setShowAddForm] = useState(false);
771
+ const [addDraft, setAddDraft] = useState<SubAgentDraft>({ name: "", description: "", instructions: "" });
403
772
 
404
773
  const toggle = (index: number) => {
405
774
  setExpanded((prev) => {
@@ -410,48 +779,200 @@ function SubAgentsSection({
410
779
  });
411
780
  };
412
781
 
782
+ const handleRemove = useCallback(
783
+ async (index: number) => {
784
+ if (!onSave) return;
785
+ const updated = subAgents
786
+ .filter((_, i) => i !== index)
787
+ .map((sa) => ({
788
+ name: sa.name,
789
+ description: sa.description || undefined,
790
+ instructions: sa.instructions || undefined,
791
+ mcpAccess: sa.mcpAccess.length > 0
792
+ ? sa.mcpAccess.map((a) => ({ mcpServer: a.mcpServer, enabledTools: a.enabledTools.length > 0 ? [...a.enabledTools] : undefined }))
793
+ : undefined,
794
+ skillRefs: sa.skillRefs.length > 0
795
+ ? sa.skillRefs.map((r) => ({ org: r.org || "", slug: r.slug }))
796
+ : undefined,
797
+ modelOverride: sa.modelOverride || undefined,
798
+ }));
799
+ await onSave(updated);
800
+ },
801
+ [subAgents, onSave],
802
+ );
803
+
804
+ const handleAdd = useCallback(async () => {
805
+ if (!onSave || !addDraft.name.trim()) return;
806
+ const existing = subAgents.map((sa) => ({
807
+ name: sa.name,
808
+ description: sa.description || undefined,
809
+ instructions: sa.instructions || undefined,
810
+ mcpAccess: sa.mcpAccess.length > 0
811
+ ? sa.mcpAccess.map((a) => ({ mcpServer: a.mcpServer, enabledTools: a.enabledTools.length > 0 ? [...a.enabledTools] : undefined }))
812
+ : undefined,
813
+ skillRefs: sa.skillRefs.length > 0
814
+ ? sa.skillRefs.map((r) => ({ org: r.org || "", slug: r.slug }))
815
+ : undefined,
816
+ modelOverride: sa.modelOverride || undefined,
817
+ }));
818
+ const newSub = {
819
+ name: addDraft.name.trim(),
820
+ description: addDraft.description.trim() || undefined,
821
+ instructions: addDraft.instructions.trim() || undefined,
822
+ };
823
+ const ok = await onSave([...existing, newSub]);
824
+ if (ok) {
825
+ setAddDraft({ name: "", description: "", instructions: "" });
826
+ setShowAddForm(false);
827
+ }
828
+ }, [subAgents, addDraft, onSave]);
829
+
413
830
  return (
414
- <Section title={`Sub-Agents (${subAgents.length})`}>
831
+ <Section title="Sub-Agents" count={subAgents.length} onEdit={editable ? () => setIsEditing((v) => !v) : undefined}>
415
832
  <div className="flex flex-col">
416
- {subAgents.map((sa, index) => {
417
- const isOpen = expanded.has(index);
833
+ {subAgents.length > 0 ? (
834
+ <div className="flex flex-col divide-y divide-border">
835
+ {subAgents.map((sa, index) => {
836
+ const isOpen = expanded.has(index);
837
+
838
+ return (
839
+ <div key={sa.name || index}>
840
+ <div className="flex items-start gap-3 px-3 py-2.5">
841
+ <button
842
+ type="button"
843
+ onClick={() => toggle(index)}
844
+ aria-expanded={isOpen}
845
+ className={cn(
846
+ "flex flex-1 items-start gap-3 text-left",
847
+ "focus-visible:outline-none",
848
+ )}
849
+ >
850
+ <ChevronRightIcon
851
+ className={cn(
852
+ "mt-0.5 size-4 shrink-0 text-muted-foreground transition-transform",
853
+ isOpen && "rotate-90",
854
+ )}
855
+ />
856
+ <div className="min-w-0 flex-1">
857
+ <span className="text-sm font-medium text-foreground">
858
+ {sa.name}
859
+ </span>
860
+ {sa.description && (
861
+ <p className="mt-0.5 text-xs text-muted-foreground">
862
+ {sa.description}
863
+ </p>
864
+ )}
865
+ </div>
866
+ </button>
867
+ {isEditing && (
868
+ <button
869
+ type="button"
870
+ onClick={() => handleRemove(index)}
871
+ disabled={isSaving}
872
+ aria-label={`Remove ${sa.name}`}
873
+ className={cn(
874
+ "mt-0.5 inline-flex size-6 items-center justify-center rounded-md text-muted-foreground",
875
+ "hover:bg-destructive-subtle hover:text-destructive",
876
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
877
+ )}
878
+ >
879
+ <XRemoveIcon className="size-3.5" />
880
+ </button>
881
+ )}
882
+ </div>
418
883
 
419
- return (
420
- <div key={sa.name || index}>
884
+ {isOpen && (
885
+ <SubAgentDetails subAgent={sa} />
886
+ )}
887
+ </div>
888
+ );
889
+ })}
890
+ </div>
891
+ ) : (
892
+ <p className="px-3 py-3 text-xs text-muted-foreground italic">
893
+ No sub-agents configured
894
+ </p>
895
+ )}
896
+
897
+ {editable && isEditing && !showAddForm && (
898
+ <div className="border-t border-border px-3 py-2">
899
+ <button
900
+ type="button"
901
+ onClick={() => setShowAddForm(true)}
902
+ className={cn(
903
+ "inline-flex items-center gap-1 rounded-md px-2.5 py-1.5 text-xs font-medium",
904
+ "border border-dashed border-border text-muted-foreground",
905
+ "hover:border-muted-foreground hover:text-foreground hover:bg-muted-subtle",
906
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
907
+ "transition-colors",
908
+ )}
909
+ >
910
+ <PlusAddIcon className="size-3" />
911
+ Add sub-agent
912
+ </button>
913
+ </div>
914
+ )}
915
+
916
+ {editable && showAddForm && (
917
+ <div className="border-t border-border p-3 space-y-2">
918
+ <input
919
+ type="text"
920
+ value={addDraft.name}
921
+ onChange={(e) => setAddDraft((d) => ({ ...d, name: e.target.value }))}
922
+ placeholder="Sub-agent name (required)"
923
+ className={cn(
924
+ "w-full rounded-md border border-border bg-input-bg px-2 py-1.5 text-sm text-foreground",
925
+ "focus:outline-none focus:ring-2 focus:ring-ring",
926
+ )}
927
+ />
928
+ <input
929
+ type="text"
930
+ value={addDraft.description}
931
+ onChange={(e) => setAddDraft((d) => ({ ...d, description: e.target.value }))}
932
+ placeholder="Description (optional)"
933
+ className={cn(
934
+ "w-full rounded-md border border-border bg-input-bg px-2 py-1.5 text-xs text-foreground",
935
+ "focus:outline-none focus:ring-2 focus:ring-ring",
936
+ )}
937
+ />
938
+ <textarea
939
+ value={addDraft.instructions}
940
+ onChange={(e) => setAddDraft((d) => ({ ...d, instructions: e.target.value }))}
941
+ placeholder="Instructions (optional)"
942
+ rows={2}
943
+ className={cn(
944
+ "w-full resize-y rounded-md border border-border bg-input-bg px-2 py-1.5 font-mono text-xs text-foreground",
945
+ "focus:outline-none focus:ring-2 focus:ring-ring",
946
+ )}
947
+ />
948
+ <div className="flex items-center justify-end gap-1.5">
421
949
  <button
422
950
  type="button"
423
- onClick={() => toggle(index)}
424
- aria-expanded={isOpen}
951
+ onClick={() => { setShowAddForm(false); setAddDraft({ name: "", description: "", instructions: "" }); }}
425
952
  className={cn(
426
- "flex w-full items-start gap-3 rounded-md px-3 py-2 text-left transition-colors",
427
- "hover:bg-accent-hover",
428
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
953
+ "rounded-md px-2.5 py-1 text-xs font-medium",
954
+ "border border-border bg-background text-foreground hover:bg-accent",
955
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
429
956
  )}
430
957
  >
431
- <ChevronRightIcon
432
- className={cn(
433
- "mt-0.5 size-4 shrink-0 text-muted-foreground transition-transform",
434
- isOpen && "rotate-90",
435
- )}
436
- />
437
- <div className="min-w-0 flex-1">
438
- <span className="text-sm font-medium text-foreground">
439
- {sa.name}
440
- </span>
441
- {sa.description && (
442
- <p className="mt-0.5 text-xs text-muted-foreground">
443
- {sa.description}
444
- </p>
445
- )}
446
- </div>
958
+ Cancel
959
+ </button>
960
+ <button
961
+ type="button"
962
+ onClick={handleAdd}
963
+ disabled={!addDraft.name.trim() || isSaving}
964
+ className={cn(
965
+ "rounded-md px-2.5 py-1 text-xs font-medium",
966
+ "bg-primary text-primary-foreground hover:bg-primary-hover",
967
+ "disabled:opacity-50",
968
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
969
+ )}
970
+ >
971
+ Add
447
972
  </button>
448
-
449
- {isOpen && (
450
- <SubAgentDetails subAgent={sa} />
451
- )}
452
973
  </div>
453
- );
454
- })}
974
+ </div>
975
+ )}
455
976
  </div>
456
977
  </Section>
457
978
  );
@@ -534,7 +1055,7 @@ function SubAgentDetails({
534
1055
  );
535
1056
  }
536
1057
 
537
- function EnvSection({
1058
+ function EnvContent({
538
1059
  data,
539
1060
  }: {
540
1061
  readonly data: { [key: string]: EnvVarDeclaration };
@@ -544,25 +1065,23 @@ function EnvSection({
544
1065
  );
545
1066
 
546
1067
  return (
547
- <Section title={`Environment Variables (${entries.length})`}>
548
- <div className="flex flex-col divide-y divide-border">
549
- {entries.map(([name, env]) => (
550
- <div key={name} className="flex items-start gap-3 px-3 py-2">
551
- <code className="shrink-0 font-mono text-sm font-medium text-foreground">
552
- {name}
553
- </code>
554
- <span className="shrink-0 rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground">
555
- {env.isSecret ? "secret" : "config"}
1068
+ <div className="flex flex-col divide-y divide-border">
1069
+ {entries.map(([name, env]) => (
1070
+ <div key={name} className="flex items-start gap-3 px-3 py-2">
1071
+ <code className="shrink-0 font-mono text-sm font-medium text-foreground">
1072
+ {name}
1073
+ </code>
1074
+ <span className="shrink-0 rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground">
1075
+ {env.isSecret ? "secret" : "config"}
1076
+ </span>
1077
+ {env.description && (
1078
+ <span className="text-xs text-muted-foreground">
1079
+ {env.description}
556
1080
  </span>
557
- {env.description && (
558
- <span className="text-xs text-muted-foreground">
559
- {env.description}
560
- </span>
561
- )}
562
- </div>
563
- ))}
564
- </div>
565
- </Section>
1081
+ )}
1082
+ </div>
1083
+ ))}
1084
+ </div>
566
1085
  );
567
1086
  }
568
1087
 
@@ -570,33 +1089,6 @@ function EnvSection({
570
1089
  // Shared layout primitives
571
1090
  // ---------------------------------------------------------------------------
572
1091
 
573
- function Section({
574
- title,
575
- children,
576
- }: {
577
- readonly title: string;
578
- readonly children: React.ReactNode;
579
- }) {
580
- return (
581
- <section>
582
- <h3 className="mb-2 text-xs font-medium uppercase tracking-wider text-muted-foreground">
583
- {title}
584
- </h3>
585
- <div className="overflow-hidden rounded-lg border border-border">
586
- {children}
587
- </div>
588
- </section>
589
- );
590
- }
591
-
592
- function Dot() {
593
- return (
594
- <span className="shrink-0" aria-hidden="true">
595
- {"\u00B7"}
596
- </span>
597
- );
598
- }
599
-
600
1092
  // ---------------------------------------------------------------------------
601
1093
  // Non-happy states
602
1094
  // ---------------------------------------------------------------------------
@@ -649,18 +1141,6 @@ function NotFoundState({ className }: { readonly className?: string }) {
649
1141
  );
650
1142
  }
651
1143
 
652
- // ---------------------------------------------------------------------------
653
- // Utilities
654
- // ---------------------------------------------------------------------------
655
-
656
- function formatDate(date: Date): string {
657
- return date.toLocaleDateString("en-US", {
658
- month: "short",
659
- day: "numeric",
660
- year: "numeric",
661
- });
662
- }
663
-
664
1144
  // ---------------------------------------------------------------------------
665
1145
  // Icons — inline SVGs following the SDK pattern (no icon library dependency)
666
1146
  // ---------------------------------------------------------------------------
@@ -737,3 +1217,19 @@ function ChevronRightIcon({ className }: { readonly className?: string }) {
737
1217
  </svg>
738
1218
  );
739
1219
  }
1220
+
1221
+ function XRemoveIcon({ className }: { readonly className?: string }) {
1222
+ return (
1223
+ <svg className={className} viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
1224
+ <path d="m4 4 8 8M12 4l-8 8" />
1225
+ </svg>
1226
+ );
1227
+ }
1228
+
1229
+ function PlusAddIcon({ className }: { readonly className?: string }) {
1230
+ return (
1231
+ <svg className={className} viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
1232
+ <path d="M8 3v10M3 8h10" />
1233
+ </svg>
1234
+ );
1235
+ }