chainlesschain 0.162.174 → 0.162.176
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 +10 -10
- package/src/assets/web-panel/assets/{AIOps-Dcl-X1Hw.js → AIOps-BDLu5Elz.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-ClMh9HzT.js → ActionButton-DH5us-CK.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DPj0rSQ5.js → Analytics-BZ0u8IFG.js} +3 -3
- package/src/assets/web-panel/assets/AppLayout-Duu8xR14.js +9 -0
- package/src/assets/web-panel/assets/{Artifacts-L8781rE8.js → Artifacts-Br2YBbh_.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CffB6WIP.js → Audit-C3C6a482.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BkLhayyY.js → BackgroundAgents-CzHvebcj.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BQnwFI78.js → Backup-DZNHYDFd.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-xuUGHQch.js → BaseInput-VRiC4fIx.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-feQXwWrg.js → Chat-Cm08WWAD.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-CGHYrugQ.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-DVaIiUGW.js → Checkbox-DtByk7d7.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-D2kEnzeU.js → Codegen-CphXXOfD.js} +1 -1
- package/src/assets/web-panel/assets/{Col-azDoyusS.js → Col-Hz86TnLR.js} +1 -1
- package/src/assets/web-panel/assets/{Community-OZdnPWM5.js → Community-HP03ltpD.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-VDMvBN-C.js → Compact-B_N1mqQz.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CPJ_zgQ1.js → Compliance-CVztRpi8.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-iRBwcsOA.js → Cowork-wUVOyZih.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-DrxrspUz.js → Cron-DW5TLJKw.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-D-rkAZXF.js → Crosschain-CrAFGhWH.js} +1 -1
- package/src/assets/web-panel/assets/{DID-5Pp1Xnmr.js → DID-pA-oD8ke.js} +2 -2
- package/src/assets/web-panel/assets/Dashboard-CXrd5gAw.js +3 -0
- package/src/assets/web-panel/assets/{Dropdown-BWj_E0Ie.js → Dropdown-EweJcsek.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BT-wgSEh.js → EmailListRenderer-C9xVLPG4.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-1PzH23pa.js → FamilyGuardDashboard-CDcEEqlu.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BxMIXGC6.js → Federation-DtZda9A_.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CyJobBln.js → FormItemContext-CiYdcVz3.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-YkjFuQTN.js → GenericCardRenderer-DA13uwA0.js} +1 -1
- package/src/assets/web-panel/assets/{Git-C2a98Wp_.js → Git-DzRhZD1O.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DKL3Fl84.js → Governance-D5RMgOSb.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BJ2cQC_3.js → Inference-BgrPfSNk.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DBAsOngt.js → KnowledgeGraph-DzjnD571.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-COt8g9LO.js → Logs-BhWzVDtN.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-3Lfht1Fd.js → MarkdownRenderer-BDape9cx.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-C9Zk9Pb2.js → Marketplace-DJtL5GV7.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DDWDFWPO.js → McpTools-CZcQygI7.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BRmVye_o.js → Memory-DUWSDUUu.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CppBbWpD.js → MobileBridge-BTwq2WKY.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-NZvvfDME.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-CcWpeGa6.js → Mtc-BiGugEQm.js} +6 -6
- package/src/assets/web-panel/assets/{MtcAudit-BcllEq0K.js → MtcAudit-DY7a6gUe.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BFD1CarL.js → Multisig-BQbDu_w7.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-QNXXYvjz.js → NLProgramming-CM2wXTLv.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-07YwgQVy.js → Notes-DI6gGs1v.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-bOccEInE.js → NotificationSettings-BsZOLWAB.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DlRi29WL.js → OrderTableRenderer-C48mu09U.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CBaezzEr.js → Organization-Cds0_tXr.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Bl5NohFO.js → Overflow-WunYMD87.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CLMal9Aw.js → P2P-Bo6j4DDv.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CGO0NITk.js → PdhVaultBrowser-Bh2XPD5f.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CPSw48E2.js → Permissions-EMvMMC8N.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-CDM5n134.js → PersonalDataHub-AX3ypUDV.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-BdsqG7WV.js → Pipeline-BOx8HOgL.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B6L4E-M7.js → Privacy-tBeTVQVM.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DXPyZKRs.js → ProjectInit-CVYg1W4M.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BrCC3xYT.js → ProjectSettings-Dvt5I7y1.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BYmuHC2q.js → Projects-Cc7FC9-e.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-CbCe2eUl.js → Providers-Ct8xqY-E.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DkukgCrR.js → QrScannerModal-Cni8Ooja.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-D-htOrV8.js → QuickAsk-BJVLKdxr.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Bm7SIfzu.js → Recommend-DPG8Rbbm.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-C9rP-iMc.js → RemoteSession-DsdR7dCt.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-kGlUgbsl.js → Reputation-Csg1YM-b.js} +1 -1
- package/src/assets/web-panel/assets/{Row-PBupbbUA.js → Row-D9DoFoEf.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-njlwKUGK.js → RssFeed-BsvKrXMS.js} +2 -2
- package/src/assets/web-panel/assets/{Search-DLdEmgBw.js → Search-DFUStfgQ.js} +1 -1
- package/src/assets/web-panel/assets/{Security-SXGPSHdu.js → Security-ILg1zxdK.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CuFGnNsb.js → Services-Dd41PCaY.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CtUC0mDa.js → Skeleton-Bzo1cN80.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-P1qgOVFn.js → Skills-BDHh17P0.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CsppE8YV.js → Sla-jl7UTiRY.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Cq1oG56m.js → SpeechSettings-BePa-RF6.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DdKW6V-C.js → SyncSettings-DiqqDKGZ.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BCc9san5.js → Tasks-DYQ_6lxj.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CcHC1dMA.js → Templates-JiDeI06L.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CA4PqU22.js → Tenant-hhgI6zwS.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-CjTZPa37.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-DHWTSvOy.js → TimelineRenderer-B8uB5Llk.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Ddz-P_yh.js → Tokens-C3b_6r2z.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-ePmrmLZ1.js → Trigger-tIP7HKVe.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DmuK1CCE.js → Trust-vjoc11vJ.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CqqBuRrT.js → UkeySign-DUPBnGuH.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BGlR3uWM.js → VideoEditing-CBvhUY5T.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Ba_Qx6Ga.js → Wallet-DUaQ0uA5.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-29neXKt2.js → WebAuthn-DllSivjE.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-lD0lR0UQ.js → WorkflowEditor-xc8D3uO6.js} +1 -1
- package/src/assets/web-panel/assets/{chat-B3stH01u.js → chat-BVicU7oA.js} +1 -1
- package/src/assets/web-panel/assets/{colors-Czly56MN.js → colors-DJzLmhLm.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-C0TkbkAJ.js → compact-item-BvYRfThE.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BJmpSlf1.js → createContext-DGXxCBKR.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BT46Y_QI.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D1q-zw7u.js → hasIn-SBDJB1y4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DV-twjNO.js → index-1SdDS6lR.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-kTvMq7.js → index-9gdI7uUW.js} +1 -1
- package/src/assets/web-panel/assets/index-B7nuIywP.js +1 -0
- package/src/assets/web-panel/assets/{index-Bm_-RKal.js → index-BJZf9DhV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQftlZn-.js → index-BO1itZaY.js} +3 -3
- package/src/assets/web-panel/assets/{index-Dw3L_smW.js → index-BTrBGBJs.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7sFKQ53.js → index-BYqz4Wrr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlvsSuBC.js → index-Bf-ctERC.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChESIe5r.js → index-CKyEivf8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaqEHaCg.js → index-CdGY9P8a.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZeoKL6t.js → index-Cf-O_g_8.js} +1 -1
- package/src/assets/web-panel/assets/{index-XWV8JWMc.js → index-CloCgBUR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpMIdPJ0.js → index-CoJAO1Lm.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgS8XUBU.js → index-Crk5NTb0.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmUta2lw.js → index-Cs2rmLFt.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dpz_7sf-.js → index-CtwqO5qo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRcQsPez.js → index-D7HimK0M.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEt2-3x5.js → index-DCdRAgjy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHvPlzWJ.js → index-DCqRS6da.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDHXx65P.js → index-DHVLJ8q0.js} +1 -1
- package/src/assets/web-panel/assets/{index-K4YaPDOn.js → index-DKrvvWm4.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1pOqU7D.js → index-DMarmfrv.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAhrn9EJ.js → index-DRfiXB_p.js} +1 -1
- package/src/assets/web-panel/assets/{index-cPjWjvmW.js → index-Dm_77jgR.js} +1 -1
- package/src/assets/web-panel/assets/{index-C27TnOoT.js → index-DnjPdvR6.js} +1 -1
- package/src/assets/web-panel/assets/{index-upY9rkGZ.js → index-DonCnfMr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbvNJUwu.js → index-DvUTDYXX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BVwJ3jht.js → index-FxZzRyE1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIF6XHIi.js → index-MjC4G09d.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8KqsomG.js → index-VMfwIH5G.js} +1 -1
- package/src/assets/web-panel/assets/{index-8GKykbS4.js → index-YJkzy8ZF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpGs96FC.js → index-d5BVd-cL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DO8xOwxi.js → index-e4fXH_WO.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cu_4HaUS.js → index-hxTODbM1.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cf7Gr3NG.js → index-lpaGoTH3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBqAm8es.js → index-wcCL-miV.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZDUhX41Z.js → index-xfluRkCT.js} +1 -1
- package/src/assets/web-panel/assets/index-ycwAfC-i.js +1 -0
- package/src/assets/web-panel/assets/{index-z8ATo2aQ.js → index-z1ZylsLq.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-QWEXi6-t.js → initDefaultProps-C1zO1KnY.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BfrQwvV1.js → motion-CWLtEGmC.js} +1 -1
- package/src/assets/web-panel/assets/{move-Dn7x0H9t.js → move-DzD_C3Vm.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-F61D_TgE.js → mtc-parser-D880PYJl.js} +1 -1
- package/src/assets/web-panel/assets/{omit-4SQZ39PF.js → omit-CFR_z2ov.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-C7DTe126.js → pickAttrs-srIhgrSC.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-40NeyzDK.js → placementArrow-C1rXpibP.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BiUJ6qWs.js → responsiveObserve-C30gRcSS.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CacJTM3f.js → slide-CvtKiMfV.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-K812HB-k.js → statusUtils-DNHO7ITG.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CKeHA2eM.js → styleChecker-Dt_Sl-g4.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CKl4FqXF.js → useFlexGapSupport-Cjev42Gh.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DPoiJjSZ.js → useFs-Baxglj2V.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-aHwBspmt.js → usePersonalDataHub-B4NkcLaP.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DrA-GuCT.js → vnode-mIRkdT7o.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-G3LMswgy.js → zoom-HzI5DlH_.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/auth/npm-auth.js +30 -5
- package/src/commands/agenda.js +64 -2
- package/src/commands/agent.js +45 -3
- package/src/commands/background-session.js +103 -0
- package/src/commands/config.js +70 -5
- package/src/commands/context.js +36 -2
- package/src/commands/hub.js +19 -1
- package/src/commands/memory.js +21 -6
- package/src/commands/permissions.js +57 -1
- package/src/commands/plugin.js +2 -0
- package/src/commands/review.js +23 -11
- package/src/commands/routine.js +31 -8
- package/src/commands/session.js +11 -3
- package/src/commands/team.js +20 -7
- package/src/commands/update.js +65 -10
- package/src/esm-bridge.js +3 -0
- package/src/gateways/terminal/PtyManager.js +8 -1
- package/src/gateways/ws/message-dispatcher.js +3 -0
- package/src/gateways/ws/session-protocol.js +26 -0
- package/src/gateways/ws/ws-agent-handler.js +107 -69
- package/src/gateways/ws/ws-server.js +92 -4
- package/src/harness/jsonl-session-store.js +13 -6
- package/src/harness/mcp-client.js +200 -1
- package/src/index.js +123 -55
- package/src/lazy-dispatch.js +86 -85
- package/src/lib/__tests__/personal-data-hub-aichat-wizard.test.js +15 -0
- package/src/lib/agent-coordinator.js +4 -0
- package/src/lib/agent-ipc-bus.js +32 -2
- package/src/lib/agent-sandbox.js +16 -2
- package/src/lib/agent-schedule-store.js +55 -0
- package/src/lib/agent-tool-admission.js +104 -0
- package/src/lib/api-key-helper.js +10 -2
- package/src/lib/async-hook-supervisor.cjs +26 -4
- package/src/lib/background-interaction-resolver.js +71 -0
- package/src/lib/background-session-transport.js +59 -1
- package/src/lib/changelog.js +19 -11
- package/src/lib/channels/channel-manager.js +6 -0
- package/src/lib/channels/telegram-channel.js +11 -1
- package/src/lib/channels/webhook-channel.js +15 -3
- package/src/lib/checkpoint-store.js +10 -2
- package/src/lib/cloud/bundle.js +12 -2
- package/src/lib/code-review.js +32 -8
- package/src/lib/computer-use/control-backend.js +18 -3
- package/src/lib/context-breakdown.js +46 -0
- package/src/lib/context-source-ledger.js +43 -0
- package/src/lib/crash-reporter.js +6 -0
- package/src/lib/diff-review-follow-up.js +154 -0
- package/src/lib/downloader.js +17 -3
- package/src/lib/ensure-utf8.js +11 -3
- package/src/lib/event-runtime-producer.js +58 -0
- package/src/lib/event-runtime-store.js +354 -0
- package/src/lib/event-runtime-worker.js +109 -0
- package/src/lib/execution-backend.js +72 -21
- package/src/lib/git-integration.js +19 -4
- package/src/lib/hook-manager.js +34 -15
- package/src/lib/hook-runner.cjs +48 -3
- package/src/lib/hooks-v2-producers.js +15 -0
- package/src/lib/hooks-v2-runtime.js +70 -21
- package/src/lib/host-adb-bridge.js +111 -21
- package/src/lib/ide-context.js +128 -1
- package/src/lib/interaction-adapter.js +39 -0
- package/src/lib/ipc-attach-protocol.js +98 -0
- package/src/lib/json-schema-validate.js +190 -36
- package/src/lib/lan-pairing-preflight.js +13 -2
- package/src/lib/lsp/__tests__/lsp-server-registry.test.js +18 -0
- package/src/lib/lsp/lsp-client.js +18 -1
- package/src/lib/lsp/lsp-manager.js +4 -0
- package/src/lib/lsp/lsp-server-registry.js +11 -0
- package/src/lib/mcp-oauth.js +8 -2
- package/src/lib/npm-invocation.js +29 -0
- package/src/lib/packer/pkg-runner.js +13 -2
- package/src/lib/packer/precheck.js +33 -16
- package/src/lib/packer/web-panel-builder.js +16 -2
- package/src/lib/permission-rules.cjs +5 -1
- package/src/lib/personal-data-hub-aichat-wizard.js +22 -6
- package/src/lib/personal-data-hub-wiring.js +27 -3
- package/src/lib/plan-mode.js +204 -11
- package/src/lib/plugin-monitor-supervisor.js +39 -4
- package/src/lib/plugin-runtime/bin.js +45 -0
- package/src/lib/plugin-runtime/hooks.js +14 -1
- package/src/lib/plugin-runtime/install.js +2 -1
- package/src/lib/plugin-runtime/lsp.js +3 -0
- package/src/lib/plugin-runtime/mcp.js +8 -1
- package/src/lib/plugin-runtime/monitors.js +4 -0
- package/src/lib/plugin-runtime/plugin-options.js +74 -7
- package/src/lib/plugin-runtime/signature.js +45 -0
- package/src/lib/pr-create.js +21 -8
- package/src/lib/pr-link-ledger.js +15 -3
- package/src/lib/process-execution-broker/credential-agent.js +295 -0
- package/src/lib/process-execution-broker/index.js +440 -14
- package/src/lib/process-execution-broker/patch-child-process.js +2 -3
- package/src/lib/process-execution-broker/platform-sandbox.js +351 -0
- package/src/lib/process-manager.js +18 -3
- package/src/lib/provenance-api.js +6 -0
- package/src/lib/proxy-bootstrap.js +19 -0
- package/src/lib/publish-workspace.js +14 -6
- package/src/lib/repl-rewind.js +9 -4
- package/src/lib/secret-store.js +159 -0
- package/src/lib/service-manager.js +64 -29
- package/src/lib/session-hooks.js +328 -473
- package/src/lib/session-telemetry-middleware.js +6 -0
- package/src/lib/settings-hook-events.cjs +61 -1
- package/src/lib/settings-hooks.cjs +4 -0
- package/src/lib/side-effect-ledger.js +22 -0
- package/src/lib/sub-agent-context.js +5 -0
- package/src/lib/sub-agent-profiles.js +4 -0
- package/src/lib/trace-api.js +6 -0
- package/src/lib/turn-context.js +14 -8
- package/src/lib/unattended-action-policy.js +83 -0
- package/src/lib/update-notice.js +9 -45
- package/src/lib/with-file-lock.js +7 -0
- package/src/lib/ws-server.js +1 -0
- package/src/repl/agent-repl.js +71 -13
- package/src/repl/clipboard-copy.js +8 -2
- package/src/repl/pr-comments.js +30 -7
- package/src/runtime/agent-core.js +439 -87
- package/src/runtime/agent-runtime.js +1 -0
- package/src/runtime/coding-agent-contract-shared.cjs +52 -0
- package/src/runtime/coding-agent-policy.cjs +20 -0
- package/src/runtime/diagnostics.js +73 -8
- package/src/runtime/headless-runner.js +63 -0
- package/src/runtime/headless-stream.js +269 -17
- package/src/runtime/mcp-config.js +16 -1
- 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/MobileProjects-C4GKn1dH.js +0 -1
- package/src/assets/web-panel/assets/Terminal-Fj7ea0In.js +0 -3
- 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
|
@@ -21,6 +21,7 @@ import EventEmitter from "events";
|
|
|
21
21
|
import { randomUUID } from "crypto";
|
|
22
22
|
import { createRequire } from "module";
|
|
23
23
|
import { RingBuffer } from "./RingBuffer.js";
|
|
24
|
+
import { executionBroker } from "../../lib/process-execution-broker/index.js";
|
|
24
25
|
|
|
25
26
|
const require = createRequire(import.meta.url);
|
|
26
27
|
|
|
@@ -66,6 +67,7 @@ export class PtyManager extends EventEmitter {
|
|
|
66
67
|
this.config = { ...DEFAULT_CONFIG, ...(opts.config || {}) };
|
|
67
68
|
this._deps = {
|
|
68
69
|
loadNodePty: opts._deps?.loadNodePty || (() => require("node-pty")),
|
|
70
|
+
spawnPty: opts._deps?.spawnPty || null,
|
|
69
71
|
now: opts._deps?.now || (() => Date.now()),
|
|
70
72
|
};
|
|
71
73
|
this._sessions = new Map();
|
|
@@ -110,12 +112,17 @@ export class PtyManager extends EventEmitter {
|
|
|
110
112
|
req.env && typeof req.env === "object" && !Array.isArray(req.env)
|
|
111
113
|
? req.env
|
|
112
114
|
: {};
|
|
113
|
-
const
|
|
115
|
+
const spawnPty =
|
|
116
|
+
this._deps.spawnPty || executionBroker.spawnPty.bind(executionBroker);
|
|
117
|
+
const proc = spawnPty(pty, cmd, [], {
|
|
114
118
|
name: "xterm-256color",
|
|
115
119
|
cols,
|
|
116
120
|
rows,
|
|
117
121
|
cwd,
|
|
118
122
|
env: { ...process.env, ...extraEnv },
|
|
123
|
+
origin: "terminal:pty",
|
|
124
|
+
policy: "allow",
|
|
125
|
+
scope: "terminal",
|
|
119
126
|
});
|
|
120
127
|
|
|
121
128
|
const sessionId = randomUUID();
|
|
@@ -110,6 +110,9 @@ export function createWsMessageDispatcher(server) {
|
|
|
110
110
|
"session-close": () => server._handleSessionClose(id, ws, message),
|
|
111
111
|
"session-interrupt": () =>
|
|
112
112
|
server._handleSessionInterrupt(id, ws, message),
|
|
113
|
+
"permission-rules-get": () => server._handlePermissionRulesGet(id, ws),
|
|
114
|
+
"permission-rules-set": () =>
|
|
115
|
+
server._handlePermissionRulesSet(id, ws, message),
|
|
113
116
|
"slash-command": () => server._handleSlashCommand(id, ws, message),
|
|
114
117
|
"session-answer": () => server._handleSessionAnswer(id, ws, message),
|
|
115
118
|
"remote-session-create": () =>
|
|
@@ -96,6 +96,27 @@ async function ensureSessionHandler(server, ws, session) {
|
|
|
96
96
|
envelopeBus: server.envelopeBus || null,
|
|
97
97
|
});
|
|
98
98
|
|
|
99
|
+
// Route MCP elicitation through the authenticated WS question channel. The
|
|
100
|
+
// MCP client may be shared by the runtime, so this is deliberately only a
|
|
101
|
+
// transport hook; the MCP request/answer ids remain inside the pending
|
|
102
|
+
// interaction entry and unknown answers are ignored by the adapter.
|
|
103
|
+
if (
|
|
104
|
+
session.mcpClient &&
|
|
105
|
+
typeof session.mcpClient.setElicitationHandler === "function"
|
|
106
|
+
) {
|
|
107
|
+
session.mcpClient.setElicitationHandler(
|
|
108
|
+
async (request) => {
|
|
109
|
+
const answer = await session.interaction.askElicitation(request);
|
|
110
|
+
if (answer == null) return { action: "cancel" };
|
|
111
|
+
if (typeof answer === "object") {
|
|
112
|
+
return { action: "accept", content: answer };
|
|
113
|
+
}
|
|
114
|
+
return { action: "accept", content: { value: answer } };
|
|
115
|
+
},
|
|
116
|
+
{ sessionId: session.id, timeoutMs: 180000 },
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
99
120
|
let handler;
|
|
100
121
|
if (session.type === "chat") {
|
|
101
122
|
const { WSChatHandler } = await import("../../lib/ws-chat-handler.js");
|
|
@@ -444,6 +465,11 @@ export function handleSessionList(server, id, ws) {
|
|
|
444
465
|
export function handleSessionClose(server, id, ws, message) {
|
|
445
466
|
const { sessionId } = message;
|
|
446
467
|
|
|
468
|
+
const closingSession = server.sessionManager?.getSession?.(sessionId);
|
|
469
|
+
if (closingSession?.mcpClient?.clearElicitationHandler) {
|
|
470
|
+
closingSession.mcpClient.clearElicitationHandler(sessionId);
|
|
471
|
+
}
|
|
472
|
+
|
|
447
473
|
const handler = server.sessionHandlers.get(sessionId);
|
|
448
474
|
if (handler && handler.destroy) {
|
|
449
475
|
handler.destroy();
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import { agentLoop, formatToolArgs } from "../../runtime/agent-core.js";
|
|
15
15
|
import { classifyToolSideEffect } from "../../lib/side-effect-ledger.js";
|
|
16
|
+
import { DiffReviewFollowUpTracker } from "../../lib/diff-review-follow-up.js";
|
|
16
17
|
import {
|
|
17
18
|
loadSideEffectLedger,
|
|
18
19
|
persistSideEffectLedger,
|
|
@@ -88,6 +89,8 @@ export class WSAgentHandler {
|
|
|
88
89
|
const abortController = new AbortController();
|
|
89
90
|
this._abortController = abortController;
|
|
90
91
|
this._activeRequestId = requestId || null;
|
|
92
|
+
let sideEffectLedger = null;
|
|
93
|
+
let diffReviewFollowUps = null;
|
|
91
94
|
|
|
92
95
|
try {
|
|
93
96
|
const { session } = this;
|
|
@@ -159,88 +162,123 @@ export class WSAgentHandler {
|
|
|
159
162
|
// persisted BEFORE it settles) and commit/fail on its result, so a bridge
|
|
160
163
|
// worker killed mid-flight is surfaced for verification on resume (see
|
|
161
164
|
// handleSessionResume) instead of being blindly replayed.
|
|
162
|
-
|
|
165
|
+
sideEffectLedger = loadSideEffectLedger(session.id);
|
|
166
|
+
diffReviewFollowUps = new DiffReviewFollowUpTracker(sideEffectLedger);
|
|
163
167
|
let currentSideEffectOpId = null;
|
|
164
168
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
idempotencyKey: operationIdempotencyKey({
|
|
169
|
+
const runAgentTurn = async () => {
|
|
170
|
+
for await (const event of agentLoop(session.messages, loopOptions)) {
|
|
171
|
+
switch (event.type) {
|
|
172
|
+
case "slot-filling":
|
|
173
|
+
this.interaction.emit("slot-filling", {
|
|
174
|
+
requestId,
|
|
175
|
+
slot: event.slot,
|
|
176
|
+
question: event.question,
|
|
177
|
+
});
|
|
178
|
+
break;
|
|
179
|
+
|
|
180
|
+
case "tool-executing":
|
|
181
|
+
this.interaction.emit("tool-executing", {
|
|
182
|
+
requestId,
|
|
183
|
+
tool: event.tool,
|
|
184
|
+
args: event.args,
|
|
185
|
+
display: formatToolArgs(event.tool, event.args),
|
|
186
|
+
});
|
|
187
|
+
currentSideEffectOpId = null;
|
|
188
|
+
{
|
|
189
|
+
const se = classifyToolSideEffect(event.tool, event.args);
|
|
190
|
+
if (se) {
|
|
191
|
+
const opId = `ws:${session.id}:${Date.now()}:${this._sideEffectSeq++}`;
|
|
192
|
+
currentSideEffectOpId = opId;
|
|
193
|
+
sideEffectLedger
|
|
194
|
+
.prepare(opId, {
|
|
195
|
+
kind: se.kind,
|
|
196
|
+
key: se.key,
|
|
197
|
+
meta: {
|
|
195
198
|
tool: event.tool,
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
199
|
+
idempotencyKey: operationIdempotencyKey({
|
|
200
|
+
tool: event.tool,
|
|
201
|
+
args: event.args,
|
|
202
|
+
}),
|
|
203
|
+
},
|
|
204
|
+
})
|
|
205
|
+
.start(opId);
|
|
206
|
+
persistSideEffectLedger(session.id, sideEffectLedger);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
|
|
211
|
+
case "tool-result":
|
|
212
|
+
this.interaction.emit("tool-result", {
|
|
213
|
+
requestId,
|
|
214
|
+
tool: event.tool,
|
|
215
|
+
result: event.result,
|
|
216
|
+
error: event.error,
|
|
217
|
+
});
|
|
218
|
+
if (currentSideEffectOpId) {
|
|
219
|
+
const err = event.error || event.result?.error || null;
|
|
220
|
+
if (event.result?._diffReviewAudit) {
|
|
221
|
+
diffReviewFollowUps.observe(
|
|
222
|
+
sideEffectLedger,
|
|
223
|
+
currentSideEffectOpId,
|
|
224
|
+
event.result._diffReviewAudit,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
if (err)
|
|
228
|
+
sideEffectLedger.fail(
|
|
229
|
+
currentSideEffectOpId,
|
|
230
|
+
String(err).slice(0, 200),
|
|
231
|
+
);
|
|
232
|
+
else sideEffectLedger.commit(currentSideEffectOpId);
|
|
201
233
|
persistSideEffectLedger(session.id, sideEffectLedger);
|
|
234
|
+
currentSideEffectOpId = null;
|
|
202
235
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const err = event.error || event.result?.error || null;
|
|
215
|
-
if (err)
|
|
216
|
-
sideEffectLedger.fail(
|
|
217
|
-
currentSideEffectOpId,
|
|
218
|
-
String(err).slice(0, 200),
|
|
219
|
-
);
|
|
220
|
-
else sideEffectLedger.commit(currentSideEffectOpId);
|
|
221
|
-
persistSideEffectLedger(session.id, sideEffectLedger);
|
|
222
|
-
currentSideEffectOpId = null;
|
|
223
|
-
}
|
|
224
|
-
break;
|
|
225
|
-
|
|
226
|
-
case "response-complete":
|
|
227
|
-
if (event.content) {
|
|
228
|
-
session.messages.push({
|
|
229
|
-
role: "assistant",
|
|
236
|
+
break;
|
|
237
|
+
|
|
238
|
+
case "response-complete":
|
|
239
|
+
if (event.content) {
|
|
240
|
+
session.messages.push({
|
|
241
|
+
role: "assistant",
|
|
242
|
+
content: event.content,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
this.interaction.emit("response-complete", {
|
|
246
|
+
requestId,
|
|
230
247
|
content: event.content,
|
|
231
248
|
});
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
requestId,
|
|
235
|
-
content: event.content,
|
|
236
|
-
});
|
|
237
|
-
break;
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
238
251
|
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
if (session.mcpClient?.withElicitationContext) {
|
|
255
|
+
await session.mcpClient.withElicitationContext(
|
|
256
|
+
session.id,
|
|
257
|
+
runAgentTurn,
|
|
258
|
+
);
|
|
259
|
+
} else {
|
|
260
|
+
await runAgentTurn();
|
|
261
|
+
}
|
|
262
|
+
if (
|
|
263
|
+
diffReviewFollowUps.complete(sideEffectLedger, {
|
|
264
|
+
status: "completed-without-reproposal",
|
|
265
|
+
}).length > 0
|
|
266
|
+
) {
|
|
267
|
+
persistSideEffectLedger(session.id, sideEffectLedger);
|
|
239
268
|
}
|
|
240
269
|
|
|
241
270
|
// Update last activity
|
|
242
271
|
session.lastActivity = new Date().toISOString();
|
|
243
272
|
} catch (err) {
|
|
273
|
+
if (
|
|
274
|
+
sideEffectLedger &&
|
|
275
|
+
diffReviewFollowUps?.complete(sideEffectLedger, {
|
|
276
|
+
status: "interrupted",
|
|
277
|
+
reason: isAbortError(err) ? "aborted" : err.message,
|
|
278
|
+
}).length > 0
|
|
279
|
+
) {
|
|
280
|
+
persistSideEffectLedger(this.session.id, sideEffectLedger);
|
|
281
|
+
}
|
|
244
282
|
if (isAbortError(err) || abortController.signal.aborted) {
|
|
245
283
|
return;
|
|
246
284
|
}
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { EventEmitter } from "node:events";
|
|
14
|
-
import { spawn } from "node:child_process";
|
|
15
14
|
import { createHash, timingSafeEqual } from "node:crypto";
|
|
16
15
|
import { fileURLToPath } from "node:url";
|
|
17
16
|
import { dirname, join } from "node:path";
|
|
@@ -113,6 +112,11 @@ import {
|
|
|
113
112
|
handleArtifactRemove,
|
|
114
113
|
handleArtifactShow,
|
|
115
114
|
} from "./artifact-protocol.js";
|
|
115
|
+
import { executionBroker } from "../../lib/process-execution-broker/index.js";
|
|
116
|
+
|
|
117
|
+
export const _deps = {
|
|
118
|
+
spawn: (...args) => executionBroker.spawn(...args),
|
|
119
|
+
};
|
|
116
120
|
|
|
117
121
|
const __filename = fileURLToPath(import.meta.url);
|
|
118
122
|
const __dirname = dirname(__filename);
|
|
@@ -216,6 +220,7 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
216
220
|
* @param {string} [options.token] - If set, clients must authenticate first
|
|
217
221
|
* @param {number} [options.maxConnections=10]
|
|
218
222
|
* @param {number} [options.timeout=30000] - Command execution timeout (ms)
|
|
223
|
+
* @param {Function} [options.spawn] - Process seam for tests
|
|
219
224
|
*/
|
|
220
225
|
constructor(options = {}) {
|
|
221
226
|
super();
|
|
@@ -240,6 +245,7 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
240
245
|
// grace window so it can't hold a maxConnections slot forever (see
|
|
241
246
|
// AUTH_TIMEOUT_MS). `??` so an explicit 0 (disable) is honoured.
|
|
242
247
|
this.authTimeoutMs = options.authTimeoutMs ?? AUTH_TIMEOUT_MS;
|
|
248
|
+
this._spawnProcess = options.spawn || _deps.spawn;
|
|
243
249
|
|
|
244
250
|
/** Optional Phase-5 envelope bus for fan-out to hosted HTTP SSE. */
|
|
245
251
|
this.envelopeBus = options.envelopeBus || null;
|
|
@@ -255,6 +261,7 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
255
261
|
|
|
256
262
|
/** Session manager for stateful agent/chat sessions */
|
|
257
263
|
this.sessionManager = options.sessionManager || null;
|
|
264
|
+
this.projectRoot = options.projectRoot || process.cwd();
|
|
258
265
|
|
|
259
266
|
/** Session handlers: sessionId → WSAgentHandler | WSChatHandler */
|
|
260
267
|
this.sessionHandlers = new Map();
|
|
@@ -530,6 +537,67 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
530
537
|
return this._dispatcher.dispatch(clientId, ws, message);
|
|
531
538
|
}
|
|
532
539
|
|
|
540
|
+
/** Read the same .claude settings rules used by the Agent Core. */
|
|
541
|
+
async _handlePermissionRulesGet(id, ws) {
|
|
542
|
+
try {
|
|
543
|
+
const { loadSettings } = await import("../../lib/settings-loader.cjs");
|
|
544
|
+
const loaded = loadSettings({ cwd: this.projectRoot });
|
|
545
|
+
this._send(ws, {
|
|
546
|
+
id,
|
|
547
|
+
type: "permission-rules",
|
|
548
|
+
rules: loaded.rules,
|
|
549
|
+
sources: loaded.sources,
|
|
550
|
+
files: loaded.files,
|
|
551
|
+
managed: loaded.managed || null,
|
|
552
|
+
});
|
|
553
|
+
} catch (error) {
|
|
554
|
+
this._send(ws, {
|
|
555
|
+
id,
|
|
556
|
+
type: "error",
|
|
557
|
+
code: "PERMISSION_RULES_READ_FAILED",
|
|
558
|
+
message: error.message,
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/** Persist one rule through settings-loader; managed policy remains authoritative. */
|
|
564
|
+
async _handlePermissionRulesSet(id, ws, message) {
|
|
565
|
+
try {
|
|
566
|
+
const decision = String(message.decision || "").toLowerCase();
|
|
567
|
+
if (!["allow", "ask", "deny"].includes(decision)) {
|
|
568
|
+
throw new Error("decision must be allow, ask, or deny");
|
|
569
|
+
}
|
|
570
|
+
const rulesMod = await import("../../lib/permission-rules.cjs");
|
|
571
|
+
const mod = rulesMod.default || rulesMod;
|
|
572
|
+
if (!mod.parseRule(message.rule)) throw new Error("invalid permission rule");
|
|
573
|
+
const { addRule } = await import("../../lib/settings-loader.cjs");
|
|
574
|
+
const scope = ["project", "local", "user"].includes(message.scope)
|
|
575
|
+
? message.scope
|
|
576
|
+
: "project";
|
|
577
|
+
const result = addRule({
|
|
578
|
+
cwd: this.projectRoot,
|
|
579
|
+
kind: decision,
|
|
580
|
+
rule: message.rule,
|
|
581
|
+
scope,
|
|
582
|
+
});
|
|
583
|
+
this._send(ws, {
|
|
584
|
+
id,
|
|
585
|
+
type: "permission-rule-updated",
|
|
586
|
+
...result,
|
|
587
|
+
decision,
|
|
588
|
+
rule: message.rule,
|
|
589
|
+
scope,
|
|
590
|
+
});
|
|
591
|
+
} catch (error) {
|
|
592
|
+
this._send(ws, {
|
|
593
|
+
id,
|
|
594
|
+
type: "error",
|
|
595
|
+
code: "PERMISSION_RULES_WRITE_FAILED",
|
|
596
|
+
message: error.message,
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
533
601
|
/**
|
|
534
602
|
* Handle an orchestrate message — runs ChainlessChain orchestration with
|
|
535
603
|
* real-time progress pushed back over this WebSocket connection.
|
|
@@ -854,11 +922,12 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
854
922
|
return;
|
|
855
923
|
}
|
|
856
924
|
|
|
857
|
-
const child =
|
|
925
|
+
const child = this._spawnProcess(process.execPath, [BIN_PATH, ...args], {
|
|
858
926
|
env: {
|
|
859
927
|
...process.env,
|
|
860
928
|
FORCE_COLOR: "0",
|
|
861
929
|
NO_SPINNER: "1",
|
|
930
|
+
NODE_NO_WARNINGS: "1",
|
|
862
931
|
// When this server runs inside Electron (e.g. desktop web-shell)
|
|
863
932
|
// process.execPath points at the Electron binary, not node. Setting
|
|
864
933
|
// ELECTRON_RUN_AS_NODE=1 makes Electron behave as a plain Node
|
|
@@ -869,6 +938,10 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
869
938
|
},
|
|
870
939
|
stdio: ["pipe", "pipe", "pipe"],
|
|
871
940
|
windowsHide: true,
|
|
941
|
+
origin: "gateway:ws-command",
|
|
942
|
+
policy: "allow",
|
|
943
|
+
scope: "gateway",
|
|
944
|
+
shell: false,
|
|
872
945
|
});
|
|
873
946
|
|
|
874
947
|
this.processes.set(id, child);
|
|
@@ -894,27 +967,42 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
894
967
|
|
|
895
968
|
if (stream) {
|
|
896
969
|
// Stream mode: send chunks as they arrive
|
|
970
|
+
// stdout is the primary command result. Node can deliver a startup
|
|
971
|
+
// warning on stderr before the first stdout chunk (especially on the
|
|
972
|
+
// `--version` fast path), which otherwise makes consumers mistake the
|
|
973
|
+
// warning for the command output. Hold early stderr until stdout has
|
|
974
|
+
// been announced; if there is no stdout, flush it before stream-end.
|
|
975
|
+
let stdoutSeen = false;
|
|
976
|
+
const pendingStderr = [];
|
|
977
|
+
|
|
897
978
|
child.stdout.on("data", (data) => {
|
|
979
|
+
stdoutSeen = true;
|
|
898
980
|
this._send(ws, {
|
|
899
981
|
id,
|
|
900
982
|
type: "stream-data",
|
|
901
983
|
channel: "stdout",
|
|
902
984
|
data: data.toString("utf8"),
|
|
903
985
|
});
|
|
986
|
+
while (pendingStderr.length > 0) {
|
|
987
|
+
this._send(ws, pendingStderr.shift());
|
|
988
|
+
}
|
|
904
989
|
});
|
|
905
990
|
|
|
906
991
|
child.stderr.on("data", (data) => {
|
|
907
|
-
|
|
992
|
+
const message = {
|
|
908
993
|
id,
|
|
909
994
|
type: "stream-data",
|
|
910
995
|
channel: "stderr",
|
|
911
996
|
data: data.toString("utf8"),
|
|
912
|
-
}
|
|
997
|
+
};
|
|
998
|
+
if (stdoutSeen) this._send(ws, message);
|
|
999
|
+
else pendingStderr.push(message);
|
|
913
1000
|
});
|
|
914
1001
|
|
|
915
1002
|
child.on("close", (exitCode) => {
|
|
916
1003
|
clearTimeout(timer);
|
|
917
1004
|
this.processes.delete(id);
|
|
1005
|
+
for (const message of pendingStderr) this._send(ws, message);
|
|
918
1006
|
this._send(ws, {
|
|
919
1007
|
id,
|
|
920
1008
|
type: "stream-end",
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
verifyTranscriptText,
|
|
21
21
|
TRANSCRIPT_CHAIN_STATUS,
|
|
22
22
|
} from "./transcript-integrity.js";
|
|
23
|
+
import { withFileLock } from "../lib/with-file-lock.js";
|
|
23
24
|
|
|
24
25
|
function getSessionsDir() {
|
|
25
26
|
const dir = join(getHomeDir(), "sessions");
|
|
@@ -82,12 +83,18 @@ function _resolveChainTail(sessionId, filePath) {
|
|
|
82
83
|
|
|
83
84
|
export function appendEvent(sessionId, type, data) {
|
|
84
85
|
const filePath = sessionPath(sessionId);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
withFileLock(
|
|
87
|
+
filePath,
|
|
88
|
+
() => {
|
|
89
|
+
const prevHash = _resolveChainTail(sessionId, filePath);
|
|
90
|
+
const core = { type, timestamp: Date.now(), data };
|
|
91
|
+
const hash = computeEventHash(prevHash, core);
|
|
92
|
+
const line = JSON.stringify({ ...core, prevHash, hash }) + "\n";
|
|
93
|
+
appendFileSync(filePath, line, "utf-8");
|
|
94
|
+
_chainTailCache.set(sessionId, hash);
|
|
95
|
+
},
|
|
96
|
+
{ failIfUnavailable: true },
|
|
97
|
+
);
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
/**
|