chainlesschain 0.162.165 → 0.162.166

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 (160) hide show
  1. package/package.json +3 -1
  2. package/src/assets/web-panel/assets/{AIOps-DgGZr3PR.js → AIOps-LbDx7jL6.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-BAOgBIc_.js → ActionButton-DnurtK34.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-Ds4GAvNF.js → Analytics-DXSsV1am.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-CoJvCkoF.js → AppLayout-dqRpzNuD.js} +4 -4
  6. package/src/assets/web-panel/assets/{Artifacts-6EgUaE1T.js → Artifacts-BwdmYepK.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-BYie_i74.js → Audit-oSX0kOUG.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-D5gxOhjd.js → BackgroundAgents-C2KxJahT.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-CIsVK2pT.js → Backup-B4TkxWkC.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-ClorP55M.js → BaseInput-CX5-KxeU.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-CnhTPGGA.js → Chat-O_HzD-PL.js} +5 -5
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-Bl1VXgwp.js → ChatBubbleRenderer-Br8saHQA.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-BRavl7TP.js → Checkbox-ChepDpC1.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-BXg_ErNT.js → Codegen-D9z8kc7q.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-CfDPzFPq.js → Col-B-H5eoNw.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-Cgo0httP.js → Community-Ccyp_Kk5.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-DU5JcEQM.js → Compact-BNvBznp_.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-DCH_TVBl.js → Compliance-D1FjRd8n.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-IGb5O2IH.js → Cowork-CV9B9u-8.js} +2 -2
  20. package/src/assets/web-panel/assets/{Cron-CPp_Xp9F.js → Cron-BowJ4VIx.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-Cwrqklzw.js → Crosschain-BJc6jzRF.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-D55sBQwM.js → DID-BEp8NV6D.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-CedXhGmP.js → Dashboard-Dls0B3YB.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-Dm6_v3V4.js → Dropdown-DQ7zXVtD.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-CWjnuE3G.js → EmailListRenderer-B9q79tOl.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DubTh7y-.js → FamilyGuardDashboard-CD8Ie-88.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-DlSM4uJv.js → Federation-5o7XU5Vf.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-BYhg0vtG.js → FormItemContext-DeKbMvOs.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-Bkh7qjfK.js → GenericCardRenderer-CZiQvz_z.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-DSLWPKvn.js → Git-CTvFxVV8.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-DIj9O8BB.js → Governance-DwzFIjHt.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-Dhep3e5Y.js → Inference-CJBk59c-.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-Cj8vzxB_.js → KnowledgeGraph-DfsaXN2z.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-Ba4SsPja.js → Logs-DVRYf18S.js} +2 -2
  35. package/src/assets/web-panel/assets/MarkdownRenderer-BL_WsWZM.js +1 -0
  36. package/src/assets/web-panel/assets/{Marketplace-CGs9IIbf.js → Marketplace-BuIwyE4t.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-BTPAoX4K.js → McpTools-D3U0o78E.js} +5 -5
  38. package/src/assets/web-panel/assets/{Memory-BJ6ISf2c.js → Memory-QYVmyb3b.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-Ca6n3Dcn.js → MobileBridge-BFgrj6eZ.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-lvilHuLt.js → MobileProjects-Bp5QB-46.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-CMo0acBV.js → Mtc-BZQu8TcH.js} +4 -4
  42. package/src/assets/web-panel/assets/{MtcAudit-Hz5wBvFX.js → MtcAudit-BnFfEkLo.js} +4 -4
  43. package/src/assets/web-panel/assets/{Multisig-BK2aKWE6.js → Multisig-iUnNS9Cm.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-CExpnYMI.js → NLProgramming-DNNz1y9Y.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-B7IFbuBo.js → Notes-CZezNYRU.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-VrGchtb0.js → NotificationSettings-DBvrplIR.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-CyrNTxkU.js → OrderTableRenderer-CTDtee49.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-I0C17GBP.js → Organization-CCOUJX1R.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-CXcWvERe.js → Overflow-DcZghdk0.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-FFSCXrZq.js → P2P-jmddWX9q.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-1PB-p8Zk.js → PdhVaultBrowser-wfjMcczl.js} +4 -4
  52. package/src/assets/web-panel/assets/{Permissions-C1YHejsb.js → Permissions-DU1GJjca.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-CEMPpgf8.js → PersonalDataHub-BzTMzDF9.js} +3 -3
  54. package/src/assets/web-panel/assets/{Pipeline-FoIScdLr.js → Pipeline-DPmjlpVc.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-DDfbEzEj.js → Privacy-B6HRLpfK.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-Dso4kB0O.js → ProjectInit-Cyy86AsN.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-WvDoydDc.js → ProjectSettings-Bl_WQxJ5.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-NJp0kzkd.js → Projects-Co9yKThA.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-BuJXnOLI.js → Providers-DLa4NlIs.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-Bb3lMvGG.js → QrScannerModal-BvzM7q5f.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-Ddxra3fK.js → QuickAsk-BN8yyyUj.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-BW-dR9qw.js → Recommend-QsVN4w0i.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-Hnm7-Qkm.js → RemoteSession-tkDXw-TY.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-DKz6meHE.js → Reputation-DAifkGsy.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-BuAsoNTS.js → Row-D7dZEyak.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-_do9DMIH.js → RssFeed-DB5sImTA.js} +2 -2
  67. package/src/assets/web-panel/assets/{Search-CMlcw7ND.js → Search-3py3TO9V.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-DhAkfSpM.js → Security-DhNUfT_k.js} +3 -3
  69. package/src/assets/web-panel/assets/{Services-5zKLhy46.js → Services-DjJAA_5D.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-DCMZ3wfv.js → Skeleton-u95JjK3n.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-DxQgYCC_.js → Skills-DPo3L0Tz.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-CJmE4cSN.js → Sla-DWhkAZV1.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-BgpRTPQp.js → SpeechSettings-PUegMtqV.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-DkogtYbB.js → SyncSettings-BMNYrnrU.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-D5OrwAl9.js → Tasks-CYm_oTJC.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-DAZIu5nN.js → Templates-Dw9Er5DN.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-BRJMI-su.js → Tenant-7P3QIBSo.js} +1 -1
  78. package/src/assets/web-panel/assets/Terminal-ClPrfWW7.js +3 -0
  79. package/src/assets/web-panel/assets/{TimelineRenderer-D4z9aSGD.js → TimelineRenderer-DbCd1bDH.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-zgYA4UOI.js → Tokens-EQofpA0t.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-DMOgHX4m.js → Trigger-ChNLLypd.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-CEtoNwcT.js → Trust-dlVGUKs5.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-DFx2pQfO.js → UkeySign-BXyBUhNF.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-DLssy-7B.js → VideoEditing-BE8-68ge.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-DQHc6gTl.js → Wallet-7ZIJOwNg.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-DgKcODkn.js → WebAuthn-DgNd2Amr.js} +3 -3
  87. package/src/assets/web-panel/assets/{WorkflowEditor-cPEWfMOf.js → WorkflowEditor-Z-Un-9l5.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-Coj7rSO1.js → chat-CtVDEkUc.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-DiyGfr-6.js → colors-PXtJ2f1B.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-DB63aMXh.js → compact-item-oN96nuBi.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-CENpsYHg.js → createContext-okCJXQXa.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-BzV6dk1B.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-B9NOmk0K.js → hasIn-pcHm--4o.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-VDFbduzG.js → index-5aO2V0V4.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-Yb9EfUnY.js → index-BDR2mi1p.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BpmTl8QC.js → index-BEtzqJw3.js} +1 -1
  97. package/src/assets/web-panel/assets/index-BFrAwXHp.js +1 -0
  98. package/src/assets/web-panel/assets/{index-nio98wGC.js → index-BHJIfdCV.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-t6hXF2Cw.js → index-BUTyx-Lk.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CRhEJ8JO.js → index-BUUJ2WfG.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BvQq6gX2.js → index-BZKk4Lnm.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BkoqtJzV.js → index-BeAWCGEK.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-7IMjHwGU.js → index-Bht9n8Sm.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-B45osqnZ.js → index-BjVIZfdA.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CmNCDN5t.js → index-Bl6N7ZyX.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BXzMKVLp.js → index-BnhHxZul.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-U_snupDl.js → index-BuME9k4Y.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Dg0v-CXZ.js → index-C0rfJBU3.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CKNt2vfs.js → index-C4ravjdv.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BxvNtndl.js → index-CAQktO-6.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CvTJ-x6b.js → index-CK0H3pQW.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DAMKhjtT.js → index-CQ1ZzJjN.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-mTK_ZHhE.js → index-CQYes2mk.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-76GMjcbq.js → index-CWUJlCvK.js} +3 -3
  115. package/src/assets/web-panel/assets/{index-CwkK9Kl2.js → index-CXhezK4d.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-D_rZCxxI.js → index-Cc_MkksW.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BramLq29.js → index-CopGaCI_.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CXRknr9W.js → index-Cs1fGk1Z.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DANoIqXP.js → index-D0bfypsF.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-ClEy1v1o.js → index-D1efSh1X.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-Bvj07Ab1.js → index-DBcKBb1E.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CxVfbuj9.js → index-DC0bqrqV.js} +1 -1
  123. package/src/assets/web-panel/assets/index-DJQFP47u.js +1 -0
  124. package/src/assets/web-panel/assets/{index-CTuX_MU0.js → index-DfL10EcN.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-C9d8hdgY.js → index-DtsyPnF5.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CAXouogg.js → index-Rk0X8lVz.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Y_UKQpsV.js → index-T3QE8LuV.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DqLC0iE4.js → index-_SaFHNsG.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-Kp2AETEw.js → index-jAY55MSx.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DsPDEHOg.js → index-mB1UV7wA.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-KDCuTzdx.js → index-nMqLdwao.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-B0C6zl0y.js → index-vW0lwj0Y.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-GTwJVIOz.js → initDefaultProps-CG1jyiI7.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-BJQLsPx8.js → motion-C8BYa98D.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-DVQM0bdG.js → move-D1hqwitW.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-CMXI1I2y.js → mtc-parser-C2lol8rp.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-CAc8MDw9.js → omit-Ct6Zghfi.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-BgqzoyP7.js → pickAttrs-CSYbYfdc.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-B9ebCdRy.js → placementArrow-WCk8di0z.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-Dy8D0D3n.js → responsiveObserve-CEC8CZ-3.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-Bcrc8J39.js → slide-BsXyd7Lq.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-CDW6FOlc.js → statusUtils-tDKldiUT.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-CWhJrDON.js → styleChecker-BIS2unhx.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-C82c33XI.js → useFlexGapSupport-yFTVMDUv.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-A6m--mih.js → useFs-CZYbJwkO.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-m-1laJY5.js → usePersonalDataHub-sbEHRLAM.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-CL9oKKRa.js → vnode-BVjeSEQK.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-DrOyaof3.js → zoom-BZKVvEZ6.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/data/changelog.json +7 -2
  151. package/src/lib/background-session-transport.js +24 -2
  152. package/src/lib/governance-coverage.js +179 -0
  153. package/src/lib/packer/smoke-runner.js +85 -15
  154. package/src/lib/protocol-replay.js +153 -0
  155. package/src/runtime/agent-core.js +35 -0
  156. package/src/assets/web-panel/assets/MarkdownRenderer-DUjyuVB3.js +0 -1
  157. package/src/assets/web-panel/assets/Terminal-CMXLqQKF.js +0 -3
  158. package/src/assets/web-panel/assets/devWarning-XvRaIiyt.js +0 -1
  159. package/src/assets/web-panel/assets/index-CbO1zSXV.js +0 -1
  160. package/src/assets/web-panel/assets/index-aCu2gbUb.js +0 -1
@@ -85,6 +85,15 @@ export async function smokeTestExe(ctx) {
85
85
  stdio: ["ignore", "pipe", "pipe"],
86
86
  windowsHide: true,
87
87
  shell: needsShell,
88
+ // POSIX: own process group so teardown can signal the WHOLE tree via the
89
+ // negative pid. Critical when shell:true wraps the launch in `/bin/sh -c`
90
+ // (the `.sh` test shim, and any real exe that re-execs): a plain
91
+ // child.kill() then hits only the wrapper shell and orphans the real
92
+ // `node` server grandchild (ppid→1), which kept serving AND — via the
93
+ // stdio pipe fds it inherited from the worker — pinned the vitest forks
94
+ // pool past its terminate deadline ("Worker exited unexpectedly" flake).
95
+ // No-op on Windows, where killChild uses taskkill /T to walk the tree.
96
+ detached: process.platform !== "win32",
88
97
  });
