kennel 0.2.20 → 0.2.22

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 (220) hide show
  1. package/README.md +39 -8
  2. package/dist/cli/dispatch.js +7 -5
  3. package/dist/cli/usage.js +6 -2
  4. package/dist/core/command.js +10 -5
  5. package/dist/package/preview.js +138 -67
  6. package/dist/plugins/external.d.ts +1 -0
  7. package/dist/plugins/external.js +22 -2
  8. package/dist/site/hot-viewer.d.ts +3 -1
  9. package/dist/site/hot-viewer.js +43 -33
  10. package/dist/site/plugin.d.ts +2 -0
  11. package/dist/site/plugin.js +32 -0
  12. package/dist/site/terminal.d.ts +1 -0
  13. package/dist/site/terminal.js +77 -0
  14. package/dist/site/viewer.d.ts +6 -6
  15. package/dist/site/viewer.js +39 -32
  16. package/package.json +2 -2
  17. package/schemas/config.schema.json +9 -0
  18. package/web/assets/abnfDiagram-VRR7QNED-aRemVX7f.js +1 -0
  19. package/web/assets/arc-BpDsnNTf.js +1 -0
  20. package/web/assets/architectureDiagram-ZJ3FMSHR-DNXHQddP.js +36 -0
  21. package/web/assets/ask-tray-PMT6VVXN-HMPARq3A.js +23 -0
  22. package/web/assets/{blockDiagram-677ZJIJ3-B404lYhT.js → blockDiagram-677ZJIJ3-CF4H4upo.js} +2 -2
  23. package/web/assets/{c4Diagram-LMCZKHZV-m6CP9WKP.js → c4Diagram-LMCZKHZV-BPWUnjtx.js} +2 -2
  24. package/web/assets/channel-CEZ4sDYU.js +1 -0
  25. package/web/assets/{chunk-2Q5K7J3B-lofRULSz.js → chunk-2Q5K7J3B-DGsa7uv7.js} +1 -1
  26. package/web/assets/{chunk-32BRIVSS-BtdUGMBQ.js → chunk-32BRIVSS-BRfic3W2.js} +1 -1
  27. package/web/assets/{chunk-5VM5RSS4-BBjGl_Dr.js → chunk-5VM5RSS4-L2h7hliu.js} +1 -1
  28. package/web/assets/{chunk-EX3LRPZG-DM3Qu278.js → chunk-EX3LRPZG-BPgD_fgx.js} +3 -3
  29. package/web/assets/{chunk-JWPE2WC7-Bp1ws-G7.js → chunk-JWPE2WC7-CckCaqu_.js} +1 -1
  30. package/web/assets/{chunk-MOJQB5TN-C7smXTrN.js → chunk-MOJQB5TN-zyGgx-VW.js} +1 -1
  31. package/web/assets/{chunk-RYQCIY6F-DODJCmXB.js → chunk-RYQCIY6F-Drzpg5IG.js} +1 -1
  32. package/web/assets/{chunk-V7JOEXUC-C7fI1RPs.js → chunk-V7JOEXUC-Di4ESKz-.js} +1 -1
  33. package/web/assets/{chunk-VR4S4FIN-BkMRGbPv.js → chunk-VR4S4FIN-C5lQtDI1.js} +1 -1
  34. package/web/assets/{chunk-XXDRQBXY-DGKhiMOo.js → chunk-XXDRQBXY-Cell0ft2.js} +1 -1
  35. package/web/assets/classDiagram-OUVF2IWQ-CjxqMQn2.js +1 -0
  36. package/web/assets/classDiagram-v2-EOCWNBFH-CjxqMQn2.js +1 -0
  37. package/web/assets/cose-bilkent-JH36ORCC-CiKtOFxl.js +1 -0
  38. package/web/assets/{cynefin-VYW2F7L2-Co86WDlY.js → cynefin-VYW2F7L2-B75MWf5b.js} +1 -1
  39. package/web/assets/cynefinDiagram-TSTJHNR4-BmNVkSWW.js +62 -0
  40. package/web/assets/{dagre-VKFMJZFB-2FzdH1tO.js → dagre-VKFMJZFB-BcM1Wqu5.js} +2 -2
  41. package/web/assets/{diagram-FQU43EPY-D8oGdGs0.js → diagram-FQU43EPY-BiBWrxa8.js} +2 -2
  42. package/web/assets/diagram-G47NLZAW-Cfxukr7T.js +24 -0
  43. package/web/assets/diagram-NH7WQ7WH-C83VkBYW.js +24 -0
  44. package/web/assets/{diagram-OA4YK3LP-Dapxn_y5.js → diagram-OA4YK3LP-Oj0uj6CX.js} +5 -5
  45. package/web/assets/diagram-WEI45ONY-DhbL0nvt.js +41 -0
  46. package/web/assets/ebnfDiagram-CCIWWBDH-D4JYp1UC.js +1 -0
  47. package/web/assets/{entities-Ba9UFGWQ.js → entity-search-page-G6QEQNXT-UKzUU5id.js} +10 -10
  48. package/web/assets/{erDiagram-Q63AITRT-BeWglGbe.js → erDiagram-Q63AITRT-C-oyRt9s.js} +2 -2
  49. package/web/assets/{flowDiagram-23GEKE2U-DQSrCvnP.js → flowDiagram-23GEKE2U-0Tplj9FK.js} +1 -1
  50. package/web/assets/ganttDiagram-NO4QXBWP-wgh2e0B_.js +292 -0
  51. package/web/assets/gitGraphDiagram-IHSO6WYX-D6z9qDXa.js +106 -0
  52. package/web/assets/index-BGwTWQMJ.css +1 -0
  53. package/web/assets/index-D_Fcgs3V.js +451 -0
  54. package/web/assets/infoDiagram-FWYZ7A6U-D3o7el5X.js +2 -0
  55. package/web/assets/{ishikawaDiagram-FXEZZL3T-zdZcsCSy.js → ishikawaDiagram-FXEZZL3T-CM0QyWYH.js} +6 -6
  56. package/web/assets/{journeyDiagram-5HDEW3XC-Cyviy-mf.js → journeyDiagram-5HDEW3XC-fmIoh0h6.js} +2 -2
  57. package/web/assets/{kanban-definition-HUTT4EX6-BEOdHBFJ.js → kanban-definition-HUTT4EX6-aEtqsiWf.js} +6 -6
  58. package/web/assets/{linear-B0Elyctv.js → linear-aJ-2UZO5.js} +1 -1
  59. package/web/assets/linked-session-header-M7WY6IGF-CltMJZiX.js +3 -0
  60. package/web/assets/{markdown-BvBsne3X.js → markdown-BP-54rPU.js} +2 -2
  61. package/web/assets/{mermaid.core-BEwF5fZo.js → mermaid.core-CL9g6xVu.js} +6 -6
  62. package/web/assets/{mindmap-definition-LN4V7U3C-DW5Nc3Z2.js → mindmap-definition-LN4V7U3C-CtQo0XrW.js} +2 -2
  63. package/web/assets/pegDiagram-2B236MQR-ecu1L_3A.js +1 -0
  64. package/web/assets/{pieDiagram-ENE6RG2P-DxF16ujD.js → pieDiagram-ENE6RG2P-CdCKg3Cn.js} +2 -2
  65. package/web/assets/plugin-host-modules-Dz_BPJRS.js +74 -0
  66. package/web/assets/{project-search-dialog-Bm4cKotY.js → project-search-dialog-HJFGW4DG-CKtXc-UP.js} +5 -5
  67. package/web/assets/project-search-page-NKQEBGPF-CMzuYEeM.js +2 -0
  68. package/web/assets/{quadrantDiagram-ABIIQ3AL-D6lKmduJ.js → quadrantDiagram-ABIIQ3AL-Bt8r5TlW.js} +2 -2
  69. package/web/assets/railroadDiagram-RFXS5EU6-DrWDVEVi.js +1 -0
  70. package/web/assets/react-DELVxLrX.js +9 -0
  71. package/web/assets/{requirementDiagram-TGXJPOKE-DCWUvc_i.js → requirementDiagram-TGXJPOKE-Ewjwpo6V.js} +2 -2
  72. package/web/assets/{sankeyDiagram-HTMAVEWB-CQ4kDW3E.js → sankeyDiagram-HTMAVEWB-CJCMHuzX.js} +2 -2
  73. package/web/assets/selection-popup-532EHNCZ-py5aCy1E.js +7 -0
  74. package/web/assets/{sequenceDiagram-DBY2YBRQ-C-ygrC5m.js → sequenceDiagram-DBY2YBRQ-Chj-4L6Q.js} +2 -2
  75. package/web/assets/sizeCapture-X5ZJPWSS-BguWhDIF.js +1 -0
  76. package/web/assets/stateDiagram-2N3HPSRC-BWisWMpK.js +1 -0
  77. package/web/assets/stateDiagram-v2-6OUMAXLB-AiBXToz-.js +1 -0
  78. package/web/assets/swimlanes-5IMT3BWC-CxVQ97_C.js +2 -0
  79. package/web/assets/swimlanesDiagram-G3AALYLV-DliPmGmf.js +8 -0
  80. package/web/assets/tanstack-CRaSxWtK.js +1 -0
  81. package/web/assets/{timeline-definition-FHXFAJF6-D3kXwv5v.js → timeline-definition-FHXFAJF6-CCbI0InF.js} +2 -2
  82. package/web/assets/{vennDiagram-L72KCM5P-DZhfR6LC.js → vennDiagram-L72KCM5P-mA5yKpJj.js} +4 -4
  83. package/web/assets/{wardleyDiagram-EHGQE667-CzwAW4nO.js → wardleyDiagram-EHGQE667-1Epw2EsU.js} +2 -2
  84. package/web/assets/{xychartDiagram-FW5EYKEG-CebaePFD.js → xychartDiagram-FW5EYKEG-DM1CMD-p.js} +2 -2
  85. package/web/index.html +5 -4
  86. package/web/kennel-theme.css +4 -2
  87. package/dist/site/mail.d.ts +0 -1
  88. package/dist/site/mail.js +0 -10
  89. package/web/assets/abnfDiagram-VRR7QNED-1RdiIYIR.js +0 -1
  90. package/web/assets/app-CEQAoxzL.js +0 -2
  91. package/web/assets/app-options-CIiczgaQ.js +0 -25
  92. package/web/assets/app-view-header-CNImosi9.js +0 -1
  93. package/web/assets/arc-DCuRiob1.js +0 -1
  94. package/web/assets/architectureDiagram-ZJ3FMSHR-CAcGR7BC.js +0 -36
  95. package/web/assets/ask-tray-DpWLca3e.js +0 -14
  96. package/web/assets/channel-CGNx58wi.js +0 -1
  97. package/web/assets/check-DjJ4znpk.js +0 -1
  98. package/web/assets/chevron-down-CiyxliRS.js +0 -1
  99. package/web/assets/chevron-right-BaJja2sG.js +0 -1
  100. package/web/assets/chevron-up-Xv7ii00h.js +0 -1
  101. package/web/assets/classDiagram-OUVF2IWQ-CepcbkQI.js +0 -1
  102. package/web/assets/classDiagram-v2-EOCWNBFH-CepcbkQI.js +0 -1
  103. package/web/assets/client-Bs3Sdel1.js +0 -6
  104. package/web/assets/client-Bz9gxOoP.js +0 -43
  105. package/web/assets/command-B-4JoDzT.js +0 -38
  106. package/web/assets/copy-DKl_cZLH.js +0 -1
  107. package/web/assets/copy-context-Bj8Sfpo7.js +0 -1
  108. package/web/assets/cose-bilkent-JH36ORCC-rQPbqPgO.js +0 -1
  109. package/web/assets/cynefinDiagram-TSTJHNR4-C9V3Tu3i.js +0 -62
  110. package/web/assets/diagram-G47NLZAW-Bav2L_9E.js +0 -24
  111. package/web/assets/diagram-NH7WQ7WH-CxOSrenv.js +0 -24
  112. package/web/assets/diagram-WEI45ONY-CGAvJVWu.js +0 -41
  113. package/web/assets/document-C4ERzZZ-.js +0 -23
  114. package/web/assets/ebnfDiagram-CCIWWBDH-CmJpnBTF.js +0 -1
  115. package/web/assets/ellipsis-DIDqkP8k.js +0 -1
  116. package/web/assets/file-text-C3hyr-Ql.js +0 -1
  117. package/web/assets/file-viewer-CYCdL53W.js +0 -1
  118. package/web/assets/folder-activity-Cv1X2ezj.js +0 -1
  119. package/web/assets/folder-filter-bar-Bl30Jv6B.js +0 -4
  120. package/web/assets/folder-image-Cy-8Vgmd.js +0 -1
  121. package/web/assets/folder-landing-BiswmWY0.js +0 -55
  122. package/web/assets/folder-list-BPufqaem.js +0 -1
  123. package/web/assets/folder-mobile-bar-Dxsu-jUM.js +0 -1
  124. package/web/assets/folder-open-CqSoJtKT.js +0 -1
  125. package/web/assets/folder-plugin-view-DiZbM5qv.js +0 -2
  126. package/web/assets/ganttDiagram-NO4QXBWP-BHGXM83R.js +0 -292
  127. package/web/assets/gitGraphDiagram-IHSO6WYX-DHoetr2P.js +0 -106
  128. package/web/assets/hooks-wZOJYSkv.js +0 -1
  129. package/web/assets/index-4-yQR2Lz.js +0 -41
  130. package/web/assets/index-4JQ747xt.js +0 -1
  131. package/web/assets/index-B6ap1Jz7.js +0 -1
  132. package/web/assets/index-BSHr1oc9.js +0 -1
  133. package/web/assets/index-CHgBEfsO.js +0 -1
  134. package/web/assets/index-CKJsEQtp.js +0 -64
  135. package/web/assets/index-DbD-bwdm.js +0 -2
  136. package/web/assets/index-uo3lipQl.js +0 -1
  137. package/web/assets/index-wmrfz8OS.css +0 -1
  138. package/web/assets/infoDiagram-FWYZ7A6U-09XQL5OF.js +0 -2
  139. package/web/assets/input-fNFbKa15.js +0 -9
  140. package/web/assets/linked-session-header-D4SUBW0L.js +0 -3
  141. package/web/assets/metadata-Dy1R-He2.js +0 -58
  142. package/web/assets/pegDiagram-2B236MQR-Cj3gTzwg.js +0 -1
  143. package/web/assets/plugin-host-modules-C_FG5LYc.js +0 -10
  144. package/web/assets/plus-TM7voyHO.js +0 -1
  145. package/web/assets/popover-DvKy7gF6.js +0 -9
  146. package/web/assets/railroadDiagram-RFXS5EU6-CNMzdL0J.js +0 -1
  147. package/web/assets/react-Dh7j6h1K.js +0 -9
  148. package/web/assets/search-Cv1HqxUc.js +0 -2
  149. package/web/assets/search-Cx23EFPc.js +0 -1
  150. package/web/assets/search-DG1auulp.css +0 -1
  151. package/web/assets/selection-popup-DPC2dc_s.js +0 -7
  152. package/web/assets/sizeCapture-X5ZJPWSS-CWCSfdrg.js +0 -1
  153. package/web/assets/stateDiagram-2N3HPSRC-BUJ8nxcE.js +0 -1
  154. package/web/assets/stateDiagram-v2-6OUMAXLB-DgubHPLq.js +0 -1
  155. package/web/assets/swimlanes-5IMT3BWC-rw0Loza_.js +0 -2
  156. package/web/assets/swimlanesDiagram-G3AALYLV-CxNu_14L.js +0 -8
  157. package/web/assets/tanstack-CirxkzEx.js +0 -1
  158. package/web/assets/utils-CvINCDjn.js +0 -1
  159. package/web/assets/view-context-DyuiMZAo.js +0 -101
  160. package/web/assets/viewer-capabilities-BkBR084B.js +0 -1
  161. package/web/assets/x-GGS-h4Nm.js +0 -1
  162. /package/web/assets/{KaTeX_AMS-Regular-DMm9YOAa.woff → KaTeX_AMS-Regular-CYEKBG2K-DMm9YOAa.woff} +0 -0
  163. /package/web/assets/{KaTeX_AMS-Regular-DRggAlZN.ttf → KaTeX_AMS-Regular-JKX5W2C4-DRggAlZN.ttf} +0 -0
  164. /package/web/assets/{KaTeX_AMS-Regular-BQhdFMY1.woff2 → KaTeX_AMS-Regular-U6PRYMIZ-BQhdFMY1.woff2} +0 -0
  165. /package/web/assets/{KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 → KaTeX_Caligraphic-Bold-5QL5CMTE-Dq_IR9rO.woff2} +0 -0
  166. /package/web/assets/{KaTeX_Caligraphic-Bold-BEiXGLvX.woff → KaTeX_Caligraphic-Bold-WZ3QSGD3-BEiXGLvX.woff} +0 -0
  167. /package/web/assets/{KaTeX_Caligraphic-Bold-ATXxdsX0.ttf → KaTeX_Caligraphic-Bold-ZTS3R3HK-ATXxdsX0.ttf} +0 -0
  168. /package/web/assets/{KaTeX_Caligraphic-Regular-CTRA-rTL.woff → KaTeX_Caligraphic-Regular-3LKEU76G-CTRA-rTL.woff} +0 -0
  169. /package/web/assets/{KaTeX_Caligraphic-Regular-wX97UBjC.ttf → KaTeX_Caligraphic-Regular-A7XRTZ5Q-wX97UBjC.ttf} +0 -0
  170. /package/web/assets/{KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 → KaTeX_Caligraphic-Regular-KX5MEWCF-Di6jR-x-.woff2} +0 -0
  171. /package/web/assets/{KaTeX_Fraktur-Bold-CL6g_b3V.woff2 → KaTeX_Fraktur-Bold-2QVFK6NQ-CL6g_b3V.woff2} +0 -0
  172. /package/web/assets/{KaTeX_Fraktur-Bold-BsDP51OF.woff → KaTeX_Fraktur-Bold-T4SWXBMT-BsDP51OF.woff} +0 -0
  173. /package/web/assets/{KaTeX_Fraktur-Bold-BdnERNNW.ttf → KaTeX_Fraktur-Bold-WGHVTYOR-BdnERNNW.ttf} +0 -0
  174. /package/web/assets/{KaTeX_Fraktur-Regular-CTYiF6lA.woff2 → KaTeX_Fraktur-Regular-2PEIFJSJ-CTYiF6lA.woff2} +0 -0
  175. /package/web/assets/{KaTeX_Fraktur-Regular-CB_wures.ttf → KaTeX_Fraktur-Regular-5U4OPH2X-CB_wures.ttf} +0 -0
  176. /package/web/assets/{KaTeX_Fraktur-Regular-Dxdc4cR9.woff → KaTeX_Fraktur-Regular-PQMHCIK6-Dxdc4cR9.woff} +0 -0
  177. /package/web/assets/{KaTeX_Main-Bold-Jm3AIy58.woff → KaTeX_Main-Bold-2GA4IZIN-Jm3AIy58.woff} +0 -0
  178. /package/web/assets/{KaTeX_Main-Bold-waoOVXN0.ttf → KaTeX_Main-Bold-W5FBVCZM-waoOVXN0.ttf} +0 -0
  179. /package/web/assets/{KaTeX_Main-Bold-Cx986IdX.woff2 → KaTeX_Main-Bold-YP5VVQRP-Cx986IdX.woff2} +0 -0
  180. /package/web/assets/{KaTeX_Main-BoldItalic-SpSLRI95.woff → KaTeX_Main-BoldItalic-4P4C7HJH-SpSLRI95.woff} +0 -0
  181. /package/web/assets/{KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 → KaTeX_Main-BoldItalic-N4V3DX7S-DxDJ3AOS.woff2} +0 -0
  182. /package/web/assets/{KaTeX_Main-BoldItalic-DzxPMmG6.ttf → KaTeX_Main-BoldItalic-ODMLBJJQ-DzxPMmG6.ttf} +0 -0
  183. /package/web/assets/{KaTeX_Main-Italic-3WenGoN9.ttf → KaTeX_Main-Italic-I43T2HSR-3WenGoN9.ttf} +0 -0
  184. /package/web/assets/{KaTeX_Main-Italic-NWA7e6Wa.woff2 → KaTeX_Main-Italic-RELBIK7M-NWA7e6Wa.woff2} +0 -0
  185. /package/web/assets/{KaTeX_Main-Italic-BMLOBm91.woff → KaTeX_Main-Italic-SASNQFN2-BMLOBm91.woff} +0 -0
  186. /package/web/assets/{KaTeX_Main-Regular-B22Nviop.woff2 → KaTeX_Main-Regular-ARRPAO67-B22Nviop.woff2} +0 -0
  187. /package/web/assets/{KaTeX_Main-Regular-Dr94JaBh.woff → KaTeX_Main-Regular-P5I74A2A-Dr94JaBh.woff} +0 -0
  188. /package/web/assets/{KaTeX_Main-Regular-ypZvNtVU.ttf → KaTeX_Main-Regular-W74P5G27-ypZvNtVU.ttf} +0 -0
  189. /package/web/assets/{KaTeX_Math-BoldItalic-iY-2wyZ7.woff → KaTeX_Math-BoldItalic-6EBV3DK5-iY-2wyZ7.woff} +0 -0
  190. /package/web/assets/{KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 → KaTeX_Math-BoldItalic-K4WTGH3J-CZnvNsCZ.woff2} +0 -0
  191. /package/web/assets/{KaTeX_Math-BoldItalic-B3XSjfu4.ttf → KaTeX_Math-BoldItalic-VB447A4D-B3XSjfu4.ttf} +0 -0
  192. /package/web/assets/{KaTeX_Math-Italic-t53AETM-.woff2 → KaTeX_Math-Italic-6KGCHLFN-t53AETM-.woff2} +0 -0
  193. /package/web/assets/{KaTeX_Math-Italic-DA0__PXp.woff → KaTeX_Math-Italic-KKK3USB2-DA0__PXp.woff} +0 -0
  194. /package/web/assets/{KaTeX_Math-Italic-flOr_0UB.ttf → KaTeX_Math-Italic-SON4MRCA-flOr_0UB.ttf} +0 -0
  195. /package/web/assets/{KaTeX_SansSerif-Bold-D1sUS0GD.woff2 → KaTeX_SansSerif-Bold-RRNVJFFW-D1sUS0GD.woff2} +0 -0
  196. /package/web/assets/{KaTeX_SansSerif-Bold-CFMepnvq.ttf → KaTeX_SansSerif-Bold-STQ6RXC7-CFMepnvq.ttf} +0 -0
  197. /package/web/assets/{KaTeX_SansSerif-Bold-DbIhKOiC.woff → KaTeX_SansSerif-Bold-X5M5EMOD-DbIhKOiC.woff} +0 -0
  198. /package/web/assets/{KaTeX_SansSerif-Italic-C3H0VqGB.woff2 → KaTeX_SansSerif-Italic-HMPFTM52-C3H0VqGB.woff2} +0 -0
  199. /package/web/assets/{KaTeX_SansSerif-Italic-DN2j7dab.woff → KaTeX_SansSerif-Italic-PSN4QKYX-DN2j7dab.woff} +0 -0
  200. /package/web/assets/{KaTeX_SansSerif-Italic-YYjJ1zSn.ttf → KaTeX_SansSerif-Italic-WTBAZBGY-YYjJ1zSn.ttf} +0 -0
  201. /package/web/assets/{KaTeX_SansSerif-Regular-BNo7hRIc.ttf → KaTeX_SansSerif-Regular-2TL3USAE-BNo7hRIc.ttf} +0 -0
  202. /package/web/assets/{KaTeX_SansSerif-Regular-CS6fqUqJ.woff → KaTeX_SansSerif-Regular-OQCII6EP-CS6fqUqJ.woff} +0 -0
  203. /package/web/assets/{KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 → KaTeX_SansSerif-Regular-XIQ62X4E-DDBCnlJ7.woff2} +0 -0
  204. /package/web/assets/{KaTeX_Script-Regular-C5JkGWo-.ttf → KaTeX_Script-Regular-72OLXYNA-C5JkGWo-.ttf} +0 -0
  205. /package/web/assets/{KaTeX_Script-Regular-D5yQViql.woff → KaTeX_Script-Regular-A5IFOEBS-D5yQViql.woff} +0 -0
  206. /package/web/assets/{KaTeX_Script-Regular-D3wIWfF6.woff2 → KaTeX_Script-Regular-APUWIHLP-D3wIWfF6.woff2} +0 -0
  207. /package/web/assets/{KaTeX_Size1-Regular-C195tn64.woff → KaTeX_Size1-Regular-4HRHTS65-C195tn64.woff} +0 -0
  208. /package/web/assets/{KaTeX_Size1-Regular-mCD8mA8B.woff2 → KaTeX_Size1-Regular-5LRUTBFT-mCD8mA8B.woff2} +0 -0
  209. /package/web/assets/{KaTeX_Size1-Regular-Dbsnue_I.ttf → KaTeX_Size1-Regular-7K6AASVL-Dbsnue_I.ttf} +0 -0
  210. /package/web/assets/{KaTeX_Size2-Regular-B7gKUWhC.ttf → KaTeX_Size2-Regular-222HN3GT-B7gKUWhC.ttf} +0 -0
  211. /package/web/assets/{KaTeX_Size2-Regular-oD1tc_U0.woff → KaTeX_Size2-Regular-K5ZHAIS6-oD1tc_U0.woff} +0 -0
  212. /package/web/assets/{KaTeX_Size2-Regular-Dy4dx90m.woff2 → KaTeX_Size2-Regular-LELKET5D-Dy4dx90m.woff2} +0 -0
  213. /package/web/assets/{KaTeX_Size3-Regular-CTq5MqoE.woff → KaTeX_Size3-Regular-TLFPAHDE-CTq5MqoE.woff} +0 -0
  214. /package/web/assets/{KaTeX_Size3-Regular-DgpXs0kz.ttf → KaTeX_Size3-Regular-UFCO6WCA-DgpXs0kz.ttf} +0 -0
  215. /package/web/assets/{KaTeX_Size4-Regular-DWFBv043.ttf → KaTeX_Size4-Regular-7PGNVPQK-DWFBv043.ttf} +0 -0
  216. /package/web/assets/{KaTeX_Size4-Regular-Dl5lxZxV.woff2 → KaTeX_Size4-Regular-CDMV7U5C-Dl5lxZxV.woff2} +0 -0
  217. /package/web/assets/{KaTeX_Size4-Regular-BF-4gkZK.woff → KaTeX_Size4-Regular-PKMWZHNC-BF-4gkZK.woff} +0 -0
  218. /package/web/assets/{KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf → KaTeX_Typewriter-Regular-3F5K6SQ6-D3Ib7_Hf.ttf} +0 -0
  219. /package/web/assets/{KaTeX_Typewriter-Regular-C0xS9mPB.woff → KaTeX_Typewriter-Regular-MJMFSK64-C0xS9mPB.woff} +0 -0
  220. /package/web/assets/{KaTeX_Typewriter-Regular-CO6r4hn1.woff2 → KaTeX_Typewriter-Regular-VBYJ4NRC-CO6r4hn1.woff2} +0 -0
