@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,147 +0,0 @@
1
- "use client";
2
-
3
- import Link from "next/link";
4
- import { useRouter } from "next/navigation";
5
- import { useState, useTransition } from "react";
6
-
7
- import { useToast } from "@/components/ToastProvider";
8
- import { errorMessage } from "@/lib/errors";
9
- import { fetchJson } from "@/lib/fetch-json";
10
- import { TicketAssignControl } from "@/app/tickets/[ticket]/TicketAssignControl";
11
-
12
- export function TicketDetailClient(props: {
13
- teamId: string;
14
- ticketId: string;
15
- file: string;
16
- markdown: string;
17
- backHref?: string;
18
- currentOwner?: string | null;
19
- }) {
20
- const router = useRouter();
21
- const toast = useToast();
22
- const [isPending, startTransition] = useTransition();
23
- const [error, setError] = useState<string | null>(null);
24
- const [confirm, setConfirm] = useState<null | { kind: "goals" | "delete" }>(null);
25
-
26
- async function moveToGoals() {
27
- setError(null);
28
- await fetchJson(`/api/teams/${encodeURIComponent(props.teamId)}/tickets/move-to-goals`, {
29
- method: "POST",
30
- headers: { "content-type": "application/json" },
31
- body: JSON.stringify({ ticket: props.ticketId }),
32
- });
33
- }
34
-
35
- async function deleteTicket() {
36
- setError(null);
37
- await fetchJson(`/api/teams/${encodeURIComponent(props.teamId)}/tickets/delete`, {
38
- method: "POST",
39
- headers: { "content-type": "application/json" },
40
- body: JSON.stringify({ ticket: props.ticketId }),
41
- });
42
- }
43
-
44
- return (
45
- <div className="space-y-4">
46
- <div className="flex items-center justify-between gap-3">
47
- <Link href={props.backHref ?? "/tickets"} className="text-sm font-medium hover:underline">
48
- ← Back
49
- </Link>
50
- <span className="text-xs text-[color:var(--ck-text-tertiary)]">{props.file}</span>
51
- </div>
52
-
53
- {error ? (
54
- <div className="ck-glass border border-[color:var(--ck-border-strong)] p-3 text-sm text-[color:var(--ck-text-primary)]">
55
- {error}
56
- </div>
57
- ) : null}
58
-
59
- {props.currentOwner !== undefined ? (
60
- <TicketAssignControl teamId={props.teamId} ticket={props.ticketId} currentOwner={props.currentOwner ?? null} />
61
- ) : null}
62
-
63
- <div className="ck-glass p-4">
64
- <div className="flex flex-wrap items-center justify-end gap-2">
65
- <button
66
- className="rounded border border-[color:var(--ck-border-subtle)] px-3 py-1.5 text-xs font-medium text-[color:var(--ck-text-secondary)] hover:border-[color:var(--ck-border-strong)]"
67
- onClick={() => setConfirm({ kind: "goals" })}
68
- disabled={isPending}
69
- >
70
- Move to Goals
71
- </button>
72
- <button
73
- className="rounded border border-[color:var(--ck-accent-red)] bg-[color:var(--ck-accent-red-soft)] px-3 py-1.5 text-xs font-medium text-[color:var(--ck-accent-red)] hover:bg-[color:var(--ck-accent-red-soft-strong)]"
74
- onClick={() => setConfirm({ kind: "delete" })}
75
- disabled={isPending}
76
- >
77
- Delete Ticket
78
- </button>
79
- </div>
80
- </div>
81
-
82
- <div className="ck-glass p-6">
83
- <pre className="whitespace-pre-wrap break-words text-sm leading-6 text-[color:var(--ck-text-primary)]">
84
- {props.markdown}
85
- </pre>
86
- </div>
87
-
88
- {confirm ? (
89
- <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
90
- <div className="ck-glass w-full max-w-lg rounded-[var(--ck-radius-md)] border border-[color:var(--ck-border-strong)] p-4">
91
- <div className="text-sm font-semibold text-[color:var(--ck-text-primary)]">
92
- {confirm.kind === "goals" ? "Move to Goals" : "Delete ticket"}
93
- </div>
94
-
95
- <div className="mt-2 text-sm text-[color:var(--ck-text-secondary)]">
96
- {confirm.kind === "goals" ? (
97
- <>This will move the ticket out of the work lanes into <code>work/goals/</code> so it won’t be picked up by automation.</>
98
- ) : (
99
- <>This will permanently remove the ticket markdown file. Assignment stubs (if any) will be archived.</>
100
- )}
101
- </div>
102
-
103
- <div className="mt-4 flex items-center justify-end gap-2">
104
- <button
105
- className="rounded border border-[color:var(--ck-border-subtle)] px-3 py-1.5 text-xs text-[color:var(--ck-text-secondary)]"
106
- onClick={() => setConfirm(null)}
107
- disabled={isPending}
108
- >
109
- Cancel
110
- </button>
111
- <button
112
- className={
113
- confirm.kind === "delete"
114
- ? "rounded bg-[color:var(--ck-accent-red)] px-3 py-1.5 text-xs font-medium text-white"
115
- : "rounded bg-[color:var(--ck-accent)] px-3 py-1.5 text-xs font-medium text-black"
116
- }
117
- onClick={() => {
118
- const kind = confirm.kind;
119
- setConfirm(null);
120
- startTransition(() => {
121
- const op = kind === "goals" ? moveToGoals() : deleteTicket();
122
- op
123
- .then(() => {
124
- toast.push({
125
- kind: "success",
126
- message: kind === "delete" ? "Ticket deleted." : "Moved to Goals.",
127
- });
128
- if (kind === "delete") {
129
- router.push(props.backHref ?? "/tickets");
130
- } else {
131
- router.refresh();
132
- }
133
- })
134
- .catch((e: unknown) => setError(errorMessage(e)));
135
- });
136
- }}
137
- disabled={isPending}
138
- >
139
- Confirm
140
- </button>
141
- </div>
142
- </div>
143
- </div>
144
- ) : null}
145
- </div>
146
- );
147
- }
@@ -1,200 +0,0 @@
1
- "use client";
2
-
3
- import { useMemo, useState } from "react";
4
- import type { TicketStage, TicketSummary } from "@/lib/tickets";
5
-
6
- const STAGES: { key: TicketStage; label: string }[] = [
7
- { key: "backlog", label: "Backlog" },
8
- { key: "in-progress", label: "In progress" },
9
- { key: "testing", label: "Testing" },
10
- { key: "done", label: "Done" },
11
- ];
12
-
13
- type DateFilter = "all" | "today" | "yesterday" | "7d" | "30d" | "custom";
14
- const DATE_FILTERS: { key: DateFilter; label: string }[] = [
15
- { key: "all", label: "All" },
16
- { key: "today", label: "Today" },
17
- { key: "yesterday", label: "Yesterday" },
18
- { key: "7d", label: "Last 7 days" },
19
- { key: "30d", label: "Last 30 days" },
20
- { key: "custom", label: "Custom range" },
21
- ];
22
-
23
- function startOfLocalDay(d: Date) {
24
- return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0, 0);
25
- }
26
-
27
- function parseDateInput(value: string): Date | null {
28
- if (!value) return null;
29
- const m = value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
30
- if (!m) return null;
31
- const y = Number(m[1]);
32
- const mo = Number(m[2]) - 1;
33
- const day = Number(m[3]);
34
- const d = new Date(y, mo, day, 0, 0, 0, 0);
35
- return Number.isFinite(d.getTime()) ? d : null;
36
- }
37
-
38
- function formatAge(hours: number) {
39
- if (hours < 1) return `${Math.max(1, Math.round(hours * 60))}m`;
40
- if (hours < 48) return `${Math.round(hours)}h`;
41
- return `${Math.round(hours / 24)}d`;
42
- }
43
-
44
- export function TicketsBoardClient({
45
- tickets,
46
- basePath,
47
- }: {
48
- tickets: TicketSummary[];
49
- basePath: string;
50
- }) {
51
- const [dateFilter, setDateFilter] = useState<DateFilter>("30d");
52
- const [customFrom, setCustomFrom] = useState<string>("");
53
- const [customTo, setCustomTo] = useState<string>("");
54
-
55
- const filteredTickets = useMemo(() => {
56
- if (dateFilter === "all") return tickets;
57
-
58
- const now = new Date();
59
- const todayStart = startOfLocalDay(now);
60
- const yesterdayStart = new Date(todayStart);
61
- yesterdayStart.setDate(yesterdayStart.getDate() - 1);
62
-
63
- let from: Date | null = null;
64
- let toExclusive: Date | null = null;
65
-
66
- if (dateFilter === "today") {
67
- from = todayStart;
68
- toExclusive = new Date(todayStart);
69
- toExclusive.setDate(toExclusive.getDate() + 1);
70
- } else if (dateFilter === "yesterday") {
71
- from = yesterdayStart;
72
- toExclusive = todayStart;
73
- } else if (dateFilter === "7d") {
74
- from = new Date(todayStart);
75
- from.setDate(from.getDate() - 6); // include today
76
- } else if (dateFilter === "30d") {
77
- from = new Date(todayStart);
78
- from.setDate(from.getDate() - 29); // include today
79
- } else if (dateFilter === "custom") {
80
- from = parseDateInput(customFrom);
81
- const to = parseDateInput(customTo);
82
- if (to) {
83
- toExclusive = new Date(to);
84
- toExclusive.setDate(toExclusive.getDate() + 1);
85
- }
86
- }
87
-
88
- return tickets.filter((t) => {
89
- const updated = new Date(t.updatedAt);
90
- if (!Number.isFinite(updated.getTime())) return false;
91
- if (from && updated < from) return false;
92
- if (toExclusive && updated >= toExclusive) return false;
93
- return true;
94
- });
95
- }, [tickets, dateFilter, customFrom, customTo]);
96
-
97
- const byStage = useMemo(() => {
98
- const map: Record<TicketStage, TicketSummary[]> = {
99
- backlog: [],
100
- "in-progress": [],
101
- testing: [],
102
- done: [],
103
- };
104
- for (const t of filteredTickets) map[t.stage].push(t);
105
- for (const s of Object.keys(map) as TicketStage[]) {
106
- map[s].sort((a, b) => a.number - b.number);
107
- }
108
- return map;
109
- }, [filteredTickets]);
110
-
111
- return (
112
- <div className="space-y-4">
113
- <div className="flex flex-wrap items-center justify-between gap-3">
114
- <h1 className="text-2xl font-semibold tracking-tight">Tickets</h1>
115
-
116
- <div className="flex flex-wrap items-center gap-3">
117
- <label className="text-xs text-[color:var(--ck-text-secondary)]">
118
- Time
119
- <select
120
- className="ml-2 rounded border border-[color:var(--ck-border-subtle)] bg-transparent px-2 py-1 text-xs"
121
- value={dateFilter}
122
- onChange={(e) => setDateFilter(e.target.value as DateFilter)}
123
- >
124
- {DATE_FILTERS.map((f) => (
125
- <option key={f.key} value={f.key}>
126
- {f.label}
127
- </option>
128
- ))}
129
- </select>
130
- </label>
131
-
132
- {dateFilter === "custom" ? (
133
- <div className="flex flex-wrap items-center gap-2">
134
- <label className="text-xs text-[color:var(--ck-text-secondary)]">
135
- From
136
- <input
137
- type="date"
138
- value={customFrom}
139
- onChange={(e) => setCustomFrom(e.target.value)}
140
- className="ml-2 rounded border border-[color:var(--ck-border-subtle)] bg-transparent px-2 py-1 text-xs"
141
- />
142
- </label>
143
- <label className="text-xs text-[color:var(--ck-text-secondary)]">
144
- To
145
- <input
146
- type="date"
147
- value={customTo}
148
- onChange={(e) => setCustomTo(e.target.value)}
149
- className="ml-2 rounded border border-[color:var(--ck-border-subtle)] bg-transparent px-2 py-1 text-xs"
150
- />
151
- </label>
152
- </div>
153
- ) : null}
154
- </div>
155
- </div>
156
-
157
- <div className="grid gap-4 lg:grid-cols-4">
158
- {STAGES.map(({ key, label }) => (
159
- <section key={key} className="ck-glass p-3">
160
- <div className="mb-3 flex items-center justify-between">
161
- <h2 className="text-sm font-semibold tracking-tight">{label}</h2>
162
- <span className="text-xs text-[color:var(--ck-text-tertiary)]">{byStage[key].length}</span>
163
- </div>
164
-
165
- <div className="space-y-2">
166
- {byStage[key].length === 0 ? (
167
- <div className="rounded-[var(--ck-radius-sm)] border border-dashed border-[color:var(--ck-border-subtle)] p-3 text-xs text-[color:var(--ck-text-tertiary)]">
168
- Empty
169
- </div>
170
- ) : null}
171
-
172
- {byStage[key].map((t) => (
173
- <div
174
- key={t.id}
175
- className="rounded-[var(--ck-radius-sm)] border border-[color:var(--ck-border-subtle)] bg-[color:var(--ck-bg-glass-strong)] p-3"
176
- >
177
- <a
178
- href={`${basePath}/${encodeURIComponent(t.id)}`}
179
- className="block text-sm font-medium text-[color:var(--ck-text-primary)] hover:underline"
180
- >
181
- {String(t.number).padStart(4, "0")} — {t.title}
182
- </a>
183
- <div className="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-[color:var(--ck-text-secondary)]">
184
- <span>{t.owner ? `Owner: ${t.owner}` : "Owner: —"}</span>
185
- <span>·</span>
186
- <span>Age: {formatAge(t.ageHours)}</span>
187
- </div>
188
- </div>
189
- ))}
190
- </div>
191
- </section>
192
- ))}
193
- </div>
194
-
195
- <p className="text-xs text-[color:var(--ck-text-tertiary)]">
196
- Source of truth: ticket markdown files in the team workspace.
197
- </p>
198
- </div>
199
- );
200
- }
@@ -1,112 +0,0 @@
1
- "use client";
2
-
3
- import { useEffect, useMemo, useState } from "react";
4
- import { useRouter } from "next/navigation";
5
-
6
- export function TicketAssignControl({
7
- teamId,
8
- ticket,
9
- currentOwner,
10
- }: {
11
- teamId?: string | null;
12
- ticket: string;
13
- currentOwner: string | null;
14
- }) {
15
- const router = useRouter();
16
- const [assignees, setAssignees] = useState<string[]>([]);
17
- const [selected, setSelected] = useState<string>(currentOwner ?? "");
18
- const [loading, setLoading] = useState(false);
19
- const [error, setError] = useState<string | null>(null);
20
-
21
- useEffect(() => {
22
- let cancelled = false;
23
- (async () => {
24
- try {
25
- const url = teamId
26
- ? `/api/teams/${encodeURIComponent(teamId)}/tickets/assignees`
27
- : "/api/tickets/assignees";
28
- const res = await fetch(url, { cache: "no-store" });
29
- const json = (await res.json()) as { assignees?: string[] };
30
- if (cancelled) return;
31
- setAssignees(Array.isArray(json.assignees) ? json.assignees : []);
32
- } catch {
33
- if (cancelled) return;
34
- setAssignees([]);
35
- }
36
- })();
37
- return () => {
38
- cancelled = true;
39
- };
40
- }, []);
41
-
42
- const options = useMemo(() => {
43
- const base = new Set(assignees);
44
- if (currentOwner) base.add(currentOwner);
45
- return Array.from(base).sort();
46
- }, [assignees, currentOwner]);
47
-
48
- async function onAssign() {
49
- setLoading(true);
50
- setError(null);
51
- try {
52
- const url = teamId
53
- ? `/api/teams/${encodeURIComponent(teamId)}/tickets/assign`
54
- : "/api/tickets/assign";
55
-
56
- const res = await fetch(url, {
57
- method: "POST",
58
- headers: { "content-type": "application/json" },
59
- body: JSON.stringify({ ticket, assignee: selected }),
60
- });
61
-
62
- const json = (await res.json()) as { error?: string };
63
- if (!res.ok) {
64
- setError(json.error || "Assign failed");
65
- return;
66
- }
67
-
68
- router.refresh();
69
- } catch {
70
- setError("Assign failed");
71
- } finally {
72
- setLoading(false);
73
- }
74
- }
75
-
76
- return (
77
- <div className="ck-glass p-4">
78
- <div className="flex flex-wrap items-center gap-3">
79
- <div className="text-xs font-medium text-[color:var(--ck-text-tertiary)]">Assignee</div>
80
- <select
81
- className="rounded-md border border-white/10 bg-black/20 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]"
82
- value={selected}
83
- onChange={(e) => setSelected(e.target.value)}
84
- >
85
- <option value="" disabled>
86
- Select…
87
- </option>
88
- {options.map((a) => (
89
- <option key={a} value={a}>
90
- {a}
91
- </option>
92
- ))}
93
- </select>
94
-
95
- <button
96
- type="button"
97
- onClick={onAssign}
98
- disabled={loading || !selected || selected === (currentOwner ?? "")}
99
- className="rounded-md bg-emerald-600 px-3 py-2 text-sm font-semibold text-white hover:bg-emerald-500 disabled:cursor-not-allowed disabled:opacity-50"
100
- >
101
- {loading ? "Assigning…" : "Assign"}
102
- </button>
103
-
104
- {currentOwner ? (
105
- <div className="text-xs text-[color:var(--ck-text-tertiary)]">Currently: {currentOwner}</div>
106
- ) : null}
107
- </div>
108
-
109
- {error ? <div className="mt-2 text-xs text-red-300">{error}</div> : null}
110
- </div>
111
- );
112
- }
@@ -1,36 +0,0 @@
1
- import { getTicketMarkdown } from "@/lib/tickets";
2
- import { TicketDetailClient } from "@/app/tickets/TicketDetailClient";
3
-
4
- // Ticket detail should always reflect current stage/file; do not cache.
5
- export const dynamic = "force-dynamic";
6
-
7
- export default async function TicketDetailPage({
8
- params,
9
- }: {
10
- params: Promise<{ ticket: string }>;
11
- }) {
12
- const { ticket } = await params;
13
- const teamId = "development-team";
14
- const data = await getTicketMarkdown(teamId, ticket);
15
-
16
- if (!data) {
17
- return (
18
- <div className="ck-glass p-6">
19
- <h1 className="text-xl font-semibold tracking-tight">Ticket not found</h1>
20
- <p className="mt-3 text-sm text-[color:var(--ck-text-secondary)]">
21
- Couldn’t locate “{ticket}” in backlog/in-progress/testing/done.
22
- </p>
23
- </div>
24
- );
25
- }
26
-
27
- return (
28
- <TicketDetailClient
29
- teamId={teamId}
30
- ticketId={data.id}
31
- file={data.file}
32
- markdown={data.markdown}
33
- currentOwner={data.owner}
34
- />
35
- );
36
- }
@@ -1,10 +0,0 @@
1
- import { listTickets } from "@/lib/tickets";
2
- import { TicketsBoardClient } from "@/app/tickets/TicketsBoardClient";
3
-
4
- // Tickets reflect live filesystem state; do not cache.
5
- export const dynamic = "force-dynamic";
6
-
7
- export default async function TicketsPage() {
8
- const tickets = await listTickets("development-team");
9
- return <TicketsBoardClient tickets={tickets} basePath="/tickets" />;
10
- }