89
98
 
90
99
  let stdoutBuf = "";
@@ -104,9 +113,26 @@ export async function smokeTestExe(ctx) {
104
113
  // is enough in practice, but /T protects us if that ever changes.
105
114
  spawn("taskkill", ["/F", "/T", "/PID", String(child.pid)], {
106
115
  stdio: "ignore",
107
- });
116
+ }).unref();
117
+ } else if (child.pid) {
118
+ // Negative pid → the whole process group from the detached spawn above,
119
+ // so a shell:true wrapper's exec'd/forked `node` grandchild dies too
120
+ // (a plain child.kill would signal only the wrapper and orphan the
121
+ // server). SIGKILL, not SIGTERM: a smoke teardown has no reason to wait
122
+ // for a graceful close and not every packed/fake server installs a
123
+ // SIGTERM handler. Fall back to a direct kill if the group is already
124
+ // gone (ESRCH).
125
+ try {
126
+ process.kill(-child.pid, "SIGKILL");
127
+ } catch {
128
+ try {
129
+ child.kill("SIGKILL");
130
+ } catch {
131
+ /* already gone */
132
+ }
133
+ }
108
134
  } else {
109
- child.kill("SIGTERM");
135
+ child.kill("SIGKILL");
110
136
  }
111
137
  } catch {
112
138
  /* best effort */
@@ -115,9 +141,10 @@ export async function smokeTestExe(ctx) {
115
141
 
116
142
  // Early-death watchdog: if the child exits before we see a listening
117
143
  // port, report the stdout/stderr so the user sees the real failure
118
- // instead of a generic timeout.
144
+ // instead of a generic timeout. Named so cleanup() can detach it.
145
+ let onExit;
119
146
  const deathPromise = new Promise((_, reject) => {
120
- child.on("exit", (code, signal) => {
147
+ onExit = (code, signal) => {
121
148
  reject(
122
149
  new PackError(
123
150
  `Smoke-test process exited (code=${code}, signal=${signal}) before ports came up.\n` +
@@ -126,16 +153,52 @@ export async function smokeTestExe(ctx) {
126
153
  EXIT.SMOKE,
127
154
  ),
128
155
  );
129
- });
156
+ };
157
+ child.on("exit", onExit);
130
158
  });
131
159
 
160
+ // Full teardown: killing the child is not enough — the parent still holds
161
+ // the child's stdout/stderr PIPE handles and the ChildProcess object, all of
162
+ // which keep the event loop alive (killed-but-unreaped on Windows, or
163
+ // still-open pipes on POSIX). Left dangling across the ~8 smokeTestExe calls
164
+ // this test makes, they pinned the vitest forks-pool worker so it could not
165
+ // terminate → the "Worker exited unexpectedly" / "Timeout terminating forks
166
+ // worker" flake blamed on whatever file ran next on the reused worker. Detach
167
+ // the exit watcher, destroy the pipes, kill, and unref so nothing survives.
168
+ let cleaned = false;
169
+ const cleanup = () => {
170
+ if (cleaned) return;
171
+ cleaned = true;
172
+ try {
173
+ child.removeListener("exit", onExit);
174
+ } catch {
175
+ /* noop */
176
+ }
177
+ killChild();
178
+ try {
179
+ child.stdout?.destroy();
180
+ } catch {
181
+ /* noop */
182
+ }
183
+ try {
184
+ child.stderr?.destroy();
185
+ } catch {
186
+ /* noop */
187
+ }
188
+ try {
189
+ child.unref();
190
+ } catch {
191
+ /* noop */
192
+ }
193
+ };
194
+
132
195
  try {
133
196
  await Promise.race([
134
197
  waitForPorts({ uiPort, wsPort, timeoutMs: bootTimeoutMs }),
135
198
  deathPromise,
136
199
  ]);
137
200
  } catch (e) {
138
- killChild();
201
+ cleanup();
139
202
  throw e;
140
203
  }
141
204
 
@@ -148,7 +211,7 @@ export async function smokeTestExe(ctx) {
148
211
  timeoutMs: probeTimeoutMs,
149
212
  });
150
213
  } catch (e) {
151
- killChild();
214
+ cleanup();
152
215
  throw new PackError(
153
216
  `Smoke-test HTTP probe failed: ${e.message}`,
154
217
  EXIT.SMOKE,
@@ -156,7 +219,7 @@ export async function smokeTestExe(ctx) {
156
219
  }
157
220
 
158
221
  if (uiStatus < 200 || uiStatus >= 300) {
159
- killChild();
222
+ cleanup();
160
223
  throw new PackError(
161
224
  `Smoke-test HTTP probe: http://127.0.0.1:${uiPort}/ returned ${uiStatus} (expected 2xx)`,
162
225
  EXIT.SMOKE,
@@ -191,7 +254,7 @@ export async function smokeTestExe(ctx) {
191
254
  ` skills check: /api/skills returned 404 — skipping (older pack predating Phase 2b)`,
192
255
  );
193
256
  skillsCheck = { ok: true, skipped: "endpoint-404" };
194
- killChild();
257
+ cleanup();
195
258
  return {
196
259
  ok: true,
197
260
  uiStatus,
@@ -200,7 +263,7 @@ export async function smokeTestExe(ctx) {
200
263
  skillsCheck,
201
264
  };
202
265
  }
203
- killChild();
266
+ cleanup();
204
267
  throw new PackError(
205
268
  `Smoke-test /api/skills probe failed: ${e.message}`,
206
269
  EXIT.SMOKE,
@@ -216,7 +279,7 @@ export async function smokeTestExe(ctx) {
216
279
  );
217
280
  const missing = bundledSkillNames.filter((n) => !registeredNames.has(n));
218
281
  if (missing.length > 0) {
219
- killChild();
282
+ cleanup();
220
283
  throw new PackError(
221
284
  `Smoke-test skills check: bundled skill(s) not registered: ${missing.join(", ")}`,
222
285
  EXIT.SMOKE,
@@ -228,7 +291,7 @@ export async function smokeTestExe(ctx) {
228
291
  skillsCheck = { ok: true, checked: bundledSkillNames.length };
229
292
  }
230
293
 
231
- killChild();
294
+ cleanup();
232
295
 
233
296
  return {
234
297
  ok: true,
@@ -280,12 +343,17 @@ function tryConnect(host, port, timeoutMs) {
280
343
  function probeHttp({ host, port, path: urlPath, timeoutMs }) {
281
344
  return new Promise((resolve, reject) => {
282
345
  const req = http.get(
283
- { host, port, path: urlPath, timeout: timeoutMs },
346
+ // agent:false a one-off connection that closes after the response
347
+ // instead of lingering in the global keep-alive pool (leak-free probe).
348
+ { host, port, path: urlPath, timeout: timeoutMs, agent: false },
284
349
  (res) => {
285
350
  const status = res.statusCode || 0;
286
351
  // Drain body so the socket can close cleanly.
287
352
  res.on("data", () => {});
288
- res.on("end", () => resolve(status));
353
+ res.on("end", () => {
354
+ req.destroy(); // release the socket now, don't wait for GC
355
+ resolve(status);
356
+ });
289
357
  res.on("error", reject);
290
358
  },
291
359
  );
@@ -299,10 +367,11 @@ function probeHttp({ host, port, path: urlPath, timeoutMs }) {
299
367
  function probeHttpJson({ host, port, path: urlPath, timeoutMs }) {
300
368
  return new Promise((resolve, reject) => {
301
369
  const req = http.get(
302
- { host, port, path: urlPath, timeout: timeoutMs },
370
+ { host, port, path: urlPath, timeout: timeoutMs, agent: false },
303
371
  (res) => {
304
372
  if (res.statusCode < 200 || res.statusCode >= 300) {
305
373
  res.resume();
374
+ req.destroy();
306
375
  reject(new Error(`HTTP ${res.statusCode} from ${urlPath}`));
307
376
  return;
308
377
  }
@@ -311,6 +380,7 @@ function probeHttpJson({ host, port, path: urlPath, timeoutMs }) {
311
380
  body += d.toString("utf8");
312
381
  });
313
382
  res.on("end", () => {
383
+ req.destroy(); // release the socket now, don't wait for GC
314
384
  try {
315
385
  resolve(JSON.parse(body));
316
386
  } catch (e) {
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Offline protocol replay — the last open pure item of P1-9 ("离线协议回放") in
3
+ * docs/CLAUDE_CODE_IDE_INCREMENTAL_GAP_ANALYSIS_2026-07-13.md.
4
+ *
5
+ * [[event-seq-replay.js]] replays for TRANSPORT reliability (re-send a gap over a
6
+ * lossy socket). This module replays for PROTOCOL COMPAT: take a recorded
7
+ * stream-json session and a negotiation context (server offer × client offer) and
8
+ * answer two offline questions no live peer is needed for —
9
+ *
10
+ * 1. REPLAY: what would these frames look like on the wire under THIS
11
+ * negotiation? (fields whose feature did not survive negotiation are
12
+ * stripped, exactly as the live emitter's field-gate would strip them.)
13
+ * 2. AUDIT: does a recorded session OBEY a claimed negotiation, i.e. does any
14
+ * frame carry a negotiable wire field the negotiation gated OFF? A vN-only
15
+ * client must never receive a vN+1 field; a recording that violates that is
16
+ * a compat bug this catches deterministically, offline, in CI.
17
+ *
18
+ * The set of gateable wire fields ({seq, trace_id, tool_use_id}) is projected
19
+ * from the ONE canonical [[capability-manifest.js]] via `toFieldGate()` — it can
20
+ * NOT drift from the negotiated feature list. All non-negotiable frame fields
21
+ * (type, content, tool name, …) always pass through untouched.
22
+ *
23
+ * PURE + deterministic: no fs / process / clock / RNG. The `digest` lets a golden
24
+ * recording be pinned so any change to negotiation/gating that alters wire output
25
+ * fails a byte/hash compare (same anti-drift philosophy as the capability doc).
26
+ */
27
+
28
+ import { createHash } from "node:crypto";
29
+ import {
30
+ negotiateProtocol,
31
+ applyNegotiationToGate,
32
+ } from "./capability-negotiation.js";
33
+ import { toFieldGate } from "./capability-manifest.js";
34
+
35
+ /** Negotiable wire field names ({seq, trace_id, tool_use_id}), single-sourced. */
36
+ export const GATEABLE_FIELDS = Object.freeze(
37
+ [...new Set(Object.values(toFieldGate()))].sort(),
38
+ );
39
+
40
+ /**
41
+ * Run negotiation and fold it into a per-field gate the replay/audit read.
42
+ * On an incompatible (ok:false) negotiation the gate stays empty → every gateable
43
+ * field is treated as OFF (fail-closed safe baseline).
44
+ *
45
+ * @param {object} params
46
+ * @param {object} params.server server offer {protocolVersion,minProtocolVersion,features}
47
+ * @param {object|null} [params.client] client offer, or null/undefined = legacy peer
48
+ * @returns {{negotiation:object, gate:object, enabledFields:string[], gatedFields:string[]}}
49
+ */
50
+ export function gateFromNegotiation({ server = {}, client = null } = {}) {
51
+ const negotiation = negotiateProtocol(server, client ?? null);
52
+ const gate = applyNegotiationToGate(negotiation, {});
53
+ const enabledFields = GATEABLE_FIELDS.filter((f) => gate[f] === true);
54
+ const gatedFields = GATEABLE_FIELDS.filter((f) => gate[f] !== true);
55
+ return { negotiation, gate, enabledFields, gatedFields };
56
+ }
57
+
58
+ /**
59
+ * Strip from a single frame every gateable wire field the gate has OFF, exactly
60
+ * as the live emitter would; all other fields pass through in original order.
61
+ * Returns a shallow copy — the input frame is never mutated.
62
+ *
63
+ * @param {object} frame
64
+ * @param {object} gate {seq?:boolean, trace_id?:boolean, tool_use_id?:boolean}
65
+ * @returns {object}
66
+ */
67
+ export function replayFrame(frame, gate = {}) {
68
+ if (!frame || typeof frame !== "object") return frame;
69
+ const out = {};
70
+ for (const [k, v] of Object.entries(frame)) {
71
+ if (GATEABLE_FIELDS.includes(k) && gate[k] !== true) continue;
72
+ out[k] = v;
73
+ }
74
+ return out;
75
+ }
76
+
77
+ /**
78
+ * Replay a recorded session under a negotiation → the frames as they'd appear on
79
+ * the wire (gated-off fields stripped) plus a deterministic digest.
80
+ *
81
+ * @param {object[]} frames recorded stream-json frames
82
+ * @param {{server:object, client?:object|null}} ctx negotiation context
83
+ * @returns {{negotiation:object, gate:object, enabledFields:string[],
84
+ * gatedFields:string[], frames:object[], digest:string}}
85
+ */
86
+ export function replaySession(frames, ctx = {}) {
87
+ const { negotiation, gate, enabledFields, gatedFields } =
88
+ gateFromNegotiation(ctx);
89
+ const emitted = (Array.isArray(frames) ? frames : []).map((f) =>
90
+ replayFrame(f, gate),
91
+ );
92
+ return {
93
+ negotiation,
94
+ gate,
95
+ enabledFields,
96
+ gatedFields,
97
+ frames: emitted,
98
+ digest: sessionDigest(emitted),
99
+ };
100
+ }
101
+
102
+ /**
103
+ * Audit a recorded session against a claimed negotiation WITHOUT stripping:
104
+ * report every frame that carries a gateable wire field the negotiation gated
105
+ * OFF (a forward-compat violation — a field a peer at the agreed version must not
106
+ * have received). Fail-closed: `ok` is true only when there are zero violations.
107
+ *
108
+ * @param {object[]} frames
109
+ * @param {{server:object, client?:object|null}} ctx
110
+ * @returns {{ok:boolean, violations:Array<{index:number, field:string, type:(string|null)}>, gate:object, gatedFields:string[]}}
111
+ */
112
+ export function auditRecordedSession(frames, ctx = {}) {
113
+ const { gate, gatedFields } = gateFromNegotiation(ctx);
114
+ const violations = [];
115
+ (Array.isArray(frames) ? frames : []).forEach((frame, index) => {
116
+ if (!frame || typeof frame !== "object") return;
117
+ for (const field of GATEABLE_FIELDS) {
118
+ if (
119
+ gate[field] !== true &&
120
+ Object.prototype.hasOwnProperty.call(frame, field)
121
+ ) {
122
+ violations.push({
123
+ index,
124
+ field,
125
+ type: typeof frame.type === "string" ? frame.type : null,
126
+ });
127
+ }
128
+ }
129
+ });
130
+ return { ok: violations.length === 0, violations, gate, gatedFields };
131
+ }
132
+
133
+ /** Recursively key-sort a value so JSON.stringify is order-independent. */
134
+ function canonical(value) {
135
+ if (Array.isArray(value)) return value.map(canonical);
136
+ if (value && typeof value === "object") {
137
+ const out = {};
138
+ for (const k of Object.keys(value).sort()) out[k] = canonical(value[k]);
139
+ return out;
140
+ }
141
+ return value;
142
+ }
143
+
144
+ /**
145
+ * Deterministic sha256 over a frame sequence (key-order independent) so a golden
146
+ * recording can be pinned and diffed. Pure.
147
+ * @param {object[]} frames
148
+ * @returns {string} 64-hex digest
149
+ */
150
+ export function sessionDigest(frames) {
151
+ const body = (Array.isArray(frames) ? frames : []).map(canonical);
152
+ return createHash("sha256").update(JSON.stringify(body)).digest("hex");
153
+ }
@@ -184,6 +184,35 @@ export function listBackgroundShellTasks() {
184
184
  // spawned detached (its own process group), so signal the group via the
185
185
  // negative pid. Windows: `taskkill /T` walks and kills the whole tree.
186
186
  // Returns true if a running task was signalled.
187
+ // Release the parent-side handles of a background task's child: the stdout/
188
+ // stderr PIPES (ref'd — on their own they keep the event loop alive) and the
189
+ // process handle. Called once a task is terminal or has been signalled to die,
190
+ // so a still-draining or slowly-dying child can never pin the process past a
191
+ // teardown. In production the agent's own REPL/run loop holds the loop open, so
192
+ // this changes nothing there; in the vitest forks pool nothing else does, and a
193
+ // SIGTERM'd-but-not-yet-dead child was tripping the worker-terminate deadline
194
+ // (the POSIX-only "Timeout terminating forks worker / Worker exited
195
+ // unexpectedly" unit-shard flake). Idempotent + best-effort.
196
+ function _releaseBgChildHandles(task) {
197
+ const child = task?.child;
198
+ if (!child) return;
199
+ try {
200
+ child.stdout?.destroy();
201
+ } catch {
202
+ /* noop */
203
+ }
204
+ try {
205
+ child.stderr?.destroy();
206
+ } catch {
207
+ /* noop */
208
+ }
209
+ try {
210
+ child.unref?.();
211
+ } catch {
212
+ /* noop */
213
+ }
214
+ }
215
+
187
216
  function _killTask(task) {
188
217
  const child = task?.child;
189
218
  if (!child || child.killed || task?.status !== "running") return false;
@@ -217,6 +246,9 @@ function _killTask(task) {
217
246
  } else {
218
247
  child.kill("SIGTERM");
219
248
  }
249
+ // Drop the ref'd pipe/process handles now — the group signal is away, so a
250
+ // slowly-dying child must not pin the loop while it finishes exiting.
251
+ _releaseBgChildHandles(task);
220
252
  return true;
221
253
  } catch (_err) {
222
254
  return false;
@@ -276,6 +308,7 @@ function _killTaskSync(task) {
276
308
  } else {
277
309
  child.kill("SIGKILL");
278
310
  }
311
+ _releaseBgChildHandles(task);
279
312
  return true;
280
313
  } catch (_err) {
281
314
  return false;
@@ -2692,6 +2725,7 @@ async function executeToolInner(
2692
2725
  task.status = "error";
2693
2726
  task.error = String(err?.message || err).substring(0, 2000);
2694
2727
  task.endedAt = new Date().toISOString();
2728
+ _releaseBgChildHandles(task);
2695
2729
  });
2696
2730
  // 'close' (not 'exit') so stdout/stderr are fully drained before the
2697
2731
  // status leaves "running" — otherwise a poll can observe completion
@@ -2704,6 +2738,7 @@ async function executeToolInner(
2704
2738
  task.exitCode = code;
2705
2739
  task.signal = signal;
2706
2740
  task.endedAt = new Date().toISOString();
2741
+ _releaseBgChildHandles(task);
2707
2742
  });
2708
2743
  } catch (err) {
2709
2744
  task.status = "error";
@@ -1 +0,0 @@
1
- import{P as c,J as p,b as s}from"./vendor-Bn1JzzAn.js";import{r as a}from"./markdown-Yo_c6Krv.js";import{_ as d}from"./index-76GMjcbq.js";const _={__name:"MarkdownRenderer",props:{content:{type:String,default:""}},setup(t,{expose:o}){o();const e=t,r=s(()=>a(e.content||"")),n={props:e,rendered:r,computed:s,get renderMarkdown(){return a}};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}},i=["innerHTML"];function u(t,o,e,r,n,m){return c(),p("div",{class:"markdown-content",innerHTML:r.rendered},null,8,i)}const b=d(_,[["render",u],["__scopeId","data-v-0b0b9f63"],["__file","/tmp/cc-web-panel-bNHuzk/repo/packages/web-panel/src/components/MarkdownRenderer.vue"]]);export{b as M};
@@ -1,3 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./xterm-BZcWGsqw.js","./markdown-CsiA8-E5.js","./markdown-Dfs9RUU9.css","./addon-fit-CK6X9sAG.js","./xterm-DFuMZ0ql.css"])))=>i.map(i=>d[i]);
2
- import{u as fe,_ as me,d as V,e as U}from"./index-76GMjcbq.js";import{I as z,J as x,U as _,Q as D,S as K,K as T,V as R,c as A,F as Q,Z as Y,R as E,o as Z,f as G,w as $,n as q,b as ee,r as S,P as y,_ as ve,a2 as we,a3 as he,a4 as _e}from"./vendor-Bn1JzzAn.js";import{R as ye,b as pe,at as ge}from"./icons-DG5UD-6K.js";const k=new Map,C=new Map,N=new Set,F=new Set;let te=!1;function xe(c){te||(te=!0,c.onMessage(o=>{if(!(!o||typeof o.type!="string")){if(o.type==="terminal.stdout"){const{sessionId:s,data:e,seq:i}=o.payload||{};if(!s)return;let w;try{const d=atob(e||""),f=new Uint8Array(d.length);for(let n=0;n<d.length;n++)f[n]=d.charCodeAt(n);w=new TextDecoder("utf-8").decode(f)}catch{w=""}const u={sessionId:s,data:w,seq:i};k.get(s)?.forEach(d=>d(u)),N.forEach(d=>d(u))}else if(o.type==="terminal.exit"){const{sessionId:s,exitCode:e,signal:i}=o.payload||{};if(!s)return;const w={sessionId:s,exitCode:e,signal:i};C.get(s)?.forEach(u=>u(w)),F.forEach(u=>u(w))}}}))}function ne(c){const o=new TextEncoder().encode(c);let s="";for(let e=0;e<o.length;e++)s+=String.fromCharCode(o[e]);return btoa(s)}function ae(c){const o=atob(c||""),s=new Uint8Array(o.length);for(let e=0;e<o.length;e++)s[e]=o.charCodeAt(e);return new TextDecoder("utf-8").decode(s)}function oe(){const c=fe();xe(c);async function o(n={}){const a=await c.sendRaw({type:"terminal.create",payload:{shell:n.shell,cwd:n.cwd,env:n.env,cols:n.cols,rows:n.rows}});if(a.ok===!1)throw new Error(a.error||"terminal_create_failed");return a.result??a}async function s(){const n=await c.sendRaw({type:"terminal.list",payload:{}});if(n.ok===!1)throw new Error(n.error||"terminal_list_failed");const a=n.result??n;return Array.isArray(a.sessions)?a.sessions:[]}async function e(n,a){const r=await c.sendRaw({type:"terminal.stdin",payload:{sessionId:n,data:ne(String(a))}});if(r.ok===!1)throw new Error(r.error||"terminal_stdin_failed");return r.result??r}async function i(n,a,r){const h=await c.sendRaw({type:"terminal.resize",payload:{sessionId:n,cols:a,rows:r}});if(h.ok===!1)throw new Error(h.error||"terminal_resize_failed");return h.result??h}async function w(n){const a=await c.sendRaw({type:"terminal.close",payload:{sessionId:n}});if(a.ok===!1)throw new Error(a.error||"terminal_close_failed");return a.result??a}async function u(n,a=0){const r=await c.sendRaw({type:"terminal.history",payload:{sessionId:n,fromSeq:a}});if(r.ok===!1)throw new Error(r.error||"terminal_history_failed");const h=r.result??r;return{truncated:!!h.truncated,chunks:(h.chunks||[]).map(L=>({seq:L.seq,data:ae(L.data)}))}}function d(n,a){return n?(k.has(n)||k.set(n,new Set),k.get(n).add(a),()=>{k.get(n)?.delete(a),k.get(n)?.size===0&&k.delete(n)}):(N.add(a),()=>N.delete(a))}function f(n,a){return n?(C.has(n)||C.set(n,new Set),C.get(n).add(a),()=>{C.get(n)?.delete(a),C.get(n)?.size===0&&C.delete(n)}):(F.add(a),()=>F.delete(a))}return{create:o,list:s,stdin:e,resize:i,close:w,history:u,onStdout:d,onExit:f,_internal:{stdoutSubs:k,exitSubs:C,toBase64Utf8:ne,fromBase64Utf8:ae}}}const Se={__name:"Terminal",setup(c,{expose:o}){o();const s=oe(),e=S([]),i=S(null),w=S("pwsh"),u=S(!1),d=S(!1),f=S(""),n=S(""),a=S([]),r=[{value:"pwsh",label:"PowerShell"},{value:"cmd",label:"CMD"},{value:"bash",label:"Bash"},{value:"wsl",label:"WSL"}],h=ee(()=>e.value.find(t=>t.id===i.value));function L(t){return t?t.slice(0,8):""}let O=null,M=null;async function I(){if(O)return{xtermMod:O,fitAddonMod:M};try{O=await U(()=>import("./xterm-BZcWGsqw.js").then(t=>t.x),__vite__mapDeps([0,1,2]),import.meta.url),M=await U(()=>import("./addon-fit-CK6X9sAG.js").then(t=>t.a),__vite__mapDeps([3,1,2]),import.meta.url),await U(()=>Promise.resolve({}),__vite__mapDeps([4]),import.meta.url)}catch(t){throw n.value="xterm 资源加载失败:"+(t?.message||"未知错误"),t}return{xtermMod:O,fitAddonMod:M}}async function B(t){await q();const{xtermMod:l,fitAddonMod:p}=await I(),b=a.value.find(v=>v?.dataset?.sessionId===t.id);if(!b)return;const m=new l.Terminal({cursorBlink:!0,fontFamily:'Consolas, "Courier New", monospace',fontSize:13,theme:{background:"#1e1e1e",foreground:"#d4d4d4"},convertEol:!1}),P=new p.FitAddon;m.loadAddon(P),m.open(b);try{P.fit()}catch{}t.xterm=m,t.fitAddon=P;const ie=m.onData(v=>{s.stdin(t.id,v).catch(g=>{String(g?.message||"").includes("dangerous_keyword_blocked")?V.warning("该命令被桌面端拦截(高危关键字)"):V.error("stdin 失败: "+(g?.message||g))})}),ce=s.onStdout(t.id,({data:v,seq:g})=>{t.lastSeq=g,m.write(v)}),de=s.onExit(t.id,({exitCode:v,signal:g})=>{t.alive=!1,t.exitCode=v,t.signal=g,m.writeln(`\r
3
- \x1B[33m[session exited, code=${v}, signal=${g??"-"}]\x1B[0m`)});t.offs=()=>{try{ie.dispose?.()}catch{}ce(),de()};try{const{chunks:v,truncated:g}=await s.history(t.id,0);g&&m.writeln("\x1B[2m[history truncated — earlier output was evicted]\x1B[0m");for(const J of v)m.write(J.data),t.lastSeq=J.seq}catch(v){m.writeln(`\x1B[31m[history fetch failed: ${v?.message||v}]\x1B[0m`)}const H=new ResizeObserver(()=>{try{P.fit(),s.resize(t.id,m.cols,m.rows).catch(()=>{})}catch{}});H.observe(b);const ue=t.offs;t.offs=()=>{try{H.disconnect()}catch{}ue()}}async function re(){u.value=!0,f.value="";try{const t=await s.create({shell:w.value,cols:80,rows:24}),l={id:t.sessionId,shell:t.shell,cwd:"",alive:!0,lastSeq:0,exitCode:null,xterm:null,fitAddon:null,offs:()=>{}};e.value.push(l),i.value=l.id,await B(l)}catch(t){f.value=t?.message||String(t)}finally{u.value=!1}}async function se(t){try{await s.close(t)}catch(l){f.value=l?.message||String(l)}setTimeout(()=>W(t),500)}function W(t){const l=e.value.findIndex(b=>b.id===t);if(l===-1)return;const p=e.value[l];try{p.offs?.()}catch{}try{p.xterm?.dispose?.()}catch{}e.value.splice(l,1),i.value===t&&(i.value=e.value[0]?.id||null)}function le(t){i.value=t,q(()=>{const l=e.value.find(p=>p.id===t);try{l?.fitAddon?.fit()}catch{}})}async function X(){d.value=!0,f.value="";try{const t=await s.list();for(const l of t){const p=e.value.find(m=>m.id===l.id);if(p){p.alive=l.alive,p.lastSeq=l.lastSeq;continue}const b={id:l.id,shell:l.shell,cwd:l.cwd,alive:l.alive,lastSeq:l.lastSeq,exitCode:null,xterm:null,fitAddon:null,offs:()=>{}};e.value.push(b),await B(b)}!i.value&&e.value.length>0&&(i.value=e.value[0].id)}catch(t){f.value=t?.message||String(t)}finally{d.value=!1}}Z(async()=>{await X()}),G(()=>{for(const t of e.value){try{t.offs?.()}catch{}try{t.xterm?.dispose?.()}catch{}}}),$(i,()=>{q(()=>{const t=h.value;try{t?.fitAddon?.fit()}catch{}})});const j={term:s,sessions:e,activeId:i,newShell:w,creating:u,loadingList:d,error:f,warning:n,xtermContainers:a,shellOptions:r,active:h,shortId:L,get xtermMod(){return O},set xtermMod(t){O=t},get fitAddonMod(){return M},set fitAddonMod(t){M=t},loadXterm:I,mountXterm:B,onCreate:re,onClose:se,removeSession:W,activate:le,refreshList:X,ref:S,computed:ee,onMounted:Z,onBeforeUnmount:G,nextTick:q,watch:$,get message(){return V},get PlusOutlined(){return ge},get CloseOutlined(){return pe},get ReloadOutlined(){return ye},get useTerminal(){return oe}};return Object.defineProperty(j,"__isScriptSetup",{enumerable:!1,value:!0}),j}},be={class:"terminal-page"},ke={class:"terminal-header"},Ce={class:"page-sub"},Ae={class:"terminal-body"},Ee={class:"session-tabs"},Oe=["onClick"],Te={class:"session-shell"},Re={class:"session-id"},Me={key:0,class:"session-empty"},ze={class:"xterm-host"},Le=["data-session-id"],Pe={key:0,class:"xterm-placeholder"},De={key:1,class:"terminal-footer"},qe={key:0,class:"footer-exit"};function Be(c,o,s,e,i,w){const u=z("a-tag"),d=z("a-select"),f=z("a-button"),n=z("a-space"),a=z("a-alert");return y(),x("div",be,[_("div",ke,[_("div",null,[o[3]||(o[3]=_("h2",{class:"page-title"},"远程终端",-1)),_("p",Ce,[o[2]||(o[2]=D(" 桌面端托管的 PTY 会话;Android 端可远程操控同一通道 ",-1)),e.warning?(y(),K(u,{key:0,color:"orange",style:{"margin-left":"8px"}},{default:T(()=>[D(E(e.warning),1)]),_:1})):R("v-if",!0)])]),A(n,null,{default:T(()=>[A(d,{value:e.newShell,"onUpdate:value":o[0]||(o[0]=r=>e.newShell=r),style:{width:"130px"},size:"small",options:e.shellOptions},null,8,["value"]),A(f,{type:"primary",size:"small",loading:e.creating,onClick:e.onCreate},{icon:T(()=>[A(e.PlusOutlined)]),default:T(()=>[o[4]||(o[4]=D(" 新会话 ",-1))]),_:1},8,["loading"]),A(f,{size:"small",loading:e.loadingList,onClick:e.refreshList},{icon:T(()=>[A(e.ReloadOutlined)]),default:T(()=>[o[5]||(o[5]=D(" 刷新 ",-1))]),_:1},8,["loading"])]),_:1})]),e.error?(y(),K(a,{key:0,message:e.error,type:"error","show-icon":"",closable:"",style:{"margin-bottom":"12px"},onClose:o[1]||(o[1]=r=>e.error="")},null,8,["message"])):R("v-if",!0),_("div",Ae,[_("div",Ee,[(y(!0),x(Q,null,Y(e.sessions,r=>(y(),x("div",{key:r.id,class:ve(["session-tab",{active:r.id===e.activeId,dead:!r.alive}]),onClick:h=>e.activate(r.id)},[_("span",Te,E(r.shell),1),_("span",Re,E(e.shortId(r.id)),1),A(e.CloseOutlined,{class:"session-close",onClick:we(h=>e.onClose(r.id),["stop"])},null,8,["onClick"])],10,Oe))),128)),e.sessions.length===0?(y(),x("div",Me,' 点击 "新会话" 创建第一个终端 ')):R("v-if",!0)]),_("div",ze,[(y(!0),x(Q,null,Y(e.sessions,r=>he((y(),x("div",{key:r.id,ref_for:!0,ref:"xtermContainers","data-session-id":r.id,class:"xterm-container"},null,8,Le)),[[_e,r.id===e.activeId]])),128)),e.sessions.length===0?(y(),x("div",Pe,[...o[6]||(o[6]=[_("span",null,"无活跃会话",-1)])])):R("v-if",!0)])]),e.active?(y(),x("div",De,[_("span",null,E(e.active.shell)+" · "+E(e.active.cwd||"(默认 cwd)")+" · seq "+E(e.active.lastSeq),1),e.active.alive?R("v-if",!0):(y(),x("span",qe,"已退出 (code="+E(e.active.exitCode??"-")+")",1))])):R("v-if",!0)])}const Fe=me(Se,[["render",Be],["__scopeId","data-v-65366a29"],["__file","/tmp/cc-web-panel-bNHuzk/repo/packages/web-panel/src/views/Terminal.vue"]]);export{Fe as default};
@@ -1 +0,0 @@
1
- import{Q as r}from"./index-76GMjcbq.js";const o=((n,a,e)=>{r(n,`[ant-design-vue: ${a}] ${e}`)});export{o as d};
@@ -1 +0,0 @@
1
- import{C as o}from"./Col-CfDPzFPq.js";import{a0 as t}from"./index-76GMjcbq.js";import"./vendor-Bn1JzzAn.js";import"./index-Bvj07Ab1.js";import"./icons-DG5UD-6K.js";const s=t(o);export{s as default};
@@ -1 +0,0 @@
1
- import{A as o}from"./Row-BuAsoNTS.js";import{a0 as t}from"./index-76GMjcbq.js";import"./vendor-Bn1JzzAn.js";import"./responsiveObserve-Dy8D0D3n.js";import"./useFlexGapSupport-C82c33XI.js";import"./styleChecker-CWhJrDON.js";import"./index-Bvj07Ab1.js";import"./icons-DG5UD-6K.js";const l=t(o);export{l as default};