package/README.md CHANGED
@@ -31,10 +31,12 @@ kennel pop plan.md --watch
31
31
  kennel pop artifacts/pricing-card.html --lan
32
32
  kennel view /path/to/workspace
33
33
  kennel serve /path/to/workspace
34
+ knl tasks /path/to/workspace
35
+ knl mail /path/to/workspace --item draft-id
34
36
  kennel dev /path/to/docs-site --config index.json
35
37
  kennel init .
36
- kennel plugin add https://github.com/example/kennel-transcripts-plugin.git#main
37
- kennel plugin add https://github.com/raggle-ai/kennel-plugins.git --path plugins/calendar
38
+ kennel plugin add https://github.com/<owner>/<plugin-repo>.git#main
39
+ kennel plugin add https://github.com/raggle-ai/kennel-starter-plugins.git --path plugins/calendar
38
40
  kennel core-folders .
39
41
  kennel mcp generate . --config index.json
40
42
  kennel publish init cloudflare .
@@ -44,7 +46,7 @@ kennel dp .
44
46
 
45
47
  `kennel pop <file>` is the pop-up preview: it starts the static viewer rooted at
46
48
  the file's folder, prints a clickable `/folder/<id>/document/<id>` URL, and
47
- opens it in the default pop-up window. Markdown, HTML artifacts, text, images,
49
+ opens it in the default browser only when `--open` is supplied. Markdown, HTML artifacts, text, images,
48
50
  code, CSV/TSV tables, and `.eml` files are recognized by extension; images and
