kennel 0.2.2 → 0.2.5

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 (237) hide show
  1. package/README.md +23 -13
  2. package/dist/cli/dispatch.js +16 -3
  3. package/dist/cli/src/cli/dispatch.js +16 -3
  4. package/dist/cli/src/cli/usage.js +1 -1
  5. package/dist/cli/src/core/command.js +1 -0
  6. package/dist/cli/src/core/init.js +5 -5
  7. package/dist/cli/src/plugins/external.d.ts +29 -3
  8. package/dist/cli/src/plugins/external.js +78 -24
  9. package/dist/cli/src/site/server-plugins.d.ts +2 -7
  10. package/dist/cli/src/site/viewer.js +1 -0
  11. package/dist/cli/usage.js +1 -1
  12. package/dist/core/command.js +1 -0
  13. package/dist/core/init.js +5 -5
  14. package/dist/core/runtime.js +357 -3207
  15. package/dist/package/preview.js +1232 -5113
  16. package/dist/plugins/external.d.ts +29 -3
  17. package/dist/plugins/external.js +78 -24
  18. package/dist/site/server-plugins.d.ts +2 -7
  19. package/dist/site/server-plugins.js +552 -10447
  20. package/dist/site/viewer.js +1 -0
  21. package/kernel/apps/web/package.json +1 -5
  22. package/kernel/apps/web/scripts/dev.mjs +53 -0
  23. package/kernel/apps/web/src/app.css +0 -3
  24. package/kernel/apps/web/src/main.tsx +0 -1
  25. package/kernel/apps/web/src/plugins.ts +0 -30
  26. package/kernel/apps/web/tsconfig.json +1 -2
  27. package/kernel/apps/web/vite.config.ts +31 -13
  28. package/kernel/packages/api/package.json +0 -4
  29. package/kernel/packages/api/src/server/folder-metadata-plugin.ts +13 -38
  30. package/kernel/packages/api/src/server/index.ts +0 -1
  31. package/kernel/packages/api/src/server/plugins.ts +49 -16
  32. package/kernel/packages/api/test/core.test.ts +13 -25
  33. package/kernel/packages/markdown/README.md +1 -1
  34. package/package.json +1 -1
  35. package/web/assets/{abnfDiagram-VRR7QNED-Bgfb1nEB.js → abnfDiagram-VRR7QNED-xd_g1uK3.js} +1 -1
  36. package/web/assets/app-CX20nNIa.js +2 -0
  37. package/web/assets/{app-options-D-RJiQ-X.js → app-options-CkPJE5ep.js} +1 -1
  38. package/web/assets/{app-view-header-BLvLq02T.js → app-view-header-CNk5KnA-.js} +1 -1
  39. package/web/assets/{arc-Dk_KI36B.js → arc-B0u5yBJA.js} +1 -1
  40. package/web/assets/{architectureDiagram-ZJ3FMSHR-NR_KhRCf.js → architectureDiagram-ZJ3FMSHR-DfxOAo8P.js} +1 -1
  41. package/web/assets/{ask-tray-TzeTcO6-.js → ask-tray-SscJecDY.js} +1 -1
  42. package/web/assets/{blockDiagram-677ZJIJ3-CkLkwx9C.js → blockDiagram-677ZJIJ3-Ci3Usxh6.js} +1 -1
  43. package/web/assets/{c4Diagram-LMCZKHZV-CFCUH8e_.js → c4Diagram-LMCZKHZV-BqgwIVgh.js} +1 -1
  44. package/web/assets/channel-X7WHyxxT.js +1 -0
  45. package/web/assets/{chunk-2Q5K7J3B-B_BPLWsW.js → chunk-2Q5K7J3B-CfX69l2U.js} +1 -1
  46. package/web/assets/{chunk-32BRIVSS-B1VB1hOy.js → chunk-32BRIVSS-CuFlzZkl.js} +1 -1
  47. package/web/assets/{chunk-5VM5RSS4-KFcYr8Co.js → chunk-5VM5RSS4-DidCMlJa.js} +1 -1
  48. package/web/assets/{chunk-EX3LRPZG-CpBX3kuK.js → chunk-EX3LRPZG-B5CDm1dS.js} +1 -1
  49. package/web/assets/{chunk-JWPE2WC7-BPSl40wG.js → chunk-JWPE2WC7-D5fGV_sH.js} +1 -1
  50. package/web/assets/{chunk-MOJQB5TN-D2RcYmoU.js → chunk-MOJQB5TN-ayhH5Q-H.js} +1 -1
  51. package/web/assets/{chunk-RYQCIY6F-m7Gyn-t3.js → chunk-RYQCIY6F-C4BfOOZn.js} +1 -1
  52. package/web/assets/{chunk-V7JOEXUC-TDvdopxS.js → chunk-V7JOEXUC-DpUEIM9V.js} +1 -1
  53. package/web/assets/{chunk-VR4S4FIN-DZTsG51a.js → chunk-VR4S4FIN-DoQuFFRh.js} +1 -1
  54. package/web/assets/{chunk-XXDRQBXY-Dp0--RE2.js → chunk-XXDRQBXY-CI9eiLwn.js} +1 -1
  55. package/web/assets/classDiagram-OUVF2IWQ-BjsLQ3dz.js +1 -0
  56. package/web/assets/classDiagram-v2-EOCWNBFH-BjsLQ3dz.js +1 -0
  57. package/web/assets/client-7OWw5kW2.js +6 -0
  58. package/web/assets/client-DYj_td4Q.js +17 -0
  59. package/web/assets/{client-j2kQmxsO.js → client-Dk-NBvJR.js} +4 -4
  60. package/web/assets/command-zkzH4hVz.js +38 -0
  61. package/web/assets/{copy-context-C0Uqsp-3.js → copy-context-D5oiWrYC.js} +1 -1
  62. package/web/assets/{cose-bilkent-JH36ORCC-CPu3PI8h.js → cose-bilkent-JH36ORCC-BHRk1mO3.js} +1 -1
  63. package/web/assets/{cynefin-VYW2F7L2-DWxftYAm.js → cynefin-VYW2F7L2-C1B09TRE.js} +1 -1
  64. package/web/assets/{cynefinDiagram-TSTJHNR4-DsmN2V-p.js → cynefinDiagram-TSTJHNR4-B27qXQbv.js} +1 -1
  65. package/web/assets/{dagre-VKFMJZFB-COEbApyY.js → dagre-VKFMJZFB-B1qEi32g.js} +1 -1
  66. package/web/assets/{diagram-FQU43EPY-0O9WGWKB.js → diagram-FQU43EPY-BMkkgADD.js} +1 -1
  67. package/web/assets/{diagram-G47NLZAW-CutEdMVh.js → diagram-G47NLZAW-Cb8_g1A5.js} +1 -1
  68. package/web/assets/{diagram-NH7WQ7WH-C9KZc3B2.js → diagram-NH7WQ7WH-B51wuc5m.js} +1 -1
  69. package/web/assets/{diagram-OA4YK3LP-D8kkPXbY.js → diagram-OA4YK3LP-xnsecbbI.js} +1 -1
  70. package/web/assets/{diagram-WEI45ONY-_YqiTaGP.js → diagram-WEI45ONY-DSZdyaAV.js} +1 -1
  71. package/web/assets/{document-Dgt5eZFj.js → document-Dc2dftTW.js} +3 -3
  72. package/web/assets/{ebnfDiagram-CCIWWBDH-JO-zQh6g.js → ebnfDiagram-CCIWWBDH-aTHmcUGy.js} +1 -1
  73. package/web/assets/{entities-C3wz7FCx.js → entities-CCUtpskY.js} +1 -1
  74. package/web/assets/{erDiagram-Q63AITRT-9UjQwJ4P.js → erDiagram-Q63AITRT-CUUPBcvo.js} +1 -1
  75. package/web/assets/{file-viewer-DZJ8nYnl.js → file-viewer-DJ3rsmef.js} +1 -1
  76. package/web/assets/{flowDiagram-23GEKE2U-Ca08tnYM.js → flowDiagram-23GEKE2U-aTQXx2Mh.js} +1 -1
  77. package/web/assets/{folder-image-BfGgxo7i.js → folder-image-Bnv43tzP.js} +1 -1
  78. package/web/assets/{folder-landing-qUKBCnG-.js → folder-landing-DCnzYXXY.js} +1 -1
  79. package/web/assets/{folder-list-BfFjv7rR.js → folder-list-DvVkVjiR.js} +1 -1
  80. package/web/assets/{folder-metadata-DCw8xzHk.js → folder-metadata-C9hMMzIH.js} +1 -1
  81. package/web/assets/{folder-mobile-bar-Ubz4babf.js → folder-mobile-bar-VoTL1GS0.js} +1 -1
  82. package/web/assets/folder-plugin-view-Cvd804ZU.js +6 -0
  83. package/web/assets/{ganttDiagram-NO4QXBWP-KnHzX5W3.js → ganttDiagram-NO4QXBWP-DiwdUp7u.js} +1 -1
  84. package/web/assets/{gitGraphDiagram-IHSO6WYX-Cm8woNtK.js → gitGraphDiagram-IHSO6WYX-BL2gG_IS.js} +1 -1
  85. package/web/assets/{index-CNyy98F8.js → index-CUTtMSyJ.js} +2 -2
  86. package/web/assets/index-CegvVQ1C.js +1 -0
  87. package/web/assets/index-Dwhf8F_U.css +1 -0
  88. package/web/assets/{infoDiagram-FWYZ7A6U-yyqmUtIb.js → infoDiagram-FWYZ7A6U-B3n0zZpt.js} +1 -1
  89. package/web/assets/{ishikawaDiagram-FXEZZL3T-BfvR_Zy4.js → ishikawaDiagram-FXEZZL3T-D7YytbEv.js} +1 -1
  90. package/web/assets/{journeyDiagram-5HDEW3XC-BKuw06HM.js → journeyDiagram-5HDEW3XC-BYwqEl3C.js} +1 -1
  91. package/web/assets/{kanban-definition-HUTT4EX6-n0010rmQ.js → kanban-definition-HUTT4EX6-BQHNJgXZ.js} +1 -1
  92. package/web/assets/{linear-C0d0lT8O.js → linear-BPiQCLNk.js} +1 -1
  93. package/web/assets/{mermaid.core-BDVbShyO.js → mermaid.core-CD-KvBjV.js} +4 -4
  94. package/web/assets/{metadata-KV0dpp4G.js → metadata-COJ7fZul.js} +1 -1
  95. package/web/assets/{mindmap-definition-LN4V7U3C--_0ks3GF.js → mindmap-definition-LN4V7U3C-C1L_gyoj.js} +1 -1
  96. package/web/assets/{pegDiagram-2B236MQR-CBoNIpKR.js → pegDiagram-2B236MQR-BDAfItqS.js} +1 -1
  97. package/web/assets/{pieDiagram-ENE6RG2P-MA5tkYh5.js → pieDiagram-ENE6RG2P-CkZYH3Vz.js} +1 -1
  98. package/web/assets/{popover-DBD7FF-W.js → popover-0oA2lLUV.js} +2 -2
  99. package/web/assets/{project-search-dialog-DM1IkSZu.js → project-search-dialog-B2oqMT6h.js} +1 -1
  100. package/web/assets/{quadrantDiagram-ABIIQ3AL-CWT1ryqF.js → quadrantDiagram-ABIIQ3AL-Dy8Al3YZ.js} +1 -1
  101. package/web/assets/{railroadDiagram-RFXS5EU6-ZiLB5FGi.js → railroadDiagram-RFXS5EU6-Dd9_yo7B.js} +1 -1
  102. package/web/assets/{requirementDiagram-TGXJPOKE-CQq9uneq.js → requirementDiagram-TGXJPOKE-DPhIUsbs.js} +1 -1
  103. package/web/assets/{sankeyDiagram-HTMAVEWB-qDG-0JqI.js → sankeyDiagram-HTMAVEWB-B2QkYtub.js} +1 -1
  104. package/web/assets/{search-DNrQA5fF.js → search-C1J0-xiB.js} +1 -1
  105. package/web/assets/select-CtXC_PLC.js +30 -0
  106. package/web/assets/{selection-popup-DmtTeRs2.js → selection-popup-qhlUFzGq.js} +1 -1
  107. package/web/assets/{sequenceDiagram-DBY2YBRQ-CiApurLO.js → sequenceDiagram-DBY2YBRQ-Bx7fcZDx.js} +1 -1
  108. package/web/assets/{sizeCapture-X5ZJPWSS-DZSR5QXm.js → sizeCapture-X5ZJPWSS-CIXIhl_A.js} +1 -1
  109. package/web/assets/{stateDiagram-2N3HPSRC-CjJJR9_z.js → stateDiagram-2N3HPSRC-DCrdAflB.js} +1 -1
  110. package/web/assets/stateDiagram-v2-6OUMAXLB-0KCFLYeQ.js +1 -0
  111. package/web/assets/{swimlanes-5IMT3BWC-CKmo1sg6.js → swimlanes-5IMT3BWC-DA2vc7iZ.js} +2 -2
  112. package/web/assets/swimlanesDiagram-G3AALYLV-CAw3AV84.js +8 -0
  113. package/web/assets/{timeline-definition-FHXFAJF6-D-NMwS3y.js → timeline-definition-FHXFAJF6-lKfJiV9V.js} +1 -1
  114. package/web/assets/{vennDiagram-L72KCM5P-CfL6LBWw.js → vennDiagram-L72KCM5P-DO1q2KzG.js} +1 -1
  115. package/web/assets/{view-context-gyDl_p2V.js → view-context-DXKM3-l1.js} +4 -4
  116. package/web/assets/{viewer-capabilities-Bpp8Uvcg.js → viewer-capabilities-Cig_xM9u.js} +1 -1
  117. package/web/assets/{wardleyDiagram-EHGQE667-DgldMxaj.js → wardleyDiagram-EHGQE667-Dal9LkuZ.js} +1 -1
  118. package/web/assets/{xychartDiagram-FW5EYKEG-CIoAIFX8.js → xychartDiagram-FW5EYKEG-B3dPLPII.js} +1 -1
  119. package/web/index.html +2 -2
  120. package/kernel/packages/api/test/partial-loading.test.ts +0 -43
  121. package/kernel/plugins/calendar/SKILL.md +0 -173
  122. package/kernel/plugins/calendar/eslint.config.js +0 -10
  123. package/kernel/plugins/calendar/package.json +0 -73
  124. package/kernel/plugins/calendar/schema.json +0 -137
  125. package/kernel/plugins/calendar/src/calendar.tsx +0 -328
  126. package/kernel/plugins/calendar/src/client.tsx +0 -139
  127. package/kernel/plugins/calendar/src/context.ts +0 -48
  128. package/kernel/plugins/calendar/src/copy-button.tsx +0 -66
  129. package/kernel/plugins/calendar/src/event-dialog.tsx +0 -270
  130. package/kernel/plugins/calendar/src/index.ts +0 -4
  131. package/kernel/plugins/calendar/src/manifest.ts +0 -7
  132. package/kernel/plugins/calendar/src/parse.ts +0 -610
  133. package/kernel/plugins/calendar/src/server.ts +0 -160
  134. package/kernel/plugins/calendar/src/utils.ts +0 -80
  135. package/kernel/plugins/calendar/src/views.tsx +0 -418
  136. package/kernel/plugins/calendar/test/context.test.mjs +0 -60
  137. package/kernel/plugins/calendar/test/package.test.mjs +0 -43
  138. package/kernel/plugins/calendar/test/parse.test.mjs +0 -392
  139. package/kernel/plugins/calendar/test/server.test.mjs +0 -126
  140. package/kernel/plugins/calendar/tsconfig.json +0 -17
  141. package/kernel/plugins/mail/SKILL.md +0 -97
  142. package/kernel/plugins/mail/eslint.config.js +0 -10
  143. package/kernel/plugins/mail/package.json +0 -79
  144. package/kernel/plugins/mail/src/api.ts +0 -359
  145. package/kernel/plugins/mail/src/bun-ffi.d.ts +0 -14
  146. package/kernel/plugins/mail/src/client.tsx +0 -14
  147. package/kernel/plugins/mail/src/flock.ts +0 -137
  148. package/kernel/plugins/mail/src/folders.ts +0 -37
  149. package/kernel/plugins/mail/src/history.ts +0 -485
  150. package/kernel/plugins/mail/src/index.ts +0 -3
  151. package/kernel/plugins/mail/src/mail-card.tsx +0 -123
  152. package/kernel/plugins/mail/src/mail-conversation.tsx +0 -153
  153. package/kernel/plugins/mail/src/mail-detail-page.tsx +0 -467
  154. package/kernel/plugins/mail/src/mail-hooks.ts +0 -252
  155. package/kernel/plugins/mail/src/mail-page.tsx +0 -109
  156. package/kernel/plugins/mail/src/mail-request.ts +0 -78
  157. package/kernel/plugins/mail/src/mail-send-box.tsx +0 -175
  158. package/kernel/plugins/mail/src/mailos.ts +0 -723
  159. package/kernel/plugins/mail/src/manifest.ts +0 -7
  160. package/kernel/plugins/mail/src/node.ts +0 -171
  161. package/kernel/plugins/mail/src/parse.ts +0 -139
  162. package/kernel/plugins/mail/src/server.ts +0 -125
  163. package/kernel/plugins/mail/src/types.ts +0 -10
  164. package/kernel/plugins/mail/src/viewer.tsx +0 -147
  165. package/kernel/plugins/mail/test/flock.test.mjs +0 -156
  166. package/kernel/plugins/mail/test/folders.test.mjs +0 -138
  167. package/kernel/plugins/mail/test/history.test.mjs +0 -460
  168. package/kernel/plugins/mail/test/mailos.test.mjs +0 -752
  169. package/kernel/plugins/mail/test/node.test.mjs +0 -207
  170. package/kernel/plugins/mail/test/package.test.mjs +0 -54
  171. package/kernel/plugins/mail/test/parse.test.mjs +0 -32
  172. package/kernel/plugins/mail/test/server.test.mjs +0 -116
  173. package/kernel/plugins/mail/test/viewer.test.mjs +0 -192
  174. package/kernel/plugins/mail/tsconfig.json +0 -17
  175. package/kernel/plugins/projects/SKILL.md +0 -73
  176. package/kernel/plugins/projects/eslint.config.js +0 -10
  177. package/kernel/plugins/projects/package.json +0 -70
  178. package/kernel/plugins/projects/src/client.tsx +0 -17
  179. package/kernel/plugins/projects/src/data/model.ts +0 -129
  180. package/kernel/plugins/projects/src/index.ts +0 -17
  181. package/kernel/plugins/projects/src/manifest.ts +0 -7
  182. package/kernel/plugins/projects/src/project-context.ts +0 -41
  183. package/kernel/plugins/projects/src/server.ts +0 -276
  184. package/kernel/plugins/projects/src/ui/project-card.tsx +0 -61
  185. package/kernel/plugins/projects/src/ui/projects-page.tsx +0 -102
  186. package/kernel/plugins/projects/test/package.test.mjs +0 -51
  187. package/kernel/plugins/projects/tsconfig.json +0 -17
  188. package/kernel/plugins/tasks/SKILL.md +0 -341
  189. package/kernel/plugins/tasks/eslint.config.js +0 -10
  190. package/kernel/plugins/tasks/package.json +0 -74
  191. package/kernel/plugins/tasks/schema.json +0 -939
  192. package/kernel/plugins/tasks/src/api.ts +0 -212
  193. package/kernel/plugins/tasks/src/client.tsx +0 -23
  194. package/kernel/plugins/tasks/src/data/parse.ts +0 -544
  195. package/kernel/plugins/tasks/src/data/task-id.ts +0 -56
  196. package/kernel/plugins/tasks/src/data/todo-model.ts +0 -795
  197. package/kernel/plugins/tasks/src/index.ts +0 -34
  198. package/kernel/plugins/tasks/src/manifest.ts +0 -7
  199. package/kernel/plugins/tasks/src/pages/task-detail.tsx +0 -48
  200. package/kernel/plugins/tasks/src/pages/task-list.tsx +0 -88
  201. package/kernel/plugins/tasks/src/server.ts +0 -447
  202. package/kernel/plugins/tasks/src/styles.css +0 -9
  203. package/kernel/plugins/tasks/src/ui/compact-todo-list.tsx +0 -372
  204. package/kernel/plugins/tasks/src/ui/error-details.tsx +0 -78
  205. package/kernel/plugins/tasks/src/ui/task-page.tsx +0 -392
  206. package/kernel/plugins/tasks/src/ui/todo-agent-filter.tsx +0 -36
  207. package/kernel/plugins/tasks/src/ui/todo-filter-bar.tsx +0 -66
  208. package/kernel/plugins/tasks/src/ui/todo-item.tsx +0 -494
  209. package/kernel/plugins/tasks/src/ui/todo-status-filter.tsx +0 -60
  210. package/kernel/plugins/tasks/src/ui/todo-tag-filter.tsx +0 -48
  211. package/kernel/plugins/tasks/src/ui/todo-warnings.tsx +0 -106
  212. package/kernel/plugins/tasks/test/api.test.mjs +0 -99
  213. package/kernel/plugins/tasks/test/folder-sources.test.mjs +0 -46
  214. package/kernel/plugins/tasks/test/package.test.mjs +0 -54
  215. package/kernel/plugins/tasks/test/parse.test.mjs +0 -225
  216. package/kernel/plugins/tasks/test/server.test.mjs +0 -386
  217. package/kernel/plugins/tasks/tsconfig.json +0 -17
  218. package/web/assets/app-DoGr2Zi7.js +0 -2
  219. package/web/assets/channel-uMEjV8qc.js +0 -1
  220. package/web/assets/classDiagram-OUVF2IWQ-fbZocVor.js +0 -1
  221. package/web/assets/classDiagram-v2-EOCWNBFH-fbZocVor.js +0 -1
  222. package/web/assets/client-C6Nxdfif.js +0 -2
  223. package/web/assets/client-CXYfBko5.js +0 -17
  224. package/web/assets/client-CoKtOq-X.js +0 -7
  225. package/web/assets/client-DyRQz5RU.js +0 -53
  226. package/web/assets/client-OY6HUzuD.js +0 -98
  227. package/web/assets/client-YOYWZIFi.js +0 -34
  228. package/web/assets/command-BugZBGXE.js +0 -38
  229. package/web/assets/folder-plugin-view-DsWR1zmQ.js +0 -6
  230. package/web/assets/index-BaRnbYRw.js +0 -1
  231. package/web/assets/index-BexmLxIP.css +0 -1
  232. package/web/assets/index-DDirZMgx.js +0 -1
  233. package/web/assets/note-card-DBfX6gW1.js +0 -6
  234. package/web/assets/select-D8cqNgcp.js +0 -30
  235. package/web/assets/stateDiagram-v2-6OUMAXLB-BpeGSCu9.js +0 -1
  236. package/web/assets/swimlanesDiagram-G3AALYLV-D9RjLKb9.js +0 -8
  237. package/web/assets/use-folder-filter-LQyXns5Q.js +0 -1
