@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,468 +0,0 @@
1
- "use client";
2
-
3
- import { useEffect, useState } from "react";
4
- import { useRouter } from "next/navigation";
5
- import { errorMessage } from "@/lib/errors";
6
- import { fetchAll, fetchJson } from "@/lib/fetch-json";
7
- import { DeleteAgentModal } from "@/components/delete-modals";
8
- import { IdentityTab, ConfigTab, SkillsTab, FilesTab } from "./agent-editor-tabs";
9
-
10
- type AgentListItem = {
11
- id: string;
12
- identityName?: string;
13
- workspace?: string;
14
- model?: string;
15
- isDefault?: boolean;
16
- };
17
-
18
- type FileListResponse = { ok?: boolean; files?: unknown[] };
19
-
20
- type FileEntry = { name: string; missing: boolean };
21
-
22
- async function loadAgentFilesAndSkills(
23
- agentId: string,
24
- setters: {
25
- setAgentFiles: (f: Array<FileEntry & { required?: boolean; rationale?: string }>) => void;
26
- setSkillsList: (s: string[]) => void;
27
- setAvailableSkills: (s: string[]) => void;
28
- setSelectedSkill: (s: string) => void;
29
- setAgentFilesLoading: (v: boolean) => void;
30
- setSkillsLoading: (v: boolean) => void;
31
- }
32
- ): Promise<void> {
33
- setters.setAgentFilesLoading(true);
34
- setters.setSkillsLoading(true);
35
- try {
36
- const [filesRes, skillsRes, availableSkillsRes] = await fetchAll([
37
- `/api/agents/files?agentId=${encodeURIComponent(agentId)}`,
38
- `/api/agents/skills?agentId=${encodeURIComponent(agentId)}`,
39
- "/api/skills/available",
40
- ]);
41
-
42
- let installedSkills: string[] = [];
43
- try {
44
- const filesJson = (await filesRes.json()) as FileListResponse;
45
- if (filesRes.ok && filesJson.ok) {
46
- const files = Array.isArray(filesJson.files) ? filesJson.files : [];
47
- setters.setAgentFiles(
48
- files.map((f) => {
49
- const entry = f as { name?: unknown; missing?: unknown };
50
- return {
51
- name: String(entry.name ?? ""),
52
- missing: Boolean(entry.missing),
53
- required: Boolean((entry as { required?: unknown }).required),
54
- rationale:
55
- typeof (entry as { rationale?: unknown }).rationale === "string"
56
- ? ((entry as { rationale?: string }).rationale as string)
57
- : undefined,
58
- };
59
- }),
60
- );
61
- }
62
- } catch {
63
- // ignore
64
- }
65
- try {
66
- const skillsJson = (await skillsRes.json()) as { ok?: boolean; skills?: unknown[] };
67
- if (skillsRes.ok && skillsJson.ok) {
68
- installedSkills = Array.isArray(skillsJson.skills) ? (skillsJson.skills as string[]) : [];
69
- setters.setSkillsList(installedSkills);
70
- }
71
- } catch {
72
- // ignore
73
- }
74
- try {
75
- const availableSkillsJson = (await availableSkillsRes.json()) as { ok?: boolean; skills?: unknown[] };
76
- if (availableSkillsRes.ok && availableSkillsJson.ok) {
77
- const list = Array.isArray(availableSkillsJson.skills) ? (availableSkillsJson.skills as string[]) : [];
78
- setters.setAvailableSkills(list);
79
- const first = list.find((s) => !installedSkills.includes(s));
80
- setters.setSelectedSkill(first ?? list[0] ?? "");
81
- }
82
- } catch {
83
- // ignore
84
- }
85
- } finally {
86
- setters.setAgentFilesLoading(false);
87
- setters.setSkillsLoading(false);
88
- }
89
- }
90
-
91
- export default function AgentEditor({ agentId, returnTo }: { agentId: string; returnTo?: string }) {
92
- const router = useRouter();
93
- const [agent, setAgent] = useState<AgentListItem | null>(null);
94
- const [loading, setLoading] = useState(true);
95
- const [saving, setSaving] = useState(false);
96
- const [loadingFile, setLoadingFile] = useState(false);
97
- // Split concerns: avoid file-load errors showing up in the Skills notice area.
98
- const [pageMsg, setPageMsg] = useState<string>("");
99
- const [fileError, setFileError] = useState<string>("");
100
- const [skillMsg, setSkillMsg] = useState<string>("");
101
- const [skillError, setSkillError] = useState<string>("");
102
-
103
- const [deleteOpen, setDeleteOpen] = useState(false);
104
- const [deleteBusy, setDeleteBusy] = useState(false);
105
- const [deleteError, setDeleteError] = useState<string | null>(null);
106
-
107
- const [activeTab, setActiveTab] = useState<"identity" | "config" | "skills" | "files">("identity");
108
-
109
- const [name, setName] = useState<string>("");
110
- const [emoji, setEmoji] = useState<string>("");
111
- const [theme, setTheme] = useState<string>("");
112
- const [avatar, setAvatar] = useState<string>("");
113
-
114
- const [model, setModel] = useState<string>("");
115
-
116
- const [skillsList, setSkillsList] = useState<string[]>([]);
117
- const [availableSkills, setAvailableSkills] = useState<string[]>([]);
118
- const [skillsLoading, setSkillsLoading] = useState(false);
119
- const [selectedSkill, setSelectedSkill] = useState<string>("");
120
- const [installingSkill, setInstallingSkill] = useState(false);
121
-
122
- const [agentFiles, setAgentFiles] = useState<Array<FileEntry & { required?: boolean; rationale?: string }>>([]);
123
- const [agentFilesLoading, setAgentFilesLoading] = useState(false);
124
- const [showOptionalFiles, setShowOptionalFiles] = useState(false);
125
- const [fileName, setFileName] = useState<string>("SOUL.md");
126
- const [fileContent, setFileContent] = useState<string>("");
127
-
128
- const teamId = agentId.includes("-") ? agentId.split("-").slice(0, -1).join("-") : "";
129
-
130
- useEffect(() => {
131
- (async () => {
132
- setLoading(true);
133
- setPageMsg("");
134
- try {
135
- const agentsJson = await fetchJson<{ agents?: unknown[] }>("/api/agents", { cache: "no-store" });
136
- const list = Array.isArray(agentsJson.agents) ? (agentsJson.agents as AgentListItem[]) : [];
137
- const found = list.find((a) => a.id === agentId) ?? null;
138
- setAgent(found);
139
- setName(found?.identityName ?? "");
140
- setModel(found?.model ?? "");
141
-
142
- setLoading(false);
143
-
144
- void loadAgentFilesAndSkills(agentId, {
145
- setAgentFiles,
146
- setSkillsList,
147
- setAvailableSkills,
148
- setSelectedSkill,
149
- setAgentFilesLoading,
150
- setSkillsLoading,
151
- });
152
- } catch (e: unknown) {
153
- setPageMsg(errorMessage(e));
154
- } finally {
155
- setLoading(false);
156
- }
157
- })();
158
- }, [agentId]);
159
-
160
- async function withSaveFeedback(
161
- fn: () => Promise<string>,
162
- ) {
163
- setSaving(true);
164
- setPageMsg("");
165
- try {
166
- const msg = await fn();
167
- setPageMsg(msg);
168
- } catch (e: unknown) {
169
- setPageMsg(errorMessage(e));
170
- } finally {
171
- setSaving(false);
172
- }
173
- }
174
-
175
- async function onSaveIdentity() {
176
- await withSaveFeedback(async () => {
177
- await fetchJson("/api/agents/identity", {
178
- method: "POST",
179
- headers: { "content-type": "application/json" },
180
- body: JSON.stringify({ agentId, name, emoji, theme, avatar }),
181
- });
182
- return "Saved identity via openclaw agents set-identity";
183
- });
184
- }
185
-
186
- async function onSaveConfig() {
187
- await withSaveFeedback(async () => {
188
- await fetchJson("/api/agents/update", {
189
- method: "POST",
190
- headers: { "content-type": "application/json" },
191
- body: JSON.stringify({ agentId, patch: { model } }),
192
- });
193
- return "Saved agent config (model) and restarted gateway";
194
- });
195
- }
196
-
197
- async function onLoadAgentFile(nextName: string) {
198
- // Update selection immediately so the UI reflects what the user clicked,
199
- // even if the network request fails.
200
- setFileName(nextName);
201
- setFileContent("");
202
-
203
- setLoadingFile(true);
204
- setFileError("");
205
- try {
206
- const json = await fetchJson<{ ok?: boolean; content?: string }>(
207
- `/api/agents/file?agentId=${encodeURIComponent(agentId)}&name=${encodeURIComponent(nextName)}`,
208
- { cache: "no-store" },
209
- );
210
- if (!json.ok) throw new Error("Failed to load file");
211
- setFileContent(String(json.content ?? ""));
212
- } catch (e: unknown) {
213
- setFileError(errorMessage(e));
214
- } finally {
215
- setLoadingFile(false);
216
- }
217
- }
218
-
219
- // When entering the Files tab, load the current file immediately (default: IDENTITY.md).
220
- useEffect(() => {
221
- if (activeTab !== "files") return;
222
- if (!agentFiles.length) return;
223
-
224
- const exists = agentFiles.some((f) => f.name === fileName);
225
- const fallback = agentFiles[0]?.name;
226
- const target = exists ? fileName : fallback;
227
- if (!target) return;
228
-
229
- if (target !== fileName) {
230
- setFileName(target);
231
- setFileContent("");
232
- }
233
-
234
- if (!fileContent) {
235
- onLoadAgentFile(target);
236
- }
237
- // eslint-disable-next-line react-hooks/exhaustive-deps -- Load file when entering Files tab; onLoadAgentFile and fileContent intentionally omitted.
238
- }, [activeTab, agentId, agentFiles.length]);
239
-
240
- function defaultFileContent(name: string) {
241
- switch (name) {
242
- case "SOUL.md":
243
- return "# SOUL.md\n\n";
244
- case "AGENTS.md":
245
- return "# AGENTS.md\n\n";
246
- case "TOOLS.md":
247
- return "# TOOLS.md\n\n";
248
- case "STATUS.md":
249
- return "# STATUS.md\n\n- (empty)\n";
250
- case "NOTES.md":
251
- return "# NOTES.md\n\n- (empty)\n";
252
- case "IDENTITY.md":
253
- return "# IDENTITY.md\n\n- **Name:**\n- **Creature:**\n- **Vibe:**\n- **Emoji:**\n- **Avatar:**\n";
254
- case "USER.md":
255
- return "# USER.md\n\n";
256
- case "HEARTBEAT.md":
257
- return "# HEARTBEAT.md\n\n# Keep this file empty (or with only comments) to skip heartbeat API calls.\n";
258
- default:
259
- return "";
260
- }
261
- }
262
-
263
- async function onSaveAgentFile() {
264
- setSaving(true);
265
- setFileError("");
266
- try {
267
- const json = await fetchJson<{ ok?: boolean }>("/api/agents/file", {
268
- method: "PUT",
269
- headers: { "content-type": "application/json" },
270
- body: JSON.stringify({ agentId, name: fileName, content: fileContent }),
271
- });
272
- if (!json.ok) throw new Error("Failed to save file");
273
-
274
- // Refresh the file list so missing/mtime updates immediately.
275
- try {
276
- const j = await fetchJson<{ ok?: boolean; files?: Array<FileEntry & { required?: boolean; rationale?: string }> }>(
277
- `/api/agents/files?agentId=${encodeURIComponent(agentId)}`,
278
- { cache: "no-store" },
279
- );
280
- if (j.ok && Array.isArray(j.files)) setAgentFiles(j.files);
281
- } catch {
282
- // ignore
283
- }
284
- // No-op: saving a file doesn't need a global notice.
285
- } catch (e: unknown) {
286
- setFileError(errorMessage(e));
287
- } finally {
288
- setSaving(false);
289
- }
290
- }
291
-
292
- async function onCreateMissingFile(name: string) {
293
- setFileName(name);
294
- setFileError("");
295
- setFileContent(defaultFileContent(name));
296
- await onSaveAgentFile();
297
- }
298
-
299
- async function onDeleteAgent() {
300
- setDeleteBusy(true);
301
- setDeleteError(null);
302
- setPageMsg("");
303
-
304
- try {
305
- await fetchJson(`/api/agents/${encodeURIComponent(agentId)}`, { method: "DELETE" });
306
-
307
- window.location.href = "/";
308
- } catch (e: unknown) {
309
- setDeleteError(errorMessage(e));
310
- setDeleteBusy(false);
311
- }
312
- }
313
-
314
- // Initial load only gates the minimal state (agent exists). Files/skills stream in.
315
- if (loading) return <div className="ck-glass mx-auto max-w-4xl p-6">Loading…</div>;
316
- if (!agent) return <div className="ck-glass mx-auto max-w-4xl p-6">Agent not found: {agentId}</div>;
317
-
318
- return (
319
- <div className="ck-glass mx-auto max-w-4xl p-6 sm:p-8">
320
- <div className="flex flex-wrap items-start justify-between gap-3">
321
- <div>
322
- <h1 className="text-2xl font-semibold tracking-tight">Agent editor</h1>
323
- <div className="mt-1 text-xs text-[color:var(--ck-text-secondary)]">
324
- {agent.id}
325
- {agent.isDefault ? " • default" : ""}
326
- {agent.model ? ` • ${agent.model}` : ""}
327
- </div>
328
- </div>
329
- <button
330
- type="button"
331
- disabled={saving}
332
- onClick={() => {
333
- setDeleteError(null);
334
- setDeleteOpen(true);
335
- }}
336
- className="rounded-[var(--ck-radius-sm)] border border-[color:rgba(255,59,48,0.45)] bg-[color:rgba(255,59,48,0.08)] px-3 py-2 text-sm font-medium text-[color:var(--ck-accent-red)] shadow-[var(--ck-shadow-1)] transition-colors hover:bg-[color:rgba(255,59,48,0.12)] disabled:opacity-50"
337
- >
338
- Delete agent
339
- </button>
340
- </div>
341
- {agent.workspace ? (
342
- <div className="mt-1 text-xs text-[color:var(--ck-text-tertiary)]">Workspace: {agent.workspace}</div>
343
- ) : null}
344
- {teamId ? <div className="mt-1 text-xs text-[color:var(--ck-text-tertiary)]">Team: {teamId}</div> : null}
345
-
346
- {pageMsg ? (
347
- <div className="mt-4 rounded-[var(--ck-radius-sm)] border border-white/10 bg-white/5 p-3 text-sm text-[color:var(--ck-text-primary)]">
348
- {pageMsg}
349
- </div>
350
- ) : null}
351
-
352
- <div className="mt-6 flex flex-wrap gap-2">
353
- {(
354
- [
355
- { id: "identity", label: "Identity" },
356
- { id: "config", label: "Config" },
357
- { id: "skills", label: "Skills" },
358
- { id: "files", label: "Files" },
359
- ] as const
360
- ).map((t) => (
361
- <button
362
- key={t.id}
363
- onClick={() => setActiveTab(t.id)}
364
- className={
365
- activeTab === t.id
366
- ? "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)]"
367
- : "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)] shadow-[var(--ck-shadow-1)] hover:bg-white/10"
368
- }
369
- >
370
- {t.label}
371
- </button>
372
- ))}
373
- </div>
374
-
375
- <div className="mt-6 grid grid-cols-1 gap-4">
376
- {activeTab === "identity" && (
377
- <IdentityTab
378
- name={name}
379
- emoji={emoji}
380
- theme={theme}
381
- avatar={avatar}
382
- saving={saving}
383
- returnTo={returnTo}
384
- onNameChange={setName}
385
- onEmojiChange={setEmoji}
386
- onThemeChange={setTheme}
387
- onAvatarChange={setAvatar}
388
- onSave={onSaveIdentity}
389
- router={router}
390
- />
391
- )}
392
- {activeTab === "config" && (
393
- <ConfigTab
394
- model={model}
395
- saving={saving}
396
- onModelChange={setModel}
397
- onSave={onSaveConfig}
398
- />
399
- )}
400
- {activeTab === "skills" && (
401
- <SkillsTab
402
- agentId={agentId}
403
- skillsList={skillsList}
404
- availableSkills={availableSkills}
405
- skillsLoading={skillsLoading}
406
- selectedSkill={selectedSkill}
407
- installingSkill={installingSkill}
408
- skillError={skillError}
409
- skillMsg={skillMsg}
410
- onSelectedSkillChange={setSelectedSkill}
411
- onInstallSkill={async () => {
412
- setInstallingSkill(true);
413
- setSkillMsg("");
414
- setSkillError("");
415
- try {
416
- await fetchJson("/api/agents/skills/install", {
417
- method: "POST",
418
- headers: { "content-type": "application/json" },
419
- body: JSON.stringify({ agentId, skill: selectedSkill }),
420
- });
421
- setSkillMsg(`Installed skill: ${selectedSkill}`);
422
- try {
423
- const j = await fetchJson<{ ok?: boolean; skills?: string[] }>(
424
- `/api/agents/skills?agentId=${encodeURIComponent(agentId)}`,
425
- { cache: "no-store" },
426
- );
427
- if (j.ok && Array.isArray(j.skills)) setSkillsList(j.skills);
428
- } catch {
429
- // ignore
430
- }
431
- } catch (e: unknown) {
432
- setSkillError(errorMessage(e));
433
- } finally {
434
- setInstallingSkill(false);
435
- }
436
- }}
437
- />
438
- )}
439
- {activeTab === "files" && (
440
- <FilesTab
441
- agentFiles={agentFiles}
442
- agentFilesLoading={agentFilesLoading}
443
- showOptionalFiles={showOptionalFiles}
444
- fileName={fileName}
445
- fileContent={fileContent}
446
- loadingFile={loadingFile}
447
- saving={saving}
448
- fileError={fileError}
449
- onShowOptionalChange={setShowOptionalFiles}
450
- onLoadFile={onLoadAgentFile}
451
- onFileContentChange={setFileContent}
452
- onSaveFile={onSaveAgentFile}
453
- onCreateMissingFile={onCreateMissingFile}
454
- />
455
- )}
456
- </div>
457
-
458
- <DeleteAgentModal
459
- open={deleteOpen}
460
- agentId={agentId}
461
- busy={deleteBusy}
462
- error={deleteError}
463
- onClose={() => setDeleteOpen(false)}
464
- onConfirm={() => void onDeleteAgent()}
465
- />
466
- </div>
467
- );
468
- }
@@ -1,32 +0,0 @@
1
- import Link from "next/link";
2
- import AgentEditor from "./agent-editor";
3
-
4
- export default async function AgentPage({
5
- params,
6
- searchParams,
7
- }: {
8
- params: Promise<{ agentId: string }>;
9
- searchParams?: Promise<Record<string, string | string[] | undefined>>;
10
- }) {
11
- const { agentId } = await params;
12
- const sp = (await searchParams) ?? {};
13
- const returnToRaw = sp.returnTo;
14
- const returnTo = Array.isArray(returnToRaw) ? returnToRaw[0] : returnToRaw;
15
- const backHref = typeof returnTo === "string" && returnTo.trim() ? returnTo : "/";
16
-
17
- return (
18
- <main className="min-h-screen p-8">
19
- <div className="mx-auto mb-4 flex max-w-6xl items-center justify-between gap-4">
20
- <Link
21
- href={backHref}
22
- className="text-sm font-medium text-[color:var(--ck-text-secondary)] transition-colors hover:text-[color:var(--ck-text-primary)]"
23
- >
24
- ← Back
25
- </Link>
26
- <div className="text-xs text-[color:var(--ck-text-tertiary)]">Agent: {agentId}</div>
27
- </div>
28
-
29
- <AgentEditor agentId={agentId} returnTo={typeof returnTo === "string" ? returnTo : undefined} />
30
- </main>
31
- );
32
- }
@@ -1,143 +0,0 @@
1
- import { describe, expect, it, vi, beforeEach } from "vitest";
2
- import { POST } from "../agents/add/route";
3
- import path from "node:path";
4
-
5
- const mockRunCommand = vi.hoisted(() => vi.fn());
6
-
7
- vi.mock("@/lib/kitchen-api", () => ({
8
- getKitchenApi: () => ({
9
- runtime: {
10
- system: {
11
- runCommandWithTimeout: mockRunCommand,
12
- },
13
- },
14
- }),
15
- }));
16
- vi.mock("node:fs/promises", () => ({
17
- default: {
18
- readFile: vi.fn(),
19
- mkdir: vi.fn(),
20
- writeFile: vi.fn(),
21
- copyFile: vi.fn(),
22
- rename: vi.fn(),
23
- },
24
- }));
25
-
26
- import fs from "node:fs/promises";
27
-
28
- const baseWorkspace = "/mock-workspace";
29
- const existingConfig = {
30
- agents: {
31
- defaults: { workspace: baseWorkspace },
32
- list: [{ id: "existing", workspace: "/ws/existing" }],
33
- },
34
- };
35
-
36
- describe("api agents add route", () => {
37
- beforeEach(() => {
38
- mockRunCommand.mockReset();
39
- vi.mocked(fs.readFile).mockReset();
40
- vi.mocked(fs.mkdir).mockReset();
41
- vi.mocked(fs.writeFile).mockReset();
42
- vi.mocked(fs.copyFile).mockReset();
43
- vi.mocked(fs.rename).mockReset();
44
-
45
- vi.stubEnv("HOME", "/mock-home");
46
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(existingConfig));
47
- vi.mocked(fs.mkdir).mockResolvedValue(undefined);
48
- vi.mocked(fs.writeFile).mockResolvedValue(undefined);
49
- vi.mocked(fs.copyFile).mockResolvedValue(undefined);
50
- vi.mocked(fs.rename).mockResolvedValue(undefined);
51
- mockRunCommand.mockResolvedValue({ stdout: "", stderr: "" });
52
- });
53
-
54
- it("returns 400 when agent id missing", async () => {
55
- const res = await POST(
56
- new Request("https://test", {
57
- method: "POST",
58
- body: JSON.stringify({}),
59
- })
60
- );
61
- expect(res.status).toBe(400);
62
- const json = await res.json();
63
- expect(json.error).toContain("agent id is required");
64
- });
65
-
66
- it("returns 400 when agent id invalid format", async () => {
67
- const res = await POST(
68
- new Request("https://test", {
69
- method: "POST",
70
- body: JSON.stringify({ newAgentId: "bad id!" }),
71
- })
72
- );
73
- expect(res.status).toBe(400);
74
- const json = await res.json();
75
- expect(json.error).toContain("match");
76
- });
77
-
78
- it("returns 500 when HOME not set", async () => {
79
- vi.stubEnv("HOME", "");
80
-
81
- const res = await POST(
82
- new Request("https://test", {
83
- method: "POST",
84
- body: JSON.stringify({ newAgentId: "my-agent" }),
85
- })
86
- );
87
- expect(res.status).toBe(500);
88
- const json = await res.json();
89
- expect(json.error).toBe("HOME is not set");
90
- });
91
-
92
- it("returns 500 when workspace not set in config", async () => {
93
- vi.mocked(fs.readFile).mockResolvedValue(
94
- JSON.stringify({ agents: {} })
95
- );
96
-
97
- const res = await POST(
98
- new Request("https://test", {
99
- method: "POST",
100
- body: JSON.stringify({ newAgentId: "my-agent" }),
101
- })
102
- );
103
- expect(res.status).toBe(500);
104
- const json = await res.json();
105
- expect(json.error).toBe("agents.defaults.workspace not set");
106
- });
107
-
108
- it("returns 409 when agent exists and overwrite false", async () => {
109
- const res = await POST(
110
- new Request("https://test", {
111
- method: "POST",
112
- body: JSON.stringify({ newAgentId: "existing" }),
113
- })
114
- );
115
- expect(res.status).toBe(409);
116
- const json = await res.json();
117
- expect(json.error).toBe("Agent already exists: existing");
118
- });
119
-
120
- it("returns ok and restarts gateway on success", async () => {
121
- const res = await POST(
122
- new Request("https://test", {
123
- method: "POST",
124
- body: JSON.stringify({
125
- newAgentId: "my-agent",
126
- name: "My Agent",
127
- }),
128
- })
129
- );
130
- expect(res.status).toBe(200);
131
- const json = await res.json();
132
- expect(json.ok).toBe(true);
133
- expect(json.agentId).toBe("my-agent");
134
- expect(json.restarted).toBe(true);
135
- expect(json.workspace).toBe(
136
- path.resolve(baseWorkspace, "..", "workspace-my-agent")
137
- );
138
- expect(mockRunCommand).toHaveBeenCalledWith(
139
- ["openclaw", "gateway", "restart"],
140
- expect.objectContaining({ timeoutMs: 120000 })
141
- );
142
- });
143
- });