@youweichen/pi-harness 0.0.0-stage → 1.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 (456) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +74 -2
  3. package/bin/pi-harness.mjs +1819 -0
  4. package/deploy/com.youweichen.pi-harness.plist +48 -0
  5. package/deploy/nginx-subpath.conf +88 -0
  6. package/deploy/pi-harness-task.xml +71 -0
  7. package/deploy/pi-harness.service +31 -0
  8. package/dist/server/agent-service.js +3131 -0
  9. package/dist/server/app-version.js +19 -0
  10. package/dist/server/attachments.js +526 -0
  11. package/dist/server/auth-file.js +61 -0
  12. package/dist/server/bg-servers.js +154 -0
  13. package/dist/server/client-eviction.js +19 -0
  14. package/dist/server/client-id.js +9 -0
  15. package/dist/server/client-state.js +202 -0
  16. package/dist/server/codemode-image-routes.js +36 -0
  17. package/dist/server/codemode-presentation.js +19 -0
  18. package/dist/server/component-updates.js +135 -0
  19. package/dist/server/context-breakdown.js +56 -0
  20. package/dist/server/control-socket.js +178 -0
  21. package/dist/server/conversation.js +65 -0
  22. package/dist/server/dir-browser.js +77 -0
  23. package/dist/server/editor-snapshot.js +38 -0
  24. package/dist/server/ensure-bash.js +80 -0
  25. package/dist/server/extension-display.js +23 -0
  26. package/dist/server/extensions-catalog.js +64 -0
  27. package/dist/server/extensions-model.js +46 -0
  28. package/dist/server/extensions-routes.js +255 -0
  29. package/dist/server/extensions-worker.js +188 -0
  30. package/dist/server/files-service.js +787 -0
  31. package/dist/server/index.js +1033 -0
  32. package/dist/server/markdown-images.js +42 -0
  33. package/dist/server/model-admin.js +801 -0
  34. package/dist/server/model-config-merge.js +32 -0
  35. package/dist/server/native-mcp-config.js +103 -0
  36. package/dist/server/native-mcp-presentation.js +12 -0
  37. package/dist/server/native-prompt-template.js +12 -0
  38. package/dist/server/native-tools.js +32 -0
  39. package/dist/server/node-agent.js +262 -0
  40. package/dist/server/node-sources.js +142 -0
  41. package/dist/server/node-workbench.js +729 -0
  42. package/dist/server/origin-policy.js +50 -0
  43. package/dist/server/patch-node-pty.js +96 -0
  44. package/dist/server/pi-environment.js +203 -0
  45. package/dist/server/plan/extension.js +74 -0
  46. package/dist/server/plan/progress.js +90 -0
  47. package/dist/server/plan/settings.js +41 -0
  48. package/dist/server/plan/state.js +123 -0
  49. package/dist/server/plugin-facilities.js +304 -0
  50. package/dist/server/plugin-updater.js +245 -0
  51. package/dist/server/plugins.js +712 -0
  52. package/dist/server/private-file.js +28 -0
  53. package/dist/server/process-utils.js +112 -0
  54. package/dist/server/prompt-delivery.js +80 -0
  55. package/dist/server/protocol-version.js +11 -0
  56. package/dist/server/protocol.js +6 -0
  57. package/dist/server/provider-auth.js +99 -0
  58. package/dist/server/query-cache.js +45 -0
  59. package/dist/server/recovery-state.js +37 -0
  60. package/dist/server/scm.js +459 -0
  61. package/dist/server/security-headers.js +24 -0
  62. package/dist/server/serialize.js +254 -0
  63. package/dist/server/session-file-read.js +225 -0
  64. package/dist/server/session-record-worker.js +21 -0
  65. package/dist/server/session-reload.js +13 -0
  66. package/dist/server/session-tree-controller.js +250 -0
  67. package/dist/server/session-tree.js +191 -0
  68. package/dist/server/settings-service.js +53 -0
  69. package/dist/server/skills-service.js +87 -0
  70. package/dist/server/slash-commands.js +286 -0
  71. package/dist/server/sqlite-preview.js +58 -0
  72. package/dist/server/sqlite-query.js +67 -0
  73. package/dist/server/sqlite-worker.js +12 -0
  74. package/dist/server/system-prompt-files.js +158 -0
  75. package/dist/server/system-prompt-routes.js +40 -0
  76. package/dist/server/system-prompt-view.js +49 -0
  77. package/dist/server/task-progress.js +233 -0
  78. package/dist/server/terminals.js +833 -0
  79. package/dist/server/text-sniff.js +269 -0
  80. package/dist/server/thinking-timing.js +91 -0
  81. package/dist/server/token-auth.js +37 -0
  82. package/dist/server/tool-output.js +97 -0
  83. package/dist/server/tool-text-incidents.js +82 -0
  84. package/dist/server/tool-text.js +67 -0
  85. package/dist/server/uploads.js +112 -0
  86. package/dist/server/user-attachments.js +96 -0
  87. package/dist/server/webui-context.js +257 -0
  88. package/dist/server/wiki-links.js +136 -0
  89. package/dist/server/wiki-pdf-worker.js +23 -0
  90. package/dist/server/wiki-pdf.js +36 -0
  91. package/dist/server/wiki-routes.js +184 -0
  92. package/dist/server/wiki-service.js +524 -0
  93. package/electron/main.mjs +607 -0
  94. package/extensions/webui.ts +192 -0
  95. package/package.json +122 -4
  96. package/web/dist/apple-touch-icon.png +0 -0
  97. package/web/dist/assets/NodeWorkbench-BiP2ktQP.js +3 -0
  98. package/web/dist/assets/TerminalPanel-CKaSUsN-.js +2 -0
  99. package/web/dist/assets/abnfDiagram-VCTEODGH-CnwRJDRL.js +1 -0
  100. package/web/dist/assets/arc-CG4Q7-W_.js +1 -0
  101. package/web/dist/assets/architectureDiagram-5GKGNRK7-BrGqX_Rg.js +36 -0
  102. package/web/dist/assets/blockDiagram-I7D4REHJ-C2t0PjZT.js +129 -0
  103. package/web/dist/assets/c4Diagram-7LVT6UL2-CadrcgGL.js +38 -0
  104. package/web/dist/assets/channel-C27Jizb6.js +1 -0
  105. package/web/dist/assets/chunk-2Q5K7J3B-CC3V2ITZ.js +1 -0
  106. package/web/dist/assets/chunk-5VM5RSS4-DqKSbGmE.js +15 -0
  107. package/web/dist/assets/chunk-F27PBJKO-_CDr3JbY.js +1 -0
  108. package/web/dist/assets/chunk-IMKFNOWR-BIR4H4fX.js +231 -0
  109. package/web/dist/assets/chunk-JWPE2WC7-CrsdBGXT.js +1 -0
  110. package/web/dist/assets/chunk-POPQ4Y6H-C6q9kQmf.js +1 -0
  111. package/web/dist/assets/chunk-SVP7TREG-l2XXTr2v.js +88 -0
  112. package/web/dist/assets/chunk-TICWLB2K-29I_mZgB.js +206 -0
  113. package/web/dist/assets/chunk-XXDRQBXY-htV9FBqi.js +1 -0
  114. package/web/dist/assets/classDiagram-ZZMXUADV-DYTBrAEP.js +1 -0
  115. package/web/dist/assets/classDiagram-v2-VYDZK3BY-DYTBrAEP.js +1 -0
  116. package/web/dist/assets/cose-bilkent-JH36ORCC-Cop-ihyx.js +1 -0
  117. package/web/dist/assets/cynefin-OW5HDTMX-IEk8qBRq.js +178 -0
  118. package/web/dist/assets/cynefinDiagram-5FMLGOSQ-Bmzt6Qb5.js +62 -0
  119. package/web/dist/assets/cytoscape.esm-Bch-eiPH.js +331 -0
  120. package/web/dist/assets/dagre-GXQ25YYZ-DiXTJYYU.js +4 -0
  121. package/web/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  122. package/web/dist/assets/diagram-S7CK7UJ4-BT7CLuNk.js +30 -0
  123. package/web/dist/assets/diagram-UQ7AKVKN-BZZ3nTCO.js +41 -0
  124. package/web/dist/assets/diagram-VSXAHHWV-Dal8LeZh.js +3 -0
  125. package/web/dist/assets/diagram-VX7I27RA-D6V9FfNA.js +24 -0
  126. package/web/dist/assets/diagram-Z3DM3KII-KUAIcFiD.js +24 -0
  127. package/web/dist/assets/ebnfDiagram-PWID7BFC-s0FEPZrV.js +1 -0
  128. package/web/dist/assets/erDiagram-RLTQ6QDP-CiIQPFCD.js +99 -0
  129. package/web/dist/assets/flowDiagram-HODETNUW-CvG4MYWn.js +168 -0
  130. package/web/dist/assets/ganttDiagram-EL5Y4UJY-CUf115ii.js +292 -0
  131. package/web/dist/assets/gitGraphDiagram-WWUBYQGX-o3K1r6fL.js +106 -0
  132. package/web/dist/assets/index-C3vDFSEV.css +10 -0
  133. package/web/dist/assets/index-C5or_GAq.js +276 -0
  134. package/web/dist/assets/infoDiagram-27XIBGKW-BxiBeQ8E.js +2 -0
  135. package/web/dist/assets/init-Gi6I4Gst.js +1 -0
  136. package/web/dist/assets/ishikawaDiagram-5VMMS53U-B1ONuCkH.js +70 -0
  137. package/web/dist/assets/journeyDiagram-3NMN7TZE-DwmuoXcX.js +139 -0
  138. package/web/dist/assets/kanban-definition-UXKFOSKX-pMKHubxH.js +89 -0
  139. package/web/dist/assets/katex-C5jXJg4s.js +257 -0
  140. package/web/dist/assets/layout-CEwfjQR0.js +1 -0
  141. package/web/dist/assets/linear-D22Gdbt1.js +1 -0
  142. package/web/dist/assets/markdown-BhJ_LInD.js +51 -0
  143. package/web/dist/assets/mermaid.core-CO2nrD04.js +312 -0
  144. package/web/dist/assets/mindmap-definition-YA3MSWOX-9MQn9ZAp.js +96 -0
  145. package/web/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  146. package/web/dist/assets/pegDiagram-XKGWAZYB-Dy6fLjM-.js +1 -0
  147. package/web/dist/assets/pieDiagram-E7YTZNPT-EDLez6nA.js +39 -0
  148. package/web/dist/assets/quadrantDiagram-AXDQQJYC-Cgcd9mvy.js +7 -0
  149. package/web/dist/assets/railroadDiagram-O6MQD6OU-B4Td0tjj.js +1 -0
  150. package/web/dist/assets/react-BddUxV-9.js +24 -0
  151. package/web/dist/assets/requirementDiagram-BXWQKSXE-aF2QNZ78.js +84 -0
  152. package/web/dist/assets/sankeyDiagram-P5KCCOFB-DgTYwYMa.js +40 -0
  153. package/web/dist/assets/sequenceDiagram-WJ2MYXX4-EUcddWUc.js +162 -0
  154. package/web/dist/assets/sizeCapture-INFHLROL-CXHOv9Sx.js +1 -0
  155. package/web/dist/assets/stateDiagram-D77RDMKH-B-xlgfaK.js +1 -0
  156. package/web/dist/assets/stateDiagram-v2-MP3YSRHH-kwAwAlWX.js +1 -0
  157. package/web/dist/assets/swimlanes-42K2YHIH-BtFBOCDh.js +1 -0
  158. package/web/dist/assets/swimlanesDiagram-VR7AAH4N-D5j5Cj3S.js +8 -0
  159. package/web/dist/assets/timeline-definition-24CTP7MA-CZlQY6pb.js +120 -0
  160. package/web/dist/assets/vennDiagram-4TSXK5OY-Cn61dJvL.js +34 -0
  161. package/web/dist/assets/wardleyDiagram-VM6X3IG4-fiMNrWpr.js +78 -0
  162. package/web/dist/assets/xterm-6GBZ9nXN.css +32 -0
  163. package/web/dist/assets/xterm-D1D2FVe3.js +38 -0
  164. package/web/dist/assets/xychartDiagram-S5SC5T6Z-CuzM_sof.js +7 -0
  165. package/web/dist/brand-mark.svg +5 -0
  166. package/web/dist/favicon-32.png +0 -0
  167. package/web/dist/favicon.svg +5 -0
  168. package/web/dist/fonts/WIKI-FONTS.md +5 -0
  169. package/web/dist/fonts/ibm-plex-mono/ibm-plex-mono-latin-400-normal.woff2 +0 -0
  170. package/web/dist/fonts/ibm-plex-mono/ibm-plex-mono-latin-500-normal.woff2 +0 -0
  171. package/web/dist/fonts/ibm-plex-mono/ibm-plex-mono-latin-600-normal.woff2 +0 -0
  172. package/web/dist/fonts/ibm-plex-mono/ibm-plex-mono-latin-ext-400-normal.woff2 +0 -0
  173. package/web/dist/fonts/ibm-plex-mono/ibm-plex-mono-latin-ext-500-normal.woff2 +0 -0
  174. package/web/dist/fonts/ibm-plex-mono/ibm-plex-mono-latin-ext-600-normal.woff2 +0 -0
  175. package/web/dist/fonts/ibm-plex-sans/LICENSE +93 -0
  176. package/web/dist/fonts/ibm-plex-sans/ibm-plex-sans-latin-400-normal.woff2 +0 -0
  177. package/web/dist/fonts/ibm-plex-sans/ibm-plex-sans-latin-500-normal.woff2 +0 -0
  178. package/web/dist/fonts/ibm-plex-sans/ibm-plex-sans-latin-600-normal.woff2 +0 -0
  179. package/web/dist/fonts/ibm-plex-sans/ibm-plex-sans-latin-ext-400-normal.woff2 +0 -0
  180. package/web/dist/fonts/ibm-plex-sans/ibm-plex-sans-latin-ext-500-normal.woff2 +0 -0
  181. package/web/dist/fonts/ibm-plex-sans/ibm-plex-sans-latin-ext-600-normal.woff2 +0 -0
  182. package/web/dist/fonts/inter/inter-latin-400-normal.woff2 +0 -0
  183. package/web/dist/fonts/inter/inter-latin-500-normal.woff2 +0 -0
  184. package/web/dist/fonts/inter/inter-latin-600-normal.woff2 +0 -0
  185. package/web/dist/fonts/inter/inter-latin-700-normal.woff2 +0 -0
  186. package/web/dist/fonts/inter/inter-latin-800-normal.woff2 +0 -0
  187. package/web/dist/fonts/inter/inter-latin-ext-400-normal.woff2 +0 -0
  188. package/web/dist/fonts/inter/inter-latin-ext-500-normal.woff2 +0 -0
  189. package/web/dist/fonts/inter/inter-latin-ext-600-normal.woff2 +0 -0
  190. package/web/dist/fonts/inter/inter-latin-ext-700-normal.woff2 +0 -0
  191. package/web/dist/fonts/inter/inter-latin-ext-800-normal.woff2 +0 -0
  192. package/web/dist/fonts/jetbrains-mono/LICENSE +93 -0
  193. package/web/dist/fonts/jetbrains-mono/jetbrains-mono-latin-400-normal.woff2 +0 -0
  194. package/web/dist/fonts/jetbrains-mono/jetbrains-mono-latin-500-normal.woff2 +0 -0
  195. package/web/dist/fonts/jetbrains-mono/jetbrains-mono-latin-600-normal.woff2 +0 -0
  196. package/web/dist/fonts/jetbrains-mono/jetbrains-mono-latin-ext-400-normal.woff2 +0 -0
  197. package/web/dist/fonts/jetbrains-mono/jetbrains-mono-latin-ext-500-normal.woff2 +0 -0
  198. package/web/dist/fonts/jetbrains-mono/jetbrains-mono-latin-ext-600-normal.woff2 +0 -0
  199. package/web/dist/fonts/noto-serif-sc/LICENSE +94 -0
  200. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-0.woff2 +0 -0
  201. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-1.woff2 +0 -0
  202. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-10.woff2 +0 -0
  203. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-100.woff2 +0 -0
  204. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-11.woff2 +0 -0
  205. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-12.woff2 +0 -0
  206. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-13.woff2 +0 -0
  207. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-14.woff2 +0 -0
  208. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-15.woff2 +0 -0
  209. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-16.woff2 +0 -0
  210. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-17.woff2 +0 -0
  211. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-18.woff2 +0 -0
  212. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-19.woff2 +0 -0
  213. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-2.woff2 +0 -0
  214. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-20.woff2 +0 -0
  215. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-21.woff2 +0 -0
  216. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-22.woff2 +0 -0
  217. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-23.woff2 +0 -0
  218. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-24.woff2 +0 -0
  219. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-25.woff2 +0 -0
  220. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-26.woff2 +0 -0
  221. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-27.woff2 +0 -0
  222. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-28.woff2 +0 -0
  223. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-29.woff2 +0 -0
  224. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-3.woff2 +0 -0
  225. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-30.woff2 +0 -0
  226. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-31.woff2 +0 -0
  227. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-32.woff2 +0 -0
  228. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-33.woff2 +0 -0
  229. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-34.woff2 +0 -0
  230. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-35.woff2 +0 -0
  231. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-36.woff2 +0 -0
  232. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-37.woff2 +0 -0
  233. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-38.woff2 +0 -0
  234. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-39.woff2 +0 -0
  235. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-4.woff2 +0 -0
  236. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-40.woff2 +0 -0
  237. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-41.woff2 +0 -0
  238. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-42.woff2 +0 -0
  239. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-43.woff2 +0 -0
  240. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-44.woff2 +0 -0
  241. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-45.woff2 +0 -0
  242. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-46.woff2 +0 -0
  243. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-47.woff2 +0 -0
  244. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-48.woff2 +0 -0
  245. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-49.woff2 +0 -0
  246. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-5.woff2 +0 -0
  247. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-50.woff2 +0 -0
  248. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-51.woff2 +0 -0
  249. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-52.woff2 +0 -0
  250. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-53.woff2 +0 -0
  251. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-54.woff2 +0 -0
  252. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-55.woff2 +0 -0
  253. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-56.woff2 +0 -0
  254. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-57.woff2 +0 -0
  255. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-58.woff2 +0 -0
  256. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-59.woff2 +0 -0
  257. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-6.woff2 +0 -0
  258. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-60.woff2 +0 -0
  259. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-61.woff2 +0 -0
  260. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-62.woff2 +0 -0
  261. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-63.woff2 +0 -0
  262. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-64.woff2 +0 -0
  263. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-65.woff2 +0 -0
  264. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-66.woff2 +0 -0
  265. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-67.woff2 +0 -0
  266. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-68.woff2 +0 -0
  267. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-69.woff2 +0 -0
  268. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-7.woff2 +0 -0
  269. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-70.woff2 +0 -0
  270. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-71.woff2 +0 -0
  271. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-72.woff2 +0 -0
  272. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-73.woff2 +0 -0
  273. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-74.woff2 +0 -0
  274. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-75.woff2 +0 -0
  275. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-76.woff2 +0 -0
  276. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-77.woff2 +0 -0
  277. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-78.woff2 +0 -0
  278. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-79.woff2 +0 -0
  279. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-8.woff2 +0 -0
  280. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-80.woff2 +0 -0
  281. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-81.woff2 +0 -0
  282. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-82.woff2 +0 -0
  283. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-83.woff2 +0 -0
  284. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-84.woff2 +0 -0
  285. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-85.woff2 +0 -0
  286. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-86.woff2 +0 -0
  287. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-87.woff2 +0 -0
  288. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-88.woff2 +0 -0
  289. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-89.woff2 +0 -0
  290. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-9.woff2 +0 -0
  291. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-90.woff2 +0 -0
  292. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-91.woff2 +0 -0
  293. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-92.woff2 +0 -0
  294. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-93.woff2 +0 -0
  295. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-94.woff2 +0 -0
  296. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-95.woff2 +0 -0
  297. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-96.woff2 +0 -0
  298. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-97.woff2 +0 -0
  299. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-98.woff2 +0 -0
  300. package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-99.woff2 +0 -0
  301. package/web/dist/fonts/source-serif-4/LICENSE +93 -0
  302. package/web/dist/fonts/source-serif-4/source-serif-4-500-0.woff2 +0 -0
  303. package/web/dist/fonts/source-serif-4/source-serif-4-500-1.woff2 +0 -0
  304. package/web/dist/fonts/source-serif-4/source-serif-4-500-2.woff2 +0 -0
  305. package/web/dist/fonts/source-serif-4/source-serif-4-500-3.woff2 +0 -0
  306. package/web/dist/fonts/source-serif-4/source-serif-4-500-4.woff2 +0 -0
  307. package/web/dist/fonts/source-serif-4/source-serif-4-500-5.woff2 +0 -0
  308. package/web/dist/icon/1a-mark.svg +1 -0
  309. package/web/dist/icon.ico +0 -0
  310. package/web/dist/index.html +18 -0
  311. package/web/public/apple-touch-icon.png +0 -0
  312. package/web/public/brand-mark.svg +5 -0
  313. package/web/public/favicon-32.png +0 -0
  314. package/web/public/favicon.svg +5 -0
  315. package/web/public/fonts/WIKI-FONTS.md +5 -0
  316. package/web/public/fonts/ibm-plex-mono/ibm-plex-mono-latin-400-normal.woff2 +0 -0
  317. package/web/public/fonts/ibm-plex-mono/ibm-plex-mono-latin-500-normal.woff2 +0 -0
  318. package/web/public/fonts/ibm-plex-mono/ibm-plex-mono-latin-600-normal.woff2 +0 -0
  319. package/web/public/fonts/ibm-plex-mono/ibm-plex-mono-latin-ext-400-normal.woff2 +0 -0
  320. package/web/public/fonts/ibm-plex-mono/ibm-plex-mono-latin-ext-500-normal.woff2 +0 -0
  321. package/web/public/fonts/ibm-plex-mono/ibm-plex-mono-latin-ext-600-normal.woff2 +0 -0
  322. package/web/public/fonts/ibm-plex-sans/LICENSE +93 -0
  323. package/web/public/fonts/ibm-plex-sans/ibm-plex-sans-latin-400-normal.woff2 +0 -0
  324. package/web/public/fonts/ibm-plex-sans/ibm-plex-sans-latin-500-normal.woff2 +0 -0
  325. package/web/public/fonts/ibm-plex-sans/ibm-plex-sans-latin-600-normal.woff2 +0 -0
  326. package/web/public/fonts/ibm-plex-sans/ibm-plex-sans-latin-ext-400-normal.woff2 +0 -0
  327. package/web/public/fonts/ibm-plex-sans/ibm-plex-sans-latin-ext-500-normal.woff2 +0 -0
  328. package/web/public/fonts/ibm-plex-sans/ibm-plex-sans-latin-ext-600-normal.woff2 +0 -0
  329. package/web/public/fonts/inter/inter-latin-400-normal.woff2 +0 -0
  330. package/web/public/fonts/inter/inter-latin-500-normal.woff2 +0 -0
  331. package/web/public/fonts/inter/inter-latin-600-normal.woff2 +0 -0
  332. package/web/public/fonts/inter/inter-latin-700-normal.woff2 +0 -0
  333. package/web/public/fonts/inter/inter-latin-800-normal.woff2 +0 -0
  334. package/web/public/fonts/inter/inter-latin-ext-400-normal.woff2 +0 -0
  335. package/web/public/fonts/inter/inter-latin-ext-500-normal.woff2 +0 -0
  336. package/web/public/fonts/inter/inter-latin-ext-600-normal.woff2 +0 -0
  337. package/web/public/fonts/inter/inter-latin-ext-700-normal.woff2 +0 -0
  338. package/web/public/fonts/inter/inter-latin-ext-800-normal.woff2 +0 -0
  339. package/web/public/fonts/jetbrains-mono/LICENSE +93 -0
  340. package/web/public/fonts/jetbrains-mono/jetbrains-mono-latin-400-normal.woff2 +0 -0
  341. package/web/public/fonts/jetbrains-mono/jetbrains-mono-latin-500-normal.woff2 +0 -0
  342. package/web/public/fonts/jetbrains-mono/jetbrains-mono-latin-600-normal.woff2 +0 -0
  343. package/web/public/fonts/jetbrains-mono/jetbrains-mono-latin-ext-400-normal.woff2 +0 -0
  344. package/web/public/fonts/jetbrains-mono/jetbrains-mono-latin-ext-500-normal.woff2 +0 -0
  345. package/web/public/fonts/jetbrains-mono/jetbrains-mono-latin-ext-600-normal.woff2 +0 -0
  346. package/web/public/fonts/noto-serif-sc/LICENSE +94 -0
  347. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-0.woff2 +0 -0
  348. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-1.woff2 +0 -0
  349. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-10.woff2 +0 -0
  350. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-100.woff2 +0 -0
  351. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-11.woff2 +0 -0
  352. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-12.woff2 +0 -0
  353. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-13.woff2 +0 -0
  354. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-14.woff2 +0 -0
  355. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-15.woff2 +0 -0
  356. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-16.woff2 +0 -0
  357. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-17.woff2 +0 -0
  358. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-18.woff2 +0 -0
  359. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-19.woff2 +0 -0
  360. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-2.woff2 +0 -0
  361. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-20.woff2 +0 -0
  362. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-21.woff2 +0 -0
  363. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-22.woff2 +0 -0
  364. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-23.woff2 +0 -0
  365. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-24.woff2 +0 -0
  366. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-25.woff2 +0 -0
  367. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-26.woff2 +0 -0
  368. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-27.woff2 +0 -0
  369. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-28.woff2 +0 -0
  370. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-29.woff2 +0 -0
  371. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-3.woff2 +0 -0
  372. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-30.woff2 +0 -0
  373. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-31.woff2 +0 -0
  374. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-32.woff2 +0 -0
  375. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-33.woff2 +0 -0
  376. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-34.woff2 +0 -0
  377. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-35.woff2 +0 -0
  378. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-36.woff2 +0 -0
  379. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-37.woff2 +0 -0
  380. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-38.woff2 +0 -0
  381. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-39.woff2 +0 -0
  382. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-4.woff2 +0 -0
  383. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-40.woff2 +0 -0
  384. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-41.woff2 +0 -0
  385. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-42.woff2 +0 -0
  386. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-43.woff2 +0 -0
  387. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-44.woff2 +0 -0
  388. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-45.woff2 +0 -0
  389. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-46.woff2 +0 -0
  390. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-47.woff2 +0 -0
  391. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-48.woff2 +0 -0
  392. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-49.woff2 +0 -0
  393. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-5.woff2 +0 -0
  394. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-50.woff2 +0 -0
  395. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-51.woff2 +0 -0
  396. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-52.woff2 +0 -0
  397. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-53.woff2 +0 -0
  398. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-54.woff2 +0 -0
  399. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-55.woff2 +0 -0
  400. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-56.woff2 +0 -0
  401. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-57.woff2 +0 -0
  402. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-58.woff2 +0 -0
  403. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-59.woff2 +0 -0
  404. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-6.woff2 +0 -0
  405. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-60.woff2 +0 -0
  406. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-61.woff2 +0 -0
  407. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-62.woff2 +0 -0
  408. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-63.woff2 +0 -0
  409. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-64.woff2 +0 -0
  410. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-65.woff2 +0 -0
  411. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-66.woff2 +0 -0
  412. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-67.woff2 +0 -0
  413. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-68.woff2 +0 -0
  414. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-69.woff2 +0 -0
  415. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-7.woff2 +0 -0
  416. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-70.woff2 +0 -0
  417. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-71.woff2 +0 -0
  418. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-72.woff2 +0 -0
  419. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-73.woff2 +0 -0
  420. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-74.woff2 +0 -0
  421. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-75.woff2 +0 -0
  422. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-76.woff2 +0 -0
  423. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-77.woff2 +0 -0
  424. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-78.woff2 +0 -0
  425. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-79.woff2 +0 -0
  426. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-8.woff2 +0 -0
  427. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-80.woff2 +0 -0
  428. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-81.woff2 +0 -0
  429. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-82.woff2 +0 -0
  430. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-83.woff2 +0 -0
  431. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-84.woff2 +0 -0
  432. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-85.woff2 +0 -0
  433. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-86.woff2 +0 -0
  434. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-87.woff2 +0 -0
  435. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-88.woff2 +0 -0
  436. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-89.woff2 +0 -0
  437. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-9.woff2 +0 -0
  438. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-90.woff2 +0 -0
  439. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-91.woff2 +0 -0
  440. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-92.woff2 +0 -0
  441. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-93.woff2 +0 -0
  442. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-94.woff2 +0 -0
  443. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-95.woff2 +0 -0
  444. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-96.woff2 +0 -0
  445. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-97.woff2 +0 -0
  446. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-98.woff2 +0 -0
  447. package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-99.woff2 +0 -0
  448. package/web/public/fonts/source-serif-4/LICENSE +93 -0
  449. package/web/public/fonts/source-serif-4/source-serif-4-500-0.woff2 +0 -0
  450. package/web/public/fonts/source-serif-4/source-serif-4-500-1.woff2 +0 -0
  451. package/web/public/fonts/source-serif-4/source-serif-4-500-2.woff2 +0 -0
  452. package/web/public/fonts/source-serif-4/source-serif-4-500-3.woff2 +0 -0
  453. package/web/public/fonts/source-serif-4/source-serif-4-500-4.woff2 +0 -0
  454. package/web/public/fonts/source-serif-4/source-serif-4-500-5.woff2 +0 -0
  455. package/web/public/icon/1a-mark.svg +1 -0
  456. package/web/public/icon.ico +0 -0