49
51
  binary files are served through `/api/raw`. `--watch` makes the pop-up refresh
50
52
  on save (the URL carries `?watch=1`). Folder mode (`--lan`/`--tailscale`)
@@ -63,6 +65,30 @@ endpoints (`/api/open-path`, `/api/open-folder`) return 403, ACP sessions are
63
65
  disabled, HTML is never streamed inline from `/api/raw`, and mutation POSTs
64
66
  require a same-origin `Origin`/`Referer`. The default host stays `127.0.0.1`.
65
67
 
68
+ ### Terminal output
69
+
70
+ `knl`, file previews, and plugin commands show a named terminal link:
71
+
72
+ ```text
73
+ (open my-folder)
74
+
75
+ shortcuts:
76
+ o - open in browser
77
+ ctrl+c - exit
78
+ ```
79
+
80
+ The `open my-folder` label is clickable in terminals that support hyperlinks. File previews use the file name instead. Press `o` without Enter to open the printed link in the default browser. Ctrl+C restores the terminal and exits the command; it does not stop a viewer that the command reused.
81
+
82
+ When output is redirected, Kennel prints the label and full URL without colors, terminal escape codes, or keyboard controls. `--open` still opens the browser explicitly; `--dry-run` remains non-interactive.
83
+
84
+ ### Installed plugins as commands
85
+
86
+ Every installed plugin ID is a top-level command: `knl tasks`, `knl calendar`, or `knl flights`. The current folder is used unless you pass another folder. Add `--item <id>` to select a plugin-owned detail view.
87
+
88
+ Plugins can declare optional `aliases` in `package.json > kennel.plugin` or `kennel.plugin.json`. The `kennel-email` package uses ID `email` with alias `mail`, so `knl email` and `knl mail` select the same view. Other plugins need no alias declaration when their ID is already the desired command. Reinstall a plugin after changing aliases.
89
+
90
+ Built-in commands take priority over plugin IDs; plugin IDs take priority over aliases. Ambiguous aliases are refused. Use `./tasks` rather than `tasks` to open a folder whose name is also a plugin command. Plugin commands use the same viewer startup as other previews, not a plugin-specific server.
91
+
66
92
  ### Localhost convention (one viewer on port 5180)
