@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,216 +0,0 @@
1
- "use client";
2
-
3
- import type { ReactNode } from "react";
4
- import { expectedFilesForRole, templateKeyToFileName } from "./recipe-editor-utils";
5
- import type { AgentRecipeFrontmatter, TeamRecipeFrontmatter } from "./types";
6
-
7
- function RecipePanelCard({
8
- title,
9
- description,
10
- buttonLabel,
11
- onButtonClick,
12
- error,
13
- children,
14
- }: {
15
- title: string;
16
- description: ReactNode;
17
- buttonLabel: string;
18
- onButtonClick: () => void;
19
- error?: string;
20
- children: ReactNode;
21
- }) {
22
- return (
23
- <div className="ck-glass-strong p-4">
24
- <div className="flex items-start justify-between gap-3">
25
- <div>
26
- <div className="text-sm font-medium text-[color:var(--ck-text-primary)]">{title}</div>
27
- <div className="mt-1 text-xs text-[color:var(--ck-text-tertiary)]">{description}</div>
28
- </div>
29
- <button
30
- type="button"
31
- onClick={onButtonClick}
32
- className="shrink-0 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)]"
33
- >
34
- {buttonLabel}
35
- </button>
36
- </div>
37
- {error ? (
38
- <div className="mt-4 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3 text-xs text-[color:var(--ck-text-primary)]">
39
- Frontmatter parse error: {error}
40
- </div>
41
- ) : null}
42
- {children}
43
- </div>
44
- );
45
- }
46
-
47
- function TeamRecipeDetails({ fm, recipe }: { fm: TeamRecipeFrontmatter | null; recipe: { id: string } }) {
48
- return (
49
- <div className="mt-4 space-y-3">
50
- <details className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/15 p-3" open>
51
- <summary className="cursor-pointer text-sm font-medium text-[color:var(--ck-text-primary)]">Recipe information</summary>
52
- <div className="mt-2 space-y-1 text-xs text-[color:var(--ck-text-secondary)]">
53
- <div><span className="text-[color:var(--ck-text-tertiary)]">Recipe id:</span> {fm?.id ?? recipe.id}</div>
54
- <div><span className="text-[color:var(--ck-text-tertiary)]">Version:</span> {fm?.version ?? "(unknown)"}</div>
55
- <div><span className="text-[color:var(--ck-text-tertiary)]">Team id:</span> {fm?.team?.teamId ?? "(not set)"}</div>
56
- {fm?.description ? <div className="whitespace-pre-wrap">{fm.description}</div> : null}
57
- </div>
58
- </details>
59
- <TeamAgentsDetails fm={fm} />
60
- <TeamCronDetails fm={fm} />
61
- </div>
62
- );
63
- }
64
-
65
- function TeamAgentsDetails({ fm }: { fm: TeamRecipeFrontmatter | null }) {
66
- return (
67
- <details className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/15 p-3">
68
- <summary className="cursor-pointer text-sm font-medium text-[color:var(--ck-text-primary)]">
69
- Agents ({fm?.agents?.length ?? 0})
70
- </summary>
71
- <div className="mt-2 space-y-2">
72
- {(fm?.agents ?? []).map((a, idx) => (
73
- <details key={`${a.role ?? "agent"}:${idx}`} className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3">
74
- <summary className="cursor-pointer text-sm text-[color:var(--ck-text-primary)]">
75
- <span className="font-medium">{a.name ?? a.role ?? "(unnamed)"}</span>
76
- {a.role ? <span className="text-[color:var(--ck-text-tertiary)]"> — {a.role}</span> : null}
77
- </summary>
78
- <div className="mt-2 space-y-1 text-xs text-[color:var(--ck-text-secondary)]">
79
- <div><span className="text-[color:var(--ck-text-tertiary)]">Role:</span> {a.role ?? "(none)"}</div>
80
- <div><span className="text-[color:var(--ck-text-tertiary)]">Tools profile:</span> {a.tools?.profile ?? "(default)"}</div>
81
- <div><span className="text-[color:var(--ck-text-tertiary)]">Allow:</span> {(a.tools?.allow ?? []).length ? (a.tools?.allow ?? []).join(", ") : "(none)"}</div>
82
- <div><span className="text-[color:var(--ck-text-tertiary)]">Deny:</span> {(a.tools?.deny ?? []).length ? (a.tools?.deny ?? []).join(", ") : "(none)"}</div>
83
- <div className="pt-1">
84
- <span className="text-[color:var(--ck-text-tertiary)]">Expected files:</span>{" "}
85
- {expectedFilesForRole(fm, a.role).length ? expectedFilesForRole(fm, a.role).join(", ") : "(not listed)"}
86
- </div>
87
- </div>
88
- </details>
89
- ))}
90
- {(!fm?.agents || fm.agents.length === 0) ? (
91
- <div className="text-xs text-[color:var(--ck-text-tertiary)]">(No agents listed in frontmatter)</div>
92
- ) : null}
93
- </div>
94
- </details>
95
- );
96
- }
97
-
98
- function TeamCronDetails({ fm }: { fm: TeamRecipeFrontmatter | null }) {
99
- return (
100
- <details className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/15 p-3">
101
- <summary className="cursor-pointer text-sm font-medium text-[color:var(--ck-text-primary)]">
102
- Cron jobs ({fm?.cronJobs?.length ?? 0})
103
- </summary>
104
- <div className="mt-2 space-y-2">
105
- {(fm?.cronJobs ?? []).map((c, idx) => (
106
- <details key={`${c.id ?? "cron"}:${idx}`} className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3">
107
- <summary className="cursor-pointer text-sm text-[color:var(--ck-text-primary)]">
108
- <span className="font-medium">{c.name ?? c.id ?? "(unnamed)"}</span>
109
- {c.schedule ? <span className="text-[color:var(--ck-text-tertiary)]"> — {c.schedule}</span> : null}
110
- </summary>
111
- <div className="mt-2 space-y-1 text-xs text-[color:var(--ck-text-secondary)]">
112
- {c.agentId ? <div><span className="text-[color:var(--ck-text-tertiary)]">Agent:</span> {c.agentId}</div> : null}
113
- {c.channel ? <div><span className="text-[color:var(--ck-text-tertiary)]">Channel:</span> {c.channel}</div> : null}
114
- {typeof c.enabledByDefault === "boolean" ? (
115
- <div><span className="text-[color:var(--ck-text-tertiary)]">Enabled by default:</span> {c.enabledByDefault ? "yes" : "no"}</div>
116
- ) : null}
117
- {c.message ? (
118
- <div className="mt-2 whitespace-pre-wrap rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 p-2 text-[11px] text-[color:var(--ck-text-primary)]">{c.message}</div>
119
- ) : null}
120
- </div>
121
- </details>
122
- ))}
123
- {(!fm?.cronJobs || fm.cronJobs.length === 0) ? (
124
- <div className="text-xs text-[color:var(--ck-text-tertiary)]">(No cron jobs listed in frontmatter)</div>
125
- ) : null}
126
- </div>
127
- </details>
128
- );
129
- }
130
-
131
- export function TeamRecipePanelContent({
132
- recipe,
133
- fm,
134
- fmErr,
135
- onOpenCreateTeam,
136
- }: {
137
- recipe: { id: string };
138
- fm: TeamRecipeFrontmatter | null;
139
- fmErr?: string;
140
- onOpenCreateTeam: () => void;
141
- }) {
142
- return (
143
- <RecipePanelCard
144
- title="Team recipe"
145
- description={
146
- <>
147
- Create a team from this recipe. Creating a Team runs <code>openclaw recipes scaffold-team</code> with{" "}
148
- <code>--apply-config</code>.
149
- </>
150
- }
151
- buttonLabel="Create Team"
152
- onButtonClick={onOpenCreateTeam}
153
- error={fmErr}
154
- >
155
- <TeamRecipeDetails fm={fm} recipe={recipe} />
156
- </RecipePanelCard>
157
- );
158
- }
159
-
160
- export function AgentRecipePanelContent({
161
- recipe,
162
- afm,
163
- afmErr,
164
- onOpenCreateAgent,
165
- }: {
166
- recipe: { id: string };
167
- afm: AgentRecipeFrontmatter | null;
168
- afmErr?: string;
169
- onOpenCreateAgent: () => void;
170
- }) {
171
- return (
172
- <RecipePanelCard
173
- title="Agent recipe"
174
- description={
175
- <>
176
- Create an agent from this recipe. Creating an Agent runs <code>openclaw recipes scaffold</code> with{" "}
177
- <code>--apply-config</code>.
178
- </>
179
- }
180
- buttonLabel="Create Agent"
181
- onButtonClick={onOpenCreateAgent}
182
- error={afmErr}
183
- >
184
- <div className="mt-4 space-y-3">
185
- <details className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/15 p-3" open>
186
- <summary className="cursor-pointer text-sm font-medium text-[color:var(--ck-text-primary)]">Recipe information</summary>
187
- <div className="mt-2 space-y-1 text-xs text-[color:var(--ck-text-secondary)]">
188
- <div><span className="text-[color:var(--ck-text-tertiary)]">Recipe id:</span> {afm?.id ?? recipe.id}</div>
189
- <div><span className="text-[color:var(--ck-text-tertiary)]">Version:</span> {afm?.version ?? "(unknown)"}</div>
190
- {afm?.description ? <div className="whitespace-pre-wrap">{afm.description}</div> : null}
191
- </div>
192
- </details>
193
- <details className="rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/15 p-3">
194
- <summary className="cursor-pointer text-sm font-medium text-[color:var(--ck-text-primary)]">
195
- Files ({Object.keys(afm?.templates ?? {}).length})
196
- </summary>
197
- <div className="mt-2 space-y-1 text-xs text-[color:var(--ck-text-secondary)]">
198
- {Object.keys(afm?.templates ?? {}).length ? (
199
- <ul className="list-disc space-y-1 pl-5">
200
- {Object.keys(afm?.templates ?? {}).map((k) => (
201
- <li key={k}>
202
- <span className="font-mono text-[11px]">{k}</span>
203
- <span className="text-[color:var(--ck-text-tertiary)]"> → </span>
204
- <span className="font-mono text-[11px]">{templateKeyToFileName(k)}</span>
205
- </li>
206
- ))}
207
- </ul>
208
- ) : (
209
- <div className="text-[color:var(--ck-text-tertiary)]">(No templates listed in frontmatter)</div>
210
- )}
211
- </div>
212
- </details>
213
- </div>
214
- </RecipePanelCard>
215
- );
216
- }
@@ -1,271 +0,0 @@
1
- "use client";
2
-
3
- import { useEffect, useMemo, useState } from "react";
4
- import { useRouter } from "next/navigation";
5
- import { errorMessage } from "@/lib/errors";
6
- import { fetchJson } from "@/lib/fetch-json";
7
- import { validateCreateId } from "@/lib/recipe-team-agents";
8
- import { fetchScaffold } from "@/lib/scaffold-client";
9
- import type { AgentRecipeFrontmatter, Recipe, TeamRecipeFrontmatter } from "./types";
10
- import { parseFrontmatter } from "./recipe-editor-utils";
11
- import { TeamRecipePanelContent, AgentRecipePanelContent } from "./RecipeEditorPanel";
12
- import { RecipeEditorCreateModal } from "./RecipeEditorCreateModal";
13
-
14
- type CreateModalKind = "team" | "agent" | null;
15
-
16
- export default function RecipeEditor({ recipeId }: { recipeId: string }) {
17
- const router = useRouter();
18
-
19
- const [loading, setLoading] = useState(true);
20
- const [saving, setSaving] = useState(false);
21
- const [recipe, setRecipe] = useState<Recipe | null>(null);
22
- const [content, setContent] = useState<string>("");
23
- const [message, setMessage] = useState<string>("");
24
-
25
- const [createModalKind, setCreateModalKind] = useState<CreateModalKind>(null);
26
- const [createId, setCreateId] = useState("");
27
- const [createName, setCreateName] = useState("");
28
- const [cronInstallChoice, setCronInstallChoice] = useState<"yes" | "no">("no");
29
- const [createBusy, setCreateBusy] = useState(false);
30
- const [createError, setCreateError] = useState("");
31
-
32
- useEffect(() => {
33
- (async () => {
34
- setLoading(true);
35
- setMessage("");
36
- try {
37
- const json = await fetchJson<{ recipe: Recipe }>(
38
- `/api/recipes/${encodeURIComponent(recipeId)}`,
39
- { cache: "no-store" }
40
- );
41
- const r = json.recipe;
42
- setRecipe(r);
43
- setContent(r.content);
44
- } catch (e: unknown) {
45
- setMessage(errorMessage(e));
46
- } finally {
47
- setLoading(false);
48
- }
49
- })();
50
- }, [recipeId]);
51
-
52
- const canSave = useMemo(() => {
53
- if (!recipe) return false;
54
- return recipe.filePath !== null;
55
- }, [recipe]);
56
-
57
- const teamFrontmatter = useMemo(() => {
58
- if (!recipe || recipe.kind !== "team") return { fm: null as TeamRecipeFrontmatter | null, error: undefined as string | undefined };
59
- return parseFrontmatter(content);
60
- }, [recipe, content]);
61
-
62
- const agentFrontmatter = useMemo(() => {
63
- if (!recipe || recipe.kind !== "agent") return { fm: null as AgentRecipeFrontmatter | null, error: undefined as string | undefined };
64
- return parseFrontmatter(content);
65
- }, [recipe, content]);
66
-
67
- async function onSave() {
68
- setSaving(true);
69
- setMessage("");
70
- try {
71
- const json = await fetchJson<{ filePath: string }>(
72
- `/api/recipes/${encodeURIComponent(recipeId)}`,
73
- {
74
- method: "PUT",
75
- headers: { "content-type": "application/json" },
76
- body: JSON.stringify({ content }),
77
- }
78
- );
79
- setMessage(`Saved to ${json.filePath}`);
80
- } catch (e: unknown) {
81
- setMessage(errorMessage(e));
82
- } finally {
83
- setSaving(false);
84
- }
85
- }
86
-
87
- function openCreateTeam() {
88
- setCreateError("");
89
- setCreateId("");
90
- setCronInstallChoice("no");
91
- setCreateModalKind("team");
92
- }
93
-
94
- function openCreateAgent() {
95
- setCreateError("");
96
- setCreateId("");
97
- setCreateName((agentFrontmatter.fm?.name || recipe?.name || "").trim());
98
- setCreateModalKind("agent");
99
- }
100
-
101
- async function onSubmitCreate() {
102
- if (!recipe || !createModalKind) return;
103
- const kind = createModalKind;
104
- const err = validateCreateId(recipe, createId, kind);
105
- if (err) {
106
- setCreateError(err);
107
- return;
108
- }
109
-
110
- const id = createId.trim();
111
- setCreateBusy(true);
112
- setCreateError("");
113
-
114
- try {
115
- if (kind === "team") {
116
- const { res, json } = await fetchScaffold({
117
- kind: "team",
118
- recipeId: recipe.id,
119
- teamId: id,
120
- cronInstallChoice,
121
- });
122
- if (!res.ok) throw new Error((json as { error?: string }).error || "Create Team failed");
123
- setCreateModalKind(null);
124
- router.push(`/teams/${encodeURIComponent(id)}`);
125
- } else {
126
- const { res, json } = await fetchScaffold({
127
- kind: "agent",
128
- recipeId: recipe.id,
129
- agentId: id,
130
- name: createName.trim() || undefined,
131
- });
132
- if (!res.ok) throw new Error((json as { error?: string }).error || "Create Agent failed");
133
- setCreateModalKind(null);
134
- router.push(`/agents/${encodeURIComponent(id)}`);
135
- }
136
- router.refresh();
137
- } catch (e: unknown) {
138
- setCreateError(errorMessage(e));
139
- } finally {
140
- setCreateBusy(false);
141
- }
142
- }
143
-
144
- if (loading) return <div className="ck-glass mx-auto max-w-4xl p-6">Loading</div>;
145
- if (!recipe) return <div className="ck-glass mx-auto max-w-4xl p-6">Not found.</div>;
146
-
147
- const fm = recipe.kind === "team" ? teamFrontmatter.fm : null;
148
- const fmErr = recipe.kind === "team" ? teamFrontmatter.error : undefined;
149
-
150
- const afm = recipe.kind === "agent" ? agentFrontmatter.fm : null;
151
- const afmErr = recipe.kind === "agent" ? agentFrontmatter.error : undefined;
152
-
153
- return (
154
- <div className="ck-glass mx-auto max-w-6xl p-6 sm:p-8">
155
- <div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between sm:gap-6">
156
- <div className="min-w-0">
157
- <h1 className="truncate text-2xl font-semibold tracking-tight">{recipe.name}</h1>
158
- <div className="mt-1 text-xs text-[color:var(--ck-text-secondary)]">
159
- {recipe.id} • {recipe.kind} • {recipe.source}
160
- </div>
161
- <div className="mt-1 text-xs text-[color:var(--ck-text-tertiary)]">
162
- Path: {recipe.filePath ?? "(unknown / not writable)"}
163
- </div>
164
- </div>
165
-
166
- <div className="flex gap-2">
167
- <button
168
- disabled={!canSave || saving}
169
- onClick={onSave}
170
- 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"
171
- >
172
- {saving ? "Saving" : "Save"}
173
- </button>
174
- </div>
175
- </div>
176
-
177
- {message ? (
178
- <div className="mt-4 rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/20 p-3 text-sm text-[color:var(--ck-text-primary)]">
179
- {message}
180
- </div>
181
- ) : null}
182
-
183
- <div className="mt-6 grid grid-cols-1 gap-4 lg:grid-cols-2">
184
- <div className="ck-glass-strong p-4">
185
- <div className="text-sm font-medium text-[color:var(--ck-text-primary)]">Recipe markdown</div>
186
- <textarea
187
- value={content}
188
- onChange={(e) => setContent(e.target.value)}
189
- className="mt-2 h-[70vh] w-full resize-none rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 p-3 font-mono text-xs text-[color:var(--ck-text-primary)] placeholder:text-[color:var(--ck-text-tertiary)]"
190
- spellCheck={false}
191
- />
192
- </div>
193
-
194
- {recipe.kind === "team" ? (
195
- <TeamRecipePanelContent recipe={recipe} fm={fm as TeamRecipeFrontmatter | null} fmErr={fmErr} onOpenCreateTeam={openCreateTeam} />
196
- ) : (
197
- <AgentRecipePanelContent recipe={recipe} afm={afm as AgentRecipeFrontmatter | null} afmErr={afmErr} onOpenCreateAgent={openCreateAgent} />
198
- )}
199
- </div>
200
-
201
- <RecipeEditorCreateModal
202
- open={createModalKind !== null}
203
- title={createModalKind === "team" ? "Create Team" : "Create Agent"}
204
- recipeId={recipe.id}
205
- busy={createBusy}
206
- error={createError || undefined}
207
- onClose={() => setCreateModalKind(null)}
208
- onConfirm={onSubmitCreate}
209
- confirmLabel={createModalKind === "team" ? "Create Team" : "Create Agent"}
210
- >
211
- {createModalKind === "team" ? (
212
- <>
213
- <label className="block">
214
- <div className="text-xs font-medium text-[color:var(--ck-text-secondary)]">Team id</div>
215
- <input
216
- value={createId}
217
- onChange={(e) => setCreateId(e.target.value)}
218
- placeholder="e.g. acme"
219
- className="mt-2 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]"
220
- disabled={createBusy}
221
- />
222
- </label>
223
- <label className="block">
224
- <div className="text-xs font-medium text-[color:var(--ck-text-secondary)]">Install cron jobs</div>
225
- <select
226
- value={cronInstallChoice}
227
- onChange={(e) => setCronInstallChoice(e.target.value as "yes" | "no")}
228
- className="mt-2 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]"
229
- disabled={createBusy}
230
- >
231
- <option value="no">No (recommended)</option>
232
- <option value="yes">Yes</option>
233
- </select>
234
- <div className="mt-1 text-xs text-[color:var(--ck-text-tertiary)]">
235
- Kitchen scaffolds non-interactively; this controls the one-time cron install choice for this run.
236
- </div>
237
- </label>
238
- </>
239
- ) : (
240
- <>
241
- <label className="block">
242
- <div className="text-xs font-medium text-[color:var(--ck-text-secondary)]">Agent id</div>
243
- <input
244
- value={createId}
245
- onChange={(e) => setCreateId(e.target.value)}
246
- placeholder="e.g. larry"
247
- className="mt-2 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]"
248
- disabled={createBusy}
249
- />
250
- </label>
251
- <label className="block">
252
- <div className="text-xs font-medium text-[color:var(--ck-text-secondary)]">Name (optional)</div>
253
- <input
254
- value={createName}
255
- onChange={(e) => setCreateName(e.target.value)}
256
- placeholder="e.g. Larry"
257
- className="mt-2 w-full rounded-[var(--ck-radius-sm)] border border-white/10 bg-black/25 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]"
258
- disabled={createBusy}
259
- />
260
- </label>
261
- </>
262
- )}
263
- </RecipeEditorCreateModal>
264
-
265
- <p className="mt-6 text-xs text-[color:var(--ck-text-tertiary)]">
266
- This page edits the recipe markdown and previews what will be created when you click{" "}
267
- {recipe.kind === "team" ? "Create Team" : "Create Agent"}.
268
- </p>
269
- </div>
270
- );
271
- }
@@ -1,46 +0,0 @@
1
- import { parse as parseYaml } from "yaml";
2
- import { errorMessage } from "@/lib/errors";
3
- import type { AgentRecipeFrontmatter, TeamRecipeFrontmatter } from "./types";
4
-
5
- export function parseFrontmatter(raw: string): { fm: TeamRecipeFrontmatter | AgentRecipeFrontmatter | null; error?: string } {
6
- const start = raw.indexOf("---\n");
7
- if (start !== 0) return { fm: null };
8
- const end = raw.indexOf("\n---\n", 4);
9
- if (end === -1) return { fm: null };
10
- const yamlText = raw.slice(4, end);
11
-
12
- try {
13
- const fm = parseYaml(yamlText) as TeamRecipeFrontmatter | AgentRecipeFrontmatter;
14
- if (!fm || typeof fm !== "object") return { fm: null };
15
- return { fm };
16
- } catch (e) {
17
- return { fm: null, error: errorMessage(e) };
18
- }
19
- }
20
-
21
- export function templateKeyToFileName(key: string, stripRolePrefix?: boolean): string {
22
- const suffix = stripRolePrefix ? key.split(".").slice(1).join(".") : key;
23
- switch (suffix) {
24
- case "soul":
25
- return "SOUL.md";
26
- case "agents":
27
- return "AGENTS.md";
28
- case "tools":
29
- return "TOOLS.md";
30
- case "identity":
31
- return "IDENTITY.md";
32
- case "install":
33
- return "INSTALL.md";
34
- case "status":
35
- return "STATUS.md";
36
- default:
37
- return suffix ? `${suffix.toUpperCase()}` : key;
38
- }
39
- }
40
-
41
- export function expectedFilesForRole(fm: TeamRecipeFrontmatter | null, role: string | undefined): string[] {
42
- if (!fm || !role || !fm.templates) return [];
43
- const keys = Object.keys(fm.templates).filter((k) => k.startsWith(`${role}.`));
44
- const files = keys.map((k) => templateKeyToFileName(k, true));
45
- return [...new Set(files)];
46
- }
@@ -1,52 +0,0 @@
1
- export type Recipe = {
2
- id: string;
3
- name: string;
4
- kind: "agent" | "team";
5
- source: "builtin" | "workspace";
6
- content: string;
7
- filePath: string | null;
8
- };
9
-
10
- export type TeamRecipeFrontmatter = {
11
- id?: string;
12
- name?: string;
13
- version?: string;
14
- description?: string;
15
- kind?: "team";
16
- source?: string;
17
- cronJobs?: Array<{
18
- id?: string;
19
- name?: string;
20
- schedule?: string;
21
- timezone?: string;
22
- agentId?: string;
23
- channel?: string;
24
- to?: string;
25
- description?: string;
26
- message?: string;
27
- enabledByDefault?: boolean;
28
- }>;
29
- agents?: Array<{
30
- role?: string;
31
- name?: string;
32
- tools?: {
33
- profile?: string;
34
- allow?: string[];
35
- deny?: string[];
36
- };
37
- }>;
38
- team?: {
39
- teamId?: string;
40
- };
41
- templates?: Record<string, string>;
42
- };
43
-
44
- export type AgentRecipeFrontmatter = {
45
- id?: string;
46
- name?: string;
47
- version?: string;
48
- description?: string;
49
- kind?: "agent";
50
- source?: string;
51
- templates?: Record<string, string>;
52
- };
@@ -1,37 +0,0 @@
1
- import Link from "next/link";
2
- import { unstable_noStore as noStore } from "next/cache";
3
-
4
- import { listRecipes } from "@/lib/recipes";
5
- import RecipeEditor from "./RecipeEditor";
6
-
7
- export const dynamic = "force-dynamic";
8
- export const revalidate = 0;
9
-
10
- async function getKind(id: string): Promise<"agent" | "team" | null> {
11
- const recipes = await listRecipes();
12
- return recipes.find((r) => r.id === id)?.kind ?? null;
13
- }
14
-
15
- export default async function RecipePage({ params }: { params: Promise<{ id: string }> }) {
16
- noStore();
17
-
18
- const { id } = await params;
19
- await getKind(id); // Resolved for future redirect logic; kept for cache consistency
20
-
21
- // NOTE: We do NOT redirect team recipes to /teams/<id>.
22
- // /recipes/<id> is the recipe editor/preview surface; /teams/<id> is the installed team editor.
23
-
24
- return (
25
- <main className="min-h-screen p-8">
26
- <div className="mx-auto mb-4 max-w-6xl">
27
- <Link
28
- href="/recipes"
29
- className="text-sm font-medium text-[color:var(--ck-text-secondary)] transition-colors hover:text-[color:var(--ck-text-primary)]"
30
- >
31
- ← Back to recipes
32
- </Link>
33
- </div>
34
- <RecipeEditor recipeId={id} />
35
- </main>
36
- );
37
- }