termdock 1.4.264 → 1.4.266

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 (327) hide show
  1. package/dist/client/assets/App-DzRCmm_W.js +156 -0
  2. package/dist/client/assets/App-DzRCmm_W.js.br +0 -0
  3. package/dist/client/assets/App-DzRCmm_W.js.gz +0 -0
  4. package/dist/client/assets/{ChangeWalkthroughPanel-xq2AwXOA.js → ChangeWalkthroughPanel-N09mFFHb.js} +2 -2
  5. package/dist/client/assets/ChangeWalkthroughPanel-N09mFFHb.js.br +0 -0
  6. package/dist/client/assets/ChangeWalkthroughPanel-N09mFFHb.js.gz +0 -0
  7. package/dist/client/assets/{DagPlayground-C3ljSBdz.js → DagPlayground-BjU87Tm4.js} +1 -1
  8. package/dist/client/assets/DagPlayground-BjU87Tm4.js.br +0 -0
  9. package/dist/client/assets/DagPlayground-BjU87Tm4.js.gz +0 -0
  10. package/dist/client/assets/{DiffLab-Ducnm_Zp.js → DiffLab-COA-b5pN.js} +1 -1
  11. package/dist/client/assets/DiffLab-COA-b5pN.js.br +0 -0
  12. package/dist/client/assets/DiffLab-COA-b5pN.js.gz +0 -0
  13. package/dist/client/assets/{DiffReview-zTuUIB7N.js → DiffReview-DPEzF3Wb.js} +1 -1
  14. package/dist/client/assets/DiffReview-DPEzF3Wb.js.br +0 -0
  15. package/dist/client/assets/DiffReview-DPEzF3Wb.js.gz +0 -0
  16. package/dist/client/assets/{DiffReviewLab-CBlF880M.js → DiffReviewLab-Dq9gLO5P.js} +1 -1
  17. package/dist/client/assets/DiffReviewLab-Dq9gLO5P.js.br +0 -0
  18. package/dist/client/assets/DiffReviewLab-Dq9gLO5P.js.gz +0 -0
  19. package/dist/client/assets/DiffViewer-DNd0R8FA.js +37 -0
  20. package/dist/client/assets/DiffViewer-DNd0R8FA.js.br +0 -0
  21. package/dist/client/assets/DiffViewer-DNd0R8FA.js.gz +0 -0
  22. package/dist/client/assets/{ModelPreview-BPPustvB.js → ModelPreview-uqYy4UHn.js} +1 -1
  23. package/dist/client/assets/ModelPreview-uqYy4UHn.js.br +0 -0
  24. package/dist/client/assets/ModelPreview-uqYy4UHn.js.gz +0 -0
  25. package/dist/client/assets/{RightSidebar-BaDQ7Gpm.js → RightSidebar-Do0_u2am.js} +45 -45
  26. package/dist/client/assets/RightSidebar-Do0_u2am.js.br +0 -0
  27. package/dist/client/assets/RightSidebar-Do0_u2am.js.gz +0 -0
  28. package/dist/client/assets/{abnfDiagram-VCTEODGH-CqyKSrWN.js → abnfDiagram-VCTEODGH-C-F1hNwL.js} +1 -1
  29. package/dist/client/assets/abnfDiagram-VCTEODGH-C-F1hNwL.js.br +0 -0
  30. package/dist/client/assets/abnfDiagram-VCTEODGH-C-F1hNwL.js.gz +0 -0
  31. package/dist/client/assets/{app-CacB_zmS.js → app-BB-UfzoN.js} +9 -9
  32. package/dist/client/assets/app-BB-UfzoN.js.br +0 -0
  33. package/dist/client/assets/app-BB-UfzoN.js.gz +0 -0
  34. package/dist/client/assets/{arc-BgwdpkOZ.js → arc-Bj1HTggS.js} +1 -1
  35. package/dist/client/assets/arc-Bj1HTggS.js.br +0 -0
  36. package/dist/client/assets/arc-Bj1HTggS.js.gz +0 -0
  37. package/dist/client/assets/{architectureDiagram-5GKGNRK7-N1kpYkPE.js → architectureDiagram-5GKGNRK7-DiQ9VX2i.js} +1 -1
  38. package/dist/client/assets/architectureDiagram-5GKGNRK7-DiQ9VX2i.js.br +0 -0
  39. package/dist/client/assets/{architectureDiagram-5GKGNRK7-N1kpYkPE.js.gz → architectureDiagram-5GKGNRK7-DiQ9VX2i.js.gz} +0 -0
  40. package/dist/client/assets/{blockDiagram-I7D4REHJ-Dw81yows.js → blockDiagram-I7D4REHJ-Bs_OA90h.js} +1 -1
  41. package/dist/client/assets/blockDiagram-I7D4REHJ-Bs_OA90h.js.br +0 -0
  42. package/dist/client/assets/blockDiagram-I7D4REHJ-Bs_OA90h.js.gz +0 -0
  43. package/dist/client/assets/{c4Diagram-7LVT6UL2-D32t58M4.js → c4Diagram-7LVT6UL2-BF4InYpU.js} +1 -1
  44. package/dist/client/assets/c4Diagram-7LVT6UL2-BF4InYpU.js.br +0 -0
  45. package/dist/client/assets/c4Diagram-7LVT6UL2-BF4InYpU.js.gz +0 -0
  46. package/dist/client/assets/channel-D4Mx8Qe2.js +1 -0
  47. package/dist/client/assets/{chunk-2Q5K7J3B-C9UvOdT5.js → chunk-2Q5K7J3B-Cagkfj0j.js} +1 -1
  48. package/dist/client/assets/{chunk-5VM5RSS4-CFC27MFf.js → chunk-5VM5RSS4-CgX5Whwp.js} +1 -1
  49. package/dist/client/assets/{chunk-F27PBJKO-B4-9Xrnz.js → chunk-F27PBJKO-B8w3974i.js} +1 -1
  50. package/dist/client/assets/chunk-F27PBJKO-B8w3974i.js.br +0 -0
  51. package/dist/client/assets/chunk-F27PBJKO-B8w3974i.js.gz +0 -0
  52. package/dist/client/assets/{chunk-IMKFNOWR-CsBaOmDp.js → chunk-IMKFNOWR-BgtujxgQ.js} +1 -1
  53. package/dist/client/assets/chunk-IMKFNOWR-BgtujxgQ.js.br +0 -0
  54. package/dist/client/assets/chunk-IMKFNOWR-BgtujxgQ.js.gz +0 -0
  55. package/dist/client/assets/{chunk-JWPE2WC7-Ck04aXnz.js → chunk-JWPE2WC7-Cf7NLgli.js} +1 -1
  56. package/dist/client/assets/{chunk-POPQ4Y6H-BqcqNVVk.js → chunk-POPQ4Y6H-BQst9Llh.js} +1 -1
  57. package/dist/client/assets/{chunk-SVP7TREG-OpdssCsG.js → chunk-SVP7TREG-D4PwA2QX.js} +1 -1
  58. package/dist/client/assets/chunk-SVP7TREG-D4PwA2QX.js.br +0 -0
  59. package/dist/client/assets/chunk-SVP7TREG-D4PwA2QX.js.gz +0 -0
  60. package/dist/client/assets/{chunk-TICWLB2K-CDexR7sW.js → chunk-TICWLB2K-DHnYkG_x.js} +1 -1
  61. package/dist/client/assets/chunk-TICWLB2K-DHnYkG_x.js.br +0 -0
  62. package/dist/client/assets/chunk-TICWLB2K-DHnYkG_x.js.gz +0 -0
  63. package/dist/client/assets/{chunk-XXDRQBXY-DNtcUYbk.js → chunk-XXDRQBXY-BHWFSVth.js} +1 -1
  64. package/dist/client/assets/classDiagram-ZZMXUADV-e0EybKcM.js +1 -0
  65. package/dist/client/assets/classDiagram-v2-VYDZK3BY-e0EybKcM.js +1 -0
  66. package/dist/client/assets/{cose-bilkent-JH36ORCC-cTbTSxj8.js → cose-bilkent-JH36ORCC-CCFMhjak.js} +1 -1
  67. package/dist/client/assets/cose-bilkent-JH36ORCC-CCFMhjak.js.br +0 -0
  68. package/dist/client/assets/cose-bilkent-JH36ORCC-CCFMhjak.js.gz +0 -0
  69. package/dist/client/assets/{cynefin-OW5HDTMX-Rm2aJeBM.js → cynefin-OW5HDTMX-aeeCA73W.js} +1 -1
  70. package/dist/client/assets/cynefin-OW5HDTMX-aeeCA73W.js.br +0 -0
  71. package/dist/client/assets/cynefin-OW5HDTMX-aeeCA73W.js.gz +0 -0
  72. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-CBBrWwPa.js → cynefinDiagram-5FMLGOSQ-Qd4yv-WB.js} +1 -1
  73. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Qd4yv-WB.js.br +0 -0
  74. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Qd4yv-WB.js.gz +0 -0
  75. package/dist/client/assets/{dagre-GXQ25YYZ-srDwDfcU.js → dagre-GXQ25YYZ-tYsGlQq_.js} +1 -1
  76. package/dist/client/assets/dagre-GXQ25YYZ-tYsGlQq_.js.br +0 -0
  77. package/dist/client/assets/dagre-GXQ25YYZ-tYsGlQq_.js.gz +0 -0
  78. package/dist/client/assets/{diagram-S7CK7UJ4-CTwLQY9V.js → diagram-S7CK7UJ4-C1Bc6nbm.js} +1 -1
  79. package/dist/client/assets/diagram-S7CK7UJ4-C1Bc6nbm.js.br +0 -0
  80. package/dist/client/assets/diagram-S7CK7UJ4-C1Bc6nbm.js.gz +0 -0
  81. package/dist/client/assets/{diagram-UQ7AKVKN-BT_rALfG.js → diagram-UQ7AKVKN-SdvjJa7O.js} +1 -1
  82. package/dist/client/assets/diagram-UQ7AKVKN-SdvjJa7O.js.br +0 -0
  83. package/dist/client/assets/diagram-UQ7AKVKN-SdvjJa7O.js.gz +0 -0
  84. package/dist/client/assets/{diagram-VSXAHHWV-BKsGk0lY.js → diagram-VSXAHHWV-CopEWwGT.js} +1 -1
  85. package/dist/client/assets/diagram-VSXAHHWV-CopEWwGT.js.br +0 -0
  86. package/dist/client/assets/diagram-VSXAHHWV-CopEWwGT.js.gz +0 -0
  87. package/dist/client/assets/{diagram-VX7I27RA-BYbtwhbM.js → diagram-VX7I27RA-CKdAVxN-.js} +1 -1
  88. package/dist/client/assets/diagram-VX7I27RA-CKdAVxN-.js.br +0 -0
  89. package/dist/client/assets/diagram-VX7I27RA-CKdAVxN-.js.gz +0 -0
  90. package/dist/client/assets/{diagram-Z3DM3KII-Db0I7mu4.js → diagram-Z3DM3KII-x9ISSrse.js} +1 -1
  91. package/dist/client/assets/diagram-Z3DM3KII-x9ISSrse.js.br +0 -0
  92. package/dist/client/assets/diagram-Z3DM3KII-x9ISSrse.js.gz +0 -0
  93. package/dist/client/assets/{ebnfDiagram-PWID7BFC-BWizg7gn.js → ebnfDiagram-PWID7BFC-Bta60dSv.js} +1 -1
  94. package/dist/client/assets/ebnfDiagram-PWID7BFC-Bta60dSv.js.br +0 -0
  95. package/dist/client/assets/ebnfDiagram-PWID7BFC-Bta60dSv.js.gz +0 -0
  96. package/dist/client/assets/{erDiagram-RLTQ6QDP-BwUS8fPZ.js → erDiagram-RLTQ6QDP-sB_bIQ0I.js} +1 -1
  97. package/dist/client/assets/erDiagram-RLTQ6QDP-sB_bIQ0I.js.br +0 -0
  98. package/dist/client/assets/erDiagram-RLTQ6QDP-sB_bIQ0I.js.gz +0 -0
  99. package/dist/client/assets/{flowDiagram-HODETNUW-MAzdNa6g.js → flowDiagram-HODETNUW-D-5EW4Om.js} +1 -1
  100. package/dist/client/assets/flowDiagram-HODETNUW-D-5EW4Om.js.br +0 -0
  101. package/dist/client/assets/flowDiagram-HODETNUW-D-5EW4Om.js.gz +0 -0
  102. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-C8VaA5zH.js → ganttDiagram-EL5Y4UJY-x4bF8XHI.js} +1 -1
  103. package/dist/client/assets/ganttDiagram-EL5Y4UJY-x4bF8XHI.js.br +0 -0
  104. package/dist/client/assets/ganttDiagram-EL5Y4UJY-x4bF8XHI.js.gz +0 -0
  105. package/dist/client/assets/{gestureArbiter-BkdwKXjM.js → gestureArbiter-C7V1_Sm6.js} +1 -1
  106. package/dist/client/assets/gestureArbiter-C7V1_Sm6.js.br +0 -0
  107. package/dist/client/assets/gestureArbiter-C7V1_Sm6.js.gz +0 -0
  108. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-BX2iDm_R.js → gitGraphDiagram-WWUBYQGX-pKX7lvtX.js} +1 -1
  109. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-pKX7lvtX.js.br +0 -0
  110. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-pKX7lvtX.js.gz +0 -0
  111. package/dist/client/assets/{index-BbK6xNAN.css → index-CQGiUA31.css} +1 -1
  112. package/dist/client/assets/index-CQGiUA31.css.br +0 -0
  113. package/dist/client/assets/{index-BbK6xNAN.css.gz → index-CQGiUA31.css.gz} +0 -0
  114. package/dist/client/assets/{infoDiagram-27XIBGKW-Ns3hP0eV.js → infoDiagram-27XIBGKW-ibYLF4lB.js} +1 -1
  115. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-Bv4pVCgQ.js → ishikawaDiagram-5VMMS53U-BF0rhBil.js} +1 -1
  116. package/dist/client/assets/ishikawaDiagram-5VMMS53U-BF0rhBil.js.br +0 -0
  117. package/dist/client/assets/ishikawaDiagram-5VMMS53U-BF0rhBil.js.gz +0 -0
  118. package/dist/client/assets/{journeyDiagram-3NMN7TZE-DRRi377b.js → journeyDiagram-3NMN7TZE-DR_bXhpA.js} +1 -1
  119. package/dist/client/assets/journeyDiagram-3NMN7TZE-DR_bXhpA.js.br +0 -0
  120. package/dist/client/assets/journeyDiagram-3NMN7TZE-DR_bXhpA.js.gz +0 -0
  121. package/dist/client/assets/{kanban-definition-UXKFOSKX-B7L-csMZ.js → kanban-definition-UXKFOSKX-rLtDawpv.js} +1 -1
  122. package/dist/client/assets/kanban-definition-UXKFOSKX-rLtDawpv.js.br +0 -0
  123. package/dist/client/assets/kanban-definition-UXKFOSKX-rLtDawpv.js.gz +0 -0
  124. package/dist/client/assets/{layout-BxSxAk6Q.js → layout-abNq6Us0.js} +1 -1
  125. package/dist/client/assets/{layout-BxSxAk6Q.js.br → layout-abNq6Us0.js.br} +0 -0
  126. package/dist/client/assets/layout-abNq6Us0.js.gz +0 -0
  127. package/dist/client/assets/{linear-BXjh9BXc.js → linear-B6ZlmcfV.js} +1 -1
  128. package/dist/client/assets/linear-B6ZlmcfV.js.br +0 -0
  129. package/dist/client/assets/linear-B6ZlmcfV.js.gz +0 -0
  130. package/dist/client/assets/{mermaid.core-5r_1zWs_.js → mermaid.core-DH5DL9hV.js} +5 -5
  131. package/dist/client/assets/mermaid.core-DH5DL9hV.js.br +0 -0
  132. package/dist/client/assets/mermaid.core-DH5DL9hV.js.gz +0 -0
  133. package/dist/client/assets/{mindmap-definition-YA3MSWOX-DUhDC9wQ.js → mindmap-definition-YA3MSWOX-Bjmuduw6.js} +1 -1
  134. package/dist/client/assets/mindmap-definition-YA3MSWOX-Bjmuduw6.js.br +0 -0
  135. package/dist/client/assets/mindmap-definition-YA3MSWOX-Bjmuduw6.js.gz +0 -0
  136. package/dist/client/assets/{passwordBootstrap-Cwjat0qO.js → passwordBootstrap-J17_f0uK.js} +2 -2
  137. package/dist/client/assets/passwordBootstrap-J17_f0uK.js.br +0 -0
  138. package/dist/client/assets/passwordBootstrap-J17_f0uK.js.gz +0 -0
  139. package/dist/client/assets/{pegDiagram-XKGWAZYB-C-SLAJDe.js → pegDiagram-XKGWAZYB-BVVc1guP.js} +1 -1
  140. package/dist/client/assets/pegDiagram-XKGWAZYB-BVVc1guP.js.br +0 -0
  141. package/dist/client/assets/pegDiagram-XKGWAZYB-BVVc1guP.js.gz +0 -0
  142. package/dist/client/assets/{pieDiagram-E7YTZNPT-qRG_HAda.js → pieDiagram-E7YTZNPT-iyGrttc6.js} +1 -1
  143. package/dist/client/assets/pieDiagram-E7YTZNPT-iyGrttc6.js.br +0 -0
  144. package/dist/client/assets/pieDiagram-E7YTZNPT-iyGrttc6.js.gz +0 -0
  145. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-Cx85SpAC.js → quadrantDiagram-AXDQQJYC-Djqtsu2z.js} +1 -1
  146. package/dist/client/assets/quadrantDiagram-AXDQQJYC-Djqtsu2z.js.br +0 -0
  147. package/dist/client/assets/quadrantDiagram-AXDQQJYC-Djqtsu2z.js.gz +0 -0
  148. package/dist/client/assets/{railroadDiagram-O6MQD6OU-CHUzbbuc.js → railroadDiagram-O6MQD6OU-C2ph9wgs.js} +1 -1
  149. package/dist/client/assets/railroadDiagram-O6MQD6OU-C2ph9wgs.js.br +0 -0
  150. package/dist/client/assets/railroadDiagram-O6MQD6OU-C2ph9wgs.js.gz +0 -0
  151. package/dist/client/assets/{referenceLongPress-CkmKcttc.js → referenceLongPress-Bm0VuySQ.js} +1 -1
  152. package/dist/client/assets/referenceLongPress-Bm0VuySQ.js.br +0 -0
  153. package/dist/client/assets/referenceLongPress-Bm0VuySQ.js.gz +0 -0
  154. package/dist/client/assets/{requirementDiagram-BXWQKSXE-BMLDFHF4.js → requirementDiagram-BXWQKSXE-vXjbhdRD.js} +1 -1
  155. package/dist/client/assets/requirementDiagram-BXWQKSXE-vXjbhdRD.js.br +0 -0
  156. package/dist/client/assets/requirementDiagram-BXWQKSXE-vXjbhdRD.js.gz +0 -0
  157. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-BWS5I_IL.js → sankeyDiagram-P5KCCOFB-SNiiKcgp.js} +1 -1
  158. package/dist/client/assets/sankeyDiagram-P5KCCOFB-SNiiKcgp.js.br +0 -0
  159. package/dist/client/assets/sankeyDiagram-P5KCCOFB-SNiiKcgp.js.gz +0 -0
  160. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-BPdGEV61.js → sequenceDiagram-WJ2MYXX4-Fn2oExLH.js} +1 -1
  161. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Fn2oExLH.js.br +0 -0
  162. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Fn2oExLH.js.gz +0 -0
  163. package/dist/client/assets/{sizeCapture-INFHLROL-oxQ5oK3g.js → sizeCapture-INFHLROL-FoHuOCXL.js} +1 -1
  164. package/dist/client/assets/sizeCapture-INFHLROL-FoHuOCXL.js.br +0 -0
  165. package/dist/client/assets/sizeCapture-INFHLROL-FoHuOCXL.js.gz +0 -0
  166. package/dist/client/assets/{sparkles-MZp-tT_G.js → sparkles-BpV0BVRF.js} +1 -1
  167. package/dist/client/assets/{stateDiagram-D77RDMKH-DtSfST46.js → stateDiagram-D77RDMKH-BiBiBFDH.js} +1 -1
  168. package/dist/client/assets/stateDiagram-D77RDMKH-BiBiBFDH.js.br +0 -0
  169. package/dist/client/assets/stateDiagram-D77RDMKH-BiBiBFDH.js.gz +0 -0
  170. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-_Vs6ah69.js +1 -0
  171. package/dist/client/assets/{swimlanes-42K2YHIH-BqUlkZ_F.js → swimlanes-42K2YHIH-8_6AEHBA.js} +1 -1
  172. package/dist/client/assets/swimlanes-42K2YHIH-8_6AEHBA.js.br +0 -0
  173. package/dist/client/assets/swimlanes-42K2YHIH-8_6AEHBA.js.gz +0 -0
  174. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DCbcOwps.js +8 -0
  175. package/dist/client/assets/{timeline-definition-24CTP7MA-B__ZTuwu.js → timeline-definition-24CTP7MA-vh_kdWEp.js} +1 -1
  176. package/dist/client/assets/timeline-definition-24CTP7MA-vh_kdWEp.js.br +0 -0
  177. package/dist/client/assets/timeline-definition-24CTP7MA-vh_kdWEp.js.gz +0 -0
  178. package/dist/client/assets/{triangle-alert-DN7qGh3M.js → triangle-alert-BDY-HlS4.js} +1 -1
  179. package/dist/client/assets/{vennDiagram-4TSXK5OY-C6JudjQT.js → vennDiagram-4TSXK5OY-DD1-E-ya.js} +1 -1
  180. package/dist/client/assets/{vennDiagram-4TSXK5OY-C6JudjQT.js.br → vennDiagram-4TSXK5OY-DD1-E-ya.js.br} +0 -0
  181. package/dist/client/assets/vennDiagram-4TSXK5OY-DD1-E-ya.js.gz +0 -0
  182. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-BHt61gtN.js → wardleyDiagram-VM6X3IG4-HMOrL8bB.js} +1 -1
  183. package/dist/client/assets/wardleyDiagram-VM6X3IG4-HMOrL8bB.js.br +0 -0
  184. package/dist/client/assets/wardleyDiagram-VM6X3IG4-HMOrL8bB.js.gz +0 -0
  185. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-C0rZbFNo.js → xychartDiagram-S5SC5T6Z-DUxhnGCd.js} +1 -1
  186. package/dist/client/assets/xychartDiagram-S5SC5T6Z-DUxhnGCd.js.br +0 -0
  187. package/dist/client/assets/xychartDiagram-S5SC5T6Z-DUxhnGCd.js.gz +0 -0
  188. package/dist/client/index.html +2 -2
  189. package/dist/client/index.html.br +0 -0
  190. package/dist/client/index.html.gz +0 -0
  191. package/dist/client/sw.js +1 -1
  192. package/dist/client/sw.js.br +0 -0
  193. package/dist/client/sw.js.gz +0 -0
  194. package/dist/server/android/recording.js +178 -0
  195. package/dist/server/cli.js +20 -0
  196. package/dist/server/entry.js +5 -2
  197. package/dist/server/routes/android.js +55 -0
  198. package/dist/server/routes/filesystem.js +6 -2
  199. package/dist/server/routes/terminal.js +30 -2
  200. package/dist/server/supervisionHandoff.js +33 -0
  201. package/dist/server/supervisor.js +6 -3
  202. package/dist/server/utils/enableSupervision.js +80 -0
  203. package/dist/server/utils/serverHealth.js +28 -3
  204. package/dist/server/utils/settings.js +1 -1
  205. package/dist/server/utils/startupFailure.js +16 -0
  206. package/dist/server/utils/supervisorProtocol.js +5 -0
  207. package/package.json +1 -1
  208. package/runtime-manifest.json +3 -3
  209. package/dist/client/assets/App-C-sArfYM.js +0 -156
  210. package/dist/client/assets/App-C-sArfYM.js.br +0 -0
  211. package/dist/client/assets/App-C-sArfYM.js.gz +0 -0
  212. package/dist/client/assets/ChangeWalkthroughPanel-xq2AwXOA.js.br +0 -0
  213. package/dist/client/assets/ChangeWalkthroughPanel-xq2AwXOA.js.gz +0 -0
  214. package/dist/client/assets/DagPlayground-C3ljSBdz.js.br +0 -0
  215. package/dist/client/assets/DagPlayground-C3ljSBdz.js.gz +0 -0
  216. package/dist/client/assets/DiffLab-Ducnm_Zp.js.br +0 -0
  217. package/dist/client/assets/DiffLab-Ducnm_Zp.js.gz +0 -0
  218. package/dist/client/assets/DiffReview-zTuUIB7N.js.br +0 -0
  219. package/dist/client/assets/DiffReview-zTuUIB7N.js.gz +0 -0
  220. package/dist/client/assets/DiffReviewLab-CBlF880M.js.br +0 -0
  221. package/dist/client/assets/DiffReviewLab-CBlF880M.js.gz +0 -0
  222. package/dist/client/assets/DiffViewer-D4UreLzY.js +0 -36
  223. package/dist/client/assets/DiffViewer-D4UreLzY.js.br +0 -0
  224. package/dist/client/assets/DiffViewer-D4UreLzY.js.gz +0 -0
  225. package/dist/client/assets/ModelPreview-BPPustvB.js.br +0 -0
  226. package/dist/client/assets/ModelPreview-BPPustvB.js.gz +0 -0
  227. package/dist/client/assets/RightSidebar-BaDQ7Gpm.js.br +0 -0
  228. package/dist/client/assets/RightSidebar-BaDQ7Gpm.js.gz +0 -0
  229. package/dist/client/assets/abnfDiagram-VCTEODGH-CqyKSrWN.js.br +0 -0
  230. package/dist/client/assets/abnfDiagram-VCTEODGH-CqyKSrWN.js.gz +0 -0
  231. package/dist/client/assets/app-CacB_zmS.js.br +0 -0
  232. package/dist/client/assets/app-CacB_zmS.js.gz +0 -0
  233. package/dist/client/assets/arc-BgwdpkOZ.js.br +0 -0
  234. package/dist/client/assets/arc-BgwdpkOZ.js.gz +0 -0
  235. package/dist/client/assets/architectureDiagram-5GKGNRK7-N1kpYkPE.js.br +0 -0
  236. package/dist/client/assets/blockDiagram-I7D4REHJ-Dw81yows.js.br +0 -0
  237. package/dist/client/assets/blockDiagram-I7D4REHJ-Dw81yows.js.gz +0 -0
  238. package/dist/client/assets/c4Diagram-7LVT6UL2-D32t58M4.js.br +0 -0
  239. package/dist/client/assets/c4Diagram-7LVT6UL2-D32t58M4.js.gz +0 -0
  240. package/dist/client/assets/channel-DhLuwycJ.js +0 -1
  241. package/dist/client/assets/chunk-F27PBJKO-B4-9Xrnz.js.br +0 -0
  242. package/dist/client/assets/chunk-F27PBJKO-B4-9Xrnz.js.gz +0 -0
  243. package/dist/client/assets/chunk-IMKFNOWR-CsBaOmDp.js.br +0 -0
  244. package/dist/client/assets/chunk-IMKFNOWR-CsBaOmDp.js.gz +0 -0
  245. package/dist/client/assets/chunk-SVP7TREG-OpdssCsG.js.br +0 -0
  246. package/dist/client/assets/chunk-SVP7TREG-OpdssCsG.js.gz +0 -0
  247. package/dist/client/assets/chunk-TICWLB2K-CDexR7sW.js.br +0 -0
  248. package/dist/client/assets/chunk-TICWLB2K-CDexR7sW.js.gz +0 -0
  249. package/dist/client/assets/classDiagram-ZZMXUADV-WqsEmR1Y.js +0 -1
  250. package/dist/client/assets/classDiagram-v2-VYDZK3BY-WqsEmR1Y.js +0 -1
  251. package/dist/client/assets/cose-bilkent-JH36ORCC-cTbTSxj8.js.br +0 -0
  252. package/dist/client/assets/cose-bilkent-JH36ORCC-cTbTSxj8.js.gz +0 -0
  253. package/dist/client/assets/cynefin-OW5HDTMX-Rm2aJeBM.js.br +0 -0
  254. package/dist/client/assets/cynefin-OW5HDTMX-Rm2aJeBM.js.gz +0 -0
  255. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CBBrWwPa.js.br +0 -0
  256. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CBBrWwPa.js.gz +0 -0
  257. package/dist/client/assets/dagre-GXQ25YYZ-srDwDfcU.js.br +0 -0
  258. package/dist/client/assets/dagre-GXQ25YYZ-srDwDfcU.js.gz +0 -0
  259. package/dist/client/assets/diagram-S7CK7UJ4-CTwLQY9V.js.br +0 -0
  260. package/dist/client/assets/diagram-S7CK7UJ4-CTwLQY9V.js.gz +0 -0
  261. package/dist/client/assets/diagram-UQ7AKVKN-BT_rALfG.js.br +0 -0
  262. package/dist/client/assets/diagram-UQ7AKVKN-BT_rALfG.js.gz +0 -0
  263. package/dist/client/assets/diagram-VSXAHHWV-BKsGk0lY.js.br +0 -0
  264. package/dist/client/assets/diagram-VSXAHHWV-BKsGk0lY.js.gz +0 -0
  265. package/dist/client/assets/diagram-VX7I27RA-BYbtwhbM.js.br +0 -0
  266. package/dist/client/assets/diagram-VX7I27RA-BYbtwhbM.js.gz +0 -0
  267. package/dist/client/assets/diagram-Z3DM3KII-Db0I7mu4.js.br +0 -0
  268. package/dist/client/assets/diagram-Z3DM3KII-Db0I7mu4.js.gz +0 -0
  269. package/dist/client/assets/ebnfDiagram-PWID7BFC-BWizg7gn.js.br +0 -0
  270. package/dist/client/assets/ebnfDiagram-PWID7BFC-BWizg7gn.js.gz +0 -0
  271. package/dist/client/assets/erDiagram-RLTQ6QDP-BwUS8fPZ.js.br +0 -0
  272. package/dist/client/assets/erDiagram-RLTQ6QDP-BwUS8fPZ.js.gz +0 -0
  273. package/dist/client/assets/flowDiagram-HODETNUW-MAzdNa6g.js.br +0 -0
  274. package/dist/client/assets/flowDiagram-HODETNUW-MAzdNa6g.js.gz +0 -0
  275. package/dist/client/assets/ganttDiagram-EL5Y4UJY-C8VaA5zH.js.br +0 -0
  276. package/dist/client/assets/ganttDiagram-EL5Y4UJY-C8VaA5zH.js.gz +0 -0
  277. package/dist/client/assets/gestureArbiter-BkdwKXjM.js.br +0 -0
  278. package/dist/client/assets/gestureArbiter-BkdwKXjM.js.gz +0 -0
  279. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BX2iDm_R.js.br +0 -0
  280. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BX2iDm_R.js.gz +0 -0
  281. package/dist/client/assets/index-BbK6xNAN.css.br +0 -0
  282. package/dist/client/assets/ishikawaDiagram-5VMMS53U-Bv4pVCgQ.js.br +0 -0
  283. package/dist/client/assets/ishikawaDiagram-5VMMS53U-Bv4pVCgQ.js.gz +0 -0
  284. package/dist/client/assets/journeyDiagram-3NMN7TZE-DRRi377b.js.br +0 -0
  285. package/dist/client/assets/journeyDiagram-3NMN7TZE-DRRi377b.js.gz +0 -0
  286. package/dist/client/assets/kanban-definition-UXKFOSKX-B7L-csMZ.js.br +0 -0
  287. package/dist/client/assets/kanban-definition-UXKFOSKX-B7L-csMZ.js.gz +0 -0
  288. package/dist/client/assets/layout-BxSxAk6Q.js.gz +0 -0
  289. package/dist/client/assets/linear-BXjh9BXc.js.br +0 -0
  290. package/dist/client/assets/linear-BXjh9BXc.js.gz +0 -0
  291. package/dist/client/assets/mermaid.core-5r_1zWs_.js.br +0 -0
  292. package/dist/client/assets/mermaid.core-5r_1zWs_.js.gz +0 -0
  293. package/dist/client/assets/mindmap-definition-YA3MSWOX-DUhDC9wQ.js.br +0 -0
  294. package/dist/client/assets/mindmap-definition-YA3MSWOX-DUhDC9wQ.js.gz +0 -0
  295. package/dist/client/assets/passwordBootstrap-Cwjat0qO.js.br +0 -0
  296. package/dist/client/assets/passwordBootstrap-Cwjat0qO.js.gz +0 -0
  297. package/dist/client/assets/pegDiagram-XKGWAZYB-C-SLAJDe.js.br +0 -0
  298. package/dist/client/assets/pegDiagram-XKGWAZYB-C-SLAJDe.js.gz +0 -0
  299. package/dist/client/assets/pieDiagram-E7YTZNPT-qRG_HAda.js.br +0 -0
  300. package/dist/client/assets/pieDiagram-E7YTZNPT-qRG_HAda.js.gz +0 -0
  301. package/dist/client/assets/quadrantDiagram-AXDQQJYC-Cx85SpAC.js.br +0 -0
  302. package/dist/client/assets/quadrantDiagram-AXDQQJYC-Cx85SpAC.js.gz +0 -0
  303. package/dist/client/assets/railroadDiagram-O6MQD6OU-CHUzbbuc.js.br +0 -0
  304. package/dist/client/assets/railroadDiagram-O6MQD6OU-CHUzbbuc.js.gz +0 -0
  305. package/dist/client/assets/referenceLongPress-CkmKcttc.js.br +0 -0
  306. package/dist/client/assets/referenceLongPress-CkmKcttc.js.gz +0 -0
  307. package/dist/client/assets/requirementDiagram-BXWQKSXE-BMLDFHF4.js.br +0 -0
  308. package/dist/client/assets/requirementDiagram-BXWQKSXE-BMLDFHF4.js.gz +0 -0
  309. package/dist/client/assets/sankeyDiagram-P5KCCOFB-BWS5I_IL.js.br +0 -0
  310. package/dist/client/assets/sankeyDiagram-P5KCCOFB-BWS5I_IL.js.gz +0 -0
  311. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BPdGEV61.js.br +0 -0
  312. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BPdGEV61.js.gz +0 -0
  313. package/dist/client/assets/sizeCapture-INFHLROL-oxQ5oK3g.js.br +0 -0
  314. package/dist/client/assets/sizeCapture-INFHLROL-oxQ5oK3g.js.gz +0 -0
  315. package/dist/client/assets/stateDiagram-D77RDMKH-DtSfST46.js.br +0 -0
  316. package/dist/client/assets/stateDiagram-D77RDMKH-DtSfST46.js.gz +0 -0
  317. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-BF_rwi5O.js +0 -1
  318. package/dist/client/assets/swimlanes-42K2YHIH-BqUlkZ_F.js.br +0 -0
  319. package/dist/client/assets/swimlanes-42K2YHIH-BqUlkZ_F.js.gz +0 -0
  320. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DP9kFtCd.js +0 -8
  321. package/dist/client/assets/timeline-definition-24CTP7MA-B__ZTuwu.js.br +0 -0
  322. package/dist/client/assets/timeline-definition-24CTP7MA-B__ZTuwu.js.gz +0 -0
  323. package/dist/client/assets/vennDiagram-4TSXK5OY-C6JudjQT.js.gz +0 -0
  324. package/dist/client/assets/wardleyDiagram-VM6X3IG4-BHt61gtN.js.br +0 -0
  325. package/dist/client/assets/wardleyDiagram-VM6X3IG4-BHt61gtN.js.gz +0 -0
  326. package/dist/client/assets/xychartDiagram-S5SC5T6Z-C0rZbFNo.js.br +0 -0
  327. package/dist/client/assets/xychartDiagram-S5SC5T6Z-C0rZbFNo.js.gz +0 -0
