excaliagent 0.0.0-stage → 0.1.0

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 (426) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -2
  3. package/bin/excaliagent.js +2 -0
  4. package/dist/server/args.js +51 -0
  5. package/dist/server/cli.js +99 -0
  6. package/dist/server/desktop/desktop.js +108 -0
  7. package/dist/server/http.js +240 -0
  8. package/dist/server/hub.js +101 -0
  9. package/dist/server/panes/herdr-client.js +220 -0
  10. package/dist/server/panes/herdr-clients.js +58 -0
  11. package/dist/server/panes/herdr.js +246 -0
  12. package/dist/server/panes/none.js +10 -0
  13. package/dist/server/panes/types.js +1 -0
  14. package/dist/server/scene-store.js +61 -0
  15. package/dist/server/sources/claude.js +292 -0
  16. package/dist/server/sources/git.js +65 -0
  17. package/dist/server/sources/log.js +10 -0
  18. package/dist/server/sources/registry.js +79 -0
  19. package/dist/server/sources/transcript.js +204 -0
  20. package/dist/server/sources/types.js +1 -0
  21. package/dist/shared/types.js +9 -0
  22. package/dist/web/assets/Assistant-Bold-gm-uSS1B.woff2 +0 -0
  23. package/dist/web/assets/Assistant-Medium-DrcxCXg3.woff2 +0 -0
  24. package/dist/web/assets/Assistant-Regular-DVxZuzxb.woff2 +0 -0
  25. package/dist/web/assets/Assistant-SemiBold-SCI4bEL9.woff2 +0 -0
  26. package/dist/web/assets/abnfDiagram-VCTEODGH-lVjPevGa.js +1 -0
  27. package/dist/web/assets/ar-SA-G6X2FPQ2-CD5aVmDx.js +10 -0
  28. package/dist/web/assets/arc-Y1ARJVZ4.js +1 -0
  29. package/dist/web/assets/architecture-7GRP2DOG-9pDjotLm.js +1 -0
  30. package/dist/web/assets/architectureDiagram-5GKGNRK7-D0Yl-_Yc.js +36 -0
  31. package/dist/web/assets/array-BifhSqXX.js +1 -0
  32. package/dist/web/assets/az-AZ-76LH7QW2-D4vT9Alz.js +1 -0
  33. package/dist/web/assets/bg-BG-XCXSNQG7-MMTI5wg3.js +5 -0
  34. package/dist/web/assets/blockDiagram-I7D4REHJ-DhrilPMV.js +129 -0
  35. package/dist/web/assets/bn-BD-2XOGV67Q-CCHqTpZW.js +5 -0
  36. package/dist/web/assets/c4Diagram-7LVT6UL2-DGXbRPw_.js +38 -0
  37. package/dist/web/assets/ca-ES-6MX7JW3Y-ChGGIAut.js +8 -0
  38. package/dist/web/assets/channel-fspI7jZI.js +1 -0
  39. package/dist/web/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  40. package/dist/web/assets/chunk-4HAMMTFA-Cw9s83q8.js +62 -0
  41. package/dist/web/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  42. package/dist/web/assets/chunk-75Z2AOVW-BC0CaRUB.js +2 -0
  43. package/dist/web/assets/chunk-DU6HZSFF-W9nFVr4b.js +127 -0
  44. package/dist/web/assets/chunk-EIO257PC-DG_y2xQ1.js +22 -0
  45. package/dist/web/assets/chunk-F27PBJKO-yfVK-Hr6.js +1 -0
  46. package/dist/web/assets/chunk-FOHPRMQF-DD4dKubD.js +161 -0
  47. package/dist/web/assets/chunk-GMAD6QVW-C2Qn052r.js +72 -0
  48. package/dist/web/assets/chunk-GVQU2GXP-IFaX5U4g.js +1 -0
  49. package/dist/web/assets/chunk-IMKFNOWR-M1ZEBqas.js +231 -0
  50. package/dist/web/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  51. package/dist/web/assets/chunk-L3NEJ4N5-oLQiZ5i-.js +1 -0
  52. package/dist/web/assets/chunk-OSK3NFVY-D-OfNZzS.js +10 -0
  53. package/dist/web/assets/chunk-P2QGCYS3-DJerQdnp.js +1 -0
  54. package/dist/web/assets/chunk-POPQ4Y6H-BC0OyYJc.js +1 -0
  55. package/dist/web/assets/chunk-PWAF6VOD-CjU6T4Vk.js +1 -0
  56. package/dist/web/assets/chunk-SHT3W25Y-DBMa5yhK.js +168 -0
  57. package/dist/web/assets/chunk-SVP7TREG-Bbvoxr5d.js +88 -0
  58. package/dist/web/assets/chunk-TICWLB2K-DIPq7Qti.js +206 -0
  59. package/dist/web/assets/chunk-XXDRQBXY-CnbRkih_.js +1 -0
  60. package/dist/web/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  61. package/dist/web/assets/classDiagram-ZZMXUADV-Dr-7S1cu.js +1 -0
  62. package/dist/web/assets/classDiagram-v2-VYDZK3BY-Dr-7S1cu.js +1 -0
  63. package/dist/web/assets/cose-bilkent-JH36ORCC-lWVj4msc.js +1 -0
  64. package/dist/web/assets/cs-CZ-2BRQDIVT-Bax3wFiz.js +11 -0
  65. package/dist/web/assets/cynefin-OW5HDTMX-y_XDTnaT.js +1 -0
  66. package/dist/web/assets/cynefinDiagram-5FMLGOSQ-BeJtQvjE.js +62 -0
  67. package/dist/web/assets/cytoscape.esm-BegBNzOV.js +321 -0
  68. package/dist/web/assets/da-DK-5WZEPLOC-i66Qepbp.js +5 -0
  69. package/dist/web/assets/dagre-D7JM2Yhv.js +1 -0
  70. package/dist/web/assets/dagre-GXQ25YYZ-CzBP3X6H.js +4 -0
  71. package/dist/web/assets/de-DE-XR44H4JA-yjhmbrBK.js +8 -0
  72. package/dist/web/assets/defaultLocale-BFoDCU3G.js +1 -0
  73. package/dist/web/assets/diagram-S7CK7UJ4-CL5OmME1.js +30 -0
  74. package/dist/web/assets/diagram-UQ7AKVKN-6_lscQb4.js +41 -0
  75. package/dist/web/assets/diagram-VSXAHHWV-C3E4-nJG.js +3 -0
  76. package/dist/web/assets/diagram-VX7I27RA-51lQ_NN2.js +24 -0
  77. package/dist/web/assets/diagram-Z3DM3KII-D86k1y9Z.js +24 -0
  78. package/dist/web/assets/directory-open-01563666-D4xXyWb_.js +1 -0
  79. package/dist/web/assets/directory-open-4ed118d0-1i309Asm.js +1 -0
  80. package/dist/web/assets/dist-BPnbDAwD.js +62 -0
  81. package/dist/web/assets/dist-CumnGVmJ.js +1 -0
  82. package/dist/web/assets/ebnfDiagram-PWID7BFC-DDjKtPWY.js +1 -0
  83. package/dist/web/assets/el-GR-BZB4AONW-Deizd0yM.js +10 -0
  84. package/dist/web/assets/en-B4ZKOASM-Dvqqxrua.js +1 -0
  85. package/dist/web/assets/erDiagram-RLTQ6QDP-Dju3XIzd.js +99 -0
  86. package/dist/web/assets/es-ES-U4NZUMDT-Bz7tNFv9.js +9 -0
  87. package/dist/web/assets/eu-ES-A7QVB2H4-B3BHiHTa.js +11 -0
  88. package/dist/web/assets/eventmodeling-NTZA5JFV-MeBWwPID.js +1 -0
  89. package/dist/web/assets/fa-IR-HGAKTJCU-B9t2EOWw.js +8 -0
  90. package/dist/web/assets/fi-FI-Z5N7JZ37-BRW-fC7d.js +6 -0
  91. package/dist/web/assets/file-open-002ab408-BHUWm0Sh.js +1 -0
  92. package/dist/web/assets/file-open-7c801643-DZtJT5zp.js +1 -0
  93. package/dist/web/assets/file-save-3189631c-CO9S4HFW.js +1 -0
  94. package/dist/web/assets/file-save-745eba88-Bwdfz6OZ.js +1 -0
  95. package/dist/web/assets/flowDiagram-HODETNUW-kdP64-E7.js +1 -0
  96. package/dist/web/assets/fr-FR-RHASNOE6-C1x7RIuS.js +9 -0
  97. package/dist/web/assets/ganttDiagram-EL5Y4UJY-CUQyfHZV.js +292 -0
  98. package/dist/web/assets/gitGraph-4MIJSDKK-77imLp1D.js +1 -0
  99. package/dist/web/assets/gitGraphDiagram-WWUBYQGX-CC4ZOu_u.js +106 -0
  100. package/dist/web/assets/gl-ES-HMX3MZ6V-DSChLEXM.js +10 -0
  101. package/dist/web/assets/graphlib-DS17s2tU.js +1 -0
  102. package/dist/web/assets/he-IL-6SHJWFNN-DqrJHras.js +10 -0
  103. package/dist/web/assets/hi-IN-IWLTKZ5I-scDn95Bz.js +4 -0
  104. package/dist/web/assets/hu-HU-A5ZG7DT2-2BB7ywaE.js +7 -0
  105. package/dist/web/assets/id-ID-SAP4L64H-BCD-rITt.js +10 -0
  106. package/dist/web/assets/image-GAAHSSAO-BHEttEFL.js +1 -0
  107. package/dist/web/assets/image-blob-reduce.esm-Fj7y_Tzy.js +2 -0
  108. package/dist/web/assets/index-C6RFmwp_.js +212 -0
  109. package/dist/web/assets/index-DtRVLazd.css +1 -0
  110. package/dist/web/assets/info-A6RAGUB7-Ee6NHVyn.js +1 -0
  111. package/dist/web/assets/infoDiagram-27XIBGKW-bwB50WOT.js +2 -0
  112. package/dist/web/assets/init-C-OQMol4.js +1 -0
  113. package/dist/web/assets/ishikawaDiagram-5VMMS53U-6CilUSFW.js +70 -0
  114. package/dist/web/assets/it-IT-JPQ66NNP-D4MSuNp_.js +11 -0
  115. package/dist/web/assets/ja-JP-DBVTYXUO-BkR3NP86.js +8 -0
  116. package/dist/web/assets/journeyDiagram-3NMN7TZE-C-woTmG9.js +139 -0
  117. package/dist/web/assets/kaa-6HZHGXH3-C_EQTf78.js +1 -0
  118. package/dist/web/assets/kab-KAB-ZGHBKWFO-P-qeHBkl.js +8 -0
  119. package/dist/web/assets/kanban-definition-UXKFOSKX-CL-EUtyf.js +89 -0
  120. package/dist/web/assets/katex-DJhrJSbw.js +257 -0
  121. package/dist/web/assets/kk-KZ-P5N5QNE5-DwZmyItd.js +1 -0
  122. package/dist/web/assets/km-KH-HSX4SM5Z-3SN2ksDz.js +11 -0
  123. package/dist/web/assets/ko-KR-MTYHY66A--YzrPq0D.js +9 -0
  124. package/dist/web/assets/ku-TR-6OUDTVRD-BV1o1ulU.js +9 -0
  125. package/dist/web/assets/line-DGLpHp6u.js +1 -0
  126. package/dist/web/assets/linear-C9iwaMOi.js +1 -0
  127. package/dist/web/assets/lt-LT-XHIRWOB4-BuU5cssW.js +3 -0
  128. package/dist/web/assets/lv-LV-5QDEKY6T-Z9bSAiFr.js +7 -0
  129. package/dist/web/assets/mermaid-parser.core-DA_7CZUN.js +7 -0
  130. package/dist/web/assets/mindmap-definition-YA3MSWOX-B58mvQws.js +96 -0
  131. package/dist/web/assets/mr-IN-CRQNXWMA-Cz6h_4fN.js +13 -0
  132. package/dist/web/assets/my-MM-5M5IBNSE-n2l8bHxH.js +1 -0
  133. package/dist/web/assets/nb-NO-T6EIAALU-r9C_Vo0N.js +10 -0
  134. package/dist/web/assets/nl-NL-IS3SIHDZ-z43DJLFx.js +8 -0
  135. package/dist/web/assets/nn-NO-6E72VCQL-Dc6CXJ79.js +8 -0
  136. package/dist/web/assets/oc-FR-POXYY2M6-BgJXbWuu.js +8 -0
  137. package/dist/web/assets/ordinal-BDEzSJ7C.js +1 -0
  138. package/dist/web/assets/pa-IN-N4M65BXN-CNGXNDOU.js +4 -0
  139. package/dist/web/assets/packet-AYTQ26CC-DBS9PBUE.js +1 -0
  140. package/dist/web/assets/path-fybaL0A-.js +1 -0
  141. package/dist/web/assets/pegDiagram-XKGWAZYB-DA7TGmky.js +1 -0
  142. package/dist/web/assets/percentages-BXMCSKIN-btxXaPp4.js +1 -0
  143. package/dist/web/assets/pica-CXv_OHDX.js +2 -0
  144. package/dist/web/assets/pie-WAS4IAKB-Cx2pnjZr.js +1 -0
  145. package/dist/web/assets/pieDiagram-E7YTZNPT-q7SgBOc3.js +39 -0
  146. package/dist/web/assets/pl-PL-T2D74RX3-NeLUNwLZ.js +9 -0
  147. package/dist/web/assets/pt-BR-5N22H2LF-D5X0RFzx.js +9 -0
  148. package/dist/web/assets/pt-PT-UZXXM6DQ-_ZsKyBBN.js +9 -0
  149. package/dist/web/assets/quadrantDiagram-AXDQQJYC-CqjGVnZh.js +7 -0
  150. package/dist/web/assets/radar-RG4KPBEZ-BWJANoHa.js +1 -0
  151. package/dist/web/assets/railroad-74A4TZTK-BTAfdSvV.js +1 -0
  152. package/dist/web/assets/railroad-abnf-HS5TGJTU-NfS3EnaM.js +1 -0
  153. package/dist/web/assets/railroad-ebnf-LZEXJU2U-Ce5m2P1B.js +1 -0
  154. package/dist/web/assets/railroad-peg-WCYAUIDC-CyXkeDDy.js +1 -0
  155. package/dist/web/assets/railroadDiagram-O6MQD6OU-C4wOSBs0.js +1 -0
  156. package/dist/web/assets/requirementDiagram-BXWQKSXE-dC2Q9_dM.js +84 -0
  157. package/dist/web/assets/ro-RO-JPDTUUEW-B0TUgaSO.js +11 -0
  158. package/dist/web/assets/rolldown-runtime-COiEfhsA.js +1 -0
  159. package/dist/web/assets/rough.esm-Dy-Kn_BL.js +1 -0
  160. package/dist/web/assets/roundRect-D01gJrlt.js +1 -0
  161. package/dist/web/assets/ru-RU-B4JR7IUQ-FyI4SBb1.js +9 -0
  162. package/dist/web/assets/sankeyDiagram-P5KCCOFB-czlewm_g.js +40 -0
  163. package/dist/web/assets/sequenceDiagram-WJ2MYXX4-rtSwZGtV.js +162 -0
  164. package/dist/web/assets/si-LK-N5RQ5JYF-q-KyMvoF.js +1 -0
  165. package/dist/web/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
  166. package/dist/web/assets/sk-SK-C5VTKIMK-tX-HO0L6.js +6 -0
  167. package/dist/web/assets/sl-SI-NN7IZMDC-Dy8vWC0s.js +6 -0
  168. package/dist/web/assets/src-BWF7jMDv.js +1 -0
  169. package/dist/web/assets/stateDiagram-D77RDMKH-CWDH4s-t.js +1 -0
  170. package/dist/web/assets/stateDiagram-v2-MP3YSRHH-DdSAvpNH.js +1 -0
  171. package/dist/web/assets/subset-shared.chunk-D1bYkpAa.js +1 -0
  172. package/dist/web/assets/subset-worker.chunk-CBZq9OSE.js +1 -0
  173. package/dist/web/assets/sv-SE-XGPEYMSR-D1ErsBn-.js +10 -0
  174. package/dist/web/assets/swimlanes-42K2YHIH-CM2OkOmc.js +1 -0
  175. package/dist/web/assets/swimlanesDiagram-VR7AAH4N-CVzVUDpQ.js +8 -0
  176. package/dist/web/assets/ta-IN-2NMHFXQM-PSu4eqYe.js +9 -0
  177. package/dist/web/assets/th-TH-HPSO5L25-BVu-PlXo.js +2 -0
  178. package/dist/web/assets/timeline-definition-24CTP7MA-Bo6sYnPJ.js +120 -0
  179. package/dist/web/assets/tr-TR-DEFEU3FU-BtC_O7fA.js +7 -0
  180. package/dist/web/assets/treeView-Q6P3EWNA-B3NS1SBg.js +1 -0
  181. package/dist/web/assets/treemap-WGGIJYW6-Du_VkW6s.js +1 -0
  182. package/dist/web/assets/uk-UA-QMV73CPH-RwWQcIwP.js +6 -0
  183. package/dist/web/assets/vennDiagram-4TSXK5OY-R1EH0pXq.js +34 -0
  184. package/dist/web/assets/vi-VN-M7AON7JQ-CUEI6eHH.js +5 -0
  185. package/dist/web/assets/wardley-WFR3VGLG-9B3cKl8K.js +1 -0
  186. package/dist/web/assets/wardleyDiagram-VM6X3IG4-XZ18gIOz.js +78 -0
  187. package/dist/web/assets/xychartDiagram-S5SC5T6Z-BLzXnvba.js +7 -0
  188. package/dist/web/assets/zh-CN-LNUGB5OW-C3asHvVp.js +10 -0
  189. package/dist/web/assets/zh-HK-E62DVLB3-BO6FsJfO.js +1 -0
  190. package/dist/web/assets/zh-TW-RAJ6MFWO-DGtaI2hh.js +9 -0
  191. package/dist/web/fonts/Assistant/Assistant-Bold.woff2 +0 -0
  192. package/dist/web/fonts/Assistant/Assistant-Medium.woff2 +0 -0
  193. package/dist/web/fonts/Assistant/Assistant-Regular.woff2 +0 -0
  194. package/dist/web/fonts/Assistant/Assistant-SemiBold.woff2 +0 -0
  195. package/dist/web/fonts/Cascadia/CascadiaCode-Regular.woff2 +0 -0
  196. package/dist/web/fonts/ComicShanns/ComicShanns-Regular-279a7b317d12eb88de06167bd672b4b4.woff2 +0 -0
  197. package/dist/web/fonts/ComicShanns/ComicShanns-Regular-6e066e8de2ac57ea9283adb9c24d7f0c.woff2 +0 -0
  198. package/dist/web/fonts/ComicShanns/ComicShanns-Regular-dc6a8806fa96795d7b3be5026f989a17.woff2 +0 -0
  199. package/dist/web/fonts/ComicShanns/ComicShanns-Regular-fcb0fc02dcbee4c9846b3e2508668039.woff2 +0 -0
  200. package/dist/web/fonts/Excalifont/Excalifont-Regular-349fac6ca4700ffec595a7150a0d1e1d.woff2 +0 -0
  201. package/dist/web/fonts/Excalifont/Excalifont-Regular-3f2c5db56cc93c5a6873b1361d730c16.woff2 +0 -0
  202. package/dist/web/fonts/Excalifont/Excalifont-Regular-41b173a47b57366892116a575a43e2b6.woff2 +0 -0
  203. package/dist/web/fonts/Excalifont/Excalifont-Regular-623ccf21b21ef6b3a0d87738f77eb071.woff2 +0 -0
  204. package/dist/web/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2 +0 -0
  205. package/dist/web/fonts/Excalifont/Excalifont-Regular-b9dcf9d2e50a1eaf42fc664b50a3fd0d.woff2 +0 -0
  206. package/dist/web/fonts/Excalifont/Excalifont-Regular-be310b9bcd4f1a43f571c46df7809174.woff2 +0 -0
  207. package/dist/web/fonts/Liberation/LiberationSans-Regular.woff2 +0 -0
  208. package/dist/web/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYE98RXi4EwSsbg.woff2 +0 -0
  209. package/dist/web/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYEF8RXi4EwQ.woff2 +0 -0
  210. package/dist/web/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2 +0 -0
  211. package/dist/web/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2 +0 -0
  212. package/dist/web/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2 +0 -0
  213. package/dist/web/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2 +0 -0
  214. package/dist/web/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2 +0 -0
  215. package/dist/web/fonts/Virgil/Virgil-Regular.woff2 +0 -0
  216. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-019d66dcad46dc156b162d267f981c20.woff2 +0 -0
  217. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-04b718e5623574919c8b0dea5f301444.woff2 +0 -0
  218. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-069e77aac84590e2e991d0a0176d34f2.woff2 +0 -0
  219. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-06c77b8c66e51ed6c63ccb502dd8b8af.woff2 +0 -0
  220. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-08e0dc436ad0ad61ba5558db0674d762.woff2 +0 -0
  221. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-093b9ef39a46ceae95a1df18a0a3a326.woff2 +0 -0
  222. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-095c169f3314805276f603a362766abd.woff2 +0 -0
  223. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-09850c4077f3fffe707905872e0e2460.woff2 +0 -0
  224. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-0986d134c05864f5025962eef9f994a0.woff2 +0 -0
  225. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-0b5d723fdc4e249c140f0909e87d03b4.woff2 +0 -0
  226. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-0f626226ba1272e832aea87bafd9720e.woff2 +0 -0
  227. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-0f7fb1e0d5015bb1371343153ecf7ce3.woff2 +0 -0
  228. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-0fa55a080fcd0f9dc2e0b0058b793df8.woff2 +0 -0
  229. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-0facdf1ea213ba40261022f5d5ed4493.woff2 +0 -0
  230. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-10a7ae9a371830a80c3d844acf1c02d7.woff2 +0 -0
  231. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-112c051027b2d766c19a519f6ee1f4f7.woff2 +0 -0
  232. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-11c345711937f0ba4b8f7b6b919c8440.woff2 +0 -0
  233. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-12b52b58eb3df36804b9a654ec9ee194.woff2 +0 -0
  234. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-13ae07ed2e272d26d59bc0691cd7117a.woff2 +0 -0
  235. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-13d2887ec8ee73c43acdabc52a05af7b.woff2 +0 -0
  236. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-145aa02cdd91946e67dc934e1acffe75.woff2 +0 -0
  237. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-15dc6d811c9cd078f9086a740d5a1038.woff2 +0 -0
  238. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-173945821411c09f70c95f98d590e697.woff2 +0 -0
  239. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-1b611157cd46bb184d4fa4dae2d6a2b8.woff2 +0 -0
  240. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-1e6fd68f1f3902ce48ce8c69df385622.woff2 +0 -0
  241. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-1ee544f0f1dac422545c505baa788992.woff2 +0 -0
  242. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-1fdc0c67ed57263a80fd108c1f6ccf24.woff2 +0 -0
  243. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-203b0e569e3b14aac86a003dc3fa523e.woff2 +0 -0
  244. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-20cc1bbf50e7efb442756cb605672c1f.woff2 +0 -0
  245. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-20e7bf72fa05de9adf7dbcc7bf51dde6.woff2 +0 -0
  246. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-21430ee05a1248901da8d0de08744d47.woff2 +0 -0
  247. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-23686f7f29da6e8008c36dd3a80c83d6.woff2 +0 -0
  248. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-23ad2d71b280f00b1363b95b7bea94eb.woff2 +0 -0
  249. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-23f228f3999c01983860012330e4be08.woff2 +0 -0
  250. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-24476a126f129212beb33f66853ea151.woff2 +0 -0
  251. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-24a21c1e4449222e8d1898d69ff3a404.woff2 +0 -0
  252. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-25b7f38e18f035f96cb5e547bd2bd08c.woff2 +0 -0
  253. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-29cec36cd205b211da97acabaa62f055.woff2 +0 -0
  254. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-2a26d20a23b00898ce82f09d2ee47c3f.woff2 +0 -0
  255. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-2adbc89c11e65905393d3dfc468b9d5b.woff2 +0 -0
  256. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-2b7441d46298788ac94e610ffcc709b6.woff2 +0 -0
  257. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-2b77e8ebfb2367ab2662396a60e7d320.woff2 +0 -0
  258. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-2cf96d082d35ea3d8106851223ad0d16.woff2 +0 -0
  259. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-2d43040e86ff03ba677f6f9c04cd0805.woff2 +0 -0
  260. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-2e33e8dc771ef5e1d9127d60a6b73679.woff2 +0 -0
  261. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-33432927cd87d40cfe393c7482bf221f.woff2 +0 -0
  262. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-353f33792a8f60dc69323ddf635a269e.woff2 +0 -0
  263. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-36925dfe329a45086cbb7fc5c20d45ac.woff2 +0 -0
  264. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-3717077e38f98d89eae729b6c14e56dc.woff2 +0 -0
  265. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-3756e81d3e149cf6099163ee79944fec.woff2 +0 -0
  266. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-395c35dd584b56b0789f58a0559beaf1.woff2 +0 -0
  267. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-3c9de2ae0ea4bc91a510942dfa4be8d2.woff2 +0 -0
  268. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-3cc70dbb64df5b21f1326cc24dee2195.woff2 +0 -0
  269. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-3e1f8f654357353bf0e04ba5c34b5f7f.woff2 +0 -0
  270. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-3e63ed8162808a9e425ed80a8bc79114.woff2 +0 -0
  271. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-3eaa538115d76932653c21d8dc28f207.woff2 +0 -0
  272. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-4095eb84ef3874e2600247bee0b04026.woff2 +0 -0
  273. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-41521fade99856108931b4768b1b2648.woff2 +0 -0
  274. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-450da755d5bcb70906e1295e559b9602.woff2 +0 -0
  275. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-452225341522a7942f0f6aab1a5c91a3.woff2 +0 -0
  276. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-4535823663ad81405188a528d8f2b1a2.woff2 +0 -0
  277. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-4806e761d750087c2d734fc64596eaff.woff2 +0 -0
  278. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-4a0fdb40036e87b40aa08dd30584cb85.woff2 +0 -0
  279. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-4a38cc3e9cf104e69ba246d37f8cf135.woff2 +0 -0
  280. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-4aca6a43e59aceee2166b0c7e4e85ef1.woff2 +0 -0
  281. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-4bfaa8ffa64c5ee560aa2daba7c9cbd3.woff2 +0 -0
  282. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-4dc6d5f188d5c96d44815cd1e81aa885.woff2 +0 -0
  283. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-4ddc14ed3eb0c3e46364317dfc0144a3.woff2 +0 -0
  284. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-4ee10ae43505e2e0bc62656ced49c0fa.woff2 +0 -0
  285. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-4f50e5136e136527280bc902c5817561.woff2 +0 -0
  286. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-51502f1206be09c565f1547c406e9558.woff2 +0 -0
  287. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-51a0e808bbc8361236ac521a119758a3.woff2 +0 -0
  288. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-52a84a22fd1369bffeaf21da2d6158dc.woff2 +0 -0
  289. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-5330a2119a716e4e7224ed108b085dac.woff2 +0 -0
  290. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-543fa46ace099a7099dad69123399400.woff2 +0 -0
  291. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-544fc28abe2c5c30e62383fd4dac255f.woff2 +0 -0
  292. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-54acdfc2166ad7fcbd074f75fd4a56ba.woff2 +0 -0
  293. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-5572b3513ba8df57a3d5d7303ee6b11b.woff2 +0 -0
  294. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-56467a5c8840c4d23a60b2f935114848.woff2 +0 -0
  295. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-56a32a7689abd0326e57c10c6c069bb4.woff2 +0 -0
  296. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-57862b464a55b18c7bf234ce22907d73.woff2 +0 -0
  297. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-583d166e56ba0de4b77eabb47ef67839.woff2 +0 -0
  298. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-5882ffa04f32584d26109137e2da4352.woff2 +0 -0
  299. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-58fd02350d0bc52cf1ca3bb32ce9766e.woff2 +0 -0
  300. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-5935a5775af3d5c6307ac667bd9ae74e.woff2 +0 -0
  301. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-59e9ff77b0efaf684bc09274fb6908c9.woff2 +0 -0
  302. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-5a1ce3117cfe90c48e8fb4a9a00f694d.woff2 +0 -0
  303. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-5a45d991244d4c7140217e1e5f5ca4f4.woff2 +0 -0
  304. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-5a7fac4b8b23a6e4e5ba0c9bf1756c91.woff2 +0 -0
  305. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-5b0ed6971aaab9c8ad563230bd5471a7.woff2 +0 -0
  306. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-5d2898fbc097a7e24c6f38d80587621e.woff2 +0 -0
  307. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-603aefd23e350ba7eb124273e3c9bcf1.woff2 +0 -0
  308. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-60a3089806700d379f11827ee9843b6b.woff2 +0 -0
  309. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-60a41c7e1c68f22424e6d22df544bc82.woff2 +0 -0
  310. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-642b26e2e5f5fb780b51b593dbc8c851.woff2 +0 -0
  311. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-66493ba5a8367f2928812f446f47b56a.woff2 +0 -0
  312. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-670ba603758d94268e8606f240a42e12.woff2 +0 -0
  313. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-671a2c20b1eb9e4ef8a192833940e319.woff2 +0 -0
  314. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-684d65f1793cac449dde5d59cb3c47fb.woff2 +0 -0
  315. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-69c09cc5fa3e55c74fc4821f76909cc3.woff2 +0 -0
  316. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-6ae5b42180ad70b971c91e7eefb8eba2.woff2 +0 -0
  317. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-6e092f71c1e634059ada0e52abadce67.woff2 +0 -0
  318. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-6f3256af8454371776bc46670d33cc65.woff2 +0 -0
  319. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-6fe5c5973cc06f74b2387a631ea36b88.woff2 +0 -0
  320. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-70c2eb8d64e71a42a834eb857ea9df51.woff2 +0 -0
  321. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-70e811fd7994e61f408c923de6ddd078.woff2 +0 -0
  322. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-7197d6fda6cba7c3874c53d6381ca239.woff2 +0 -0
  323. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-72252d73220fa3cd856677888cee1635.woff2 +0 -0
  324. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-72536a3d71b694a0d53dd90ddceae41e.woff2 +0 -0
  325. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-726303e0774b4e678bff8c2deb6ca603.woff2 +0 -0
  326. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-733171b4ffcd17ea1fe1c0ba627173bf.woff2 +0 -0
  327. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-739bc1a567439c7cffcd1614644593d2.woff2 +0 -0
  328. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-73e309718fd16cea44b4d54a33581811.woff2 +0 -0
  329. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-7494dc504ae00ee9cd0505f990f88c5d.woff2 +0 -0
  330. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-74e2263a91439c25b91d5132ce9f4d62.woff2 +0 -0
  331. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-761d05e3cd968cf574166867998ef06a.woff2 +0 -0
  332. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-7718fe60986d8b42b1be9c5ace5ccf25.woff2 +0 -0
  333. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-774d4f764a1299da5d28ec2f2ffe0d69.woff2 +0 -0
  334. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-79d494361ae093b69e74ee9dbe65bfd4.woff2 +0 -0
  335. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-79f007c1c6d07557120982951ea67998.woff2 +0 -0
  336. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-7a07ddc0f0c0f5f4a9bad6ee3dda66b5.woff2 +0 -0
  337. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-7ab2bed91166a9dca83a5ebfbe2a7f38.woff2 +0 -0
  338. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-7ccce86603f80a099ddb0cb21d4ae3e3.woff2 +0 -0
  339. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-7e4bde7e9c7f84cd34d8a845e384c746.woff2 +0 -0
  340. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-7e929f262f30c8ee78bf398150b1a7cd.woff2 +0 -0
  341. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-7eb9fffd1aa890d07d0f88cc82e6cfe4.woff2 +0 -0
  342. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-7f855356ab893b0d2b9c1c83b8116f0e.woff2 +0 -0
  343. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-829615148e6357d826b9242eb7fbbd1e.woff2 +0 -0
  344. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-866fa7613df6b3fd272bcfd4530c0bb9.woff2 +0 -0
  345. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-87599f94b6cc129d505b375798d0d751.woff2 +0 -0
  346. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-8c2f33cee3993174f7e87c28e4bf42ee.woff2 +0 -0
  347. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-8d3bcabb847b56243b16afe62adaaf21.woff2 +0 -0
  348. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-8de5b863cb50dfefdd07cb11c774d579.woff2 +0 -0
  349. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-8e9f97f01034820170065b2921b4fb5e.woff2 +0 -0
  350. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-8f476c4c99813d57cbe6eca4727388ad.woff2 +0 -0
  351. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-903bb6865f3452e2fda42e3a25547bc5.woff2 +0 -0
  352. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-91ddb2969bf2d31ba02ad82998d1314c.woff2 +0 -0
  353. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-938d90c10ff8c20386af7f242c05d6b0.woff2 +0 -0
  354. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-93fc8f28a33234bcadf1527cafabd502.woff2 +0 -0
  355. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-95429962233afd82db1c27df1500a28c.woff2 +0 -0
  356. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-9544732d2e62d1a429674f8ee41b5d3a.woff2 +0 -0
  357. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-9592bfc861f07bcb8d75c196b370e548.woff2 +0 -0
  358. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-95bfd249da4902577b4b7d76ebdd0b44.woff2 +0 -0
  359. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-968cffdc8ee679da094e77ebf50f58ef.woff2 +0 -0
  360. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-97f7f48ce90c9429bf32ae51469db74d.woff2 +0 -0
  361. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-982b630266d87db93d2539affb1275c6.woff2 +0 -0
  362. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-98f2ad84457de7f3740d9920b8fa8667.woff2 +0 -0
  363. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-99a16ef6a64934d5781933dbd9c46b2e.woff2 +0 -0
  364. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-9cfb2a77a4e45025105ad29a1748b90d.woff2 +0 -0
  365. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-9d81066dd2b337c938df6e90380a00dc.woff2 +0 -0
  366. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-9eb5a99df4e76ac3363453ac9ca288b1.woff2 +0 -0
  367. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-a004ddfcb26e67bd6e678c8ed19e25ce.woff2 +0 -0
  368. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-a0ca5df4258213d7fc9fce80f65ce760.woff2 +0 -0
  369. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-a1f916d6039285c4ffb900cd654e418f.woff2 +0 -0
  370. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-a203b91dad570bf05a58c3c3ddb529bf.woff2 +0 -0
  371. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-a365e82ed54697a52f27adcea1315fe8.woff2 +0 -0
  372. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-a4c34be6d42152e64b0df90bc4607f64.woff2 +0 -0
  373. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-a7accba310e821da5505f71c03b76bdb.woff2 +0 -0
  374. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-aa0d470430e6391eca720c7cfa44446f.woff2 +0 -0
  375. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-aa5c9ca6cf4fba00433b7aa3fa10671a.woff2 +0 -0
  376. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-ac9ceb44437becc3e9c4dbfebab7fc2d.woff2 +0 -0
  377. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-b1220a3c61f85cc0408deedb4c5f57a2.woff2 +0 -0
  378. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-b358f7a51ece39a3247942b1feabdb29.woff2 +0 -0
  379. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-b57aaedfd8ebdf3931f25119dc6a5eb2.woff2 +0 -0
  380. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-b5c1596551c256e0e9cf02028595b092.woff2 +0 -0
  381. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-b6d128682ee29e471486354d486a1b90.woff2 +0 -0
  382. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-b6fd38ca30869792244804b04bc058da.woff2 +0 -0
  383. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-b7d203b051eff504ff59ddca7576b6a9.woff2 +0 -0
  384. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-b96d9226ce77ec94ceca043d712182e6.woff2 +0 -0
  385. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-ba3de316d63c7e339987b16f41a0b879.woff2 +0 -0
  386. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-bafff7a14c27403dcc6cf1432e8ea836.woff2 +0 -0
  387. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-bd77e3c7f9e0b072d96af37f73d1aa32.woff2 +0 -0
  388. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-be549ab72f0719d606a5c01e2c0219b6.woff2 +0 -0
  389. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-c16ed9740b85badf16e86ea782a3062f.woff2 +0 -0
  390. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-c1f94158256bb1f3bf665b053d895af9.woff2 +0 -0
  391. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-c40533fdf4cc57177b12803598af7e59.woff2 +0 -0
  392. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-c4a687ac4f0c2766eefc9f77ed99cddf.woff2 +0 -0
  393. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-c69f61a4ab18d0488c8d1fc12e7028e8.woff2 +0 -0
  394. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-c8b71798409ccc126ee264a00aadcf21.woff2 +0 -0
  395. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-c99eda15fc26a2941579560f76c3a5cf.woff2 +0 -0
  396. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-cb17fc3db95f6d139afc9d31a8e93293.woff2 +0 -0
  397. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-cbaaefaaf326668277aa24dfa93c4d28.woff2 +0 -0
  398. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-cd145ce4a0ea18469358df53c207bc1b.woff2 +0 -0
  399. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-cdbce89e82cc1ab53a2decbf5819278f.woff2 +0 -0
  400. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-ce4884f96f11589608b76b726a755803.woff2 +0 -0
  401. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-cf2cc71752631e579e35b0e423bf2638.woff2 +0 -0
  402. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-cf6ff4e0f491ca0cf3038187a997b9b4.woff2 +0 -0
  403. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-cfb211578629b7e8153b37240de6a9d5.woff2 +0 -0
  404. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-d0cf73942fea1c74edbdf0b3011f4656.woff2 +0 -0
  405. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-d2666cbed13462c5dc36fa2f15c202ca.woff2 +0 -0
  406. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-d3716376641d615e2995605b29bca7b6.woff2 +0 -0
  407. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-dac48066b5883d8b4551fc584f0c2a3e.woff2 +0 -0
  408. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-dbea1af6dcd9860be40c3d18254338f5.woff2 +0 -0
  409. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-e11567fd2accf9957cd0d3c2be937d87.woff2 +0 -0
  410. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-e2ead7ea7da0437f085f42ffc05f8d13.woff2 +0 -0
  411. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-e3fcf5180fd466c8915c4e8069491054.woff2 +0 -0
  412. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-e480d9c614742d05f0e78f274f1e69e6.woff2 +0 -0
  413. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-e4bca6cfa53e499cae0a6be4894a90e9.woff2 +0 -0
  414. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-e51ef413167c6e14e0c0fdcc585f2fc9.woff2 +0 -0
  415. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-e5f453bb04da18eed01675eeebd88bf8.woff2 +0 -0
  416. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-e656f091b9dc4709722c9f4b84d3c797.woff2 +0 -0
  417. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-ec181b795ac1fb5a50d700b6e996d745.woff2 +0 -0
  418. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-ee8bae97908d5147b423f77ad0d3c1bb.woff2 +0 -0
  419. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-f0f13b5c60e0af5553bd359f5513be1b.woff2 +0 -0
  420. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-f2b54d4e7be0eaefe1c2c56836fa5368.woff2 +0 -0
  421. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-f56414bf9bced67990def8660e306759.woff2 +0 -0
  422. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-f5d079153c99a25b9be5b8583c4cc8a7.woff2 +0 -0
  423. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-f6032fc06eb20480f096199713f70885.woff2 +0 -0
  424. package/dist/web/fonts/Xiaolai/Xiaolai-Regular-f8ee5d36068a42b51d0e4a1116cfcec1.woff2 +0 -0
  425. package/dist/web/index.html +15 -0
  426. package/package.json +67 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Martin Popovski
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,91 @@
1
- # Temporary Holding Version
1
+ # excaliagent
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A spatial scratchboard for your Claude Code sessions, on an Excalidraw canvas.
4
+
5
+ Every session is a card. You drag cards wherever they make sense to you (parked,
6
+ blocked on a colleague, come back to, done) and draw anything around them. The
7
+ app keeps each card's **color and label** in sync with the session and never
8
+ moves, resizes, or edits anything else.
9
+
10
+ ```
11
+ Fix flaky checkout test ← title (handwritten, larger)
12
+ demo-app · fix/flaky ← repo · branch
13
+ needs user: input needed · 2m ← status · what it waits for · last activity
14
+ cache warm 41m ← prompt-cache warmth
15
+ herdr: demo-app › oauth ← herdr workspace › tab
16
+ PR #12 ← last PR link
17
+ ```
18
+
19
+ | Color | Meaning |
20
+ |---|---|
21
+ | red | needs you (input, permission, trust, blocked) |
22
+ | blue | busy |
23
+ | green | idle, prompt cache still warm: review it before it goes cold |
24
+ | grey | idle, cache cold |
25
+ | dashed, pale | dormant (not running) |
26
+
27
+ ## Run
28
+
29
+ ```sh
30
+ npx excaliagent
31
+ ```
32
+
33
+ It starts a server on `127.0.0.1` and opens the board in your browser.
34
+
35
+ - **Live sessions** appear in the *inbox* rectangle by themselves.
36
+ - **Dormant sessions** are added from the **Sessions** panel (top right).
37
+ - **Double-click a card** to jump to it: a live session focuses its
38
+ [herdr](https://herdr.dev) pane and raises the terminal window (Hyprland,
39
+ Sway). A dormant session is resumed with `claude --resume` in a new herdr
40
+ tab, in the workspace for that repo. Without herdr, the resume command is
41
+ copied instead.
42
+ - **Right-click a card** for an excaliagent section on top of the Excalidraw
43
+ menu: focus or resume, copy the resume command (with or without `cd`), open
44
+ the PR.
45
+ - A **PR link** (GitHub, Bitbucket, GitLab) shows on the card; the card's link
46
+ icon opens it.
47
+ - The board is saved to `$XDG_STATE_HOME/excaliagent/scene.json`
48
+ (default `~/.local/state/excaliagent/`).
49
+
50
+ Options: `--port`, `--no-open`, `--state-dir`, `--claude-dir`, `--no-herdr`, `--no-raise`.
51
+ See `npx excaliagent --help`.
52
+
53
+ ## Privacy and security
54
+
55
+ - Reads `~/.claude/sessions/*.json` and the transcript files under
56
+ `~/.claude/projects/` (only metadata lines: title, branch, timestamps, token
57
+ usage, PR links; never message content). Installs no hooks, writes nothing
58
+ outside its state directory.
59
+ - Listens on loopback only. A random token is put into the URL it opens and
60
+ exchanged for an HttpOnly cookie; every request needs it. Requests with a
61
+ foreign `Host` (DNS rebinding) or cross-origin writes are refused.
62
+ - Its only actions: focus a herdr pane, raise the terminal window, and start
63
+ `claude --resume <id>` in a new herdr pane. It never types into a running
64
+ session.
65
+
66
+ ## herdr (optional)
67
+
68
+ If [herdr](https://herdr.dev) is running, cards are linked to panes by matching
69
+ the session's process id to the pane's foreground process. No herdr
70
+ integration or plugin is needed. Tested with herdr 0.9.0 and its protocol 22.
71
+
72
+ ## Development
73
+
74
+ The repo ships a Nix flake with Node 24 and Chromium for the browser tests:
75
+
76
+ ```sh
77
+ direnv allow # or: nix develop
78
+ npm install
79
+ npm test # unit tests (vitest)
80
+ npm run test:e2e # browser tests (playwright) against a mock Claude home
81
+ npm run demo # the board with a seeded, synthetic set of sessions
82
+ npm run dev # server + Vite hot reload against your real ~/.claude
83
+ ```
84
+
85
+ Tests never read your real `~/.claude` or talk to your running herdr:
86
+ `test/mock-claude.ts` seeds a throwaway Claude home with dummy processes, and the
87
+ herdr tests start an isolated `herdr server` with its own temp home and socket.
88
+ A privacy test fails if any fixture contains this machine's home path or user
89
+ name.
90
+
91
+ Docs: [product](docs/product.md), [design](docs/design.md), [roadmap](docs/roadmap.md). Agents start at [AGENTS.md](AGENTS.md).
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../dist/server/cli.js";
@@ -0,0 +1,51 @@
1
+ import { parseArgs } from "node:util";
2
+ export const USAGE = `Usage: excaliagent [options]
3
+
4
+ A spatial Excalidraw board for your Claude Code sessions.
5
+
6
+ Options:
7
+ --port <n> Port on 127.0.0.1 (default: random free port)
8
+ --no-open Do not open the browser, just print the URL
9
+ --state-dir <dir> Where scene.json lives (default: $XDG_STATE_HOME/excaliagent)
10
+ --claude-dir <dir> Claude Code home (default: ~/.claude)
11
+ --no-herdr Do not link sessions to herdr panes
12
+ --no-raise Focus the herdr pane but do not raise its terminal window
13
+ --dev Serve the frontend through Vite with hot reload
14
+ -h, --help Show this help
15
+ -v, --version Show the version
16
+ `;
17
+ export function parseCliArgs(argv) {
18
+ const { values } = parseArgs({
19
+ args: argv,
20
+ strict: true,
21
+ allowNegative: true,
22
+ options: {
23
+ port: { type: "string" },
24
+ open: { type: "boolean", default: true },
25
+ dev: { type: "boolean", default: false },
26
+ herdr: { type: "boolean", default: true },
27
+ raise: { type: "boolean", default: true },
28
+ "state-dir": { type: "string" },
29
+ "claude-dir": { type: "string" },
30
+ help: { type: "boolean", short: "h", default: false },
31
+ version: { type: "boolean", short: "v", default: false },
32
+ },
33
+ });
34
+ let port = 0;
35
+ if (values.port !== undefined) {
36
+ port = Number(values.port);
37
+ if (!Number.isInteger(port) || port < 0 || port > 65535)
38
+ throw new Error(`invalid --port: ${values.port}`);
39
+ }
40
+ return {
41
+ port,
42
+ open: values.open,
43
+ dev: values.dev,
44
+ herdr: values.herdr,
45
+ raise: values.raise,
46
+ stateDir: values["state-dir"],
47
+ claudeDir: values["claude-dir"],
48
+ help: values.help,
49
+ version: values.version,
50
+ };
51
+ }
@@ -0,0 +1,99 @@
1
+ import { spawn } from "node:child_process";
2
+ import { randomBytes } from "node:crypto";
3
+ import { readFileSync } from "node:fs";
4
+ import { dirname, join } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { parseCliArgs, USAGE } from "./args.js";
7
+ import { createHub } from "./hub.js";
8
+ import { createAppServer } from "./http.js";
9
+ import { createDesktop } from "./desktop/desktop.js";
10
+ import { createHerdrLink, createNoPaneLink } from "./panes/herdr.js";
11
+ import { createSceneStore, defaultStateDir } from "./scene-store.js";
12
+ import { createClaudeSource } from "./sources/claude.js";
13
+ const here = dirname(fileURLToPath(import.meta.url));
14
+ // src/server or dist/server → package root
15
+ const root = join(here, "..", "..");
16
+ function openBrowser(url) {
17
+ const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
18
+ const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
19
+ try {
20
+ const child = spawn(cmd, args, { detached: true, stdio: "ignore" });
21
+ child.on("error", () => { });
22
+ child.unref();
23
+ }
24
+ catch {
25
+ // printing the URL is enough
26
+ }
27
+ }
28
+ async function main(args) {
29
+ const token = randomBytes(24).toString("base64url");
30
+ const source = createClaudeSource({ claudeDir: args.claudeDir });
31
+ const panes = args.herdr
32
+ ? createHerdrLink({ desktop: args.raise ? createDesktop({ env: process.env }) : undefined })
33
+ : createNoPaneLink();
34
+ const hub = createHub({ source, panes });
35
+ await hub.start();
36
+ const scenes = createSceneStore(args.stateDir ?? defaultStateDir());
37
+ let middleware;
38
+ let closeVite = async () => { };
39
+ const server = createAppServer({
40
+ hub,
41
+ scenes,
42
+ token,
43
+ webRoot: join(root, "dist", "web"),
44
+ get middleware() {
45
+ return middleware;
46
+ },
47
+ });
48
+ if (args.dev) {
49
+ const { createServer } = await import("vite");
50
+ const vite = await createServer({
51
+ configFile: join(root, "vite.config.ts"),
52
+ server: { middlewareMode: true, hmr: { server: server.server } },
53
+ appType: "spa",
54
+ });
55
+ middleware = vite.middlewares;
56
+ closeVite = () => vite.close();
57
+ }
58
+ await server.listen(args.port);
59
+ const url = `http://127.0.0.1:${server.port}/?token=${token}`;
60
+ console.log(`excaliagent ${args.dev ? "(dev) " : ""}listening on http://127.0.0.1:${server.port}`);
61
+ console.log(`scene: ${scenes.path}`);
62
+ console.log(`herdr: ${panes.available() ? "connected" : args.herdr ? "not running (will retry)" : "disabled"}`);
63
+ console.log(`open: ${url}`);
64
+ if (args.open)
65
+ openBrowser(url);
66
+ let stopping = false;
67
+ const stop = async () => {
68
+ if (stopping)
69
+ process.exit(1);
70
+ stopping = true;
71
+ hub.stop();
72
+ panes.close();
73
+ await closeVite();
74
+ await server.close();
75
+ process.exit(0);
76
+ };
77
+ process.on("SIGINT", stop);
78
+ process.on("SIGTERM", stop);
79
+ }
80
+ let args;
81
+ try {
82
+ args = parseCliArgs(process.argv.slice(2));
83
+ }
84
+ catch (err) {
85
+ console.error(`excaliagent: ${err.message}\n\n${USAGE}`);
86
+ process.exit(2);
87
+ }
88
+ if (args.help) {
89
+ console.log(USAGE);
90
+ }
91
+ else if (args.version) {
92
+ console.log(JSON.parse(readFileSync(join(root, "package.json"), "utf8")).version);
93
+ }
94
+ else {
95
+ main(args).catch((err) => {
96
+ console.error("excaliagent:", err);
97
+ process.exit(1);
98
+ });
99
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Raise the desktop window that hosts a process (e.g. the terminal running a
3
+ * herdr client), so focusing a pane also brings its terminal to the front.
4
+ *
5
+ * Walks each candidate pid's ancestors via /proc/<pid>/stat and focuses the
6
+ * first ancestor that owns a window. Supported: Hyprland (hyprctl) and Sway
7
+ * (swaymsg). Anything else is a no-op. Never throws.
8
+ */
9
+ import { execFile } from "node:child_process";
10
+ import { readFile } from "node:fs/promises";
11
+ import { join } from "node:path";
12
+ export const defaultExec = (file, args, opts) => new Promise((resolve, reject) => {
13
+ execFile(file, args, { timeout: opts.timeout, maxBuffer: 16 << 20, encoding: "utf8" }, (err, stdout) => {
14
+ if (err)
15
+ reject(err);
16
+ else
17
+ resolve({ stdout });
18
+ });
19
+ });
20
+ /** ppid from /proc/<pid>/stat; comm (field 2) may contain spaces and parens. */
21
+ export async function parentPid(procRoot, pid) {
22
+ try {
23
+ const stat = await readFile(join(procRoot, String(pid), "stat"), "utf8");
24
+ const rest = stat.slice(stat.lastIndexOf(")") + 1).trim().split(/\s+/);
25
+ const ppid = Number(rest[1]);
26
+ return Number.isInteger(ppid) && ppid > 0 ? ppid : undefined;
27
+ }
28
+ catch {
29
+ return undefined;
30
+ }
31
+ }
32
+ /** pid, then its parents up to (excluding) init. */
33
+ async function ancestry(procRoot, pid) {
34
+ const chain = [];
35
+ const seen = new Set();
36
+ let cur = pid;
37
+ while (cur !== undefined && cur > 1 && !seen.has(cur) && chain.length < 64) {
38
+ seen.add(cur);
39
+ chain.push(cur);
40
+ cur = await parentPid(procRoot, cur);
41
+ }
42
+ return chain;
43
+ }
44
+ function hyprland(exec, timeout) {
45
+ return {
46
+ async windows() {
47
+ const { stdout } = await exec("hyprctl", ["clients", "-j"], { timeout });
48
+ const out = new Map();
49
+ for (const c of JSON.parse(stdout)) {
50
+ if (typeof c.pid === "number" && typeof c.address === "string" && !out.has(c.pid))
51
+ out.set(c.pid, c.address);
52
+ }
53
+ return out;
54
+ },
55
+ async focus(address) {
56
+ await exec("hyprctl", ["dispatch", "focuswindow", `address:${address}`], { timeout });
57
+ },
58
+ };
59
+ }
60
+ function sway(exec, timeout) {
61
+ return {
62
+ async windows() {
63
+ const { stdout } = await exec("swaymsg", ["-t", "get_tree"], { timeout });
64
+ const out = new Map();
65
+ const walk = (n) => {
66
+ if (typeof n.pid === "number")
67
+ out.set(n.pid, String(n.pid));
68
+ for (const c of [...(n.nodes ?? []), ...(n.floating_nodes ?? [])])
69
+ walk(c);
70
+ };
71
+ walk(JSON.parse(stdout));
72
+ return out;
73
+ },
74
+ async focus(pid) {
75
+ await exec("swaymsg", [`[pid=${pid}]`, "focus"], { timeout });
76
+ },
77
+ };
78
+ }
79
+ export function createDesktop(opts = {}) {
80
+ const { env = process.env, exec = defaultExec, procRoot = "/proc", timeoutMs = 2000 } = opts;
81
+ const wm = env.HYPRLAND_INSTANCE_SIGNATURE
82
+ ? hyprland(exec, timeoutMs)
83
+ : env.SWAYSOCK
84
+ ? sway(exec, timeoutMs)
85
+ : undefined;
86
+ return {
87
+ async raise(pids) {
88
+ if (!wm || pids.length === 0)
89
+ return false;
90
+ try {
91
+ const windows = await wm.windows();
92
+ for (const pid of pids) {
93
+ for (const p of await ancestry(procRoot, pid)) {
94
+ const target = windows.get(p);
95
+ if (target !== undefined) {
96
+ await wm.focus(target);
97
+ return true;
98
+ }
99
+ }
100
+ }
101
+ }
102
+ catch {
103
+ // no compositor, timeout, bad output: just don't raise
104
+ }
105
+ return false;
106
+ },
107
+ };
108
+ }
@@ -0,0 +1,240 @@
1
+ import { createServer } from "node:http";
2
+ import { readFile, stat } from "node:fs/promises";
3
+ import { extname, join, normalize, sep } from "node:path";
4
+ import { timingSafeEqual } from "node:crypto";
5
+ import { SESSION_ID } from "./hub.js";
6
+ const COOKIE = "excaliagent_token";
7
+ const MAX_BODY = 50 * 1024 * 1024;
8
+ const TYPES = {
9
+ ".html": "text/html; charset=utf-8",
10
+ ".js": "text/javascript; charset=utf-8",
11
+ ".mjs": "text/javascript; charset=utf-8",
12
+ ".css": "text/css; charset=utf-8",
13
+ ".json": "application/json",
14
+ ".svg": "image/svg+xml",
15
+ ".png": "image/png",
16
+ ".ico": "image/x-icon",
17
+ ".woff2": "font/woff2",
18
+ ".woff": "font/woff",
19
+ ".ttf": "font/ttf",
20
+ ".wasm": "application/wasm",
21
+ };
22
+ class HttpError extends Error {
23
+ status;
24
+ constructor(status, message) {
25
+ super(message);
26
+ this.status = status;
27
+ }
28
+ }
29
+ function sameToken(a, b) {
30
+ if (!a)
31
+ return false;
32
+ const x = Buffer.from(a);
33
+ const y = Buffer.from(b);
34
+ return x.length === y.length && timingSafeEqual(x, y);
35
+ }
36
+ function cookieToken(req) {
37
+ for (const part of (req.headers.cookie ?? "").split(";")) {
38
+ const [k, ...v] = part.trim().split("=");
39
+ if (k === COOKIE)
40
+ return v.join("=");
41
+ }
42
+ return undefined;
43
+ }
44
+ function json(res, status, body) {
45
+ res.writeHead(status, { "content-type": "application/json", "cache-control": "no-store" });
46
+ res.end(JSON.stringify(body));
47
+ }
48
+ function text(res, status, body) {
49
+ res.writeHead(status, { "content-type": "text/plain; charset=utf-8" });
50
+ res.end(body);
51
+ }
52
+ async function readJson(req) {
53
+ if (!(req.headers["content-type"] ?? "").startsWith("application/json")) {
54
+ throw new HttpError(415, "expected application/json");
55
+ }
56
+ const chunks = [];
57
+ let size = 0;
58
+ for await (const chunk of req) {
59
+ size += chunk.length;
60
+ if (size > MAX_BODY)
61
+ throw new HttpError(413, "body too large");
62
+ chunks.push(chunk);
63
+ }
64
+ try {
65
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
66
+ }
67
+ catch {
68
+ throw new HttpError(400, "invalid JSON");
69
+ }
70
+ }
71
+ export function createAppServer(opts) {
72
+ const host = opts.host ?? "127.0.0.1";
73
+ let port = 0;
74
+ const allowedHosts = () => new Set([`${host}:${port}`, `127.0.0.1:${port}`, `localhost:${port}`]);
75
+ const allowedOrigins = () => new Set([...allowedHosts()].map((h) => `http://${h}`));
76
+ async function serveStatic(req, res, pathname) {
77
+ const root = opts.webRoot;
78
+ if (!root)
79
+ return text(res, 404, "not found");
80
+ let rel;
81
+ try {
82
+ rel = decodeURIComponent(pathname);
83
+ }
84
+ catch {
85
+ return text(res, 400, "bad path");
86
+ }
87
+ if (rel === "/" || rel === "")
88
+ rel = "/index.html";
89
+ const file = normalize(join(root, rel));
90
+ if (!file.startsWith(normalize(root) + sep))
91
+ return text(res, 404, "not found");
92
+ try {
93
+ if (!(await stat(file)).isFile())
94
+ return text(res, 404, "not found");
95
+ const body = await readFile(file);
96
+ res.writeHead(200, {
97
+ "content-type": TYPES[extname(file)] ?? "application/octet-stream",
98
+ "cache-control": rel.startsWith("/assets/") ? "public, max-age=31536000, immutable" : "no-store",
99
+ });
100
+ res.end(req.method === "HEAD" ? undefined : body);
101
+ }
102
+ catch {
103
+ text(res, 404, "not found");
104
+ }
105
+ }
106
+ function events(req, res) {
107
+ res.writeHead(200, {
108
+ "content-type": "text/event-stream",
109
+ "cache-control": "no-store",
110
+ connection: "keep-alive",
111
+ });
112
+ const send = (sessions) => res.write(`event: sessions\ndata: ${JSON.stringify(sessions)}\n\n`);
113
+ send(opts.hub.sessions());
114
+ const unsubscribe = opts.hub.subscribe(send);
115
+ const heartbeat = setInterval(() => res.write(": ping\n\n"), 25_000);
116
+ req.on("close", () => {
117
+ clearInterval(heartbeat);
118
+ unsubscribe();
119
+ });
120
+ }
121
+ async function api(req, res, pathname) {
122
+ const route = `${req.method} ${pathname}`;
123
+ switch (route) {
124
+ case "GET /api/sessions":
125
+ return json(res, 200, opts.hub.sessions());
126
+ case "GET /api/events":
127
+ return events(req, res);
128
+ case "GET /api/picker":
129
+ return json(res, 200, await opts.hub.picker());
130
+ case "POST /api/lookup": {
131
+ const body = (await readJson(req));
132
+ if (!Array.isArray(body?.ids) || !body.ids.every((i) => typeof i === "string")) {
133
+ throw new HttpError(400, "ids must be a string array");
134
+ }
135
+ return json(res, 200, await opts.hub.lookup(body.ids));
136
+ }
137
+ case "GET /api/scene":
138
+ return json(res, 200, await opts.scenes.load());
139
+ case "PUT /api/scene": {
140
+ const body = (await readJson(req));
141
+ if (!body || !Array.isArray(body.elements))
142
+ throw new HttpError(400, "elements must be an array");
143
+ const appState = body.appState && typeof body.appState === "object" ? body.appState : {};
144
+ await opts.scenes.save({ elements: body.elements, appState: appState });
145
+ res.writeHead(204).end();
146
+ return;
147
+ }
148
+ case "POST /api/focus": {
149
+ const body = (await readJson(req));
150
+ if (typeof body?.sessionId !== "string")
151
+ throw new HttpError(400, "sessionId required");
152
+ if (await opts.hub.focus(body.sessionId)) {
153
+ res.writeHead(204).end();
154
+ return;
155
+ }
156
+ return json(res, 409, { error: "no pane" });
157
+ }
158
+ case "POST /api/resume": {
159
+ const body = (await readJson(req));
160
+ if (typeof body?.sessionId !== "string" || !SESSION_ID.test(body.sessionId)) {
161
+ throw new HttpError(400, "sessionId must be a session UUID");
162
+ }
163
+ const result = await opts.hub.resume(body.sessionId);
164
+ if (result === "resumed") {
165
+ res.writeHead(204).end();
166
+ return;
167
+ }
168
+ if (result === "unknown")
169
+ return json(res, 404, { error: "unknown session" });
170
+ return json(res, 409, { error: result === "live" ? "live" : "no herdr" });
171
+ }
172
+ default:
173
+ return json(res, 404, { error: "not found" });
174
+ }
175
+ }
176
+ async function handle(req, res) {
177
+ if (!allowedHosts().has(req.headers.host ?? ""))
178
+ return text(res, 421, "unexpected Host header");
179
+ const url = new URL(req.url ?? "/", "http://localhost");
180
+ const method = req.method ?? "GET";
181
+ if (method !== "GET" && method !== "HEAD") {
182
+ const origin = req.headers.origin;
183
+ if (origin !== undefined && !allowedOrigins().has(origin))
184
+ return text(res, 403, "cross-origin request");
185
+ }
186
+ const queryToken = url.searchParams.get("token");
187
+ if (queryToken !== null && method === "GET" && !url.pathname.startsWith("/api/")) {
188
+ if (!sameToken(queryToken, opts.token))
189
+ return text(res, 401, "bad token");
190
+ res.writeHead(302, {
191
+ location: "/",
192
+ "set-cookie": `${COOKIE}=${opts.token}; HttpOnly; SameSite=Strict; Path=/`,
193
+ });
194
+ res.end();
195
+ return;
196
+ }
197
+ if (!sameToken(cookieToken(req), opts.token)) {
198
+ return text(res, 401, "excaliagent: open the URL printed in the terminal (it carries the access token).");
199
+ }
200
+ if (url.pathname.startsWith("/api/"))
201
+ return api(req, res, url.pathname);
202
+ if (opts.middleware)
203
+ return opts.middleware(req, res, () => text(res, 404, "not found"));
204
+ return serveStatic(req, res, url.pathname);
205
+ }
206
+ const server = createServer((req, res) => {
207
+ handle(req, res).catch((err) => {
208
+ const status = err instanceof HttpError ? err.status : 500;
209
+ if (status === 500)
210
+ console.error("excaliagent:", err);
211
+ if (!res.headersSent)
212
+ json(res, status, { error: err.message });
213
+ else
214
+ res.end();
215
+ });
216
+ });
217
+ return {
218
+ server,
219
+ get port() {
220
+ return port;
221
+ },
222
+ listen(p) {
223
+ return new Promise((resolve, reject) => {
224
+ server.once("error", reject);
225
+ server.listen(p, host, () => {
226
+ server.off("error", reject);
227
+ const addr = server.address();
228
+ port = typeof addr === "object" && addr ? addr.port : p;
229
+ resolve();
230
+ });
231
+ });
232
+ },
233
+ close() {
234
+ return new Promise((resolve) => {
235
+ server.close(() => resolve());
236
+ server.closeAllConnections();
237
+ });
238
+ },
239
+ };
240
+ }