67
93
 
68
94
  Kennel can keep one always-running localhost viewer at
@@ -88,8 +114,11 @@ The same user config stores trusted external folder plugins added with
88
114
  command pins the requested ref, or `HEAD` with no fragment, to a full commit,
89
115
  selects the repository root or the requested subdirectory as the plugin package
90
116
  root, validates package metadata and explicit client/server/manifest exports
91
- plus optional API/CSS exports, compiles the plugin in the XDG cache, and only
92
- then atomically updates config. Installed plugin imports are derived from
117
+ plus optional API/CSS exports, installs the package's declared production
118
+ `dependencies` with npm (no dev or peer dependencies, no install scripts),
119
+ compiles the plugin in the XDG cache, and only then atomically updates config.
120
+ React, `kennel-plugins` and the other shared viewer packages always come from
121
+ Kennel, so plugins declare them as peers. Installed plugin imports are derived from
93
122
  package metadata, not from URL text. The transcripts plugin contract is package
94
123
  `kennel-transcripts-plugin`, id `memos`, trigger `memos.json`.
95
124
 
@@ -139,7 +168,7 @@ well-known scratch folder across any AI client.
139
168
  `kennel init` scaffolds starter content files for installed folder plugins into
140
169
  the current folder (or the given path). The external Tasks and Calendar plugins
