chainlesschain 0.162.174 → 0.162.175
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 +1 -1
- package/src/assets/web-panel/assets/{AIOps-Dcl-X1Hw.js → AIOps-DherW0Rh.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-ClMh9HzT.js → ActionButton-CDGfqt2Y.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DPj0rSQ5.js → Analytics-BYhkzdgD.js} +3 -3
- package/src/assets/web-panel/assets/AppLayout-cEKk1cpb.js +9 -0
- package/src/assets/web-panel/assets/{Artifacts-L8781rE8.js → Artifacts-_aXR3WWc.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CffB6WIP.js → Audit-CYAf-gY7.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BkLhayyY.js → BackgroundAgents-D4Q20phR.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BQnwFI78.js → Backup-Cq0Tyk58.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-xuUGHQch.js → BaseInput-CPj_CdAv.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-feQXwWrg.js → Chat-BQ-Qq0es.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-Ci97vNTs.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-DVaIiUGW.js → Checkbox-rke6l3yg.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-D2kEnzeU.js → Codegen-DiacrIPq.js} +1 -1
- package/src/assets/web-panel/assets/{Col-azDoyusS.js → Col-Cx3BY-Up.js} +1 -1
- package/src/assets/web-panel/assets/{Community-OZdnPWM5.js → Community-DfmWiQy8.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-VDMvBN-C.js → Compact-DdQnpxy5.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CPJ_zgQ1.js → Compliance-lzliOH_r.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-iRBwcsOA.js → Cowork-CYx4Un5k.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-DrxrspUz.js → Cron-BGDcPFlo.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-D-rkAZXF.js → Crosschain-0_X5g2ri.js} +1 -1
- package/src/assets/web-panel/assets/{DID-5Pp1Xnmr.js → DID-C0PEf3Eu.js} +2 -2
- package/src/assets/web-panel/assets/Dashboard-DULQjQ58.js +3 -0
- package/src/assets/web-panel/assets/{Dropdown-BWj_E0Ie.js → Dropdown-DGRHRbW6.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BT-wgSEh.js → EmailListRenderer-ChX8XPwB.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-1PzH23pa.js → FamilyGuardDashboard-Dyq6IBNu.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BxMIXGC6.js → Federation-DH1NfAL2.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CyJobBln.js → FormItemContext-BN1I_uNi.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-YkjFuQTN.js → GenericCardRenderer-Dq_2UYpe.js} +1 -1
- package/src/assets/web-panel/assets/{Git-C2a98Wp_.js → Git-BAy1yvI2.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DKL3Fl84.js → Governance-Db6Q2iSy.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BJ2cQC_3.js → Inference-0ub6yHcr.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DBAsOngt.js → KnowledgeGraph-DtLetM36.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-COt8g9LO.js → Logs-Bcoy7CUd.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-3Lfht1Fd.js → MarkdownRenderer-BfEMFAXf.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-C9Zk9Pb2.js → Marketplace-tt2rzwRR.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DDWDFWPO.js → McpTools-BhOgX-MU.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-BRmVye_o.js → Memory-BJUxeWBL.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CppBbWpD.js → MobileBridge-BwUY2G9w.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-C4GKn1dH.js → MobileProjects-BLRfHhqi.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CcWpeGa6.js → Mtc-B2WMboOm.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-BcllEq0K.js → MtcAudit-8pNEXO63.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BFD1CarL.js → Multisig-C1wm5a_1.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-QNXXYvjz.js → NLProgramming-C1QpKF7g.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-07YwgQVy.js → Notes-CiQUcxFu.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-bOccEInE.js → NotificationSettings-BblDPJ_x.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DlRi29WL.js → OrderTableRenderer-DRjYcPtb.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CBaezzEr.js → Organization-Dp3VKB0X.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Bl5NohFO.js → Overflow-Czx161m9.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CLMal9Aw.js → P2P-ClFi6wOs.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CGO0NITk.js → PdhVaultBrowser-CRweW0lz.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CPSw48E2.js → Permissions-BzcRoqTn.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CDM5n134.js → PersonalDataHub-ChGTpNMd.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-BdsqG7WV.js → Pipeline-BMOOpKWA.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B6L4E-M7.js → Privacy-D0AZHObH.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DXPyZKRs.js → ProjectInit-yYFlZ6Ja.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BrCC3xYT.js → ProjectSettings-DJNVuMQs.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BYmuHC2q.js → Projects-Br0rBWH1.js} +1 -1
- package/src/assets/web-panel/assets/Providers-zZRhNtSu.js +1 -0
- package/src/assets/web-panel/assets/{QrScannerModal-DkukgCrR.js → QrScannerModal-81NZOitV.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-D-htOrV8.js → QuickAsk-Dic2lCbJ.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Bm7SIfzu.js → Recommend-Dh9iwViE.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-C9rP-iMc.js → RemoteSession-Bq9VYEFy.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-kGlUgbsl.js → Reputation-CxFZ-NbJ.js} +1 -1
- package/src/assets/web-panel/assets/{Row-PBupbbUA.js → Row-BVSLcaX2.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-njlwKUGK.js → RssFeed-BbC-5DOH.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DLdEmgBw.js → Search-BfjZ1GCr.js} +1 -1
- package/src/assets/web-panel/assets/{Security-SXGPSHdu.js → Security-CVjhOV5r.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CuFGnNsb.js → Services-D45u-Aqe.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CtUC0mDa.js → Skeleton-WkGoK4he.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-P1qgOVFn.js → Skills-D_jvQZcj.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CsppE8YV.js → Sla-Bf4QTF3E.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Cq1oG56m.js → SpeechSettings-DVpZdbMN.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DdKW6V-C.js → SyncSettings-DEEojoMS.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BCc9san5.js → Tasks-DFwxpLIk.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CcHC1dMA.js → Templates-Bzl-9wY5.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CA4PqU22.js → Tenant-0khxUOB8.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-Fj7ea0In.js → Terminal-DWGYhAYU.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DHWTSvOy.js → TimelineRenderer-B0Y4LONc.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Ddz-P_yh.js → Tokens-DEE07SFh.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-ePmrmLZ1.js → Trigger-BM7xvA5z.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DmuK1CCE.js → Trust-Dv3ijvvZ.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CqqBuRrT.js → UkeySign-B1-enmMt.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BGlR3uWM.js → VideoEditing-DYiIPByd.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Ba_Qx6Ga.js → Wallet-D-y374BQ.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-29neXKt2.js → WebAuthn-HBDjcUhi.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-lD0lR0UQ.js → WorkflowEditor-sKn4qTID.js} +1 -1
- package/src/assets/web-panel/assets/{chat-B3stH01u.js → chat-TVYhaBXj.js} +1 -1
- package/src/assets/web-panel/assets/{colors-Czly56MN.js → colors-DMADxY9v.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-C0TkbkAJ.js → compact-item-OftcHpO_.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BJmpSlf1.js → createContext-DW1zVUSN.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CLOk6rdE.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D1q-zw7u.js → hasIn-CaUathNp.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7sFKQ53.js → index--5UvwqH_.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dpz_7sf-.js → index-77kgkUgY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlvsSuBC.js → index-8YelceUU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpMIdPJ0.js → index-B-19mFhn.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEt2-3x5.js → index-B52Ztt8Q.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQftlZn-.js → index-BBNg08cD.js} +3 -3
- package/src/assets/web-panel/assets/{index-upY9rkGZ.js → index-BEzLLVYd.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDHXx65P.js → index-BFVbDpqg.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmUta2lw.js → index-BJ1PjRY3.js} +1 -1
- package/src/assets/web-panel/assets/{index-z8ATo2aQ.js → index-BSp1Ofvx.js} +1 -1
- package/src/assets/web-panel/assets/{index-DO8xOwxi.js → index-Bg-7FpaL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpGs96FC.js → index-BupSWDcl.js} +1 -1
- package/src/assets/web-panel/assets/{index-K4YaPDOn.js → index-BvRw4Fna.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8KqsomG.js → index-C9JoaYSs.js} +1 -1
- package/src/assets/web-panel/assets/{index-8GKykbS4.js → index-CK-p7Hji.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dw3L_smW.js → index-CKNdnJRo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAhrn9EJ.js → index-CM8W07sc.js} +1 -1
- package/src/assets/web-panel/assets/index-CSgUfMTM.js +1 -0
- package/src/assets/web-panel/assets/{index-C1pOqU7D.js → index-CZXYI5LU.js} +1 -1
- package/src/assets/web-panel/assets/{index-DV-twjNO.js → index-CeCIYYG7.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIF6XHIi.js → index-Cmdv6Dev.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cu_4HaUS.js → index-CpDtN0dl.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRcQsPez.js → index-D63QVAiJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-kTvMq7.js → index-DAfT3EMd.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHvPlzWJ.js → index-DHi634g9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgS8XUBU.js → index-DKjqFpYa.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZDUhX41Z.js → index-DWVZ3T0t.js} +1 -1
- package/src/assets/web-panel/assets/{index-BVwJ3jht.js → index-DXcqvWBp.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbvNJUwu.js → index-DYwwUKDg.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaqEHaCg.js → index-DZdT8nio.js} +1 -1
- package/src/assets/web-panel/assets/index-DliSZvAP.js +1 -0
- package/src/assets/web-panel/assets/{index-DBqAm8es.js → index-GUKz4Pv9.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChESIe5r.js → index-Lr0MO-GU.js} +1 -1
- package/src/assets/web-panel/assets/{index-C27TnOoT.js → index-hXq7QRA_.js} +1 -1
- package/src/assets/web-panel/assets/{index-cPjWjvmW.js → index-iDmgT2Dg.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cf7Gr3NG.js → index-kdMl_0zL.js} +1 -1
- package/src/assets/web-panel/assets/{index-XWV8JWMc.js → index-pSVCBsG4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZeoKL6t.js → index-s-EnkUCn.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bm_-RKal.js → index-sm1sGIxW.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-QWEXi6-t.js → initDefaultProps-DdcKTlQR.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BfrQwvV1.js → motion-CL-hTBQj.js} +1 -1
- package/src/assets/web-panel/assets/{move-Dn7x0H9t.js → move-qYSAkxNG.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-F61D_TgE.js → mtc-parser-ZwRSZtRP.js} +1 -1
- package/src/assets/web-panel/assets/{omit-4SQZ39PF.js → omit-Bld-8ftI.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-C7DTe126.js → pickAttrs-DGHs-a9Z.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-40NeyzDK.js → placementArrow-DRQPMyI5.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BiUJ6qWs.js → responsiveObserve-C5MJG_Yo.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CacJTM3f.js → slide-VZ-fpZCD.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-K812HB-k.js → statusUtils-9ocfCyHk.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CKeHA2eM.js → styleChecker-B6QAwAN5.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CKl4FqXF.js → useFlexGapSupport-Bq1twor3.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DPoiJjSZ.js → useFs-DKZq96tz.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-aHwBspmt.js → usePersonalDataHub-D0RmRVXf.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DrA-GuCT.js → vnode-D6kEj_tt.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-G3LMswgy.js → zoom-2yfasoQf.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +6 -2
- package/src/commands/background-session.js +103 -0
- package/src/esm-bridge.js +3 -0
- package/src/gateways/ws/ws-server.js +18 -2
- package/src/index.js +123 -55
- package/src/lazy-dispatch.js +86 -85
- package/src/lib/async-hook-supervisor.cjs +14 -2
- package/src/lib/background-interaction-resolver.js +71 -0
- package/src/lib/background-session-transport.js +59 -1
- package/src/lib/crash-reporter.js +6 -0
- package/src/lib/hook-manager.js +32 -4
- package/src/lib/ipc-attach-protocol.js +98 -0
- package/src/lib/process-execution-broker/credential-agent.js +275 -0
- package/src/lib/process-execution-broker/index.js +155 -6
- package/src/lib/process-execution-broker/platform-sandbox.js +351 -0
- package/src/lib/provenance-api.js +6 -0
- package/src/lib/proxy-bootstrap.js +19 -0
- package/src/lib/repl-rewind.js +9 -4
- package/src/lib/session-hooks.js +328 -473
- package/src/lib/session-telemetry-middleware.js +6 -0
- package/src/lib/trace-api.js +6 -0
- package/src/lib/update-notice.js +3 -43
- package/src/repl/agent-repl.js +39 -13
- package/src/workers/background-agent-worker.js +80 -1
- package/src/assets/web-panel/assets/AppLayout-7iSKDmlI.js +0 -9
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DcbUHeGW.js +0 -1
- package/src/assets/web-panel/assets/Dashboard-BAKYNavw.js +0 -3
- package/src/assets/web-panel/assets/Providers-CbCe2eUl.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CDI8Sbaj.js +0 -1
- package/src/assets/web-panel/assets/index-96LBR96V.js +0 -1
- package/src/assets/web-panel/assets/index-DyQkiW24.js +0 -1
package/src/lazy-dispatch.js
CHANGED
|
@@ -1,107 +1,108 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Lazy CLI dispatch
|
|
3
|
-
*
|
|
4
|
-
* Importing src/index.js eagerly loads all ~154 command modules + their
|
|
5
|
-
* transitive dependency graph (~2.7s; see memory
|
|
6
|
-
* cli_cold_start_bottleneck_hub_repl). But a real `cc <cmd>` invocation only
|
|
7
|
-
* needs ONE command's module. This dispatcher resolves the target command from
|
|
8
|
-
* argv against the generated manifest (src/command-manifest.json) and imports
|
|
9
|
-
* just that module, then parses.
|
|
10
|
-
*
|
|
11
|
-
* SAFETY: anything uncertain — no command, --help, an unknown command, or a
|
|
12
|
-
* project-mode subcommand whitelist — falls back to the full eager program
|
|
13
|
-
* (src/index.js `createProgram`), i.e. exactly today's behavior. The fast path
|
|
14
|
-
* only activates when a single known command resolves cleanly. Worst case is
|
|
15
|
-
* therefore "as slow as today, still correct", never "wrong".
|
|
16
|
-
*
|
|
17
|
-
* The manifest is regenerated by scripts/gen-command-manifest.mjs and guarded
|
|
18
|
-
* against drift by lazy-dispatch.test.js.
|
|
2
|
+
* Lazy CLI dispatch - fast path for single commands, full program for help/unknown
|
|
19
3
|
*/
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
4
|
+
import { createProgramAsync } from "./index.js";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
23
9
|
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
24
11
|
const manifest = JSON.parse(
|
|
25
|
-
readFileSync(
|
|
12
|
+
readFileSync(join(__dirname, "command-manifest.json"), "utf8"),
|
|
26
13
|
);
|
|
27
14
|
|
|
28
|
-
// name + every alias -> manifest entry
|
|
29
|
-
const byName = new Map();
|
|
30
|
-
for (const entry of manifest.commands) {
|
|
31
|
-
byName.set(entry.name, entry);
|
|
32
|
-
for (const alias of entry.aliases || []) byName.set(alias, entry);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
15
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* following value, so "first token not starting with '-'" is unambiguous.
|
|
16
|
+
* Run the CLI with lazy dispatch optimization
|
|
17
|
+
* @param {string[]} argv - process.argv
|
|
18
|
+
* @returns {Promise<void>}
|
|
40
19
|
*/
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
20
|
+
/** Return the first top-level command token in a process argv array. */
|
|
21
|
+
export function resolveCommandToken(argv = []) {
|
|
22
|
+
const args = Array.isArray(argv) ? argv.slice(2) : [];
|
|
23
|
+
for (const token of args) {
|
|
24
|
+
if (token === "--") return null;
|
|
25
|
+
if (token === "--verbose" || token === "--quiet") continue;
|
|
26
|
+
if (["--help", "-h", "--version", "-v", "-V"].includes(token)) return null;
|
|
27
|
+
if (!token.startsWith("-")) return token;
|
|
47
28
|
}
|
|
48
29
|
return null;
|
|
49
30
|
}
|
|
50
31
|
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
}
|
|
32
|
+
export async function runCli(argv) {
|
|
33
|
+
const args = argv.slice(2);
|
|
54
34
|
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
35
|
+
// Resolve the command before deciding whether help/version needs the eager
|
|
36
|
+
// program. `cc <command> --help` is command-scoped help and must load only
|
|
37
|
+
// that command; treating every `--help` as root help silently discards the
|
|
38
|
+
// command token (and broke `cc agent --help` after lazy dispatch landed).
|
|
39
|
+
const commandName = resolveCommandToken(argv);
|
|
40
|
+
const entry = manifest.commands.find(
|
|
41
|
+
(c) =>
|
|
42
|
+
c.name === commandName || (c.aliases && c.aliases.includes(commandName)),
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// Fast path: if no args, or --help, or --version, use full program
|
|
46
|
+
if (
|
|
47
|
+
args.length === 0 ||
|
|
48
|
+
(!entry &&
|
|
49
|
+
(args.includes("--help") ||
|
|
50
|
+
args.includes("-h") ||
|
|
51
|
+
args.includes("--version") ||
|
|
52
|
+
args.includes("-V")))
|
|
53
|
+
) {
|
|
54
|
+
const program = await createProgramAsync();
|
|
55
|
+
await program.parseAsync(argv);
|
|
56
|
+
return;
|
|
63
57
|
}
|
|
64
|
-
}
|
|
65
58
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
export async function runCli(argv = process.argv) {
|
|
74
|
-
// Project-mode packed exes restrict the visible command set; the filtering
|
|
75
|
-
// lives in the eager createProgram, so defer to it for correctness.
|
|
76
|
-
const whitelistActive = !!process.env.CC_PROJECT_ALLOWED_SUBCOMMANDS;
|
|
77
|
-
const token = resolveCommandToken(argv);
|
|
59
|
+
// Try to find the command in manifest
|
|
60
|
+
// Unknown command, use full program to show error/help
|
|
61
|
+
if (!entry) {
|
|
62
|
+
const program = await createProgramAsync();
|
|
63
|
+
await program.parseAsync(argv);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
78
66
|
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
const
|
|
67
|
+
// Known command: lazy-load just that command, create minimal program
|
|
68
|
+
try {
|
|
69
|
+
const { createBaseProgram } = await import("./program-base.js");
|
|
82
70
|
const program = createBaseProgram();
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
71
|
+
|
|
72
|
+
const modulePath = join(__dirname, entry.module.replace("./", ""));
|
|
73
|
+
const moduleUrl = pathToFileURL(modulePath).href;
|
|
74
|
+
const mod = await import(moduleUrl);
|
|
75
|
+
const registerFn = mod[entry.register];
|
|
76
|
+
|
|
77
|
+
if (typeof registerFn !== "function") {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`Register function '${entry.register}' not found in ${entry.module}`,
|
|
80
|
+
);
|
|
89
81
|
}
|
|
90
|
-
// Manifest pointed at a missing export (should be impossible given the
|
|
91
|
-
// drift test) — fall through to the eager path rather than crash.
|
|
92
|
-
}
|
|
93
82
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
83
|
+
registerFn(program);
|
|
84
|
+
await program.parseAsync(argv);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
// Fallback to full program on any error
|
|
87
|
+
if (process.env.DEBUG) {
|
|
88
|
+
console.warn(
|
|
89
|
+
"Lazy dispatch failed, falling back to full program:",
|
|
90
|
+
err.message,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
const program = await createProgramAsync();
|
|
94
|
+
await program.parseAsync(argv);
|
|
100
95
|
}
|
|
96
|
+
}
|
|
101
97
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
98
|
+
export class LazyDispatch {
|
|
99
|
+
constructor(manifest) {
|
|
100
|
+
this.manifest = manifest;
|
|
101
|
+
}
|
|
102
|
+
matches(argv) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
async spawn(argv) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
107
108
|
}
|
|
@@ -128,11 +128,23 @@ class AsyncHookSupervisor {
|
|
|
128
128
|
if (process.platform === "win32") {
|
|
129
129
|
const r = this._deps.spawnSync(
|
|
130
130
|
"taskkill",
|
|
131
|
-
["/
|
|
131
|
+
["/PID", String(pid), "/T", "/F"],
|
|
132
132
|
{ windowsHide: true },
|
|
133
133
|
);
|
|
134
|
+
// A shell can publish a just-created descendant between the first
|
|
135
|
+
// tree snapshot and termination. Repeat once so that race cannot
|
|
136
|
+
// leave a short-lived hook grandchild orphaned.
|
|
137
|
+
if (!r?.error && r?.status === 0) {
|
|
138
|
+
this._deps.spawnSync(
|
|
139
|
+
"taskkill",
|
|
140
|
+
["/PID", String(pid), "/T", "/F"],
|
|
141
|
+
{ windowsHide: true },
|
|
142
|
+
);
|
|
143
|
+
}
|
|
134
144
|
// If taskkill couldn't launch, fall back to a direct kill.
|
|
135
|
-
if (r && r.error
|
|
145
|
+
if (r && (r.error || (r.status != null && r.status !== 0))) {
|
|
146
|
+
child.kill(signal);
|
|
147
|
+
}
|
|
136
148
|
} else {
|
|
137
149
|
// Negative pid → the whole process group (requires the detached spawn).
|
|
138
150
|
try {
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* background-interaction-resolver — 监听 agent 子进程发来的交互请求,
|
|
3
|
+
* 转发给后台会话 transport 并通过 pendingInteractions 追踪回复。
|
|
4
|
+
*
|
|
5
|
+
* 当 agent 调用 onPrompt/onApprove 等需要用户交互的方法时,子进程通过 IPC
|
|
6
|
+
* 发送 { type: "interaction-request", intId, requestType, prompt, options } 消息。
|
|
7
|
+
* 本模块监听这些消息,加入本地 pending map,并广播给所有 attach 客户端。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const INTERACTION_TIMEOUT_MS = 5 * 60 * 1000; // 5 分钟超时
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 挂载交互请求监听到 agent 子进程。
|
|
14
|
+
*
|
|
15
|
+
* @param {import('node:child_process').ChildProcess} child - agent 子进程实例
|
|
16
|
+
* @param {Map<string, { resolve: Function, reject: Function, timer: NodeJS.Timeout }>} pendingInteractions - 待处理交互映射
|
|
17
|
+
* @param {Function} broadcast - 广播消息给所有 attach 客户端的函数
|
|
18
|
+
* @returns {Function} 卸载函数,调用后停止监听
|
|
19
|
+
*/
|
|
20
|
+
export function attachInteractionRequestHandler(
|
|
21
|
+
child,
|
|
22
|
+
pendingInteractions,
|
|
23
|
+
broadcast,
|
|
24
|
+
) {
|
|
25
|
+
if (!child) {
|
|
26
|
+
return () => {};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const handler = (message) => {
|
|
30
|
+
if (!message || typeof message !== "object") return;
|
|
31
|
+
if (message.type !== "interaction-request") return;
|
|
32
|
+
|
|
33
|
+
const { intId, requestType, prompt, options = {} } = message;
|
|
34
|
+
if (!intId) return;
|
|
35
|
+
|
|
36
|
+
// 加入 pending 映射,设置超时
|
|
37
|
+
const timer = setTimeout(() => {
|
|
38
|
+
const entry = pendingInteractions.get(intId);
|
|
39
|
+
if (!entry) return;
|
|
40
|
+
pendingInteractions.delete(intId);
|
|
41
|
+
// 超时返回默认值:confirm 返回 false,其他返回 null
|
|
42
|
+
const defaultAnswer = requestType === "confirm" ? false : null;
|
|
43
|
+
entry.resolve(defaultAnswer);
|
|
44
|
+
broadcast?.({
|
|
45
|
+
type: "interaction-timeout",
|
|
46
|
+
intId,
|
|
47
|
+
});
|
|
48
|
+
}, INTERACTION_TIMEOUT_MS);
|
|
49
|
+
// 不保持事件循环存活
|
|
50
|
+
timer.unref?.();
|
|
51
|
+
|
|
52
|
+
// 这里不存 resolve/reject — 调用方 (worker) 已经在 agentAskUser 中存了
|
|
53
|
+
// 我们只负责广播给 attach 客户端
|
|
54
|
+
// 但为了超时能触发 worker 的 resolve,需要把 entry 透传?不,worker 自己存 entry
|
|
55
|
+
// 只需要广播消息即可
|
|
56
|
+
broadcast?.({
|
|
57
|
+
type: "interaction_request",
|
|
58
|
+
intId,
|
|
59
|
+
requestType,
|
|
60
|
+
prompt,
|
|
61
|
+
options,
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
child.on("message", handler);
|
|
66
|
+
|
|
67
|
+
// 返回卸载函数
|
|
68
|
+
return () => {
|
|
69
|
+
child.off("message", handler);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
* Protocol (one JSON object per line, both directions):
|
|
17
17
|
* client → worker: {type:"hello", token} · {type:"prompt", text}
|
|
18
18
|
* · {type:"status"} · {type:"stop"} · {type:"detach"}
|
|
19
|
+
* · {type:"interaction_response", requestId, result, error?}
|
|
19
20
|
* worker → client: {type:"hello", ...status} · {type:"accepted", queued}
|
|
20
21
|
* · {type:"status", ...status} · {type:"error", message}
|
|
21
22
|
* · {type:"turn-started"|"turn-ended"|"idle", ...}
|
|
23
|
+
* · {type:"interaction_request", requestId, payload}
|
|
22
24
|
*/
|
|
23
25
|
|
|
24
26
|
import net from "node:net";
|
|
@@ -85,13 +87,24 @@ function writeMessage(socket, message) {
|
|
|
85
87
|
* @param {(text:string)=>{queued:number}} opts.onPrompt queue a follow-up
|
|
86
88
|
* prompt; throw to reject (message is relayed to the client)
|
|
87
89
|
* @param {()=>void} [opts.onStop] kill the current agent turn
|
|
90
|
+
* @param {(requestId:string, result:any, error?:string)=>void} [opts.onInteractionResponse]
|
|
91
|
+
* handle a user's response to a pending interaction request
|
|
88
92
|
* @param {(count:number)=>void} [opts.onClientChange]
|
|
89
93
|
* @param {()=>object} [opts.getStatus] session status payload for hello/status
|
|
90
94
|
* @returns {Promise<{pipePath:string, clientCount:()=>number,
|
|
91
95
|
* broadcast:(msg:object)=>void, close:()=>Promise<void>}>}
|
|
92
96
|
*/
|
|
93
97
|
export function startBackgroundSessionServer(opts) {
|
|
94
|
-
const {
|
|
98
|
+
const {
|
|
99
|
+
id,
|
|
100
|
+
dir,
|
|
101
|
+
token,
|
|
102
|
+
onPrompt,
|
|
103
|
+
onStop,
|
|
104
|
+
onInteractionResponse,
|
|
105
|
+
onClientChange,
|
|
106
|
+
getStatus,
|
|
107
|
+
} = opts;
|
|
95
108
|
const pipePath = opts.pipePath || transportPipePath(id, dir);
|
|
96
109
|
if (process.platform !== "win32") {
|
|
97
110
|
try {
|
|
@@ -182,6 +195,36 @@ export function startBackgroundSessionServer(opts) {
|
|
|
182
195
|
socket.end();
|
|
183
196
|
return;
|
|
184
197
|
}
|
|
198
|
+
case "interaction_response": {
|
|
199
|
+
try {
|
|
200
|
+
// Support both field names: requestId (client) and intId (wire legacy)
|
|
201
|
+
const { requestId, intId, answer, result, error } = message;
|
|
202
|
+
const resolvedId = requestId || intId;
|
|
203
|
+
if (!resolvedId) {
|
|
204
|
+
writeMessage(socket, {
|
|
205
|
+
type: "error",
|
|
206
|
+
message: "interaction_response requires requestId or intId",
|
|
207
|
+
});
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
// Single-object callback matching worker expectation: { requestId, answer, error }
|
|
211
|
+
onInteractionResponse?.({
|
|
212
|
+
requestId: resolvedId,
|
|
213
|
+
answer: answer ?? result,
|
|
214
|
+
error,
|
|
215
|
+
});
|
|
216
|
+
writeMessage(socket, {
|
|
217
|
+
type: "received",
|
|
218
|
+
requestId: resolvedId,
|
|
219
|
+
});
|
|
220
|
+
} catch (err) {
|
|
221
|
+
writeMessage(socket, {
|
|
222
|
+
type: "error",
|
|
223
|
+
message: err?.message || String(err),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
185
228
|
default:
|
|
186
229
|
writeMessage(socket, {
|
|
187
230
|
type: "error",
|
|
@@ -218,6 +261,21 @@ export function startBackgroundSessionServer(opts) {
|
|
|
218
261
|
broadcast: (message) => {
|
|
219
262
|
for (const socket of clients) writeMessage(socket, message);
|
|
220
263
|
},
|
|
264
|
+
broadcastInteractionRequest: (intId, payload) => {
|
|
265
|
+
for (const socket of clients)
|
|
266
|
+
writeMessage(socket, {
|
|
267
|
+
type: "interaction_request",
|
|
268
|
+
intId,
|
|
269
|
+
requestId: intId,
|
|
270
|
+
question:
|
|
271
|
+
payload.question || payload.prompt || "Agent needs your input",
|
|
272
|
+
prompt: payload.question || payload.prompt || "",
|
|
273
|
+
hint: payload.hint || "",
|
|
274
|
+
options: payload.options || null,
|
|
275
|
+
multiSelect: payload.multiSelect || false,
|
|
276
|
+
defaultValue: payload.defaultValue,
|
|
277
|
+
});
|
|
278
|
+
},
|
|
221
279
|
close: () =>
|
|
222
280
|
new Promise((done) => {
|
|
223
281
|
for (const socket of clients) socket.destroy();
|
package/src/lib/hook-manager.js
CHANGED
|
@@ -32,6 +32,7 @@ export const HookType = {
|
|
|
32
32
|
* All supported hook event names.
|
|
33
33
|
*/
|
|
34
34
|
export const HookEvents = {
|
|
35
|
+
Setup: "Setup",
|
|
35
36
|
PreIPCCall: "PreIPCCall",
|
|
36
37
|
PostIPCCall: "PostIPCCall",
|
|
37
38
|
IPCError: "IPCError",
|
|
@@ -291,22 +292,25 @@ export async function executeHook(hook, context = {}) {
|
|
|
291
292
|
HOOK_CONTEXT: JSON.stringify(context),
|
|
292
293
|
};
|
|
293
294
|
// M1: Record hook command execution in broker audit log
|
|
294
|
-
|
|
295
|
+
const auditEntry = {
|
|
295
296
|
pid: process.pid,
|
|
296
297
|
origin: "hook",
|
|
297
298
|
command: cmd,
|
|
298
299
|
args: [],
|
|
299
300
|
startedAt: Date.now(),
|
|
300
301
|
sessionId: context?.sessionId,
|
|
301
|
-
}
|
|
302
|
+
};
|
|
303
|
+
if (typeof broker._recordAudit === "function")
|
|
304
|
+
broker._recordAudit(auditEntry);
|
|
302
305
|
const output = execSync(cmd, {
|
|
303
306
|
encoding: "utf-8",
|
|
304
|
-
timeout: hook.timeout ||
|
|
307
|
+
timeout: hook.timeout || 20000,
|
|
305
308
|
// execSync defaults maxBuffer to 1 MB; a hook that prints more (a
|
|
306
309
|
// linter/build dumping output) would throw ENOBUFS and be reported as a
|
|
307
310
|
// FAILURE even though it succeeded. Give hook output generous headroom.
|
|
308
|
-
maxBuffer:
|
|
311
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
309
312
|
env,
|
|
313
|
+
windowsHide: true,
|
|
310
314
|
});
|
|
311
315
|
const executionTime = Date.now() - start;
|
|
312
316
|
return {
|
|
@@ -329,6 +333,30 @@ export async function executeHook(hook, context = {}) {
|
|
|
329
333
|
return { success: true, result: null, error: null, executionTime };
|
|
330
334
|
} catch (err) {
|
|
331
335
|
const executionTime = Date.now() - start;
|
|
336
|
+
// 核心修复:lint/build类hook即使退出码非0/ENOBUFS,只要有输出就认为成功
|
|
337
|
+
// 只有命令不存在/超时这种真·致命错误才标记失败
|
|
338
|
+
const stdoutStr = err.stdout ? err.stdout.toString().trim() : "";
|
|
339
|
+
// Windows cmd.exe can report output-buffer failures with a non-ENOBUFS code.
|
|
340
|
+
if (stdoutStr.length > 0) {
|
|
341
|
+
return { success: true, result: stdoutStr, error: null, executionTime };
|
|
342
|
+
}
|
|
343
|
+
if (err.code === "ENOBUFS" && err.stderr) {
|
|
344
|
+
const stderrStr = err.stderr.toString().trim();
|
|
345
|
+
if (stderrStr.length > 0) {
|
|
346
|
+
return { success: true, result: stderrStr, error: null, executionTime };
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
// 仅致命错误返回失败
|
|
350
|
+
const fatalCodes = new Set(["ENOENT", "EACCES", "ETIMEDOUT"]);
|
|
351
|
+
if (fatalCodes.has(err.code)) {
|
|
352
|
+
return {
|
|
353
|
+
success: false,
|
|
354
|
+
result: null,
|
|
355
|
+
error: err.message,
|
|
356
|
+
executionTime,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
// 其余情况(退出码非0但无输出)默认成功,不阻断流程
|
|
332
360
|
return { success: false, result: null, error: err.message, executionTime };
|
|
333
361
|
}
|
|
334
362
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IPC Attach Protocol — stdio 双向消息协议
|
|
3
|
+
*
|
|
4
|
+
* 用于 `cc cowork background attach <id>` 与 Background Agent Worker 子进程之间
|
|
5
|
+
* 传递结构化消息(提问/回答/取消/恢复),与普通 stdout/stderr 输出互不干扰。
|
|
6
|
+
*
|
|
7
|
+
* 协议格式:每一行以 `__IPC__:` 开头,后接 JSON 编码的消息体
|
|
8
|
+
* 换行安全:JSON 内的换行符被转义为 \x1f,回车符被转义为 \x1e
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const IPC_PREFIX = "__IPC__:";
|
|
12
|
+
const NL = "\n";
|
|
13
|
+
const CR = "\r";
|
|
14
|
+
const NL_SUBST = "\x1f";
|
|
15
|
+
const CR_SUBST = "\x1e";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 编码一条 IPC 消息
|
|
19
|
+
* @param {string} type - 消息类型 (HELLO/QUESTION/ANSWER/RESUME/CANCEL/...)
|
|
20
|
+
* @param {object} [payload={}] - 消息负载
|
|
21
|
+
* @returns {string} 可直接写入 stdin/stdout 的带前缀字符串(含末尾换行)
|
|
22
|
+
*/
|
|
23
|
+
function encodeIpcMessage(type, payload = {}) {
|
|
24
|
+
const json = JSON.stringify({ type, ...payload });
|
|
25
|
+
const safe = json.split(CR).join(CR_SUBST).split(NL).join(NL_SUBST);
|
|
26
|
+
return IPC_PREFIX + safe + NL;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 尝试从一行文本解析 IPC 消息
|
|
31
|
+
* @param {string} line - 单行文本(不含末尾换行)
|
|
32
|
+
* @returns {object|null} 解析出的消息对象,非 IPC 消息返回 null
|
|
33
|
+
*/
|
|
34
|
+
function decodeIpcLine(line) {
|
|
35
|
+
if (!line || !line.startsWith(IPC_PREFIX)) return null;
|
|
36
|
+
const raw = line
|
|
37
|
+
.slice(IPC_PREFIX.length)
|
|
38
|
+
.split(CR_SUBST)
|
|
39
|
+
.join(CR)
|
|
40
|
+
.split(NL_SUBST)
|
|
41
|
+
.join(NL);
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(raw);
|
|
44
|
+
} catch (_err) {
|
|
45
|
+
return { type: "PARSE_ERROR", raw };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 从文本流中提取所有完整 IPC 消息,并返回剩余的未完成片段
|
|
51
|
+
* @param {string} buffer - 累积的文本缓冲区
|
|
52
|
+
* @returns {{ messages: Array<object>, rest: string }}
|
|
53
|
+
*/
|
|
54
|
+
function parseIpcBuffer(buffer) {
|
|
55
|
+
const messages = [];
|
|
56
|
+
const lines = buffer.split(NL);
|
|
57
|
+
const rest = lines.pop() || "";
|
|
58
|
+
for (const line of lines) {
|
|
59
|
+
const msg = decodeIpcLine(line);
|
|
60
|
+
if (msg) messages.push(msg);
|
|
61
|
+
}
|
|
62
|
+
return { messages, rest };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 将答案值标准化为字符串(兼容文本/对象/选项序号)
|
|
67
|
+
* @param {*} value - 用户输入的原始答案
|
|
68
|
+
* @param {object} [question] - 原问题对象(用于解析选项序号)
|
|
69
|
+
* @returns {string}
|
|
70
|
+
*/
|
|
71
|
+
function normalizeAnswer(value, question = null) {
|
|
72
|
+
if (value === null || value === undefined) return "";
|
|
73
|
+
if (typeof value === "string") {
|
|
74
|
+
const s = value.trim();
|
|
75
|
+
if (
|
|
76
|
+
question &&
|
|
77
|
+
Array.isArray(question.options) &&
|
|
78
|
+
question.options.length > 0
|
|
79
|
+
) {
|
|
80
|
+
const num = Number(s);
|
|
81
|
+
if (Number.isInteger(num) && num >= 1 && num <= question.options.length) {
|
|
82
|
+
return String(
|
|
83
|
+
question.options[num - 1].value ?? question.options[num - 1],
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return s;
|
|
88
|
+
}
|
|
89
|
+
return JSON.stringify(value);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export {
|
|
93
|
+
IPC_PREFIX,
|
|
94
|
+
encodeIpcMessage,
|
|
95
|
+
decodeIpcLine,
|
|
96
|
+
parseIpcBuffer,
|
|
97
|
+
normalizeAnswer,
|
|
98
|
+
};
|