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
|
@@ -49,6 +49,14 @@ export const CAPABILITY_MANIFEST = Object.freeze({
|
|
|
49
49
|
description:
|
|
50
50
|
'tool_use / tool_result lines carry a pairing `id` ("tu-<n>")',
|
|
51
51
|
}),
|
|
52
|
+
Object.freeze({
|
|
53
|
+
key: "permission_decision",
|
|
54
|
+
field: "permission_decision",
|
|
55
|
+
companionFields: Object.freeze(["permission_decision_id"]),
|
|
56
|
+
minVersion: 1,
|
|
57
|
+
description:
|
|
58
|
+
"gated tool_result lines may carry a redacted permission decision and its correlation id",
|
|
59
|
+
}),
|
|
52
60
|
Object.freeze({
|
|
53
61
|
key: "trace_id",
|
|
54
62
|
field: "trace_id",
|
|
@@ -135,6 +143,24 @@ export function toFieldGate(m = CAPABILITY_MANIFEST) {
|
|
|
135
143
|
return out;
|
|
136
144
|
}
|
|
137
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Every negotiable line field → the primary gate field that controls it.
|
|
148
|
+
* Companion fields are kept under the same logical feature so negotiation can
|
|
149
|
+
* never emit a decision without its id (or an orphan id without its decision).
|
|
150
|
+
* @returns {Record<string, string>}
|
|
151
|
+
*/
|
|
152
|
+
export function toGateableFieldGate(m = CAPABILITY_MANIFEST) {
|
|
153
|
+
const out = {};
|
|
154
|
+
for (const f of wireFeaturesOf(m)) {
|
|
155
|
+
if (!f?.field) continue;
|
|
156
|
+
out[f.field] = f.field;
|
|
157
|
+
for (const companion of f.companionFields || []) {
|
|
158
|
+
if (companion) out[companion] = f.field;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
|
|
138
164
|
/**
|
|
139
165
|
* The server negotiation offer shape consumed by
|
|
140
166
|
* capability-negotiation.js `negotiateProtocol(server, …)`.
|
|
@@ -199,7 +225,12 @@ export function capabilityDigest(m = CAPABILITY_MANIFEST) {
|
|
|
199
225
|
protocolVersion: Number(mm.protocolVersion) || 1,
|
|
200
226
|
minProtocolVersion: Number(mm.minProtocolVersion) || 1,
|
|
201
227
|
wire: wireFeaturesOf(mm)
|
|
202
|
-
.map((f) => [
|
|
228
|
+
.map((f) => [
|
|
229
|
+
f.key,
|
|
230
|
+
f.field,
|
|
231
|
+
[...(f.companionFields || [])].sort(),
|
|
232
|
+
Number(f.minVersion) || 1,
|
|
233
|
+
])
|
|
203
234
|
.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0)),
|
|
204
235
|
runtime: [...(mm.runtimeFeatures || [])].sort(),
|
|
205
236
|
mcp: [...(mm.mcpFeatures || [])].sort(),
|
|
@@ -224,7 +255,7 @@ export function renderBehaviorMatrix(m = CAPABILITY_MANIFEST) {
|
|
|
224
255
|
return wireFeaturesOf(m).map((f) => ({
|
|
225
256
|
feature: f.key,
|
|
226
257
|
minVersion: Number(f.minVersion) || 1,
|
|
227
|
-
field: f.field,
|
|
258
|
+
field: [f.field, ...(f.companionFields || [])].join(", "),
|
|
228
259
|
negotiable: true,
|
|
229
260
|
description: String(f.description || ""),
|
|
230
261
|
}));
|
|
@@ -280,6 +311,7 @@ export function diffCapabilities(prev, next = CAPABILITY_MANIFEST) {
|
|
|
280
311
|
for (const f of wireFeaturesOf(m)) {
|
|
281
312
|
out.set(f.key, {
|
|
282
313
|
field: f.field,
|
|
314
|
+
companionFields: [...(f.companionFields || [])].sort(),
|
|
283
315
|
minVersion: Number(f.minVersion) || 1,
|
|
284
316
|
});
|
|
285
317
|
}
|
|
@@ -294,7 +326,13 @@ export function diffCapabilities(prev, next = CAPABILITY_MANIFEST) {
|
|
|
294
326
|
const changedWireFeatures = [];
|
|
295
327
|
for (const [key, nv] of n) {
|
|
296
328
|
const pv = p.get(key);
|
|
297
|
-
if (
|
|
329
|
+
if (
|
|
330
|
+
pv &&
|
|
331
|
+
(pv.field !== nv.field ||
|
|
332
|
+
pv.minVersion !== nv.minVersion ||
|
|
333
|
+
JSON.stringify(pv.companionFields) !==
|
|
334
|
+
JSON.stringify(nv.companionFields))
|
|
335
|
+
) {
|
|
298
336
|
changedWireFeatures.push({ feature: key, from: pv, to: nv });
|
|
299
337
|
}
|
|
300
338
|
}
|
|
@@ -210,7 +210,7 @@ const FEATURE_TO_FIELD = toFieldGate();
|
|
|
210
210
|
* baseline). Mutates `gate` in place and returns it.
|
|
211
211
|
*
|
|
212
212
|
* @param {{features:string[], ok:boolean}} result
|
|
213
|
-
* @param {{seq?:boolean, trace_id?:boolean, tool_use_id?:boolean}} gate
|
|
213
|
+
* @param {{seq?:boolean, trace_id?:boolean, tool_use_id?:boolean, permission_decision?:boolean}} gate
|
|
214
214
|
*/
|
|
215
215
|
export function applyNegotiationToGate(result, gate = {}) {
|
|
216
216
|
if (!result || result.ok === false) return gate;
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
describeAuthorityChain,
|
|
22
22
|
} from "../agent-authority.js";
|
|
23
23
|
import { EventRuntimeStore } from "../event-runtime-store.js";
|
|
24
|
+
import { getDefaultEventRuntimeHost } from "../event-runtime-host.js";
|
|
24
25
|
|
|
25
26
|
export const CHANNEL_KINDS = ["webhook", "telegram"];
|
|
26
27
|
|
|
@@ -128,8 +129,31 @@ export async function startChannels(specsInput, opts = {}) {
|
|
|
128
129
|
// `approve`) before the caller's handler sees it — so a channel message can
|
|
129
130
|
// never be mistaken for a user approval no matter what it contains.
|
|
130
131
|
const onEvent = stampChannelAuthority(opts.onEvent);
|
|
132
|
+
const eventRuntimeHost =
|
|
133
|
+
opts.eventRuntimeHost ||
|
|
134
|
+
(eventRuntimeStore && process.env.CC_EVENT_RUNTIME_DURABLE === "1"
|
|
135
|
+
? getDefaultEventRuntimeHost({ store: eventRuntimeStore })
|
|
136
|
+
: null);
|
|
131
137
|
|
|
132
138
|
const started = [];
|
|
139
|
+
const unregisterRuntimeHandlers = [];
|
|
140
|
+
if (eventRuntimeHost) {
|
|
141
|
+
for (const origin of new Set(specs.map((spec) => spec.kind))) {
|
|
142
|
+
unregisterRuntimeHandlers.push(
|
|
143
|
+
eventRuntimeHost.registerHandler(
|
|
144
|
+
(event) =>
|
|
145
|
+
onEvent({
|
|
146
|
+
channel: event.channel || origin,
|
|
147
|
+
sender: event.sender,
|
|
148
|
+
text: event.text,
|
|
149
|
+
...(event.meta == null ? {} : { meta: event.meta }),
|
|
150
|
+
eventId: event.event_id || event.eventId || event.id || null,
|
|
151
|
+
}),
|
|
152
|
+
{ queue: "inbox", type: "channel.event", origin },
|
|
153
|
+
),
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
133
157
|
const stopAll = () => {
|
|
134
158
|
for (const c of started) {
|
|
135
159
|
try {
|
|
@@ -138,6 +162,13 @@ export async function startChannels(specsInput, opts = {}) {
|
|
|
138
162
|
/* best-effort */
|
|
139
163
|
}
|
|
140
164
|
}
|
|
165
|
+
for (const unregister of unregisterRuntimeHandlers.splice(0)) {
|
|
166
|
+
try {
|
|
167
|
+
unregister();
|
|
168
|
+
} catch {
|
|
169
|
+
/* best-effort */
|
|
170
|
+
}
|
|
171
|
+
}
|
|
141
172
|
};
|
|
142
173
|
|
|
143
174
|
try {
|
|
@@ -154,6 +185,7 @@ export async function startChannels(specsInput, opts = {}) {
|
|
|
154
185
|
onEvent,
|
|
155
186
|
log,
|
|
156
187
|
eventRuntimeStore,
|
|
188
|
+
eventRuntimeHost,
|
|
157
189
|
});
|
|
158
190
|
started.push({ kind: "webhook", describe: handle.describe, ...handle });
|
|
159
191
|
} else if (spec.kind === "telegram") {
|
|
@@ -167,6 +199,7 @@ export async function startChannels(specsInput, opts = {}) {
|
|
|
167
199
|
onEvent,
|
|
168
200
|
log,
|
|
169
201
|
eventRuntimeStore,
|
|
202
|
+
eventRuntimeHost,
|
|
170
203
|
});
|
|
171
204
|
started.push({
|
|
172
205
|
kind: "telegram",
|
|
@@ -29,6 +29,7 @@ export async function startTelegramChannel(options = {}) {
|
|
|
29
29
|
// the event loop (timers, stop()) entirely.
|
|
30
30
|
pollPauseMs = 50,
|
|
31
31
|
eventRuntimeStore = null,
|
|
32
|
+
eventRuntimeHost = null,
|
|
32
33
|
} = options;
|
|
33
34
|
const runtimeProducer = eventRuntimeStore
|
|
34
35
|
? new EventRuntimeProducer({ store: eventRuntimeStore })
|
|
@@ -74,13 +75,30 @@ export async function startTelegramChannel(options = {}) {
|
|
|
74
75
|
channel: "telegram",
|
|
75
76
|
sender: String(chatId),
|
|
76
77
|
text,
|
|
78
|
+
eventId: `telegram:${update.update_id}`,
|
|
77
79
|
meta: { updateId: update.update_id },
|
|
78
80
|
};
|
|
79
|
-
runtimeProducer
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
if (runtimeProducer) {
|
|
82
|
+
const record = runtimeProducer.publish(
|
|
83
|
+
{
|
|
84
|
+
...event,
|
|
85
|
+
type: "channel.event",
|
|
86
|
+
requiresHandler: true,
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
origin: "telegram",
|
|
90
|
+
id: `telegram:${update.update_id}`,
|
|
91
|
+
},
|
|
92
|
+
);
|
|
93
|
+
if (eventRuntimeHost) {
|
|
94
|
+
await eventRuntimeHost.runOnce();
|
|
95
|
+
} else {
|
|
96
|
+
const result = await onEvent?.(event);
|
|
97
|
+
eventRuntimeStore.acknowledgeInbox?.(record.id, result);
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
await onEvent?.(event);
|
|
101
|
+
}
|
|
84
102
|
} catch {
|
|
85
103
|
/* downstream owns its failures */
|
|
86
104
|
}
|
|
@@ -36,6 +36,7 @@ export async function startWebhookChannel(options = {}) {
|
|
|
36
36
|
onEvent,
|
|
37
37
|
log = () => {},
|
|
38
38
|
eventRuntimeStore = null,
|
|
39
|
+
eventRuntimeHost = null,
|
|
39
40
|
} = options;
|
|
40
41
|
const runtimeProducer = eventRuntimeStore
|
|
41
42
|
? new EventRuntimeProducer({ store: eventRuntimeStore })
|
|
@@ -80,7 +81,7 @@ export async function startWebhookChannel(options = {}) {
|
|
|
80
81
|
}
|
|
81
82
|
chunks.push(chunk);
|
|
82
83
|
});
|
|
83
|
-
req.on("end", () => {
|
|
84
|
+
req.on("end", async () => {
|
|
84
85
|
if (aborted) return;
|
|
85
86
|
let payload;
|
|
86
87
|
try {
|
|
@@ -92,30 +93,52 @@ export async function startWebhookChannel(options = {}) {
|
|
|
92
93
|
if (!text) return respond(400, { error: "missing text" });
|
|
93
94
|
const sender =
|
|
94
95
|
typeof payload.sender === "string" ? payload.sender : "webhook";
|
|
96
|
+
const eventId = payload.event_id || payload.eventId || null;
|
|
95
97
|
if (Array.isArray(allowlist) && allowlist.length > 0) {
|
|
96
98
|
if (!allowlist.includes(sender)) {
|
|
97
99
|
return respond(403, { error: "sender not in allowlist" });
|
|
98
100
|
}
|
|
99
101
|
}
|
|
100
102
|
const event = {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
channel: "webhook",
|
|
104
|
+
sender,
|
|
105
|
+
text,
|
|
106
|
+
...(eventId == null ? {} : { eventId: String(eventId) }),
|
|
107
|
+
meta:
|
|
108
|
+
payload.meta && typeof payload.meta === "object"
|
|
109
|
+
? payload.meta
|
|
110
|
+
: undefined,
|
|
111
|
+
};
|
|
109
112
|
try {
|
|
110
|
-
runtimeProducer
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
if (runtimeProducer) {
|
|
114
|
+
const record = runtimeProducer.publish(
|
|
115
|
+
{
|
|
116
|
+
...event,
|
|
117
|
+
type: "channel.event",
|
|
118
|
+
requiresHandler: true,
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
origin: "webhook",
|
|
122
|
+
id: eventId,
|
|
123
|
+
},
|
|
124
|
+
);
|
|
125
|
+
if (eventRuntimeHost) {
|
|
126
|
+
const stats = await eventRuntimeHost.runOnce();
|
|
127
|
+
if (Number(stats?.inboxFailed || 0) > 0) {
|
|
128
|
+
throw new Error("durable event delivery failed");
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
const result = await onEvent?.(event);
|
|
132
|
+
eventRuntimeStore.acknowledgeInbox?.(record.id, result);
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
await onEvent?.(event);
|
|
136
|
+
}
|
|
115
137
|
} catch {
|
|
116
138
|
// A configured durable runtime is the recovery boundary. Refuse the
|
|
117
139
|
// request rather than acknowledging an event that was not persisted.
|
|
118
|
-
if (runtimeProducer)
|
|
140
|
+
if (runtimeProducer)
|
|
141
|
+
return respond(503, { error: "event persistence unavailable" });
|
|
119
142
|
}
|
|
120
143
|
respond(202, { ok: true });
|
|
121
144
|
});
|
|
@@ -31,6 +31,7 @@ import os from "os";
|
|
|
31
31
|
import path from "path";
|
|
32
32
|
import http from "http";
|
|
33
33
|
import executionBroker from "./process-execution-broker/index.js";
|
|
34
|
+
import { redactSecrets } from "./secret-scan.js";
|
|
34
35
|
|
|
35
36
|
export const DEFAULT_CDP_PORT = 9222;
|
|
36
37
|
|
|
@@ -67,6 +68,122 @@ export function normalizeLaunchUrl(url) {
|
|
|
67
68
|
}
|
|
68
69
|
export const DEFAULT_DOM_CAP = 150000;
|
|
69
70
|
|
|
71
|
+
/** Secret-safe text carried from a browser into transcripts or audit logs. */
|
|
72
|
+
export function redactBrowserText(value, cap = 500) {
|
|
73
|
+
if (value == null) return "";
|
|
74
|
+
const text = redactSecrets(String(value));
|
|
75
|
+
return text.length > cap ? `${text.slice(0, cap)}…` : text;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Preserve the page origin/path and query KEY names while removing credentials,
|
|
80
|
+
* fragments, and every query value. Query values often contain opaque sessions
|
|
81
|
+
* that a generic secret scanner cannot recognize.
|
|
82
|
+
*/
|
|
83
|
+
export function redactBrowserUrl(value, cap = 500) {
|
|
84
|
+
const raw = String(value || "");
|
|
85
|
+
if (!raw) return "";
|
|
86
|
+
try {
|
|
87
|
+
const parsed = new URL(raw);
|
|
88
|
+
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
89
|
+
return redactBrowserText(raw, cap);
|
|
90
|
+
}
|
|
91
|
+
const keys = [...new Set(parsed.searchParams.keys())].slice(0, 64);
|
|
92
|
+
const query =
|
|
93
|
+
keys.length > 0
|
|
94
|
+
? `?${keys
|
|
95
|
+
.map((key) => `${encodeURIComponent(key)}=[REDACTED]`)
|
|
96
|
+
.join("&")}`
|
|
97
|
+
: "";
|
|
98
|
+
return redactBrowserText(
|
|
99
|
+
`${parsed.protocol}//${parsed.host}${parsed.pathname}${query}`,
|
|
100
|
+
cap,
|
|
101
|
+
);
|
|
102
|
+
} catch {
|
|
103
|
+
return redactBrowserText(raw, cap);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function redactBrowserDomUrl(value, cap = 1000) {
|
|
108
|
+
const raw = String(value || "");
|
|
109
|
+
if (!raw) return "";
|
|
110
|
+
if (/^https?:\/\//i.test(raw)) return redactBrowserUrl(raw, cap);
|
|
111
|
+
if (raw.startsWith("//")) {
|
|
112
|
+
const safe = redactBrowserUrl(`https:${raw}`, cap + 6);
|
|
113
|
+
return safe.startsWith("https:")
|
|
114
|
+
? redactBrowserText(safe.slice(6), cap)
|
|
115
|
+
: redactBrowserText(safe, cap);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const withoutFragment = raw.split("#", 1)[0];
|
|
119
|
+
const queryIndex = withoutFragment.indexOf("?");
|
|
120
|
+
if (queryIndex < 0) return redactBrowserText(withoutFragment, cap);
|
|
121
|
+
const prefix = withoutFragment.slice(0, queryIndex);
|
|
122
|
+
const keys = [
|
|
123
|
+
...new Set(
|
|
124
|
+
withoutFragment
|
|
125
|
+
.slice(queryIndex + 1)
|
|
126
|
+
.split(/&(?:amp;)?/i)
|
|
127
|
+
.map((part) => part.split("=", 1)[0].trim())
|
|
128
|
+
.filter(Boolean)
|
|
129
|
+
.slice(0, 64),
|
|
130
|
+
),
|
|
131
|
+
];
|
|
132
|
+
const query =
|
|
133
|
+
keys.length > 0
|
|
134
|
+
? `?${keys
|
|
135
|
+
.map((key) => `${encodeURIComponent(key.slice(0, 128))}=[REDACTED]`)
|
|
136
|
+
.join("&")}`
|
|
137
|
+
: "";
|
|
138
|
+
return redactBrowserText(`${prefix}${query}`, cap);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Redact secret-shaped text, sensitive form values, and DOM URL query values
|
|
143
|
+
* from the bounded snapshot before it crosses the tool boundary.
|
|
144
|
+
*/
|
|
145
|
+
export function redactBrowserDom(value, cap = DEFAULT_DOM_CAP) {
|
|
146
|
+
let html = redactSecrets(String(value || ""));
|
|
147
|
+
html = html.replace(/<input\b[^>]*>/gi, (tag) => {
|
|
148
|
+
const sensitive =
|
|
149
|
+
/\btype\s*=\s*["']?password\b/i.test(tag) ||
|
|
150
|
+
/\b(?:name|id)\s*=\s*["'][^"']*(?:password|passwd|token|secret|api[-_]?key)[^"']*["']/i.test(
|
|
151
|
+
tag,
|
|
152
|
+
);
|
|
153
|
+
if (!sensitive) return tag;
|
|
154
|
+
return tag.replace(/\bvalue\s*=\s*(["'])[^"']*\1/i, 'value="[REDACTED]"');
|
|
155
|
+
});
|
|
156
|
+
html = html.replace(
|
|
157
|
+
/(<textarea\b[^>]*(?:name|id)\s*=\s*["'][^"']*(?:password|passwd|token|secret|api[-_]?key)[^"']*["'][^>]*>)[\s\S]*?(<\/textarea>)/gi,
|
|
158
|
+
"$1[REDACTED]$2",
|
|
159
|
+
);
|
|
160
|
+
html = html.replace(
|
|
161
|
+
/\b(href|src|action)\s*=\s*(["'])([^"']+)\2/gi,
|
|
162
|
+
(_match, attr, quote, url) =>
|
|
163
|
+
`${attr}=${quote}${redactBrowserDomUrl(url, 1000)}${quote}`,
|
|
164
|
+
);
|
|
165
|
+
return html.slice(0, Math.max(0, Number(cap) || 0));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function redactScreenshotFailure(error, generatedPath, cap = 300) {
|
|
169
|
+
let message = String(error && error.message ? error.message : error);
|
|
170
|
+
if (generatedPath) {
|
|
171
|
+
message = message
|
|
172
|
+
.split(String(generatedPath))
|
|
173
|
+
.join("[SCREENSHOT_PATH]");
|
|
174
|
+
}
|
|
175
|
+
return redactBrowserText(message.split("\n")[0], cap);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function cleanupFailedScreenshot(generatedPath, deps) {
|
|
179
|
+
if (!generatedPath) return;
|
|
180
|
+
try {
|
|
181
|
+
deps.fs.rmSync(generatedPath, { force: true });
|
|
182
|
+
} catch {
|
|
183
|
+
// Failure cleanup is best-effort; never mask the browser action error.
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
70
187
|
const _deps = {
|
|
71
188
|
fs,
|
|
72
189
|
spawn: executionBroker.spawn.bind(executionBroker),
|
|
@@ -286,15 +403,18 @@ export async function captureState({
|
|
|
286
403
|
const networkEntries = [];
|
|
287
404
|
const onConsole = (m) => {
|
|
288
405
|
if (consoleEntries.length < 200) {
|
|
289
|
-
consoleEntries.push({
|
|
406
|
+
consoleEntries.push({
|
|
407
|
+
type: redactBrowserText(m.type(), 40),
|
|
408
|
+
text: redactBrowserText(m.text(), 500),
|
|
409
|
+
});
|
|
290
410
|
}
|
|
291
411
|
};
|
|
292
412
|
const onRequestFailed = (r) => {
|
|
293
413
|
if (networkEntries.length < 200) {
|
|
294
414
|
networkEntries.push({
|
|
295
415
|
kind: "failed",
|
|
296
|
-
url: r.url()
|
|
297
|
-
error: r.failure()?.errorText || "",
|
|
416
|
+
url: redactBrowserUrl(r.url(), 300),
|
|
417
|
+
error: redactBrowserText(r.failure()?.errorText || "", 300),
|
|
298
418
|
});
|
|
299
419
|
}
|
|
300
420
|
};
|
|
@@ -302,7 +422,7 @@ export async function captureState({
|
|
|
302
422
|
if (res.status() >= 400 && networkEntries.length < 200) {
|
|
303
423
|
networkEntries.push({
|
|
304
424
|
kind: "http-error",
|
|
305
|
-
url: res.url()
|
|
425
|
+
url: redactBrowserUrl(res.url(), 300),
|
|
306
426
|
status: res.status(),
|
|
307
427
|
});
|
|
308
428
|
}
|
|
@@ -322,22 +442,33 @@ export async function captureState({
|
|
|
322
442
|
ok: true,
|
|
323
443
|
port,
|
|
324
444
|
tab: index,
|
|
325
|
-
url: page.url(),
|
|
326
|
-
title: await page.title().catch(() => ""),
|
|
327
|
-
tabs: pages.map((p, i) => ({
|
|
445
|
+
url: redactBrowserUrl(page.url()),
|
|
446
|
+
title: redactBrowserText(await page.title().catch(() => ""), 500),
|
|
447
|
+
tabs: pages.map((p, i) => ({
|
|
448
|
+
index: i,
|
|
449
|
+
url: redactBrowserUrl(p.url()),
|
|
450
|
+
})),
|
|
328
451
|
console: consoleEntries,
|
|
329
452
|
network: networkEntries,
|
|
330
453
|
};
|
|
331
454
|
if (includeDom) {
|
|
332
455
|
const html = await page.content().catch(() => "");
|
|
333
|
-
state.html = html
|
|
456
|
+
state.html = redactBrowserDom(html, domCap);
|
|
334
457
|
state.htmlTruncated = html.length > domCap;
|
|
335
458
|
}
|
|
336
459
|
if (screenshotPath) {
|
|
337
460
|
await page.screenshot({ path: screenshotPath }).catch((err) => {
|
|
338
|
-
|
|
461
|
+
cleanupFailedScreenshot(screenshotPath, deps);
|
|
462
|
+
state.screenshotError = redactScreenshotFailure(
|
|
463
|
+
err,
|
|
464
|
+
screenshotPath,
|
|
465
|
+
300,
|
|
466
|
+
);
|
|
339
467
|
});
|
|
340
|
-
if (!state.screenshotError)
|
|
468
|
+
if (!state.screenshotError) {
|
|
469
|
+
state.screenshotPath = screenshotPath;
|
|
470
|
+
state.screenshotRef = path.basename(screenshotPath);
|
|
471
|
+
}
|
|
341
472
|
}
|
|
342
473
|
return state;
|
|
343
474
|
} finally {
|
|
@@ -417,8 +548,7 @@ export function resolveLoopbackCdpPort(
|
|
|
417
548
|
}
|
|
418
549
|
|
|
419
550
|
function truncateForAudit(value, cap = 200) {
|
|
420
|
-
|
|
421
|
-
return s.length > cap ? `${s.slice(0, cap)}…` : s;
|
|
551
|
+
return redactBrowserText(value, cap);
|
|
422
552
|
}
|
|
423
553
|
|
|
424
554
|
/**
|
|
@@ -592,7 +722,7 @@ async function runOneAction(page, act, timeoutMs) {
|
|
|
592
722
|
return `selector appeared: ${act.selector}`;
|
|
593
723
|
case "screenshot":
|
|
594
724
|
await page.screenshot({ path: act.screenshotPath });
|
|
595
|
-
return
|
|
725
|
+
return "screenshot captured";
|
|
596
726
|
case "assertText": {
|
|
597
727
|
const text = await page.textContent(act.selector, {
|
|
598
728
|
timeout: timeoutMs,
|
|
@@ -693,16 +823,24 @@ export async function performActions(
|
|
|
693
823
|
for (const act of normalized) {
|
|
694
824
|
const started = Date.now();
|
|
695
825
|
const step = { ok: false, action: act.type, detail: "", durationMs: 0 };
|
|
826
|
+
const pageBefore = redactBrowserUrl(page.url());
|
|
696
827
|
try {
|
|
697
|
-
|
|
828
|
+
const detail = await runOneAction(page, act, stepTimeout);
|
|
829
|
+
step.detail =
|
|
830
|
+
act.type === "navigate"
|
|
831
|
+
? `navigated to ${redactBrowserUrl(act.url)}`
|
|
832
|
+
: redactBrowserText(detail, 500);
|
|
698
833
|
step.ok = true;
|
|
699
|
-
if (act.screenshotPath)
|
|
834
|
+
if (act.screenshotPath) {
|
|
835
|
+
step.screenshotPath = act.screenshotPath;
|
|
836
|
+
step.screenshotRef = path.basename(act.screenshotPath);
|
|
837
|
+
}
|
|
700
838
|
} catch (err) {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
)[0];
|
|
839
|
+
cleanupFailedScreenshot(act.screenshotPath, deps);
|
|
840
|
+
step.detail = redactScreenshotFailure(err, act.screenshotPath, 500);
|
|
704
841
|
}
|
|
705
842
|
step.durationMs = Date.now() - started;
|
|
843
|
+
const pageAfter = redactBrowserUrl(page.url());
|
|
706
844
|
result.steps.push(step);
|
|
707
845
|
try {
|
|
708
846
|
const entry = {
|
|
@@ -710,14 +848,22 @@ export async function performActions(
|
|
|
710
848
|
action: act.type,
|
|
711
849
|
ok: step.ok,
|
|
712
850
|
durationMs: step.durationMs,
|
|
851
|
+
pageBefore,
|
|
852
|
+
pageAfter,
|
|
853
|
+
result: step.detail,
|
|
713
854
|
};
|
|
714
|
-
if (sessionId)
|
|
855
|
+
if (sessionId) {
|
|
856
|
+
entry.sessionId = redactBrowserText(sessionId, 160);
|
|
857
|
+
}
|
|
715
858
|
if (act.selector) entry.selector = truncateForAudit(act.selector);
|
|
716
|
-
if (act.url) entry.url =
|
|
859
|
+
if (act.url) entry.url = redactBrowserUrl(act.url);
|
|
717
860
|
if (act.key) entry.key = truncateForAudit(act.key, 50);
|
|
861
|
+
if (step.ok && act.screenshotPath) {
|
|
862
|
+
entry.screenshotRef = path.basename(act.screenshotPath);
|
|
863
|
+
}
|
|
718
864
|
appendActionAudit(entry, deps);
|
|
719
865
|
} catch (err) {
|
|
720
|
-
auditError = err.message;
|
|
866
|
+
auditError = redactBrowserText(err.message, 300);
|
|
721
867
|
}
|
|
722
868
|
if (!step.ok && !continueOnError) break;
|
|
723
869
|
}
|
|
@@ -727,8 +873,8 @@ export async function performActions(
|
|
|
727
873
|
result.steps.length === normalized.length &&
|
|
728
874
|
result.steps.every((s) => s.ok);
|
|
729
875
|
if (auditError) result.auditError = auditError;
|
|
730
|
-
result.url = page.url();
|
|
731
|
-
result.title = await page.title().catch(() => "");
|
|
876
|
+
result.url = redactBrowserUrl(page.url());
|
|
877
|
+
result.title = redactBrowserText(await page.title().catch(() => ""), 500);
|
|
732
878
|
return result;
|
|
733
879
|
} finally {
|
|
734
880
|
// connectOverCDP close() disconnects the client; the browser lives on.
|
|
@@ -22,7 +22,7 @@ export const _deps = {
|
|
|
22
22
|
},
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
export function loadConfig() {
|
|
25
|
+
export function loadConfig({ failIfUnavailable = false } = {}) {
|
|
26
26
|
const configPath = getConfigPath();
|
|
27
27
|
if (!existsSync(configPath)) {
|
|
28
28
|
return { ...structuredClone(DEFAULT_CONFIG) };
|
|
@@ -32,6 +32,14 @@ export function loadConfig() {
|
|
|
32
32
|
const parsed = JSON.parse(raw);
|
|
33
33
|
return deepMerge(structuredClone(DEFAULT_CONFIG), parsed);
|
|
34
34
|
} catch (err) {
|
|
35
|
+
if (failIfUnavailable) {
|
|
36
|
+
const error = new Error(
|
|
37
|
+
`Could not read durable config at ${configPath}: ${err.message}`,
|
|
38
|
+
{ cause: err },
|
|
39
|
+
);
|
|
40
|
+
error.code = "CONFIG_STORE_UNAVAILABLE";
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
35
43
|
// The file EXISTS but couldn't be read/parsed (a typo, trailing comma, or
|
|
36
44
|
// truncated write). Silently returning defaults drops the user's entire
|
|
37
45
|
// config — provider, model, baseUrl, API key — and falls back to the
|
|
@@ -134,14 +142,20 @@ export function getConfigValue(key) {
|
|
|
134
142
|
export function setConfigValue(key, value) {
|
|
135
143
|
// Serialize the read-modify-write across processes: two concurrent
|
|
136
144
|
// `cc config set` invocations would otherwise each load, mutate, and write
|
|
137
|
-
// back, silently losing one update.
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
+
// back, silently losing one update. Configuration can carry credentials and
|
|
146
|
+
// permission policy, so bounded lock failure must never write unlocked.
|
|
147
|
+
const configPath = getConfigPath();
|
|
148
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
149
|
+
return withFileLock(
|
|
150
|
+
configPath,
|
|
151
|
+
() => {
|
|
152
|
+
const config = loadConfig({ failIfUnavailable: true });
|
|
153
|
+
setNestedValue(config, key, parseValue(value));
|
|
154
|
+
saveConfig(config);
|
|
155
|
+
return config;
|
|
156
|
+
},
|
|
157
|
+
{ failIfUnavailable: true },
|
|
158
|
+
);
|
|
145
159
|
}
|
|
146
160
|
|
|
147
161
|
export function resetConfig() {
|
|
@@ -105,11 +105,32 @@ export function breakdownSkillCache(cache) {
|
|
|
105
105
|
scans: Number(descriptors.scans) || 0,
|
|
106
106
|
cacheHits: Number(descriptors.cacheHits) || 0,
|
|
107
107
|
estimatedTokens: Number(descriptors.estimatedTokens) || 0,
|
|
108
|
+
contextLoads: Number(descriptors.contextLoads) || 0,
|
|
109
|
+
contextTokens: Number(descriptors.contextTokens) || 0,
|
|
110
|
+
entries: Array.isArray(descriptors.entries)
|
|
111
|
+
? descriptors.entries.map((entry) => ({
|
|
112
|
+
id: String(entry?.id || "skill"),
|
|
113
|
+
source: String(entry?.source || "skill"),
|
|
114
|
+
estimatedTokens: Number(entry?.estimatedTokens) || 0,
|
|
115
|
+
contextLoads: Number(entry?.contextLoads) || 0,
|
|
116
|
+
contextTokens: Number(entry?.contextTokens) || 0,
|
|
117
|
+
loadedBecause: Array.isArray(entry?.loadedBecause)
|
|
118
|
+
? entry.loadedBecause.map(String)
|
|
119
|
+
: [],
|
|
120
|
+
}))
|
|
121
|
+
: [],
|
|
108
122
|
},
|
|
109
123
|
bodies: {
|
|
110
124
|
resident: Number(bodies.resident) || 0,
|
|
111
125
|
cacheHits: Number(bodies.cacheHits) || 0,
|
|
112
126
|
cacheMisses: Number(bodies.cacheMisses) || 0,
|
|
127
|
+
estimatedTokensResident:
|
|
128
|
+
Number(bodies.estimatedTokensResident) || 0,
|
|
129
|
+
estimatedTokensServed: Number(bodies.estimatedTokensServed) || 0,
|
|
130
|
+
estimatedTokensAvoidedByCache:
|
|
131
|
+
Number(bodies.estimatedTokensAvoidedByCache) || 0,
|
|
132
|
+
contextLoads: Number(bodies.contextLoads) || 0,
|
|
133
|
+
contextTokens: Number(bodies.contextTokens) || 0,
|
|
113
134
|
entries: Array.isArray(bodies.entries)
|
|
114
135
|
? bodies.entries.map((entry) => ({
|
|
115
136
|
id: String(entry?.id || "skill"),
|
|
@@ -117,6 +138,16 @@ export function breakdownSkillCache(cache) {
|
|
|
117
138
|
estimatedTokens: Number(entry?.estimatedTokens) || 0,
|
|
118
139
|
loads: Number(entry?.loads) || 0,
|
|
119
140
|
cacheHits: Number(entry?.cacheHits) || 0,
|
|
141
|
+
cacheMisses:
|
|
142
|
+
Number(entry?.cacheMisses) ||
|
|
143
|
+
Math.max(
|
|
144
|
+
0,
|
|
145
|
+
(Number(entry?.loads) || 0) -
|
|
146
|
+
(Number(entry?.cacheHits) || 0),
|
|
147
|
+
),
|
|
148
|
+
contextLoads: Number(entry?.contextLoads) || 0,
|
|
149
|
+
contextCacheHits: Number(entry?.contextCacheHits) || 0,
|
|
150
|
+
contextTokens: Number(entry?.contextTokens) || 0,
|
|
120
151
|
loadedBecause: Array.isArray(entry?.loadedBecause)
|
|
121
152
|
? entry.loadedBecause.map(String)
|
|
122
153
|
: [],
|