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,7 +0,0 @@
1
- import type { FolderPluginManifest } from "@raggle-ai/folder-plugin"
2
-
3
- /** Stable Mail plugin identity and navigation label. No side effects. */
4
- export const mailManifest: FolderPluginManifest = {
5
- id: "mail",
6
- label: "Mail",
7
- }
@@ -1,171 +0,0 @@
1
- import { createHash } from "node:crypto"
2
- import { realpathSync } from "node:fs"
3
- import { readdir, readFile } from "node:fs/promises"
4
- import { homedir } from "node:os"
5
- import { isAbsolute, relative, resolve, sep } from "node:path"
6
-
7
- import type { Mail, MailListItem } from "./parse.ts"
8
- import { mailExcerpt, parseMailMarkdown } from "./parse.ts"
9
-
10
- export type ListMailOptions = {
11
- mailDir?: string
12
- folder: string
13
- }
14
-
15
- export function defaultMailDir() {
16
- return resolve(homedir(), ".email/drafts")
17
- }
18
-
19
- function draftFilePath(mailDir: string, id: string) {
20
- const trimmed = id.trim()
21
- if (
22
- !trimmed ||
23
- trimmed === "." ||
24
- trimmed === ".." ||
25
- /[\\/]/.test(trimmed)
26
- ) {
27
- throw new Error("Invalid mail id")
28
- }
29
- return resolve(mailDir, `${trimmed}.md`)
30
- }
31
-
32
- /**
33
- * Drafts currently being worked on. MailOS keeps sent and archived drafts in
34
- * the same folder, so the reader must exclude them here to show the same
35
- * current draft set without invoking the MailOS binary.
36
- */
37
- const activeStatuses = new Set(["working", "ready"])
38
-
39
- function isActiveStatus(status: string | null) {
40
- return status !== null && activeStatuses.has(status)
41
- }
42
-
43
- function canonicalDraftPath(path: string): string | null {
44
- try {
45
- return realpathSync(resolve(path))
46
- } catch {
47
- return null
48
- }
49
- }
50
-
51
- /**
52
- * True when `candidate` is `root` itself or a real descendant directory of
53
- * `root`. Both paths must exist on disk and are resolved through realpath, so
54
- * sibling-prefix paths, outside ancestors, traversal escapes, and symlink
55
- * escapes are rejected; an unresolved (missing) folder is denied rather than
56
- * guessed. Shared by list and detail authorization so draft membership is
57
- * consistent everywhere.
58
- */
59
- export function isFolderWithin(
60
- root: string,
61
- candidate: string | null | undefined,
62
- ): boolean {
63
- if (!candidate) return false
64
- const anchor = canonicalDraftPath(root)
65
- if (anchor === null) return false
66
- const target = canonicalDraftPath(candidate)
67
- if (target === null) return false
68
- if (anchor === target) return true
69
- const rel = relative(anchor, target)
70
- if (!rel) return true
71
- if (rel === ".." || rel.startsWith(`..${sep}`)) return false
72
- return !isAbsolute(rel)
73
- }
74
-
75
- function sortDateKey(value: string | null) {
76
- const parsed = value ? Date.parse(value) : Number.NaN
77
- if (Number.isNaN(parsed)) return 0
78
- return parsed
79
- }
80
-
81
- function sortMail(items: MailListItem[]) {
82
- items.sort((a, b) => {
83
- const aKey = sortDateKey(a.updatedAt ?? a.createdAt)
84
- const bKey = sortDateKey(b.updatedAt ?? b.createdAt)
85
- return bKey - aKey
86
- })
87
- return items
88
- }
89
-
90
- function draftRevision(content: string) {
91
- return createHash("sha256").update(content).digest("hex")
92
- }
93
-
94
- async function mailFromFile(
95
- filePath: string,
96
- ): Promise<(Mail & { filePath: string; revision: string }) | null> {
97
- const content = await readFile(filePath, "utf8").catch(() => null)
98
- if (!content) return null
99
- const parsed = parseMailMarkdown(content)
100
- if (!parsed.id) return null
101
- if (!isActiveStatus(parsed.status)) return null
102
-
103
- return {
104
- id: parsed.id,
105
- status: parsed.status,
106
- tags: parsed.tags,
107
- folder: parsed.folder,
108
- attachments: parsed.attachments,
109
- from: parsed.from,
110
- inReplyTo: parsed.inReplyTo,
111
- references: parsed.references,
112
- to: parsed.to,
113
- cc: parsed.cc,
114
- bcc: parsed.bcc,
115
- subject: parsed.subject,
116
- createdAt: parsed.createdAt,
117
- updatedAt: parsed.updatedAt,
118
- noSignature: parsed.noSignature,
119
- body: parsed.body,
120
- filePath,
121
- revision: draftRevision(content),
122
- }
123
- }
124
-
125
- export async function listMailForFolder({
126
- mailDir = defaultMailDir(),
127
- folder,
128
- }: ListMailOptions): Promise<MailListItem[]> {
129
- const entries = await readdir(mailDir, { withFileTypes: true })
130
- const items: MailListItem[] = []
131
-
132
- for (const entry of entries) {
133
- if (!entry.isFile()) continue
134
- if (!entry.name.endsWith(".md")) continue
135
-
136
- const filePath = resolve(mailDir, entry.name)
137
- const mail = await mailFromFile(filePath)
138
- if (!mail) continue
139
- if (!isFolderWithin(folder, mail.folder)) continue
140
-
141
- items.push({
142
- id: mail.id,
143
- status: mail.status,
144
- tags: mail.tags,
145
- folder: mail.folder,
146
- attachments: mail.attachments,
147
- from: mail.from,
148
- inReplyTo: mail.inReplyTo,
149
- references: mail.references,
150
- to: mail.to,
151
- cc: mail.cc,
152
- bcc: mail.bcc,
153
- subject: mail.subject,
154
- createdAt: mail.createdAt,
155
- updatedAt: mail.updatedAt,
156
- noSignature: mail.noSignature,
157
- excerpt: mailExcerpt(mail.body),
158
- filePath,
159
- revision: mail.revision,
160
- })
161
- }
162
-
163
- return sortMail(items)
164
- }
165
-
166
- export async function readMailById(
167
- id: string,
168
- mailDir = defaultMailDir(),
169
- ): Promise<(Mail & { filePath: string; revision: string }) | null> {
170
- return mailFromFile(draftFilePath(mailDir, id))
171
- }
@@ -1,139 +0,0 @@
1
- import { parse as parseYaml } from "yaml"
2
-
3
- export type MailStatus = "working" | "ready" | "sent" | "canceled" | string
4
-
5
- export type Mail = {
6
- id: string
7
- status: MailStatus | null
8
- tags: string[]
9
- folder: string | null
10
- attachments: string[]
11
- from: string | null
12
- inReplyTo: string | null
13
- references: string[]
14
- to: string[]
15
- cc: string[]
16
- bcc: string[]
17
- subject: string | null
18
- createdAt: string | null
19
- updatedAt: string | null
20
- /** Draft frontmatter `no_signature: true`: suppresses any signature on send. */
21
- noSignature: boolean
22
- body: string
23
- }
24
-
25
- export type MailListItem = Omit<Mail, "body"> & {
26
- excerpt: string
27
- filePath: string
28
- /**
29
- * sha256 of the exact draft file bytes. MailOS treats this hash as the
30
- * draft revision, so guarded destructive actions can prove the file has not
31
- * changed since the client last loaded it.
32
- */
33
- revision: string
34
- }
35
-
36
- function stringOrNull(value: unknown) {
37
- return typeof value === "string" && value.trim() ? value : null
38
- }
39
-
40
- function boolValue(value: unknown) {
41
- return value === true || value === "true"
42
- }
43
-
44
- function stringList(value: unknown): string[] {
45
- if (!value) return []
46
- if (Array.isArray(value))
47
- return value
48
- .filter((item): item is string => typeof item === "string")
49
- .map((item) => item.trim())
50
- .filter(Boolean)
51
- if (typeof value === "string") return value.trim() ? [value.trim()] : []
52
- return []
53
- }
54
-
55
- export function parseMailMarkdown(content: string): Omit<Mail, "id"> & {
56
- id: string | null
57
- } {
58
- if (!content.startsWith("---\n")) {
59
- return {
60
- id: null,
61
- status: null,
62
- tags: [],
63
- folder: null,
64
- attachments: [],
65
- from: null,
66
- inReplyTo: null,
67
- references: [],
68
- to: [],
69
- cc: [],
70
- bcc: [],
71
- subject: null,
72
- createdAt: null,
73
- updatedAt: null,
74
- noSignature: false,
75
- body: content,
76
- }
77
- }
78
-
79
- const end = content.indexOf("\n---\n")
80
- if (end < 0) {
81
- return {
82
- id: null,
83
- status: null,
84
- tags: [],
85
- folder: null,
86
- attachments: [],
87
- from: null,
88
- inReplyTo: null,
89
- references: [],
90
- to: [],
91
- cc: [],
92
- bcc: [],
93
- subject: null,
94
- createdAt: null,
95
- updatedAt: null,
96
- noSignature: false,
97
- body: content,
98
- }
99
- }
100
-
101
- const frontmatterRaw = content.slice(4, end)
102
- const body = content.slice(end + "\n---\n".length).replace(/^\n+/, "")
103
-
104
- const frontmatterValue = parseYaml(frontmatterRaw) as unknown
105
- const frontmatter =
106
- frontmatterValue &&
107
- typeof frontmatterValue === "object" &&
108
- !Array.isArray(frontmatterValue)
109
- ? (frontmatterValue as Record<string, unknown>)
110
- : {}
111
-
112
- return {
113
- id: stringOrNull(frontmatter.id),
114
- status: stringOrNull(frontmatter.status),
115
- tags: stringList(frontmatter.tags),
116
- folder: stringOrNull(frontmatter.folder),
117
- attachments: stringList(frontmatter.file),
118
- from: stringOrNull(frontmatter.from),
119
- inReplyTo: stringOrNull(frontmatter.in_reply_to),
120
- references: stringList(frontmatter.references),
121
- to: stringList(frontmatter.to),
122
- cc: stringList(frontmatter.cc),
123
- bcc: stringList(frontmatter.bcc),
124
- subject: stringOrNull(frontmatter.subject),
125
- createdAt: stringOrNull(frontmatter.created_at),
126
- updatedAt: stringOrNull(frontmatter.updated_at),
127
- noSignature: boolValue(frontmatter.no_signature),
128
- body,
129
- }
130
- }
131
-
132
- export function mailExcerpt(body: string, maxChars = 280) {
133
- const normalized = body
134
- .trim()
135
- .replace(/\r\n/g, "\n")
136
- .replace(/\n{3,}/g, "\n\n")
137
- if (normalized.length <= maxChars) return normalized
138
- return `${normalized.slice(0, maxChars).trimEnd()}…`
139
- }
@@ -1,125 +0,0 @@
1
- import type {
2
- FolderPluginContext,
3
- FolderPluginData,
4
- FolderPluginDetection,
5
- } from "@raggle-ai/folder-plugin/server"
6
- import { FolderPluginFailure } from "@raggle-ai/folder-plugin/server"
7
-
8
- import type { Mail, MailListItem } from "./parse.ts"
9
- import type { MailPreview } from "./types.ts"
10
- import { createMailosService } from "./mailos.ts"
11
- import { mailManifest } from "./manifest.ts"
12
- import {
13
- defaultMailDir,
14
- isFolderWithin,
15
- listMailForFolder,
16
- readMailById,
17
- } from "./node.ts"
18
-
19
- export type MailCreatePluginOptions = {
20
- /**
21
- * Override MailOS mail directory. Intended for tests.
22
- * Defaults to ~/.email/drafts.
23
- */
24
- mailDir?: string
25
- /** Preview execution hook. Fallback reads the draft body without a composer. */
26
- previewer?: (options: {
27
- folder: string
28
- id: string
29
- mail: NonNullable<Awaited<ReturnType<typeof readMailById>>>
30
- }) => Promise<MailPreview>
31
- }
32
-
33
- type DetailMail = Mail & { filePath: string; revision: string }
34
-
35
- function detailData(mail: DetailMail, preview: MailPreview): FolderPluginData {
36
- return {
37
- kind: "available",
38
- data: {
39
- mail: {
40
- ...mail,
41
- bcc: mail.bcc,
42
- body: mail.body,
43
- cc: mail.cc,
44
- createdAt: mail.createdAt,
45
- filePath: mail.filePath,
46
- folder: mail.folder,
47
- id: mail.id,
48
- status: mail.status,
49
- subject: mail.subject,
50
- tags: mail.tags,
51
- to: mail.to,
52
- updatedAt: mail.updatedAt,
53
- noSignature: mail.noSignature,
54
- },
55
- preview,
56
- },
57
- }
58
- }
59
-
60
- export function createMailPlugin({
61
- mailDir = defaultMailDir(),
62
- previewer,
63
- }: MailCreatePluginOptions = {}) {
64
- const mailos = createMailosService()
65
- const compose =
66
- previewer ??
67
- (async ({ mail }) => ({
68
- body: mail.body,
69
- // A no_signature draft sends without any signature; do not show one.
70
- signature: mail.noSignature
71
- ? null
72
- : mail.folder
73
- ? await mailos.signature(mail.folder)
74
- : null,
75
- }))
76
-
77
- return {
78
- ...mailManifest,
79
- async detect(context: FolderPluginContext): Promise<FolderPluginDetection> {
80
- const items = await listMailForFolder({ folder: context.folder, mailDir })
81
- if (!items.length) return { status: "unavailable" }
82
- return { count: items.length, status: "available" }
83
- },
84
- async handle(
85
- context: FolderPluginContext,
86
- subpath: string,
87
- ): Promise<FolderPluginData> {
88
- const folder = context.folder
89
-
90
- if (subpath === "") {
91
- const items = await listMailForFolder({ folder, mailDir })
92
- if (!items.length) {
93
- return {
94
- kind: "available",
95
- data: { folder, items: [], status: "unavailable" },
96
- }
97
- }
98
- return {
99
- kind: "available",
100
- data: { folder, items, status: "available" },
101
- }
102
- }
103
-
104
- const id = subpath.trim()
105
- const mail = await readMailById(id, mailDir)
106
- if (!mail) throw new Error("Mail not found")
107
- if (!mail.folder) throw new Error("Mail has no folder")
108
- if (!isFolderWithin(folder, mail.folder))
109
- throw new Error("Mail not found for this folder")
110
-
111
- let preview: MailPreview
112
- try {
113
- preview = await compose({ folder, id: mail.id, mail })
114
- } catch (error) {
115
- const message =
116
- error instanceof Error ? error.message : "Unknown preview error"
117
- throw new FolderPluginFailure(`Mail preview failed: ${message}`)
118
- }
119
-
120
- return detailData(mail, preview)
121
- },
122
- }
123
- }
124
-
125
- export type { MailListItem }
@@ -1,10 +0,0 @@
1
- export type MailPreview = {
2
- /**
3
- * Plain body of the draft read directly from its Markdown file.
4
- */
5
- body: string
6
- /**
7
- * Appended signature text. Null when no signature is present.
8
- */
9
- signature: string | null
10
- }
@@ -1,147 +0,0 @@
1
- import type { ReactNode } from "react"
2
-
3
- import { FolderFilterBar } from "@raggle-ai/ui/components/folder-filter-bar"
4
-
5
- import type { MailFolderChoice } from "./folders.ts"
6
- import type { MailPreview } from "./types.ts"
7
- import { MailCard } from "./mail-card.tsx"
8
-
9
- export type MailListItem = {
10
- attachments: string[]
11
- bcc: string[]
12
- cc: string[]
13
- createdAt: string | null
14
- excerpt: string
15
- filePath: string
16
- folder: string | null
17
- from: string | null
18
- id: string
19
- inReplyTo: string | null
20
- references: string[]
21
- revision: string
22
- status: string | null
23
- subject: string | null
24
- tags: string[]
25
- to: string[]
26
- updatedAt: string | null
27
- noSignature: boolean
28
- }
29
-
30
- export type MailDetail = Omit<MailListItem, "excerpt"> & { body: string }
31
-
32
- export type { MailPreview } from "./types.ts"
33
-
34
- export type MailListAction = "archive" | "delete"
35
-
36
- export type MailContextInput = {
37
- attachments?: ReadonlyArray<string>
38
- bcc?: ReadonlyArray<string>
39
- cc?: ReadonlyArray<string>
40
- excerpt?: string
41
- filePath: string
42
- folder?: string | null
43
- from?: string | null
44
- status?: string | null
45
- subject?: string | null
46
- tags?: ReadonlyArray<string>
47
- to?: ReadonlyArray<string>
48
- }
49
-
50
- /**
51
- * Agent-friendly text context for one mail item, in the same shape the tasks
52
- * plugin copies (`todoItemContext`). Callers pass the item they have — a list
53
- * item (excerpt only) or a detail (full body via the second argument).
54
- */
55
- export const mailItemContext = (item: MailContextInput, body?: string) =>
56
- [
57
- "You are helping with an email draft. Use the context below to understand the message and what it needs next.",
58
- "",
59
- "Instructions for the LLM:",
60
- "- Treat the subject as the draft's objective.",
61
- "- Use recipients, tags and body (or the owning draft file) as the authoritative message context.",
62
- "- If information is missing, state the exact missing input or recipient needed.",
63
- "- Return: 1) current status, 2) what the message needs next, 3) suggested edits or reply if asked.",
64
- "",
65
- "Mail context:",
66
- `- Subject: ${item.subject ?? "(no subject)"}`,
67
- item.from ? `- From: ${item.from}` : null,
68
- item.to?.length ? `- To: ${item.to.join(", ")}` : null,
69
- item.cc?.length ? `- Cc: ${item.cc.join(", ")}` : null,
70
- item.bcc?.length ? `- Bcc: ${item.bcc.join(", ")}` : null,
71
- item.attachments?.length
72
- ? `- Attachments: ${item.attachments.join(", ")}`
73
- : null,
74
- `- Status: ${item.status ?? "unknown"}`,
75
- item.folder ? `- Folder: ${item.folder}` : null,
76
- item.tags?.length
77
- ? `- Tags: ${item.tags.map((tag) => `#${tag}`).join(" ")}`
78
- : null,
79
- `- Draft file: ${item.filePath}`,
80
- body ? "" : null,
81
- body ? "Draft body:" : null,
82
- body ?? null,
83
- !body && item.excerpt ? "" : null,
84
- !body && item.excerpt ? "Draft excerpt:" : null,
85
- !body && item.excerpt ? item.excerpt : null,
86
- ]
87
- .filter((line): line is string => line != null)
88
- .join("\n")
89
-
90
- export type MailDetailResponse = {
91
- mail: MailDetail
92
- preview?: MailPreview
93
- }
94
-
95
- export function MailFolderFilter({
96
- choices,
97
- onSelect,
98
- selected,
99
- total,
100
- }: {
101
- choices: MailFolderChoice[]
102
- onSelect: (folders: readonly string[]) => void
103
- selected: readonly string[]
104
- total: number
105
- }) {
106
- return (
107
- <FolderFilterBar
108
- allLabel="All folders"
109
- ariaLabel="Filter drafts by folder"
110
- choices={choices}
111
- onSelect={onSelect}
112
- selected={selected}
113
- total={total}
114
- />
115
- )
116
- }
117
-
118
- export function MailList({
119
- actions,
120
- folderLabel,
121
- mailHref,
122
- items,
123
- }: {
124
- /**
125
- * Optional per-draft action menu rendered in the card corner. The mail
126
- * package stays UI-framework agnostic: the web layer passes its own menu
127
- * (e.g. a shadcn dropdown) through this render slot.
128
- */
129
- actions?: (item: MailListItem) => ReactNode
130
- folderLabel?: (folder: string | null) => string | null
131
- mailHref: (id: string) => string
132
- items: MailListItem[]
133
- }) {
134
- return (
135
- <ol className="m-0 grid list-none grid-cols-1 gap-2 p-0">
136
- {items.map((item) => (
137
- <MailCard
138
- actions={actions}
139
- folderLabel={folderLabel?.(item.folder)}
140
- href={mailHref(item.id)}
141
- item={item}
142
- key={item.id}
143
- />
144
- ))}
145
- </ol>
146
- )
147
- }