@jiggai/kitchen 0.3.1 → 0.3.3

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 (307) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +2 -2
  3. package/.next/server/app/_global-error.html +2 -2
  4. package/.next/server/app/_global-error.rsc +1 -1
  5. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  6. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  7. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  8. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  10. package/.next/server/app/_not-found.html +1 -1
  11. package/.next/server/app/_not-found.rsc +1 -1
  12. package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  13. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  14. package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  15. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  16. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  17. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  18. package/.next/server/app/channels.html +2 -2
  19. package/.next/server/app/channels.rsc +1 -1
  20. package/.next/server/app/channels.segments/_full.segment.rsc +1 -1
  21. package/.next/server/app/channels.segments/_head.segment.rsc +1 -1
  22. package/.next/server/app/channels.segments/_index.segment.rsc +1 -1
  23. package/.next/server/app/channels.segments/_tree.segment.rsc +1 -1
  24. package/.next/server/app/channels.segments/channels/__PAGE__.segment.rsc +1 -1
  25. package/.next/server/app/channels.segments/channels.segment.rsc +1 -1
  26. package/.next/server/app/cron-jobs.html +1 -1
  27. package/.next/server/app/cron-jobs.rsc +1 -1
  28. package/.next/server/app/cron-jobs.segments/_full.segment.rsc +1 -1
  29. package/.next/server/app/cron-jobs.segments/_head.segment.rsc +1 -1
  30. package/.next/server/app/cron-jobs.segments/_index.segment.rsc +1 -1
  31. package/.next/server/app/cron-jobs.segments/_tree.segment.rsc +1 -1
  32. package/.next/server/app/cron-jobs.segments/cron-jobs/__PAGE__.segment.rsc +1 -1
  33. package/.next/server/app/cron-jobs.segments/cron-jobs.segment.rsc +1 -1
  34. package/.next/server/app/goals/new.html +2 -2
  35. package/.next/server/app/goals/new.rsc +1 -1
  36. package/.next/server/app/goals/new.segments/_full.segment.rsc +1 -1
  37. package/.next/server/app/goals/new.segments/_head.segment.rsc +1 -1
  38. package/.next/server/app/goals/new.segments/_index.segment.rsc +1 -1
  39. package/.next/server/app/goals/new.segments/_tree.segment.rsc +1 -1
  40. package/.next/server/app/goals/new.segments/goals/new/__PAGE__.segment.rsc +1 -1
  41. package/.next/server/app/goals/new.segments/goals/new.segment.rsc +1 -1
  42. package/.next/server/app/goals/new.segments/goals.segment.rsc +1 -1
  43. package/.next/server/app/goals.html +1 -1
  44. package/.next/server/app/goals.rsc +1 -1
  45. package/.next/server/app/goals.segments/_full.segment.rsc +1 -1
  46. package/.next/server/app/goals.segments/_head.segment.rsc +1 -1
  47. package/.next/server/app/goals.segments/_index.segment.rsc +1 -1
  48. package/.next/server/app/goals.segments/_tree.segment.rsc +1 -1
  49. package/.next/server/app/goals.segments/goals/__PAGE__.segment.rsc +1 -1
  50. package/.next/server/app/goals.segments/goals.segment.rsc +1 -1
  51. package/.next/server/app/settings.html +1 -1
  52. package/.next/server/app/settings.rsc +1 -1
  53. package/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  54. package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  55. package/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  56. package/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  57. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +1 -1
  58. package/.next/server/app/settings.segments/settings.segment.rsc +1 -1
  59. package/.next/server/pages/404.html +1 -1
  60. package/.next/server/pages/500.html +2 -2
  61. package/package.json +1 -2
  62. package/src/app/HomeClient.tsx +0 -207
  63. package/src/app/agents/[agentId]/agent-editor-tabs.tsx +0 -298
  64. package/src/app/agents/[agentId]/agent-editor.tsx +0 -468
  65. package/src/app/agents/[agentId]/page.tsx +0 -32
  66. package/src/app/api/__tests__/agents-add-route.test.ts +0 -143
  67. package/src/app/api/__tests__/agents-file-route.test.ts +0 -117
  68. package/src/app/api/__tests__/agents-files-route.test.ts +0 -61
  69. package/src/app/api/__tests__/agents-id-route.test.ts +0 -104
  70. package/src/app/api/__tests__/agents-identity-route.test.ts +0 -92
  71. package/src/app/api/__tests__/agents-route.test.ts +0 -54
  72. package/src/app/api/__tests__/agents-skills-install-route.test.ts +0 -131
  73. package/src/app/api/__tests__/agents-skills-route.test.ts +0 -64
  74. package/src/app/api/__tests__/agents-update-route.test.ts +0 -95
  75. package/src/app/api/__tests__/channels-bindings-route.test.ts +0 -143
  76. package/src/app/api/__tests__/cron-delete-route.test.ts +0 -93
  77. package/src/app/api/__tests__/cron-job-route.test.ts +0 -78
  78. package/src/app/api/__tests__/cron-jobs-route.test.ts +0 -116
  79. package/src/app/api/__tests__/cron-recipe-installed-route.test.ts +0 -114
  80. package/src/app/api/__tests__/gateway-restart-route.test.ts +0 -36
  81. package/src/app/api/__tests__/goals-promote-route.test.ts +0 -200
  82. package/src/app/api/__tests__/goals-route.test.ts +0 -184
  83. package/src/app/api/__tests__/ids-check-route.test.ts +0 -188
  84. package/src/app/api/__tests__/marketplace-recipes-route.test.ts +0 -123
  85. package/src/app/api/__tests__/recipes-clone-route.test.ts +0 -221
  86. package/src/app/api/__tests__/recipes-delete-route.test.ts +0 -248
  87. package/src/app/api/__tests__/recipes-id-route.test.ts +0 -166
  88. package/src/app/api/__tests__/recipes-route.test.ts +0 -57
  89. package/src/app/api/__tests__/recipes-team-agents-route.test.ts +0 -135
  90. package/src/app/api/__tests__/scaffold-route.test.ts +0 -173
  91. package/src/app/api/__tests__/settings-cron-installation-route.test.ts +0 -82
  92. package/src/app/api/__tests__/skills-available-route.test.ts +0 -47
  93. package/src/app/api/__tests__/swarms-start-route.test.ts +0 -79
  94. package/src/app/api/__tests__/swarms-status-route.test.ts +0 -42
  95. package/src/app/api/__tests__/teams-file-route.test.ts +0 -129
  96. package/src/app/api/__tests__/teams-files-route.test.ts +0 -57
  97. package/src/app/api/__tests__/teams-meta-route.test.ts +0 -113
  98. package/src/app/api/__tests__/teams-orchestrator-install-route.test.ts +0 -66
  99. package/src/app/api/__tests__/teams-orchestrator-route.test.ts +0 -59
  100. package/src/app/api/__tests__/teams-remove-team-route.test.ts +0 -122
  101. package/src/app/api/__tests__/teams-skills-install-route.test.ts +0 -78
  102. package/src/app/api/__tests__/teams-skills-route.test.ts +0 -73
  103. package/src/app/api/__tests__/teams-workflow-runs-route.test.ts +0 -85
  104. package/src/app/api/__tests__/teams-workflows-route.test.ts +0 -110
  105. package/src/app/api/__tests__/tickets-move-route.test.ts +0 -60
  106. package/src/app/api/agents/[id]/route.ts +0 -83
  107. package/src/app/api/agents/add/route.ts +0 -114
  108. package/src/app/api/agents/file/route.ts +0 -45
  109. package/src/app/api/agents/files/route.ts +0 -23
  110. package/src/app/api/agents/identity/route.ts +0 -41
  111. package/src/app/api/agents/route.ts +0 -22
  112. package/src/app/api/agents/skills/install/route.ts +0 -34
  113. package/src/app/api/agents/skills/route.ts +0 -39
  114. package/src/app/api/agents/update/route.ts +0 -52
  115. package/src/app/api/channels/bindings/route.ts +0 -63
  116. package/src/app/api/cron/__tests__/helpers.test.ts +0 -164
  117. package/src/app/api/cron/delete/route.ts +0 -23
  118. package/src/app/api/cron/helpers.ts +0 -172
  119. package/src/app/api/cron/job/route.ts +0 -22
  120. package/src/app/api/cron/jobs/route.ts +0 -52
  121. package/src/app/api/cron/recipe-installed/route.ts +0 -65
  122. package/src/app/api/gateway/restart/route.ts +0 -20
  123. package/src/app/api/goals/[id]/promote/route.ts +0 -119
  124. package/src/app/api/goals/[id]/route.ts +0 -54
  125. package/src/app/api/goals/route.ts +0 -44
  126. package/src/app/api/ids/check/route.ts +0 -113
  127. package/src/app/api/marketplace/recipes/[slug]/route.ts +0 -16
  128. package/src/app/api/marketplace/recipes/route.ts +0 -22
  129. package/src/app/api/recipes/[id]/route.ts +0 -62
  130. package/src/app/api/recipes/clone/route.ts +0 -106
  131. package/src/app/api/recipes/custom-team/route.ts +0 -193
  132. package/src/app/api/recipes/delete/helpers.ts +0 -65
  133. package/src/app/api/recipes/delete/route.ts +0 -73
  134. package/src/app/api/recipes/route.ts +0 -21
  135. package/src/app/api/recipes/team-agents/__tests__/helpers.test.ts +0 -156
  136. package/src/app/api/recipes/team-agents/helpers.ts +0 -151
  137. package/src/app/api/recipes/team-agents/route.ts +0 -80
  138. package/src/app/api/scaffold/__tests__/helpers.test.ts +0 -186
  139. package/src/app/api/scaffold/helpers.ts +0 -214
  140. package/src/app/api/scaffold/route.ts +0 -95
  141. package/src/app/api/settings/cron-installation/route.ts +0 -58
  142. package/src/app/api/skills/available/route.ts +0 -23
  143. package/src/app/api/swarms/start/route.ts +0 -100
  144. package/src/app/api/swarms/status/route.ts +0 -31
  145. package/src/app/api/teams/[teamId]/tickets/assign/route.ts +0 -105
  146. package/src/app/api/teams/[teamId]/tickets/assignees/route.ts +0 -27
  147. package/src/app/api/teams/[teamId]/tickets/delete/route.ts +0 -55
  148. package/src/app/api/teams/[teamId]/tickets/move/route.ts +0 -70
  149. package/src/app/api/teams/[teamId]/tickets/move-to-goals/route.ts +0 -56
  150. package/src/app/api/teams/file/route.ts +0 -46
  151. package/src/app/api/teams/files/route.ts +0 -63
  152. package/src/app/api/teams/memory/route.ts +0 -250
  153. package/src/app/api/teams/meta/route.ts +0 -43
  154. package/src/app/api/teams/orchestrator/install/route.ts +0 -129
  155. package/src/app/api/teams/orchestrator/route.ts +0 -216
  156. package/src/app/api/teams/remove-team/route.ts +0 -37
  157. package/src/app/api/teams/skills/install/route.ts +0 -18
  158. package/src/app/api/teams/skills/route.ts +0 -25
  159. package/src/app/api/teams/workflow-runs/route.ts +0 -534
  160. package/src/app/api/teams/workflow-templates/route.ts +0 -71
  161. package/src/app/api/teams/workflows/route.ts +0 -55
  162. package/src/app/api/tickets/assign/route.ts +0 -94
  163. package/src/app/api/tickets/assignees/route.ts +0 -24
  164. package/src/app/api/tickets/move/route.ts +0 -69
  165. package/src/app/channels/channels-client.tsx +0 -271
  166. package/src/app/channels/page.tsx +0 -5
  167. package/src/app/cron-jobs/cron-jobs-client.tsx +0 -243
  168. package/src/app/cron-jobs/page.tsx +0 -34
  169. package/src/app/favicon.ico +0 -0
  170. package/src/app/global-error.tsx +0 -50
  171. package/src/app/globals.css +0 -153
  172. package/src/app/goals/[id]/goal-editor.tsx +0 -162
  173. package/src/app/goals/[id]/page.tsx +0 -6
  174. package/src/app/goals/goals-client.tsx +0 -201
  175. package/src/app/goals/new/page.tsx +0 -81
  176. package/src/app/goals/page.tsx +0 -10
  177. package/src/app/layout.tsx +0 -53
  178. package/src/app/manifest.ts +0 -15
  179. package/src/app/not-found.tsx +0 -8
  180. package/src/app/page.tsx +0 -33
  181. package/src/app/recipes/CreateAgentModal.tsx +0 -156
  182. package/src/app/recipes/CreateCustomTeamModal.tsx +0 -375
  183. package/src/app/recipes/CreateModalShell.tsx +0 -55
  184. package/src/app/recipes/CreateTeamModal.tsx +0 -91
  185. package/src/app/recipes/[id]/RecipeEditor/RecipeEditorCreateModal.tsx +0 -72
  186. package/src/app/recipes/[id]/RecipeEditor/RecipeEditorPanel.tsx +0 -216
  187. package/src/app/recipes/[id]/RecipeEditor/index.tsx +0 -271
  188. package/src/app/recipes/[id]/RecipeEditor/recipe-editor-utils.ts +0 -46
  189. package/src/app/recipes/[id]/RecipeEditor/types.ts +0 -52
  190. package/src/app/recipes/[id]/page.tsx +0 -37
  191. package/src/app/recipes/page.tsx +0 -101
  192. package/src/app/recipes/recipes-client.tsx +0 -620
  193. package/src/app/settings/page.tsx +0 -26
  194. package/src/app/settings/settings-client.tsx +0 -91
  195. package/src/app/teams/[teamId]/CloneTeamModal.tsx +0 -116
  196. package/src/app/teams/[teamId]/OrchestratorPanel.tsx +0 -255
  197. package/src/app/teams/[teamId]/OrchestratorSetupModal.tsx +0 -184
  198. package/src/app/teams/[teamId]/PublishChangesModal.tsx +0 -43
  199. package/src/app/teams/[teamId]/page.tsx +0 -49
  200. package/src/app/teams/[teamId]/team-editor/TeamAgentsTab.tsx +0 -145
  201. package/src/app/teams/[teamId]/team-editor/TeamCronTab.tsx +0 -72
  202. package/src/app/teams/[teamId]/team-editor/TeamFilesTab.tsx +0 -74
  203. package/src/app/teams/[teamId]/team-editor/TeamMemoryTab.tsx +0 -349
  204. package/src/app/teams/[teamId]/team-editor/TeamRecipeTab.tsx +0 -151
  205. package/src/app/teams/[teamId]/team-editor/TeamSkillsTab.tsx +0 -68
  206. package/src/app/teams/[teamId]/team-editor/index.tsx +0 -558
  207. package/src/app/teams/[teamId]/team-editor/team-editor-data.ts +0 -255
  208. package/src/app/teams/[teamId]/team-editor/team-editor-utils.ts +0 -78
  209. package/src/app/teams/[teamId]/team-editor/types.ts +0 -34
  210. package/src/app/teams/[teamId]/tickets/[ticket]/page.tsx +0 -35
  211. package/src/app/teams/[teamId]/tickets/page.tsx +0 -15
  212. package/src/app/teams/[teamId]/workflows/[workflowId]/WorkflowCanvas.tsx +0 -111
  213. package/src/app/teams/[teamId]/workflows/[workflowId]/page.tsx +0 -27
  214. package/src/app/teams/[teamId]/workflows/[workflowId]/workflows-editor-client.tsx +0 -1608
  215. package/src/app/teams/[teamId]/workflows/page.tsx +0 -40
  216. package/src/app/teams/[teamId]/workflows/workflows-client.tsx +0 -494
  217. package/src/app/tickets/TicketDetailClient.tsx +0 -147
  218. package/src/app/tickets/TicketsBoardClient.tsx +0 -200
  219. package/src/app/tickets/[ticket]/TicketAssignControl.tsx +0 -112
  220. package/src/app/tickets/[ticket]/page.tsx +0 -36
  221. package/src/app/tickets/page.tsx +0 -10
  222. package/src/components/AppShell.tsx +0 -286
  223. package/src/components/ConfirmationModal.tsx +0 -81
  224. package/src/components/DeleteEntityModal.tsx +0 -41
  225. package/src/components/ErrorBoundary.tsx +0 -70
  226. package/src/components/FileListWithOptionalToggle.tsx +0 -86
  227. package/src/components/GoalFormFields.tsx +0 -163
  228. package/src/components/ScaffoldOverlay.tsx +0 -78
  229. package/src/components/ThemeToggle.tsx +0 -53
  230. package/src/components/ToastProvider.tsx +0 -163
  231. package/src/components/__tests__/ConfirmationModal.test.tsx +0 -109
  232. package/src/components/__tests__/ErrorBoundary.test.tsx +0 -39
  233. package/src/components/__tests__/FileListWithOptionalToggle.test.tsx +0 -109
  234. package/src/components/__tests__/GoalFormFields.test.tsx +0 -117
  235. package/src/components/delete-modals.tsx +0 -59
  236. package/src/components/icons.tsx +0 -48
  237. package/src/lib/__tests__/agent-workspace.test.ts +0 -44
  238. package/src/lib/__tests__/agents.test.ts +0 -36
  239. package/src/lib/__tests__/api-route-helpers.test.ts +0 -188
  240. package/src/lib/__tests__/cron.test.ts +0 -45
  241. package/src/lib/__tests__/editor-utils.test.ts +0 -38
  242. package/src/lib/__tests__/errors.test.ts +0 -15
  243. package/src/lib/__tests__/exec.test.ts +0 -13
  244. package/src/lib/__tests__/fetch-json.test.ts +0 -118
  245. package/src/lib/__tests__/gateway.test.ts +0 -234
  246. package/src/lib/__tests__/goal-promote.test.ts +0 -39
  247. package/src/lib/__tests__/goals-client.test.ts +0 -26
  248. package/src/lib/__tests__/goals.test.ts +0 -275
  249. package/src/lib/__tests__/json.test.ts +0 -15
  250. package/src/lib/__tests__/kitchen-api.test.ts +0 -32
  251. package/src/lib/__tests__/marketplace.test.ts +0 -116
  252. package/src/lib/__tests__/openclaw.test.ts +0 -129
  253. package/src/lib/__tests__/paths.test.ts +0 -136
  254. package/src/lib/__tests__/poll.test.ts +0 -26
  255. package/src/lib/__tests__/recipe-clone.test.ts +0 -85
  256. package/src/lib/__tests__/recipe-team-agents.test.ts +0 -70
  257. package/src/lib/__tests__/recipes.test.ts +0 -199
  258. package/src/lib/__tests__/scaffold-client.test.ts +0 -106
  259. package/src/lib/__tests__/scaffold.test.ts +0 -64
  260. package/src/lib/__tests__/slugify.test.ts +0 -23
  261. package/src/lib/__tests__/tickets.test.ts +0 -158
  262. package/src/lib/__tests__/type-guards.test.ts +0 -18
  263. package/src/lib/__tests__/use-slugified-id.test.tsx +0 -120
  264. package/src/lib/agent-workspace.ts +0 -14
  265. package/src/lib/agents.ts +0 -17
  266. package/src/lib/api-route-helpers.ts +0 -157
  267. package/src/lib/cron.ts +0 -40
  268. package/src/lib/editor-utils.ts +0 -18
  269. package/src/lib/errors.ts +0 -7
  270. package/src/lib/exec.ts +0 -4
  271. package/src/lib/fetch-json.ts +0 -29
  272. package/src/lib/gateway.ts +0 -100
  273. package/src/lib/goal-promote.ts +0 -27
  274. package/src/lib/goals-client.ts +0 -69
  275. package/src/lib/goals.ts +0 -171
  276. package/src/lib/json.ts +0 -10
  277. package/src/lib/kitchen-api.ts +0 -19
  278. package/src/lib/marketplace.ts +0 -46
  279. package/src/lib/openclaw.ts +0 -59
  280. package/src/lib/paths.ts +0 -69
  281. package/src/lib/poll.ts +0 -18
  282. package/src/lib/recipe-clone.ts +0 -42
  283. package/src/lib/recipe-team-agents.ts +0 -30
  284. package/src/lib/recipes.ts +0 -95
  285. package/src/lib/scaffold-client.ts +0 -31
  286. package/src/lib/scaffold.ts +0 -37
  287. package/src/lib/slugify.ts +0 -25
  288. package/src/lib/swarms.ts +0 -25
  289. package/src/lib/tickets.ts +0 -192
  290. package/src/lib/type-guards.ts +0 -3
  291. package/src/lib/use-slugified-id.ts +0 -35
  292. package/src/lib/workflows/README.md +0 -11
  293. package/src/lib/workflows/__tests__/storage.test.ts +0 -129
  294. package/src/lib/workflows/__tests__/validate.test.ts +0 -92
  295. package/src/lib/workflows/api-handlers.ts +0 -35
  296. package/src/lib/workflows/readdir.ts +0 -23
  297. package/src/lib/workflows/runs-storage.ts +0 -59
  298. package/src/lib/workflows/runs-types.ts +0 -42
  299. package/src/lib/workflows/storage.ts +0 -70
  300. package/src/lib/workflows/templates/index.ts +0 -1
  301. package/src/lib/workflows/templates/marketing-cadence-v1.ts +0 -142
  302. package/src/lib/workflows/types.ts +0 -48
  303. package/src/lib/workflows/validate.ts +0 -92
  304. package/src/proxy.ts +0 -28
  305. /package/.next/static/{z86RoqzzXXrWnpi229zP6 → Jrrrm9HH5bKkSrQhe1j93}/_buildManifest.js +0 -0
  306. /package/.next/static/{z86RoqzzXXrWnpi229zP6 → Jrrrm9HH5bKkSrQhe1j93}/_clientMiddlewareManifest.json +0 -0
  307. /package/.next/static/{z86RoqzzXXrWnpi229zP6 → Jrrrm9HH5bKkSrQhe1j93}/_ssgManifest.js +0 -0
