@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,23 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { slugifyId } from "../slugify";
3
-
4
- describe("slugifyId", () => {
5
- it("lowercases and replaces spaces with hyphens", () => {
6
- expect(slugifyId("My Goal Title")).toBe("my-goal-title");
7
- });
8
-
9
- it("trims leading and trailing hyphens", () => {
10
- expect(slugifyId(" --foo-- ")).toBe("foo");
11
- });
12
-
13
- it("respects maxLength parameter", () => {
14
- const long = "a".repeat(100);
15
- expect(slugifyId(long, 64).length).toBe(64);
16
- expect(slugifyId(long, 80).length).toBe(80);
17
- });
18
-
19
- it("returns empty for empty input", () => {
20
- expect(slugifyId("")).toBe("");
21
- expect(slugifyId(" ")).toBe("");
22
- });
23
- });
@@ -1,158 +0,0 @@
1
- import { describe, expect, it, vi, beforeEach } from "vitest";
2
- import {
3
- parseTitle,
4
- stageDir,
5
- parseNumberFromFilename,
6
- listTickets,
7
- getTicketMarkdown,
8
- } from "../tickets";
9
- import fs from "node:fs/promises";
10
-
11
- vi.mock("node:fs/promises", () => ({
12
- default: {
13
- readdir: vi.fn(),
14
- readFile: vi.fn(),
15
- stat: vi.fn(),
16
- },
17
- }));
18
-
19
- describe("tickets", () => {
20
- describe("stageDir", () => {
21
- it("maps each stage to correct path", () => {
22
- expect(stageDir("backlog")).toContain("work/backlog");
23
- expect(stageDir("in-progress")).toContain("work/in-progress");
24
- expect(stageDir("testing")).toContain("work/testing");
25
- expect(stageDir("done")).toContain("work/done");
26
- });
27
- });
28
-
29
- describe("parseTitle", () => {
30
- it("derives title from slug when no explicit title", () => {
31
- expect(parseTitle("# 0033-fix-login-bug")).toBe("Fix Login Bug");
32
- expect(parseTitle("# 0042-api-rate-limits")).toBe("API Rate Limits");
33
- });
34
-
35
- it("keeps explicit title when present", () => {
36
- expect(parseTitle("# 0033-fix-login Fix the login bug")).toBe("Fix the login bug");
37
- });
38
-
39
- it("handles acronyms in slug", () => {
40
- expect(parseTitle("# 0100-api-cli-integration")).toContain("API");
41
- expect(parseTitle("# 0100-api-cli-integration")).toContain("CLI");
42
- });
43
-
44
- it("returns untitled for empty or missing header", () => {
45
- expect(parseTitle("")).toBe("(untitled)");
46
- expect(parseTitle("no header here")).toBe("(untitled)");
47
- });
48
- });
49
-
50
- describe("parseNumberFromFilename", () => {
51
- it("extracts 4-digit prefix", () => {
52
- expect(parseNumberFromFilename("0033-fix-login.md")).toBe(33);
53
- expect(parseNumberFromFilename("0042-something.md")).toBe(42);
54
- expect(parseNumberFromFilename("0001-first.md")).toBe(1);
55
- });
56
-
57
- it("returns null for invalid filenames", () => {
58
- expect(parseNumberFromFilename("abc-def.md")).toBeNull();
59
- expect(parseNumberFromFilename("33-something.md")).toBeNull();
60
- expect(parseNumberFromFilename("00333-too-long.md")).toBeNull();
61
- });
62
- });
63
-
64
- describe("listTickets", () => {
65
- beforeEach(() => {
66
- vi.mocked(fs.readdir).mockReset();
67
- vi.mocked(fs.readFile).mockReset();
68
- vi.mocked(fs.stat).mockReset();
69
- });
70
-
71
- it("returns tickets from all stages", async () => {
72
- vi.mocked(fs.readdir)
73
- .mockResolvedValueOnce(["0033-fix-login.md"])
74
- .mockResolvedValueOnce([])
75
- .mockResolvedValueOnce([])
76
- .mockResolvedValueOnce([]);
77
-
78
- vi.mocked(fs.readFile).mockResolvedValue("# 0033-fix-login Fix Login\n\nOwner: alice");
79
- vi.mocked(fs.stat).mockResolvedValue({
80
- mtime: new Date("2026-01-15T10:00:00Z"),
81
- mtimeMs: new Date("2026-01-15T10:00:00Z").getTime(),
82
- } as ReturnType<typeof fs.stat> extends Promise<infer T> ? T : never);
83
-
84
- const result = await listTickets();
85
- expect(result).toHaveLength(1);
86
- expect(result[0].number).toBe(33);
87
- expect(result[0].id).toBe("0033-fix-login");
88
- expect(result[0].title).toBe("Fix Login");
89
- expect(result[0].owner).toBe("alice");
90
- expect(result[0].stage).toBe("backlog");
91
- });
92
-
93
- it("skips stages that throw", async () => {
94
- vi.mocked(fs.readdir)
95
- .mockRejectedValueOnce(new Error("no dir"))
96
- .mockResolvedValueOnce([])
97
- .mockResolvedValueOnce([])
98
- .mockResolvedValueOnce([]);
99
-
100
- const result = await listTickets();
101
- expect(result).toEqual([]);
102
- });
103
-
104
- it("skips non-md files", async () => {
105
- vi.mocked(fs.readdir)
106
- .mockResolvedValueOnce(["0033-a.md", "readme.txt"])
107
- .mockResolvedValueOnce([])
108
- .mockResolvedValueOnce([])
109
- .mockResolvedValueOnce([]);
110
-
111
- vi.mocked(fs.readFile).mockResolvedValue("# 0033-a\n");
112
- vi.mocked(fs.stat).mockResolvedValue({
113
- mtime: new Date(),
114
- mtimeMs: Date.now(),
115
- } as ReturnType<typeof fs.stat> extends Promise<infer T> ? T : never);
116
-
117
- const result = await listTickets();
118
- expect(result).toHaveLength(1);
119
- expect(result[0].id).toBe("0033-a");
120
- });
121
- });
122
-
123
- describe("getTicketMarkdown", () => {
124
- beforeEach(() => {
125
- vi.mocked(fs.readdir)
126
- .mockResolvedValueOnce(["0033-fix.md"])
127
- .mockResolvedValueOnce([])
128
- .mockResolvedValueOnce([])
129
- .mockResolvedValueOnce([]);
130
- vi.mocked(fs.readFile)
131
- .mockResolvedValueOnce("# 0033-fix Fix it\n")
132
- .mockResolvedValueOnce("# 0033-fix Fix it\n");
133
- vi.mocked(fs.stat).mockResolvedValue({
134
- mtime: new Date(),
135
- mtimeMs: Date.now(),
136
- } as ReturnType<typeof fs.stat> extends Promise<infer T> ? T : never);
137
- });
138
-
139
- it("finds by id and returns markdown", async () => {
140
- const result = await getTicketMarkdown("development-team", "0033-fix");
141
- expect(result).not.toBeNull();
142
- expect(result!.id).toBe("0033-fix");
143
- expect(result!.markdown).toContain("Fix it");
144
- });
145
-
146
- it("finds by number", async () => {
147
- const result = await getTicketMarkdown("development-team", "33");
148
- expect(result).not.toBeNull();
149
- expect(result!.id).toBe("0033-fix");
150
- });
151
-
152
- it("returns null when not found", async () => {
153
- vi.mocked(fs.readdir).mockReset().mockResolvedValue([]);
154
- const result = await getTicketMarkdown("development-team", "9999");
155
- expect(result).toBeNull();
156
- });
157
- });
158
- });
@@ -1,18 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { isRecord } from "../type-guards";
3
-
4
- describe("type-guards", () => {
5
- describe("isRecord", () => {
6
- it("returns true for plain objects", () => {
7
- expect(isRecord({})).toBe(true);
8
- expect(isRecord({ a: 1 })).toBe(true);
9
- });
10
- it("returns false for arrays and primitives", () => {
11
- expect(isRecord([])).toBe(false);
12
- expect(isRecord(null)).toBe(false);
13
- expect(isRecord(undefined)).toBe(false);
14
- expect(isRecord("x")).toBe(false);
15
- expect(isRecord(1)).toBe(false);
16
- });
17
- });
18
- });
@@ -1,120 +0,0 @@
1
- import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
2
- import { renderHook, act } from "@testing-library/react";
3
- import { useSlugifiedId } from "../use-slugified-id";
4
-
5
- describe("useSlugifiedId", () => {
6
- const mockSetName = vi.fn();
7
- const mockSetId = vi.fn();
8
- const mockSetIdTouched = vi.fn();
9
-
10
- beforeEach(() => {
11
- mockSetName.mockClear();
12
- mockSetId.mockClear();
13
- mockSetIdTouched.mockClear();
14
- });
15
-
16
- afterEach(() => {
17
- vi.clearAllMocks();
18
- });
19
-
20
- it("returns derivedId from slugified name", () => {
21
- const { result } = renderHook(() =>
22
- useSlugifiedId({
23
- open: true,
24
- name: "My Agent",
25
- setName: mockSetName,
26
- id: "",
27
- setId: mockSetId,
28
- idTouched: false,
29
- setIdTouched: mockSetIdTouched,
30
- })
31
- );
32
- expect(result.current.derivedId).toBe("my-agent");
33
- });
34
-
35
- it("returns effectiveId as derivedId when idTouched is false", () => {
36
- const { result } = renderHook(() =>
37
- useSlugifiedId({
38
- open: true,
39
- name: "Test Name",
40
- setName: mockSetName,
41
- id: "custom-id",
42
- setId: mockSetId,
43
- idTouched: false,
44
- setIdTouched: mockSetIdTouched,
45
- })
46
- );
47
- expect(result.current.effectiveId).toBe("test-name");
48
- });
49
-
50
- it("returns effectiveId as id when idTouched is true", () => {
51
- const { result } = renderHook(() =>
52
- useSlugifiedId({
53
- open: true,
54
- name: "Test Name",
55
- setName: mockSetName,
56
- id: "custom-id",
57
- setId: mockSetId,
58
- idTouched: true,
59
- setIdTouched: mockSetIdTouched,
60
- })
61
- );
62
- expect(result.current.effectiveId).toBe("custom-id");
63
- });
64
-
65
- it("syncs derivedId to id when open and !idTouched", () => {
66
- renderHook(() =>
67
- useSlugifiedId({
68
- open: true,
69
- name: "Hello World",
70
- setName: mockSetName,
71
- id: "",
72
- setId: mockSetId,
73
- idTouched: false,
74
- setIdTouched: mockSetIdTouched,
75
- })
76
- );
77
- expect(mockSetId).toHaveBeenCalledWith("hello-world");
78
- });
79
-
80
- it("resets form when modal closes (open becomes false)", () => {
81
- const { rerender } = renderHook(
82
- ({ open }) =>
83
- useSlugifiedId({
84
- open,
85
- name: "Test",
86
- setName: mockSetName,
87
- id: "test-id",
88
- setId: mockSetId,
89
- idTouched: true,
90
- setIdTouched: mockSetIdTouched,
91
- }),
92
- { initialProps: { open: true } }
93
- );
94
-
95
- act(() => {
96
- rerender({ open: false });
97
- });
98
-
99
- expect(mockSetIdTouched).toHaveBeenCalledWith(false);
100
- expect(mockSetName).toHaveBeenCalledWith("");
101
- expect(mockSetId).toHaveBeenCalledWith("");
102
- });
103
-
104
- it("uses custom slugify when provided", () => {
105
- const customSlugify = (s: string) => s.toUpperCase().replace(/\s/g, "_");
106
- const { result } = renderHook(() =>
107
- useSlugifiedId({
108
- open: true,
109
- name: "foo bar",
110
- setName: mockSetName,
111
- id: "",
112
- setId: mockSetId,
113
- idTouched: false,
114
- setIdTouched: mockSetIdTouched,
115
- slugify: customSlugify,
116
- })
117
- );
118
- expect(result.current.derivedId).toBe("FOO_BAR");
119
- });
120
- });
@@ -1,14 +0,0 @@
1
- import path from "node:path";
2
-
3
- export function parseTeamRoleWorkspace(ws: string):
4
- | { kind: "teamRole"; teamDir: string; teamId: string; roleDir: string; role: string }
5
- | { kind: "other" } {
6
- const normalized = ws.replace(/\\/g, "/");
7
- const m = normalized.match(/^(.*\/workspace-([^\/]+))\/roles\/([^\/]+)\/?$/);
8
- if (!m) return { kind: "other" };
9
- const teamDir = m[1];
10
- const teamId = m[2];
11
- const role = m[3];
12
- const roleDir = path.join(teamDir, "roles", role);
13
- return { kind: "teamRole", teamDir, teamId, roleDir, role };
14
- }
package/src/lib/agents.ts DELETED
@@ -1,17 +0,0 @@
1
- import { runOpenClaw } from "./openclaw";
2
-
3
- export type AgentListItem = {
4
- id: string;
5
- identityName?: string;
6
- workspace?: string;
7
- model?: string;
8
- isDefault?: boolean;
9
- };
10
-
11
- export async function resolveAgentWorkspace(agentId: string): Promise<string> {
12
- const { stdout } = await runOpenClaw(["agents", "list", "--json"]);
13
- const list = JSON.parse(stdout) as AgentListItem[];
14
- const agent = list.find((a) => a.id === agentId);
15
- if (!agent?.workspace) throw new Error(`Agent workspace not found for ${agentId}`);
16
- return agent.workspace;
17
- }
@@ -1,157 +0,0 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- import { NextResponse } from "next/server";
4
-
5
- /** Parses JSON body; returns 400 on parse error. */
6
- export async function parseJsonBody(req: Request): Promise<{ body: Record<string, unknown> } | NextResponse> {
7
- let body: unknown;
8
- try {
9
- body = await req.json();
10
- } catch {
11
- return NextResponse.json({ ok: false, error: "Invalid JSON" }, { status: 400 });
12
- }
13
- const o = body && typeof body === "object" ? (body as Record<string, unknown>) : {};
14
- return { body: o };
15
- }
16
-
17
- /** Returns NextResponse.json({ ok: true, ...rest }) from a storage result with ok field. */
18
- export function jsonOkRest<T extends { ok: boolean }>(r: T): NextResponse {
19
- const rest = Object.fromEntries(Object.entries(r as Record<string, unknown>).filter(([k]) => k !== "ok"));
20
- return NextResponse.json({ ok: true, ...rest });
21
- }
22
-
23
- import { resolveAgentWorkspace } from "@/lib/agents";
24
- import { errorMessage } from "@/lib/errors";
25
-
26
- /** Runs async storage fn and returns jsonOkRest on success, or 500 on error. */
27
- export async function withStorageError<T extends { ok: boolean }>(
28
- fn: () => Promise<T>
29
- ): Promise<NextResponse> {
30
- try {
31
- return jsonOkRest(await fn());
32
- } catch (err: unknown) {
33
- return NextResponse.json({ ok: false, error: errorMessage(err) }, { status: 500 });
34
- }
35
- }
36
- import { readOpenClawConfig, teamDirFromBaseWorkspace } from "@/lib/paths";
37
-
38
- export type TeamContext = { teamId: string; teamDir: string };
39
-
40
- /** Error response for install-skill openclaw failures. Use when runOpenClaw returns !ok. */
41
- export function installSkillErrorResponse(
42
- args: string[],
43
- res: { stdout?: string; stderr?: string; exitCode?: number },
44
- extra?: Record<string, unknown>
45
- ): NextResponse {
46
- const stdout = res.stdout?.trim();
47
- const stderr = res.stderr?.trim();
48
- return NextResponse.json(
49
- {
50
- ok: false,
51
- error: stderr || stdout || `openclaw ${args.join(" ")} failed (exit=${res.exitCode})`,
52
- stdout: res.stdout,
53
- stderr: res.stderr,
54
- ...extra,
55
- },
56
- { status: 500 }
57
- );
58
- }
59
-
60
- async function resolveTeamContext(teamId: string): Promise<TeamContext | NextResponse> {
61
- if (!teamId) return NextResponse.json({ ok: false, error: "teamId is required" }, { status: 400 });
62
-
63
- const cfg = await readOpenClawConfig();
64
- const baseWorkspace = String(cfg.agents?.defaults?.workspace ?? "").trim();
65
- if (!baseWorkspace) {
66
- return NextResponse.json({ ok: false, error: "agents.defaults.workspace not set" }, { status: 500 });
67
- }
68
-
69
- const teamDir = teamDirFromBaseWorkspace(baseWorkspace, teamId);
70
- return { teamId, teamDir };
71
- }
72
-
73
- /** Resolves teamId and teamDir from URL search params. Returns error response if invalid. */
74
- export async function getTeamContextFromQuery(req: Request): Promise<TeamContext | NextResponse> {
75
- const { searchParams } = new URL(req.url);
76
- const teamId = String(searchParams.get("teamId") ?? "").trim();
77
- return resolveTeamContext(teamId);
78
- }
79
-
80
- /** Runs handler with team context from query; returns error response if context invalid. */
81
- export async function withTeamContextFromQuery(
82
- req: Request,
83
- handler: (ctx: TeamContext) => Promise<NextResponse>
84
- ): Promise<NextResponse> {
85
- const ctx = await getTeamContextFromQuery(req);
86
- if (ctx instanceof NextResponse) return ctx;
87
- return handler(ctx);
88
- }
89
-
90
- /** Resolves teamId and teamDir from parsed body. Caller must parse req.json() first. */
91
- export async function getTeamContextFromBody(body: { teamId?: string }): Promise<TeamContext | NextResponse> {
92
- const teamId = String(body.teamId ?? "").trim();
93
- return resolveTeamContext(teamId);
94
- }
95
-
96
- export type AgentContext = { agentId: string; ws: string };
97
-
98
- /** Resolves agentId and workspace from URL search params. Returns error response if invalid. */
99
- export async function getAgentContextFromQuery(req: Request): Promise<AgentContext | NextResponse> {
100
- const { searchParams } = new URL(req.url);
101
- const agentId = String(searchParams.get("agentId") ?? "").trim();
102
- return resolveAgentContext(agentId);
103
- }
104
-
105
- /** Resolves agentId and workspace from parsed body. Caller must parse req.json() first. */
106
- export async function getAgentContextFromBody(body: { agentId?: string }): Promise<AgentContext | NextResponse> {
107
- const agentId = String(body.agentId ?? "").trim();
108
- return resolveAgentContext(agentId);
109
- }
110
-
111
- async function resolveAgentContext(agentId: string): Promise<AgentContext | NextResponse> {
112
- if (!agentId) return NextResponse.json({ ok: false, error: "agentId is required" }, { status: 400 });
113
- try {
114
- const ws = await resolveAgentWorkspace(agentId);
115
- return { agentId, ws };
116
- } catch (e: unknown) {
117
- return NextResponse.json({ ok: false, error: errorMessage(e) }, { status: 404 });
118
- }
119
- }
120
-
121
- export type FileCandidate = { name: string; required: boolean; rationale: string };
122
-
123
- /** Lists workspace files with presence/size info. */
124
- export async function listWorkspaceFiles(
125
- baseDir: string,
126
- candidates: FileCandidate[]
127
- ): Promise<
128
- Array<{
129
- name: string;
130
- required: boolean;
131
- rationale: string;
132
- path: string;
133
- missing: boolean;
134
- size?: number;
135
- updatedAtMs?: number;
136
- }>
137
- > {
138
- return Promise.all(
139
- candidates.map(async (c) => {
140
- const p = path.join(baseDir, c.name);
141
- try {
142
- const st = await fs.stat(p);
143
- return {
144
- name: c.name,
145
- required: c.required,
146
- rationale: c.rationale,
147
- path: p,
148
- missing: false,
149
- size: st.size,
150
- updatedAtMs: st.mtimeMs,
151
- };
152
- } catch {
153
- return { name: c.name, required: c.required, rationale: c.rationale, path: p, missing: true };
154
- }
155
- })
156
- );
157
- }
package/src/lib/cron.ts DELETED
@@ -1,40 +0,0 @@
1
- /**
2
- * Shared shape for cron job objects returned by the gateway cron tool.
3
- * Different callers may receive slightly different structures; these helpers normalize access.
4
- */
5
- export type CronJobShape = {
6
- id?: unknown;
7
- jobId?: unknown;
8
- name?: unknown;
9
- enabled?: unknown;
10
- state?: { enabled?: unknown };
11
- };
12
-
13
- /** Typed cron job for UI display. API returns jobs that match this structure. */
14
- export type CronJob = {
15
- id: string;
16
- name?: string;
17
- enabled?: boolean;
18
- schedule?: { kind?: string; expr?: string; everyMs?: number };
19
- state?: { nextRunAtMs?: number };
20
- agentId?: string;
21
- sessionTarget?: string;
22
- };
23
-
24
- export function cronJobId(j: CronJobShape): string {
25
- return String(j.id ?? j.jobId ?? "").trim();
26
- }
27
-
28
- export function cronJobLabel(j: CronJobShape): string {
29
- return String(j.name ?? j.id ?? j.jobId ?? "(unnamed)");
30
- }
31
-
32
- export function fmtCronSchedule(s?: CronJob["schedule"]): string {
33
- if (!s) return "";
34
- if (s.kind === "cron" && s.expr) return s.expr;
35
- if (s.kind === "every" && s.everyMs) {
36
- const mins = Math.round(s.everyMs / 60000);
37
- return mins >= 60 ? `every ${Math.round(mins / 60)}h` : `every ${mins}m`;
38
- }
39
- return s.kind ?? "";
40
- }
@@ -1,18 +0,0 @@
1
- export type FileListEntry = {
2
- name: string;
3
- missing: boolean;
4
- required: boolean;
5
- rationale?: string;
6
- };
7
-
8
- export function normalizeFileListEntries(files: unknown[]): FileListEntry[] {
9
- return files.map((f) => {
10
- const entry = f as { name?: unknown; missing?: unknown; required?: unknown; rationale?: unknown };
11
- return {
12
- name: String(entry.name ?? ""),
13
- missing: Boolean(entry.missing),
14
- required: Boolean(entry.required),
15
- rationale: typeof entry.rationale === "string" ? entry.rationale : undefined,
16
- };
17
- });
18
- }
package/src/lib/errors.ts DELETED
@@ -1,7 +0,0 @@
1
- /**
2
- * Extracts a string message from an unknown error value.
3
- * Used consistently across API routes and client components.
4
- */
5
- export function errorMessage(e: unknown): string {
6
- return e instanceof Error ? e.message : String(e);
7
- }
package/src/lib/exec.ts DELETED
@@ -1,4 +0,0 @@
1
- import { execFile } from "node:child_process";
2
- import { promisify } from "node:util";
3
-
4
- export const execFileAsync = promisify(execFile);
@@ -1,29 +0,0 @@
1
- /** Fetches multiple URLs in parallel with cache: "no-store". */
2
- export async function fetchAll(urls: string[]): Promise<Response[]> {
3
- return Promise.all(urls.map((url) => fetch(url, { cache: "no-store" })));
4
- }
5
-
6
- /**
7
- * Fetches JSON and throws on !res.ok.
8
- * Use errorMessage(e) in catch blocks.
9
- */
10
- export async function fetchJson<T = unknown>(url: string, opts?: RequestInit): Promise<T> {
11
- const res = await fetch(url, opts);
12
- const json = (await res.json()) as { error?: string };
13
- if (!res.ok) throw new Error(json.error ?? "Request failed");
14
- return json as T;
15
- }
16
-
17
- /**
18
- * Fetches JSON and returns result with status. Use when you need to handle specific
19
- * HTTP status codes (e.g. 409) differently from generic errors.
20
- */
21
- export async function fetchJsonWithStatus<T = unknown>(
22
- url: string,
23
- opts?: RequestInit
24
- ): Promise<{ ok: true; data: T } | { ok: false; status: number; error: string }> {
25
- const res = await fetch(url, opts);
26
- const json = (await res.json()) as { error?: string };
27
- if (res.ok) return { ok: true, data: json as T };
28
- return { ok: false, status: res.status, error: json.error ?? "Request failed" };
29
- }