chainlesschain 0.162.180 → 0.162.182
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 +7 -3
- package/scripts/build-windows-sandbox-helper.ps1 +163 -0
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-D_TIL54O.js → AIOps-DzZ5_xoj.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-eQwy9r-f.js → ActionButton-DeLXddIg.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-D2eNuDgT.js → Analytics-rvDCmet1.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CFhwOFsf.js → AppLayout-Yt6QVDnp.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CJUMw6PB.js → Artifacts-BS112K5L.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CDB9V58o.js → Audit-0wJuQrNu.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-TBppYFjN.js → BackgroundAgents-B90PMgbn.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CYEOUpzJ.js → Backup-TkgMglQQ.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-C88fFT2u.js → BaseInput-CQVS9p1l.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-mkr1vC3N.js → Chat-YTjQHoC7.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-PR074hUN.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-CVU4xqti.js → Checkbox-5bwaOabq.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-rrNcByz3.js → Codegen-BFmNQ_Xe.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Cqu-zCvh.js → Col-BT_u4Dzp.js} +1 -1
- package/src/assets/web-panel/assets/{Community-RGRlSgXV.js → Community-CJP52u5b.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DBm6epOK.js → Compact-BpzhJE9i.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BgKw5iaW.js → Compliance-Cg7rfslp.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BqQcNO3Z.js → Cowork-JisxL6Yy.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DO5gTFNb.js → Cron-Bu7Ug_MC.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-B8hbJNuN.js → Crosschain-CvuqoLdj.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B08bFJ2C.js → DID-C2u9G8Pu.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-xNdy_ifo.js → Dashboard-BFt5Yv3d.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-D-KIZgWL.js → Dropdown-DIaT9Wxq.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DKCvsaGo.js → EmailListRenderer-D_A601Y4.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-D_cfqama.js → FamilyGuardDashboard--IyQ8I8w.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-B-UqQD68.js → Federation-BihWHxuY.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BWWvWuJW.js → FormItemContext-BB8dOXc_.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CPchx6N7.js → GenericCardRenderer-DQYhj1HH.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Vx4co9Ff.js → Git-B-2QZxGf.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-D4x0pp_m.js → Governance-CusSb-nG.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-T3KvwPYR.js → Inference-BAjmvPPL.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Ddv3KUv3.js → KnowledgeGraph-DoNYWKYq.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DfH-Dkae.js → Logs-B8fKWD-n.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-DHW3PbCq.js → MarkdownRenderer-BlJm1J7E.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-tjgb0R3D.js → Marketplace-CyOscbSL.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DHAk5nYX.js → McpTools-Ex6Om5da.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-A2Yx7thM.js → Memory-CDcD8l8r.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BEmTVfN5.js → MobileBridge-xfBqoFDg.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DuFHUgE4.js → MobileProjects-BwObMMA2.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BDSll0OZ.js → Mtc-CIWd36OV.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-CuBvluaS.js → MtcAudit-CPX0ouuA.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BmXAA-Sb.js → Multisig-BDJsIUuW.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-ci2stZAe.js → NLProgramming-DEkbuD3N.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-D-1RpqnS.js → Notes-DJpHRhH1.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-C0GyitIT.js → NotificationSettings-C1UZ-Qd5.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-U2bN-hj5.js → OrderTableRenderer-GlJtqLjT.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BNZgpPci.js → Organization-Bbhj0fac.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CDidKmUN.js → Overflow-1H04x3kx.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BnreBaXq.js → P2P-CDpPe3et.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DwJUxO9j.js → PdhVaultBrowser-MUX0Bpvw.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BQGgJPH0.js → Permissions-A07-0Ci1.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-k_fSkCwL.js → PersonalDataHub-DhhDWxAZ.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-WGqKMqau.js → Pipeline-CyfbJfe-.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DtHj9Ymq.js → Privacy-CNFps3ED.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B3wH2SFC.js → ProjectInit--T-u3Dr5.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Cd0cgcA1.js → ProjectSettings-DJmrK2fC.js} +2 -2
- package/src/assets/web-panel/assets/Projects-Qx_MdX9k.js +1 -0
- package/src/assets/web-panel/assets/{Providers-DTpxEXur.js → Providers-DLzzbOZd.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-B2v6gR-C.js → QrScannerModal-CexOomKS.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-D3Nr9xXR.js → QuickAsk-QklGi19_.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-C9inoMky.js → Recommend-Bb9kwSw8.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-DZuVNNN5.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-41KFG646.js → Reputation-Dr5cLP0N.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DqAaqqCv.js → Row-oCQHYv5t.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CMDpCDKc.js → RssFeed-IFDEykIR.js} +3 -3
- package/src/assets/web-panel/assets/{Search-B6mtegNL.js → Search-CspVIxDc.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BaePFVZ8.js → Security-Bm66o_DH.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DeG3Qscl.js → Services-DvanNqXl.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-D_QP7F90.js → Skeleton-CHjEe9_O.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DLGyUgIA.js → Skills-Cb8jWjMX.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BN2pxW1Q.js → Sla-DxZm1491.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BWsZPd8B.js → SpeechSettings-DWxEEclC.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-VOZRPODW.js → SyncSettings-FIvOFw5p.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-CyuLnDFR.js +1 -0
- package/src/assets/web-panel/assets/{Templates-eJSob-q0.js → Templates-CaNjzV_t.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-Bdwk8Rwy.js → Tenant-DjlP6TmH.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-DwzGMniO.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-D5qkbPKT.js → TimelineRenderer-DoZ8y7y8.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DKgwn8hI.js → Tokens-390cg2TC.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-HlEHniGM.js → Trigger-CLrtCj5_.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CdPcsBpN.js → Trust-DpESfSPn.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-vAdXd-vG.js → UkeySign-CN6279O0.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-9hHBYFnH.js → VideoEditing-DPtAUlSe.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Dxh5d1yR.js → Wallet-nKOMV_1n.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BsFmLHkp.js → WebAuthn-HuXlSOc4.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-Cn0OIwLn.js → WorkflowEditor-CUfFjARi.js} +1 -1
- package/src/assets/web-panel/assets/chat-6Eq0PcZJ.js +1 -0
- package/src/assets/web-panel/assets/{colors-Du9jzLN0.js → colors-BP_Sf6Iy.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DhEscfzw.js → compact-item-BufMKIh5.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CwzEfF3i.js → createContext-BBMXxWSW.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DgVKduH2.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DT_GSE6J.js → hasIn-fUK_tRO2.js} +1 -1
- package/src/assets/web-panel/assets/{index-tND8-TDU.js → index-2A5ph8b2.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8s5FxJY.js → index-3FuwBewR.js} +1 -1
- package/src/assets/web-panel/assets/{index-53z1YUxX.js → index-6GmBa4Kg.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFD0cEna.js → index-B2vS66eI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQWxDOvM.js → index-B7Etk0Te.js} +1 -1
- package/src/assets/web-panel/assets/{index-VeHs6qH0.js → index-B9WYSn4m.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGvgnfl9.js → index-BHy6yNiF.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3llLkYM.js → index-BMLHv389.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dny_ZnAO.js → index-BWKoBU8R.js} +1 -1
- package/src/assets/web-panel/assets/{index-DzjzrOli.js → index-Bkg4ZePE.js} +1 -1
- package/src/assets/web-panel/assets/{index-DN60VBn5.js → index-C44atv4k.js} +1 -1
- package/src/assets/web-panel/assets/{index-v5HLYCVa.js → index-CE2DdTP2.js} +1 -1
- package/src/assets/web-panel/assets/{index-BF-ZCVGE.js → index-CGjmILDm.js} +1 -1
- package/src/assets/web-panel/assets/{index-gFjYdstW.js → index-CW_G-MXw.js} +1 -1
- package/src/assets/web-panel/assets/{index-NA2oBLSB.js → index-CZ6Yt17L.js} +1 -1
- package/src/assets/web-panel/assets/{index-Mobw3PHs.js → index-CeASi4fr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWL3SYN3.js → index-CgiECHu2.js} +1 -1
- package/src/assets/web-panel/assets/{index-1LoutPJd.js → index-Cp8vhyZy.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnHhFnwt.js → index-CwSf5pnf.js} +1 -1
- package/src/assets/web-panel/assets/{index-B6QDWRLk.js → index-D4_MuGkd.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-QkW1fp.js → index-D9vU25ij.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4SN3by5.js → index-DASluSqY.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyEhUJcu.js → index-DLpIs_P_.js} +1 -1
- package/src/assets/web-panel/assets/index-DOZTSoS7.js +1 -0
- package/src/assets/web-panel/assets/{index-BrkJ7JPm.js → index-DPdUNk1i.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cnok8mhZ.js → index-DVsqvI4M.js} +1 -1
- package/src/assets/web-panel/assets/index-DhpvjpqI.js +1 -0
- package/src/assets/web-panel/assets/{index-CAVW0cWM.js → index-DmkMXwnR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cc9aPkv-.js → index-DocdRcbd.js} +1 -1
- package/src/assets/web-panel/assets/{index-DnVVYKCE.js → index-Dyngbd29.js} +20 -20
- package/src/assets/web-panel/assets/{index-D8gt0j7r.js → index-GwdRUZ-x.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIYTjbv_.js → index-LvCBfTLo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhXay17G.js → index-cpEli44X.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQWENaZf.js → index-fzaMtSJ8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfRDyY1q.js → index-pum7HYBA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgSR2WMG.js → index-t8N1tSeX.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5IytTND.js → index-uCbEN7cY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtRwLhee.js → index-wKTLbKyc.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4kZoXNr.js → index-wV6iGdpY.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Cvt59c10.js → initDefaultProps-V5Fo95FM.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D15pPEzl.js → motion-BYWU0hUT.js} +1 -1
- package/src/assets/web-panel/assets/{move-N55KeXJ7.js → move-Cr1M-J2h.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CyFO1bYP.js → mtc-parser-BysQKi2N.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B5IXfxU2.js → omit-D1zHU8GC.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CpVqsulV.js → pickAttrs-CUArxtfi.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-ME36sMF3.js → placementArrow-ChoYEys0.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BXAIR1r-.js → responsiveObserve-BQRs3Mo7.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BkOX3-Dp.js → slide-B8zbsCkg.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Cy4Aklpt.js → statusUtils-C2U8Gs6h.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-gUd2T206.js → styleChecker-Dd8MgL_V.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CaVD4o99.js → useFlexGapSupport-hknqY5NH.js} +1 -1
- package/src/assets/web-panel/assets/{useFs--pFGl0KD.js → useFs-CLTAmcfw.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-D45iP86i.js → usePersonalDataHub-ByegHbiB.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BayoChH_.js → vnode-DqlAy5DP.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CpP38poi.js → zoom-DiXiztQn.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agenda.js +115 -3
- package/src/commands/agent.js +10 -1
- package/src/commands/background-session.js +2 -1
- package/src/commands/context.js +69 -2
- package/src/data/changelog.json +26 -0
- package/src/gateways/terminal/PtyManager.js +45 -4
- 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 +18 -2
- package/src/harness/background-task-manager.js +70 -2
- package/src/harness/feature-flags.js +15 -8
- package/src/harness/mcp-client.js +618 -43
- package/src/harness/worktree-isolator.js +14 -3
- package/src/lazy-dispatch.js +30 -1
- package/src/lib/agent-authority.js +22 -0
- package/src/lib/agent-core.js +3 -0
- package/src/lib/agent-sandbox.js +161 -0
- package/src/lib/agent-schedule-store.js +45 -22
- 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 +7 -2
- 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 +3 -0
- package/src/lib/permission-decision.js +99 -0
- package/src/lib/plugin-monitor-supervisor.js +3 -0
- package/src/lib/plugin-runtime/bin.js +1148 -70
- 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 +112 -8
- 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 +27 -13
- 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 +765 -49
- package/src/lib/process-execution-broker/platform-sandbox.js +4233 -138
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +3856 -0
- package/src/lib/project-mcp-trust.js +21 -26
- package/src/lib/protocol-replay.js +19 -12
- package/src/lib/repl-bang-memorize.js +67 -10
- package/src/lib/settings-hooks.cjs +13 -0
- package/src/lib/skill-loader.js +83 -10
- package/src/lib/slash-commands.js +27 -4
- package/src/lib/sync-credentials.js +5 -4
- package/src/lib/turn-binding.js +8 -6
- package/src/repl/agent-repl.js +117 -31
- package/src/repl/repl-turn-binding.js +5 -2
- package/src/runtime/agent-core.js +699 -70
- package/src/runtime/agent-runtime.js +13 -1
- package/src/runtime/coding-agent-contract-shared.cjs +3 -3
- package/src/runtime/headless-runner.js +105 -7
- 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/ChatBubbleRenderer-C7bofJuA.js +0 -1
- 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/Terminal-CsMLKIoV.js +0 -3
- 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/commands/context.js
CHANGED
|
@@ -330,14 +330,81 @@ export function registerContextCommand(program) {
|
|
|
330
330
|
);
|
|
331
331
|
}
|
|
332
332
|
if (sourceReport.skillCache.descriptors.resident > 0) {
|
|
333
|
+
const skillDescriptors = sourceReport.skillCache.descriptors;
|
|
334
|
+
const skillBodies = sourceReport.skillCache.bodies;
|
|
333
335
|
logger.log("");
|
|
334
336
|
logger.log(
|
|
335
337
|
chalk.gray(
|
|
336
|
-
` Skill cache: ${
|
|
337
|
-
|
|
338
|
+
` Skill cache: ${skillDescriptors.resident} descriptors ` +
|
|
339
|
+
`(${skillDescriptors.estimatedTokens} estimated descriptor-token equivalents), ` +
|
|
340
|
+
`${skillBodies.resident} bodies resident ` +
|
|
341
|
+
`(${skillBodies.estimatedTokensResident} estimated body-token equivalents), ` +
|
|
338
342
|
`${sourceReport.skillCache.savings.estimatedTokensAvoided} estimated tokens kept lazy`,
|
|
339
343
|
),
|
|
340
344
|
);
|
|
345
|
+
logger.log(
|
|
346
|
+
chalk.gray(
|
|
347
|
+
` Descriptor prompt returns: ${skillDescriptors.contextLoads} / ` +
|
|
348
|
+
`${skillDescriptors.contextTokens} estimated context tokens`,
|
|
349
|
+
),
|
|
350
|
+
);
|
|
351
|
+
logger.log(
|
|
352
|
+
chalk.gray(
|
|
353
|
+
` On-demand reads: ${skillBodies.cacheMisses} disk / ` +
|
|
354
|
+
`${skillBodies.cacheHits} cache; cache reuse avoided ` +
|
|
355
|
+
`${skillBodies.estimatedTokensAvoidedByCache} body-token equivalents of disk reads`,
|
|
356
|
+
),
|
|
357
|
+
);
|
|
358
|
+
logger.log(
|
|
359
|
+
chalk.gray(
|
|
360
|
+
` Prompt injections: ${skillBodies.contextLoads} loads / ` +
|
|
361
|
+
`${skillBodies.contextTokens} estimated context tokens`,
|
|
362
|
+
),
|
|
363
|
+
);
|
|
364
|
+
const activeBodies = [...skillBodies.entries]
|
|
365
|
+
.filter((entry) => entry.loads > 0 || entry.contextLoads > 0)
|
|
366
|
+
.sort(
|
|
367
|
+
(a, b) =>
|
|
368
|
+
b.contextTokens - a.contextTokens ||
|
|
369
|
+
b.loads - a.loads ||
|
|
370
|
+
a.id.localeCompare(b.id),
|
|
371
|
+
);
|
|
372
|
+
for (const entry of activeBodies.slice(0, 8)) {
|
|
373
|
+
logger.log(
|
|
374
|
+
chalk.gray(
|
|
375
|
+
` ${entry.id} [${entry.source}]: ${entry.estimatedTokens} token body; ` +
|
|
376
|
+
`${entry.cacheMisses} disk / ${entry.cacheHits} cache reads; ` +
|
|
377
|
+
`${entry.contextLoads} prompt loads / ${entry.contextTokens} tokens`,
|
|
378
|
+
),
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
if (activeBodies.length > 8) {
|
|
382
|
+
logger.log(
|
|
383
|
+
chalk.gray(` ... ${activeBodies.length - 8} more active bodies`),
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
const usedDescriptors = [...skillDescriptors.entries]
|
|
387
|
+
.filter((entry) => entry.contextLoads > 0)
|
|
388
|
+
.sort(
|
|
389
|
+
(a, b) =>
|
|
390
|
+
b.contextTokens - a.contextTokens ||
|
|
391
|
+
a.id.localeCompare(b.id),
|
|
392
|
+
);
|
|
393
|
+
for (const entry of usedDescriptors.slice(0, 8)) {
|
|
394
|
+
logger.log(
|
|
395
|
+
chalk.gray(
|
|
396
|
+
` descriptor ${entry.id} [${entry.source}]: ` +
|
|
397
|
+
`${entry.contextLoads} prompt returns / ${entry.contextTokens} tokens`,
|
|
398
|
+
),
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
if (usedDescriptors.length > 8) {
|
|
402
|
+
logger.log(
|
|
403
|
+
chalk.gray(
|
|
404
|
+
` ... ${usedDescriptors.length - 8} more used descriptors`,
|
|
405
|
+
),
|
|
406
|
+
);
|
|
407
|
+
}
|
|
341
408
|
}
|
|
342
409
|
if (sourceReport.optimizations.length > 0) {
|
|
343
410
|
logger.log("");
|
package/src/data/changelog.json
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "CHANGELOG.md",
|
|
3
3
|
"releases": [
|
|
4
|
+
{
|
|
5
|
+
"productVersion": null,
|
|
6
|
+
"cliVersion": "0.162.182",
|
|
7
|
+
"cliVersions": ["0.162.181", "0.162.182"],
|
|
8
|
+
"date": "2026-07-27",
|
|
9
|
+
"title": "",
|
|
10
|
+
"sections": [
|
|
11
|
+
{
|
|
12
|
+
"heading": "Fixed — cc CLI 0.162.182: attested native plugin sandbox closure",
|
|
13
|
+
"body": "> `chainlesschain` **0.162.181 → 0.162.182** (2026-07-27).\n> CLI-only release; `@chainlesschain/personal-data-hub` remains **0.4.57**\n> and `@chainlesschain/agent-sdk` remains **0.1.7**.\n\n- **One-shot native plugin execution contracts**: policy-bearing native plugin\n bins must preserve the resolver-issued target, literal argv, plugin root, and\n executable identity through the process broker. Replayed, copied, stale, or\n asynchronous contracts fail closed before a target process is started.\n- **Linux strong boundary completion**: strict native launches accept only\n attested static ELF executables for the current architecture, reject dynamic\n loaders and malformed program headers, pin the plugin tree through file\n descriptors, and enter the fixed bubblewrap filesystem/network policy\n without exposing a mutable host path.\n- **Cross-platform identity hardening**: Windows AppContainer launches retain\n attested target handles, while platform adapters revalidate executable and\n plugin identities across probe, spawn, IPC, and detached launch boundaries.\n- **Release validation gate**: the exact release commit must pass `CLI CI` and\n `CLI Strict Sandbox` on their configured Ubuntu, Windows, and macOS runners;\n local tests are supplementary and cannot authorize publication."
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"productVersion": null,
|
|
19
|
+
"cliVersion": "0.162.181",
|
|
20
|
+
"cliVersions": ["0.162.181"],
|
|
21
|
+
"date": "2026-07-26",
|
|
22
|
+
"title": "",
|
|
23
|
+
"sections": [
|
|
24
|
+
{
|
|
25
|
+
"heading": "Added — cc CLI 0.162.181 + PDH 0.4.57 + Agent SDK 0.1.7: sandbox contracts and complete collection",
|
|
26
|
+
"body": "> `chainlesschain` **0.162.181** bundles\n> `@chainlesschain/personal-data-hub` **0.4.57** and co-releases\n> `@chainlesschain/agent-sdk` **0.1.7** (2026-07-26).\n\n- **Enforced process boundaries**: the CLI process broker preserves native\n sandbox identity across foreground, detached, IPC, plugin hook, MCP, monitor,\n and LSP launches. Plugin manifests can require explicit sandbox boundaries,\n and Linux launches attest the primitives actually applied.\n- **Runtime and protocol convergence**: restore compatibility-shim exports,\n keep permission-decision fields stable in golden transcripts, and carry the\n current background-session and event-recovery contract through the Agent SDK.\n- **Complete resumable collection**: PDH adapters use explicit cursors and\n bounded page budgets across local databases, desktop clients, mobile APIs,\n maps, social, messaging, education, music, health, shopping, and travel\n sources. Partial or unreadable SQLite results now fail closed instead of\n silently advancing checkpoints.\n- **Release validation**: PDH 282 files / 4,528 tests, Agent SDK build plus\n 50 tests, CLI sandbox/plugin focused regression, Web Panel build, and\n isolated Git-worktree/WebSocket regressions passed before publication."
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
4
30
|
{
|
|
5
31
|
"productVersion": null,
|
|
6
32
|
"cliVersion": "0.162.180",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* PtyManager — ESM mirror of `desktop-app-vue/src/main/terminal/PtyManager.js`.
|
|
3
3
|
*
|
|
4
|
-
* Keep
|
|
5
|
-
* process; this one targets `cc ui` (Node ESM)
|
|
6
|
-
*
|
|
4
|
+
* Keep their protocol and session behavior in sync. The desktop copy targets
|
|
5
|
+
* Electron's CJS main process; this one targets `cc ui` (Node ESM), whose host
|
|
6
|
+
* injects its own trusted workspace-policy resolver.
|
|
7
7
|
*
|
|
8
8
|
* Design notes — see docs/design/Android_Remote_Terminal_Plan_A.md §4:
|
|
9
9
|
* - node-pty loaded lazily so the module loads without the native
|
|
@@ -44,6 +44,24 @@ function resolveShellCmd(shell) {
|
|
|
44
44
|
return shell;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
function validatePinnedSandboxPolicy(policy) {
|
|
48
|
+
if (policy == null) return null;
|
|
49
|
+
if (
|
|
50
|
+
typeof policy !== "object" ||
|
|
51
|
+
Array.isArray(policy) ||
|
|
52
|
+
typeof policy.then === "function" ||
|
|
53
|
+
!Array.isArray(policy.requiredBoundaries) ||
|
|
54
|
+
policy.requiredBoundaries.length === 0 ||
|
|
55
|
+
!Object.isFrozen(policy) ||
|
|
56
|
+
!Object.isFrozen(policy.requiredBoundaries)
|
|
57
|
+
) {
|
|
58
|
+
const error = new TypeError("invalid_pty_sandbox_policy");
|
|
59
|
+
error.code = "ERR_PTY_SANDBOX_POLICY_INVALID";
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
return policy;
|
|
63
|
+
}
|
|
64
|
+
|
|
47
65
|
class PtySession {
|
|
48
66
|
constructor({ id, shell, cwd, cols, rows, proc, createdAt, ringBuffer }) {
|
|
49
67
|
this.id = id;
|
|
@@ -65,6 +83,16 @@ export class PtyManager extends EventEmitter {
|
|
|
65
83
|
constructor(opts = {}) {
|
|
66
84
|
super();
|
|
67
85
|
this.config = { ...DEFAULT_CONFIG, ...(opts.config || {}) };
|
|
86
|
+
const resolveSandboxPolicy =
|
|
87
|
+
opts.resolveSandboxPolicy ?? opts._deps?.resolveSandboxPolicy ?? null;
|
|
88
|
+
if (
|
|
89
|
+
resolveSandboxPolicy !== null &&
|
|
90
|
+
typeof resolveSandboxPolicy !== "function"
|
|
91
|
+
) {
|
|
92
|
+
throw new TypeError("resolveSandboxPolicy must be a function or null");
|
|
93
|
+
}
|
|
94
|
+
this._policyCwd = opts.policyCwd || process.cwd();
|
|
95
|
+
this._resolveSandboxPolicy = resolveSandboxPolicy;
|
|
68
96
|
this._deps = {
|
|
69
97
|
loadNodePty: opts._deps?.loadNodePty || (() => require("node-pty")),
|
|
70
98
|
spawnPty: opts._deps?.spawnPty || null,
|
|
@@ -92,6 +120,19 @@ export class PtyManager extends EventEmitter {
|
|
|
92
120
|
throw new Error("shell_not_allowed");
|
|
93
121
|
}
|
|
94
122
|
|
|
123
|
+
const cwd = req.cwd || this.config.defaultCwd || process.cwd();
|
|
124
|
+
// A remote cwd may discover a stricter policy, but it must never replace
|
|
125
|
+
// the fixed workspace root supplied by the host. Resolve and validate the
|
|
126
|
+
// pinned policy before loading node-pty or allocating a native terminal.
|
|
127
|
+
const sandboxPolicy = this._resolveSandboxPolicy
|
|
128
|
+
? validatePinnedSandboxPolicy(
|
|
129
|
+
this._resolveSandboxPolicy({
|
|
130
|
+
workspaceCwd: this._policyCwd,
|
|
131
|
+
executionCwd: cwd,
|
|
132
|
+
}),
|
|
133
|
+
)
|
|
134
|
+
: null;
|
|
135
|
+
|
|
95
136
|
let pty;
|
|
96
137
|
try {
|
|
97
138
|
pty = this._deps.loadNodePty();
|
|
@@ -101,7 +142,6 @@ export class PtyManager extends EventEmitter {
|
|
|
101
142
|
throw err;
|
|
102
143
|
}
|
|
103
144
|
|
|
104
|
-
const cwd = req.cwd || this.config.defaultCwd || process.cwd();
|
|
105
145
|
const cols = Number.isFinite(req.cols) ? req.cols : 80;
|
|
106
146
|
const rows = Number.isFinite(req.rows) ? req.rows : 24;
|
|
107
147
|
const cmd = resolveShellCmd(shell);
|
|
@@ -123,6 +163,7 @@ export class PtyManager extends EventEmitter {
|
|
|
123
163
|
origin: "terminal:pty",
|
|
124
164
|
policy: "allow",
|
|
125
165
|
scope: "terminal",
|
|
166
|
+
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
126
167
|
});
|
|
127
168
|
|
|
128
169
|
const sessionId = randomUUID();
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* log, latestSeq, [reattached, replayed,
|
|
13
13
|
* replayTruncated]}
|
|
14
14
|
* bg-prompt {bgId, text} → {type:"bg-prompt", bgId, sent}
|
|
15
|
+
* bg-answer {bgId, requestId, binding, answer}
|
|
16
|
+
* → {type:"bg-answer", bgId, sent}
|
|
15
17
|
* bg-stop-turn {bgId} → {type:"bg-stop-turn", bgId, sent}
|
|
16
18
|
* bg-detach {bgId} → {type:"bg-detach", bgId}
|
|
17
19
|
* bg-stop {bgId} → {type:"bg-stop", session} (kill whole session)
|
|
@@ -340,6 +342,42 @@ export async function handleBgPrompt(server, clientId, id, ws, message) {
|
|
|
340
342
|
server._send(ws, { id, type: "bg-prompt", bgId: message.bgId, sent });
|
|
341
343
|
}
|
|
342
344
|
|
|
345
|
+
export async function handleBgAnswer(server, clientId, id, ws, message) {
|
|
346
|
+
const entry = requireAttachment(server, clientId, id, ws, message);
|
|
347
|
+
if (!entry) return;
|
|
348
|
+
const requestId = String(message.requestId || "");
|
|
349
|
+
if (!requestId) {
|
|
350
|
+
return sendError(server, id, ws, "NO_REQUEST_ID", "requestId required");
|
|
351
|
+
}
|
|
352
|
+
if (
|
|
353
|
+
!message.binding ||
|
|
354
|
+
typeof message.binding !== "object" ||
|
|
355
|
+
Array.isArray(message.binding)
|
|
356
|
+
) {
|
|
357
|
+
return sendError(
|
|
358
|
+
server,
|
|
359
|
+
id,
|
|
360
|
+
ws,
|
|
361
|
+
"NO_INTERACTION_BINDING",
|
|
362
|
+
"interaction binding required",
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
const sent = entry.conn.send({
|
|
366
|
+
type: "interaction_response",
|
|
367
|
+
requestId,
|
|
368
|
+
binding: message.binding,
|
|
369
|
+
answer: message.answer,
|
|
370
|
+
...(message.error ? { error: message.error } : {}),
|
|
371
|
+
});
|
|
372
|
+
server._send(ws, {
|
|
373
|
+
id,
|
|
374
|
+
type: "bg-answer",
|
|
375
|
+
bgId: message.bgId,
|
|
376
|
+
requestId,
|
|
377
|
+
sent,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
343
381
|
export async function handleBgStopTurn(server, clientId, id, ws, message) {
|
|
344
382
|
const entry = requireAttachment(server, clientId, id, ws, message);
|
|
345
383
|
if (!entry) return;
|
|
@@ -182,6 +182,7 @@ export function createWsMessageDispatcher(server) {
|
|
|
182
182
|
"bg-view": () => server._handleBgView(id, ws, message),
|
|
183
183
|
"bg-attach": () => server._handleBgAttach(clientId, id, ws, message),
|
|
184
184
|
"bg-prompt": () => server._handleBgPrompt(clientId, id, ws, message),
|
|
185
|
+
"bg-answer": () => server._handleBgAnswer(clientId, id, ws, message),
|
|
185
186
|
"bg-stop-turn": () =>
|
|
186
187
|
server._handleBgStopTurn(clientId, id, ws, message),
|
|
187
188
|
"bg-detach": () => server._handleBgDetach(clientId, id, ws, message),
|
|
@@ -12,12 +12,15 @@ import { RemoteCommandLedger } from "../../harness/remote-command-ledger.js";
|
|
|
12
12
|
import {
|
|
13
13
|
ORIGIN,
|
|
14
14
|
assertCanApprove,
|
|
15
|
+
assertCanAnswerInteraction,
|
|
15
16
|
describeAuthorityChain,
|
|
16
17
|
} from "../../lib/agent-authority.js";
|
|
18
|
+
import { hasCompleteInteractionBinding } from "../../lib/interaction-binding.js";
|
|
17
19
|
|
|
18
20
|
const CLIENT_EVENT_SCOPES = Object.freeze({
|
|
19
21
|
prompt: "prompt",
|
|
20
22
|
"approval.resolve": "approve",
|
|
23
|
+
"question.answer": "prompt",
|
|
21
24
|
interrupt: "interrupt",
|
|
22
25
|
});
|
|
23
26
|
|
|
@@ -30,7 +33,8 @@ function audit(server, entry) {
|
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
/**
|
|
33
|
-
* Apply a remote-client control event (prompt / approval.resolve /
|
|
36
|
+
* Apply a remote-client control event (prompt / approval.resolve /
|
|
37
|
+
* question.answer / interrupt)
|
|
34
38
|
* idempotently when it carries a stable `commandId`. This is the ACTUAL takeover
|
|
35
39
|
* path — a paired mobile/web device driving the host agent — and it does NOT
|
|
36
40
|
* flow through message-dispatcher's execute/stream ledger, so without this a
|
|
@@ -448,7 +452,7 @@ export async function handleRemoteSessionPublish(
|
|
|
448
452
|
requiredScope || "observe",
|
|
449
453
|
);
|
|
450
454
|
// Runtime/output events are host-only. Remote clients may publish only the
|
|
451
|
-
//
|
|
455
|
+
// explicitly scoped control event types above.
|
|
452
456
|
if (!requiredScope && session.hostClientId !== clientId) {
|
|
453
457
|
throw new Error("Only the host can publish runtime events");
|
|
454
458
|
}
|
|
@@ -468,6 +472,24 @@ export async function handleRemoteSessionPublish(
|
|
|
468
472
|
) {
|
|
469
473
|
throw new Error("prompt content is required");
|
|
470
474
|
}
|
|
475
|
+
if (message.event.type === "question.answer") {
|
|
476
|
+
if (
|
|
477
|
+
typeof message.event.requestId !== "string" ||
|
|
478
|
+
!message.event.requestId
|
|
479
|
+
) {
|
|
480
|
+
throw new Error("question requestId is required");
|
|
481
|
+
}
|
|
482
|
+
if (!hasCompleteInteractionBinding(message.event.binding)) {
|
|
483
|
+
throw new Error("complete question binding is required");
|
|
484
|
+
}
|
|
485
|
+
assertCanAnswerInteraction({
|
|
486
|
+
origin: ORIGIN.REMOTE,
|
|
487
|
+
authenticated: true,
|
|
488
|
+
scopes: ["prompt"],
|
|
489
|
+
principalId: clientId,
|
|
490
|
+
sessionId: message.remoteSessionId,
|
|
491
|
+
});
|
|
492
|
+
}
|
|
471
493
|
// Authority (§"权限来源与跨 Agent 授权边界"): a remote *approve* is honored
|
|
472
494
|
// only from an authenticated, approve-scoped device — the SINGLE
|
|
473
495
|
// authoritative rule, not just the per-device scope check above, so the
|
|
@@ -531,7 +553,9 @@ export async function handleRemoteSessionPublish(
|
|
|
531
553
|
? "control.prompt"
|
|
532
554
|
: message.event.type === "approval.resolve"
|
|
533
555
|
? "control.approval"
|
|
534
|
-
: "
|
|
556
|
+
: message.event.type === "question.answer"
|
|
557
|
+
? "control.question"
|
|
558
|
+
: "control.interrupt";
|
|
535
559
|
audit(server, {
|
|
536
560
|
sessionId: message.remoteSessionId,
|
|
537
561
|
actor: clientId,
|
|
@@ -548,11 +572,23 @@ export async function handleRemoteSessionPublish(
|
|
|
548
572
|
authority: describeAuthorityChain(approvalEnvelope || {}),
|
|
549
573
|
forwarded: true,
|
|
550
574
|
}
|
|
551
|
-
:
|
|
575
|
+
: message.event.type === "question.answer"
|
|
576
|
+
? {
|
|
577
|
+
requestId: message.event.requestId,
|
|
578
|
+
authority: describeAuthorityChain({
|
|
579
|
+
origin: ORIGIN.REMOTE,
|
|
580
|
+
authenticated: true,
|
|
581
|
+
scopes: ["prompt"],
|
|
582
|
+
principalId: clientId,
|
|
583
|
+
sessionId: message.remoteSessionId,
|
|
584
|
+
}),
|
|
585
|
+
forwarded: true,
|
|
586
|
+
}
|
|
587
|
+
: { forwarded: true },
|
|
552
588
|
});
|
|
553
589
|
// Hand the event to the host process. `message.event` carries any
|
|
554
|
-
// echoed approval binding, so the host gate can
|
|
555
|
-
// tampered verdict.
|
|
590
|
+
// echoed approval or interaction binding, so the host gate can
|
|
591
|
+
// reject a stale / tampered verdict.
|
|
556
592
|
server._send(hostTarget.ws, {
|
|
557
593
|
type: "remote-session-control",
|
|
558
594
|
remoteSessionId: message.remoteSessionId,
|
|
@@ -599,6 +635,29 @@ export async function handleRemoteSessionPublish(
|
|
|
599
635
|
// a verdict whose binding doesn't match the pending request.
|
|
600
636
|
binding: message.event.binding ?? null,
|
|
601
637
|
});
|
|
638
|
+
} else if (message.event.type === "question.answer") {
|
|
639
|
+
const authority = {
|
|
640
|
+
origin: ORIGIN.REMOTE,
|
|
641
|
+
authenticated: true,
|
|
642
|
+
scopes: ["prompt"],
|
|
643
|
+
principalId: clientId,
|
|
644
|
+
sessionId: message.remoteSessionId,
|
|
645
|
+
};
|
|
646
|
+
audit(server, {
|
|
647
|
+
sessionId: message.remoteSessionId,
|
|
648
|
+
actor: clientId,
|
|
649
|
+
action: "control.question",
|
|
650
|
+
detail: {
|
|
651
|
+
requestId: message.event.requestId,
|
|
652
|
+
authority: describeAuthorityChain(authority),
|
|
653
|
+
},
|
|
654
|
+
});
|
|
655
|
+
await handleSessionAnswer(server, message.id, ws, {
|
|
656
|
+
...controlMessage,
|
|
657
|
+
requestId: message.event.requestId,
|
|
658
|
+
answer: message.event.answer ?? null,
|
|
659
|
+
binding: message.event.binding,
|
|
660
|
+
});
|
|
602
661
|
} else if (message.event.type === "interrupt") {
|
|
603
662
|
audit(server, {
|
|
604
663
|
sessionId: message.remoteSessionId,
|
|
@@ -95,6 +95,7 @@ import {
|
|
|
95
95
|
import { handleLlmChat } from "./llm-chat-protocol.js";
|
|
96
96
|
import {
|
|
97
97
|
cleanupBgAttachments,
|
|
98
|
+
handleBgAnswer,
|
|
98
99
|
handleBgAttach,
|
|
99
100
|
handleBgDetach,
|
|
100
101
|
handleBgList,
|
|
@@ -113,6 +114,7 @@ import {
|
|
|
113
114
|
handleArtifactShow,
|
|
114
115
|
} from "./artifact-protocol.js";
|
|
115
116
|
import { executionBroker } from "../../lib/process-execution-broker/index.js";
|
|
117
|
+
import { collectWorkspacePluginBinSandboxPolicy } from "../../lib/plugin-runtime/bin.js";
|
|
116
118
|
|
|
117
119
|
export const _deps = {
|
|
118
120
|
spawn: (...args) => executionBroker.spawn(...args),
|
|
@@ -569,7 +571,8 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
569
571
|
}
|
|
570
572
|
const rulesMod = await import("../../lib/permission-rules.cjs");
|
|
571
573
|
const mod = rulesMod.default || rulesMod;
|
|
572
|
-
if (!mod.parseRule(message.rule))
|
|
574
|
+
if (!mod.parseRule(message.rule))
|
|
575
|
+
throw new Error("invalid permission rule");
|
|
573
576
|
const { addRule } = await import("../../lib/settings-loader.cjs");
|
|
574
577
|
const scope = ["project", "local", "user"].includes(message.scope)
|
|
575
578
|
? message.scope
|
|
@@ -767,6 +770,11 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
767
770
|
return handleBgPrompt(this, clientId, id, ws, message);
|
|
768
771
|
}
|
|
769
772
|
|
|
773
|
+
/** @private — answer a bound interaction in an attached background session */
|
|
774
|
+
async _handleBgAnswer(clientId, id, ws, message) {
|
|
775
|
+
return handleBgAnswer(this, clientId, id, ws, message);
|
|
776
|
+
}
|
|
777
|
+
|
|
770
778
|
/** @private — stop the current turn of an attached background session */
|
|
771
779
|
async _handleBgStopTurn(clientId, id, ws, message) {
|
|
772
780
|
return handleBgStopTurn(this, clientId, id, ws, message);
|
|
@@ -1208,7 +1216,15 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
1208
1216
|
if (this._taskManager) return this._taskManager;
|
|
1209
1217
|
const { BackgroundTaskManager } =
|
|
1210
1218
|
await import("../../harness/background-task-manager.js");
|
|
1211
|
-
this._taskManager = new BackgroundTaskManager({
|
|
1219
|
+
this._taskManager = new BackgroundTaskManager({
|
|
1220
|
+
recoverOnStart: true,
|
|
1221
|
+
policyCwd: this.projectRoot,
|
|
1222
|
+
resolveSandboxPolicy: ({ workspaceCwd, executionCwd }) =>
|
|
1223
|
+
collectWorkspacePluginBinSandboxPolicy({
|
|
1224
|
+
workspaceCwd,
|
|
1225
|
+
executionCwd,
|
|
1226
|
+
}),
|
|
1227
|
+
});
|
|
1212
1228
|
this._subscribeTaskNotifications();
|
|
1213
1229
|
return this._taskManager;
|
|
1214
1230
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { existsSync, mkdirSync, appendFileSync, readFileSync } from "node:fs";
|
|
12
|
-
import { join } from "node:path";
|
|
12
|
+
import { join, resolve } from "node:path";
|
|
13
13
|
import { createHash } from "node:crypto";
|
|
14
14
|
import { EventEmitter } from "node:events";
|
|
15
15
|
import { getHomeDir } from "../lib/paths.js";
|
|
@@ -42,9 +42,55 @@ const RECOVERABLE_TASK_STATUSES = new Set([
|
|
|
42
42
|
TaskStatus.RUNNING,
|
|
43
43
|
]);
|
|
44
44
|
|
|
45
|
+
function validatePinnedSandboxPolicy(policy) {
|
|
46
|
+
if (policy == null) return null;
|
|
47
|
+
if (
|
|
48
|
+
typeof policy !== "object" ||
|
|
49
|
+
Array.isArray(policy) ||
|
|
50
|
+
typeof policy.then === "function" ||
|
|
51
|
+
!Array.isArray(policy.requiredBoundaries) ||
|
|
52
|
+
policy.requiredBoundaries.length === 0 ||
|
|
53
|
+
policy.requiredBoundaries.some(
|
|
54
|
+
(boundary) => typeof boundary !== "string" || boundary.length === 0,
|
|
55
|
+
) ||
|
|
56
|
+
!Object.isFrozen(policy) ||
|
|
57
|
+
!Object.isFrozen(policy.requiredBoundaries)
|
|
58
|
+
) {
|
|
59
|
+
const error = new TypeError("invalid_background_task_sandbox_policy");
|
|
60
|
+
error.code = "ERR_BACKGROUND_TASK_SANDBOX_POLICY_INVALID";
|
|
61
|
+
error.sandboxReason = "invalid_background_task_sandbox_policy";
|
|
62
|
+
error.sandboxFailClosed = true;
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
return policy;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function createUnsupportedSandboxError(sandboxPolicy) {
|
|
69
|
+
const requiredBoundaries = [...sandboxPolicy.requiredBoundaries];
|
|
70
|
+
const error = new Error(
|
|
71
|
+
`Background tasks cannot run without their required sandbox boundaries: ${requiredBoundaries.join(", ")}`,
|
|
72
|
+
);
|
|
73
|
+
error.code = "ERR_BACKGROUND_TASK_SANDBOX_UNSUPPORTED";
|
|
74
|
+
error.sandboxReason = "background_execution_unsupported";
|
|
75
|
+
error.sandboxFailClosed = true;
|
|
76
|
+
error.requiredBoundaries = requiredBoundaries;
|
|
77
|
+
error.actualGuarantees = [];
|
|
78
|
+
error.missingBoundaries = [...requiredBoundaries];
|
|
79
|
+
error.sandboxBackend = null;
|
|
80
|
+
error.sandboxCandidateBackend = null;
|
|
81
|
+
return error;
|
|
82
|
+
}
|
|
83
|
+
|
|
45
84
|
export class BackgroundTaskManager extends EventEmitter {
|
|
46
85
|
constructor(options = {}) {
|
|
47
86
|
super();
|
|
87
|
+
const resolveSandboxPolicy = options.resolveSandboxPolicy ?? null;
|
|
88
|
+
if (
|
|
89
|
+
resolveSandboxPolicy !== null &&
|
|
90
|
+
typeof resolveSandboxPolicy !== "function"
|
|
91
|
+
) {
|
|
92
|
+
throw new TypeError("resolveSandboxPolicy must be a function or null");
|
|
93
|
+
}
|
|
48
94
|
this.maxConcurrent = options.maxConcurrent || 3;
|
|
49
95
|
this.heartbeatTimeout = options.heartbeatTimeout || 60000;
|
|
50
96
|
this.historyLimit = options.historyLimit || 50;
|
|
@@ -54,6 +100,10 @@ export class BackgroundTaskManager extends EventEmitter {
|
|
|
54
100
|
`${process.pid}@${process.platform}`;
|
|
55
101
|
this.recoveryPolicy = options.recoveryPolicy || "claim-stale";
|
|
56
102
|
this.staleNodeTimeout = options.staleNodeTimeout || 5 * 60 * 1000;
|
|
103
|
+
this._policyCwd = resolveSandboxPolicy
|
|
104
|
+
? resolve(options.policyCwd || process.cwd())
|
|
105
|
+
: null;
|
|
106
|
+
this._resolveSandboxPolicy = resolveSandboxPolicy;
|
|
57
107
|
this.tasks = new Map();
|
|
58
108
|
this.processes = new Map();
|
|
59
109
|
this._checkInterval = null;
|
|
@@ -72,12 +122,15 @@ export class BackgroundTaskManager extends EventEmitter {
|
|
|
72
122
|
);
|
|
73
123
|
}
|
|
74
124
|
|
|
125
|
+
const cwd = spec.cwd || process.cwd();
|
|
126
|
+
this._assertSandboxSupported(cwd);
|
|
127
|
+
|
|
75
128
|
const id = `task-${Date.now()}-${createHash("sha256").update(Math.random().toString()).digest("hex").slice(0, 6)}`;
|
|
76
129
|
const task = {
|
|
77
130
|
id,
|
|
78
131
|
type: spec.type || "shell",
|
|
79
132
|
command: spec.command,
|
|
80
|
-
cwd
|
|
133
|
+
cwd,
|
|
81
134
|
description: spec.description || spec.command,
|
|
82
135
|
status: TaskStatus.PENDING,
|
|
83
136
|
createdAt: Date.now(),
|
|
@@ -111,6 +164,8 @@ export class BackgroundTaskManager extends EventEmitter {
|
|
|
111
164
|
throw new Error(`Task ${taskId} is not pending (status: ${task.status})`);
|
|
112
165
|
}
|
|
113
166
|
|
|
167
|
+
this._assertSandboxSupported(task.cwd);
|
|
168
|
+
|
|
114
169
|
task.status = TaskStatus.RUNNING;
|
|
115
170
|
task.startedAt = Date.now();
|
|
116
171
|
task.lastHeartbeat = Date.now();
|
|
@@ -185,6 +240,19 @@ export class BackgroundTaskManager extends EventEmitter {
|
|
|
185
240
|
return task;
|
|
186
241
|
}
|
|
187
242
|
|
|
243
|
+
_assertSandboxSupported(executionCwd) {
|
|
244
|
+
if (!this._resolveSandboxPolicy) return;
|
|
245
|
+
const sandboxPolicy = validatePinnedSandboxPolicy(
|
|
246
|
+
this._resolveSandboxPolicy({
|
|
247
|
+
workspaceCwd: this._policyCwd,
|
|
248
|
+
executionCwd,
|
|
249
|
+
}),
|
|
250
|
+
);
|
|
251
|
+
if (sandboxPolicy) {
|
|
252
|
+
throw createUnsupportedSandboxError(sandboxPolicy);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
188
256
|
get(taskId) {
|
|
189
257
|
return this.tasks.get(taskId) || null;
|
|
190
258
|
}
|
|
@@ -17,6 +17,8 @@ import { withFileLock } from "../lib/with-file-lock.js";
|
|
|
17
17
|
import { getConfigPath } from "../lib/paths.js";
|
|
18
18
|
import { createHash } from "node:crypto";
|
|
19
19
|
import { hostname } from "node:os";
|
|
20
|
+
import { mkdirSync } from "node:fs";
|
|
21
|
+
import { dirname } from "node:path";
|
|
20
22
|
|
|
21
23
|
const FLAG_REGISTRY = {
|
|
22
24
|
BACKGROUND_TASKS: {
|
|
@@ -115,14 +117,19 @@ export function listFeatures() {
|
|
|
115
117
|
export function setFeature(name, value) {
|
|
116
118
|
// Serialize the read-modify-write across processes so two concurrent
|
|
117
119
|
// `cc config features enable/disable` invocations don't clobber each other
|
|
118
|
-
// (and to space out writes so the atomic rename doesn't collide).
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
120
|
+
// (and to space out writes so the atomic rename doesn't collide).
|
|
121
|
+
const configPath = getConfigPath();
|
|
122
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
123
|
+
withFileLock(
|
|
124
|
+
configPath,
|
|
125
|
+
() => {
|
|
126
|
+
const config = loadConfig({ failIfUnavailable: true });
|
|
127
|
+
if (!config.features) config.features = {};
|
|
128
|
+
config.features[name] = value;
|
|
129
|
+
saveConfig(config);
|
|
130
|
+
},
|
|
131
|
+
{ failIfUnavailable: true },
|
|
132
|
+
);
|
|
126
133
|
}
|
|
127
134
|
|
|
128
135
|
export function getFlagInfo(name) {
|