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
|
@@ -13,12 +13,16 @@
|
|
|
13
13
|
* Store: ~/.chainlesschain/trusted-project-mcp.json { [absPath]: {fingerprint, trustedAt} }
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import fs from "node:fs";
|
|
17
16
|
import path from "node:path";
|
|
18
17
|
import { createHash } from "node:crypto";
|
|
19
18
|
import { getHomeDir } from "./paths.js";
|
|
19
|
+
import { withFileLock } from "./with-file-lock.js";
|
|
20
|
+
import {
|
|
21
|
+
mutateSecurityStore,
|
|
22
|
+
readSecurityStore,
|
|
23
|
+
} from "./durable-security-store.js";
|
|
20
24
|
|
|
21
|
-
export const _deps = {
|
|
25
|
+
export const _deps = { withFileLock };
|
|
22
26
|
|
|
23
27
|
function storePath(opts = {}) {
|
|
24
28
|
return (
|
|
@@ -33,13 +37,7 @@ export function projectMcpFingerprint(content) {
|
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
function readStore(opts) {
|
|
36
|
-
|
|
37
|
-
const raw = _deps.fs.readFileSync(storePath(opts), "utf-8");
|
|
38
|
-
const data = JSON.parse(raw);
|
|
39
|
-
return data && typeof data === "object" ? data : {};
|
|
40
|
-
} catch {
|
|
41
|
-
return {};
|
|
42
|
-
}
|
|
40
|
+
return readSecurityStore(storePath(opts), "project MCP trust");
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
/**
|
|
@@ -61,23 +59,20 @@ export function checkProjectMcpTrust(file, content, opts = {}) {
|
|
|
61
59
|
/** Record (or re-record) the trusted fingerprint for a file. */
|
|
62
60
|
export function recordProjectMcpTrust(file, content, opts = {}) {
|
|
63
61
|
const target = storePath(opts);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
} catch {
|
|
79
|
-
return false; // best-effort — a failed record just re-prompts next run
|
|
80
|
-
}
|
|
62
|
+
return mutateSecurityStore(
|
|
63
|
+
target,
|
|
64
|
+
"project MCP trust",
|
|
65
|
+
(store) => {
|
|
66
|
+
store[path.resolve(file)] = {
|
|
67
|
+
fingerprint: projectMcpFingerprint(content),
|
|
68
|
+
trustedAt: new Date(
|
|
69
|
+
typeof opts.now === "number" ? opts.now : Date.now(),
|
|
70
|
+
).toISOString(),
|
|
71
|
+
};
|
|
72
|
+
return true;
|
|
73
|
+
},
|
|
74
|
+
{ lock: _deps.withFileLock },
|
|
75
|
+
);
|
|
81
76
|
}
|
|
82
77
|
|
|
83
78
|
/** Truthy CC_PROJECT_MCP_TRUST → the user explicitly re-trusts this run. */
|
|
@@ -15,10 +15,11 @@
|
|
|
15
15
|
* client must never receive a vN+1 field; a recording that violates that is
|
|
16
16
|
* a compat bug this catches deterministically, offline, in CI.
|
|
17
17
|
*
|
|
18
|
-
* The
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* The gateable wire fields are projected from the ONE canonical
|
|
19
|
+
* [[capability-manifest.js]] via `toGateableFieldGate()` — including companion
|
|
20
|
+
* fields controlled by the same logical feature. They cannot drift from the
|
|
21
|
+
* negotiated feature list. All non-negotiable frame fields (type, content,
|
|
22
|
+
* tool name, …) always pass through untouched.
|
|
22
23
|
*
|
|
23
24
|
* PURE + deterministic: no fs / process / clock / RNG. The `digest` lets a golden
|
|
24
25
|
* recording be pinned so any change to negotiation/gating that alters wire output
|
|
@@ -30,13 +31,19 @@ import {
|
|
|
30
31
|
negotiateProtocol,
|
|
31
32
|
applyNegotiationToGate,
|
|
32
33
|
} from "./capability-negotiation.js";
|
|
33
|
-
import {
|
|
34
|
+
import { toGateableFieldGate } from "./capability-manifest.js";
|
|
34
35
|
|
|
35
|
-
/** Negotiable wire field
|
|
36
|
+
/** Negotiable wire field → primary gate field, single-sourced. */
|
|
37
|
+
const GATEABLE_FIELD_GATE = Object.freeze(toGateableFieldGate());
|
|
38
|
+
|
|
39
|
+
/** Every negotiable wire field name, including same-feature companions. */
|
|
36
40
|
export const GATEABLE_FIELDS = Object.freeze(
|
|
37
|
-
|
|
41
|
+
Object.keys(GATEABLE_FIELD_GATE).sort(),
|
|
38
42
|
);
|
|
39
43
|
|
|
44
|
+
const gateOn = (gate, field) =>
|
|
45
|
+
gate[GATEABLE_FIELD_GATE[field] || field] === true;
|
|
46
|
+
|
|
40
47
|
/**
|
|
41
48
|
* Run negotiation and fold it into a per-field gate the replay/audit read.
|
|
42
49
|
* On an incompatible (ok:false) negotiation the gate stays empty → every gateable
|
|
@@ -50,8 +57,8 @@ export const GATEABLE_FIELDS = Object.freeze(
|
|
|
50
57
|
export function gateFromNegotiation({ server = {}, client = null } = {}) {
|
|
51
58
|
const negotiation = negotiateProtocol(server, client ?? null);
|
|
52
59
|
const gate = applyNegotiationToGate(negotiation, {});
|
|
53
|
-
const enabledFields = GATEABLE_FIELDS.filter((f) => gate
|
|
54
|
-
const gatedFields = GATEABLE_FIELDS.filter((f) => gate
|
|
60
|
+
const enabledFields = GATEABLE_FIELDS.filter((f) => gateOn(gate, f));
|
|
61
|
+
const gatedFields = GATEABLE_FIELDS.filter((f) => !gateOn(gate, f));
|
|
55
62
|
return { negotiation, gate, enabledFields, gatedFields };
|
|
56
63
|
}
|
|
57
64
|
|
|
@@ -61,14 +68,14 @@ export function gateFromNegotiation({ server = {}, client = null } = {}) {
|
|
|
61
68
|
* Returns a shallow copy — the input frame is never mutated.
|
|
62
69
|
*
|
|
63
70
|
* @param {object} frame
|
|
64
|
-
* @param {object} gate
|
|
71
|
+
* @param {object} gate negotiated primary-field gate
|
|
65
72
|
* @returns {object}
|
|
66
73
|
*/
|
|
67
74
|
export function replayFrame(frame, gate = {}) {
|
|
68
75
|
if (!frame || typeof frame !== "object") return frame;
|
|
69
76
|
const out = {};
|
|
70
77
|
for (const [k, v] of Object.entries(frame)) {
|
|
71
|
-
if (GATEABLE_FIELDS.includes(k) && gate
|
|
78
|
+
if (GATEABLE_FIELDS.includes(k) && !gateOn(gate, k)) continue;
|
|
72
79
|
out[k] = v;
|
|
73
80
|
}
|
|
74
81
|
return out;
|
|
@@ -116,7 +123,7 @@ export function auditRecordedSession(frames, ctx = {}) {
|
|
|
116
123
|
if (!frame || typeof frame !== "object") return;
|
|
117
124
|
for (const field of GATEABLE_FIELDS) {
|
|
118
125
|
if (
|
|
119
|
-
gate
|
|
126
|
+
!gateOn(gate, field) &&
|
|
120
127
|
Object.prototype.hasOwnProperty.call(frame, field)
|
|
121
128
|
) {
|
|
122
129
|
violations.push({
|
|
@@ -21,6 +21,7 @@ import fsDefault from "fs";
|
|
|
21
21
|
import pathDefault from "path";
|
|
22
22
|
import { findProjectRoot } from "./project-instructions.js";
|
|
23
23
|
import executionBroker from "./process-execution-broker/index.js";
|
|
24
|
+
import { collectPluginBinSandboxPolicy as collectDefaultPluginBinSandboxPolicy } from "./plugin-runtime/bin.js";
|
|
24
25
|
|
|
25
26
|
export const BANG_TIMEOUT_MS = 120_000;
|
|
26
27
|
export const BANG_MAX_BUFFER = 10 * 1024 * 1024;
|
|
@@ -33,6 +34,8 @@ export const MEMO_NOTE_MAX = 4_000;
|
|
|
33
34
|
|
|
34
35
|
export const _deps = {
|
|
35
36
|
spawnSync: (...args) => executionBroker.spawnSync(...args),
|
|
37
|
+
collectPluginBinSandboxPolicy: (opts) =>
|
|
38
|
+
collectDefaultPluginBinSandboxPolicy(opts),
|
|
36
39
|
fs: fsDefault,
|
|
37
40
|
path: pathDefault,
|
|
38
41
|
};
|
|
@@ -44,6 +47,46 @@ function cap(s) {
|
|
|
44
47
|
: str;
|
|
45
48
|
}
|
|
46
49
|
|
|
50
|
+
function resolveWindowsCommandShell(opts = {}) {
|
|
51
|
+
const path = opts.deps?.path || _deps.path;
|
|
52
|
+
const env = opts.env || process.env;
|
|
53
|
+
const normalizeLocalPath = (candidate) => {
|
|
54
|
+
const value =
|
|
55
|
+
typeof candidate === "string"
|
|
56
|
+
? candidate.trim()
|
|
57
|
+
: String(candidate || "");
|
|
58
|
+
// `path.win32.isAbsolute("\\foo")` is true even though the result still
|
|
59
|
+
// depends on the process's current drive. Require a drive-qualified local
|
|
60
|
+
// path so the helper receives one deterministic executable identity.
|
|
61
|
+
if (!/^[a-z]:[\\/]/i.test(value)) return null;
|
|
62
|
+
return path.win32.normalize(value);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
for (const candidate of [opts.comSpec, env.ComSpec, env.COMSPEC]) {
|
|
66
|
+
const value = normalizeLocalPath(candidate);
|
|
67
|
+
if (value && path.win32.basename(value).toLowerCase() === "cmd.exe") {
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for (const candidate of [
|
|
73
|
+
opts.systemRoot,
|
|
74
|
+
env.SystemRoot,
|
|
75
|
+
env.SYSTEMROOT,
|
|
76
|
+
env.WINDIR,
|
|
77
|
+
"C:\\Windows",
|
|
78
|
+
]) {
|
|
79
|
+
const value = normalizeLocalPath(candidate);
|
|
80
|
+
if (value) {
|
|
81
|
+
return path.win32.join(value, "System32", "cmd.exe");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// The literal fallback above is absolute, so this is unreachable with Node's
|
|
86
|
+
// path.win32 implementation. Keep a fail-closed guard for injected path seams.
|
|
87
|
+
throw new Error("No absolute Windows command shell is available");
|
|
88
|
+
}
|
|
89
|
+
|
|
47
90
|
/** True when the REPL line is a `!` bash passthrough. */
|
|
48
91
|
export function isBangCommand(trimmed) {
|
|
49
92
|
return (
|
|
@@ -70,24 +113,37 @@ export function isMemorizeLine(trimmed) {
|
|
|
70
113
|
*/
|
|
71
114
|
export function runBangCommand(line, opts = {}) {
|
|
72
115
|
const spawnSync = opts.deps?.spawnSync || _deps.spawnSync;
|
|
116
|
+
const collectPluginBinSandboxPolicy =
|
|
117
|
+
opts.deps?.collectPluginBinSandboxPolicy ||
|
|
118
|
+
_deps.collectPluginBinSandboxPolicy;
|
|
73
119
|
const cwd = opts.cwd || process.cwd();
|
|
74
120
|
const isWin =
|
|
75
121
|
opts.platform != null
|
|
76
122
|
? opts.platform === "win32"
|
|
77
123
|
: process.platform === "win32";
|
|
78
124
|
const cmd = String(line).replace(/^!/, "").trim();
|
|
125
|
+
// A bang command is another arbitrary workspace process surface. Collect the
|
|
126
|
+
// tighten-only Plugin bin boundary union before the shell starts so it cannot
|
|
127
|
+
// bypass a policy that run_shell already pins for the same workspace.
|
|
128
|
+
const sandboxPolicy = collectPluginBinSandboxPolicy({ cwd });
|
|
129
|
+
const sandboxOptions = sandboxPolicy ? { sandboxPolicy } : {};
|
|
79
130
|
|
|
80
131
|
const res = isWin
|
|
81
|
-
? spawnSync(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
132
|
+
? spawnSync(
|
|
133
|
+
resolveWindowsCommandShell(opts),
|
|
134
|
+
["/d", "/s", "/c", `chcp 65001 >nul && ${cmd}`],
|
|
135
|
+
{
|
|
136
|
+
encoding: "utf-8",
|
|
137
|
+
timeout: BANG_TIMEOUT_MS,
|
|
138
|
+
maxBuffer: BANG_MAX_BUFFER,
|
|
139
|
+
cwd,
|
|
140
|
+
origin: "repl:bang-command",
|
|
141
|
+
policy: "allow",
|
|
142
|
+
scope: "repl",
|
|
143
|
+
shell: false,
|
|
144
|
+
...sandboxOptions,
|
|
145
|
+
},
|
|
146
|
+
)
|
|
91
147
|
: spawnSync("/bin/sh", ["-c", cmd], {
|
|
92
148
|
encoding: "utf-8",
|
|
93
149
|
timeout: BANG_TIMEOUT_MS,
|
|
@@ -97,6 +153,7 @@ export function runBangCommand(line, opts = {}) {
|
|
|
97
153
|
policy: "allow",
|
|
98
154
|
scope: "repl",
|
|
99
155
|
shell: false,
|
|
156
|
+
...sandboxOptions,
|
|
100
157
|
});
|
|
101
158
|
|
|
102
159
|
const exitCode = res.status == null ? (res.error ? -1 : 0) : res.status;
|
|
@@ -256,6 +256,19 @@ function collectHooks(hooksBlock, event, toolName) {
|
|
|
256
256
|
pluginId: h.pluginId || null,
|
|
257
257
|
pluginVersion: h.pluginVersion || null,
|
|
258
258
|
pluginSource: h.pluginSource || null,
|
|
259
|
+
...(h.shell != null ? { shell: h.shell } : {}),
|
|
260
|
+
...(h.environmentAllowlist != null
|
|
261
|
+
? { environmentAllowlist: h.environmentAllowlist }
|
|
262
|
+
: {}),
|
|
263
|
+
...(h.envAllowlist != null
|
|
264
|
+
? { envAllowlist: h.envAllowlist }
|
|
265
|
+
: {}),
|
|
266
|
+
...(h.sandboxPolicy !== undefined
|
|
267
|
+
? { sandboxPolicy: h.sandboxPolicy }
|
|
268
|
+
: {}),
|
|
269
|
+
...(h.requiredBoundaries !== undefined
|
|
270
|
+
? { requiredBoundaries: h.requiredBoundaries }
|
|
271
|
+
: {}),
|
|
259
272
|
});
|
|
260
273
|
}
|
|
261
274
|
}
|
package/src/lib/skill-loader.js
CHANGED
|
@@ -332,6 +332,7 @@ export class CLISkillLoader {
|
|
|
332
332
|
this._cacheStats = {
|
|
333
333
|
descriptorScans: 0,
|
|
334
334
|
descriptorCacheHits: 0,
|
|
335
|
+
descriptorUses: new Map(),
|
|
335
336
|
bodyCacheHits: 0,
|
|
336
337
|
bodyCacheMisses: 0,
|
|
337
338
|
bodyLoads: new Map(),
|
|
@@ -579,10 +580,16 @@ export class CLISkillLoader {
|
|
|
579
580
|
estimatedTokens: cached.estimatedTokens,
|
|
580
581
|
loads: 0,
|
|
581
582
|
cacheHits: 0,
|
|
583
|
+
contextLoads: 0,
|
|
584
|
+
contextCacheHits: 0,
|
|
582
585
|
loadedBecause: [],
|
|
583
586
|
};
|
|
584
587
|
prior.loads += 1;
|
|
585
588
|
if (cacheRead) prior.cacheHits += 1;
|
|
589
|
+
if (context.bodyIncluded === true) {
|
|
590
|
+
prior.contextLoads += 1;
|
|
591
|
+
if (cacheRead) prior.contextCacheHits += 1;
|
|
592
|
+
}
|
|
586
593
|
const reason = context.loadedBecause || "explicit";
|
|
587
594
|
if (!prior.loadedBecause.includes(reason)) prior.loadedBecause.push(reason);
|
|
588
595
|
this._cacheStats.bodyLoads.set(skill.skillMdPath, prior);
|
|
@@ -594,12 +601,17 @@ export class CLISkillLoader {
|
|
|
594
601
|
sourceType: "skill",
|
|
595
602
|
sourceId: skill.id,
|
|
596
603
|
permissionMode: context.permissionMode || "agent",
|
|
597
|
-
|
|
604
|
+
// Only text that actually entered a model prompt consumes context
|
|
605
|
+
// tokens. Ordinary run_skill materialization is still recorded, but
|
|
606
|
+
// as a content-size/cache observation rather than a false token charge.
|
|
607
|
+
tokenCount:
|
|
608
|
+
context.bodyIncluded === true ? cached.estimatedTokens : 0,
|
|
598
609
|
metadata: {
|
|
599
610
|
source: skill.source,
|
|
600
611
|
loadedBecause: reason,
|
|
601
612
|
cacheRead,
|
|
602
613
|
bodyIncluded: context.bodyIncluded === true,
|
|
614
|
+
estimatedBodyTokens: cached.estimatedTokens,
|
|
603
615
|
},
|
|
604
616
|
});
|
|
605
617
|
} catch {
|
|
@@ -612,6 +624,22 @@ export class CLISkillLoader {
|
|
|
612
624
|
recordDescriptorUse(skills, context = {}) {
|
|
613
625
|
for (const skill of Array.isArray(skills) ? skills : []) {
|
|
614
626
|
const descriptorText = `${skill.id}\n${skill.description || ""}\n${skill.category || ""}`;
|
|
627
|
+
const estimatedTokens = estimateSkillTokens(descriptorText);
|
|
628
|
+
const prior = this._cacheStats.descriptorUses.get(skill.id) || {
|
|
629
|
+
id: skill.id,
|
|
630
|
+
source: skill.source,
|
|
631
|
+
estimatedTokens,
|
|
632
|
+
contextLoads: 0,
|
|
633
|
+
contextTokens: 0,
|
|
634
|
+
loadedBecause: [],
|
|
635
|
+
};
|
|
636
|
+
prior.contextLoads += 1;
|
|
637
|
+
prior.contextTokens += estimatedTokens;
|
|
638
|
+
const reason = context.loadedBecause || "list_skills";
|
|
639
|
+
if (!prior.loadedBecause.includes(reason)) {
|
|
640
|
+
prior.loadedBecause.push(reason);
|
|
641
|
+
}
|
|
642
|
+
this._cacheStats.descriptorUses.set(skill.id, prior);
|
|
615
643
|
try {
|
|
616
644
|
this._contextLedger?.recordRead?.({
|
|
617
645
|
sessionId: context.sessionId || "unknown",
|
|
@@ -619,10 +647,10 @@ export class CLISkillLoader {
|
|
|
619
647
|
sourceType: "skill_descriptor",
|
|
620
648
|
sourceId: skill.id,
|
|
621
649
|
permissionMode: context.permissionMode || "agent",
|
|
622
|
-
tokenCount:
|
|
650
|
+
tokenCount: estimatedTokens,
|
|
623
651
|
metadata: {
|
|
624
652
|
source: skill.source,
|
|
625
|
-
loadedBecause:
|
|
653
|
+
loadedBecause: reason,
|
|
626
654
|
bodyLoaded: skill.bodyLoaded === true,
|
|
627
655
|
},
|
|
628
656
|
});
|
|
@@ -635,10 +663,28 @@ export class CLISkillLoader {
|
|
|
635
663
|
/** Content-free cache/cost snapshot for `cc context --sources`. */
|
|
636
664
|
getCacheLedger() {
|
|
637
665
|
const descriptors = Array.isArray(this._cache) ? this._cache : [];
|
|
638
|
-
const
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
666
|
+
const descriptorEntries = descriptors.map((skill) => {
|
|
667
|
+
const descriptorText = `${skill.id}\n${skill.displayName}\n${skill.description}\n${skill.category}`;
|
|
668
|
+
const used = this._cacheStats.descriptorUses.get(skill.id);
|
|
669
|
+
return {
|
|
670
|
+
id: skill.id,
|
|
671
|
+
source: skill.source,
|
|
672
|
+
estimatedTokens: estimateSkillTokens(descriptorText),
|
|
673
|
+
contextLoads: Number(used?.contextLoads) || 0,
|
|
674
|
+
contextTokens: Number(used?.contextTokens) || 0,
|
|
675
|
+
loadedBecause: [...(used?.loadedBecause || [])],
|
|
676
|
+
};
|
|
677
|
+
});
|
|
678
|
+
const descriptorTokens = descriptorEntries.reduce(
|
|
679
|
+
(sum, entry) => sum + entry.estimatedTokens,
|
|
680
|
+
0,
|
|
681
|
+
);
|
|
682
|
+
const descriptorContextLoads = descriptorEntries.reduce(
|
|
683
|
+
(sum, entry) => sum + entry.contextLoads,
|
|
684
|
+
0,
|
|
685
|
+
);
|
|
686
|
+
const descriptorContextTokens = descriptorEntries.reduce(
|
|
687
|
+
(sum, entry) => sum + entry.contextTokens,
|
|
642
688
|
0,
|
|
643
689
|
);
|
|
644
690
|
const residentPaths = new Set(this._bodyCache.keys());
|
|
@@ -649,20 +695,46 @@ export class CLISkillLoader {
|
|
|
649
695
|
0,
|
|
650
696
|
);
|
|
651
697
|
const bodyLoads = Array.from(this._cacheStats.bodyLoads.values()).map(
|
|
652
|
-
(entry) => ({
|
|
698
|
+
(entry) => ({
|
|
699
|
+
...entry,
|
|
700
|
+
cacheMisses: Math.max(0, entry.loads - entry.cacheHits),
|
|
701
|
+
contextTokens: entry.estimatedTokens * entry.contextLoads,
|
|
702
|
+
loadedBecause: [...entry.loadedBecause],
|
|
703
|
+
}),
|
|
704
|
+
);
|
|
705
|
+
const bodyTotals = bodyLoads.reduce(
|
|
706
|
+
(totals, entry) => {
|
|
707
|
+
totals.estimatedTokensResident += entry.estimatedTokens;
|
|
708
|
+
totals.estimatedTokensServed += entry.estimatedTokens * entry.loads;
|
|
709
|
+
totals.estimatedTokensAvoidedByCache +=
|
|
710
|
+
entry.estimatedTokens * entry.cacheHits;
|
|
711
|
+
totals.contextLoads += entry.contextLoads;
|
|
712
|
+
totals.contextTokens += entry.contextTokens;
|
|
713
|
+
return totals;
|
|
714
|
+
},
|
|
715
|
+
{
|
|
716
|
+
estimatedTokensResident: 0,
|
|
717
|
+
estimatedTokensServed: 0,
|
|
718
|
+
estimatedTokensAvoidedByCache: 0,
|
|
719
|
+
contextLoads: 0,
|
|
720
|
+
contextTokens: 0,
|
|
721
|
+
},
|
|
653
722
|
);
|
|
654
723
|
return {
|
|
655
724
|
descriptors: {
|
|
656
725
|
resident: descriptors.length,
|
|
657
726
|
scans: this._cacheStats.descriptorScans,
|
|
658
727
|
cacheHits: this._cacheStats.descriptorCacheHits,
|
|
659
|
-
|
|
660
|
-
|
|
728
|
+
estimatedTokens: descriptorTokens,
|
|
729
|
+
contextLoads: descriptorContextLoads,
|
|
730
|
+
contextTokens: descriptorContextTokens,
|
|
731
|
+
entries: descriptorEntries,
|
|
661
732
|
},
|
|
662
733
|
bodies: {
|
|
663
734
|
resident: this._bodyCache.size,
|
|
664
735
|
cacheHits: this._cacheStats.bodyCacheHits,
|
|
665
736
|
cacheMisses: this._cacheStats.bodyCacheMisses,
|
|
737
|
+
...bodyTotals,
|
|
666
738
|
entries: bodyLoads,
|
|
667
739
|
},
|
|
668
740
|
savings: {
|
|
@@ -770,6 +842,7 @@ export class CLISkillLoader {
|
|
|
770
842
|
this._cacheStats = {
|
|
771
843
|
descriptorScans: 0,
|
|
772
844
|
descriptorCacheHits: 0,
|
|
845
|
+
descriptorUses: new Map(),
|
|
773
846
|
bodyCacheHits: 0,
|
|
774
847
|
bodyCacheMisses: 0,
|
|
775
848
|
bodyLoads: new Map(),
|
|
@@ -24,11 +24,14 @@ import { homedir } from "node:os";
|
|
|
24
24
|
import { expandFileRefs } from "../runtime/file-ref-expander.js";
|
|
25
25
|
import { projectRootBase } from "./project-root.cjs";
|
|
26
26
|
import executionBroker from "./process-execution-broker/index.js";
|
|
27
|
+
import { collectPluginBinSandboxPolicy as collectDefaultPluginBinSandboxPolicy } from "./plugin-runtime/bin.js";
|
|
27
28
|
|
|
28
29
|
const _deps = {
|
|
29
30
|
fs: fsDefault,
|
|
30
31
|
path: pathDefault,
|
|
31
32
|
execSync: (...args) => executionBroker.execSync(...args),
|
|
33
|
+
collectPluginBinSandboxPolicy: (opts) =>
|
|
34
|
+
collectDefaultPluginBinSandboxPolicy(opts),
|
|
32
35
|
};
|
|
33
36
|
|
|
34
37
|
/**
|
|
@@ -186,8 +189,16 @@ export function substituteArgs(text, args = []) {
|
|
|
186
189
|
return out;
|
|
187
190
|
}
|
|
188
191
|
|
|
192
|
+
function isSandboxFailClosedError(error) {
|
|
193
|
+
return (
|
|
194
|
+
error?.sandboxFailClosed === true ||
|
|
195
|
+
(typeof error?.code === "string" &&
|
|
196
|
+
error.code.startsWith("ERR_PROCESS_SANDBOX"))
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
189
200
|
/** Run every `!`cmd`` and replace it with the command's stdout (best-effort). */
|
|
190
|
-
function runBangs(text, { cwd, execSync }) {
|
|
201
|
+
function runBangs(text, { cwd, execSync, sandboxPolicy }) {
|
|
191
202
|
return text.replace(/!`([^`]+)`/g, (_, cmd) => {
|
|
192
203
|
try {
|
|
193
204
|
const out = execSync(cmd, {
|
|
@@ -199,9 +210,13 @@ function runBangs(text, { cwd, execSync }) {
|
|
|
199
210
|
policy: "allow",
|
|
200
211
|
scope: "slash-command",
|
|
201
212
|
shell: true,
|
|
213
|
+
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
202
214
|
});
|
|
203
215
|
return String(out).trim();
|
|
204
216
|
} catch (err) {
|
|
217
|
+
// Broker boundary failures are security decisions, not ordinary command
|
|
218
|
+
// failures. Preserve the exact structured error for the caller.
|
|
219
|
+
if (isSandboxFailClosedError(err)) throw err;
|
|
205
220
|
return `[command failed: ${cmd} — ${err.message?.split("\n")[0] || err}]`;
|
|
206
221
|
}
|
|
207
222
|
});
|
|
@@ -215,18 +230,26 @@ function runBangs(text, { cwd, execSync }) {
|
|
|
215
230
|
*
|
|
216
231
|
* @param {object} command output of getCommand/parseCommandFile (needs .body)
|
|
217
232
|
* @param {string[]} args
|
|
218
|
-
* @param {object} [opts] { cwd, allowBang,
|
|
233
|
+
* @param {object} [opts] { cwd, allowBang,
|
|
234
|
+
* deps:{ execSync, collectPluginBinSandboxPolicy } }
|
|
219
235
|
* @returns {{ prompt:string, warnings:string[] }}
|
|
220
236
|
*/
|
|
221
237
|
export function expandCommand(command, args = [], opts = {}) {
|
|
222
238
|
const cwd = opts.cwd || process.cwd();
|
|
223
239
|
const execSync = opts.deps?.execSync || _deps.execSync;
|
|
240
|
+
const collectPluginBinSandboxPolicy =
|
|
241
|
+
opts.deps?.collectPluginBinSandboxPolicy ||
|
|
242
|
+
_deps.collectPluginBinSandboxPolicy;
|
|
224
243
|
const warnings = [];
|
|
225
244
|
|
|
226
245
|
let text = substituteArgs(command.body || "", args);
|
|
227
246
|
|
|
228
|
-
if (opts.allowBang !== false) {
|
|
229
|
-
|
|
247
|
+
if (opts.allowBang !== false && /!`[^`]+`/.test(text)) {
|
|
248
|
+
// Resolve and pin once before the first bang. Every expansion in this macro
|
|
249
|
+
// receives the same immutable policy object, so no earlier command can run
|
|
250
|
+
// before a later discovery failure or observe a weaker boundary set.
|
|
251
|
+
const sandboxPolicy = collectPluginBinSandboxPolicy({ cwd });
|
|
252
|
+
text = runBangs(text, { cwd, execSync, sandboxPolicy });
|
|
230
253
|
}
|
|
231
254
|
|
|
232
255
|
// @file expansion appends a <referenced-files> block when anything resolves.
|
|
@@ -214,14 +214,15 @@ function setCredentials(providerId, creds) {
|
|
|
214
214
|
if (!creds || typeof creds !== "object") {
|
|
215
215
|
throw new Error("sync-credentials: creds must be an object");
|
|
216
216
|
}
|
|
217
|
-
//
|
|
218
|
-
//
|
|
217
|
+
// Credential metadata is security-critical: never decrypt-modify-encrypt
|
|
218
|
+
// without exclusion, because a lost update can silently restore/revoke the
|
|
219
|
+
// wrong provider credentials.
|
|
219
220
|
return withFileLock(_vaultPath(), () => {
|
|
220
221
|
const all = loadAll();
|
|
221
222
|
if (!all.sync || typeof all.sync !== "object") all.sync = {};
|
|
222
223
|
all.sync[providerId] = { ...creds };
|
|
223
224
|
return saveAll(all);
|
|
224
|
-
});
|
|
225
|
+
}, { failIfUnavailable: true });
|
|
225
226
|
}
|
|
226
227
|
|
|
227
228
|
function clearCredentials(providerId) {
|
|
@@ -233,7 +234,7 @@ function clearCredentials(providerId) {
|
|
|
233
234
|
return saveAll(all);
|
|
234
235
|
}
|
|
235
236
|
return true;
|
|
236
|
-
});
|
|
237
|
+
}, { failIfUnavailable: true });
|
|
237
238
|
}
|
|
238
239
|
|
|
239
240
|
/** Test seam: override the resolved chainlesschain dir without env leak. */
|
package/src/lib/turn-binding.js
CHANGED
|
@@ -555,12 +555,14 @@ export function createTurnBindingFeed({
|
|
|
555
555
|
// New core events expose the exact decision id. Legacy/custom event
|
|
556
556
|
// sources retain the deterministic compatibility derivation.
|
|
557
557
|
const policy = event.result?.policy;
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
558
|
+
const decisionId =
|
|
559
|
+
event.permission_decision_id ||
|
|
560
|
+
event.permission_decision?.id ||
|
|
561
|
+
(policy && (policy.via || policy.decision)
|
|
562
|
+
? `${callId || "call"}:perm:${policy.via || policy.decision}`
|
|
563
|
+
: null);
|
|
564
|
+
if (decisionId) {
|
|
565
|
+
log.recordPermissionDecision(turnId, decisionId);
|
|
564
566
|
dirty = true;
|
|
565
567
|
}
|
|
566
568
|
if (event.result?.userEdited === true) {
|