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.
- package/package.json +3 -1
- package/src/assets/web-panel/assets/{AIOps-DgGZr3PR.js → AIOps-LbDx7jL6.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BAOgBIc_.js → ActionButton-DnurtK34.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Ds4GAvNF.js → Analytics-DXSsV1am.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CoJvCkoF.js → AppLayout-dqRpzNuD.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-6EgUaE1T.js → Artifacts-BwdmYepK.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BYie_i74.js → Audit-oSX0kOUG.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-D5gxOhjd.js → BackgroundAgents-C2KxJahT.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CIsVK2pT.js → Backup-B4TkxWkC.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-ClorP55M.js → BaseInput-CX5-KxeU.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CnhTPGGA.js → Chat-O_HzD-PL.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-Bl1VXgwp.js → ChatBubbleRenderer-Br8saHQA.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BRavl7TP.js → Checkbox-ChepDpC1.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BXg_ErNT.js → Codegen-D9z8kc7q.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CfDPzFPq.js → Col-B-H5eoNw.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Cgo0httP.js → Community-Ccyp_Kk5.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DU5JcEQM.js → Compact-BNvBznp_.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DCH_TVBl.js → Compliance-D1FjRd8n.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-IGb5O2IH.js → Cowork-CV9B9u-8.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-CPp_Xp9F.js → Cron-BowJ4VIx.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-Cwrqklzw.js → Crosschain-BJc6jzRF.js} +1 -1
- package/src/assets/web-panel/assets/{DID-D55sBQwM.js → DID-BEp8NV6D.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CedXhGmP.js → Dashboard-Dls0B3YB.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Dm6_v3V4.js → Dropdown-DQ7zXVtD.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CWjnuE3G.js → EmailListRenderer-B9q79tOl.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DubTh7y-.js → FamilyGuardDashboard-CD8Ie-88.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DlSM4uJv.js → Federation-5o7XU5Vf.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BYhg0vtG.js → FormItemContext-DeKbMvOs.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-Bkh7qjfK.js → GenericCardRenderer-CZiQvz_z.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DSLWPKvn.js → Git-CTvFxVV8.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DIj9O8BB.js → Governance-DwzFIjHt.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Dhep3e5Y.js → Inference-CJBk59c-.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Cj8vzxB_.js → KnowledgeGraph-DfsaXN2z.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Ba4SsPja.js → Logs-DVRYf18S.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BL_WsWZM.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-CGs9IIbf.js → Marketplace-BuIwyE4t.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BTPAoX4K.js → McpTools-D3U0o78E.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BJ6ISf2c.js → Memory-QYVmyb3b.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Ca6n3Dcn.js → MobileBridge-BFgrj6eZ.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-lvilHuLt.js → MobileProjects-Bp5QB-46.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CMo0acBV.js → Mtc-BZQu8TcH.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-Hz5wBvFX.js → MtcAudit-BnFfEkLo.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BK2aKWE6.js → Multisig-iUnNS9Cm.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CExpnYMI.js → NLProgramming-DNNz1y9Y.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-B7IFbuBo.js → Notes-CZezNYRU.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-VrGchtb0.js → NotificationSettings-DBvrplIR.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CyrNTxkU.js → OrderTableRenderer-CTDtee49.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-I0C17GBP.js → Organization-CCOUJX1R.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CXcWvERe.js → Overflow-DcZghdk0.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-FFSCXrZq.js → P2P-jmddWX9q.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-1PB-p8Zk.js → PdhVaultBrowser-wfjMcczl.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-C1YHejsb.js → Permissions-DU1GJjca.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CEMPpgf8.js → PersonalDataHub-BzTMzDF9.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-FoIScdLr.js → Pipeline-DPmjlpVc.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DDfbEzEj.js → Privacy-B6HRLpfK.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Dso4kB0O.js → ProjectInit-Cyy86AsN.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-WvDoydDc.js → ProjectSettings-Bl_WQxJ5.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-NJp0kzkd.js → Projects-Co9yKThA.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-BuJXnOLI.js → Providers-DLa4NlIs.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-Bb3lMvGG.js → QrScannerModal-BvzM7q5f.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Ddxra3fK.js → QuickAsk-BN8yyyUj.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BW-dR9qw.js → Recommend-QsVN4w0i.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-Hnm7-Qkm.js → RemoteSession-tkDXw-TY.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-DKz6meHE.js → Reputation-DAifkGsy.js} +1 -1
- package/src/assets/web-panel/assets/{Row-BuAsoNTS.js → Row-D7dZEyak.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-_do9DMIH.js → RssFeed-DB5sImTA.js} +2 -2
- package/src/assets/web-panel/assets/{Search-CMlcw7ND.js → Search-3py3TO9V.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DhAkfSpM.js → Security-DhNUfT_k.js} +3 -3
- package/src/assets/web-panel/assets/{Services-5zKLhy46.js → Services-DjJAA_5D.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DCMZ3wfv.js → Skeleton-u95JjK3n.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DxQgYCC_.js → Skills-DPo3L0Tz.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CJmE4cSN.js → Sla-DWhkAZV1.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BgpRTPQp.js → SpeechSettings-PUegMtqV.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DkogtYbB.js → SyncSettings-BMNYrnrU.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-D5OrwAl9.js → Tasks-CYm_oTJC.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DAZIu5nN.js → Templates-Dw9Er5DN.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BRJMI-su.js → Tenant-7P3QIBSo.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-ClPrfWW7.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-D4z9aSGD.js → TimelineRenderer-DbCd1bDH.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-zgYA4UOI.js → Tokens-EQofpA0t.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DMOgHX4m.js → Trigger-ChNLLypd.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CEtoNwcT.js → Trust-dlVGUKs5.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DFx2pQfO.js → UkeySign-BXyBUhNF.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DLssy-7B.js → VideoEditing-BE8-68ge.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DQHc6gTl.js → Wallet-7ZIJOwNg.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DgKcODkn.js → WebAuthn-DgNd2Amr.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-cPEWfMOf.js → WorkflowEditor-Z-Un-9l5.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Coj7rSO1.js → chat-CtVDEkUc.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DiyGfr-6.js → colors-PXtJ2f1B.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DB63aMXh.js → compact-item-oN96nuBi.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CENpsYHg.js → createContext-okCJXQXa.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BzV6dk1B.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-B9NOmk0K.js → hasIn-pcHm--4o.js} +1 -1
- package/src/assets/web-panel/assets/{index-VDFbduzG.js → index-5aO2V0V4.js} +1 -1
- package/src/assets/web-panel/assets/{index-Yb9EfUnY.js → index-BDR2mi1p.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpmTl8QC.js → index-BEtzqJw3.js} +1 -1
- package/src/assets/web-panel/assets/index-BFrAwXHp.js +1 -0
- package/src/assets/web-panel/assets/{index-nio98wGC.js → index-BHJIfdCV.js} +1 -1
- package/src/assets/web-panel/assets/{index-t6hXF2Cw.js → index-BUTyx-Lk.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRhEJ8JO.js → index-BUUJ2WfG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BvQq6gX2.js → index-BZKk4Lnm.js} +1 -1
- package/src/assets/web-panel/assets/{index-BkoqtJzV.js → index-BeAWCGEK.js} +1 -1
- package/src/assets/web-panel/assets/{index-7IMjHwGU.js → index-Bht9n8Sm.js} +1 -1
- package/src/assets/web-panel/assets/{index-B45osqnZ.js → index-BjVIZfdA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmNCDN5t.js → index-Bl6N7ZyX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXzMKVLp.js → index-BnhHxZul.js} +1 -1
- package/src/assets/web-panel/assets/{index-U_snupDl.js → index-BuME9k4Y.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dg0v-CXZ.js → index-C0rfJBU3.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKNt2vfs.js → index-C4ravjdv.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxvNtndl.js → index-CAQktO-6.js} +1 -1
- package/src/assets/web-panel/assets/{index-CvTJ-x6b.js → index-CK0H3pQW.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAMKhjtT.js → index-CQ1ZzJjN.js} +1 -1
- package/src/assets/web-panel/assets/{index-mTK_ZHhE.js → index-CQYes2mk.js} +1 -1
- package/src/assets/web-panel/assets/{index-76GMjcbq.js → index-CWUJlCvK.js} +3 -3
- package/src/assets/web-panel/assets/{index-CwkK9Kl2.js → index-CXhezK4d.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_rZCxxI.js → index-Cc_MkksW.js} +1 -1
- package/src/assets/web-panel/assets/{index-BramLq29.js → index-CopGaCI_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CXRknr9W.js → index-Cs1fGk1Z.js} +1 -1
- package/src/assets/web-panel/assets/{index-DANoIqXP.js → index-D0bfypsF.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClEy1v1o.js → index-D1efSh1X.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bvj07Ab1.js → index-DBcKBb1E.js} +1 -1
- package/src/assets/web-panel/assets/{index-CxVfbuj9.js → index-DC0bqrqV.js} +1 -1
- package/src/assets/web-panel/assets/index-DJQFP47u.js +1 -0
- package/src/assets/web-panel/assets/{index-CTuX_MU0.js → index-DfL10EcN.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9d8hdgY.js → index-DtsyPnF5.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAXouogg.js → index-Rk0X8lVz.js} +1 -1
- package/src/assets/web-panel/assets/{index-Y_UKQpsV.js → index-T3QE8LuV.js} +1 -1
- package/src/assets/web-panel/assets/{index-DqLC0iE4.js → index-_SaFHNsG.js} +1 -1
- package/src/assets/web-panel/assets/{index-Kp2AETEw.js → index-jAY55MSx.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsPDEHOg.js → index-mB1UV7wA.js} +1 -1
- package/src/assets/web-panel/assets/{index-KDCuTzdx.js → index-nMqLdwao.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0C6zl0y.js → index-vW0lwj0Y.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-GTwJVIOz.js → initDefaultProps-CG1jyiI7.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BJQLsPx8.js → motion-C8BYa98D.js} +1 -1
- package/src/assets/web-panel/assets/{move-DVQM0bdG.js → move-D1hqwitW.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CMXI1I2y.js → mtc-parser-C2lol8rp.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CAc8MDw9.js → omit-Ct6Zghfi.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BgqzoyP7.js → pickAttrs-CSYbYfdc.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B9ebCdRy.js → placementArrow-WCk8di0z.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Dy8D0D3n.js → responsiveObserve-CEC8CZ-3.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Bcrc8J39.js → slide-BsXyd7Lq.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CDW6FOlc.js → statusUtils-tDKldiUT.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CWhJrDON.js → styleChecker-BIS2unhx.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C82c33XI.js → useFlexGapSupport-yFTVMDUv.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-A6m--mih.js → useFs-CZYbJwkO.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-m-1laJY5.js → usePersonalDataHub-sbEHRLAM.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CL9oKKRa.js → vnode-BVjeSEQK.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DrOyaof3.js → zoom-BZKVvEZ6.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +7 -2
- package/src/lib/background-session-transport.js +24 -2
- package/src/lib/governance-coverage.js +179 -0
- package/src/lib/packer/smoke-runner.js +85 -15
- package/src/lib/protocol-replay.js +153 -0
- package/src/runtime/agent-core.js +35 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-DUjyuVB3.js +0 -1
- package/src/assets/web-panel/assets/Terminal-CMXLqQKF.js +0 -3
- package/src/assets/web-panel/assets/devWarning-XvRaIiyt.js +0 -1
- package/src/assets/web-panel/assets/index-CbO1zSXV.js +0 -1
- 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("
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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", () =>
|
|
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};
|