kennel 0.2.3 → 0.2.6

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 (274) 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 +28 -2
  8. package/dist/cli/src/plugins/external.js +77 -23
  9. package/dist/cli/src/site/server-plugins.d.ts +4 -9
  10. package/dist/cli/src/site/viewer.js +1 -0
  11. package/dist/cli/usage.js +1 -1
  12. package/dist/core/api-client.js +576 -10317
  13. package/dist/core/command.js +1 -0
  14. package/dist/core/core-folders.js +2313 -12088
  15. package/dist/core/init.js +5 -5
  16. package/dist/core/runtime.js +8237 -20713
  17. package/dist/package/preview.js +19617 -33352
  18. package/dist/plugins/external.d.ts +28 -2
  19. package/dist/plugins/external.js +77 -23
  20. package/dist/site/server-plugins.d.ts +4 -9
  21. package/dist/site/server-plugins.js +557 -10452
  22. package/dist/site/viewer.js +1 -0
  23. package/kernel/apps/web/package.json +2 -6
  24. package/kernel/apps/web/scripts/dev.mjs +53 -0
  25. package/kernel/apps/web/src/app.css +0 -3
  26. package/kernel/apps/web/src/external-plugins.ts +1 -1
  27. package/kernel/apps/web/src/folder-filter-icons.tsx +1 -1
  28. package/kernel/apps/web/src/folder-plugin-view.tsx +1 -1
  29. package/kernel/apps/web/src/main.tsx +0 -1
  30. package/kernel/apps/web/src/plugins.ts +1 -31
  31. package/kernel/apps/web/tsconfig.json +1 -2
  32. package/kernel/apps/web/vite.config.ts +32 -14
  33. package/kernel/packages/agents/package.json +1 -1
  34. package/kernel/packages/agents/src/agent-card.tsx +1 -1
  35. package/kernel/packages/agents/src/client.tsx +1 -1
  36. package/kernel/packages/agents/src/manifest.ts +1 -1
  37. package/kernel/packages/agents/src/server.ts +1 -1
  38. package/kernel/packages/agents/src/viewer.tsx +1 -1
  39. package/kernel/packages/api/package.json +1 -5
  40. package/kernel/packages/api/src/server/acp-live-plugin.ts +1 -1
  41. package/kernel/packages/api/src/server/api/create-agent-file.ts +2 -2
  42. package/kernel/packages/api/src/server/api/document-edit.ts +2 -2
  43. package/kernel/packages/api/src/server/api/open-path.ts +2 -2
  44. package/kernel/packages/api/src/server/folder-metadata-plugin.ts +17 -42
  45. package/kernel/packages/api/src/server/index.ts +0 -1
  46. package/kernel/packages/api/src/server/plugins.ts +52 -19
  47. package/kernel/packages/api/src/shared/viewer-route.ts +1 -1
  48. package/kernel/packages/api/test/core.test.ts +14 -26
  49. package/kernel/packages/markdown/README.md +1 -1
  50. package/kernel/packages/notes/package.json +1 -1
  51. package/kernel/packages/notes/src/client.tsx +1 -1
  52. package/kernel/packages/notes/src/manifest.ts +1 -1
  53. package/kernel/packages/notes/src/server.ts +1 -1
  54. package/kernel/packages/plugins/SKILL.md +39 -0
  55. package/kernel/{plugins/mail → packages/plugins}/package.json +53 -28
  56. package/kernel/packages/plugins/src/index.ts +52 -0
  57. package/kernel/packages/plugins/src/page.ts +17 -0
  58. package/kernel/{plugins/projects → packages/plugins}/tsconfig.json +5 -1
  59. package/kernel/packages/plugins/tsup.config.ts +25 -0
  60. package/kernel/packages/ui/src/components/content-issues.tsx +1 -1
  61. package/kernel/packages/ui/tsconfig.json +1 -1
  62. package/package.json +2 -3
  63. package/web/assets/{abnfDiagram-VRR7QNED-Bgfb1nEB.js → abnfDiagram-VRR7QNED-xd_g1uK3.js} +1 -1
  64. package/web/assets/app-CX20nNIa.js +2 -0
  65. package/web/assets/{app-options-D-RJiQ-X.js → app-options-CkPJE5ep.js} +1 -1
  66. package/web/assets/{app-view-header-BLvLq02T.js → app-view-header-CNk5KnA-.js} +1 -1
  67. package/web/assets/{arc-Dk_KI36B.js → arc-B0u5yBJA.js} +1 -1
  68. package/web/assets/{architectureDiagram-ZJ3FMSHR-NR_KhRCf.js → architectureDiagram-ZJ3FMSHR-DfxOAo8P.js} +1 -1
  69. package/web/assets/{ask-tray-TzeTcO6-.js → ask-tray-SscJecDY.js} +1 -1
  70. package/web/assets/{blockDiagram-677ZJIJ3-CkLkwx9C.js → blockDiagram-677ZJIJ3-Ci3Usxh6.js} +1 -1
  71. package/web/assets/{c4Diagram-LMCZKHZV-CFCUH8e_.js → c4Diagram-LMCZKHZV-BqgwIVgh.js} +1 -1
  72. package/web/assets/channel-X7WHyxxT.js +1 -0
  73. package/web/assets/{chunk-2Q5K7J3B-B_BPLWsW.js → chunk-2Q5K7J3B-CfX69l2U.js} +1 -1
  74. package/web/assets/{chunk-32BRIVSS-B1VB1hOy.js → chunk-32BRIVSS-CuFlzZkl.js} +1 -1
  75. package/web/assets/{chunk-5VM5RSS4-KFcYr8Co.js → chunk-5VM5RSS4-DidCMlJa.js} +1 -1
  76. package/web/assets/{chunk-EX3LRPZG-CpBX3kuK.js → chunk-EX3LRPZG-B5CDm1dS.js} +1 -1
  77. package/web/assets/{chunk-JWPE2WC7-BPSl40wG.js → chunk-JWPE2WC7-D5fGV_sH.js} +1 -1
  78. package/web/assets/{chunk-MOJQB5TN-D2RcYmoU.js → chunk-MOJQB5TN-ayhH5Q-H.js} +1 -1
  79. package/web/assets/{chunk-RYQCIY6F-m7Gyn-t3.js → chunk-RYQCIY6F-C4BfOOZn.js} +1 -1
  80. package/web/assets/{chunk-V7JOEXUC-TDvdopxS.js → chunk-V7JOEXUC-DpUEIM9V.js} +1 -1
  81. package/web/assets/{chunk-VR4S4FIN-DZTsG51a.js → chunk-VR4S4FIN-DoQuFFRh.js} +1 -1
  82. package/web/assets/{chunk-XXDRQBXY-Dp0--RE2.js → chunk-XXDRQBXY-CI9eiLwn.js} +1 -1
  83. package/web/assets/classDiagram-OUVF2IWQ-BjsLQ3dz.js +1 -0
  84. package/web/assets/classDiagram-v2-EOCWNBFH-BjsLQ3dz.js +1 -0
  85. package/web/assets/client-7OWw5kW2.js +6 -0
  86. package/web/assets/client-DYj_td4Q.js +17 -0
  87. package/web/assets/{client-j2kQmxsO.js → client-Dk-NBvJR.js} +4 -4
  88. package/web/assets/command-zkzH4hVz.js +38 -0
  89. package/web/assets/{copy-context-C0Uqsp-3.js → copy-context-D5oiWrYC.js} +1 -1
  90. package/web/assets/{cose-bilkent-JH36ORCC-CPu3PI8h.js → cose-bilkent-JH36ORCC-BHRk1mO3.js} +1 -1
  91. package/web/assets/{cynefin-VYW2F7L2-DWxftYAm.js → cynefin-VYW2F7L2-C1B09TRE.js} +1 -1
  92. package/web/assets/{cynefinDiagram-TSTJHNR4-DsmN2V-p.js → cynefinDiagram-TSTJHNR4-B27qXQbv.js} +1 -1
  93. package/web/assets/{dagre-VKFMJZFB-COEbApyY.js → dagre-VKFMJZFB-B1qEi32g.js} +1 -1
  94. package/web/assets/{diagram-FQU43EPY-0O9WGWKB.js → diagram-FQU43EPY-BMkkgADD.js} +1 -1
  95. package/web/assets/{diagram-G47NLZAW-CutEdMVh.js → diagram-G47NLZAW-Cb8_g1A5.js} +1 -1
  96. package/web/assets/{diagram-NH7WQ7WH-C9KZc3B2.js → diagram-NH7WQ7WH-B51wuc5m.js} +1 -1
  97. package/web/assets/{diagram-OA4YK3LP-D8kkPXbY.js → diagram-OA4YK3LP-xnsecbbI.js} +1 -1
  98. package/web/assets/{diagram-WEI45ONY-_YqiTaGP.js → diagram-WEI45ONY-DSZdyaAV.js} +1 -1
  99. package/web/assets/{document-Dgt5eZFj.js → document-Dc2dftTW.js} +3 -3
  100. package/web/assets/{ebnfDiagram-CCIWWBDH-JO-zQh6g.js → ebnfDiagram-CCIWWBDH-aTHmcUGy.js} +1 -1
  101. package/web/assets/{entities-C3wz7FCx.js → entities-CCUtpskY.js} +1 -1
  102. package/web/assets/{erDiagram-Q63AITRT-9UjQwJ4P.js → erDiagram-Q63AITRT-CUUPBcvo.js} +1 -1
  103. package/web/assets/{file-viewer-DZJ8nYnl.js → file-viewer-DJ3rsmef.js} +1 -1
  104. package/web/assets/{flowDiagram-23GEKE2U-Ca08tnYM.js → flowDiagram-23GEKE2U-aTQXx2Mh.js} +1 -1
  105. package/web/assets/{folder-image-BfGgxo7i.js → folder-image-Bnv43tzP.js} +1 -1
  106. package/web/assets/{folder-landing-qUKBCnG-.js → folder-landing-DCnzYXXY.js} +1 -1
  107. package/web/assets/{folder-list-BfFjv7rR.js → folder-list-DvVkVjiR.js} +1 -1
  108. package/web/assets/{folder-metadata-DCw8xzHk.js → folder-metadata-C9hMMzIH.js} +1 -1
  109. package/web/assets/{folder-mobile-bar-Ubz4babf.js → folder-mobile-bar-VoTL1GS0.js} +1 -1
  110. package/web/assets/folder-plugin-view-Cvd804ZU.js +6 -0
  111. package/web/assets/{ganttDiagram-NO4QXBWP-KnHzX5W3.js → ganttDiagram-NO4QXBWP-DiwdUp7u.js} +1 -1
  112. package/web/assets/{gitGraphDiagram-IHSO6WYX-Cm8woNtK.js → gitGraphDiagram-IHSO6WYX-BL2gG_IS.js} +1 -1
  113. package/web/assets/{index-CNyy98F8.js → index-CUTtMSyJ.js} +2 -2
  114. package/web/assets/index-CegvVQ1C.js +1 -0
  115. package/web/assets/index-Dwhf8F_U.css +1 -0
  116. package/web/assets/{infoDiagram-FWYZ7A6U-yyqmUtIb.js → infoDiagram-FWYZ7A6U-B3n0zZpt.js} +1 -1
  117. package/web/assets/{ishikawaDiagram-FXEZZL3T-BfvR_Zy4.js → ishikawaDiagram-FXEZZL3T-D7YytbEv.js} +1 -1
  118. package/web/assets/{journeyDiagram-5HDEW3XC-BKuw06HM.js → journeyDiagram-5HDEW3XC-BYwqEl3C.js} +1 -1
  119. package/web/assets/{kanban-definition-HUTT4EX6-n0010rmQ.js → kanban-definition-HUTT4EX6-BQHNJgXZ.js} +1 -1
  120. package/web/assets/{linear-C0d0lT8O.js → linear-BPiQCLNk.js} +1 -1
  121. package/web/assets/{mermaid.core-BDVbShyO.js → mermaid.core-CD-KvBjV.js} +4 -4
  122. package/web/assets/{metadata-KV0dpp4G.js → metadata-COJ7fZul.js} +1 -1
  123. package/web/assets/{mindmap-definition-LN4V7U3C--_0ks3GF.js → mindmap-definition-LN4V7U3C-C1L_gyoj.js} +1 -1
  124. package/web/assets/{pegDiagram-2B236MQR-CBoNIpKR.js → pegDiagram-2B236MQR-BDAfItqS.js} +1 -1
  125. package/web/assets/{pieDiagram-ENE6RG2P-MA5tkYh5.js → pieDiagram-ENE6RG2P-CkZYH3Vz.js} +1 -1
  126. package/web/assets/{popover-DBD7FF-W.js → popover-0oA2lLUV.js} +2 -2
  127. package/web/assets/{project-search-dialog-DM1IkSZu.js → project-search-dialog-B2oqMT6h.js} +1 -1
  128. package/web/assets/{quadrantDiagram-ABIIQ3AL-CWT1ryqF.js → quadrantDiagram-ABIIQ3AL-Dy8Al3YZ.js} +1 -1
  129. package/web/assets/{railroadDiagram-RFXS5EU6-ZiLB5FGi.js → railroadDiagram-RFXS5EU6-Dd9_yo7B.js} +1 -1
  130. package/web/assets/{requirementDiagram-TGXJPOKE-CQq9uneq.js → requirementDiagram-TGXJPOKE-DPhIUsbs.js} +1 -1
  131. package/web/assets/{sankeyDiagram-HTMAVEWB-qDG-0JqI.js → sankeyDiagram-HTMAVEWB-B2QkYtub.js} +1 -1
  132. package/web/assets/{search-DNrQA5fF.js → search-C1J0-xiB.js} +1 -1
  133. package/web/assets/select-CtXC_PLC.js +30 -0
  134. package/web/assets/{selection-popup-DmtTeRs2.js → selection-popup-qhlUFzGq.js} +1 -1
  135. package/web/assets/{sequenceDiagram-DBY2YBRQ-CiApurLO.js → sequenceDiagram-DBY2YBRQ-Bx7fcZDx.js} +1 -1
  136. package/web/assets/{sizeCapture-X5ZJPWSS-DZSR5QXm.js → sizeCapture-X5ZJPWSS-CIXIhl_A.js} +1 -1
  137. package/web/assets/{stateDiagram-2N3HPSRC-CjJJR9_z.js → stateDiagram-2N3HPSRC-DCrdAflB.js} +1 -1
  138. package/web/assets/stateDiagram-v2-6OUMAXLB-0KCFLYeQ.js +1 -0
  139. package/web/assets/{swimlanes-5IMT3BWC-CKmo1sg6.js → swimlanes-5IMT3BWC-DA2vc7iZ.js} +2 -2
  140. package/web/assets/swimlanesDiagram-G3AALYLV-CAw3AV84.js +8 -0
  141. package/web/assets/{timeline-definition-FHXFAJF6-D-NMwS3y.js → timeline-definition-FHXFAJF6-lKfJiV9V.js} +1 -1
  142. package/web/assets/{vennDiagram-L72KCM5P-CfL6LBWw.js → vennDiagram-L72KCM5P-DO1q2KzG.js} +1 -1
  143. package/web/assets/{view-context-gyDl_p2V.js → view-context-DXKM3-l1.js} +4 -4
  144. package/web/assets/{viewer-capabilities-Bpp8Uvcg.js → viewer-capabilities-Cig_xM9u.js} +1 -1
  145. package/web/assets/{wardleyDiagram-EHGQE667-DgldMxaj.js → wardleyDiagram-EHGQE667-Dal9LkuZ.js} +1 -1
  146. package/web/assets/{xychartDiagram-FW5EYKEG-CIoAIFX8.js → xychartDiagram-FW5EYKEG-B3dPLPII.js} +1 -1
  147. package/web/index.html +2 -2
  148. package/kernel/packages/api/test/partial-loading.test.ts +0 -43
  149. package/kernel/packages/folder-plugin/package.json +0 -50
  150. package/kernel/packages/folder-plugin/src/index.ts +0 -15
  151. package/kernel/packages/folder-plugin/tsconfig.json +0 -17
  152. package/kernel/plugins/calendar/SKILL.md +0 -173
  153. package/kernel/plugins/calendar/eslint.config.js +0 -10
  154. package/kernel/plugins/calendar/package.json +0 -73
  155. package/kernel/plugins/calendar/schema.json +0 -137
  156. package/kernel/plugins/calendar/src/calendar.tsx +0 -328
  157. package/kernel/plugins/calendar/src/client.tsx +0 -139
  158. package/kernel/plugins/calendar/src/context.ts +0 -48
  159. package/kernel/plugins/calendar/src/copy-button.tsx +0 -66
  160. package/kernel/plugins/calendar/src/event-dialog.tsx +0 -270
  161. package/kernel/plugins/calendar/src/index.ts +0 -4
  162. package/kernel/plugins/calendar/src/manifest.ts +0 -7
  163. package/kernel/plugins/calendar/src/parse.ts +0 -610
  164. package/kernel/plugins/calendar/src/server.ts +0 -160
  165. package/kernel/plugins/calendar/src/utils.ts +0 -80
  166. package/kernel/plugins/calendar/src/views.tsx +0 -418
  167. package/kernel/plugins/calendar/test/context.test.mjs +0 -60
  168. package/kernel/plugins/calendar/test/package.test.mjs +0 -43
  169. package/kernel/plugins/calendar/test/parse.test.mjs +0 -392
  170. package/kernel/plugins/calendar/test/server.test.mjs +0 -126
  171. package/kernel/plugins/calendar/tsconfig.json +0 -17
  172. package/kernel/plugins/mail/SKILL.md +0 -97
  173. package/kernel/plugins/mail/eslint.config.js +0 -10
  174. package/kernel/plugins/mail/src/api.ts +0 -359
  175. package/kernel/plugins/mail/src/bun-ffi.d.ts +0 -14
  176. package/kernel/plugins/mail/src/client.tsx +0 -14
  177. package/kernel/plugins/mail/src/flock.ts +0 -137
  178. package/kernel/plugins/mail/src/folders.ts +0 -37
  179. package/kernel/plugins/mail/src/history.ts +0 -485
  180. package/kernel/plugins/mail/src/index.ts +0 -3
  181. package/kernel/plugins/mail/src/mail-card.tsx +0 -123
  182. package/kernel/plugins/mail/src/mail-conversation.tsx +0 -153
  183. package/kernel/plugins/mail/src/mail-detail-page.tsx +0 -467
  184. package/kernel/plugins/mail/src/mail-hooks.ts +0 -252
  185. package/kernel/plugins/mail/src/mail-page.tsx +0 -109
  186. package/kernel/plugins/mail/src/mail-request.ts +0 -78
  187. package/kernel/plugins/mail/src/mail-send-box.tsx +0 -175
  188. package/kernel/plugins/mail/src/mailos.ts +0 -723
  189. package/kernel/plugins/mail/src/manifest.ts +0 -7
  190. package/kernel/plugins/mail/src/node.ts +0 -171
  191. package/kernel/plugins/mail/src/parse.ts +0 -139
  192. package/kernel/plugins/mail/src/server.ts +0 -125
  193. package/kernel/plugins/mail/src/types.ts +0 -10
  194. package/kernel/plugins/mail/src/viewer.tsx +0 -147
  195. package/kernel/plugins/mail/test/flock.test.mjs +0 -156
  196. package/kernel/plugins/mail/test/folders.test.mjs +0 -138
  197. package/kernel/plugins/mail/test/history.test.mjs +0 -460
  198. package/kernel/plugins/mail/test/mailos.test.mjs +0 -752
  199. package/kernel/plugins/mail/test/node.test.mjs +0 -207
  200. package/kernel/plugins/mail/test/package.test.mjs +0 -54
  201. package/kernel/plugins/mail/test/parse.test.mjs +0 -32
  202. package/kernel/plugins/mail/test/server.test.mjs +0 -116
  203. package/kernel/plugins/mail/test/viewer.test.mjs +0 -192
  204. package/kernel/plugins/mail/tsconfig.json +0 -17
  205. package/kernel/plugins/projects/SKILL.md +0 -73
  206. package/kernel/plugins/projects/eslint.config.js +0 -10
  207. package/kernel/plugins/projects/package.json +0 -70
  208. package/kernel/plugins/projects/src/client.tsx +0 -17
  209. package/kernel/plugins/projects/src/data/model.ts +0 -129
  210. package/kernel/plugins/projects/src/index.ts +0 -17
  211. package/kernel/plugins/projects/src/manifest.ts +0 -7
  212. package/kernel/plugins/projects/src/project-context.ts +0 -41
  213. package/kernel/plugins/projects/src/server.ts +0 -276
  214. package/kernel/plugins/projects/src/ui/project-card.tsx +0 -61
  215. package/kernel/plugins/projects/src/ui/projects-page.tsx +0 -102
  216. package/kernel/plugins/projects/test/package.test.mjs +0 -51
  217. package/kernel/plugins/tasks/SKILL.md +0 -341
  218. package/kernel/plugins/tasks/eslint.config.js +0 -10
  219. package/kernel/plugins/tasks/package.json +0 -74
  220. package/kernel/plugins/tasks/schema.json +0 -939
  221. package/kernel/plugins/tasks/src/api.ts +0 -212
  222. package/kernel/plugins/tasks/src/client.tsx +0 -23
  223. package/kernel/plugins/tasks/src/data/parse.ts +0 -544
  224. package/kernel/plugins/tasks/src/data/task-id.ts +0 -56
  225. package/kernel/plugins/tasks/src/data/todo-model.ts +0 -795
  226. package/kernel/plugins/tasks/src/index.ts +0 -34
  227. package/kernel/plugins/tasks/src/manifest.ts +0 -7
  228. package/kernel/plugins/tasks/src/pages/task-detail.tsx +0 -48
  229. package/kernel/plugins/tasks/src/pages/task-list.tsx +0 -88
  230. package/kernel/plugins/tasks/src/server.ts +0 -447
  231. package/kernel/plugins/tasks/src/styles.css +0 -9
  232. package/kernel/plugins/tasks/src/ui/compact-todo-list.tsx +0 -372
  233. package/kernel/plugins/tasks/src/ui/error-details.tsx +0 -78
  234. package/kernel/plugins/tasks/src/ui/task-page.tsx +0 -392
  235. package/kernel/plugins/tasks/src/ui/todo-agent-filter.tsx +0 -36
  236. package/kernel/plugins/tasks/src/ui/todo-filter-bar.tsx +0 -66
  237. package/kernel/plugins/tasks/src/ui/todo-item.tsx +0 -494
  238. package/kernel/plugins/tasks/src/ui/todo-status-filter.tsx +0 -60
  239. package/kernel/plugins/tasks/src/ui/todo-tag-filter.tsx +0 -48
  240. package/kernel/plugins/tasks/src/ui/todo-warnings.tsx +0 -106
  241. package/kernel/plugins/tasks/test/api.test.mjs +0 -99
  242. package/kernel/plugins/tasks/test/folder-sources.test.mjs +0 -46
  243. package/kernel/plugins/tasks/test/package.test.mjs +0 -54
  244. package/kernel/plugins/tasks/test/parse.test.mjs +0 -225
  245. package/kernel/plugins/tasks/test/server.test.mjs +0 -386
  246. package/kernel/plugins/tasks/tsconfig.json +0 -17
  247. package/web/assets/app-DoGr2Zi7.js +0 -2
  248. package/web/assets/channel-uMEjV8qc.js +0 -1
  249. package/web/assets/classDiagram-OUVF2IWQ-fbZocVor.js +0 -1
  250. package/web/assets/classDiagram-v2-EOCWNBFH-fbZocVor.js +0 -1
  251. package/web/assets/client-C6Nxdfif.js +0 -2
  252. package/web/assets/client-CXYfBko5.js +0 -17
  253. package/web/assets/client-CoKtOq-X.js +0 -7
  254. package/web/assets/client-DyRQz5RU.js +0 -53
  255. package/web/assets/client-OY6HUzuD.js +0 -98
  256. package/web/assets/client-YOYWZIFi.js +0 -34
  257. package/web/assets/command-BugZBGXE.js +0 -38
  258. package/web/assets/folder-plugin-view-DsWR1zmQ.js +0 -6
  259. package/web/assets/index-BaRnbYRw.js +0 -1
  260. package/web/assets/index-BexmLxIP.css +0 -1
  261. package/web/assets/index-DDirZMgx.js +0 -1
  262. package/web/assets/note-card-DBfX6gW1.js +0 -6
  263. package/web/assets/select-D8cqNgcp.js +0 -30
  264. package/web/assets/stateDiagram-v2-6OUMAXLB-BpeGSCu9.js +0 -1
  265. package/web/assets/swimlanesDiagram-G3AALYLV-D9RjLKb9.js +0 -8
  266. package/web/assets/use-folder-filter-LQyXns5Q.js +0 -1
  267. /package/kernel/packages/{folder-plugin → plugins}/eslint.config.js +0 -0
  268. /package/kernel/packages/{folder-plugin → plugins}/src/client.ts +0 -0
  269. /package/kernel/packages/{folder-plugin → plugins}/src/endpoint.ts +0 -0
  270. /package/kernel/packages/{folder-plugin → plugins}/src/server.ts +0 -0
  271. /package/kernel/packages/{folder-plugin → plugins}/src/subpath.ts +0 -0
  272. /package/kernel/packages/{folder-plugin → plugins}/src/types.ts +0 -0
  273. /package/kernel/packages/{folder-plugin → plugins}/src/validation.ts +0 -0
  274. /package/kernel/packages/{folder-plugin → plugins}/test/contract.test.mjs +0 -0
