@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,109 +0,0 @@
1
- import { describe, expect, it, vi, afterEach } from "vitest";
2
- import { render, screen, fireEvent, cleanup } from "@testing-library/react";
3
-
4
- afterEach(cleanup);
5
- import { FileListWithOptionalToggle } from "../FileListWithOptionalToggle";
6
-
7
- const files = [
8
- { name: "SOUL.md", missing: false, required: true },
9
- { name: "AGENTS.md", missing: true, required: false },
10
- { name: "USER.md", missing: false, required: false },
11
- ];
12
-
13
- describe("FileListWithOptionalToggle", () => {
14
- it("renders title and file list", () => {
15
- render(
16
- <FileListWithOptionalToggle
17
- title="Agent files"
18
- files={files}
19
- showOptionalFiles={true}
20
- onShowOptionalChange={vi.fn()}
21
- selectedFileName=""
22
- onSelectFile={vi.fn()}
23
- />
24
- );
25
- expect(screen.getByText("Agent files")).toBeTruthy();
26
- expect(screen.getByText("SOUL.md")).toBeTruthy();
27
- expect(screen.getByText("AGENTS.md")).toBeTruthy();
28
- expect(screen.getByText("USER.md")).toBeTruthy();
29
- });
30
-
31
- it("filters optional missing files when showOptionalFiles is false", () => {
32
- const { container } = render(
33
- <FileListWithOptionalToggle
34
- title="Filtered Files"
35
- files={files}
36
- showOptionalFiles={false}
37
- onShowOptionalChange={vi.fn()}
38
- selectedFileName=""
39
- onSelectFile={vi.fn()}
40
- />
41
- );
42
- expect(container.textContent).toContain("SOUL.md");
43
- expect(container.textContent).toContain("USER.md");
44
- expect(container.textContent).not.toContain("AGENTS.md");
45
- });
46
-
47
- it("shows all files when showOptionalFiles is true", () => {
48
- const { container } = render(
49
- <FileListWithOptionalToggle
50
- title="All Files"
51
- files={files}
52
- showOptionalFiles={true}
53
- onShowOptionalChange={vi.fn()}
54
- selectedFileName=""
55
- onSelectFile={vi.fn()}
56
- />
57
- );
58
- expect(container.textContent).toContain("AGENTS.md");
59
- });
60
-
61
- it("calls onSelectFile when file clicked", () => {
62
- const onSelectFile = vi.fn();
63
- render(
64
- <FileListWithOptionalToggle
65
- title="Click Files"
66
- files={files}
67
- showOptionalFiles={true}
68
- onShowOptionalChange={vi.fn()}
69
- selectedFileName=""
70
- onSelectFile={onSelectFile}
71
- />
72
- );
73
- const buttons = screen.getAllByRole("button");
74
- const soulButton = buttons.find((b) => b.textContent?.includes("SOUL.md"));
75
- fireEvent.click(soulButton!);
76
- expect(onSelectFile).toHaveBeenCalledWith("SOUL.md");
77
- });
78
-
79
- it("calls onShowOptionalChange when checkbox toggled", () => {
80
- const onShowOptionalChange = vi.fn();
81
- render(
82
- <FileListWithOptionalToggle
83
- title="Files"
84
- files={files}
85
- showOptionalFiles={false}
86
- onShowOptionalChange={onShowOptionalChange}
87
- selectedFileName=""
88
- onSelectFile={vi.fn()}
89
- />
90
- );
91
- fireEvent.click(screen.getByRole("checkbox"));
92
- expect(onShowOptionalChange).toHaveBeenCalledWith(true);
93
- });
94
-
95
- it("shows Loading… when loading", () => {
96
- render(
97
- <FileListWithOptionalToggle
98
- title="Files"
99
- files={[]}
100
- loading={true}
101
- showOptionalFiles={true}
102
- onShowOptionalChange={vi.fn()}
103
- selectedFileName=""
104
- onSelectFile={vi.fn()}
105
- />
106
- );
107
- expect(screen.getByText("Loading…")).toBeTruthy();
108
- });
109
- });
@@ -1,117 +0,0 @@
1
- import { describe, expect, it, vi, afterEach } from "vitest";
2
- import { render, screen, fireEvent, cleanup } from "@testing-library/react";
3
-
4
- afterEach(cleanup);
5
- import { GoalFormCard, GoalFormFields, type GoalFormState } from "../GoalFormFields";
6
-
7
- function makeFormState(overrides?: Partial<GoalFormState>): GoalFormState {
8
- return {
9
- title: "",
10
- setTitle: vi.fn(),
11
- status: "planned",
12
- setStatus: vi.fn(),
13
- tagsRaw: "",
14
- setTagsRaw: vi.fn(),
15
- teamsRaw: "",
16
- setTeamsRaw: vi.fn(),
17
- body: "",
18
- setBody: vi.fn(),
19
- ...overrides,
20
- };
21
- }
22
-
23
- describe("GoalFormCard", () => {
24
- it("renders children and actions", () => {
25
- render(
26
- <GoalFormCard error={null} actions={<button>Save</button>}>
27
- <div data-testid="child">Form content</div>
28
- </GoalFormCard>
29
- );
30
- expect(screen.getByTestId("child").textContent).toBe("Form content");
31
- expect(screen.getByRole("button", { name: "Save" })).toBeTruthy();
32
- });
33
-
34
- it("shows error when provided", () => {
35
- render(
36
- <GoalFormCard error="Something went wrong" actions={<button>Save</button>}>
37
- <div>Content</div>
38
- </GoalFormCard>
39
- );
40
- expect(screen.getByText("Something went wrong")).toBeTruthy();
41
- });
42
-
43
- it("hides error when null", () => {
44
- render(
45
- <GoalFormCard error={null} actions={<button>Save</button>}>
46
- <div data-testid="content">Content</div>
47
- </GoalFormCard>
48
- );
49
- expect(screen.getByTestId("content")).toBeTruthy();
50
- expect(screen.queryByText("Something went wrong")).toBeNull();
51
- });
52
- });
53
-
54
- describe("GoalFormFields", () => {
55
- it("renders title, status, tags, teams, body inputs", () => {
56
- const formState = makeFormState({ title: "My goal", body: "Body text" });
57
- render(<GoalFormFields formState={formState} />);
58
-
59
- expect((screen.getByPlaceholderText("Goal title") as HTMLInputElement).value).toBe("My goal");
60
- const textarea = screen.getByPlaceholderText("Write the goal here…");
61
- expect((textarea as HTMLTextAreaElement).value).toBe("Body text");
62
- expect(screen.getByRole("combobox")).toBeTruthy();
63
- });
64
-
65
- it("renders id field when idField provided", () => {
66
- const setId = vi.fn();
67
- const formState = makeFormState();
68
- render(
69
- <GoalFormFields
70
- formState={formState}
71
- idField={{ id: "my-id", setId, suggestedId: "suggested-id" }}
72
- />
73
- );
74
- expect((screen.getByPlaceholderText("increase-trial-activation") as HTMLInputElement).value).toBe("my-id");
75
- });
76
-
77
- it("shows suggested id button when id is empty", () => {
78
- const setId = vi.fn();
79
- const formState = makeFormState();
80
- render(
81
- <GoalFormFields
82
- formState={formState}
83
- idField={{ id: "", setId, suggestedId: "suggested-id" }}
84
- />
85
- );
86
- expect(screen.getByText("suggested-id")).toBeTruthy();
87
- });
88
-
89
- it("clicking suggested id button calls setId", () => {
90
- const setId = vi.fn();
91
- const formState = makeFormState();
92
- render(
93
- <GoalFormFields
94
- formState={formState}
95
- idField={{ id: "", setId, suggestedId: "suggested-id" }}
96
- />
97
- );
98
- fireEvent.click(screen.getByText("suggested-id"));
99
- expect(setId).toHaveBeenCalledWith("suggested-id");
100
- });
101
-
102
- it("calls setTitle when title input changes", () => {
103
- const setTitle = vi.fn();
104
- const formState = makeFormState({ setTitle });
105
- render(<GoalFormFields formState={formState} />);
106
- fireEvent.change(screen.getByPlaceholderText("Goal title"), { target: { value: "x" } });
107
- expect(setTitle).toHaveBeenCalledWith("x");
108
- });
109
-
110
- it("calls setStatus when status select changes", () => {
111
- const setStatus = vi.fn();
112
- const formState = makeFormState({ setStatus });
113
- render(<GoalFormFields formState={formState} />);
114
- fireEvent.change(screen.getByRole("combobox"), { target: { value: "active" } });
115
- expect(setStatus).toHaveBeenCalledWith("active");
116
- });
117
- });
@@ -1,59 +0,0 @@
1
- "use client";
2
-
3
- import { DeleteEntityModal } from "./DeleteEntityModal";
4
-
5
- type EntityLabelKey = "agentId" | "teamId" | "recipeId" | "jobLabel";
6
-
7
- type BaseProps = {
8
- open: boolean;
9
- onClose: () => void;
10
- onConfirm: () => void;
11
- busy?: boolean;
12
- error?: string | null;
13
- };
14
-
15
- function createDeleteModal<K extends EntityLabelKey>(config: {
16
- title: string;
17
- bodyText: string;
18
- entityLabelKey: K;
19
- }) {
20
- return function DeleteModal(props: BaseProps & Record<K, string>) {
21
- const entityLabel = props[config.entityLabelKey];
22
- return (
23
- <DeleteEntityModal
24
- open={props.open}
25
- onClose={props.onClose}
26
- title={config.title}
27
- entityLabel={entityLabel}
28
- bodyText={config.bodyText}
29
- onConfirm={props.onConfirm}
30
- busy={props.busy}
31
- error={props.error}
32
- />
33
- );
34
- };
35
- }
36
-
37
- export const DeleteAgentModal = createDeleteModal({
38
- title: "Delete agent",
39
- bodyText: "This will remove its workspace/state.",
40
- entityLabelKey: "agentId",
41
- });
42
-
43
- export const DeleteTeamModal = createDeleteModal({
44
- title: "Delete Team",
45
- bodyText: "This will remove the team workspace, agents, and stamped cron jobs.",
46
- entityLabelKey: "teamId",
47
- });
48
-
49
- export const DeleteRecipeModal = createDeleteModal({
50
- title: "Delete recipe",
51
- bodyText: "This removes the markdown file from your workspace.",
52
- entityLabelKey: "recipeId",
53
- });
54
-
55
- export const DeleteCronJobModal = createDeleteModal({
56
- title: "Delete cron job",
57
- bodyText: "This removes it from the Gateway scheduler. You can recreate it later.",
58
- entityLabelKey: "jobLabel",
59
- });
@@ -1,48 +0,0 @@
1
- "use client";
2
-
3
- function IconSvg({ className, children }: { className?: string; children: React.ReactNode }) {
4
- return (
5
- <svg
6
- className={className}
7
- viewBox="0 0 24 24"
8
- fill="none"
9
- xmlns="http://www.w3.org/2000/svg"
10
- aria-hidden="true"
11
- >
12
- {children}
13
- </svg>
14
- );
15
- }
16
-
17
- export function SunIcon({ className }: { className?: string }) {
18
- return (
19
- <IconSvg className={className}>
20
- <path
21
- d="M12 18a6 6 0 1 0 0-12 6 6 0 0 0 0 12Z"
22
- stroke="currentColor"
23
- strokeWidth="1.8"
24
- />
25
- <path d="M12 2v2.5" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
26
- <path d="M12 19.5V22" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
27
- <path d="M2 12h2.5" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
28
- <path d="M19.5 12H22" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
29
- <path d="M4.2 4.2 6 6" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
30
- <path d="M18 18l1.8 1.8" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
31
- <path d="M18 6l1.8-1.8" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
32
- <path d="M4.2 19.8 6 18" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
33
- </IconSvg>
34
- );
35
- }
36
-
37
- export function MoonIcon({ className }: { className?: string }) {
38
- return (
39
- <IconSvg className={className}>
40
- <path
41
- d="M21 14.2A7.8 7.8 0 0 1 9.8 3a7 7 0 1 0 11.2 11.2Z"
42
- stroke="currentColor"
43
- strokeWidth="1.8"
44
- strokeLinejoin="round"
45
- />
46
- </IconSvg>
47
- );
48
- }
@@ -1,44 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { parseTeamRoleWorkspace } from "../agent-workspace";
3
-
4
- describe("agent-workspace", () => {
5
- describe("parseTeamRoleWorkspace", () => {
6
- it("returns teamRole for valid workspace path", () => {
7
- const ws = "/home/user/.openclaw/workspace-myteam/roles/lead";
8
- const result = parseTeamRoleWorkspace(ws);
9
- expect(result).toEqual({
10
- kind: "teamRole",
11
- teamDir: "/home/user/.openclaw/workspace-myteam",
12
- teamId: "myteam",
13
- roleDir: "/home/user/.openclaw/workspace-myteam/roles/lead",
14
- role: "lead",
15
- });
16
- });
17
-
18
- it("returns teamRole with trailing slash", () => {
19
- const ws = "/path/workspace-team1/roles/dev/";
20
- const result = parseTeamRoleWorkspace(ws);
21
- expect(result).toEqual({
22
- kind: "teamRole",
23
- teamDir: "/path/workspace-team1",
24
- teamId: "team1",
25
- roleDir: "/path/workspace-team1/roles/dev",
26
- role: "dev",
27
- });
28
- });
29
-
30
- it("returns other for non-team-role path", () => {
31
- expect(parseTeamRoleWorkspace("/some/other/path")).toEqual({ kind: "other" });
32
- expect(parseTeamRoleWorkspace("/workspace-x/agents/y")).toEqual({ kind: "other" });
33
- expect(parseTeamRoleWorkspace("")).toEqual({ kind: "other" });
34
- });
35
-
36
- it("normalizes backslashes to forward slashes", () => {
37
- const ws = "C:\\Users\\x\\.openclaw\\workspace-t1\\roles\\lead";
38
- const result = parseTeamRoleWorkspace(ws);
39
- expect(result.kind).toBe("teamRole");
40
- expect((result as { teamId: string }).teamId).toBe("t1");
41
- expect((result as { role: string }).role).toBe("lead");
42
- });
43
- });
44
- });
@@ -1,36 +0,0 @@
1
- import { describe, expect, it, vi, beforeEach } from "vitest";
2
- import { resolveAgentWorkspace } from "../agents";
3
-
4
- vi.mock("../openclaw", () => ({ runOpenClaw: vi.fn() }));
5
-
6
- import { runOpenClaw } from "../openclaw";
7
-
8
- describe("agents", () => {
9
- beforeEach(() => {
10
- vi.mocked(runOpenClaw).mockReset();
11
- });
12
-
13
- describe("resolveAgentWorkspace", () => {
14
- it("returns workspace when agent found", async () => {
15
- vi.mocked(runOpenClaw).mockResolvedValue({
16
- ok: true,
17
- exitCode: 0,
18
- stdout: JSON.stringify([{ id: "a1", workspace: "/ws/a1" }]),
19
- stderr: "",
20
- });
21
- expect(await resolveAgentWorkspace("a1")).toBe("/ws/a1");
22
- });
23
-
24
- it("throws when agent not found", async () => {
25
- vi.mocked(runOpenClaw).mockResolvedValue({
26
- ok: true,
27
- exitCode: 0,
28
- stdout: JSON.stringify([{ id: "other" }]),
29
- stderr: "",
30
- });
31
- await expect(resolveAgentWorkspace("missing")).rejects.toThrow(
32
- "Agent workspace not found for missing"
33
- );
34
- });
35
- });
36
- });
@@ -1,188 +0,0 @@
1
- import { describe, expect, it, vi, beforeEach } from "vitest";
2
- import {
3
- getTeamContextFromQuery,
4
- getTeamContextFromBody,
5
- jsonOkRest,
6
- listWorkspaceFiles,
7
- installSkillErrorResponse,
8
- parseJsonBody,
9
- } from "../api-route-helpers";
10
-
11
- vi.mock("@/lib/paths", () => ({
12
- readOpenClawConfig: vi.fn(),
13
- teamDirFromBaseWorkspace: vi.fn((base: string, teamId: string) => `${base}/../workspace-${teamId}`),
14
- }));
15
-
16
- import { readOpenClawConfig } from "@/lib/paths";
17
- import fs from "node:fs/promises";
18
-
19
- vi.mock("node:fs/promises", () => ({
20
- default: { stat: vi.fn() },
21
- }));
22
-
23
- describe("api-route-helpers", () => {
24
- beforeEach(() => {
25
- vi.mocked(readOpenClawConfig).mockReset();
26
- });
27
-
28
- describe("getTeamContextFromQuery", () => {
29
- it("returns 400 when teamId missing", async () => {
30
- const res = await getTeamContextFromQuery(new Request("https://test/api/teams/files"));
31
- expect(res).toBeInstanceOf(Response);
32
- expect((res as Response).status).toBe(400);
33
- const json = await (res as Response).json();
34
- expect(json.error).toBe("teamId is required");
35
- });
36
-
37
- it("returns 500 when workspace not set", async () => {
38
- vi.mocked(readOpenClawConfig).mockResolvedValue({});
39
- const res = await getTeamContextFromQuery(new Request("https://test?teamId=my-team"));
40
- expect(res).toBeInstanceOf(Response);
41
- expect((res as Response).status).toBe(500);
42
- const json = await (res as Response).json();
43
- expect(json.error).toBe("agents.defaults.workspace not set");
44
- });
45
-
46
- it("returns team context when valid", async () => {
47
- vi.mocked(readOpenClawConfig).mockResolvedValue({
48
- agents: { defaults: { workspace: "/home/x/agents" } },
49
- });
50
- const res = await getTeamContextFromQuery(new Request("https://test?teamId=my-team"));
51
- expect(res).not.toBeInstanceOf(Response);
52
- expect(res).toEqual({
53
- teamId: "my-team",
54
- teamDir: "/home/x/agents/../workspace-my-team",
55
- });
56
- });
57
- });
58
-
59
- describe("parseJsonBody", () => {
60
- it("returns body object when JSON valid", async () => {
61
- const req = new Request("https://test", {
62
- method: "POST",
63
- body: JSON.stringify({ teamId: "t1", x: 1 }),
64
- headers: { "content-type": "application/json" },
65
- });
66
- const result = await parseJsonBody(req);
67
- expect(result).not.toBeInstanceOf(Response);
68
- expect((result as { body: Record<string, unknown> }).body).toEqual({ teamId: "t1", x: 1 });
69
- });
70
-
71
- it("returns 400 when JSON invalid", async () => {
72
- const req = new Request("https://test", {
73
- method: "POST",
74
- body: "not json",
75
- headers: { "content-type": "application/json" },
76
- });
77
- const result = await parseJsonBody(req);
78
- expect(result).toBeInstanceOf(Response);
79
- expect((result as Response).status).toBe(400);
80
- const json = await (result as Response).json();
81
- expect(json.error).toBe("Invalid JSON");
82
- });
83
- });
84
-
85
- describe("jsonOkRest", () => {
86
- it("returns NextResponse.json with ok:true and rest of object", async () => {
87
- const res = jsonOkRest({ ok: true, path: "/a/b", workflow: { id: "w1", name: "W" } });
88
- expect(res.status).toBe(200);
89
- const json = await res.json();
90
- expect(json.ok).toBe(true);
91
- expect(json.path).toBe("/a/b");
92
- expect(json.workflow).toEqual({ id: "w1", name: "W" });
93
- });
94
-
95
- it("omits ok from rest when input has ok:false", async () => {
96
- const res = jsonOkRest({ ok: false, error: "x" });
97
- const json = await res.json();
98
- expect(json.ok).toBe(true);
99
- expect(json.error).toBe("x");
100
- });
101
- });
102
-
103
- describe("installSkillErrorResponse", () => {
104
- it("returns 500 JSON with error from stderr", async () => {
105
- const res = installSkillErrorResponse(
106
- ["recipes", "install-skill", "foo", "--agent-id", "a1", "--yes"],
107
- { stdout: "out", stderr: "err", exitCode: 1 }
108
- );
109
- expect(res.status).toBe(500);
110
- const json = await res.json();
111
- expect(json.ok).toBe(false);
112
- expect(json.error).toBe("err");
113
- expect(json.stdout).toBe("out");
114
- expect(json.stderr).toBe("err");
115
- });
116
-
117
- it("falls back to stdout when stderr empty", async () => {
118
- const res = installSkillErrorResponse(["recipes", "install-skill", "x"], { stdout: "stdout", stderr: "", exitCode: 2 });
119
- const json = await res.json();
120
- expect(json.error).toBe("stdout");
121
- });
122
-
123
- it("includes extra fields when provided", async () => {
124
- const res = installSkillErrorResponse(["x"], { stdout: "", stderr: "fail" }, { scopeArgs: ["a", "b"] });
125
- const json = await res.json();
126
- expect(json.scopeArgs).toEqual(["a", "b"]);
127
- });
128
- });
129
-
130
- describe("getTeamContextFromBody", () => {
131
- it("returns 400 when teamId missing", async () => {
132
- const res = await getTeamContextFromBody({});
133
- expect(res).toBeInstanceOf(Response);
134
- expect((res as Response).status).toBe(400);
135
- });
136
-
137
- it("returns team context when valid", async () => {
138
- vi.mocked(readOpenClawConfig).mockResolvedValue({
139
- agents: { defaults: { workspace: "/ws" } },
140
- });
141
- const res = await getTeamContextFromBody({ teamId: "t1" });
142
- expect(res).toEqual({ teamId: "t1", teamDir: "/ws/../workspace-t1" });
143
- });
144
- });
145
-
146
- describe("listWorkspaceFiles", () => {
147
- beforeEach(() => {
148
- vi.mocked(fs.stat).mockReset();
149
- });
150
-
151
- it("returns file info for existing files", async () => {
152
- vi.mocked(fs.stat).mockResolvedValue({ size: 100, mtimeMs: 123 } as never);
153
-
154
- const result = await listWorkspaceFiles("/base", [
155
- { name: "a.md", required: true, rationale: "A" },
156
- { name: "b.md", required: false, rationale: "B" },
157
- ]);
158
-
159
- expect(result).toHaveLength(2);
160
- expect(result[0]).toEqual({
161
- name: "a.md",
162
- required: true,
163
- rationale: "A",
164
- path: "/base/a.md",
165
- missing: false,
166
- size: 100,
167
- updatedAtMs: 123,
168
- });
169
- expect(result[1].missing).toBe(false);
170
- });
171
-
172
- it("marks missing files", async () => {
173
- vi.mocked(fs.stat).mockRejectedValue(new Error("ENOENT"));
174
-
175
- const result = await listWorkspaceFiles("/base", [
176
- { name: "missing.md", required: true, rationale: "M" },
177
- ]);
178
-
179
- expect(result[0]).toEqual({
180
- name: "missing.md",
181
- required: true,
182
- rationale: "M",
183
- path: "/base/missing.md",
184
- missing: true,
185
- });
186
- });
187
- });
188
- });
@@ -1,45 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { cronJobId, cronJobLabel, fmtCronSchedule } from "../cron";
3
-
4
- describe("cronJobId", () => {
5
- it("returns id when present", () => {
6
- expect(cronJobId({ id: "j1" })).toBe("j1");
7
- });
8
-
9
- it("returns jobId when id missing", () => {
10
- expect(cronJobId({ jobId: "j2" })).toBe("j2");
11
- });
12
-
13
- it("returns empty string when both missing", () => {
14
- expect(cronJobId({})).toBe("");
15
- });
16
- });
17
-
18
- describe("cronJobLabel", () => {
19
- it("returns name when present", () => {
20
- expect(cronJobLabel({ name: "Daily sync" })).toBe("Daily sync");
21
- });
22
-
23
- it("falls back to id then jobId", () => {
24
- expect(cronJobLabel({ id: "j1" })).toBe("j1");
25
- expect(cronJobLabel({ jobId: "j2" })).toBe("j2");
26
- });
27
-
28
- it("returns (unnamed) when all missing", () => {
29
- expect(cronJobLabel({})).toBe("(unnamed)");
30
- });
31
- });
32
-
33
- describe("fmtCronSchedule", () => {
34
- it("returns cron expr when kind is cron", () => {
35
- expect(fmtCronSchedule({ kind: "cron", expr: "0 * * * *" })).toBe("0 * * * *");
36
- });
37
-
38
- it("returns minutes when kind is every and everyMs", () => {
39
- expect(fmtCronSchedule({ kind: "every", everyMs: 300000 })).toBe("every 5m");
40
- });
41
-
42
- it("returns empty for undefined", () => {
43
- expect(fmtCronSchedule(undefined)).toBe("");
44
- });
45
- });
@@ -1,38 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { normalizeFileListEntries } from "../editor-utils";
3
-
4
- describe("editor-utils", () => {
5
- describe("normalizeFileListEntries", () => {
6
- it("normalizes file list entries", () => {
7
- const input = [
8
- { name: "TEAM.md", missing: false, required: true, rationale: "Overview" },
9
- { name: "X.md", missing: true, required: false },
10
- ];
11
- const result = normalizeFileListEntries(input);
12
- expect(result).toEqual([
13
- { name: "TEAM.md", missing: false, required: true, rationale: "Overview" },
14
- { name: "X.md", missing: true, required: false, rationale: undefined },
15
- ]);
16
- });
17
-
18
- it("handles empty array", () => {
19
- expect(normalizeFileListEntries([])).toEqual([]);
20
- });
21
-
22
- it("coerces non-string name to string", () => {
23
- const result = normalizeFileListEntries([{ name: 123 }]);
24
- expect(result[0].name).toBe("123");
25
- });
26
-
27
- it("coerces null/undefined to empty string", () => {
28
- const result = normalizeFileListEntries([{}]);
29
- expect(result[0].name).toBe("");
30
- });
31
-
32
- it("treats missing/required as boolean", () => {
33
- const result = normalizeFileListEntries([{ name: "x", missing: "yes", required: 1 }]);
34
- expect(result[0].missing).toBe(true);
35
- expect(result[0].required).toBe(true);
36
- });
37
- });
38
- });