@@ -1,372 +0,0 @@
1
- import type { ReactNode } from "react"
2
- import { useCallback, useEffect, useMemo, useState } from "react"
3
- import { Effect } from "effect"
4
- import { Check, ChevronRight } from "lucide-react"
5
-
6
- import { CopyContextButton } from "@raggle-ai/ui/components/copy-context"
7
-
8
- import type {
9
- JsonTodo,
10
- TodoDataset,
11
- TodoDatasetOptions,
12
- TodoFilter,
13
- TodoFilterSelection,
14
- TodoState,
15
- UiTodoItem,
16
- } from "../data/todo-model.js"
17
- import { qualifiedTaskId } from "../data/task-id.js"
18
- import {
19
- fetchTodoDataset,
20
- initialState,
21
- visibleTodos,
22
- } from "../data/todo-model.js"
23
- import { TodoFilterBar } from "./todo-filter-bar.js"
24
- import { todoItemContext } from "./todo-item.js"
25
-
26
- export type CompactTodoListProps = TodoDatasetOptions & {
27
- readonly dataset?: TodoDataset | null
28
- readonly className?: string
29
- /** When set, each task title links to this href (a task detail view). */
30
- readonly itemHref?: (item: UiTodoItem) => string | undefined
31
- /** When set, rows get a complete/reopen tick button. */
32
- readonly onToggle?: (item: UiTodoItem) => void
33
- /** When set, the status/tag/agent filter line is shown. */
34
- readonly filters?: boolean
35
- /** Filter controls rendered in front of the filter line (e.g. folder
36
- * chips), so all filter areas share one horizontal row. */
37
- readonly leadingFilters?: ReactNode
38
- /** Controls rendered at the right end of the filter line (e.g. the
39
- * warnings modal trigger). */
40
- readonly trailingFilters?: ReactNode
41
- }
42
-
43
- export function CompactTodoList({
44
- dataset = null,
45
- className = "",
46
- filters = false,
47
- leadingFilters,
48
- trailingFilters,
49
- itemHref,
50
- onToggle,
51
- ...options
52
- }: CompactTodoListProps) {
53
- const [filter, setFilter] = useState<TodoFilter>(initialState.filter)
54
- const [tag, setTag] = useState<TodoFilterSelection>([])
55
- const [assignee, setAssignee] = useState<TodoFilterSelection>([])
56
- // URL-driven usage (no `dataset` prop) fetches the dataset itself.
57
- const [fetched, setFetched] = useState<TodoDataset | null>(null)
58
- const [error, setError] = useState<string | null>(null)
59
-
60
- const activeDataset = dataset ?? fetched
61
-
62
- // Fetch only when a dataset is not provided by the caller. State updates
63
- // happen inside the promise callback, never synchronously in the effect.
64
- useEffect(() => {
65
- if (dataset) return
66
- let cancelled = false
67
- void Effect.runPromise(
68
- Effect.either(
69
- fetchTodoDataset({
70
- dataUrl: options.dataUrl,
71
- path: options.path,
72
- schemaUrl: options.schemaUrl,
73
- }),
74
- ),
75
- ).then((result) => {
76
- if (cancelled) return
77
- if (result._tag === "Left") {
78
- setError(result.left.message)
79
- } else {
80
- setError(null)
81
- setFetched(result.right)
82
- }
83
- })
84
- return () => {
85
- cancelled = true
86
- }
87
- }, [dataset, options.dataUrl, options.path, options.schemaUrl])
88
-
89
- const todos = useMemo(() => {
90
- const state: TodoState = {
91
- ...initialState,
92
- dataset: activeDataset,
93
- filter,
94
- tag,
95
- assignee,
96
- }
97
- return Effect.runSync(visibleTodos(state))
98
- }, [activeDataset, filter, tag, assignee])
99
- const loading = !activeDataset && !error
100
-
101
- return (
102
- <main
103
- className={["min-h-full bg-transparent text-slate-950", className]
104
- .filter(Boolean)
105
- .join(" ")}
106
- >
107
- <section className="mx-auto w-full max-w-3xl px-3 py-4 sm:px-5 sm:py-5">
108
- {error ? (
109
- <p
110
- className="mb-3 rounded-lg border border-red-200 bg-red-50 px-3 py-2
111
- text-sm text-red-700"
112
- >
113
- {error}
114
- </p>
115
- ) : null}
116
-
117
- {filters ? (
118
- <TodoFilterBar
119
- assignee={assignee}
120
- className="mb-3"
121
- dataset={activeDataset}
122
- filter={filter}
123
- leading={leadingFilters}
124
- trailing={trailingFilters}
125
- onAssigneeChange={setAssignee}
126
- onFilterChange={setFilter}
127
- onTagChange={setTag}
128
- tag={tag}
129
- />
130
- ) : null}
131
-
132
- {loading ? (
133
- <p className="py-8 text-center text-sm text-slate-500">
134
- Loading tasks…
135
- </p>
136
- ) : todos.length === 0 ? (
137
- <p className="py-8 text-center text-sm text-slate-500">
138
- {emptyFilterText(filter, tag)}
139
- </p>
140
- ) : (
141
- <ol className="space-y-2">
142
- {todos.map((item) => (
143
- <CompactTodoRow
144
- // Row identity uses the workspace-qualified address, not the
145
- // bare file-local id: merged nested task files repeat ids
146
- // like "todo:0" across folders.
147
- key={
148
- qualifiedTaskId(item.jsonTodo.source?.id, item.jsonTodo) ??
149
- item.id
150
- }
151
- item={item}
152
- folderPath={options.path}
153
- itemHref={itemHref}
154
- onToggle={onToggle}
155
- />
156
- ))}
157
- </ol>
158
- )}
159
- </section>
160
- </main>
161
- )
162
- }
163
-
164
- function CompactTodoRow({
165
- item,
166
- folderPath,
167
- itemHref,
168
- onToggle,
169
- }: {
170
- item: UiTodoItem
171
- folderPath?: string
172
- itemHref?: (item: UiTodoItem) => string | undefined
173
- onToggle?: (item: UiTodoItem) => void
174
- }) {
175
- const meta = compactMeta(item)
176
- const href = itemHref?.(item)
177
- // Build the prompt on click (wait function), not on render.
178
- const context = useCallback(
179
- () => compactTodoPrompt(item, folderPath),
180
- [item, folderPath],
181
- )
182
-
183
- return (
184
- <li
185
- // One border/background style per row: Tailwind sorts same-property
186
- // classes alphabetically, so stacked classes override each other.
187
- className={[
188
- "rounded-md border px-3 py-2",
189
- item.overdue
190
- ? "border-red-400 bg-red-50"
191
- : item.status === "blocked"
192
- ? "border-rose-300 bg-rose-50/60"
193
- : "border-slate-200 bg-white",
194
- ]
195
- .filter(Boolean)
196
- .join(" ")}
197
- >
198
- <div className="flex items-start gap-3">
199
- {onToggle ? (
200
- <button
201
- type="button"
202
- aria-pressed={item.status === "done"}
203
- aria-label={
204
- item.status === "done"
205
- ? `Reopen ${item.title}`
206
- : `Complete ${item.title}`
207
- }
208
- title={item.status === "done" ? "Reopen task" : "Complete task"}
209
- onClick={() => onToggle(item)}
210
- className={[
211
- "mt-0.5 grid h-5 w-5 shrink-0 place-items-center rounded-full",
212
- "border transition-colors",
213
- item.status === "done"
214
- ? "border-emerald-500 bg-emerald-500 text-white hover:bg-emerald-600"
215
- : item.status === "blocked"
216
- ? "border-rose-300 bg-rose-100 text-rose-600"
217
- : "border-slate-300 bg-white text-transparent hover:border-emerald-500 hover:bg-emerald-50 hover:text-emerald-600",
218
- ].join(" ")}
219
- >
220
- <Check className="h-3 w-3" />
221
- </button>
222
- ) : null}
223
- <div className="min-w-0 flex-1 space-y-1">
224
- {href ? (
225
- <a
226
- href={href}
227
- className={[
228
- "inline-flex items-center gap-1 text-sm leading-5 font-medium",
229
- "text-slate-900 no-underline hover:text-indigo-700",
230
- item.status === "done" ? "text-slate-500 line-through" : "",
231
- ]
232
- .filter(Boolean)
233
- .join(" ")}
234
- >
235
- <span>{item.title}</span>
236
- <ChevronRight
237
- aria-hidden="true"
238
- className="h-3.5 w-3.5 text-slate-400"
239
- />
240
- </a>
241
- ) : (
242
- <p
243
- className={[
244
- "text-sm leading-5 font-medium text-slate-900",
245
- item.status === "done" ? "text-slate-500 line-through" : "",
246
- ].join(" ")}
247
- >
248
- {item.title}
249
- </p>
250
- )}
251
- {meta.status || meta.folder ? (
252
- <p className="text-xs leading-4 text-slate-500">
253
- {meta.status ? (
254
- <span
255
- className={item.overdue ? "font-medium text-red-600" : ""}
256
- >
257
- {meta.status}
258
- </span>
259
- ) : null}
260
- {meta.folder ? (
261
- <span>
262
- {meta.status ? " • " : ""}
263
- {meta.folder}
264
- </span>
265
- ) : null}
266
- </p>
267
- ) : null}
268
- </div>
269
- <CopyContextButton
270
- className="shrink-0 text-slate-500 hover:text-slate-900"
271
- context={context}
272
- label={`Copy prompt for ${item.title}`}
273
- />
274
- </div>
275
- </li>
276
- )
277
- }
278
-
279
- const emptyFilterText = (filter: TodoFilter, tag: TodoFilterSelection) => {
280
- const status =
281
- filter === "done"
282
- ? "done"
283
- : filter === "blocked"
284
- ? "blocked"
285
- : filter === "overdue"
286
- ? "late"
287
- : filter === "all"
288
- ? ""
289
- : "open"
290
- if (tag.length)
291
- return `No ${status ? `${status} ` : ""}tasks with the selected tags`
292
- switch (filter) {
293
- case "done":
294
- return "No done tasks"
295
- case "blocked":
296
- return "No blocked tasks"
297
- case "overdue":
298
- return "No late tasks"
299
- case "all":
300
- return "No tasks"
301
- default:
302
- return "No open tasks"
303
- }
304
- }
305
-
306
- /** Row meta: the status label, then the folder the task file lives in. */
307
- const compactMeta = (item: UiTodoItem) => ({
308
- status:
309
- item.status === "blocked"
310
- ? "Blocked"
311
- : item.overdue
312
- ? "Late"
313
- : item.status === "done"
314
- ? "Done"
315
- : "",
316
- folder: item.jsonTodo.source.title.replace(/ tasks$/, ""),
317
- })
318
-
319
- const compactTodoPrompt = (item: UiTodoItem, folderPath?: string) => {
320
- const todoJsonPath = folderPath ? `${folderPath}/todo.json` : "todo.json"
321
- const relatedFiles = relatedReadFiles(item.jsonTodo)
322
-
323
- return [
324
- `The model is instructed to complete this specific todo: ${item.title}`,
325
- "",
326
- todoItemContext(item),
327
- "",
328
- `Todo JSON: ${todoJsonPath}`,
329
- relatedFiles.length ? "Read these relative files before you start:" : null,
330
- relatedFiles.length
331
- ? relatedFiles.map((path) => `- ${path}`).join("\n")
332
- : null,
333
- ]
334
- .filter((line): line is string => Boolean(line))
335
- .join("\n")
336
- }
337
-
338
- const relatedReadFiles = (todo: JsonTodo) =>
339
- unique(relativePathsFromCustomFields(todo.customFields))
340
-
341
- const relativePathsFromCustomFields = (
342
- fields: ReadonlyArray<{ id: string; value: unknown }>,
343
- ) =>
344
- fields.flatMap((field) =>
345
- fileFieldName(field.id) ? relativePathsFromValue(field.value) : [],
346
- )
347
-
348
- const fileFieldName = (value: string) =>
349
- /(file|path|read|context|source|doc)/i.test(value)
350
-
351
- const relativePathsFromValue = (value: unknown): string[] => {
352
- if (typeof value === "string") {
353
- return isRelativeFilePath(value) ? [value] : []
354
- }
355
- if (Array.isArray(value)) {
356
- return value.flatMap((entry) => relativePathsFromValue(entry))
357
- }
358
- if (value && typeof value === "object") {
359
- return Object.entries(value).flatMap(([key, entry]) =>
360
- fileFieldName(key) ? relativePathsFromValue(entry) : [],
361
- )
362
- }
363
- return []
364
- }
365
-
366
- const isRelativeFilePath = (value: string) =>
367
- Boolean(value) &&
368
- !value.startsWith("/") &&
369
- !/^[a-z]+:\/\//i.test(value) &&
370
- /[./\\]/.test(value)
371
-
372
- const unique = (values: ReadonlyArray<string>) => [...new Set(values)]
@@ -1,78 +0,0 @@
1
- import type { ReactNode } from "react"
2
- import { useState } from "react"
3
- import { ChevronDown } from "lucide-react"
4
-
5
- import type { CopyContextSource } from "@raggle-ai/ui/components/copy-context"
6
- import { Button } from "@raggle-ai/ui/components/button"
7
- import { CopyContextButton } from "@raggle-ai/ui/components/copy-context"
8
-
9
- export type ErrorDetailsProps = {
10
- /** Short heading, e.g. "Task data is not valid." */
11
- title: string
12
- /** Full error text. Collapsed to a short preview by default. */
13
- error: string
14
- /** What "Copy context" writes; defaults to the error text. */
15
- context?: CopyContextSource
16
- /** Accessible name and tooltip for the copy button. */
17
- copyLabel?: string
18
- /** Optional extra action next to copy, e.g. a Retry button. */
19
- action?: ReactNode
20
- }
21
-
22
- /**
23
- * Collapsible red error panel for the tasks viewer. Long schema and
24
- * validation dumps take one small collapsed row by default; the full text,
25
- * plus a copy-context button for pasting the failure back to an agent, is
26
- * one click away.
27
- */
28
- export function ErrorDetails({
29
- title,
30
- error,
31
- context,
32
- copyLabel = "Copy error context",
33
- action,
34
- }: ErrorDetailsProps): ReactNode {
35
- const [expanded, setExpanded] = useState(false)
36
- const isLong = error.length > 200 || error.includes("\n")
37
-
38
- return (
39
- <div className="rounded-md border border-[#9c3a3a]/40 p-4">
40
- <div className="flex items-start justify-between gap-2">
41
- <p className="m-0 text-sm font-semibold text-[#9c3a3a]">{title}</p>
42
- <div className="flex shrink-0 items-center gap-1">
43
- {action}
44
- <CopyContextButton
45
- className="text-[#9c3a3a] hover:text-[#6f2020]"
46
- context={context ?? error}
47
- label={copyLabel}
48
- />
49
- </div>
50
- </div>
51
- <p
52
- className={`m-0 mt-1 text-[13px] text-[#9c3a3a] ${
53
- expanded || !isLong
54
- ? "break-words whitespace-pre-wrap"
55
- : "line-clamp-2"
56
- }`}
57
- >
58
- {error}
59
- </p>
60
- {isLong ? (
61
- <Button
62
- className="mt-1 -ml-2 text-[#9c3a3a] hover:text-[#6f2020]"
63
- onClick={() => setExpanded((value) => !value)}
64
- size="sm"
65
- type="button"
66
- variant="ghost"
67
- >
68
- {expanded ? "Show less" : "Show more"}
69
- <ChevronDown
70
- className={`size-3.5 transition-transform ${
71
- expanded ? "rotate-180" : ""
72
- }`}
73
- />
74
- </Button>
75
- ) : null}
76
- </div>
77
- )
78
- }