@@ -1,544 +0,0 @@
1
- /**
2
- * Validation functions for the raw `todo.json` source document.
3
- *
4
- * This module is the tasks plugin's "validate" seam: it turns a source file
5
- * into either a typed document or a list of precise, human-readable issues
6
- * (`path` + `message`). It is deliberately dependency-free and shared by the
7
- * server entry (detection + data loading), the client error panel, and the
8
- * plugin's node tests.
9
- *
10
- * Parsing never throws: invalid JSON and structural mistakes are reported as
11
- * issues so the host and viewer can show exactly what is wrong instead of a
12
- * 404 or a generic "could not parse" message.
13
- */
14
-
15
- import type { ContentIssue } from "@raggle-ai/folder-plugin/validation"
16
- import {
17
- issueSummary,
18
- parseJsonSource,
19
- } from "@raggle-ai/folder-plugin/validation"
20
-
21
- export const TASK_TYPES = [
22
- "task",
23
- "bug",
24
- "feature",
25
- "chore",
26
- "spike",
27
- "epic",
28
- "milestone",
29
- ] as const
30
-
31
- export const TASK_STATUSES = [
32
- "todo",
33
- "in_progress",
34
- "blocked",
35
- "review",
36
- "done",
37
- "canceled",
38
- ] as const
39
-
40
- export const RELATION_TYPES = [
41
- "blocks",
42
- "blocked_by",
43
- "related_to",
44
- "duplicates",
45
- "duplicated_by",
46
- "parent_of",
47
- "child_of",
48
- ] as const
49
-
50
- export const LINK_PROVIDERS = ["github", "linear", "jira", "web"] as const
51
-
52
- export const LINK_KINDS = [
53
- "issue",
54
- "pull_request",
55
- "commit",
56
- "repository",
57
- "project",
58
- "document",
59
- "design",
60
- "discussion",
61
- "external",
62
- ] as const
63
-
64
- export const LINK_RELATIONS = [
65
- "references",
66
- "implemented_by",
67
- "fixes",
68
- "reported_by",
69
- "spec",
70
- "design",
71
- "review",
72
- "deployment",
73
- "blocked_by",
74
- ] as const
75
-
76
- const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/
77
-
78
- /** One precise problem found in a task document. `path` is JSON-pointer-ish. */
79
- export type TodoIssue = ContentIssue
80
-
81
- /** The source document after validation; tasks keep their raw shapes. */
82
- export type TodoFile = {
83
- $schema?: string
84
- id?: string
85
- tasks: Array<Record<string, unknown>>
86
- title?: string
87
- version?: number
88
- }
89
-
90
- export type ParsedTodo =
91
- { ok: true; document: TodoFile } | { ok: false; issues: TodoIssue[] }
92
-
93
- function isRecord(value: unknown): value is Record<string, unknown> {
94
- return Boolean(value) && typeof value === "object" && !Array.isArray(value)
95
- }
96
-
97
- function nonEmptyString(value: unknown): value is string {
98
- return typeof value === "string" && value.trim().length > 0
99
- }
100
-
101
- /** Compact summary for nav badges and error headers. */
102
- export function todoIssueSummary(issues: TodoIssue[]): string {
103
- return issueSummary(issues, "todo.json")
104
- }
105
-
106
- /**
107
- * Validate an already-parsed JSON value. Returns every problem found; an
108
- * empty array means the document is structurally valid. Enums below mirror
109
- * the published schema (`https://raggle.co/schemas/tasks.json`) and the
110
- * client decoder in `./ui` (this plugin's vendored todo UI).
111
- */
112
- export function validateTodoFile(value: unknown): TodoIssue[] {
113
- if (!isRecord(value)) {
114
- return [{ path: "#", message: "todo.json must contain a JSON object" }]
115
- }
116
-
117
- const issues: TodoIssue[] = []
118
-
119
- if (
120
- value.version !== undefined &&
121
- value.version !== 1 &&
122
- value.version !== 2
123
- ) {
124
- issues.push({
125
- path: "version",
126
- message: `must be 1 or 2; got ${JSON.stringify(value.version)}`,
127
- })
128
- }
129
-
130
- if (value.$schema !== undefined && !nonEmptyString(value.$schema)) {
131
- issues.push({ path: "$schema", message: "must be a non-empty string" })
132
- }
133
-
134
- if (value.id !== undefined && !nonEmptyString(value.id)) {
135
- issues.push({ path: "id", message: "must be a non-empty string" })
136
- }
137
-
138
- if (value.title !== undefined && !nonEmptyString(value.title)) {
139
- issues.push({ path: "title", message: "must be a non-empty string" })
140
- }
141
-
142
- if (!Array.isArray(value.tasks)) {
143
- issues.push({ path: "tasks", message: "must be an array of tasks" })
144
- return issues
145
- }
146
-
147
- const ids = new Set<string>()
148
- const keys = new Set<string>()
149
- value.tasks.forEach((task, index) => {
150
- validateTask(task, `tasks[${index}]`, issues, ids, keys)
151
- })
152
-
153
- // Cross-task integrity: relation targets must point at a known task id.
154
- value.tasks.forEach((task, index) => {
155
- if (!isRecord(task) || !Array.isArray(task.relations)) return
156
- task.relations.forEach((relation, relIndex) => {
157
- if (!isRecord(relation)) return
158
- const target = relation.targetTaskId
159
- if (typeof target === "string" && !ids.has(target)) {
160
- issues.push({
161
- path: `tasks[${index}].relations[${relIndex}].targetTaskId`,
162
- message: `references unknown task id ${JSON.stringify(target)}`,
163
- })
164
- }
165
- })
166
- })
167
-
168
- return issues
169
- }
170
-
171
- function validateTask(
172
- task: unknown,
173
- path: string,
174
- issues: TodoIssue[],
175
- ids: Set<string>,
176
- keys: Set<string>,
177
- ) {
178
- if (!isRecord(task)) {
179
- issues.push({ path, message: "must be a task object" })
180
- return
181
- }
182
-
183
- if (!nonEmptyString(task.name)) {
184
- issues.push({
185
- path: `${path}.name`,
186
- message: "required; a task needs a non-empty name",
187
- })
188
- }
189
-
190
- if (task.id !== undefined) {
191
- if (!nonEmptyString(task.id)) {
192
- issues.push({ path: `${path}.id`, message: "must be a non-empty string" })
193
- } else if (ids.has(task.id)) {
194
- issues.push({
195
- path: `${path}.id`,
196
- message: `duplicate task id ${JSON.stringify(task.id)}`,
197
- })
198
- } else {
199
- ids.add(task.id)
200
- }
201
- }
202
-
203
- if (task.key !== undefined) {
204
- if (!nonEmptyString(task.key)) {
205
- issues.push({
206
- path: `${path}.key`,
207
- message: "must be a non-empty string",
208
- })
209
- } else if (keys.has(task.key)) {
210
- issues.push({
211
- path: `${path}.key`,
212
- message: `duplicate task key ${JSON.stringify(task.key)}`,
213
- })
214
- } else {
215
- keys.add(task.key)
216
- }
217
- }
218
-
219
- if (task.type !== undefined && !inEnum(task.type, TASK_TYPES)) {
220
- issues.push({
221
- path: `${path}.type`,
222
- message: `must be one of ${TASK_TYPES.join(", ")}; got ${JSON.stringify(task.type)}`,
223
- })
224
- }
225
-
226
- if (task.status !== undefined && !inEnum(task.status, TASK_STATUSES)) {
227
- issues.push({
228
- path: `${path}.status`,
229
- message: `must be one of ${TASK_STATUSES.join(", ")}; got ${JSON.stringify(task.status)}`,
230
- })
231
- }
232
-
233
- if (task.done !== undefined && typeof task.done !== "boolean") {
234
- issues.push({ path: `${path}.done`, message: "must be a boolean" })
235
- }
236
-
237
- if (task.priority !== undefined && task.priority !== null) {
238
- const priority = task.priority
239
- if (
240
- typeof priority !== "number" ||
241
- !Number.isInteger(priority) ||
242
- priority < 1 ||
243
- priority > 5
244
- ) {
245
- issues.push({
246
- path: `${path}.priority`,
247
- message: "must be an integer between 1 and 5",
248
- })
249
- }
250
- }
251
-
252
- if (
253
- task.deadline !== undefined &&
254
- task.deadline !== null &&
255
- (typeof task.deadline !== "string" || !DATE_PATTERN.test(task.deadline))
256
- ) {
257
- issues.push({
258
- path: `${path}.deadline`,
259
- message: "must be an ISO date (YYYY-MM-DD)",
260
- })
261
- }
262
-
263
- for (const section of ["acceptanceCriteria", "steps"]) {
264
- const items = task[section]
265
- if (items === undefined) continue
266
- if (!Array.isArray(items)) {
267
- issues.push({
268
- path: `${path}.${section}`,
269
- message: "must be an array of check items",
270
- })
271
- continue
272
- }
273
- items.forEach((item, index) => {
274
- validateCheckItem(item, `${path}.${section}[${index}]`, issues)
275
- })
276
- }
277
-
278
- if (task.links !== undefined) {
279
- if (!Array.isArray(task.links)) {
280
- issues.push({
281
- path: `${path}.links`,
282
- message: "must be an array of links",
283
- })
284
- } else {
285
- task.links.forEach((link, index) => {
286
- validateLink(link, `${path}.links[${index}]`, issues)
287
- })
288
- }
289
- }
290
-
291
- if (task.notes !== undefined) {
292
- if (!Array.isArray(task.notes)) {
293
- issues.push({
294
- path: `${path}.notes`,
295
- message: "must be an array of note references",
296
- })
297
- } else {
298
- task.notes.forEach((note, index) => {
299
- validateNoteRef(note, `${path}.notes[${index}]`, issues)
300
- })
301
- }
302
- }
303
- }
304
-
305
- const UNSAFE_NOTE_REFERENCE = /^(?:\/|\\\\|[a-z][a-z0-9+.-]*:|~)/i
306
-
307
- /**
308
- * One `notes` entry: an https URL, or a folder-relative note path with an
309
- * optional `#section` heading (for example "notes/spec.md#Plan").
310
- */
311
- function validateNoteRef(note: unknown, path: string, issues: TodoIssue[]) {
312
- if (!nonEmptyString(note)) {
313
- issues.push({ path, message: "must be a non-empty string" })
314
- return
315
- }
316
- if (/^https?:\/\//i.test(note)) {
317
- let url: URL
318
- try {
319
- url = new URL(note)
320
- } catch {
321
- issues.push({ path, message: "is not a valid absolute URL" })
322
- return
323
- }
324
- if (url.username || url.password) {
325
- issues.push({ path, message: "must not contain embedded credentials" })
326
- return
327
- }
328
- const isLocalhost =
329
- url.hostname === "localhost" ||
330
- url.hostname === "127.0.0.1" ||
331
- url.hostname === "::1"
332
- if (
333
- url.protocol !== "https:" &&
334
- !(url.protocol === "http:" && isLocalhost)
335
- ) {
336
- issues.push({
337
- path,
338
- message: "must use https, except localhost development links",
339
- })
340
- }
341
- return
342
- }
343
- if (UNSAFE_NOTE_REFERENCE.test(note) || note.split(/[\\/]/).includes("..")) {
344
- issues.push({
345
- path,
346
- message: "must be a folder-relative path (or an https URL)",
347
- })
348
- }
349
- }
350
-
351
- function validateCheckItem(item: unknown, path: string, issues: TodoIssue[]) {
352
- if (!isRecord(item)) {
353
- issues.push({
354
- path,
355
- message: "must be an object with id, text and done",
356
- })
357
- return
358
- }
359
- if (!nonEmptyString(item.id)) {
360
- issues.push({ path: `${path}.id`, message: "required non-empty string" })
361
- }
362
- if (!nonEmptyString(item.text)) {
363
- issues.push({ path: `${path}.text`, message: "required non-empty string" })
364
- }
365
- if (typeof item.done !== "boolean") {
366
- issues.push({ path: `${path}.done`, message: "required boolean" })
367
- }
368
- }
369
-
370
- function validateLink(link: unknown, path: string, issues: TodoIssue[]) {
371
- if (!isRecord(link)) {
372
- issues.push({ path, message: "must be a link object" })
373
- return
374
- }
375
- for (const field of ["id", "provider", "kind", "relation", "url"]) {
376
- if (!nonEmptyString(link[field])) {
377
- issues.push({
378
- path: `${path}.${field}`,
379
- message: "required non-empty string",
380
- })
381
- }
382
- }
383
- if (link.provider !== undefined && !inEnum(link.provider, LINK_PROVIDERS)) {
384
- issues.push({
385
- path: `${path}.provider`,
386
- message: `must be one of ${LINK_PROVIDERS.join(", ")}; got ${JSON.stringify(link.provider)}`,
387
- })
388
- }
389
- if (link.kind !== undefined && !inEnum(link.kind, LINK_KINDS)) {
390
- issues.push({
391
- path: `${path}.kind`,
392
- message: `must be one of ${LINK_KINDS.join(", ")}; got ${JSON.stringify(link.kind)}`,
393
- })
394
- }
395
- if (link.relation !== undefined && !inEnum(link.relation, LINK_RELATIONS)) {
396
- issues.push({
397
- path: `${path}.relation`,
398
- message: `must be one of ${LINK_RELATIONS.join(", ")}; got ${JSON.stringify(link.relation)}`,
399
- })
400
- }
401
-
402
- const urlValue = link.url
403
- if (typeof urlValue === "string") {
404
- let url: URL
405
- try {
406
- url = new URL(urlValue)
407
- } catch {
408
- issues.push({
409
- path: `${path}.url`,
410
- message: "is not a valid absolute URL",
411
- })
412
- return
413
- }
414
- if (url.username || url.password) {
415
- issues.push({
416
- path: `${path}.url`,
417
- message: "must not contain embedded credentials",
418
- })
419
- }
420
- const isLocalhost =
421
- url.hostname === "localhost" ||
422
- url.hostname === "127.0.0.1" ||
423
- url.hostname === "::1"
424
- if (
425
- url.protocol !== "https:" &&
426
- !(url.protocol === "http:" && isLocalhost)
427
- ) {
428
- issues.push({
429
- path: `${path}.url`,
430
- message: "must use https, except localhost development links",
431
- })
432
- }
433
- if (link.provider === "github" && url.hostname !== "github.com") {
434
- issues.push({
435
- path: `${path}.url`,
436
- message: "github links must use github.com",
437
- })
438
- }
439
- if (
440
- link.provider === "linear" &&
441
- url.hostname !== "linear.app" &&
442
- !url.hostname.endsWith(".linear.app")
443
- ) {
444
- issues.push({
445
- path: `${path}.url`,
446
- message: "linear links must use linear.app",
447
- })
448
- }
449
- if (
450
- link.provider === "jira" &&
451
- !url.hostname.endsWith(".atlassian.net") &&
452
- url.hostname !== "jira.atlassian.com"
453
- ) {
454
- issues.push({
455
- path: `${path}.url`,
456
- message: "jira links must use an Atlassian Jira host",
457
- })
458
- }
459
- }
460
- }
461
-
462
- function inEnum(value: unknown, allowed: readonly string[]) {
463
- return allowed.includes(String(value))
464
- }
465
-
466
- /**
467
- * Advisory checks that do not invalidate the file. Today there is one: a
468
- * task with no `notes` entries warns, because todos are meant to be
469
- * accompanied by notes — link a note file or an https reference. Paths use
470
- * the same `tasks[i]` convention as `validateTodoFile` issues, relative to
471
- * the file the task lives in.
472
- */
473
- export function todoFileWarnings(value: unknown): TodoIssue[] {
474
- if (!isRecord(value) || !Array.isArray(value.tasks)) return []
475
- return value.tasks.flatMap((task, index) =>
476
- isRecord(task) &&
477
- Array.isArray(task.notes) &&
478
- task.notes.some((note) => nonEmptyString(note))
479
- ? []
480
- : [
481
- {
482
- message:
483
- "no notes; link the accompanying note file or https reference",
484
- path: `tasks[${index}].notes`,
485
- severity: "warning" as const,
486
- },
487
- ],
488
- )
489
- }
490
-
491
- /**
492
- * Parse a `todo.json` source string into a validated document. Never throws:
493
- * invalid JSON and structural mistakes come back as issues with paths, so the
494
- * caller can render "what is wrong and where" directly.
495
- */
496
- export function parseTodoSource(source: string): ParsedTodo {
497
- return parseJsonSource<TodoFile>(source, validateTodoFile)
498
- }
499
-
500
- /**
501
- * Starter `todo.json` for `kennel init`: a valid v2 document with one sample
502
- * task showing the common fields. The folder name becomes the project title.
503
- */
504
- export function starterTodoSource(folder: string): string {
505
- const title = folder.trim().split(/[\\/]/).filter(Boolean).at(-1) ?? "Tasks"
506
- return `${JSON.stringify(
507
- {
508
- $schema: "https://raggle.co/schemas/tasks.json",
509
- version: 2,
510
- id: "todo",
511
- title,
512
- people: [],
513
- projects: [],
514
- cycles: [],
515
- milestones: [],
516
- components: [],
517
- areas: [],
518
- integrations: [],
519
- customFields: [],
520
- automations: [],
521
- tasks: [
522
- {
523
- id: "todo:0",
524
- key: "TODO-1",
525
- index: 0,
526
- rank: "0001",
527
- name: "First task",
528
- description: "Describe what needs to happen.",
529
- type: "task",
530
- status: "todo",
531
- done: false,
532
- priority: 3,
533
- deadline: null,
534
- assigneeIds: [],
535
- acceptanceCriteria: [
536
- { id: "ac-1", text: "Acceptance check", done: false },
537
- ],
538
- },
539
- ],
540
- },
541
- null,
542
- 2,
543
- )}\n`
544
- }
@@ -1,56 +0,0 @@
1
- import { folderPathId } from "@raggle-ai/folder-plugin/client"
2
-
3
- /**
4
- * Tasks from several `todo.json` sources merge into one workspace list, and
5
- * file-local ids such as `todo:1` repeat across sources. Task addresses
6
- * therefore qualify the task id with its owning folder:
7
- *
8
- * `<folderPathId(source folder)>@<task id|key>`
9
- *
10
- * `folderPathId` is the viewer's stable base64url folder id, so the address
11
- * stays one URL-safe path segment and survives the single-segment
12
- * `/folder/<id>/views/tasks/<subpath>` route. A bare `<taskId|key>` remains
13
- * valid as a legacy address and resolves to the first matching source (the
14
- * previous behavior), but every address the plugin builds is qualified.
15
- */
16
-
17
- const QUALIFIER = "@"
18
-
19
- /** Base64url output of `folderPathId`; a task id ref must look like one. */
20
- const REF_PATTERN = /^[A-Za-z0-9_-]+$/
21
-
22
- /**
23
- * Qualified task address for a task inside `sourceFolder`, or undefined when
24
- * the task has neither id nor key (or the source folder is unknown).
25
- */
26
- export function qualifiedTaskId(
27
- sourceFolder: unknown,
28
- task: { id?: unknown; key?: unknown },
29
- ): string | undefined {
30
- if (typeof sourceFolder !== "string" || !sourceFolder) return undefined
31
- const target =
32
- typeof task.id === "string" && task.id.trim()
33
- ? task.id.trim()
34
- : typeof task.key === "string" && task.key.trim()
35
- ? task.key.trim()
36
- : undefined
37
- if (!target) return undefined
38
- return `${folderPathId(sourceFolder)}${QUALIFIER}${target}`
39
- }
40
-
41
- /** Splits a qualified address; undefined for a plain task id/key string. */
42
- export function parseQualifiedTaskId(
43
- value: string,
44
- ): { id: string; ref: string } | undefined {
45
- const at = value.indexOf(QUALIFIER)
46
- if (at < 1) return undefined
47
- const ref = value.slice(0, at)
48
- const id = value.slice(at + 1)
49
- if (!id || !REF_PATTERN.test(ref)) return undefined
50
- return { id, ref }
51
- }
52
-
53
- /** True when `ref` is the view-stable id of `sourceFolder`. */
54
- export function refMatchesFolder(ref: string, sourceFolder: unknown): boolean {
55
- return typeof sourceFolder === "string" && folderPathId(sourceFolder) === ref
56
- }