141
170
  provide `todo.json` and `calendar.json` templates after they are installed from
142
- `raggle-ai/kennel-plugins` with `kennel plugin add ... --path plugins/<id>`.
171
+ `raggle-ai/kennel-starter-plugins` with `kennel plugin add ... --path plugins/<id>`.
143
172
  Existing files are left untouched; `--plugin <id>` scaffolds one plugin,
144
173
  `--force` overwrites, and `--list` prints what would be created without
145
174
  writing.
@@ -151,8 +180,10 @@ diagnostics come from the declared schema and Markdown frontmatter. Pass
151
180
  list. See [Core folders and metadata indexing](../docs/core-folders.md) for
152
181
  patterns, parser support, navigation labels and refresh semantics.
153
182
 
154
- `kennel view` starts the source Vite viewer from a Kennel checkout, also when
155
- external plugins are installed. React and CSS changes use HMR. Changes to
183
+ In a Kennel checkout, `kennel view` starts the source Vite viewer, also when
184
+ external plugins are installed. An npm install has no source checkout, so
185
+ `kennel view` and `kennel open` start the packaged static viewer, the same as
186
+ `kennel serve`. React and CSS changes use HMR. Changes to
156
187
  schema and content files cause a metadata refetch without a full page reload.
157
188
  The Vite viewer and the packaged static viewer load the same compiled plugin
158
189
  build and report its plugin-set key from `/api/health`. The hot
@@ -97,11 +97,6 @@ export async function dispatch(argv) {
97
97
  await viewer(['--hot', ...args]);
98
98
  return;
99
99
  }
