chainlesschain 0.162.180 → 0.162.181
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 +6 -3
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-D_TIL54O.js → AIOps-cq0dwbnf.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-eQwy9r-f.js → ActionButton-CvcgGl3w.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-D2eNuDgT.js → Analytics-hM2-jFqg.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CFhwOFsf.js → AppLayout-B9_Gsd_g.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CJUMw6PB.js → Artifacts-B7bu52Og.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CDB9V58o.js → Audit-DThfDgqB.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-TBppYFjN.js → BackgroundAgents-DjlFiD4v.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CYEOUpzJ.js → Backup-CK9xJKnG.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-C88fFT2u.js → BaseInput-DEiSU8K8.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-mkr1vC3N.js → Chat-CpT96czj.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-C7bofJuA.js → ChatBubbleRenderer-BKPPNmZI.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CVU4xqti.js → Checkbox-C1GfDnO0.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-rrNcByz3.js → Codegen-3DAKgiLx.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Cqu-zCvh.js → Col-74cOwZU1.js} +1 -1
- package/src/assets/web-panel/assets/{Community-RGRlSgXV.js → Community-tn9Kkz9j.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DBm6epOK.js → Compact-BcoXH7m4.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BgKw5iaW.js → Compliance-DIPGUBgi.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BqQcNO3Z.js → Cowork-doD5_91c.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-DO5gTFNb.js → Cron-C-IDvubz.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-B8hbJNuN.js → Crosschain-CdcCoBdj.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B08bFJ2C.js → DID-DdH5aMMA.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-xNdy_ifo.js → Dashboard-DHLA4mm0.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-D-KIZgWL.js → Dropdown-dEeCt7Md.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DKCvsaGo.js → EmailListRenderer-BMaecFv9.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-D_cfqama.js → FamilyGuardDashboard-DUaUukTN.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-B-UqQD68.js → Federation-CMBE0_rp.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BWWvWuJW.js → FormItemContext-PG-JDbXq.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CPchx6N7.js → GenericCardRenderer-Bcb0p88m.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Vx4co9Ff.js → Git-Bgv15myB.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-D4x0pp_m.js → Governance-DB8YTArI.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-T3KvwPYR.js → Inference-BQMwCWaS.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Ddv3KUv3.js → KnowledgeGraph-B1_ZziiB.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DfH-Dkae.js → Logs-DovEEnt_.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-DHW3PbCq.js → MarkdownRenderer-D201OL4T.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-tjgb0R3D.js → Marketplace-BlCXSpyB.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DHAk5nYX.js → McpTools-CsCR09Wj.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-A2Yx7thM.js → Memory-CBVRLKno.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BEmTVfN5.js → MobileBridge-C9OIafgA.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DuFHUgE4.js → MobileProjects-D_zoJ8Xs.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BDSll0OZ.js → Mtc-vE-HdvLj.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-CuBvluaS.js → MtcAudit-CPLaekCd.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-BmXAA-Sb.js → Multisig-C_UP9C2o.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-ci2stZAe.js → NLProgramming-2nODJcU1.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-D-1RpqnS.js → Notes-BhE-SJGu.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-C0GyitIT.js → NotificationSettings-D21q7BNU.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-U2bN-hj5.js → OrderTableRenderer-0b62GYOD.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BNZgpPci.js → Organization-CEqmw_sb.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CDidKmUN.js → Overflow-MW-gMDO_.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BnreBaXq.js → P2P-CY0hjI_G.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DwJUxO9j.js → PdhVaultBrowser-BbWh7Man.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BQGgJPH0.js → Permissions-ChqEA_4Q.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-k_fSkCwL.js → PersonalDataHub-B3YrbYfD.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-WGqKMqau.js → Pipeline-B8WBhhlW.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DtHj9Ymq.js → Privacy-Cmb0PXNx.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B3wH2SFC.js → ProjectInit-hF6zW3Nz.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Cd0cgcA1.js → ProjectSettings-BFSVfpW0.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DAWkVFkc.js +1 -0
- package/src/assets/web-panel/assets/{Providers-DTpxEXur.js → Providers-B8yux8Dx.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-B2v6gR-C.js → QrScannerModal-N76cQluO.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-D3Nr9xXR.js → QuickAsk-ClvZ0KYR.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-C9inoMky.js → Recommend-B-GfgBpT.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-mlglCdQi.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-41KFG646.js → Reputation-DJIZzQeG.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DqAaqqCv.js → Row-COzxu_bb.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CMDpCDKc.js → RssFeed-CoYsJQuE.js} +3 -3
- package/src/assets/web-panel/assets/{Search-B6mtegNL.js → Search-DC77Mq9S.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BaePFVZ8.js → Security-Loy2EdMO.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DeG3Qscl.js → Services-GUD07Eu0.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-D_QP7F90.js → Skeleton-DWzkptYU.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DLGyUgIA.js → Skills-CEDn1r-Z.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BN2pxW1Q.js → Sla-ub_k4pXh.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BWsZPd8B.js → SpeechSettings-D7HLX9CA.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-VOZRPODW.js → SyncSettings-DbwOvl6m.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-CBQzoAu5.js +1 -0
- package/src/assets/web-panel/assets/{Templates-eJSob-q0.js → Templates-BNVeIhud.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-Bdwk8Rwy.js → Tenant-PS9AzhXU.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CsMLKIoV.js → Terminal-Cgb4eLB_.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-D5qkbPKT.js → TimelineRenderer-CrmXMOkg.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DKgwn8hI.js → Tokens-DD-VDHw1.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-HlEHniGM.js → Trigger-BsoN_n-n.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CdPcsBpN.js → Trust-n8LmN4ZV.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-vAdXd-vG.js → UkeySign-C9_7MImA.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-9hHBYFnH.js → VideoEditing-DyBteNgn.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Dxh5d1yR.js → Wallet-BS5ixeXI.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BsFmLHkp.js → WebAuthn-spc4UImU.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-Cn0OIwLn.js → WorkflowEditor-D7iVvaBO.js} +1 -1
- package/src/assets/web-panel/assets/chat-6CmBkHrL.js +1 -0
- package/src/assets/web-panel/assets/{colors-Du9jzLN0.js → colors-BGoCLkxI.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DhEscfzw.js → compact-item-fYZBetMO.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CwzEfF3i.js → createContext-BeM-1UVj.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BzPwHnw8.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DT_GSE6J.js → hasIn-CE7ZuEnV.js} +1 -1
- package/src/assets/web-panel/assets/{index-53z1YUxX.js → index--lap6cf7.js} +1 -1
- package/src/assets/web-panel/assets/{index-NA2oBLSB.js → index-ATcSr_2O.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWL3SYN3.js → index-B2U-ObMq.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-QkW1fp.js → index-B3CDgvNW.js} +1 -1
- package/src/assets/web-panel/assets/{index-BF-ZCVGE.js → index-B4wiTEOM.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4kZoXNr.js → index-B8BsdNV_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DnVVYKCE.js → index-BEVm0lCS.js} +10 -10
- package/src/assets/web-panel/assets/{index-DfRDyY1q.js → index-BNZDILcO.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8s5FxJY.js → index-BU_2qiDk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnHhFnwt.js → index-BV551878.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhXay17G.js → index-BfPL-m46.js} +1 -1
- package/src/assets/web-panel/assets/{index-B6QDWRLk.js → index-BowH1eLQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DN60VBn5.js → index-BsMfoaeo.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cnok8mhZ.js → index-BunaQCa0.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dny_ZnAO.js → index-C0v6YKKO.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8gt0j7r.js → index-C4SJVjs4.js} +1 -1
- package/src/assets/web-panel/assets/{index-Mobw3PHs.js → index-C9Y3k0HI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAVW0cWM.js → index-CIpVrf5P.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyEhUJcu.js → index-CRLjEP1H.js} +1 -1
- package/src/assets/web-panel/assets/{index-DzjzrOli.js → index-CRnUE8Cb.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5IytTND.js → index-Cip8emOQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQWENaZf.js → index-CpIGIB85.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQWxDOvM.js → index-D1r9tT3J.js} +1 -1
- package/src/assets/web-panel/assets/{index-BrkJ7JPm.js → index-DT3zPSVX.js} +1 -1
- package/src/assets/web-panel/assets/index-DacrAdc-.js +1 -0
- package/src/assets/web-panel/assets/{index-BFD0cEna.js → index-De0quFDw.js} +1 -1
- package/src/assets/web-panel/assets/{index-v5HLYCVa.js → index-DoXk5KJ8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtRwLhee.js → index-DsvfrESp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgSR2WMG.js → index-Dw1PyYPm.js} +1 -1
- package/src/assets/web-panel/assets/index-EHzNJozo.js +1 -0
- package/src/assets/web-panel/assets/{index-CGvgnfl9.js → index-MtOuq2i6.js} +1 -1
- package/src/assets/web-panel/assets/{index-1LoutPJd.js → index-Puq6Luf1.js} +1 -1
- package/src/assets/web-panel/assets/{index-tND8-TDU.js → index-QIpnpZgz.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3llLkYM.js → index-RMZ8a7Yt.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4SN3by5.js → index-WUrJ6S1j.js} +1 -1
- package/src/assets/web-panel/assets/{index-VeHs6qH0.js → index-YjcumOZ4.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cc9aPkv-.js → index-lJBjB1QX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIYTjbv_.js → index-ukg99D1V.js} +1 -1
- package/src/assets/web-panel/assets/{index-gFjYdstW.js → index-zb7rVOhV.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Cvt59c10.js → initDefaultProps-CYHMs1ag.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D15pPEzl.js → motion-DDB2Ffk5.js} +1 -1
- package/src/assets/web-panel/assets/{move-N55KeXJ7.js → move-Bg3cD-dX.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CyFO1bYP.js → mtc-parser-B5nedjTS.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B5IXfxU2.js → omit-BHyuUILu.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CpVqsulV.js → pickAttrs-C9YQnEN9.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-ME36sMF3.js → placementArrow-DBUFYUe7.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BXAIR1r-.js → responsiveObserve-nBs2Obnk.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BkOX3-Dp.js → slide-DkCEaXNU.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Cy4Aklpt.js → statusUtils-aqE1Wi6U.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-gUd2T206.js → styleChecker-CN5bhfHB.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CaVD4o99.js → useFlexGapSupport-B_oX_kvJ.js} +1 -1
- package/src/assets/web-panel/assets/{useFs--pFGl0KD.js → useFs-rCuXHeme.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-D45iP86i.js → usePersonalDataHub-DZR9Abyd.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BayoChH_.js → vnode-ConCYQlX.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CpP38poi.js → zoom-CUdDxG5M.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +4 -1
- package/src/commands/background-session.js +2 -1
- package/src/commands/context.js +69 -2
- package/src/data/changelog.json +13 -0
- package/src/gateways/ws/background-agent-protocol.js +38 -0
- package/src/gateways/ws/message-dispatcher.js +1 -0
- package/src/gateways/ws/remote-session-protocol.js +65 -6
- package/src/gateways/ws/ws-server.js +8 -1
- package/src/harness/feature-flags.js +15 -8
- package/src/harness/mcp-client.js +618 -43
- package/src/lazy-dispatch.js +30 -1
- package/src/lib/agent-authority.js +22 -0
- package/src/lib/agent-core.js +2 -0
- package/src/lib/agent-sandbox.js +161 -0
- package/src/lib/agent-team/team-runner.js +22 -0
- package/src/lib/artifact-store.js +35 -0
- package/src/lib/async-hook-supervisor.cjs +13 -2
- package/src/lib/audit-mtc.js +3 -2
- package/src/lib/background-agent-supervisor.js +104 -3
- package/src/lib/background-interaction-journal.js +407 -0
- package/src/lib/background-interaction-resolver.js +23 -34
- package/src/lib/background-session-transport.js +12 -2
- package/src/lib/capability-manifest.js +41 -3
- package/src/lib/capability-negotiation.js +1 -1
- package/src/lib/channels/channel-manager.js +33 -0
- package/src/lib/channels/telegram-channel.js +23 -5
- package/src/lib/channels/webhook-channel.js +38 -15
- package/src/lib/chrome-connector.js +169 -23
- package/src/lib/config-manager.js +23 -9
- package/src/lib/context-breakdown.js +31 -0
- package/src/lib/cowork-cron.js +274 -32
- package/src/lib/cross-chain-mtc.js +3 -2
- package/src/lib/durable-security-store.js +124 -0
- package/src/lib/event-runtime-host.js +67 -6
- package/src/lib/event-runtime-store.js +163 -0
- package/src/lib/goal-store.js +32 -12
- package/src/lib/headless-manifest.js +2 -1
- package/src/lib/hook-environment.cjs +58 -0
- package/src/lib/hook-manager.js +12 -5
- package/src/lib/hook-runner.cjs +122 -28
- package/src/lib/hook-runner.js +1 -0
- package/src/lib/hooks-v2-producers.js +36 -0
- package/src/lib/hooks-v2-runtime.js +329 -52
- package/src/lib/interaction-adapter.js +60 -19
- package/src/lib/interaction-binding.js +64 -0
- package/src/lib/json-schema-output.js +439 -14
- package/src/lib/json-schema-validate.js +514 -883
- package/src/lib/lan-pairing-tokens.js +115 -57
- package/src/lib/lsp/__tests__/lsp-client.test.js +32 -0
- package/src/lib/lsp/__tests__/lsp-manager.test.js +25 -0
- package/src/lib/lsp/lsp-client.js +4 -0
- package/src/lib/lsp/lsp-manager.js +3 -0
- package/src/lib/lsp/lsp-server-registry.js +18 -0
- package/src/lib/mcp-client.js +1 -0
- package/src/lib/mcp-oauth.js +35 -21
- package/src/lib/packer/pkg-config-generator.js +1 -0
- package/src/lib/permission-decision.js +99 -0
- package/src/lib/plugin-monitor-supervisor.js +3 -0
- package/src/lib/plugin-runtime/capabilities.js +50 -0
- package/src/lib/plugin-runtime/capability-consent.js +42 -35
- package/src/lib/plugin-runtime/hooks.js +36 -9
- package/src/lib/plugin-runtime/install.js +23 -7
- package/src/lib/plugin-runtime/lsp.js +4 -0
- package/src/lib/plugin-runtime/manifest.js +50 -2
- package/src/lib/plugin-runtime/mcp.js +30 -5
- package/src/lib/plugin-runtime/monitors.js +11 -0
- package/src/lib/plugin-runtime/plugin-options.js +94 -38
- package/src/lib/plugin-runtime/policy.js +29 -2
- package/src/lib/plugin-runtime/sandbox-policy.js +84 -0
- package/src/lib/plugin-runtime/scopes.js +7 -3
- package/src/lib/plugin-runtime/trust.js +36 -31
- package/src/lib/process-execution-broker/credential-agent.js +114 -16
- package/src/lib/process-execution-broker/credential-transport-worker.js +312 -0
- package/src/lib/process-execution-broker/credential-transport.js +378 -0
- package/src/lib/process-execution-broker/index.js +408 -19
- package/src/lib/process-execution-broker/platform-sandbox.js +561 -21
- package/src/lib/process-execution-broker/windows-sandbox.ps1 +999 -0
- package/src/lib/project-mcp-trust.js +21 -26
- package/src/lib/protocol-replay.js +19 -12
- package/src/lib/settings-hooks.cjs +13 -0
- package/src/lib/skill-loader.js +83 -10
- package/src/lib/sync-credentials.js +5 -4
- package/src/lib/turn-binding.js +8 -6
- package/src/repl/agent-repl.js +113 -28
- package/src/repl/repl-turn-binding.js +5 -2
- package/src/runtime/agent-core.js +331 -26
- package/src/runtime/coding-agent-contract-shared.cjs +3 -3
- package/src/runtime/headless-runner.js +101 -4
- package/src/runtime/headless-stream.js +209 -23
- package/src/runtime/mcp-config.js +29 -17
- package/src/runtime/policies/agent-policy.js +2 -0
- package/src/workers/background-agent-worker.js +128 -13
- package/src/assets/web-panel/assets/Projects-BbgmyQnS.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-Bqk3EYSu.js +0 -4
- package/src/assets/web-panel/assets/Tasks-3bDAUz8K.js +0 -1
- package/src/assets/web-panel/assets/chat-CJ19O6Dh.js +0 -1
- package/src/assets/web-panel/assets/devWarning-BBMFnsja.js +0 -1
- package/src/assets/web-panel/assets/index-Do8JMV4N.js +0 -1
- package/src/assets/web-panel/assets/index-UYAJ6iNM.js +0 -1
package/src/lazy-dispatch.js
CHANGED
|
@@ -6,6 +6,10 @@ import { pathToFileURL } from "node:url";
|
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { readFileSync } from "node:fs";
|
|
9
|
+
import {
|
|
10
|
+
startDefaultEventRuntimeHost,
|
|
11
|
+
stopDefaultEventRuntimeHost,
|
|
12
|
+
} from "./lib/event-runtime-host.js";
|
|
9
13
|
|
|
10
14
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
15
|
const manifest = JSON.parse(
|
|
@@ -29,7 +33,28 @@ export function resolveCommandToken(argv = []) {
|
|
|
29
33
|
return null;
|
|
30
34
|
}
|
|
31
35
|
|
|
32
|
-
export async function
|
|
36
|
+
export async function withDefaultEventRuntimeLifecycle(
|
|
37
|
+
task,
|
|
38
|
+
{ hostOptions = {} } = {},
|
|
39
|
+
) {
|
|
40
|
+
if (typeof task !== "function") {
|
|
41
|
+
throw new TypeError("Event Runtime lifecycle task must be a function");
|
|
42
|
+
}
|
|
43
|
+
const host = startDefaultEventRuntimeHost({
|
|
44
|
+
...hostOptions,
|
|
45
|
+
// Let the selected command finish registering its handlers before the
|
|
46
|
+
// first claim. Resident commands then run on the normal interval; short
|
|
47
|
+
// commands receive a bounded final drain in the finally block.
|
|
48
|
+
immediate: false,
|
|
49
|
+
});
|
|
50
|
+
try {
|
|
51
|
+
return await task(host);
|
|
52
|
+
} finally {
|
|
53
|
+
if (host) await stopDefaultEventRuntimeHost({ drain: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function dispatchCli(argv) {
|
|
33
58
|
const args = argv.slice(2);
|
|
34
59
|
|
|
35
60
|
// Resolve the command before deciding whether help/version needs the eager
|
|
@@ -95,6 +120,10 @@ export async function runCli(argv) {
|
|
|
95
120
|
}
|
|
96
121
|
}
|
|
97
122
|
|
|
123
|
+
export async function runCli(argv) {
|
|
124
|
+
return withDefaultEventRuntimeLifecycle(() => dispatchCli(argv));
|
|
125
|
+
}
|
|
126
|
+
|
|
98
127
|
export class LazyDispatch {
|
|
99
128
|
constructor(manifest) {
|
|
100
129
|
this.manifest = manifest;
|
|
@@ -154,6 +154,28 @@ export function canManageSession(envelope = {}) {
|
|
|
154
154
|
);
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
/**
|
|
158
|
+
* True when this envelope may answer a human-interaction request. A local UI
|
|
159
|
+
* owns this authority. A remote peer must be authenticated and explicitly
|
|
160
|
+
* paired for prompt/approve/manage control; observe-only peers cannot answer.
|
|
161
|
+
*/
|
|
162
|
+
export function canAnswerInteraction(envelope = {}) {
|
|
163
|
+
if (envelope.origin === ORIGIN.USER) return true;
|
|
164
|
+
if (envelope.origin !== ORIGIN.REMOTE || envelope.authenticated !== true) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
const scopes = normalizeScopes(envelope);
|
|
168
|
+
return scopes.has("prompt") || scopes.has("approve") || scopes.has("manage");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function assertCanAnswerInteraction(envelope = {}) {
|
|
172
|
+
if (canAnswerInteraction(envelope)) return;
|
|
173
|
+
const who = envelope.origin || "unknown";
|
|
174
|
+
throw new Error(
|
|
175
|
+
`origin "${who}" is not authorized to answer interaction requests`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
157
179
|
/**
|
|
158
180
|
* Throw a clear, log-safe error when an envelope is NOT allowed to approve.
|
|
159
181
|
* Callers gate every "resolve a permission" seam through this so the rule
|
package/src/lib/agent-core.js
CHANGED
package/src/lib/agent-sandbox.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** OS-isolated shell execution for the coding agent. */
|
|
2
|
+
import fs from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { proxyEnv } from "./sandbox-egress-proxy.js";
|
|
4
5
|
import executionBroker from "./process-execution-broker/index.js";
|
|
@@ -29,6 +30,166 @@ function resolvePolicyPaths(entries, cwd) {
|
|
|
29
30
|
});
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
function pathEntryExists(candidate, fsImpl) {
|
|
34
|
+
try {
|
|
35
|
+
fsImpl.lstatSync(candidate);
|
|
36
|
+
return true;
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (error?.code === "ENOENT" || error?.code === "ENOTDIR") return false;
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Resolve a path for policy comparison without requiring the final target to
|
|
45
|
+
* exist. Existing ancestors are resolved through symlinks/junctions before the
|
|
46
|
+
* missing suffix is appended. This is important for writes: checking only the
|
|
47
|
+
* lexical target lets `workspace/link/new-file` escape when `link` points
|
|
48
|
+
* outside the workspace.
|
|
49
|
+
*/
|
|
50
|
+
function canonicalPolicyPath(candidate, fsImpl) {
|
|
51
|
+
const absolute = path.resolve(candidate);
|
|
52
|
+
let existing = absolute;
|
|
53
|
+
const missing = [];
|
|
54
|
+
|
|
55
|
+
while (!pathEntryExists(existing, fsImpl)) {
|
|
56
|
+
const parent = path.dirname(existing);
|
|
57
|
+
if (parent === existing) {
|
|
58
|
+
throw new Error(`No existing ancestor for path: ${absolute}`);
|
|
59
|
+
}
|
|
60
|
+
missing.unshift(path.basename(existing));
|
|
61
|
+
existing = parent;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const realpath =
|
|
65
|
+
typeof fsImpl.realpathSync?.native === "function"
|
|
66
|
+
? fsImpl.realpathSync.native
|
|
67
|
+
: fsImpl.realpathSync;
|
|
68
|
+
if (typeof realpath !== "function") {
|
|
69
|
+
throw new Error("Filesystem realpath support is unavailable");
|
|
70
|
+
}
|
|
71
|
+
return path.resolve(realpath(existing), ...missing);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function pathIsWithin(candidate, root) {
|
|
75
|
+
const relative = path.relative(root, candidate);
|
|
76
|
+
return (
|
|
77
|
+
relative === "" ||
|
|
78
|
+
(relative !== ".." &&
|
|
79
|
+
!relative.startsWith(`..${path.sep}`) &&
|
|
80
|
+
!path.isAbsolute(relative))
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function normalizeWorkspaceRoots(entries, cwd) {
|
|
85
|
+
const roots =
|
|
86
|
+
Array.isArray(entries) && entries.length > 0 ? entries : [cwd];
|
|
87
|
+
return stringList(roots).map((entry) => path.resolve(cwd, entry));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Resolve and authorize one built-in agent file-tool path.
|
|
92
|
+
*
|
|
93
|
+
* The workspace roots are always allowed. A normalized sandbox policy may add
|
|
94
|
+
* explicit read/write roots and may deny narrower paths. Both existing targets
|
|
95
|
+
* and the nearest existing ancestor are realpath-resolved, so an in-workspace
|
|
96
|
+
* symlink/junction cannot redirect a read or write outside the declared roots.
|
|
97
|
+
*
|
|
98
|
+
* @returns {{
|
|
99
|
+
* ok:boolean,
|
|
100
|
+
* path?:string,
|
|
101
|
+
* canonicalPath?:string,
|
|
102
|
+
* reason?:string,
|
|
103
|
+
* error?:string
|
|
104
|
+
* }}
|
|
105
|
+
*/
|
|
106
|
+
export function resolveSandboxPolicyPath(
|
|
107
|
+
requestedPath,
|
|
108
|
+
{
|
|
109
|
+
access = "read",
|
|
110
|
+
cwd = process.cwd(),
|
|
111
|
+
workspaceRoots = null,
|
|
112
|
+
sandbox = null,
|
|
113
|
+
policy = sandbox?.policy || null,
|
|
114
|
+
fsImpl = null,
|
|
115
|
+
} = {},
|
|
116
|
+
) {
|
|
117
|
+
if (access !== "read" && access !== "write") {
|
|
118
|
+
return {
|
|
119
|
+
ok: false,
|
|
120
|
+
reason: "invalid-access",
|
|
121
|
+
error: `Unsupported filesystem access mode: ${access}`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
if (
|
|
125
|
+
typeof requestedPath !== "string" ||
|
|
126
|
+
requestedPath.length === 0 ||
|
|
127
|
+
requestedPath.includes("\0")
|
|
128
|
+
) {
|
|
129
|
+
return {
|
|
130
|
+
ok: false,
|
|
131
|
+
reason: "invalid-path",
|
|
132
|
+
error: "A non-empty filesystem path is required",
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const resolvedCwd = path.resolve(cwd);
|
|
137
|
+
const resolvedPath = path.resolve(resolvedCwd, requestedPath);
|
|
138
|
+
const effectiveFs = fsImpl || fs;
|
|
139
|
+
const normalizedPolicy = policy || {};
|
|
140
|
+
const policyAllows =
|
|
141
|
+
access === "write"
|
|
142
|
+
? normalizedPolicy.allowWrite
|
|
143
|
+
: normalizedPolicy.allowRead;
|
|
144
|
+
const policyDenies =
|
|
145
|
+
access === "write"
|
|
146
|
+
? normalizedPolicy.denyWrite
|
|
147
|
+
: normalizedPolicy.denyRead;
|
|
148
|
+
const allowedInputs = [
|
|
149
|
+
...normalizeWorkspaceRoots(workspaceRoots, resolvedCwd),
|
|
150
|
+
...resolvePolicyPaths(policyAllows, resolvedCwd),
|
|
151
|
+
];
|
|
152
|
+
const deniedInputs = resolvePolicyPaths(policyDenies, resolvedCwd);
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const canonicalPath = canonicalPolicyPath(resolvedPath, effectiveFs);
|
|
156
|
+
const allowedRoots = allowedInputs.map((root) =>
|
|
157
|
+
canonicalPolicyPath(root, effectiveFs),
|
|
158
|
+
);
|
|
159
|
+
if (!allowedRoots.some((root) => pathIsWithin(canonicalPath, root))) {
|
|
160
|
+
return {
|
|
161
|
+
ok: false,
|
|
162
|
+
path: resolvedPath,
|
|
163
|
+
canonicalPath,
|
|
164
|
+
reason: "outside-workspace",
|
|
165
|
+
error: `${access} path resolves outside the allowed workspace roots`,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const deniedRoots = deniedInputs.map((root) =>
|
|
170
|
+
canonicalPolicyPath(root, effectiveFs),
|
|
171
|
+
);
|
|
172
|
+
if (deniedRoots.some((root) => pathIsWithin(canonicalPath, root))) {
|
|
173
|
+
return {
|
|
174
|
+
ok: false,
|
|
175
|
+
path: resolvedPath,
|
|
176
|
+
canonicalPath,
|
|
177
|
+
reason: "denied-by-policy",
|
|
178
|
+
error: `${access} path is denied by the sandbox filesystem policy`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return { ok: true, path: resolvedPath, canonicalPath };
|
|
183
|
+
} catch (error) {
|
|
184
|
+
return {
|
|
185
|
+
ok: false,
|
|
186
|
+
path: resolvedPath,
|
|
187
|
+
reason: "realpath-failed",
|
|
188
|
+
error: `Unable to safely resolve filesystem path: ${error.message}`,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
32
193
|
export function normalizeSandboxPolicy(settings = {}, cwd = process.cwd()) {
|
|
33
194
|
const filesystem = settings.filesystem || {};
|
|
34
195
|
const network = settings.network || {};
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* status panel. A total-time / total-task budget bounds a runaway graph.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { emitHooksV2Event } from "../hooks-v2-producers.js";
|
|
18
|
+
|
|
17
19
|
export class TeamRunner {
|
|
18
20
|
/**
|
|
19
21
|
* @param {TaskLeaseRegistry} registry
|
|
@@ -33,6 +35,8 @@ export class TeamRunner {
|
|
|
33
35
|
// Lease-renewal heartbeat cadence while a task runs (default ttl/3).
|
|
34
36
|
this.renewEveryMs = opts.renewEveryMs;
|
|
35
37
|
this.onEvent = typeof opts.onEvent === "function" ? opts.onEvent : () => {};
|
|
38
|
+
this.emitHook =
|
|
39
|
+
typeof opts.emitHook === "function" ? opts.emitHook : emitHooksV2Event;
|
|
36
40
|
this.maxTasks = opts.maxTasks > 0 ? opts.maxTasks : 1000;
|
|
37
41
|
this._now = opts.now || registry._now || (() => Date.now());
|
|
38
42
|
// Team-wide token/USD/time/task budget (null → unbounded). Consulted before
|
|
@@ -80,8 +84,26 @@ export class TeamRunner {
|
|
|
80
84
|
return m;
|
|
81
85
|
}
|
|
82
86
|
if (m.state === state) return m; // no transition
|
|
87
|
+
const previousState = m.state;
|
|
83
88
|
m.state = state;
|
|
84
89
|
this._emit("teammate:state", { holder, state, ...extra });
|
|
90
|
+
// Initial registration starts in `idle`; the hook is reserved for a real
|
|
91
|
+
// transition back to idle after a teammate has participated in the run.
|
|
92
|
+
if (state === "idle" && previousState !== null) {
|
|
93
|
+
try {
|
|
94
|
+
this.emitHook("TeammateIdle", {
|
|
95
|
+
schema_version: 1,
|
|
96
|
+
holder,
|
|
97
|
+
state,
|
|
98
|
+
previous_state: previousState,
|
|
99
|
+
completed: m.completed,
|
|
100
|
+
failed: m.failed,
|
|
101
|
+
...extra,
|
|
102
|
+
});
|
|
103
|
+
} catch {
|
|
104
|
+
/* hook observer is best-effort */
|
|
105
|
+
}
|
|
106
|
+
}
|
|
85
107
|
return m;
|
|
86
108
|
}
|
|
87
109
|
|
|
@@ -40,6 +40,41 @@ export const MAX_ARTIFACT_BYTES = 100 * 1024 * 1024; // 100 MB
|
|
|
40
40
|
/** Default retention before `clean` removes an artifact. */
|
|
41
41
|
export const DEFAULT_TTL_DAYS = 30;
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Metadata safe to return across the agent/session protocol boundary.
|
|
45
|
+
*
|
|
46
|
+
* The persisted index deliberately retains sourcePath for local artifact
|
|
47
|
+
* management, but absolute source paths are host details and must not enter
|
|
48
|
+
* model transcripts or remote-session payloads.
|
|
49
|
+
*/
|
|
50
|
+
export function publicArtifactMetadata(entry) {
|
|
51
|
+
if (!entry || typeof entry !== "object") return null;
|
|
52
|
+
const {
|
|
53
|
+
id,
|
|
54
|
+
title,
|
|
55
|
+
kind,
|
|
56
|
+
mime,
|
|
57
|
+
size,
|
|
58
|
+
sha256,
|
|
59
|
+
file,
|
|
60
|
+
sessionId,
|
|
61
|
+
createdAt,
|
|
62
|
+
expiresAt,
|
|
63
|
+
} = entry;
|
|
64
|
+
return {
|
|
65
|
+
id,
|
|
66
|
+
title,
|
|
67
|
+
kind,
|
|
68
|
+
mime,
|
|
69
|
+
size,
|
|
70
|
+
sha256,
|
|
71
|
+
file,
|
|
72
|
+
sessionId,
|
|
73
|
+
createdAt,
|
|
74
|
+
expiresAt,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
43
78
|
const MIME_BY_EXT = Object.freeze({
|
|
44
79
|
".md": "text/markdown",
|
|
45
80
|
".markdown": "text/markdown",
|
|
@@ -32,7 +32,10 @@
|
|
|
32
32
|
* testable with fake child processes (no real shell).
|
|
33
33
|
*/
|
|
34
34
|
|
|
35
|
-
const {
|
|
35
|
+
const {
|
|
36
|
+
tryParseDecision,
|
|
37
|
+
resolveHookSandboxPolicy,
|
|
38
|
+
} = require("./hook-runner.cjs");
|
|
36
39
|
|
|
37
40
|
const DEFAULT_TIMEOUT_MS = 60000;
|
|
38
41
|
const MAX_TIMEOUT_MS = 600000;
|
|
@@ -359,6 +362,7 @@ class AsyncHookSupervisor {
|
|
|
359
362
|
|
|
360
363
|
let child;
|
|
361
364
|
try {
|
|
365
|
+
const sandboxPolicy = resolveHookSandboxPolicy(hook, opts);
|
|
362
366
|
const spawnOptions = {
|
|
363
367
|
cwd: opts.cwd || process.cwd(),
|
|
364
368
|
shell: true,
|
|
@@ -370,6 +374,7 @@ class AsyncHookSupervisor {
|
|
|
370
374
|
...process.env,
|
|
371
375
|
CLAUDE_HOOK_EVENT: hook.event || payload.hook_event_name || "",
|
|
372
376
|
},
|
|
377
|
+
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
373
378
|
};
|
|
374
379
|
if (typeof this._deps.run !== "function") {
|
|
375
380
|
throw new Error("async hook process runner unavailable");
|
|
@@ -384,10 +389,15 @@ class AsyncHookSupervisor {
|
|
|
384
389
|
pluginSource: hook.pluginSource || null,
|
|
385
390
|
});
|
|
386
391
|
} catch (err) {
|
|
392
|
+
const sandboxDenied =
|
|
393
|
+
err?.code === "ERR_PROCESS_SANDBOX_BOUNDARY_UNSATISFIED";
|
|
387
394
|
this._record(hook, {
|
|
388
395
|
ok: false,
|
|
389
396
|
exitCode: null,
|
|
390
|
-
error:
|
|
397
|
+
error: sandboxDenied
|
|
398
|
+
? `hook sandbox denied: ${err.message}`
|
|
399
|
+
: `hook spawn failed: ${err.message}`,
|
|
400
|
+
sandboxDenied,
|
|
391
401
|
started,
|
|
392
402
|
});
|
|
393
403
|
return;
|
|
@@ -483,6 +493,7 @@ class AsyncHookSupervisor {
|
|
|
483
493
|
error: fields.error || null,
|
|
484
494
|
additionalContext: fields.additionalContext || null,
|
|
485
495
|
blocked: !!fields.blocked,
|
|
496
|
+
...(fields.sandboxDenied === true ? { sandboxDenied: true } : {}),
|
|
486
497
|
asyncRewake: hook.asyncRewake === true,
|
|
487
498
|
ts: now,
|
|
488
499
|
ms: fields.started != null ? now - fields.started : 0,
|
package/src/lib/audit-mtc.js
CHANGED
|
@@ -322,11 +322,12 @@ export function closeBatch(dir, opts = {}) {
|
|
|
322
322
|
// across processes. Without it, two concurrent closes (e.g. overlapping
|
|
323
323
|
// `cc audit mtc reconcile` runs) both scan the same staging events, allocate
|
|
324
324
|
// the same batch id, and the defensive rmSync(finalDir) lets the second
|
|
325
|
-
// silently overwrite the first's audit batch.
|
|
326
|
-
//
|
|
325
|
+
// silently overwrite the first's audit batch. Audit ledger state is critical:
|
|
326
|
+
// bounded contention must fail closed rather than assemble an unlocked batch.
|
|
327
327
|
ensureDirs(dir);
|
|
328
328
|
return withFileLock(batchesDir(dir), () => _closeBatchImpl(dir, opts), {
|
|
329
329
|
timeoutMs: 15000,
|
|
330
|
+
failIfUnavailable: true,
|
|
330
331
|
});
|
|
331
332
|
}
|
|
332
333
|
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
finishAgentWorktree,
|
|
21
21
|
validateAgentWorktree,
|
|
22
22
|
} from "./agent-worktree.js";
|
|
23
|
+
import { rejectPendingBackgroundInteractions } from "./background-interaction-journal.js";
|
|
23
24
|
import executionBroker from "./process-execution-broker/index.js";
|
|
24
25
|
|
|
25
26
|
export const DEFAULT_HEARTBEAT_INTERVAL_MS = 5000;
|
|
@@ -464,6 +465,67 @@ export function effectiveBackgroundAgentState(state, options = {}) {
|
|
|
464
465
|
/* best-effort */
|
|
465
466
|
}
|
|
466
467
|
}
|
|
468
|
+
if (
|
|
469
|
+
options.persist !== false &&
|
|
470
|
+
state.sessionId &&
|
|
471
|
+
!isSameProcess(state.pid, state.startedAt)
|
|
472
|
+
) {
|
|
473
|
+
const pending = state.pendingQuestion;
|
|
474
|
+
const requestId = pending?.requestId || pending?.intId;
|
|
475
|
+
try {
|
|
476
|
+
const recovery = rejectPendingBackgroundInteractions(
|
|
477
|
+
state.sessionId,
|
|
478
|
+
state.id,
|
|
479
|
+
{
|
|
480
|
+
fallbackRequest: requestId
|
|
481
|
+
? {
|
|
482
|
+
requestId,
|
|
483
|
+
binding: pending.binding,
|
|
484
|
+
payload: {
|
|
485
|
+
kind: "question",
|
|
486
|
+
question: pending.question || pending.prompt || "",
|
|
487
|
+
options: pending.options || null,
|
|
488
|
+
multiSelect: pending.multiSelect === true,
|
|
489
|
+
timeoutMs: pending.timeoutMs,
|
|
490
|
+
},
|
|
491
|
+
createdAt: pending.askedAt,
|
|
492
|
+
}
|
|
493
|
+
: null,
|
|
494
|
+
code: "INTERACTION_WORKER_LOST",
|
|
495
|
+
message:
|
|
496
|
+
"The background worker was lost before the interaction settled",
|
|
497
|
+
},
|
|
498
|
+
);
|
|
499
|
+
const recoveredRecord = requestId
|
|
500
|
+
? recovery.journal.get(requestId)
|
|
501
|
+
: null;
|
|
502
|
+
if (
|
|
503
|
+
recovery.changed ||
|
|
504
|
+
(recoveredRecord && recoveredRecord.status !== "pending")
|
|
505
|
+
) {
|
|
506
|
+
next = {
|
|
507
|
+
...next,
|
|
508
|
+
phase: null,
|
|
509
|
+
pendingQuestion: null,
|
|
510
|
+
interactionRecovery: {
|
|
511
|
+
status: "rejected",
|
|
512
|
+
requestIds: recovery.rejected.map((record) => record.requestId),
|
|
513
|
+
recoveredAt: t,
|
|
514
|
+
},
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
} catch (error) {
|
|
518
|
+
next = {
|
|
519
|
+
...next,
|
|
520
|
+
interactionRecovery: {
|
|
521
|
+
status: "failed",
|
|
522
|
+
code: error?.code || "INTERACTION_RECOVERY_FAILED",
|
|
523
|
+
message: error?.message || String(error),
|
|
524
|
+
recoveredAt: t,
|
|
525
|
+
},
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
}
|
|
467
529
|
if (options.persist !== false) {
|
|
468
530
|
try {
|
|
469
531
|
writeBackgroundAgentState(next);
|
|
@@ -838,11 +900,17 @@ export function launchBackgroundAgent({
|
|
|
838
900
|
};
|
|
839
901
|
writeBackgroundAgentState(state);
|
|
840
902
|
let child;
|
|
903
|
+
let workerLogFd;
|
|
841
904
|
try {
|
|
905
|
+
// Preserve loader/bootstrap failures that happen before the worker can
|
|
906
|
+
// open its own append handle. This also gives detached Windows targets
|
|
907
|
+
// concrete inheritable stdout/stderr handles instead of relying on the
|
|
908
|
+
// hosted process' possibly absent standard handles.
|
|
909
|
+
workerLogFd = openSync(job.logFile, "a");
|
|
842
910
|
child = _deps.spawn(process.execPath, [worker, jobFile], {
|
|
843
911
|
cwd,
|
|
844
912
|
detached: true,
|
|
845
|
-
stdio: "ignore",
|
|
913
|
+
stdio: ["ignore", workerLogFd, workerLogFd],
|
|
846
914
|
windowsHide: true,
|
|
847
915
|
origin: "background-agent:worker",
|
|
848
916
|
policy: "allow",
|
|
@@ -853,6 +921,10 @@ export function launchBackgroundAgent({
|
|
|
853
921
|
rmSync(jobFile, { force: true });
|
|
854
922
|
rmSync(statePath(id), { force: true });
|
|
855
923
|
throw error;
|
|
924
|
+
} finally {
|
|
925
|
+
if (Number.isInteger(workerLogFd)) {
|
|
926
|
+
closeSync(workerLogFd);
|
|
927
|
+
}
|
|
856
928
|
}
|
|
857
929
|
// Async spawn failures (EPERM, cwd raced away between the check and the
|
|
858
930
|
// spawn, …) arrive as an 'error' event on the detached child. Reap them
|
|
@@ -875,13 +947,42 @@ export function launchBackgroundAgent({
|
|
|
875
947
|
/* best-effort */
|
|
876
948
|
}
|
|
877
949
|
});
|
|
950
|
+
child.on("exit", (code, signal) => {
|
|
951
|
+
try {
|
|
952
|
+
rmSync(jobFile, { force: true });
|
|
953
|
+
const current = readBackgroundAgentState(id);
|
|
954
|
+
// A healthy worker persists completed/failed before exiting. If the
|
|
955
|
+
// process (or its platform wrapper) exits while the state still says
|
|
956
|
+
// running, bootstrap or finalization failed and the session must not
|
|
957
|
+
// remain a phantom live task until heartbeat reconciliation.
|
|
958
|
+
if (current && current.status === "running") {
|
|
959
|
+
writeBackgroundAgentState({
|
|
960
|
+
...current,
|
|
961
|
+
status: "failed",
|
|
962
|
+
endedAt: Date.now(),
|
|
963
|
+
exitCode: Number.isInteger(code) ? code : null,
|
|
964
|
+
signal: signal || null,
|
|
965
|
+
lostReason: `worker-exited-before-finalize: exit=${
|
|
966
|
+
Number.isInteger(code) ? code : "null"
|
|
967
|
+
} signal=${signal || "none"}`,
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
} catch {
|
|
971
|
+
/* best-effort */
|
|
972
|
+
}
|
|
973
|
+
});
|
|
878
974
|
}
|
|
879
975
|
child.unref();
|
|
880
976
|
const current = readBackgroundAgentState(id) || state;
|
|
881
977
|
const withPid = {
|
|
882
978
|
...current,
|
|
883
|
-
|
|
884
|
-
|
|
979
|
+
// A platform wrapper (notably the Windows Job Object adapter) can return
|
|
980
|
+
// from spawn after the real worker has already claimed the state file.
|
|
981
|
+
// Preserve that authoritative process.pid instead of racing it back to
|
|
982
|
+
// the wrapper pid. With an ordinary direct spawn both fields are still
|
|
983
|
+
// null here and are initialized from child.pid as before.
|
|
984
|
+
pid: current.pid ?? child.pid,
|
|
985
|
+
workerPid: current.workerPid ?? child.pid,
|
|
885
986
|
};
|
|
886
987
|
writeBackgroundAgentState(withPid);
|
|
887
988
|
return withPid;
|