@@ -31,6 +31,8 @@ import { fileURLToPath } from 'url';
31
31
  import { WebSocketServer } from 'ws';
32
32
  import terminalRoutes, { handleTerminalWebSocket, handleControlWebSocket, resolveStableFederationSessionId } from './routes/terminal.js';
33
33
  import androidRoutes, { handleAndroidWebSocket } from './routes/android.js';
34
+ import { exitWithStartupFailure } from './utils/startupFailure.js';
35
+ import { androidRecordings } from './android/recording.js';
34
36
  import { stopAllScrcpySessions } from './android/scrcpy.js';
35
37
  import filesystemRoutes from './routes/filesystem.js';
36
38
  import authRoutes from './routes/auth.js';
@@ -463,7 +465,7 @@ export function startServer(options = {}) {
463
465
  server.once('close', () => { clearInterval(desktopRoutesTimer); for (const target of dynamicDirectTargets.values())
464
466
  target.close(); });
465
467
  server.once('close', () => relayRouter.close());
466
- server.once('close', () => { void stopAllScrcpySessions(); });
468
+ server.once('close', () => { void stopAllScrcpySessions(); void androidRecordings.stopAll(); });
467
469
  const federation = createFederationRuntime(app, path.join(homedir(), '.termdock', 'federation'), {
468
470
  terminal: handleTerminalWebSocket, control: handleControlWebSocket, android: handleAndroidWebSocket,
469
471
  }, {
@@ -773,7 +775,8 @@ export function startServer(options = {}) {
773
775
  crashForensics.recordIncident('port-conflict', { extra: { port, host, code: error.code } });
774
776
  console.error(`Port ${port} is already in use.`);
775
777
  console.error(`To free it, find and stop the process: lsof -tiTCP:${port} -sTCP:LISTEN | xargs kill`);
776
- process.exit(1);
778
+ exitWithStartupFailure('port-conflict', `Port ${port} is already in use (EADDRINUSE).`);
779
+ return;
777
780
  }
778
781
  console.error('Server error:', error);
779
782
  process.exit(1);
@@ -1,6 +1,8 @@
1
1
  import { Router } from 'express';
2
2
  import { connectDevice, disconnectDevice, listDevices, resolveAdbBinary } from '../android/adb.js';
3
3
  import { createScrcpySession, resolveScrcpyBinaries } from '../android/scrcpy.js';
4
+ import { androidRecordings } from '../android/recording.js';
5
+ import { pathValidator } from '../utils/pathValidator.js';
4
6
  const router = Router();
5
7
  const SERIAL_PATTERN = /^[0-9a-zA-Z_.:\-]{1,128}$/;
6
8
  /** 逐帧/逐控件的诊断日志默认关闭,需要时 TERMDOCK_ANDROID_DEBUG=1 打开。 */
@@ -46,6 +48,59 @@ router.post('/disconnect', async (req, res) => {
46
48
  res.status(400).json({ error: message, code: message });
47
49
  }
48
50
  });
51
+ router.get('/recordings', async (req, res) => {
52
+ const serial = typeof req.query.serial === 'string' ? req.query.serial : '';
53
+ if (!isValidAndroidSerial(serial)) {
54
+ res.status(400).json({ error: 'INVALID_SERIAL' });
55
+ return;
56
+ }
57
+ try {
58
+ res.json({ recordings: await androidRecordings.list(serial) });
59
+ }
60
+ catch (error) {
61
+ res.status(500).json({ error: String(error) });
62
+ }
63
+ });
64
+ router.post('/recordings', async (req, res) => {
65
+ const serial = typeof req.body?.serial === 'string' ? req.body.serial : '';
66
+ if (!isValidAndroidSerial(serial)) {
67
+ res.status(400).json({ error: 'INVALID_SERIAL' });
68
+ return;
69
+ }
70
+ try {
71
+ res.json(await androidRecordings.start(serial));
72
+ }
73
+ catch (error) {
74
+ res.status(500).json({ error: error instanceof Error ? error.message : String(error) });
75
+ }
76
+ });
77
+ router.post('/recordings/:id/stop', async (req, res) => {
78
+ try {
79
+ res.json(await androidRecordings.stop(req.params.id));
80
+ }
81
+ catch (error) {
82
+ res.status(400).json({ error: String(error) });
83
+ }
84
+ });
85
+ router.post('/recordings/:id/save', async (req, res) => {
86
+ try {
87
+ const directory = req.body?.directory === undefined ? undefined
88
+ : await (req.pathValidator ?? pathValidator).validateAsync(req.body.directory);
89
+ res.json({ path: await androidRecordings.save(req.params.id, directory) });
90
+ }
91
+ catch (error) {
92
+ res.status(400).json({ error: error instanceof Error ? error.message : String(error) });
93
+ }
94
+ });
95
+ router.delete('/recordings/:id', async (req, res) => {
96
+ try {
97
+ await androidRecordings.discard(req.params.id);
98
+ res.json({ ok: true });
99
+ }
100
+ catch (error) {
101
+ res.status(400).json({ error: String(error) });
102
+ }
103
+ });
49
104
  export default router;
50
105
  function clampInt(value, min, max, fallback) {
51
106
  if (typeof value !== 'number' || !Number.isFinite(value))
@@ -4806,9 +4806,13 @@ router.post('/apply-hunk', async (req, res) => {
4806
4806
  }
4807
4807
  await runGitApply(gitRoot, mode, patch, GIT_APPLY_TIMEOUT_MS);
4808
4808
  clearGitBundleCacheForRoot(gitRoot);
4809
- const bundle = await refreshGitBundleCacheDetached(resolvedCwd, gitRoot, includeNested, { discoverOnly });
4809
+ // git apply has committed the mutation. A slow/failed workspace scan must
4810
+ // neither delay acknowledgement nor report that successful mutation failed.
4811
+ void refreshGitBundleCacheDetached(resolvedCwd, gitRoot, includeNested, { discoverOnly }).catch((error) => {
4812
+ logFsIoEvent({ id: requestId, action, op: 'git.apply-hunk', event: 'bundle-refresh-error', path: requestedPath, cwd, repoRoot: gitRoot, extra: { mode, error: error instanceof Error ? error.message : String(error) } });
4813
+ });
4810
4814
  logFsIo({ id: requestId, action, op: 'git.apply-hunk', startedAt, status: 'ok', path: requestedPath, cwd, repoRoot: gitRoot, extra: { mode } });
4811
- res.json({ ok: true, bundle });
4815
+ res.json({ ok: true });
4812
4816
  }
4813
4817
  catch (error) {
4814
4818
  const message = error instanceof Error ? error.message : 'Git apply failed';
@@ -1,3 +1,4 @@
1
+ import { androidRecordings } from '../android/recording.js';
1
2
  import { assertPeerRegistrationAuthority } from '../agent/collaborationPeerTransport.js';
2
3
  import { progressRoutes } from '../notifications/progressRoutes.js';
3
4
  import { ensureNodePty } from '../utils/ensureNodePty.js';
@@ -38,6 +39,7 @@ import { AgentResumeHistoryStore } from '../agent/resumeHistory.js';
38
39
  import { isTmuxRecoveryCandidate } from '../utils/tmuxRecoveryCandidate.js';
39
40
  import { AutomationStore, normalizeAutomationSchedule } from '../agent/automationStore.js';
40
41
  import { buildBracketedSubmitBytes, canDeliverPromptToAgent } from '../agent/promptDelivery.js';
42
+ import { prepareSupervisionEnable } from '../utils/enableSupervision.js';
41
43
  import { buildServerHealthState, dismissServerHealth } from '../utils/serverHealth.js';
42
44
  import { collaborationRoutes } from '../agent/collaborationRoutes.js';
43
45
  import { extrasFromBody } from '../agent/collaborationProtocol.js';
@@ -625,8 +627,24 @@ function flushPersistAndExit() {
625
627
  }
626
628
  catch { /* best effort */ }
627
629
  }
628
- process.on('SIGTERM', () => { flushPersistAndExit(); void persistToolbarPresetsNow(); caffeinateManager.shutdown(); process.exit(0); });
629
- process.on('SIGINT', () => { flushPersistAndExit(); void persistToolbarPresetsNow(); caffeinateManager.shutdown(); process.exit(0); });
630
+ let shuttingDown = false;
631
+ const shutdownWithRecordings = async () => {
632
+ if (shuttingDown)
633
+ return;
634
+ shuttingDown = true;
635
+ flushPersistAndExit();
636
+ void persistToolbarPresetsNow();
637
+ caffeinateManager.shutdown();
638
+ // Give the MP4 muxer a chance to write its trailer before the service exits.
639
+ try {
640
+ await androidRecordings.stopAll();
641
+ }
642
+ finally {
643
+ process.exit(0);
644
+ }
645
+ };
646
+ process.on('SIGTERM', () => { void shutdownWithRecordings(); });
647
+ process.on('SIGINT', () => { void shutdownWithRecordings(); });
630
648
  // 服务启动时从磁盘加载(带去重,防止历史累积的重复条目复活)
631
649
  void (async () => {
632
650
  await Promise.all([loadGlobalSessionStateFromDisk(), loadTmuxRecoveryStateFromDisk()]);
@@ -6258,6 +6276,16 @@ router.post('/update/restart', async (_req, res) => {
6258
6276
  router.get('/server-health', (_req, res) => {
6259
6277
  res.json(buildServerHealthState());
6260
6278
  });
6279
+ router.post('/server-health/enable-supervision', async (_req, res) => {
6280
+ try {
6281
+ const commit = await prepareSupervisionEnable();
6282
+ res.once('finish', commit);
6283
+ res.status(202).json({ restarting: true });
6284
+ }
6285
+ catch (error) {
6286
+ res.status(409).json({ error: error instanceof Error ? error.message : String(error) });
6287
+ }
6288
+ });
6261
6289
  router.post('/server-health/dismiss', (_req, res) => {
6262
6290
  res.status(202).json(dismissServerHealth());
6263
6291
  });
@@ -0,0 +1,33 @@
1
+ /** The prepared process becomes the supervisor once the old service has exited. */
2
+ import fs from 'node:fs';
3
+ import { runSupervisor } from './supervisor.js';
4
+ import { isProcessRunning } from './utils/termdockState.js';
5
+ const { parentPid, config } = JSON.parse(process.argv[2]);
6
+ if (!Number.isSafeInteger(parentPid) || parentPid <= 1 || !process.connected)
7
+ process.exit(1);
8
+ fs.accessSync(config.childEntry, fs.constants.R_OK);
9
+ if (config.healthCaPath)
10
+ fs.accessSync(config.healthCaPath, fs.constants.R_OK);
11
+ let committed = false;
12
+ const expiry = setTimeout(() => process.exit(1), 10_000);
13
+ process.on('disconnect', () => { if (!committed)
14
+ process.exit(1); });
15
+ process.once('message', (message) => {
16
+ if (message?.type !== 'handoff-commit')
17
+ process.exit(1);
18
+ committed = true;
19
+ clearTimeout(expiry);
20
+ const deadline = Date.now() + 30_000;
21
+ const timer = setInterval(() => {
22
+ if (isProcessRunning(parentPid)) {
23
+ if (Date.now() >= deadline) {
24
+ console.error('[supervisor] old service did not exit; handoff cancelled');
25
+ process.exit(1);
26
+ }
27
+ return;
28
+ }
29
+ clearInterval(timer);
30
+ runSupervisor(config);
31
+ }, 100);
32
+ });
33
+ process.send?.({ type: 'handoff-ready' });
@@ -29,7 +29,7 @@ import { backoffDelayMs } from './utils/backoff.js';
29
29
  import { installCrashForensics, isOomSuspect, readRuntimeTail, readServerLogTail } from './utils/crashForensics.js';
30
30
  import { probeHealthOnce, HEALTH_PROBE_TIMEOUT_MS } from './utils/healthProbe.js';
31
31
  import { writeJsonLogSync } from './utils/serverLogger.js';
32
- import { SUPERVISOR_STATE_VERSION, classifyChildExit, isReadyMessage, isServerIntentMessage, shouldGiveUp, } from './utils/supervisorProtocol.js';
32
+ import { SUPERVISOR_STATE_VERSION, classifyChildExit, isReadyMessage, isStartupFailedMessage, isServerIntentMessage, shouldGiveUp, } from './utils/supervisorProtocol.js';
33
33
  import { SUPERVISOR_STATE_PATH, STOP_GRACE_MS, isProcessRunning, removeJsonState, writeJsonStateAtomic, } from './utils/termdockState.js';
34
34
  export const DEFAULT_SUPERVISOR_TIMING = {
35
35
  readyTimeoutMs: 30_000,
@@ -189,6 +189,10 @@ export function createSupervisor(config, deps) {
189
189
  deps.notifyLauncher({ type: 'termdock-ready' });
190
190
  return;
191
191
  }
192
+ if (isStartupFailedMessage(message) && !becameReady) {
193
+ portConflict = message.reason === 'port-conflict';
194
+ return;
195
+ }
192
196
  if (isServerIntentMessage(message)) {
193
197
  intent = message.intent;
194
198
  deps.log(`[supervisor] server declared intent: ${message.intent}`);
@@ -356,7 +360,6 @@ export function createSupervisor(config, deps) {
356
360
  return;
357
361
  }
358
362
  if (shouldGiveUp(consecutiveCrashes, timing.maxConsecutiveCrashes)) {
359
- lastIncident.detail = `${lastIncident.detail} — gave up after ${consecutiveCrashes} consecutive crashes`;
360
363
  deps.log(`[supervisor] ${consecutiveCrashes} consecutive crashes; giving up. Service is NOT running.`);
361
364
  recordApplicationGaveUp();
362
365
  setPhase('gave-up');
@@ -380,7 +383,7 @@ export function createSupervisor(config, deps) {
380
383
  deps.recordIncident({
381
384
  role: 'supervisor',
382
385
  event: 'gave-up',
383
- detail: `gave up after ${consecutiveCrashes} consecutive crashes`,
386
+ detail: `gave up after ${consecutiveCrashes} consecutive failures: ${lastIncident?.detail ?? 'unknown cause'}`,
384
387
  version: config.version ?? null,
385
388
  restarts,
386
389
  lastIncident,
@@ -0,0 +1,80 @@
1
+ import { spawn } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { getSupervisorStatus } from './supervisorClient.js';
5
+ import { SERVER_LOG_PATH } from './termdockState.js';
6
+ let config = null;
7
+ let pending = false;
8
+ // Only the production CLI registers a launch recipe. Desktop and development
9
+ // runtimes must remain owned by their original launcher.
10
+ export function configureSupervisionEnable(value) {
11
+ config = value;
12
+ }
13
+ export function canEnableSupervision() {
14
+ return config !== null && !(process.env.TERMDOCK_SUPERVISED === '1' && process.connected)
15
+ && !process.env.TERMDOCK_DESKTOP && !process.env.TERMDOCK_DESKTOP_OWNER_SOCKET
16
+ && !process.env.INVOCATION_ID && !process.env.NOTIFY_SOCKET && !process.env.PM2_HOME
17
+ && !getSupervisorStatus()?.alive;
18
+ }
19
+ /** Prepare the replacement before stopping anything; commit after HTTP flush. */
20
+ export async function prepareSupervisionEnable() {
21
+ if (pending)
22
+ throw new Error('Automatic recovery is already being enabled.');
23
+ if (!canEnableSupervision() || !config)
24
+ throw new Error('Enable automatic recovery through the service launcher.');
25
+ pending = true;
26
+ try {
27
+ const script = fileURLToPath(new URL('../supervisionHandoff.js', import.meta.url));
28
+ fs.accessSync(script, fs.constants.R_OK);
29
+ fs.accessSync(config.childEntry, fs.constants.R_OK);
30
+ const fd = fs.openSync(SERVER_LOG_PATH, 'a', 0o600);
31
+ let child;
32
+ try {
33
+ child = spawn(process.execPath, [script, JSON.stringify({ parentPid: process.pid, config })], {
34
+ detached: true,
35
+ stdio: ['ignore', fd, fd, 'ipc'],
36
+ });
37
+ }
38
+ finally {
39
+ fs.closeSync(fd);
40
+ }
41
+ await new Promise((resolve, reject) => {
42
+ const timer = setTimeout(() => {
43
+ child.kill();
44
+ reject(new Error('Automatic recovery did not become ready.'));
45
+ }, 5000);
46
+ child.once('error', (error) => { clearTimeout(timer); reject(error); });
47
+ child.once('exit', () => {
48
+ clearTimeout(timer);
49
+ pending = false;
50
+ reject(new Error('Automatic recovery could not start.'));
51
+ });
52
+ child.once('message', (message) => {
53
+ if (message?.type !== 'handoff-ready')
54
+ return;
55
+ clearTimeout(timer);
56
+ resolve();
57
+ });
58
+ });
59
+ let committed = false;
60
+ return () => {
61
+ if (committed)
62
+ return;
63
+ committed = true;
64
+ // Never terminate the working service if the prepared process vanished.
65
+ child.send({ type: 'handoff-commit' }, (error) => {
66
+ if (error) {
67
+ pending = false;
68
+ return;
69
+ }
70
+ child.disconnect();
71
+ child.unref();
72
+ setTimeout(() => process.kill(process.pid, 'SIGTERM'), 750).unref();
73
+ });
74
+ };
75
+ }
76
+ catch (error) {
77
+ pending = false;
78
+ throw error;
79
+ }
80
+ }
@@ -12,6 +12,7 @@
12
12
  import { INCIDENT_DISMISSED_PATH, readJsonFile, writeJsonStateAtomic, } from './termdockState.js';
13
13
  import { readCrashLogTail } from './crashForensics.js';
14
14
  import { getSupervisorStatus } from './supervisorClient.js';
15
+ import { canEnableSupervision } from './enableSupervision.js';
15
16
  /**
16
17
  * 值得用户知道的事件。刻意排除 `stop`(是用户自己停的)、
17
18
  * `update-restart` / `manual-restart`(我们自己发起的,成功了就没什么可说)。
@@ -60,8 +61,31 @@ export function toIncident(entry) {
60
61
  export function findLatestNotableIncident(entries) {
61
62
  for (let index = entries.length - 1; index >= 0; index -= 1) {
62
63
  const incident = toIncident(entries[index]);
63
- if (incident && NOTABLE_EVENTS.has(incident.event))
64
- return incident;
64
+ if (!incident || !NOTABLE_EVENTS.has(incident.event))
65
+ continue;
66
+ if (incident.event === 'gave-up') {
67
+ // Old logs store the final failure separately. Match the supervisor, then
68
+ // its exact child PID; never borrow an unrelated process's port conflict.
69
+ const summary = entries[index];
70
+ const failure = entries.slice(0, index).reverse().find((entry) => entry.role === 'supervisor' && entry.pid === summary.pid
71
+ && entry.event !== 'gave-up' && NOTABLE_EVENTS.has(String(entry.event)));
72
+ const nested = summary.lastIncident;
73
+ const cause = nested && typeof nested === 'object' ? nested : failure;
74
+ const portConflict = failure && typeof failure.serverPid === 'number'
75
+ ? entries.slice(0, index).reverse().find((entry) => entry.role === 'server'
76
+ && entry.pid === failure.serverPid && entry.event === 'port-conflict'
77
+ && typeof entry.ts === 'string' && Date.parse(entry.ts) <= incident.at
78
+ && incident.at - Date.parse(entry.ts) < 60_000)
79
+ : undefined;
80
+ const causeEvent = portConflict ? 'port-conflict' : pickString(cause?.event);
81
+ if (causeEvent)
82
+ incident.causeEvent = causeEvent;
83
+ if (portConflict) {
84
+ const port = pickNumber(portConflict.port);
85
+ incident.detail = port === null ? 'EADDRINUSE' : `Port ${port} is already in use (EADDRINUSE).`;
86
+ }
87
+ }
88
+ return incident;
65
89
  }
66
90
  return null;
67
91
  }
@@ -101,7 +125,8 @@ export function buildServerHealthState(options = {}) {
101
125
  }
102
126
  const dismissedAt = readDismissal(dismissedPath);
103
127
  return {
104
- supervised: process.env.TERMDOCK_SUPERVISED === '1',
128
+ supervised: process.env.TERMDOCK_SUPERVISED === '1' && process.connected === true,
129
+ canEnableSupervision: canEnableSupervision(),
105
130
  supervisor,
106
131
  incident,
107
132
  dismissedAt,
@@ -108,7 +108,7 @@ function normalizeAndroidQuality(value) {
108
108
  if (!value || typeof value !== 'object' || Array.isArray(value))
109
109
  return null;
110
110
  const item = value;
111
- if (item.id !== 'low' && item.id !== 'medium' && item.id !== 'high' && item.id !== 'custom')
111
+ if (item.id !== 'auto' && item.id !== 'low' && item.id !== 'medium' && item.id !== 'high' && item.id !== 'custom')
112
112
  return null;
113
113
  const maxSize = typeof item.maxSize === 'number' ? Math.max(360, Math.min(2160, Math.round(item.maxSize))) : 1080;
114
114
  const bitRate = typeof item.bitRate === 'number' ? Math.max(300_000, Math.min(30_000_000, Math.round(item.bitRate))) : 4_000_000;
@@ -0,0 +1,16 @@
1
+ /** Flush the failure to the supervisor before exiting; a log entry alone is not IPC. */
2
+ export function exitWithStartupFailure(reason, detail) {
3
+ if (!process.connected || !process.send)
4
+ process.exit(1);
5
+ const timeout = setTimeout(() => process.exit(1), 1_000);
6
+ const finish = () => {
7
+ clearTimeout(timeout);
8
+ process.exit(1);
9
+ };
10
+ try {
11
+ process.send({ type: 'termdock-startup-failed', reason, detail }, finish);
12
+ }
13
+ catch {
14
+ finish();
15
+ }
16
+ }
@@ -5,6 +5,11 @@
5
5
  * 否则唯一验证手段就只剩"手动 kill 一下看看"。
6
6
  */
7
7
  export const SUPERVISOR_STATE_VERSION = 1;
8
+ export function isStartupFailedMessage(value) {
9
+ return isRecord(value) && value.type === 'termdock-startup-failed'
10
+ && typeof value.reason === 'string'
11
+ && (value.detail === undefined || typeof value.detail === 'string');
12
+ }
8
13
  function isRecord(value) {
9
14
  return typeof value === 'object' && value !== null;
10
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termdock",
3
- "version": "1.4.264",
3
+ "version": "1.4.266",
4
4
  "description": "A complete web-based terminal application with modern UI",
5
5
  "type": "module",
6
6
  "main": ".desktop-dist/main.js",
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "packageName": "termdock",
4
- "version": "1.4.264",
4
+ "version": "1.4.266",
5
5
  "runtimeProtocolVersion": 1,
6
6
  "minimumDesktopVersion": "1.4.46",
7
7
  "nodeMajor": 22,
8
8
  "dependencyHash": "sha256-K4KyYJuVoQDpZsBM8ZX1Rw3MddOxAzVdp/cPm0iGZz0=",
9
- "serverBundleHash": "sha256-eGq7LQ95VBb2nfxC0SU71k+o3Iwq4X3tyJpahIVYSdw=",
10
- "clientBundleHash": "sha256-9jlON5andoQRcGoJBxqv55zje1spcZjcny1dqFcWhGw=",
9
+ "serverBundleHash": "sha256-OzEmGLQ2089pXmDouFuQcJQt6ZHuQfArddq3xlvkjrU=",
10
+ "clientBundleHash": "sha256-SM1viL4lDEGX0IJs/ltbippjKurPa5ahbqiu8hL2BcQ=",
11
11
  "entrypoint": "dist/server/cli.js",
12
12
  "clientEntrypoint": "dist/client/index.html"
13
13
  }