100
- if (command === 'mail') {
101
- const { mail } = await import('../site/mail.js');
102
- await mail(args);
103
- return;
104
- }
105
100
  if (command === 'serve') {
106
101
  const { viewer } = await import('../site/viewer.js');
107
102
  await viewer(['--static', ...args]);
@@ -155,6 +150,13 @@ export async function dispatch(argv) {
155
150
  deploy(args);
156
151
  return;
157
152
  }
153
+ // Built-in commands win; use an explicit path (./tasks) to open a folder
154
+ // whose name is also an installed plugin command.
155
+ if (/^[a-z][a-z0-9-]*$/u.test(command)) {
156
+ const { pluginCommand } = await import('../site/plugin.js');
157
+ if (await pluginCommand(command, args))
158
+ return;
159
+ }
158
160
  // Positionals that are flags or existing paths still go straight to the
159
161
  // viewer (`kennel [folder]`, `kennel note.md`, `kennel --lan .`). Unknown
160
162
  // command words fail loudly instead of silently opening a viewer.
package/dist/cli/usage.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export function usage() {
2
2
  console.log(`Usage:
3
- knl core [folder] [--host <host>] [--port <port>] [--api-only]
3
+ knl core [folder] [--host <host>] [--port <port>] [--api-only] [--web-root <dir>]
4
4
  kennel init [path] [--plugin <id>] [--force] [--list]
5
5
  kennel plugin add <git-repository-url-or-local-path> [--path <subdirectory>]
6
6
  kennel plugin new <id>
@@ -9,7 +9,7 @@ export function usage() {
9
9
  kennel pop|p <file|folder> [--open] [--watch] [--host <host>] [--port <port>] [--lan|--tailscale]
10
10
  kennel view [folder] [--host <host>] [--port <port>] [--dry-run]
11
11
  kennel open|o [folder] [--open] [--host <host>] [--port <port>] [--dry-run]
12
- kennel mail [folder] [--open] [--host <host>] [--port <port>] [--dry-run]
12
+ knl <plugin-id|alias> [folder] [--item <id>] [--open] [--dry-run]
13
13
  kennel serve [folder] [--host <host>] [--port <port>] [--lan|--tailscale]
14
14
  kennel share [folder] [--lan|--tailscale] [--port <port>] [--dry-run]
15
15
  kennel dev [path] [--config <json-file>] [--port <port>] [--script <script>] [--dry-run] [-- <args...>]
@@ -22,5 +22,9 @@ export function usage() {
22
22
  kennel publish vercel [path] [--config <json-file>] [--dry-run] [--force] [--hostname <hostname>] [--skip-test]
23
23
  kennel deploy [path] [--config <json-file>] [legacy alias for publish]
24
24
  kennel dp [path] [--config <json-file>] [legacy alias for publish]
25
+
26
+ Installed plugin ids are commands, for example knl tasks or knl calendar.
27
+ Plugins can declare extra aliases, for example knl mail for plugin id email.
28
+ Use --item <id> for a plugin detail view. Built-in commands take priority.
25
29
  `);
26
30
  }
@@ -7,21 +7,24 @@ export async function core(args) {
7
7
  let port = 5181;
8
8
  let apiOnly = false;
9
9
  let folderSet = false;
10
+ let customWebRoot;
10
11
  for (let index = 0; index < args.length; index++) {
11
12
  const arg = args[index];
12
13
  if (arg === "--help" || arg === "-h") {
13
- console.log("Usage: knl core [folder] [--port 5181] [--host 127.0.0.1] [--api-only]\nNon-loopback hosts restrict reads to folder and disable host actions/ACP.");
14
+ console.log("Usage: knl core [folder] [--port 5181] [--host 127.0.0.1] [--api-only] [--web-root dir]\nNon-loopback hosts restrict reads to folder and disable host actions/ACP.\n--web-root serves another host page (for example a desktop shell) instead of the web app.");
14
15
  return;
15
16
  }
16
17
  if (arg === "--api-only") {
17
18
  apiOnly = true;
18
19
  continue;
19
20
  }
20
- if (arg === "--host" || arg === "--port") {
21
+ if (arg === "--host" || arg === "--port" || arg === "--web-root") {
21
22
  const value = args[++index];
22
23
  if (!value || value.startsWith("--"))
23
24
  throw new Error(`Missing value for ${arg}`);
24
- if (arg === "--host")
25
+ if (arg === "--web-root")
26
+ customWebRoot = resolve(value);
27
+ else if (arg === "--host")
25
28
  host = value;
26
29
  else {
27
30
  port = Number(value);
@@ -40,9 +43,11 @@ export async function core(args) {
40
43
  throw new Error("Core root must be a directory");
41
44
  const { ensurePluginBuild, usePluginBuild, webRoot: cliWebRoot } = await import("../plugins/external.js");
42
45
  const plugins = await ensurePluginBuild();
43
- const webRoot = cliWebRoot();
46
+ const webRoot = customWebRoot ?? cliWebRoot();
44
47
  if (!apiOnly && !existsSync(resolve(webRoot, "index.html")))
45
- throw new Error("Web assets missing; build the CLI or use --api-only");
48
+ throw new Error(customWebRoot
49
+ ? `No index.html in --web-root ${customWebRoot}`
50
+ : "Web assets missing; build the CLI or use --api-only");
46
51
  usePluginBuild(plugins);
47
52
  const api = createKennelApi({
48
53
  root,
@@ -215,6 +215,81 @@ var init_src = __esm(() => {
215
215
  init_kinds();
216
216
  });
217
217
 
218
+ // packages/preview/src/terminal.ts
219
+ import { execFile } from "node:child_process";
220
+ import { basename } from "node:path";
221
+ import { emitKeypressEvents } from "node:readline";
222
+ function openPreview(url) {
223
+ const command = process.platform === "darwin" ? "/usr/bin/open" : process.platform === "win32" ? "explorer.exe" : "xdg-open";
224
+ execFile(command, [url], (error) => {
225
+ if (error)
226
+ console.error(`Could not open browser: ${error.message}`);
227
+ });
228
+ }
229
+ function previewTerminal(url, target) {
230
+ url = new URL(url).href;
231
+ const input = process.stdin;
232
+ const output = process.stdout;
233
+ const terminal = Boolean(output.isTTY && process.env.TERM !== "dumb");
234
+ const interactive = terminal && Boolean(input.isTTY);
235
+ const name = (basename(target.target ?? target.root) || target.root).replace(/[\u0000-\u001f\u007f-\u009f]/g, "");
236
+ const label = `(open ${name})`;
237
+ const color = terminal && process.env.NO_COLOR === undefined && output.hasColors();
238
+ const accent = (text) => color ? `\x1B[36m${text}\x1B[39m` : text;
239
+ const link = terminal ? `\x1B]8;;${url}\x1B\\${accent(label)}\x1B]8;;\x1B\\` : `${label}
240
+ ${url}`;
241
+ const wasRaw = Boolean(input.isRaw);
242
+ const wasFlowing = input.readableFlowing === true;
243
+ let resolveClosed;
244
+ const closed = new Promise((resolve) => {
245
+ resolveClosed = resolve;
246
+ });
247
+ let finished = false;
248
+ const close = () => {
249
+ if (finished)
250
+ return;
251
+ finished = true;
252
+ process.off("SIGINT", close);
253
+ process.off("SIGTERM", close);
254
+ process.off("exit", close);
255
+ if (interactive) {
256
+ input.off("keypress", keypress);
257
+ input.off("end", close);
258
+ input.setRawMode(wasRaw);
259
+ if (!wasFlowing)
260
+ input.pause();
261
+ }
262
+ resolveClosed();
263
+ };
264
+ const keypress = (_text, key) => {
265
+ if (key.ctrl && (key.name === "c" || key.name === "d"))
266
+ close();
267
+ else if (key.name === "o" && !key.ctrl && !key.meta)
268
+ openPreview(url);
269
+ };
270
+ process.once("SIGINT", close);
271
+ process.once("SIGTERM", close);
272
+ process.once("exit", close);
273
+ if (interactive) {
274
+ emitKeypressEvents(input);
275
+ input.setRawMode(true);
276
+ input.on("keypress", keypress);
277
+ input.once("end", close);
278
+ input.resume();
279
+ }
280
+ console.log(`
281
+ ${link}
282
+ `);
283
+ if (interactive) {
284
+ console.log(` shortcuts:
285
+ ${accent("o")} - open in browser
286
+ ctrl+c - exit
287
+ `);
288
+ }
289
+ return { close, closed, interactive };
290
+ }
291
+ var init_terminal = () => {};
292
+
218
293
  // node_modules/.bun/openapi-fetch@0.17.0/node_modules/openapi-fetch/dist/index.mjs
219
294
  function randomID() {
220
295
  return Math.random().toString(36).slice(2, 11);
@@ -6028,7 +6103,7 @@ var init_src2 = __esm(() => {
6028
6103
  });
6029
6104
 
6030
6105
  // packages/preview/src/hot-viewer.ts
6031
- import { execFile, execFileSync, spawn } from "node:child_process";
6106
+ import { execFileSync, spawn } from "node:child_process";
6032
6107
  import { randomUUID } from "node:crypto";
6033
6108
  import { existsSync } from "node:fs";
6034
6109
  import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
@@ -6138,18 +6213,25 @@ async function hotViewer(options) {
6138
6213
  const displayHost = options.lan ? lanHost() : options.host;
6139
6214
  const viewerHosts = [displayHost, "localhost", "127.0.0.1"].join(",");
6140
6215
  const viewerUrl = `http://${displayHost}:${options.port}${openPath}`;
6141
- console.log(`Kennel hot viewer: ${viewerUrl}`);
6142
6216
  if (options.dryRun) {
6217
+ console.log(`Kennel hot viewer: ${viewerUrl}`);
6143
6218
  console.log(`bun ${[...args, ...options.open ? ["--open", openPath] : []].join(" ")}`);
6144
6219
  return;
6145
6220
  }
6221
+ const reuse = async () => {
6222
+ const terminal = previewTerminal(viewerUrl, options);
6223
+ if (options.open)
6224
+ openPreview(viewerUrl);
6225
+ try {
6226
+ if (terminal.interactive)
6227
+ await terminal.closed;
6228
+ } finally {
6229
+ terminal.close();
6230
+ }
6231
+ };
6146
6232
  const status = await viewerStatus(url);
6147
6233
  if (status === "running") {
6148
- if (options.open) {
6149
- console.log(`Kennel hot viewer is already running at ${viewerUrl}`);
6150
- } else {
6151
- console.log("Kennel hot viewer is already running. Reusing it.");
6152
- }
6234
+ await reuse();
6153
6235
  return;
6154
6236
  }
6155
6237
  if (status === "other") {
@@ -6157,11 +6239,7 @@ async function hotViewer(options) {
6157
6239
  }
6158
6240
  if (await portOpen(options.host, options.port)) {
6159
6241
  if (await viewerRunning(url, 20, true)) {
6160
- if (options.open) {
6161
- console.log(`Kennel hot viewer is already running at ${viewerUrl}`);
6162
- } else {
6163
- console.log("Kennel hot viewer is already running. Reusing it.");
6164
- }
6242
+ await reuse();
6165
6243
  return;
6166
6244
  }
6167
6245
  throw new Error(`Port ${options.port} is used by another service. Stop it or select another port.`);
@@ -6170,11 +6248,7 @@ async function hotViewer(options) {
6170
6248
  let token = await acquireLock(lock);
6171
6249
  if (!token) {
6172
6250
  if (await viewerRunning(url, 40, true)) {
6173
- if (options.open) {
6174
- console.log(`Kennel hot viewer is already running at ${viewerUrl}`);
6175
- } else {
6176
- console.log("Kennel hot viewer is already running. Reusing it.");
6177
- }
6251
+ await reuse();
6178
6252
  return;
6179
6253
  }
6180
6254
  await rm(lock, { force: true, recursive: true });
@@ -6184,14 +6258,9 @@ async function hotViewer(options) {
6184
6258
  throw new Error(`Could not acquire the hot viewer startup lock for port ${options.port}.`);
6185
6259
  if (await viewerRunning(url)) {
6186
6260
  await releaseLock(lock, token);
6187
- if (options.open) {
6188
- console.log(`Kennel hot viewer is already running at ${viewerUrl}`);
6189
- } else {
6190
- console.log("Kennel hot viewer is already running. Reusing it.");
6191
- }
6261
+ await reuse();
6192
6262
  return;
6193
6263
  }
6194
- console.log(`bun ${args.join(" ")}`);
6195
6264
  if (options.open)
6196
6265
  args.push("--open", openPath);
6197
6266
  const child = spawn("bun", args, {
@@ -6204,7 +6273,12 @@ async function hotViewer(options) {
6204
6273
  ...options.target ? { KENNEL_VIEWER_TARGET: options.target } : {},
6205
6274
  LC_ALL: "en_GB.UTF-8"
6206
6275
  },
6207
- stdio: "inherit"
6276
+ stdio: ["ignore", "inherit", "inherit"]
6277
+ });
6278
+ const terminal = previewTerminal(viewerUrl, options);
6279
+ terminal.closed.then(() => {
6280
+ if (child.exitCode === null && child.signalCode === null)
6281
+ child.kill("SIGTERM");
6208
6282
  });
6209
6283
  await new Promise((done, fail) => {
6210
6284
  child.once("error", fail);
@@ -6213,16 +6287,21 @@ async function hotViewer(options) {
6213
6287
  done();
6214
6288
  return;
6215
6289
  }
6290
+ terminal.close();
6216
6291
  if (await viewerRunning(url, 20, true)) {
6217
- console.log("Kennel hot viewer is already running. Reusing it.");
6292
+ await reuse();
6218
6293
  done();
6219
6294
  return;
6220
6295
  }
6221
6296
  fail(new Error(`Kennel hot viewer stopped with exit code ${code ?? "unknown"}`));
6222
6297
  });
6223
- }).finally(() => releaseLock(lock, token));
6298
+ }).finally(async () => {
6299
+ terminal.close();
6300
+ await releaseLock(lock, token);
6301
+ });
6224
6302
  }
6225
6303
  var init_hot_viewer = __esm(() => {
6304
+ init_terminal();
6226
6305
  init_src2();
6227
6306
  });
6228
6307
 
@@ -28108,7 +28187,7 @@ var init_server = __esm(() => {
28108
28187
  // packages/schemas/src/data/workspace.ts
28109
28188
  import { existsSync as existsSync3, readFileSync, realpathSync, statSync as statSync2 } from "node:fs";
28110
28189
  import {
28111
- basename,
28190
+ basename as basename2,
28112
28191
  dirname as dirname3,
28113
28192
  isAbsolute,
28114
28193
  relative as relative3,
@@ -28169,7 +28248,7 @@ function folderWorkspace(input, { allowMissingSchemas = false } = {}) {
28169
28248
  for (let current = folder;inside(root, current); current = dirname3(current)) {
28170
28249
  breadcrumbs.unshift({
28171
28250
  path: current,
28172
- title: basename(current),
28251
+ title: basename2(current),
28173
28252
  schema: schemaRoots.some((owner) => inside(owner, current))
28174
28253
  });
28175
28254
  if (current === root)
@@ -37714,7 +37793,7 @@ var init_load = __esm(() => {
37714
37793
  // packages/schemas/src/node.ts
37715
37794
  import { readdir as readdir2, readFile as readFile4, realpath as realpath2, stat as stat2 } from "node:fs/promises";
37716
37795
  import {
37717
- basename as basename2,
37796
+ basename as basename3,
37718
37797
  dirname as dirname5,
37719
37798
  isAbsolute as isAbsolute3,
37720
37799
  relative as relative5,
@@ -37747,7 +37826,7 @@ function createCoreFolderIndex() {
37747
37826
  affected.add(scope);
37748
37827
  }
37749
37828
  }
37750
- if (inside3(path, scope) || basename2(path) === "raggle.json" && inside3(dirname5(path), scope) || ["schema.json", "_schema.json"].includes(basename2(path)) && dirname5(path) === scope)
37829
+ if (inside3(path, scope) || basename3(path) === "raggle.json" && inside3(dirname5(path), scope) || ["schema.json", "_schema.json"].includes(basename3(path)) && dirname5(path) === scope)
37751
37830
  affected.add(scope);
37752
37831
  }
37753
37832
  for (const file of records.keys())
@@ -37856,7 +37935,7 @@ function createCoreFolderIndex() {
37856
37935
  path,
37857
37936
  relativePath: localPath,
37858
37937
  modifiedAt: info.mtimeMs,
37859
- title: text(fieldValue(parsed.fields, primary)) ?? text(parsed.fields.title) ?? parsed.heading ?? basename2(path, ".md"),
37938
+ title: text(fieldValue(parsed.fields, primary)) ?? text(parsed.fields.title) ?? parsed.heading ?? basename3(path, ".md"),
37860
37939
  fields: parsed.fields,
37861
37940
  validationErrors,
37862
37941
  icon: await recordIcon(parsed.fields, path, entry.folder, parsed.body)
@@ -37882,7 +37961,7 @@ function createCoreFolderIndex() {
37882
37961
  const data = {
37883
37962
  id,
37884
37963
  ...entry,
37885
- title: text(schema?.title) ?? config.title ?? basename2(entry.folder),
37964
+ title: text(schema?.title) ?? config.title ?? basename3(entry.folder),
37886
37965
  navLabel: config.ui?.navLabel,
37887
37966
  icon: config.icon,
37888
37967
  count: indexedRecords.length,
@@ -37953,7 +38032,7 @@ var init_node3 = __esm(() => {
37953
38032
 
37954
38033
  // packages/schemas/src/server.ts
37955
38034
  import { createHash as createHash3 } from "node:crypto";
37956
- import { basename as basename3, relative as relative6 } from "node:path";
38035
+ import { basename as basename4, relative as relative6 } from "node:path";
37957
38036
  function createSchemaCollectionServer(host, options = {}) {
37958
38037
  const collectionIndex = createCoreFolderIndex();
37959
38038
  const collectionScopes = new Set;
@@ -38003,7 +38082,7 @@ function createSchemaCollectionServer(host, options = {}) {
38003
38082
  };
38004
38083
  const invalidate = (path) => {
38005
38084
  const affected = collectionIndex.invalidate(path);
38006
- if (affected.length || basename3(path) === "raggle.json" && collectionScopes.size) {
38085
+ if (affected.length || basename4(path) === "raggle.json" && collectionScopes.size) {
38007
38086
  clearTimeout(collectionRefresh);
38008
38087
  collectionRefresh = setTimeout(() => {
38009
38088
  host.emit({
@@ -38100,7 +38179,7 @@ var init_server2 = __esm(() => {
38100
38179
  import { readdir as readdir3, readFile as readFile5, realpath as realpath3, stat as stat3 } from "node:fs/promises";
38101
38180
  import { homedir as homedir2 } from "node:os";
38102
38181
  import {
38103
- basename as basename4,
38182
+ basename as basename5,
38104
38183
  dirname as dirname6,
38105
38184
  extname as extname2,
38106
38185
  isAbsolute as isAbsolute4,
@@ -38245,10 +38324,10 @@ async function readEntity(folderPath, rootPath) {
38245
38324
  return {
38246
38325
  content: document2.body,
38247
38326
  path: relative7(folderPath, filePath),
38248
- title: stringValue(document2.frontmatter.title) ?? heading(document2.body) ?? basename4(filePath, extname2(filePath))
38327
+ title: stringValue(document2.frontmatter.title) ?? heading(document2.body) ?? basename5(filePath, extname2(filePath))
38249
38328
  };
38250
38329
  }));
38251
- const title = stringValue(index.frontmatter.title) ?? heading(index.body) ?? basename4(folderPath);
38330
+ const title = stringValue(index.frontmatter.title) ?? heading(index.body) ?? basename5(folderPath);
38252
38331
  const relativePath = relative7(rootPath, folderPath) || ".";
38253
38332
  return {
38254
38333
  aliases: stringValues(index.frontmatter.aliases),
@@ -38576,7 +38655,7 @@ var init_manifest = __esm(() => {
38576
38655
 
38577
38656
  // packages/notes/src/server.ts
38578
38657
  import { readdir as readdir4, stat as stat6 } from "node:fs/promises";
38579
- import { basename as basename5, extname as extname5, relative as relative9, resolve as resolve10, sep as sep5 } from "node:path";
38658
+ import { basename as basename6, extname as extname5, relative as relative9, resolve as resolve10, sep as sep5 } from "node:path";
38580
38659
  async function listMarkdownFiles(folder) {
38581
38660
  const files = [];
38582
38661
  const visit = async (current) => {
@@ -38597,7 +38676,7 @@ async function listMarkdownFiles(folder) {
38597
38676
  });
38598
38677
  files.push({
38599
38678
  activityAt: details?.mtimeMs ?? 0,
38600
- name: basename5(entry.name, extname5(entry.name)),
38679
+ name: basename6(entry.name, extname5(entry.name)),
38601
38680
  relativePath: relative9(folder, path).split(sep5).join("/")
38602
38681
  });
38603
38682
  }
@@ -38968,7 +39047,7 @@ import { realpathSync as realpathSync2 } from "node:fs";
38968
39047
  import { readdir as readdir5, readFile as readFile9, stat as stat7 } from "node:fs/promises";
38969
39048
  import { homedir as homedir3 } from "node:os";
38970
39049
  import {
38971
- basename as basename6,
39050
+ basename as basename7,
38972
39051
  dirname as dirname10,
38973
39052
  extname as extname6,
38974
39053
  isAbsolute as isAbsolute6,
@@ -39163,7 +39242,7 @@ async function loadFolderData(folder) {
39163
39242
  items: projects.map((project) => ({
39164
39243
  id: project.id,
39165
39244
  worktree: project.worktree,
39166
- name: project.name ?? basename6(project.worktree),
39245
+ name: project.name ?? basename7(project.worktree),
39167
39246
  relativePath: relative11(folder, project.worktree)
39168
39247
  }))
39169
39248
  }
@@ -39661,7 +39740,7 @@ function createFolderApi({
39661
39740
  ETag: etag,
39662
39741
  "X-Content-Type-Options": "nosniff",
39663
39742
  ...download ? {
39664
- "Content-Disposition": `attachment; filename="${basename6(target.path)}"`
39743
+ "Content-Disposition": `attachment; filename="${basename7(target.path)}"`
39665
39744
  } : {}
39666
39745
  });
39667
39746
  response.end(await readFile9(target.path));
@@ -44803,7 +44882,7 @@ import { resolve as resolve15 } from "node:path";
44803
44882
  import { existsSync as existsSync7 } from "node:fs";
44804
44883
 
44805
44884
  // packages/preview/src/viewer.ts
44806
- import { execFile as execFile6, execFileSync as execFileSync2 } from "node:child_process";
44885
+ import { execFileSync as execFileSync2 } from "node:child_process";
44807
44886
  import { existsSync as existsSync6, realpathSync as realpathSync3, statSync as statSync3 } from "node:fs";
44808
44887
  import { createServer as createServer2 } from "node:net";
44809
44888
  import { dirname as dirname11, isAbsolute as isAbsolute8, relative as relative13, resolve as resolve14 } from "node:path";
@@ -44813,6 +44892,7 @@ import { fileURLToPath as fileURLToPath3 } from "node:url";
44813
44892
  init_src();
44814
44893
 
44815
44894
  // packages/preview/src/viewer.ts
44895
+ init_terminal();
44816
44896
  var loopbackHosts = new Set([
44817
44897
  "127.0.0.1",
44818
44898
  "::1",
@@ -44992,13 +45072,6 @@ async function availableViewerPort(start, host) {
44992
45072
  }
44993
45073
  throw new Error(`Kennel could not find a free port at or above ${start}`);
44994
45074
  }
44995
- function openUrl(url) {
44996
- const command = process.platform === "darwin" ? "/usr/bin/open" : process.platform === "win32" ? "explorer.exe" : "xdg-open";
44997
- execFile6(command, [url], (error) => {
44998
- if (error)
44999
- console.error(`Could not open browser: ${error.message}`);
45000
- });
45001
- }
45002
45075
  function lanHost2() {
45003
45076
  const route = execFileSync2("/sbin/route", ["-n", "get", "default"], {
45004
45077
  encoding: "utf8"
@@ -45045,10 +45118,15 @@ async function viewer(input) {
45045
45118
  const existing = await runningViewer(initialViewerUrl);
45046
45119
  if (existing && isSameOrDescendant(existing.root, options.root)) {
45047
45120
  const viewerUrl = popUrl(displayHost, options.port, options);
45048
- console.log(viewerUrl);
45049
- console.log(`Kennel is already running at ${viewerUrl}`);
45121
+ const terminal = previewTerminal(viewerUrl, options);
45050
45122
  if (options.open)
45051
- openUrl(viewerUrl);
45123
+ openPreview(viewerUrl);
45124
+ try {
45125
+ if (terminal.interactive)
45126
+ await terminal.closed;
45127
+ } finally {
45128
+ terminal.close();
45129
+ }
45052
45130
  return;
45053
45131
  }
45054
45132
  if (!portExplicit) {
@@ -45064,25 +45142,18 @@ async function viewer(input) {
45064
45142
  });
45065
45143
  try {
45066
45144
  await api.listen(Number(options.port));
45067
- console.log(`Reading documents from ${options.root}`);
45068
45145
  if (options.tailscale) {
45069
45146
  execFileSync2("tailscale", ["serve", "--bg", "--yes", options.port]);
45070
45147
  }
45071
45148
  const viewerUrl = popUrl(displayHost, options.port, options);
45072
- console.log(viewerUrl);
45073
- console.log(`Kennel is running at ${viewerUrl}`);
45074
- console.log("Press Ctrl+C to stop.");
45149
+ const terminal = previewTerminal(viewerUrl, options);
45075
45150
  if (options.open)
45076
- openUrl(viewerUrl);
45077
- await new Promise((done) => {
45078
- const close = () => {
45079
- process.off("SIGINT", close);
45080
- process.off("SIGTERM", close);
45081
- done();
45082
- };
45083
- process.once("SIGINT", close);
45084
- process.once("SIGTERM", close);
45085
- });
45151
+ openPreview(viewerUrl);
45152
+ try {
45153
+ await terminal.closed;
45154
+ } finally {
45155
+ terminal.close();
45156
+ }
45086
45157
  } finally {
45087
45158
  await api.close();
45088
45159
  }
@@ -4,6 +4,7 @@ export type ExternalPluginEntry = {
4
4
  commit: string;
5
5
  packageName: string;
6
6
  id: string;
7
+ aliases?: string[];
7
8
  directory?: string;
8
9
  path?: string;
9
10
  trigger?: string;