@@ -0,0 +1,192 @@
1
+ /**
2
+ * pi-harness 的 pi 扩展 —— 提供命令行集成。
3
+ *
4
+ * 能力:
5
+ * /webui 启动本机 pi-harness 服务器,打开浏览器访问
6
+ * /webui --port 9000 指定端口启动
7
+ * /webui --no-browser 启动但不开浏览器
8
+ * /webui stop 停止已启动的服务器
9
+ * /webui status 查看运行状态 / URL
10
+ *
11
+ * 实现说明:
12
+ * - 不依赖全局 bin(pi install 后 pi-harness 命令不一定在 PATH),直接用
13
+ * node 调包内 dist/server/index.js,通过环境变量 PORT / PI_WEB_CWD /
14
+ * PI_WEB_DATA_DIR 控制。
15
+ * - 工作目录默认用当前 pi 会话的 ctx.cwd;可用 --cwd / path 覆盖。
16
+ * - 服务器作为子进程后台运行,/webui 不阻塞 pi。
17
+ * - 每个 pi 会话管理一个子进程;session_shutdown 时清理,避免孤儿进程。
18
+ */
19
+
20
+ import { spawn } from "node:child_process";
21
+ import { existsSync } from "node:fs";
22
+ import { dirname, join, resolve } from "node:path";
23
+ import { fileURLToPath } from "node:url";
24
+ import net from "node:net";
25
+ import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
26
+
27
+ // 本文件位于 <pkg>/extensions/webui.ts → 包根在上一级
28
+ const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
29
+ const SERVER_ENTRY = join(PKG_ROOT, "dist", "server", "index.js");
30
+ const NODE = process.execPath;
31
+
32
+ /** 每个会话的服务器子进程 + 元数据 */
33
+ interface RunningServer {
34
+ proc: ReturnType<typeof spawn>;
35
+ port: number;
36
+ cwd: string;
37
+ url: string;
38
+ }
39
+
40
+ // 会话 → 运行实例(模块级 Map;每会话一个会话对象,无需清理全局)
41
+ const running = new Map<string, RunningServer>();
42
+
43
+ /** 找一个空闲端口 */
44
+ function findFreePort(from = 8787): Promise<number> {
45
+ return new Promise((resolve_, reject) => {
46
+ const srv = net.createServer();
47
+ srv.listen(from, () => {
48
+ const port = (srv.address() as net.AddressInfo).port;
49
+ srv.close(() => resolve_(port));
50
+ });
51
+ srv.on("error", () => {
52
+ // 端口被占则顺延
53
+ findFreePort(from + 1).then(resolve_, reject);
54
+ });
55
+ });
56
+ }
57
+
58
+ /** 解析 --key value / --flag 参数 */
59
+ function parseArgs(args: string): { port?: number; cwd?: string; noBrowser: boolean } {
60
+ const out: { port?: number; cwd?: string; noBrowser: boolean } = { noBrowser: false };
61
+ const toks = args.split(/\s+/).filter(Boolean);
62
+ for (let i = 0; i < toks.length; i++) {
63
+ const t = toks[i];
64
+ if ((t === "--port" || t === "-p") && toks[i + 1]) {
65
+ const n = Number(toks[++i]);
66
+ if (Number.isInteger(n) && n > 0 && n < 65536) out.port = n;
67
+ } else if ((t === "--cwd") && toks[i + 1]) {
68
+ out.cwd = resolve(toks[++i]);
69
+ } else if (t === "--no-browser") {
70
+ out.noBrowser = true;
71
+ }
72
+ }
73
+ return out;
74
+ }
75
+
76
+ /** 打开浏览器 */
77
+ async function openBrowser(url: string): Promise<void> {
78
+ const { platform } = process;
79
+ const [cmd, ...rest] =
80
+ platform === "darwin"
81
+ ? ["open", url]
82
+ : platform === "win32"
83
+ ? ["cmd", "/c", "start", "", url]
84
+ : ["xdg-open", url];
85
+ // 无界面环境缺少 xdg-open 等打开器时,ENOENT 以异步 'error' 事件触发,
86
+ // try/catch 拦不住会崩掉整个进程 —— 必须挂 error 监听。
87
+ spawn(cmd, rest, { stdio: "ignore", detached: true })
88
+ .on("error", (err) => {
89
+ if ((err as NodeJS.ErrnoException)?.code === "ENOENT") {
90
+ console.warn(
91
+ `[webui] 未找到浏览器打开器 (${(err as NodeJS.ErrnoException).path || "command not found"}),请用 --no-browser 关闭自动打开`
92
+ );
93
+ } else {
94
+ console.warn("[webui] 打开浏览器失败:", err.message);
95
+ }
96
+ })
97
+ .unref();
98
+ }
99
+
100
+ export default function (pi: ExtensionAPI): void {
101
+ pi.registerCommand("webui", {
102
+ description: "启动本机 pi-harness Web 界面(/webui [--port N] [--cwd PATH] [--no-browser] | stop | status)",
103
+ handler: async (args: string, ctx: ExtensionCommandContext) => {
104
+ const sid = ctx.sessionManager.getSessionId();
105
+ const opts = parseArgs(args);
106
+ const action = (args.split(/\s+/)[0] || "start").toLowerCase();
107
+
108
+ // 停止
109
+ if (action === "stop" || action === "kill") {
110
+ const inst = running.get(sid);
111
+ if (!inst) {
112
+ ctx.ui.notify("没有正在运行的本机 pi-harness 服务器", "info");
113
+ return;
114
+ }
115
+ inst.proc.kill("SIGTERM");
116
+ running.delete(sid);
117
+ ctx.ui.notify(`已停止 pi-harness (${inst.url})`, "info");
118
+ return;
119
+ }
120
+
121
+ // 状态
122
+ if (action === "status") {
123
+ const inst = running.get(sid);
124
+ if (!inst) {
125
+ ctx.ui.notify("本机 pi-harness 未运行", "info");
126
+ return;
127
+ }
128
+ const alive = inst.proc.exitCode === null;
129
+ ctx.ui.notify(
130
+ alive ? `pi-harness 运行中 → ${inst.url}\n端口 ${inst.port} · cwd ${inst.cwd}` : `已退出(exit=${inst.proc.exitCode})`,
131
+ alive ? "info" : "warning",
132
+ );
133
+ return;
134
+ }
135
+
136
+ // 默认 start
137
+ if (action !== "start" && action !== "run") {
138
+ ctx.ui.notify(`未知动作 ${action}(可用 start|stop|status)`, "warning");
139
+ return;
140
+ }
141
+
142
+ // 已运行则提示
143
+ const existing = running.get(sid);
144
+ if (existing && existing.proc.exitCode === null) {
145
+ ctx.ui.notify(`pi-harness 已在运行 → ${existing.url}`, "info");
146
+ return;
147
+ }
148
+
149
+ // 检查是否已构建
150
+ if (!existsSync(SERVER_ENTRY)) {
151
+ ctx.ui.notify(
152
+ "缺少 dist/ 产物(当前安装未包含已构建前端)。请运行 `npm run build` 后重试,或用 pi-harness 官方 npm 包。",
153
+ "warning",
154
+ );
155
+ return;
156
+ }
157
+
158
+ const port = opts.port ?? (await findFreePort());
159
+ const cwd = opts.cwd ?? ctx.cwd;
160
+ const url = `http://localhost:${port}`;
161
+
162
+ const env = {
163
+ ...process.env,
164
+ PORT: String(port),
165
+ PI_WEB_CWD: cwd,
166
+ ...(process.env.PI_WEB_DATA_DIR ? {} : { PI_WEB_DATA_DIR: join(cwd, ".pi-web") }),
167
+ };
168
+ const proc = spawn(NODE, [SERVER_ENTRY], { cwd, env, stdio: "ignore", detached: true });
169
+ proc.unref();
170
+ running.set(sid, { proc, port, cwd, url });
171
+
172
+ ctx.ui.notify(`pi-harness 启动中 → ${url}\n端口 ${port} · cwd ${cwd}\n(几秒后可用,/webui status 查看)`);
173
+
174
+ if (!opts.noBrowser) await openBrowser(url);
175
+
176
+ // 进程退出时清理
177
+ proc.on("exit", () => {
178
+ if (running.get(sid)?.proc === proc) running.delete(sid);
179
+ });
180
+ },
181
+ });
182
+
183
+ // 会话结束清理子进程,避免孤儿
184
+ pi.on("session_shutdown", async (_event, ctx) => {
185
+ const sid = ctx.sessionManager.getSessionId();
186
+ const inst = running.get(sid);
187
+ if (inst && inst.proc.exitCode === null) {
188
+ inst.proc.kill("SIGTERM");
189
+ running.delete(sid);
190
+ }
191
+ });
192
+ }
package/package.json CHANGED
@@ -1,6 +1,124 @@
1
1
  {
2
2
  "name": "@youweichen/pi-harness",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.1.0",
4
+ "description": "Web chat interface for the pi coding agent, powered by the pi SDK (@earendil-works/pi-coding-agent) — one-command run, Docker/systemd/launchd deployable",
5
+ "license": "MIT",
6
+ "author": {
7
+ "name": "youweichen",
8
+ "email": "youweichen0208@gmail.com"
9
+ },
10
+ "type": "module",
11
+ "bin": {
12
+ "pi-harness": "bin/pi-harness.mjs"
13
+ },
14
+ "main": "electron/main.mjs",
15
+ "files": [
16
+ "bin/",
17
+ "dist/",
18
+ "web/dist/",
19
+ "web/public/",
20
+ "deploy/",
21
+ "extensions/",
22
+ "README.md",
23
+ "LICENSE"
24
+ ],
25
+ "keywords": [
26
+ "pi",
27
+ "pi-package",
28
+ "coding-agent",
29
+ "ai",
30
+ "chat",
31
+ "web-ui",
32
+ "terminal",
33
+ "llm"
34
+ ],
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/youweichen0208/pi-harness.git"
38
+ },
39
+ "pi": {
40
+ "extensions": [
41
+ "./extensions"
42
+ ]
43
+ },
44
+ "engines": {
45
+ "node": ">=22.19.0"
46
+ },
47
+ "scripts": {
48
+ "prepublishOnly": "npm run build",
49
+ "dev": "concurrently -k -n server,web -c blue,green \"npm:dev:server\" \"npm:dev:web\"",
50
+ "dev:server": "cross-env PORT=8788 PI_WEB_ALLOW_ORIGINS=http://localhost:5173,http://127.0.0.1:5173 node --watch --import tsx server/index.ts",
51
+ "dev:web": "vite --config web/vite.config.ts",
52
+ "build": "npm run build:web && npm run build:server",
53
+ "build:web": "vite build --config web/vite.config.ts",
54
+ "build:server": "tsc -p tsconfig.server.json",
55
+ "typecheck": "tsc -p tsconfig.server.json --noEmit && tsc -p web/tsconfig.json --noEmit && tsc -p tsconfig.tests.json --noEmit",
56
+ "test": "node --test tests/check-design-tokens-test.mjs && npm run check:design && vitest run",
57
+ "test:unit": "vitest run",
58
+ "test:smoke": "node tests/run-smoke.mjs",
59
+ "check:lockfile": "node scripts/check-lockfile.mjs",
60
+ "check:protocol": "node scripts/check-protocol-sync.mjs",
61
+ "test:freeze": "node tests/freeze-test.mjs",
62
+ "start": "node dist/server/index.js",
63
+ "start:electron": "electron .",
64
+ "dev:electron": "electron .",
65
+ "build:electron": "electron-builder build",
66
+ "build:electron:mac": "electron-builder build --mac",
67
+ "build:electron:win": "electron-builder build --win",
68
+ "build:electron:linux": "electron-builder build --linux",
69
+ "publish:electron": "electron-builder build --publish always",
70
+ "check:design": "node scripts/check-design-tokens.mjs"
71
+ },
72
+ "dependencies": {
73
+ "@earendil-works/pi-ai": "1.0.4",
74
+ "@earendil-works/pi-coding-agent": "1.0.4",
75
+ "compression": "^1.8.1",
76
+ "electron-updater": "^6.0.0",
77
+ "express": "^4.21.2",
78
+ "node-pty": "^1.1.0",
79
+ "pdfjs-dist": "6.4.299",
80
+ "proper-lockfile": "4.1.2",
81
+ "remark-parse": "^11.0.0",
82
+ "ssh2": "^1.17.0",
83
+ "typebox": "^1.3.14",
84
+ "unified": "^11.0.5",
85
+ "ws": "^8.18.0"
86
+ },
87
+ "devDependencies": {
88
+ "@types/compression": "^1.8.1",
89
+ "@types/express": "^4.17.21",
90
+ "@types/node": "^22.10.0",
91
+ "@types/react": "^18.3.12",
92
+ "@types/react-dom": "^18.3.1",
93
+ "@types/ssh2": "^1.15.6",
94
+ "@types/turndown": "^5.0.6",
95
+ "@types/ws": "^8.5.13",
96
+ "@vitejs/plugin-react": "^4.3.4",
97
+ "@xterm/addon-fit": "^0.11.0",
98
+ "@xterm/xterm": "^6.0.0",
99
+ "concurrently": "^9.1.0",
100
+ "cross-env": "^10.1.0",
101
+ "electron": "^41.0.0",
102
+ "electron-builder": "^26.15.3",
103
+ "highlight.js": "^11.10.0",
104
+ "mermaid": "^11.17.2",
105
+ "playwright-core": "^1.62.1",
106
+ "postcss": "^8.5.25",
107
+ "react": "^18.3.1",
108
+ "react-dom": "^18.3.1",
109
+ "react-icons": "^5.7.0",
110
+ "react-markdown": "^9.0.1",
111
+ "rehype-highlight": "^7.0.1",
112
+ "remark-gfm": "^4.0.0",
113
+ "tsx": "^4.19.2",
114
+ "turndown": "^7.2.4",
115
+ "turndown-plugin-gfm": "^1.0.2",
116
+ "typescript": "^5.7.2",
117
+ "vite": "^6.0.3",
118
+ "vitest": "^4.1.11"
119
+ },
120
+ "allowScripts": {
121
+ "node-pty@1.1.0": true,
122
+ "electron@41.10.7": true
123
+ }
124
+ }
Binary file
@@ -0,0 +1,3 @@
1
+ import{a as r,j as e,M as Pn,b as Dn}from"./markdown-BhJ_LInD.js";import{u as Ee,b as jn,T as fn,r as je}from"./index-C5or_GAq.js";import{D as En,o as $n}from"./xterm-D1D2FVe3.js";/* empty css */import"./react-BddUxV-9.js";const Mn=r.memo(function({text:w}){return e.jsx(Pn,{remarkPlugins:[Dn],components:{a:({href:t,children:s})=>/^https?:\/\//.test(t??"")?e.jsx("a",{href:t,target:"_blank",rel:"noreferrer",children:s}):e.jsx("span",{children:s}),img:({alt:t})=>e.jsx("span",{children:t})},children:w})});function Rn({nodeId:P,defaultDir:w,connected:t,agent:s,request:ne,draft:T,setDraft:$,consumedEditors:J}){var oe;const u=Ee(),[te,se]=r.useState(w),[C,y]=r.useState({}),[b,G]=r.useState(""),[M,q]=r.useState(""),[z,le]=r.useState("followUp"),D=r.useRef(null),W=r.useRef(!0),x=s==null?void 0:s.dialogs[0],A=Object.keys(C).length>0,Q=Object.values(C).some(d=>d.action==="agent_dialog");r.useEffect(()=>{q((x==null?void 0:x.prefill)??"")},[x==null?void 0:x.id]),r.useEffect(()=>{s!=null&&s.editorText&&J[P]!==s.editorText.id&&(J[P]=s.editorText.id,$(s.editorText.text))},[s==null?void 0:s.editorText]),r.useEffect(()=>{W.current&&D.current&&(D.current.scrollTop=D.current.scrollHeight)},[s==null?void 0:s.messages,s==null?void 0:s.streamingMessage,s==null?void 0:s.tools]),r.useEffect(()=>{const d=a=>{var E;const S=a.detail,N=S.requestId?C[S.requestId]:void 0;S.nodeId!==P||!N||(S.event==="failure"&&(G(String(((E=S.data)==null?void 0:E.message)??"")),y(k=>{const R={...k};return delete R[S.requestId],R})),S.event==="result"&&(N.text!==void 0&&$(k=>k===N.text?"":k),y(k=>{const R={...k};return delete R[S.requestId],R})))};return window.addEventListener("pi-node-event",d),()=>window.removeEventListener("pi-node-event",d)},[P,C]),r.useEffect(()=>{t||y({})},[t]);const H=(d,a,S)=>{G("");const N=ne(d,P,a,void 0,s==null?void 0:s.id);N?y(E=>({...E,[N]:{action:d,text:S}})):G(u("nodeAgentOffline"))},ae=()=>{!T.trim()||A||!t||(s==null?void 0:s.phase)!=="ready"||(W.current=!0,H("agent_prompt",{text:T,...s.running?{queue:z}:{}},T))},U=[...(s==null?void 0:s.messages)??[],...s!=null&&s.streamingMessage?[s.streamingMessage]:[]],ce=new Map(U.filter(d=>d.role==="toolResult").map(d=>[d.toolCallId,d])),fe=d=>e.jsxs("article",{className:`node-agent-message ${d.role}`,children:[e.jsx("small",{children:d.role==="user"?u("nodeAgentYou"):"pi"}),d.errorMessage&&e.jsx("p",{role:"alert",className:"node-agent-error",children:d.errorMessage}),d.content.map((a,S)=>{if(a.type==="text"&&"text"in a&&typeof a.text=="string")return e.jsx(Mn,{text:a.text},S);if(a.type==="thinking"&&"thinking"in a&&typeof a.thinking=="string")return e.jsxs("details",{children:[e.jsx("summary",{children:u("nodeAgentThinking")}),e.jsx("pre",{children:a.thinking})]},S);if(a.type==="toolCall"&&"id"in a&&"name"in a){const N=ce.get(String(a.id)),E=s==null?void 0:s.tools.find(k=>k.id===a.id);return e.jsxs("details",{className:"node-agent-tool",children:[e.jsxs("summary",{children:[e.jsx("code",{children:String(a.name)}),e.jsx("span",{children:u(N!=null&&N.isError||E!=null&&E.isError?"error":N||E&&!E.running?"done":s!=null&&s.running?"running":"toolQueued")})]}),e.jsx("pre",{children:String(a.argumentsText??"")}),N==null?void 0:N.content.map((k,R)=>"text"in k&&typeof k.text=="string"?e.jsx("pre",{children:k.text},R):null)]},S)}return a.type==="image"&&"dataUrl"in a&&typeof a.dataUrl=="string"&&a.dataUrl.startsWith("data:image/")?e.jsx("img",{src:a.dataUrl,alt:u("toolResultImage")},S):null})]},d.id);return e.jsxs("section",{className:"node-agent","aria-label":u("nodeAgentTitle"),children:[e.jsxs("header",{children:[e.jsx("strong",{children:u("nodeAgentTitle")}),e.jsx("span",{children:s!=null&&s.model?`${s.model.provider} / ${s.model.name}`:u("nodeAgentRemote")}),(s==null?void 0:s.phase)==="ready"&&e.jsxs(e.Fragment,{children:[e.jsx("button",{disabled:A||s.running||!t,onClick:()=>H("agent_new"),children:u("nodeAgentNew")}),e.jsx("button",{disabled:!t,onClick:()=>H("agent_close"),children:u("nodeAgentClose")})]})]}),(!s||s.phase==="closed")&&e.jsxs("div",{className:"node-agent-setup",children:[e.jsx("p",{children:u("nodeAgentSetup")}),e.jsxs("label",{children:[u("nodeDefaultDir"),e.jsx("input",{value:te,onChange:d=>se(d.target.value)})]}),e.jsx("button",{disabled:!t||A,onClick:()=>H("agent_start",{cwd:te}),children:u(A?"nodeAgentStarting":"nodeAgentStart")}),e.jsx("p",{className:"node-muted",children:u("nodeAgentInstall")}),e.jsx("code",{children:"npm install -g @earendil-works/pi-coding-agent@1.0.4"})]}),(s==null?void 0:s.phase)==="starting"&&e.jsx("p",{role:"status",children:u("nodeAgentStarting")}),!t&&e.jsx("p",{role:"status",children:u("nodeAgentOffline")}),(b||(s==null?void 0:s.error))&&e.jsx("p",{role:"alert",className:"node-agent-error",children:b||(s==null?void 0:s.error)}),(s==null?void 0:s.notice)&&e.jsx("p",{role:"status",className:"node-muted",children:s.notice}),e.jsxs("div",{className:"node-agent-feed",ref:D,onScroll:d=>{const a=d.currentTarget;W.current=a.scrollHeight-a.scrollTop-a.clientHeight<100},children:[U.filter(d=>d.role!=="toolResult"&&(d.errorMessage||d.content.some(a=>a.type==="toolCall"||a.type==="image"||"text"in a&&typeof a.text=="string"&&a.text.trim()||"thinking"in a&&typeof a.thinking=="string"&&a.thinking.trim()))).map(fe),(s==null?void 0:s.running)&&e.jsxs("p",{className:"node-agent-working",role:"status",children:[u("nodeAgentWorking"),s.tools.filter(d=>d.running).map(d=>e.jsx("code",{children:d.name},d.id))]})]}),x&&e.jsxs("form",{className:"node-agent-dialog",onSubmit:d=>{d.preventDefault(),H("agent_dialog",{id:x.id,value:M,confirmed:!0})},children:[e.jsx("strong",{children:x.title}),x.message&&e.jsx("p",{children:x.message}),x.method==="select"?e.jsxs("select",{"aria-label":x.title,required:!0,value:M,onChange:d=>q(d.target.value),children:[e.jsx("option",{value:"",disabled:!0,children:u("nodeAgentSelect")}),(oe=x.options)==null?void 0:oe.map(d=>e.jsx("option",{children:d},d))]}):x.method!=="confirm"&&e.jsx("textarea",{"aria-label":x.title,value:M,onChange:d=>q(d.target.value),rows:x.method==="editor"?6:2}),e.jsx("button",{disabled:Q||!t,type:"submit",children:u("confirm")}),e.jsx("button",{disabled:Q||!t,type:"button",onClick:()=>H("agent_dialog",{id:x.id,cancelled:!0}),children:u("cancel")})]}),(s==null?void 0:s.phase)==="ready"&&e.jsxs("form",{className:"node-agent-input",onSubmit:d=>{d.preventDefault(),ae()},children:[e.jsx("textarea",{"aria-label":u("nodeAgentPrompt"),placeholder:u("nodeAgentPrompt"),value:T,onChange:d=>$(d.target.value),rows:3,onKeyDown:d=>{d.key==="Enter"&&!d.shiftKey&&!d.nativeEvent.isComposing&&(d.preventDefault(),ae())}}),e.jsxs("div",{children:[e.jsxs("select",{"aria-label":u("nodeAgentModel"),value:s.model?JSON.stringify([s.model.provider,s.model.id]):"",disabled:s.running||A||!t,onChange:d=>{const[a,S]=JSON.parse(d.target.value);H("agent_model",{provider:a,modelId:S})},children:[e.jsx("option",{value:"",disabled:!0,children:u("nodeAgentModel")}),s.models.map(d=>e.jsxs("option",{value:JSON.stringify([d.provider,d.id]),children:[d.provider," / ",d.name]},`${d.provider}/${d.id}`))]}),s.running&&e.jsxs(e.Fragment,{children:[e.jsxs("select",{"aria-label":u("nodeAgentQueue"),value:z,onChange:d=>le(d.target.value),children:[e.jsx("option",{value:"followUp",children:u("nodeAgentFollowUp")}),e.jsx("option",{value:"steer",children:u("nodeAgentSteer")})]}),e.jsx("button",{type:"button",disabled:!t,onClick:()=>H("agent_abort"),children:u("stop")})]}),e.jsx("button",{type:"submit",disabled:!T.trim()||A||!t,children:u("nodeAgentSend")})]})]})]})}function Tn({nodeId:P,tab:w,active:t,send:s,initialOutput:ne}){const T=Ee(),$=r.useRef(null),J=r.useRef(w.closed);J.current=w.closed;const[u,te]=r.useState(""),[se,C]=r.useState("");return r.useEffect(()=>{if(!$.current)return;const y=getComputedStyle($.current),b=new En({theme:{...jn(),background:y.getPropertyValue("--node-terminal-bg").trim(),foreground:y.getPropertyValue("--node-terminal-fg").trim()},fontFamily:'"JetBrains Mono", Consolas, monospace',fontSize:13,scrollback:8e3,allowProposedApi:!0}),G=()=>{b.options.theme={...jn(),background:y.getPropertyValue("--node-terminal-bg").trim(),foreground:y.getPropertyValue("--node-terminal-fg").trim()}};window.addEventListener(fn,G);const M=new $n;b.loadAddon(M),b.open($.current),ne&&b.write(ne);const q=(x,A={})=>s({type:"node_request",action:x,requestId:je(),nodeId:P,terminalId:w.id,conversationId:w.conversationId,payload:A}),z=b.onData(x=>{J.current||q(x===""?"interrupt":"terminal_input",{data:x})}),le=b.onSelectionChange(()=>te(b.getSelection().slice(0,32e3))),D=x=>{var Q;const A=x.detail;A.nodeId!==P||A.terminalId!==w.id||A.event==="terminal_output"&&b.write(String(((Q=A.data)==null?void 0:Q.text)??""))};window.addEventListener("pi-node-event",D);const W=new ResizeObserver(()=>{var x;if(!(!((x=$.current)!=null&&x.clientWidth)||!$.current.clientHeight))try{M.fit(),J.current||q("terminal_resize",{cols:b.cols,rows:b.rows})}catch{}});return W.observe($.current),()=>{window.removeEventListener(fn,G),W.disconnect(),z.dispose(),le.dispose(),window.removeEventListener("pi-node-event",D),b.dispose()}},[P,w.id,w.conversationId,s]),e.jsxs("div",{className:"node-terminal-wrap",style:{display:t?"block":"none"},children:[e.jsx("div",{ref:$,className:"node-xterm"}),u&&e.jsxs("div",{className:"node-selection-menu",children:[e.jsx("button",{onClick:()=>void navigator.clipboard.writeText(u).then(()=>C(T("nodeCopied"))).catch(y=>C(String(y))),children:T("nodeCopy")}),se&&e.jsx("span",{role:"status",children:se})]})]})}const qn=()=>({name:"",group:"默认",host:"",port:22,username:"root",auth:"password",defaultDir:"/"});function Un({send:P,active:w}){var Be,Je,Ge,Ve;const t=Ee(),[s,ne]=r.useState([]),[T,$]=r.useState([]),[J,u]=r.useState(!1),[te,se]=r.useState(!1),[C,y]=r.useState(null),[b,G]=r.useState(""),[M,q]=r.useState(!1),[z,le]=r.useState(!1),[D,W]=r.useState("agent"),[x,A]=r.useState({}),Q=r.useRef({}),[H,ae]=r.useState({}),[U,ce]=r.useState("password"),[fe,oe]=r.useState(""),[d,a]=r.useState(null),[S,N]=r.useState(!0),[E,k]=r.useState(!1),[R,ge]=r.useState(!1),re=r.useRef(null),Y=r.useRef(new Set),$e=r.useRef(new Set),[Me,ve]=r.useState(""),[de,gn]=r.useState([]),[Se,vn]=r.useState({}),[Re,Sn]=r.useState(Date.now()),[K,yn]=r.useState({}),[Ie,ue]=r.useState({}),[c,ye]=r.useState(localStorage.getItem("pi-node-selected")??""),[bn,Te]=r.useState({}),[v,B]=r.useState(null),[be,F]=r.useState(""),[qe,he]=r.useState(""),[we,Ae]=r.useState("/"),[Ke,wn]=r.useState({}),[L,ke]=r.useState(null),Z=r.useRef(new Map),Fe=r.useRef(new Map),Le=r.useRef(new Map),me=r.useRef(null),j=r.useCallback((n,i,o,h,I)=>{const ie=je();return P({type:"node_request",requestId:ie,action:n,nodeId:i,terminalId:h,conversationId:I,payload:o})?ie:null},[P]);r.useEffect(()=>{if(!w||!M)return;const n=setInterval(()=>Sn(Date.now()),1e3);return()=>clearInterval(n)},[w,M]);const l=de.find(n=>n.id===c),pe=Ie[c]??[],g=pe.find(n=>n.id===bn[c])??pe.at(-1),V=de.find(n=>n.id===d),X=s.find(n=>n.id===(l==null?void 0:l.sourceId)),kn=((Be=Ke[c])==null?void 0:Be.path)===we?Ke[c].entries:[];r.useEffect(()=>{w&&(j("state"),j("source_detect"))},[w,j]),r.useEffect(()=>{l&&Ae(l.defaultDir)},[c,l==null?void 0:l.defaultDir]),r.useEffect(()=>{const n=i=>{var ie,_e,Pe,Ne,Xe,ze,Qe,Ye,Ze,en,nn,tn,sn,on,rn,dn,ln,an,cn,un,hn,mn,pn,xn;const o=i.detail,h=o.nodeId??"";if(o.event==="state"){const p=((ie=o.data)==null?void 0:ie.nodes)??[];gn(p),ae(m=>{var xe;const f=Object.fromEntries(Object.entries(m).map(([O,_])=>[O,{..._,phase:"closed",running:!1,dialogs:[]}]));for(const O of((xe=o.data)==null?void 0:xe.connections)??[])O.agent&&(f[O.nodeId]=O.agent);for(const O of Object.keys(f))p.some(_=>_.id===O)||delete f[O];return f}),vn(Object.fromEntries((((_e=o.data)==null?void 0:_e.connections)??[]).map(m=>[m.nodeId,m]))),ne(((Pe=o.data)==null?void 0:Pe.sources)??[]),yn(Object.fromEntries((((Ne=o.data)==null?void 0:Ne.connections)??[]).map(m=>[m.nodeId,m.status])));for(const m of((Xe=o.data)==null?void 0:Xe.connections)??[])for(const f of m.terminals)Z.current.set(`${m.nodeId}:${f.id}`,f.output??"");ue(m=>{var xe,O;const f={...m};for(const _ of((xe=o.data)==null?void 0:xe.connections)??[]){const ee=(m[_.nodeId]??[]).filter(De=>!_.terminals.some(_n=>_n.id===De.id)).map(De=>({...De,closed:!0}));f[_.nodeId]=[...ee,..._.terminals]}for(const _ of Object.keys(f))(((O=o.data)==null?void 0:O.connections)??[]).some(ee=>ee.nodeId===_)||(f[_]=f[_].map(ee=>({...ee,closed:!0})));for(const _ of Object.keys(f))p.some(ee=>ee.id===_)||delete f[_];return f});return}if(o.event==="agent_state"&&((ze=o.data)!=null&&ze.agent)){const p=o.data.agent;ae(m=>({...m,[h]:p}));return}if(o.event==="terminal_output"){const p=`${h}:${o.terminalId}`;Z.current.set(p,((Z.current.get(p)??"")+String(((Qe=o.data)==null?void 0:Qe.text)??"")).slice(-65536));return}if(o.event==="trust_required"){if(o.requestId&&$e.current.add(o.requestId),window.confirm(t("nodeTrust",{name:String(((Ye=o.data)==null?void 0:Ye.name)??""),host:String(((Ze=o.data)==null?void 0:Ze.host)??""),fingerprint:String(((en=o.data)==null?void 0:en.fingerprint)??"")}))){const p=re.current;(p==null?void 0:p.nodeId)===h?j("credential_test",h,{...p.payload,fingerprint:(nn=o.data)==null?void 0:nn.fingerprint}):j("trust",h,{fingerprint:(tn=o.data)==null?void 0:tn.fingerprint})}else Y.current.delete(h),re.current=null,ge(!1);return}if(o.event==="failure"&&String(((sn=o.data)==null?void 0:sn.action)??"").startsWith("agent_"))return;if(o.event==="failure"){o.requestId===me.current&&(me.current=null);const p=String(((on=o.data)==null?void 0:on.message)??"");o.requestId&&$e.current.delete(o.requestId)||(he(p),ge(!1),((rn=o.data)==null?void 0:rn.action)==="credential_test"&&(re.current=null),Y.current.delete(h));return}if(o.event==="terminal_busy"){ue(p=>({...p,[h]:(p[h]??[]).map(m=>{var f;return m.id===o.terminalId?{...m,busy:!!((f=o.data)!=null&&f.busy)}:m})}));return}if(o.event==="terminal_exit"){const p=`${h}:${o.terminalId}`;Z.current.set(p,(Z.current.get(p)??"")+`\r
2
+ [SSH 已断开]\r
3
+ `),ue(m=>({...m,[h]:(m[h]??[]).map(f=>f.id===o.terminalId?{...f,closed:!0}:f)}));return}if(o.event!=="result")return;const I=(dn=o.data)==null?void 0:dn.action;if(I==="source_detect"&&($(((ln=o.data)==null?void 0:ln.sources)??[]),se(!0)),I==="source_add"&&(y(null),u(!1)),I==="credential_test"&&(re.current=null,ge(!1),a(null),F(""),ve(t("nodeCredentialsSaved",{n:Number(((an=o.data)==null?void 0:an.count)??1)}))),(I==="connect"||I==="trust"||I==="credential_test")&&Y.current.has(h)&&(Y.current.delete(h),j("terminal_open",h,{},je()),q(!0)),I==="terminal_open"){const p={id:String((cn=o.data)==null?void 0:cn.terminalId),conversationId:String((un=o.data)==null?void 0:un.conversationId),busy:!1};ue(m=>({...m,[h]:(m[h]??[]).some(f=>f.id===p.id)?m[h]:[...m[h]??[],p]})),Te(m=>({...m,[h]:p.id}))}I==="list"&&o.requestId===Fe.current.get(h)&&wn(p=>{var m,f;return{...p,[h]:{path:String(((m=o.data)==null?void 0:m.path)??""),entries:((f=o.data)==null?void 0:f.entries)??[]}}}),I==="read"&&o.requestId===Le.current.get(h)&&ke({nodeId:h,path:String(((hn=o.data)==null?void 0:hn.path)??""),text:String(((mn=o.data)==null?void 0:mn.text)??"")}),I==="write"&&o.requestId===me.current&&(me.current=null,ke(p=>{var m;return(p==null?void 0:p.nodeId)===h&&p.path===((m=o.data)==null?void 0:m.path)?null:p})),I==="save"&&(B(null),F(""),(pn=o.data)!=null&&pn.id&&ye(String(o.data.id))),(I==="import_legacy"||I==="import")&&ve(t("nodeImported",{n:Number(((xn=o.data)==null?void 0:xn.count)??0)}))};return window.addEventListener("pi-node-event",n),()=>window.removeEventListener("pi-node-event",n)},[j,t]);const Ce=r.useMemo(()=>de.filter(n=>`${n.name} ${n.host} ${n.username}`.toLowerCase().includes(b.toLowerCase())),[de,b]),Cn=r.useMemo(()=>[...new Set(Ce.map(n=>n.group))],[Ce]),Oe=n=>{const i=j("list",c,{path:n},g==null?void 0:g.id,g==null?void 0:g.conversationId);i&&Fe.current.set(c,i)},Nn=n=>{const i=j("read",c,{path:n},g==null?void 0:g.id,g==null?void 0:g.conversationId);i&&Le.current.set(c,i)},In=()=>{!L||L.nodeId!==c||(me.current=j("write",L.nodeId,{path:L.path,text:L.text},g==null?void 0:g.id,g==null?void 0:g.conversationId))},He=n=>{var i;if(ye(n.id),he(""),n.auth==="password"&&!n.hasSecret||n.auth==="key"&&(!n.keyPath||(i=n.unsupported)!=null&&i.includes("key"))&&!n.localKeyPath){ce(n.auth==="key"?"key":"password"),oe(n.localKeyPath||n.keyPath||""),a(n.id),F(""),k(!1),Y.current.add(n.id);return}q(!0),u(!1),K[n.id]==="connected"?(Ie[n.id]??[]).some(o=>!o.closed)||j("terminal_open",n.id,{},je()):(Y.current.add(n.id),j("connect",n.id))},Ue=e.jsx("button",{onClick:()=>{B(qn()),F("")},"aria-label":t("nodeAdd"),children:"+"}),We=e.jsxs("label",{className:"node-secondary",children:[t("nodeImportJson"),e.jsx("input",{type:"file",accept:"application/json,.json",hidden:!0,onChange:async n=>{var o;const i=(o=n.target.files)==null?void 0:o[0];if(i){try{const h=JSON.parse(await i.text());j("import",void 0,{nodes:h.nodes})}catch{he(t("nodeInvalidJson"))}n.target.value=""}}})]}),An=e.jsxs("div",{className:"node-source-page",children:[e.jsx("div",{className:"node-eyebrow",children:t("nodeSources")}),e.jsx("h2",{children:t("nodeAdd")}),e.jsx("p",{className:"node-muted",children:t("nodeSourceIntro")}),te&&!T.length&&!s.length&&e.jsx("p",{className:"node-muted",children:t("nodeNoSources")}),[...s,...T.filter(n=>!s.some(i=>i.path===n.path))].map(n=>e.jsxs("section",{className:"node-source-card",children:[e.jsxs("header",{children:[e.jsx("span",{className:"node-source-icon",children:n.kind==="xshell"?"X":"~/"}),e.jsxs("div",{children:[e.jsx("strong",{children:n.kind==="xshell"?"Xshell 8":"SSH config"}),e.jsx("small",{children:t("nodeSyncInfo",{n:n.count??0,g:n.groups??0})})]})]}),e.jsx("code",{children:n.path}),e.jsxs("p",{children:["✓ ",t("nodeSyncFields")]}),e.jsxs("p",{className:"node-muted",children:["— ",t("nodeSyncPassword"),e.jsx("br",{}),"— ",t("nodeSyncUnsupported")]}),n.error&&e.jsx("p",{className:"node-error",role:"alert",children:n.error}),n.lastSync&&e.jsx("small",{children:t("nodeSyncTime",{time:new Date(n.lastSync).toLocaleString()})}),e.jsxs("div",{className:"node-actions",children:[n.id?e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:()=>j("source_sync",void 0,{id:n.id}),children:t("nodeSyncNow")}),e.jsx("button",{onClick:()=>j("source_toggle",void 0,{id:n.id,enabled:!n.enabled}),children:t(n.enabled?"nodeSyncPause":"nodeSyncResume")})]}):e.jsxs(e.Fragment,{children:[e.jsx("button",{className:"node-primary",onClick:()=>j("source_add",void 0,{kind:n.kind,path:n.path,enabled:!0}),children:t("nodeSyncKeep")}),e.jsx("button",{onClick:()=>j("source_add",void 0,{kind:n.kind,path:n.path,enabled:!1}),children:t("nodeImportOnce")})]}),e.jsx("button",{onClick:()=>y({kind:n.kind??"xshell",path:n.path??""}),children:t("nodeChangePath")})]})]},n.path)),e.jsxs("div",{className:"node-actions",children:[e.jsx("button",{onClick:()=>y({kind:"xshell",path:""}),children:t("nodeAddSource")}),e.jsx("button",{onClick:()=>j("source_detect"),children:t("nodeDetect")}),Ue,We]})]});return e.jsxs("div",{className:`node-workbench ${D==="agent"?"node-agent-open":""} ${M&&l?"node-workspace-open":""}`,children:[qe&&e.jsxs("div",{className:"node-global-message node-error",role:"alert",children:[qe,e.jsx("button",{"aria-label":t("close"),onClick:()=>he(""),children:"×"})]}),Me&&e.jsxs("div",{className:"node-global-message node-notice",role:"status",children:[Me,e.jsx("button",{"aria-label":t("close"),onClick:()=>ve(""),children:"×"})]}),!M&&e.jsxs("aside",{className:"node-sidebar",children:[e.jsxs("header",{children:[e.jsx("strong",{children:t("nodeWorkbench")}),Ue]}),e.jsx("input",{"aria-label":t("nodeSearch"),placeholder:t("nodeSearch"),value:b,onChange:n=>G(n.target.value)}),s.map(n=>e.jsxs("button",{className:"node-source-status",onClick:()=>u(!0),children:[e.jsx("span",{className:`node-dot ${n.error?"connecting":n.enabled?"connected":"offline"}`}),n.kind==="xshell"?"Xshell 8":"SSH config",e.jsx("small",{children:n.error||(n.lastSync?new Date(n.lastSync).toLocaleTimeString():"…")})]},n.id)),e.jsx("div",{className:"node-list",children:Cn.map(n=>e.jsxs("section",{children:[e.jsxs("h3",{children:[n,e.jsx("span",{children:Ce.filter(i=>i.group===n).length})]}),Ce.filter(i=>i.group===n).map(i=>{var o,h;return e.jsxs("div",{className:`node-item ${c===i.id?"selected":""}`,children:[e.jsxs("button",{onClick:()=>{ye(i.id),u(!1)},children:[e.jsx("span",{className:`node-dot ${K[i.id]??"offline"}`}),i.name,e.jsxs("small",{children:[i.username,"@",i.host,":",i.port]})]}),(i.sourceMissing||((o=i.unsupported)==null?void 0:o.length)||i.auth==="password"&&!i.hasSecret)&&e.jsx("span",{className:"node-badge",children:t(i.sourceMissing?"nodeSourceMissing":(h=i.unsupported)!=null&&h.length?"nodeUnsupported":"nodeMissingSecret")}),!i.sourceId&&e.jsx("button",{title:t("nodeEdit"),onClick:()=>{B(i),F("")},children:"⋯"})]},i.id)})]},n))}),e.jsxs("footer",{children:[e.jsx("button",{onClick:()=>u(!0),children:t("nodeSources")}),We,e.jsxs("details",{children:[e.jsx("summary",{children:"⋯"}),e.jsx("button",{onClick:()=>j("import_legacy"),children:t("nodeImportLegacy")}),e.jsx("button",{onClick:()=>{const n=de.map(({hasSecret:h,fingerprint:I,sourceId:ie,sourceKey:_e,sourceMissing:Pe,...Ne})=>Ne),i=URL.createObjectURL(new Blob([JSON.stringify({nodes:n},null,2)],{type:"application/json"})),o=document.createElement("a");o.href=i,o.download="pi-nodes.json",o.click(),setTimeout(()=>URL.revokeObjectURL(i),1e3)},children:t("nodeExport")})]})]})]}),!M&&(J||!l?An:e.jsxs("section",{className:"node-detail",children:[e.jsxs("header",{className:"node-detail-head",children:[e.jsxs("div",{children:[e.jsx("div",{className:"node-eyebrow",children:l.group}),e.jsx("h2",{children:l.name}),e.jsxs("code",{children:[l.username,"@",l.host,":",l.port]})]}),e.jsxs("div",{className:"node-actions",children:[X&&e.jsx("button",{onClick:()=>j("source_reveal",void 0,{id:X.id}),children:t("nodeRevealSource")}),!l.sourceId&&e.jsx("button",{onClick:()=>{B(l),F("")},children:t("nodeEdit")}),e.jsx("button",{className:"node-primary",disabled:!!((Je=l.unsupported)!=null&&Je.some(n=>n!=="key"))||l.sourceMissing||K[l.id]==="connecting",onClick:()=>He(l),children:t("nodeOpenWorkbench")})]})]}),l.sourceMissing&&e.jsx("p",{className:"node-warning",children:t("nodeSourceMissing")}),!!((Ge=l.unsupported)!=null&&Ge.length)&&e.jsxs("p",{className:"node-warning",children:[t("nodeUnsupported"),": ",l.unsupported.join(", ")]}),e.jsxs("div",{className:l.hasSecret?"node-credential-note":"node-warning",children:[e.jsxs("div",{children:[e.jsxs("strong",{children:[t(l.auth==="agent"?"nodeAgentAuth":l.auth==="password"?"nodePassword":"nodePassphrase"),!l.hasSecret&&l.auth==="password"&&` · ${t("nodeMissingSecret")}`]}),e.jsx("p",{children:t("nodeCredentialHint")})]}),e.jsx("button",{onClick:()=>{ce(l.auth==="key"?"key":"password"),oe(l.localKeyPath||l.keyPath||""),a(l.id),F(""),k(!1)},children:t("nodeFillSecret")})]}),e.jsxs("dl",{children:[e.jsx("dt",{children:t("nodeAuth")}),e.jsx("dd",{children:t(l.auth==="key"?"nodeKey":l.auth==="agent"?"nodeAgentAuth":"nodePassword")}),(l.localKeyPath||l.keyPath)&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:t("nodeKeyPath")}),e.jsx("dd",{children:e.jsx("code",{children:l.localKeyPath||l.keyPath})})]}),X&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:t("nodeSourceLocation")}),e.jsxs("dd",{children:[e.jsxs("code",{children:[X.path,X.kind==="xshell"?`/${l.sourceKey}`:` · ${l.sourceKey}`]}),e.jsx("small",{children:t("nodeSourceReadonly")}),e.jsx("button",{title:t("nodeSourceOpenHint"),onClick:()=>void navigator.clipboard.writeText(X.kind==="xshell"?`${X.path}/${l.sourceKey}`:X.path).then(()=>ve(t("nodeCopied"))).catch(n=>he(String(n))),children:t("nodeCopy")})]})]}),e.jsx("dt",{children:t("nodeLastConnected")}),e.jsx("dd",{children:l.lastConnected?new Date(l.lastConnected).toLocaleString():t("nodeNever")}),e.jsx("dt",{children:t("nodeDefaultDir")}),e.jsx("dd",{children:e.jsx("code",{children:l.defaultDir})})]})]})),M&&l&&e.jsxs("div",{className:"node-connected",children:[e.jsxs("nav",{className:"node-connection-tabs",children:[e.jsx("button",{onClick:()=>q(!1),children:t("nodeBackList")}),de.filter(n=>{var i;return n.id===c||K[n.id]||((i=Ie[n.id])==null?void 0:i.length)}).map(n=>e.jsxs("button",{className:n.id===c?"active":"",onClick:()=>ye(n.id),children:[e.jsx("span",{className:`node-dot ${K[n.id]??"offline"}`}),n.name]},n.id)),e.jsx("button",{onClick:()=>{q(!1),u(!0)},"aria-label":t("nodeAdd"),children:"+"}),((Ve=Se[c])==null?void 0:Ve.connectedAt)&&e.jsx("span",{className:"node-connection-timing",children:t("nodeConnectionTiming",{ms:Se[c].latencyMs??0,duration:`${Math.floor(Math.max(0,Re-Se[c].connectedAt)/6e4)}:${String(Math.floor(Math.max(0,Re-Se[c].connectedAt)/1e3)%60).padStart(2,"0")}`})})]}),e.jsx("div",{className:"node-connected-body",children:e.jsxs("section",{className:"node-main",children:[e.jsxs("header",{className:"node-main-head",children:[e.jsx("strong",{children:l.name}),e.jsxs("span",{children:[l.username,"@",l.host,":",l.port]}),e.jsx("em",{children:t(K[c]==="connected"?"nodeConnected":"nodeDisconnected")}),e.jsx("button",{onClick:()=>K[c]==="connected"?j("disconnect",c):He(l),children:t(K[c]==="connected"?"nodeDisconnect":"nodeConnect")})]}),e.jsxs("nav",{className:"node-workbench-modes","aria-label":t("nodeWorkbench"),children:[e.jsx("button",{className:D==="agent"?"active":"",onClick:()=>W("agent"),children:t("nodeAgentTitle")}),e.jsx("button",{className:D==="terminal"?"active":"",onClick:()=>W("terminal"),children:t("nodeAgentTerminal")})]}),e.jsx("div",{className:"node-agent-container",hidden:D!=="agent",children:e.jsx(Rn,{nodeId:c,defaultDir:l.defaultDir,connected:K[c]==="connected",agent:H[c],request:j,draft:x[c]??"",setDraft:n=>A(i=>({...i,[c]:typeof n=="function"?n(i[c]??""):n})),consumedEditors:Q.current},c)}),e.jsxs("div",{className:"node-manual-workbench",hidden:D!=="terminal",children:[e.jsxs("div",{className:"node-tabs",children:[pe.map((n,i)=>e.jsxs("div",{className:(g==null?void 0:g.id)===n.id?"active":"",children:[e.jsxs("button",{onClick:()=>Te(o=>({...o,[c]:n.id})),children:[t("nodeTab",{n:i+1}),n.closed?` · ${t("nodeTabClosed")}`:n.busy?` · ${t("nodeTabBusy")}`:""]}),e.jsx("button",{"aria-label":t("nodeCloseTab"),onClick:()=>{n.closed||j("terminal_close",c,{},n.id,n.conversationId),Z.current.delete(`${c}:${n.id}`),ue(o=>({...o,[c]:(o[c]??[]).filter(h=>h.id!==n.id)}))},children:"×"})]},n.id)),e.jsx("button",{disabled:K[c]!=="connected",onClick:()=>j("terminal_open",c,{},je()),children:"+"})]}),e.jsxs("div",{className:"node-terminals",children:[pe.map(n=>e.jsx(Tn,{nodeId:c,tab:n,active:w&&D==="terminal"&&(g==null?void 0:g.id)===n.id,send:P,initialOutput:Z.current.get(`${c}:${n.id}`)??n.output},`${c}:${n.id}`)),!pe.length&&e.jsx("div",{className:"node-empty",children:t("nodeOpenHint")})]}),e.jsxs("div",{className:"node-terminal-footer",children:[e.jsx("span",{children:t("nodeTerminalHint")}),e.jsx("button",{onClick:()=>le(!z),children:t("nodeShowFiles")})]}),z&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"node-filebar",children:[e.jsx("input",{value:we,onChange:n=>Ae(n.target.value),"aria-label":t("nodeDefaultDir")}),e.jsx("button",{disabled:K[c]!=="connected",onClick:()=>Oe(we),children:t("nodeBrowse")})]}),e.jsx("div",{className:"node-files",children:kn.map(n=>{const i=`${we.replace(/\/$/,"")}/${n.name}`;return e.jsxs("button",{onClick:()=>n.type==="dir"?(Ae(i),Oe(i)):Nn(i),children:[n.type==="dir"?"▸":"·"," ",n.name]},n.name)})})]}),(L==null?void 0:L.nodeId)===c&&e.jsxs("div",{className:"node-file-editor",children:[e.jsx("span",{children:L.path}),e.jsx("button",{onClick:In,children:t("save")}),e.jsx("button",{onClick:()=>ke(null),children:t("close")}),e.jsx("textarea",{value:L.text,onChange:n=>ke({...L,text:n.target.value})})]})]})]})})]}),C&&e.jsx("div",{className:"node-modal-backdrop",children:e.jsxs("form",{className:"node-modal",onSubmit:n=>{n.preventDefault(),j("source_add",void 0,{...C,enabled:!0})},children:[e.jsx("h2",{children:t("nodeAddSource")}),e.jsxs("label",{children:[t("nodeSources"),e.jsxs("select",{value:C.kind,onChange:n=>y({...C,kind:n.target.value}),children:[e.jsx("option",{value:"xshell",children:"Xshell 8"}),e.jsx("option",{value:"ssh",children:"SSH config"})]})]}),e.jsxs("label",{children:[t("nodeSourcePath"),e.jsx("input",{required:!0,autoFocus:!0,value:C.path,onChange:n=>y({...C,path:n.target.value})})]}),e.jsxs("div",{className:"node-modal-actions",children:[e.jsx("button",{type:"button",onClick:()=>y(null),children:t("cancel")}),e.jsx("button",{type:"submit",children:t("nodeSyncKeep")}),e.jsx("button",{type:"button",disabled:!C.path.trim(),onClick:()=>j("source_add",void 0,{...C,enabled:!1}),children:t("nodeImportOnce")})]})]})}),V&&e.jsx("div",{className:"node-modal-backdrop",children:e.jsxs("form",{className:"node-modal",onSubmit:n=>{n.preventDefault();const i={auth:U,secret:be,persist:S,sameGroup:E,...U==="key"?{keyPath:fe}:{}};re.current={nodeId:V.id,payload:i},ge(!0),j("credential_test",V.id,i)},children:[e.jsx("h2",{children:V.name}),e.jsxs("code",{children:[V.username,"@",V.host,":",V.port]}),e.jsxs("label",{children:[t("nodeAuth"),e.jsxs("select",{disabled:R,value:U,onChange:n=>{ce(n.target.value),F(""),k(!1)},children:[e.jsx("option",{value:"password",children:t("nodePassword")}),e.jsx("option",{value:"key",children:t("nodeKey")})]})]}),e.jsx("p",{className:"node-muted",children:t("nodeLocalAuthHint")}),e.jsx(e.Fragment,{children:U==="key"&&e.jsxs(e.Fragment,{children:[e.jsxs("label",{children:[t("nodeKeyPath"),e.jsx("input",{required:!0,value:fe,onChange:n=>oe(n.target.value)})]}),e.jsx("p",{className:"node-muted",children:t("nodePrivateKeyHint")})]})}),e.jsxs("label",{children:[t(U==="key"?"nodePassphrase":"nodePassword"),e.jsx("input",{autoFocus:!0,type:"password",autoComplete:"new-password",required:U==="password",value:be,onChange:n=>F(n.target.value)})]}),e.jsxs("label",{className:"node-checkbox",children:[e.jsx("input",{type:"checkbox",checked:S,onChange:n=>N(n.target.checked)}),t("nodePersistSecret")]}),U==="password"&&e.jsxs("label",{className:"node-checkbox",children:[e.jsx("input",{type:"checkbox",checked:E,onChange:n=>k(n.target.checked)}),t("nodeGroupSecret")]}),E&&e.jsx("p",{className:"node-muted",children:t("nodeGroupHint")}),e.jsx("p",{className:"node-muted",children:t("nodeCredentialHint")}),e.jsxs("div",{className:"node-modal-actions",children:[e.jsx("button",{type:"button",disabled:R,onClick:()=>{Y.current.delete(V.id),a(null),F(""),re.current=null},children:t("cancel")}),e.jsx("button",{disabled:R,className:"node-primary",children:t(R?"nodeTesting":"nodeTestSave")})]})]})}),v&&e.jsx("div",{className:"node-modal-backdrop",children:e.jsxs("form",{className:"node-modal",onSubmit:n=>{n.preventDefault(),j("save",v.id,{...v,secret:be||void 0})},children:[e.jsx("h2",{children:v.id?t("nodeEdit"):t("nodeAdd")}),[["group",t("nodeGroup")],["name",t("nodeName")],["host",t("nodeAddress")],["port",t("nodePort")],["username",t("nodeUsername")],["defaultDir",t("nodeDefaultDir")]].map(([n,i])=>e.jsxs("label",{children:[i,e.jsx("input",{required:n!=="group",value:String(v[n]??""),onChange:o=>B({...v,[n]:n==="port"?Number(o.target.value):o.target.value})})]},n)),e.jsxs("label",{children:[t("nodeAuth"),e.jsxs("select",{value:v.auth,onChange:n=>B({...v,auth:n.target.value}),children:[e.jsx("option",{value:"password",children:t("nodePassword")}),e.jsx("option",{value:"key",children:t("nodeKey")}),e.jsx("option",{value:"agent",children:t("nodeAgentAuth")})]})]}),v.auth==="key"&&e.jsxs("label",{children:[t("nodeKeyPath"),e.jsx("input",{value:v.keyPath??"",onChange:n=>B({...v,keyPath:n.target.value})})]}),v.auth!=="agent"&&e.jsxs("label",{children:[v.auth==="key"?t("nodePassphrase"):t("nodePassword"),e.jsx("input",{type:"password",value:be,onChange:n=>F(n.target.value),placeholder:v.hasSecret?t("nodeKeepSecret"):""})]}),e.jsxs("div",{className:"node-modal-actions",children:[v.id&&v.fingerprint&&e.jsx("button",{type:"button",onClick:()=>{window.confirm(t("nodeForgetHostKeyConfirm",{name:v.name??""}))&&j("forget_host_key",v.id)},children:t("nodeForgetHostKey")}),v.id&&e.jsx("button",{type:"button",onClick:()=>{window.confirm(t("nodeDeleteConfirm",{name:v.name??""}))&&(j("delete",v.id),B(null))},children:t("nodeDelete")}),e.jsx("button",{type:"button",onClick:()=>B(null),children:t("cancel")}),e.jsx("button",{type:"submit",children:t("save")})]})]})})," "]})}export{Un as NodeWorkbench};
@@ -0,0 +1,2 @@
1
+ import{a as m,j as n}from"./markdown-BhJ_LInD.js";import{b as $,T as K,u as P,F as q,a as A,c as L,d as B,e as J,f as W,g as X,h as G,r as Q}from"./index-C5or_GAq.js";import{D as U,o as V}from"./xterm-D1D2FVe3.js";/* empty css */import"./react-BddUxV-9.js";function Y({conversationId:s,terminalId:r,command:f,cwd:R,active:t,send:u,register:x}){const v=m.useRef(null),w=m.useRef(t);w.current=t;const N=m.useRef(null),b=f?JSON.stringify(f):"";return m.useEffect(()=>{const d=v.current;if(!d)return;const a=new U({theme:$(),fontFamily:'"SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace',fontSize:13,cursorBlink:!0,scrollback:8e3}),l=new V;a.loadAddon(l),a.open(d),N.current={term:a,fit:l},t&&a.focus();const j=()=>{a.options.theme=$()};window.addEventListener(K,j),a.attachCustomKeyEventHandler(o=>{var F;if(o.type!=="keydown")return!0;const E=(F=o.key)==null?void 0:F.toLowerCase();if((o.ctrlKey||o.metaKey)&&E==="v")return!1;if(o.ctrlKey&&!o.shiftKey&&!o.altKey&&E==="c"&&a.hasSelection()){const T=a.textarea;return T&&(T.value=a.getSelection(),T.select()),!1}return!0});const g=x(s,r,{write:o=>a.write(o),dispose:()=>a.dispose()}),C=()=>{if(!(!w.current||!d.clientWidth||!d.clientHeight))try{l.fit(),u({type:"terminal_resize",terminalId:r,conversationId:s,cols:a.cols,rows:a.rows})}catch{}},h=requestAnimationFrame(()=>{try{l.fit()}catch{}u(f?{type:"run_command",terminalId:r,conversationId:s,command:f,cols:a.cols,rows:a.rows}:{type:"terminal_create",terminalId:r,conversationId:s,cwd:R,cols:a.cols,rows:a.rows})}),k=a.onData(o=>{u({type:"terminal_input",terminalId:r,conversationId:s,data:o})});let y=null;return typeof ResizeObserver<"u"&&(y=new ResizeObserver(()=>{d.offsetWidth>0&&d.offsetHeight>0&&C()}),y.observe(d)),()=>{cancelAnimationFrame(h),k.dispose(),window.removeEventListener(K,j),y==null||y.disconnect(),g(),a.dispose(),N.current=null}},[s,r,b,u,x]),m.useEffect(()=>{if(!t)return;const d=requestAnimationFrame(()=>{const a=N.current;if(a){try{a.fit.fit(),u({type:"terminal_resize",terminalId:r,conversationId:s,cols:a.term.cols,rows:a.term.rows})}catch{}a.term.focus()}});return()=>cancelAnimationFrame(d)},[t]),n.jsx("div",{ref:v,className:`term-xterm ${t?"":"hidden"}`})}const H={name:"",command:"",cwd:"${pwd}"};function ae({chat:s,send:r,terminal:f,active:R}){const t=P(),[u,x]=m.useState(null),[v,w]=m.useState(!1),[N,b]=m.useState(!1),[d,a]=m.useState(null),[l,j]=m.useState(H),[g,C]=m.useState(null),h=m.useRef(null);m.useEffect(()=>{s.terminals.length===0?x(null):s.terminals.some(e=>e.id===u)||x(s.terminals[s.terminals.length-1].id)},[s.terminals,u]),m.useEffect(()=>()=>{h.current&&clearTimeout(h.current)},[]);const k=e=>{var p;if(!s.ready)return;const i=Q(),c=s.activeConversationId||((p=s.state)==null?void 0:p.conversationId)||"";f.create({...e,id:i,conversationId:c,cols:e.cols??80,rows:e.rows??24,running:!0,exitCode:null}),x(i),w(!1)},y=()=>{var e;return k({title:t("terminalTitle",{n:s.terminals.length+1}),cwd:((e=s.state)==null?void 0:e.cwd)??""})},o=e=>{var p;const i=e.name||e.command,c=s.terminals.find(_=>_.title===i);if(c){f.restart(c.id),x(c.id),r({type:"run_command",terminalId:c.id,conversationId:c.conversationId,command:e,cols:80,rows:24});return}k({title:i,cwd:((p=s.state)==null?void 0:p.cwd)??"",command:e})},E=e=>{const i=s.terminals.find(c=>c.id===e);if(i&&r({type:"terminal_kill",terminalId:e,conversationId:i.conversationId}),f.close(e),u===e){const c=s.terminals.filter(p=>p.id!==e);x(c.length>0?c[c.length-1].id:null)}},F=()=>{b(!0),a(null),j(H)},T=e=>{const i=s.commands[e];i&&(b(!1),a(e),j({name:i.name,command:i.command,cwd:i.cwd??""}))},D=()=>{b(!1),a(null)},S=()=>{const e=l.name.trim(),i=l.command.trim();if(!e||!i)return;const c=l.cwd.trim(),p={name:e,command:i,cwd:c||void 0},_=N?[...s.commands,p]:d!==null?s.commands.map((z,O)=>O===d?p:z):s.commands;r({type:"save_commands",commands:_}),D()},I=e=>{if(g===e){const i=s.commands.filter((c,p)=>p!==e);r({type:"save_commands",commands:i}),C(null),h.current&&clearTimeout(h.current)}else C(e),h.current&&clearTimeout(h.current),h.current=setTimeout(()=>C(null),2500)},M=N||d!==null;return n.jsxs("div",{className:"terminal-view",children:[n.jsxs("aside",{className:`term-side term-commands ${v?"open":""}`,children:[n.jsxs("div",{className:"panel-header",children:[n.jsx("span",{className:"panel-title",children:t("commands")}),n.jsxs("div",{className:"panel-header-actions",children:[n.jsx("button",{type:"button",className:"panel-refresh",title:t("rerun"),onClick:()=>r({type:"list_commands"}),children:n.jsx(q,{})}),n.jsx("button",{type:"button",className:"panel-new",title:t("newCommand"),onClick:F,children:n.jsx(A,{})})]})]}),n.jsx("div",{className:"panel-body",children:M?n.jsxs("div",{className:"cmd-form",children:[n.jsx("label",{htmlFor:"cmd-name",children:t("name")}),n.jsx("input",{id:"cmd-name",className:"cmd-input",value:l.name,placeholder:t("exampleName"),autoFocus:!0,onChange:e=>j({...l,name:e.target.value})}),n.jsx("label",{htmlFor:"cmd-command",children:t("command")}),n.jsx("input",{id:"cmd-command",className:"cmd-input",value:l.command,placeholder:t("exampleCommand"),onChange:e=>j({...l,command:e.target.value}),onKeyDown:e=>{e.key==="Enter"&&!e.nativeEvent.isComposing&&S()}}),n.jsxs("label",{htmlFor:"cmd-cwd",children:[t("directory")," ",n.jsx("span",{className:"cmd-hint",children:t("cwdHint")})]}),n.jsx("input",{id:"cmd-cwd",className:"cmd-input",value:l.cwd,placeholder:"${pwd}",onChange:e=>j({...l,cwd:e.target.value}),onKeyDown:e=>{e.key==="Enter"&&!e.nativeEvent.isComposing&&S()}}),n.jsxs("div",{className:"cmd-form-actions",children:[n.jsx("button",{type:"button",className:"btn",onClick:D,children:t("cancel")}),n.jsx("button",{type:"button",className:"btn primary",disabled:!l.name.trim()||!l.command.trim(),onClick:S,children:t("save")})]})]}):n.jsxs(n.Fragment,{children:[s.commands.length===0&&n.jsx("div",{className:"panel-empty",children:t("noCommands")}),s.commands.map((e,i)=>n.jsxs("div",{className:"cmd-item",children:[n.jsx("button",{type:"button",className:"cmd-run",title:t("clickToRun"),onClick:()=>o(e),children:n.jsx(L,{})}),n.jsxs("button",{type:"button",className:"cmd-main",title:t("clickToRun"),onClick:()=>o(e),children:[n.jsx("span",{className:"cmd-name",children:e.name}),n.jsx("span",{className:"cmd-command",children:e.command}),e.cwd&&n.jsx("span",{className:"cmd-cwd",children:e.cwd})]}),n.jsx("button",{type:"button",className:"cmd-act",title:t("edit"),onClick:()=>T(i),children:n.jsx(B,{})}),n.jsx("button",{type:"button",className:`cmd-act del ${g===i?"confirm":""}`,title:t("delete"),onClick:()=>I(i),children:g===i?t("confirmQ"):n.jsx(J,{})})]},i))]})}),n.jsxs("div",{className:"term-tabs-block",children:[n.jsxs("div",{className:"panel-header",children:[n.jsx("span",{className:"panel-title",children:t("terminal")}),n.jsx("button",{type:"button",className:"panel-new",title:t("newTerminal"),onClick:y,children:n.jsx(A,{})})]}),n.jsxs("div",{className:"panel-body",children:[s.terminals.length===0&&n.jsx("div",{className:"panel-empty",children:t("noTerminal")}),s.terminals.map(e=>n.jsxs("div",{className:`term-tab ${e.id===u?"active":""}`,children:[n.jsxs("button",{type:"button",className:"term-tab-main",title:`${e.cwd}${e.command?`
2
+ > ${e.command.command}`:""}`,onClick:()=>{x(e.id),w(!1)},children:[n.jsx("span",{className:`term-tab-dot ${e.running?"run":"exit"}`}),n.jsxs("span",{className:"term-tab-title",children:[e.title,!e.running&&n.jsx("span",{className:"term-tab-exit",children:t("exited",{code:e.exitCode===null?"":` ${e.exitCode}`})})]})]}),n.jsx("button",{type:"button",className:"term-tab-close",title:t("closeTerminal"),onClick:()=>E(e.id),children:n.jsx(W,{})})]},e.id))]})]})]}),n.jsxs("div",{className:"term-main",children:[v&&n.jsx("div",{className:"drawer-backdrop",onClick:()=>w(!1)}),n.jsx("button",{type:"button",className:"term-side-toggle",title:t("commands"),onClick:()=>w(e=>!e),children:n.jsx(X,{})}),s.terminals.length===0?n.jsxs("div",{className:"term-empty",children:[n.jsx(G,{className:"term-empty-icon"}),n.jsx("div",{className:"term-empty-title",children:t("builtinTerminal")}),n.jsx("div",{className:"term-empty-sub",children:t("termEmptySub")})]}):s.terminals.map(e=>n.jsx(Y,{conversationId:e.conversationId,terminalId:e.id,command:e.command,cwd:e.cwd,active:R&&e.id===u,send:r,register:f.register},`${e.conversationId}:${e.id}`))]})]})}export{ae as TerminalPanel};
@@ -0,0 +1 @@
1
+ import{g as p,r as u,d as a}from"./chunk-SVP7TREG-l2XXTr2v.js";import{p as f}from"./chunk-JWPE2WC7-CrsdBGXT.js";import{_ as n,l as o}from"./mermaid.core-CO2nrD04.js";import{M as c,b as d}from"./cynefin-OW5HDTMX-IEk8qBRq.js";import"./index-C5or_GAq.js";import"./markdown-BhJ_LInD.js";import"./react-BddUxV-9.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},I={parser:R,db:a,renderer:u,styles:p};export{I as diagram};
@@ -0,0 +1 @@
1
+ import{a0 as ln,a1 as an,a2 as y,a3 as tn,a4 as H,a5 as q,a6 as _,a7 as un,a8 as rn,a9 as L,aa as o,ab as B,ac as sn,ad as on,ae as fn}from"./mermaid.core-CO2nrD04.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,C,a){var O=I-l,i=D-h,n=C-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function W(l,h,I,D,v,A,C){var a=l-I,O=h-D,i=(C?A:-A)/L(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,F=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*L(fn(0,T*T*R-P*P)),j=(P*g-m*S)/R,z=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=j-F,e=z-t,r=w-F,G=p-t;return x*x+e*e>r*r+G*G&&(j=w,z=p),{cx:j,cy:z,x01:-n,y01:-d,x11:j*(v/T-1),y11:z*(v/T-1)}}function hn(){var l=cn,h=yn,I=B(0),D=null,v=gn,A=dn,C=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-an,c=A.apply(this,arguments)-an,F=un(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(F>tn-y)a.moveTo(s*H(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*H(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=F,S=F,j=C.apply(this,arguments)/2,z=j>y&&(D?+D.apply(this,arguments):L(u*u+s*s)),w=_(un(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if(z>y){var G=sn(z/u*q(j)),M=sn(z/s*q(j));(P-=G*2)>y?(G*=t?1:-1,R+=G,T-=G):(P=0,R=T=(f+c)/2),(S-=M*2)>y?(M*=t?1:-1,m+=M,g-=M):(S=0,m=g=(f+c)/2)}var J=s*H(m),K=s*q(m),N=u*H(T),Q=u*q(T);if(w>y){var U=s*H(g),V=s*q(g),X=u*H(R),Y=u*q(R),E;if(F<rn)if(E=pn(J,K,X,Y,U,V,N,Q)){var Z=J-E[0],$=K-E[1],b=U-E[0],k=V-E[1],nn=1/q(on((Z*b+$*k)/(L(Z*Z+$*$)*L(b*b+k*k)))/2),en=L(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=W(X,Y,J,K,s,x,t),r=W(U,V,N,Q,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(J,K),a.arc(0,0,s,m,g,!t)):a.moveTo(J,K),!(u>y)||!(P>y)?a.lineTo(N,Q):p>y?(e=W(N,Q,U,V,u,-p,t),r=W(J,K,X,Y,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-rn/2;return[H(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:B(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:B(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:B(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:B(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:B(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:B(+n),i):A},i.padAngle=function(n){return arguments.length?(C=typeof n=="function"?n:B(+n),i):C},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};