@@ -1,375 +0,0 @@
1
- "use client";
2
-
3
- import { useEffect, useMemo, useState } from "react";
4
- import { CreateModalShell } from "./CreateModalShell";
5
- import { fetchJsonWithStatus } from "@/lib/fetch-json";
6
- import type { AgentListItem } from "@/lib/agents";
7
-
8
- type SelectedRole = { agentId: string; roleId: string; displayName: string };
9
-
10
- function defaultRoleIdFromAgentId(agentId: string) {
11
- // Strip any existing team prefix if present; keep it sluggy.
12
- const id = agentId.split("/").pop() || agentId;
13
- const last = id.split("-").slice(-1)[0] || id;
14
- return last.toLowerCase().replace(/[^a-z0-9_-]+/g, "-");
15
- }
16
-
17
- function normalizeTeamIdInput(v: string) {
18
- // UX: when the user types spaces, turn them into dashes (live).
19
- // Also keep it lowercase to match id rules.
20
- return v.toLowerCase().replace(/\s+/g, "-");
21
- }
22
-
23
- function isValidId(id: string) {
24
- return /^[a-z0-9][a-z0-9_-]{1,62}$/.test(id);
25
- }
26
-
27
- function isValidTeamId(id: string) {
28
- // OpenClaw scaffold-team constraint.
29
- return isValidId(id) && id.endsWith("-team");
30
- }
31
-
32
- export function CreateCustomTeamModal({
33
- open,
34
- teamId,
35
- setTeamId,
36
- busy,
37
- error,
38
- onClose,
39
- onConfirm,
40
- onRolesChange,
41
- }: {
42
- open: boolean;
43
- teamId: string;
44
- setTeamId: (v: string) => void;
45
- busy?: boolean;
46
- error?: string | null;
47
- onClose: () => void;
48
- onConfirm: () => void;
49
- onRolesChange: (roles: SelectedRole[]) => void;
50
- }) {
51
- const [agents, setAgents] = useState<AgentListItem[]>([]);
52
- const [agentsError, setAgentsError] = useState<string | null>(null);
53
- const [selected, setSelected] = useState<Record<string, SelectedRole>>({});
54
-
55
- const [previewMd, setPreviewMd] = useState<string | null>(null);
56
- const [previewPath, setPreviewPath] = useState<string | null>(null);
57
- const [previewError, setPreviewError] = useState<string | null>(null);
58
-
59
- useEffect(() => {
60
- let cancelled = false;
61
- (async () => {
62
- const res = await fetchJsonWithStatus<{ agents?: AgentListItem[]; error?: string; message?: string }>(
63
- "/api/agents",
64
- { cache: "no-store" },
65
- );
66
- if (cancelled) return;
67
- if (!res.ok) {
68
- setAgentsError(res.error);
69
- return;
70
- }
71
- const list = Array.isArray(res.data.agents) ? res.data.agents : [];
72
- setAgents(list);
73
- })();
74
-
75
- return () => {
76
- cancelled = true;
77
- };
78
- }, []);
79
-
80
- const [availability, setAvailability] = useState<
81
- | { state: "unknown" }
82
- | { state: "checking" }
83
- | { state: "available" }
84
- | { state: "taken"; reason?: string }
85
- >({ state: "unknown" });
86
-
87
- const agentChoices = useMemo(() => {
88
- return agents
89
- .slice()
90
- .sort((a, b) => String(a.id ?? "").localeCompare(String(b.id ?? "")))
91
- .map((a) => ({
92
- id: String(a.id ?? ""),
93
- label: a.identityName ? `${a.identityName} (${a.id})` : String(a.id ?? ""),
94
- }))
95
- .filter((a) => a.id);
96
- }, [agents]);
97
-
98
- const roles = useMemo(() => Object.values(selected), [selected]);
99
-
100
- const teamIdTrimmed = teamId.trim();
101
- const teamIdError = useMemo(() => {
102
- if (!open) return null;
103
- if (!teamIdTrimmed) return "Team id is required.";
104
- if (!isValidId(teamIdTrimmed)) {
105
- return "Invalid team id. Use lowercase letters/numbers with - or _ (2-63 chars).";
106
- }
107
- if (!teamIdTrimmed.endsWith("-team")) {
108
- return "Team id must end with -team.";
109
- }
110
- if (availability.state === "taken") {
111
- return `Team id is already taken: ${teamIdTrimmed}`;
112
- }
113
- return null;
114
- }, [open, teamIdTrimmed, availability.state]);
115
-
116
- const roleErrors = useMemo(() => {
117
- const errors = new Map<string, string>();
118
- for (const r of roles) {
119
- const roleId = String(r.roleId ?? "").trim();
120
- if (!roleId) {
121
- errors.set(r.agentId, "Role id is required.");
122
- continue;
123
- }
124
- if (!isValidId(roleId)) {
125
- errors.set(r.agentId, "Invalid role id (lowercase letters/numbers with - or _)." );
126
- }
127
- }
128
- return errors;
129
- }, [roles]);
130
-
131
- const canConfirm =
132
- !teamIdError &&
133
- availability.state !== "checking" &&
134
- availability.state !== "unknown" &&
135
- roles.length > 0 &&
136
- roleErrors.size === 0;
137
-
138
- useEffect(() => {
139
- if (!open) return;
140
- onRolesChange(roles);
141
- }, [open, roles, onRolesChange]);
142
-
143
- // Team id availability check (debounced).
144
- useEffect(() => {
145
- if (!open) return;
146
-
147
- let cancelled = false;
148
- const t = setTimeout(async () => {
149
- if (!teamIdTrimmed || !isValidTeamId(teamIdTrimmed)) {
150
- setAvailability({ state: "unknown" });
151
- return;
152
- }
153
-
154
- setAvailability({ state: "checking" });
155
-
156
- const res = await fetchJsonWithStatus<{ ok?: boolean; available?: boolean; reason?: string; error?: string }>(
157
- `/api/ids/check?kind=team&id=${encodeURIComponent(teamIdTrimmed)}`,
158
- { cache: "no-store" },
159
- );
160
-
161
- if (cancelled) return;
162
-
163
- if (!res.ok) {
164
- setAvailability({ state: "unknown" });
165
- return;
166
- }
167
-
168
- if (res.data.ok && res.data.available === true) {
169
- setAvailability({ state: "available" });
170
- return;
171
- }
172
-
173
- setAvailability({ state: "taken", reason: res.data.reason });
174
- }, 250);
175
-
176
- return () => {
177
- cancelled = true;
178
- clearTimeout(t);
179
- };
180
- }, [open, teamIdTrimmed]);
181
-
182
- // Best-effort preview (debounced).
183
- useEffect(() => {
184
- if (!open) return;
185
- if (!canConfirm) return;
186
-
187
- let cancelled = false;
188
- const t = setTimeout(async () => {
189
- const baseRecipeId = teamIdTrimmed.endsWith("-team") ? teamIdTrimmed.slice(0, -"-team".length) : teamIdTrimmed;
190
-
191
- const res = await fetchJsonWithStatus<{
192
- ok?: boolean;
193
- error?: string;
194
- md?: string;
195
- filePath?: string;
196
- }>("/api/recipes/custom-team", {
197
- method: "POST",
198
- headers: { "content-type": "application/json" },
199
- body: JSON.stringify({
200
- dryRun: true,
201
- recipeId: baseRecipeId,
202
- teamId: teamIdTrimmed,
203
- roles: roles.map((r) => ({ roleId: r.roleId, displayName: r.displayName })),
204
- }),
205
- });
206
-
207
- if (cancelled) return;
208
-
209
- if (!res.ok) {
210
- setPreviewError(res.error);
211
- setPreviewMd(null);
212
- setPreviewPath(null);
213
- return;
214
- }
215
- if (!res.data.ok) {
216
- setPreviewError(res.data.error || "Failed to generate preview");
217
- setPreviewMd(null);
218
- setPreviewPath(null);
219
- return;
220
- }
221
-
222
- setPreviewError(null);
223
- setPreviewMd(typeof res.data.md === "string" ? res.data.md : null);
224
- setPreviewPath(typeof res.data.filePath === "string" ? res.data.filePath : null);
225
- }, 250);
226
-
227
- return () => {
228
- cancelled = true;
229
- clearTimeout(t);
230
- };
231
- }, [open, canConfirm, teamIdTrimmed, roles]);
232
-
233
- return (
234
- <CreateModalShell
235
- open={open}
236
- title="Create custom team"
237
- recipeId={"(new recipe)"}
238
- recipeName={"Custom Team"}
239
- error={error || agentsError}
240
- busy={busy}
241
- canConfirm={canConfirm}
242
- onClose={onClose}
243
- onConfirm={onConfirm}
244
- confirmLabel="Create team"
245
- >
246
- <div className="mt-4">
247
- <label className="text-sm font-medium text-[color:var(--ck-text-primary)]">Team id</label>
248
- <input
249
- value={teamId}
250
- onChange={(e) => setTeamId(normalizeTeamIdInput(e.target.value))}
251
- placeholder="e.g. my-team"
252
- className="mt-2 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 px-3 py-2 text-sm text-[color:var(--ck-text-primary)] placeholder:text-[color:var(--ck-text-tertiary)]"
253
- autoFocus
254
- />
255
- {teamIdError ? <div className="mt-2 text-xs text-red-300">{teamIdError}</div> : null}
256
- {!teamIdError && teamIdTrimmed ? (
257
- <div className="mt-2 text-xs text-[color:var(--ck-text-tertiary)]">
258
- {availability.state === "checking" ? "Checking availability…" : null}
259
- {availability.state === "available" ? "Available." : null}
260
- </div>
261
- ) : null}
262
- <div className="mt-2 text-xs text-[color:var(--ck-text-tertiary)]">
263
- This creates a new team recipe under <code>~/.openclaw/workspace/recipes</code> and scaffolds
264
- <code className="ml-1">~/.openclaw/workspace-&lt;teamId&gt;</code>.
265
- </div>
266
- </div>
267
-
268
- <div className="mt-6">
269
- <div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Select agents</div>
270
- <div className="mt-2 text-xs text-[color:var(--ck-text-tertiary)]">
271
- MVP: this creates new team roles that mirror the selected agents&apos; names. You can edit the
272
- resulting team recipe later.
273
- </div>
274
-
275
- <div className="mt-3 max-h-[220px] overflow-auto rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 p-3">
276
- {agentChoices.length === 0 ? (
277
- <div className="text-sm text-[color:var(--ck-text-secondary)]">No installed agents found.</div>
278
- ) : (
279
- <div className="space-y-2">
280
- {agentChoices.map((a) => {
281
- const checked = !!selected[a.id];
282
- return (
283
- <label key={a.id} className="flex items-start gap-2 text-sm text-[color:var(--ck-text-secondary)]">
284
- <input
285
- type="checkbox"
286
- checked={checked}
287
- onChange={(e) => {
288
- const next = { ...selected };
289
- if (e.target.checked) {
290
- next[a.id] = {
291
- agentId: a.id,
292
- roleId: defaultRoleIdFromAgentId(a.id),
293
- displayName: a.label,
294
- };
295
- } else {
296
- delete next[a.id];
297
- }
298
- setSelected(next);
299
- }}
300
- />
301
- <span className="min-w-0 break-words">{a.label}</span>
302
- </label>
303
- );
304
- })}
305
- </div>
306
- )}
307
- </div>
308
- </div>
309
-
310
- {roles.length ? (
311
- <div className="mt-6">
312
- <div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Role mapping</div>
313
- <div className="mt-3 space-y-3">
314
- {roles.map((r) => {
315
- const roleErr = roleErrors.get(r.agentId);
316
- return (
317
- <div key={r.agentId} className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 p-3">
318
- <div className="text-xs text-[color:var(--ck-text-tertiary)]">{r.agentId}</div>
319
-
320
- <div className="mt-3 grid grid-cols-1 gap-3 sm:grid-cols-2">
321
- <div>
322
- <label className="text-xs font-medium text-[color:var(--ck-text-secondary)]">Role id</label>
323
- <input
324
- value={r.roleId}
325
- onChange={(e) => {
326
- setSelected((prev) => ({
327
- ...prev,
328
- [r.agentId]: { ...prev[r.agentId], roleId: e.target.value },
329
- }));
330
- }}
331
- className="mt-1 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]"
332
- />
333
- {roleErr ? <div className="mt-1 text-xs text-red-300">{roleErr}</div> : null}
334
- </div>
335
-
336
- <div>
337
- <label className="text-xs font-medium text-[color:var(--ck-text-secondary)]">Display name</label>
338
- <input
339
- value={r.displayName}
340
- onChange={(e) => {
341
- setSelected((prev) => ({
342
- ...prev,
343
- [r.agentId]: { ...prev[r.agentId], displayName: e.target.value },
344
- }));
345
- }}
346
- className="mt-1 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]"
347
- />
348
- </div>
349
- </div>
350
- </div>
351
- );
352
- })}
353
- </div>
354
- </div>
355
- ) : null}
356
-
357
- <div className="mt-6">
358
- <div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Preview</div>
359
- <div className="mt-2 text-xs text-[color:var(--ck-text-tertiary)]">
360
- Generated recipe preview (best-effort). This is what will be written to
361
- <code className="ml-1">~/.openclaw/workspace/recipes/&lt;teamId&gt;.md</code>.
362
- </div>
363
- {canConfirm && previewError ? <div className="mt-2 text-xs text-red-300">{previewError}</div> : null}
364
- {canConfirm && previewPath ? (
365
- <div className="mt-2 text-xs text-[color:var(--ck-text-tertiary)]">
366
- Target path: <code>{previewPath}</code>
367
- </div>
368
- ) : null}
369
- <pre className="mt-3 max-h-[260px] overflow-auto whitespace-pre-wrap rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/30 p-3 text-xs text-[color:var(--ck-text-secondary)]">
370
- {canConfirm ? previewMd || "(Loading preview…)" : "(Select a valid team id and at least one agent to preview.)"}
371
- </pre>
372
- </div>
373
- </CreateModalShell>
374
- );
375
- }
@@ -1,55 +0,0 @@
1
- "use client";
2
-
3
- import { ConfirmationModal } from "@/components/ConfirmationModal";
4
-
5
- export function CreateModalShell({
6
- open,
7
- title,
8
- recipeId,
9
- recipeName,
10
- children,
11
- error,
12
- busy,
13
- canConfirm,
14
- onClose,
15
- onConfirm,
16
- confirmLabel,
17
- }: {
18
- open: boolean;
19
- title: string;
20
- recipeId: string;
21
- recipeName: string;
22
- children: React.ReactNode;
23
- error?: string | null;
24
- busy?: boolean;
25
- canConfirm: boolean;
26
- onClose: () => void;
27
- onConfirm: () => void;
28
- confirmLabel: string;
29
- }) {
30
- return (
31
- <ConfirmationModal
32
- open={open}
33
- onClose={onClose}
34
- title={title}
35
- error={error}
36
- confirmLabel={confirmLabel}
37
- confirmBusyLabel="Creating…"
38
- confirmDisabled={!canConfirm}
39
- busy={busy}
40
- onConfirm={onConfirm}
41
- >
42
- <p className="mt-2 text-sm text-[color:var(--ck-text-secondary)]">
43
- Create a new {title.toLowerCase().replace("create ", "")} from recipe{" "}
44
- <code className="font-mono">{recipeId}</code>
45
- {recipeName ? (
46
- <>
47
- {" "}(<span className="font-medium">{recipeName}</span>)
48
- </>
49
- ) : null}
50
- .
51
- </p>
52
- {children}
53
- </ConfirmationModal>
54
- );
55
- }
@@ -1,91 +0,0 @@
1
- "use client";
2
-
3
- import { useState } from "react";
4
- import { useSlugifiedId } from "@/lib/use-slugified-id";
5
- import { CreateModalShell } from "./CreateModalShell";
6
-
7
- export function CreateTeamModal({
8
- open,
9
- recipeId,
10
- recipeName,
11
- teamId,
12
- setTeamId,
13
- installCron,
14
- setInstallCron,
15
- busy,
16
- error,
17
- onClose,
18
- onConfirm,
19
- }: {
20
- open: boolean;
21
- recipeId: string;
22
- recipeName: string;
23
- teamId: string;
24
- setTeamId: (v: string) => void;
25
- installCron: boolean;
26
- setInstallCron: (v: boolean) => void;
27
- busy?: boolean;
28
- error?: string | null;
29
- onClose: () => void;
30
- onConfirm: () => void;
31
- }) {
32
- const [teamName, setTeamName] = useState("");
33
- const [idTouched, setIdTouched] = useState(false);
34
-
35
- const { effectiveId } = useSlugifiedId({
36
- open,
37
- name: teamName,
38
- setName: setTeamName,
39
- id: teamId,
40
- setId: setTeamId,
41
- idTouched,
42
- setIdTouched,
43
- });
44
-
45
- return (
46
- <CreateModalShell
47
- open={open}
48
- title="Create team"
49
- recipeId={recipeId}
50
- recipeName={recipeName}
51
- error={error}
52
- busy={busy}
53
- canConfirm={!!effectiveId.trim()}
54
- onClose={onClose}
55
- onConfirm={onConfirm}
56
- confirmLabel="Create team"
57
- >
58
- <div className="mt-4">
59
- <label className="text-sm font-medium text-[color:var(--ck-text-primary)]">Team name</label>
60
- <input
61
- value={teamName}
62
- onChange={(e) => setTeamName(e.target.value)}
63
- placeholder="e.g. Crypto Team"
64
- className="mt-2 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 px-3 py-2 text-sm text-[color:var(--ck-text-primary)] placeholder:text-[color:var(--ck-text-tertiary)]"
65
- autoFocus
66
- />
67
- </div>
68
-
69
- <div className="mt-4">
70
- <label className="text-sm font-medium text-[color:var(--ck-text-primary)]">Team id</label>
71
- <input
72
- value={effectiveId}
73
- onChange={(e) => {
74
- setIdTouched(true);
75
- setTeamId(e.target.value);
76
- }}
77
- placeholder="e.g. my-team"
78
- className="mt-2 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 px-3 py-2 text-sm text-[color:var(--ck-text-primary)] placeholder:text-[color:var(--ck-text-tertiary)]"
79
- />
80
- <div className="mt-2 text-xs text-[color:var(--ck-text-tertiary)]">
81
- This will scaffold ~/.openclaw/workspace-&lt;teamId&gt; and add the team to config.
82
- </div>
83
- </div>
84
-
85
- <label className="mt-4 flex items-center gap-2 text-sm text-[color:var(--ck-text-secondary)]">
86
- <input type="checkbox" checked={installCron} onChange={(e) => setInstallCron(e.target.checked)} />
87
- Install cron jobs from this recipe
88
- </label>
89
- </CreateModalShell>
90
- );
91
- }
@@ -1,72 +0,0 @@
1
- "use client";
2
-
3
- import type { ReactNode } from "react";
4
-
5
- type RecipeEditorCreateModalProps = {
6
- open: boolean;
7
- title: string;
8
- recipeId: string;
9
- children: ReactNode;
10
- error?: string;
11
- busy: boolean;
12
- onClose: () => void;
13
- onConfirm: () => void;
14
- confirmLabel: string;
15
- };
16
-
17
- export function RecipeEditorCreateModal({
18
- open,
19
- title,
20
- recipeId,
21
- children,
22
- error,
23
- busy,
24
- onClose,
25
- onConfirm,
26
- confirmLabel,
27
- }: RecipeEditorCreateModalProps) {
28
- if (!open) return null;
29
- return (
30
- <div className="fixed inset-0 z-[100] flex items-center justify-center bg-black/60 p-4" role="dialog" aria-modal="true">
31
- <div className="ck-glass w-full max-w-lg p-5">
32
- <div className="flex items-start justify-between gap-3">
33
- <div className="min-w-0">
34
- <div className="truncate text-lg font-semibold tracking-tight">{title}</div>
35
- <div className="mt-1 text-xs text-[color:var(--ck-text-secondary)]">From recipe: {recipeId}</div>
36
- </div>
37
- <button
38
- type="button"
39
- onClick={() => (!busy ? onClose() : undefined)}
40
- className="rounded-[var(--ck-radius-sm)] px-2 py-1 text-sm text-[color:var(--ck-text-secondary)] hover:text-[color:var(--ck-text-primary)]"
41
- >
42
- Close
43
- </button>
44
- </div>
45
- <div className="mt-4 space-y-3">
46
- {children}
47
- {error ? (
48
- <div className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3 text-sm">{error}</div>
49
- ) : null}
50
- <div className="flex justify-end gap-2 pt-2">
51
- <button
52
- type="button"
53
- disabled={busy}
54
- onClick={onClose}
55
- className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 px-3 py-2 text-sm font-medium text-[color:var(--ck-text-primary)] transition-colors hover:bg-white/10 disabled:opacity-50"
56
- >
57
- Cancel
58
- </button>
59
- <button
60
- type="button"
61
- disabled={busy}
62
- onClick={onConfirm}
63
- className="rounded-[var(--ck-radius-sm)] bg-[var(--ck-accent-red)] px-3 py-2 text-sm font-medium text-white shadow-[var(--ck-shadow-1)] transition-colors hover:bg-[var(--ck-accent-red-hover)] active:bg-[var(--ck-accent-red-active)] disabled:opacity-50"
64
- >
65
- {busy ? "Creating" : confirmLabel}
66
- </button>
67
- </div>
68
- </div>
69
- </div>
70
- </div>
71
- );
72
- }