chainlesschain 0.166.10 → 0.166.14
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/README.md +33 -0
- package/bin/chainlesschain.js +5 -0
- package/package.json +4 -2
- package/src/assets/web-panel/assets/{AIOps-CLYBDAGv.js → AIOps-C8SyFhOo.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CpeSttcu.js → ActionButton-Dup5gFK0.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Ba1TNLG0.js → Analytics-8FyOWA7V.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-xBy8EOeg.js → AppLayout-DBzdU9dg.js} +3 -3
- package/src/assets/web-panel/assets/{Artifacts-CJ_3TFb8.js → Artifacts-C_0Z8gNy.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DUATFCG3.js → Audit-Cf2a-58m.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BRXYPIGp.js → BackgroundAgents-M7w-2zgB.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-D8auLx7y.js → Backup-CCTHQXoL.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CBgdslQ3.js → BaseInput-DjXpeFwJ.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-B32LvAiE.js → Chat-cAvchsJU.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CVfvAy-n.js → ChatBubbleRenderer-DvEvxlZv.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BwzBxOpC.js → Checkbox-DKs6qvOn.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-0U5vrg1H.js → Codegen-DlkA7b9X.js} +1 -1
- package/src/assets/web-panel/assets/{Col-dZ2i4aAj.js → Col-CkfdKhyJ.js} +1 -1
- package/src/assets/web-panel/assets/{Community-UVvpLr8c.js → Community-iNXMHzj6.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BDNEb1Bd.js → Compact-DQxPEd09.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BrzQPxyS.js → Compliance-CSKvMCjs.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BbgGsu-9.js → Cowork-CkWqazpD.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-G321XPhp.js → Cron-k6W8IzhB.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CgLNUyMn.js → Crosschain-C8MS1OuY.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BAfRj18q.js → DID-DJuCcgiQ.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-BNIxA4TK.js → Dashboard-LeThKzp3.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BLAUmCAN.js → Dropdown-BvxwgpE4.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CsnhTW22.js → EmailListRenderer-n3e_a1M3.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-zcQ7Ip1n.js → FamilyGuardDashboard-509W6W6v.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-KFwxodNU.js → Federation-xgZReQm0.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-3CYRLEHG.js → FormItemContext-jZOhKcQx.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-D3d9D8L9.js → GenericCardRenderer-Jo0ULzHv.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BJ202nJY.js → Git-BsRcyWQP.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-ClnnXVQ-.js → Governance-JlpMYTAk.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DNU-PTkc.js → Inference-CUEz872-.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DJuinbuY.js → KnowledgeGraph-DgrvvEDU.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-D4No-46s.js → Logs-Df-KY4U3.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BEPDcSwz.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Ba-KqRN3.js → Marketplace-kPZDTOeI.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DVoxnPgE.js → McpTools-CRRzPqNX.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-D_C8gzAZ.js → Memory-D6pNSkg9.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DnzTPcDH.js → MobileBridge-g-pvtwRC.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-Bzayfrfe.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-CvEHmHId.js → Mtc-B7S3W-XL.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-VNJmWqmv.js → MtcAudit-B8OMEWVb.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-BO0x_Vsa.js → Multisig-CowRp7GH.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CM2gI1UY.js → NLProgramming-BkQNyi4c.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CMc1HsML.js → Notes-Cm7gtkKz.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DGNmSKGM.js → NotificationSettings-CbPTVh9m.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-Du-Kct3p.js → OrderTableRenderer-Dswi26mJ.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DRtRZjas.js → Organization-BkjQ9yy7.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Dp4OeWsn.js → Overflow-DmRFXP7Y.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DXMJVls8.js → P2P-DQE1toAu.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-BujyoDRG.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-D1Hbb51o.js → Permissions-xSjfOaiU.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BridiDhr.js → PersonalDataHub-B9ICLqVP.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-B4bUNCm1.js → Pipeline-CUNwyN9E.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BTu_HEqK.js → Privacy-SOoCricX.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-SVtL2hnt.js → ProjectInit-CSaFul0F.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-B2Sh7JZ2.js → ProjectSettings-CueiB_oe.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BwU1xalW.js → Projects-BOeXvU7y.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-BWdWQSDw.js → Providers-CTqf_31h.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-Brzc-Sxb.js → QrScannerModal-C8ZP31E9.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DIBz7FCe.js → QuickAsk-CPgn4713.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CZ8RriIJ.js → Recommend-8_e0zw0i.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-CM0KJQ3t.js → RemoteSession-iT7lbGqw.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-D_wo8H0O.js → Reputation-B4q9SUOz.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D1G1fD7N.js → Row-CA_nASyL.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-dKCVtA0K.js → RssFeed-Cwb0E3yv.js} +2 -2
- package/src/assets/web-panel/assets/{Search-Be1D61xo.js → Search-D9iVsOxJ.js} +1 -1
- package/src/assets/web-panel/assets/{Security-IbNiR6OC.js → Security-DPLbYchG.js} +3 -3
- package/src/assets/web-panel/assets/{Services-nuHK8y8p.js → Services-DGMVL_LF.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DnM5jdnC.js → Skeleton-B_6kym0D.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DCTdoq_q.js → Skills-Ds6r0dXB.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DlWun-Ui.js → Sla-BLHAbBhb.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-C19kv2sd.js → SpeechSettings-CZuddd14.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CkQIR_Hu.js → SyncSettings-CdBq7oSl.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-DdbqOEbs.js → Tasks-DfT60Nyl.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-B7GpIXeo.js → Templates-RLfsKy2V.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-ByEstFhY.js → Tenant-Cw8xCNLE.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BKRVID1a.js → Terminal-BOUkNu4f.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CNS3dHNv.js → TimelineRenderer-CgGZWaRm.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BykqylCL.js → Tokens-CpwjVyir.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-ByNxq51W.js → Trigger-DL21H-eb.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BlrFsdaS.js → Trust-B3ffFclW.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Dg26A-sd.js → UkeySign-CkBeb5aI.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-C1wUxNn0.js → VideoEditing-U2iVaE3r.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-OphEUzI4.js → Wallet-CQk2wzYd.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-_8lL08hF.js → WebAuthn-DYIuIYzT.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-BnTuIvnP.js → WorkflowEditor-tg1c2mZQ.js} +1 -1
- package/src/assets/web-panel/assets/{chat-3N3VLQYr.js → chat-CtL61spq.js} +1 -1
- package/src/assets/web-panel/assets/{colors-Bo_G96gg.js → colors-DKpbeo8s.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DjubfjI_.js → compact-item-gPZsrswt.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Cx_HSLCk.js → createContext-CfHlwzVr.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DdqnMhzi.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D5OjAOlA.js → hasIn-MV47g_6X.js} +1 -1
- package/src/assets/web-panel/assets/{index-x7o-2T3S.js → index-6G0ETFTW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqZq3zWr.js → index-BBw52sEl.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-4sfa0l.js → index-BN-wxSQ8.js} +1 -1
- package/src/assets/web-panel/assets/{index-uAcJUJkx.js → index-BOyGUuBE.js} +1 -1
- package/src/assets/web-panel/assets/{index-CC7RnaPP.js → index-BQp5M0s1.js} +1 -1
- package/src/assets/web-panel/assets/index-BcK8o4ke.js +1 -0
- package/src/assets/web-panel/assets/{index-CNmsP0Xf.js → index-BjlPD7GO.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVPDhmVH.js → index-C4lF-f_z.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRKk1JPX.js → index-C6nC_DyY.js} +1 -1
- package/src/assets/web-panel/assets/{index-B905-Mcs.js → index-C9RF4ieu.js} +1 -1
- package/src/assets/web-panel/assets/{index-3_CEBEEf.js → index-C9gtY4nG.js} +3 -3
- package/src/assets/web-panel/assets/{index-Y-H7j25u.js → index-CB1HnbNK.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5IwN9q3.js → index-CRv_uMLV.js} +1 -1
- package/src/assets/web-panel/assets/{index-Q_vn0t8d.js → index-C_B9LiKs.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cz5tQ5PY.js → index-Cjv0kKCU.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgPb37tI.js → index-CmM9jqwe.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dbdr8tVi.js → index-CmPJpLoD.js} +1 -1
- package/src/assets/web-panel/assets/{index-DrVjatPe.js → index-CzfxTSPW.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-_Cy0k_.js → index-D1XB5-t5.js} +1 -1
- package/src/assets/web-panel/assets/{index-C8dPFFhy.js → index-DGtEBodr.js} +1 -1
- package/src/assets/web-panel/assets/{index-UnpsQ6A0.js → index-DIeJmlAA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxgIE4PD.js → index-DMMvlLp9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlcbE0sX.js → index-DU4rZpiK.js} +1 -1
- package/src/assets/web-panel/assets/{index-EZr3bvz2.js → index-D_Pl1GnW.js} +1 -1
- package/src/assets/web-panel/assets/{index-BScGr1BY.js → index-Dd19vRwy.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ce8EWU6r.js → index-Ddcpj1El.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCjq3g32.js → index-Df9sWKpl.js} +1 -1
- package/src/assets/web-panel/assets/{index-ydnEPOzZ.js → index-DfLyHCWi.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4MAnkl5.js → index-DnZ_zS1M.js} +1 -1
- package/src/assets/web-panel/assets/{index-DXJqa1-I.js → index-DsH-i_3d.js} +1 -1
- package/src/assets/web-panel/assets/index-DvbAjyYI.js +1 -0
- package/src/assets/web-panel/assets/{index-DBvZhdCb.js → index-ExAGPAnX.js} +1 -1
- package/src/assets/web-panel/assets/{index-DD1zSPZH.js → index-Rb7CRMw9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DE4XtzMl.js → index-Zvkt9xqi.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmLwI-Y8.js → index-bSFrAszw.js} +1 -1
- package/src/assets/web-panel/assets/{index-HioDjvUF.js → index-fYcS7NS0.js} +1 -1
- package/src/assets/web-panel/assets/{index-BvYo09C0.js → index-srBc9U_s.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bj7S5IJw.js → index-xUlgG0Xe.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaU60K3A.js → index-yxxXlqBA.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DurpENJY.js → initDefaultProps-BeOZoSZ4.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CIh-z-gR.js → motion-BXE8VMKx.js} +1 -1
- package/src/assets/web-panel/assets/{move-Uc_yI2NA.js → move-I9sdvPGX.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DUevj5wz.js → mtc-parser-d25zrJd0.js} +1 -1
- package/src/assets/web-panel/assets/{omit-85eMYyur.js → omit-D71V_T4e.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-AuxDD20F.js → pickAttrs-BNZKpIAR.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DOWn8dd1.js → placementArrow-jOcgxTTz.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CPxTWodH.js → responsiveObserve-pta_O8AU.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BqvbGPjx.js → slide-Dlq6om7z.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BzXKkV8d.js → statusUtils-BnkO_yRv.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B2O7yRk3.js → styleChecker-p8NfWmcG.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DRWp7px1.js → useFlexGapSupport-KcjZZ5U7.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-Dp0V7sjM.js → useFs-gqonDMWB.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CyCrG3ql.js → usePersonalDataHub-jIIfE4go.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CXhoFpFo.js → vnode-Dyo7fBrM.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-0z3mtwEg.js → zoom-6l8BMg9W.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +5 -5
- package/src/commands/agent.js +76 -23
- package/src/commands/compact.js +349 -3
- package/src/commands/context.js +72 -1
- package/src/commands/graph.js +26 -15
- package/src/commands/hmemory.js +21 -0
- package/src/commands/hook.js +256 -28
- package/src/commands/memory.js +209 -42
- package/src/commands/promcomp.js +17 -0
- package/src/commands/record-replay.js +772 -0
- package/src/commands/serve.js +94 -10
- package/src/commands/session.js +2 -3
- package/src/commands/skill.js +3 -0
- package/src/commands/team.js +7 -1
- package/src/data/changelog.json +41 -2
- package/src/gateways/ws/session-core-protocol.js +62 -3
- package/src/gateways/ws/session-protocol.js +123 -15
- package/src/gateways/ws/ws-agent-handler.js +157 -9
- package/src/gateways/ws/ws-session-gateway.js +204 -30
- package/src/generated/cc-agent-protocol.schema.json +2094 -4
- package/src/harness/prompt-compressor.js +5 -55
- package/src/lib/agent-sandbox.js +8 -2
- package/src/lib/agent-team/team-distributed-graph-bridge.js +3 -3
- package/src/lib/agent-team/team-message-tools.js +23 -5
- package/src/lib/app-server/context-memory-notifications.js +54 -0
- package/src/lib/app-server/rollout-store-factory.js +115 -0
- package/src/lib/app-server/rollout-store.js +310 -23
- package/src/lib/app-server/server.js +184 -7
- package/src/lib/app-server/sqlite-rollout-store.js +59 -16
- package/src/lib/auto-mode-config.js +26 -0
- package/src/lib/causal-observability.js +13 -1
- package/src/lib/context-memory-kernel/authority.js +95 -0
- package/src/lib/context-memory-kernel/durable-memory-port.js +296 -0
- package/src/lib/context-memory-kernel/index.js +8 -0
- package/src/lib/context-memory-kernel/jsonl-session-context-port.js +232 -0
- package/src/lib/context-memory-kernel/live-compaction.js +375 -0
- package/src/lib/context-memory-kernel/memory-service.js +667 -0
- package/src/lib/context-memory-kernel/message-adapter.js +451 -0
- package/src/lib/context-memory-kernel/privacy-purge-port.js +244 -0
- package/src/lib/context-memory-kernel/provider-context.js +192 -0
- package/src/lib/context-memory-kernel/runtime.js +61 -0
- package/src/lib/direct-model-usage.js +22 -18
- package/src/lib/graph-kernel/cutover-authority-resolver.js +4 -5
- package/src/lib/graph-kernel/cutover-ledger.js +2 -2
- package/src/lib/graph-kernel/event-store.js +3 -5
- package/src/lib/graph-kernel/migration-saga.js +2 -2
- package/src/lib/graph-kernel/production-cutover-evidence.js +8 -1
- package/src/lib/hierarchical-memory.js +22 -0
- package/src/lib/hook-audit-store.js +170 -0
- package/src/lib/hook-event-bus.cjs +0 -0
- package/src/lib/hook-manager.js +25 -83
- package/src/lib/hook-runtime-adapters.js +233 -0
- package/src/lib/hook-runtime-contract.cjs +291 -0
- package/src/lib/hook-runtime-contract.js +21 -0
- package/src/lib/hook-trust.js +210 -0
- package/src/lib/hooks-v2-producers.js +52 -6
- package/src/lib/hooks-v2-runtime.js +443 -178
- package/src/lib/llm-pricing.js +10 -0
- package/src/lib/memory-manager.js +29 -4
- package/src/lib/model-context-window.js +52 -0
- package/src/lib/permanent-memory.js +17 -0
- package/src/lib/plan-mode.js +8 -4
- package/src/lib/process-execution-broker/credential-transport.js +31 -0
- package/src/lib/process-execution-broker/index.js +282 -16
- 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 +7 -3
- package/src/lib/record-replay/browser-target-policy.js +406 -0
- package/src/lib/record-replay/index.js +4 -0
- package/src/lib/record-replay/playwright-ui-driver.js +83 -20
- package/src/lib/record-replay/playwright-ui-recorder.js +611 -0
- package/src/lib/record-replay/recorded-skill-package.js +486 -0
- package/src/lib/record-replay/recorded-skill-store.js +1166 -0
- package/src/lib/record-replay/skill-recorder.js +634 -64
- package/src/lib/runtime-usage-ledger.js +20 -0
- package/src/lib/session-consolidator.js +59 -0
- package/src/lib/session-core-singletons.js +17 -4
- package/src/lib/session-hooks.js +29 -2
- package/src/lib/session-transcript-migration.js +188 -0
- package/src/lib/settings-hook-events.cjs +37 -401
- package/src/lib/settings-hook-events.js +210 -8
- package/src/lib/settings-hooks.cjs +42 -83
- package/src/lib/ws-session-manager.js +4 -1
- package/src/repl/agent-repl.js +186 -53
- package/src/runtime/agent-core.js +376 -350
- package/src/runtime/headless-runner.js +112 -84
- package/src/runtime/headless-stream.js +131 -30
- package/src/assets/web-panel/assets/MarkdownRenderer-Dt8hH_qA.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-Jg2dVUc-.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-0jYeVmyY.js +0 -7
- package/src/assets/web-panel/assets/devWarning-BX944k9E.js +0 -1
- package/src/assets/web-panel/assets/index-C_9Jt_SR.js +0 -1
- package/src/assets/web-panel/assets/index-DL2EFx7m.js +0 -1
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
const MAX_HTML_CHARS = 1_000_000;
|
|
4
|
+
const MAX_ALLOWED_ORIGINS = 8;
|
|
5
|
+
const MAX_URL_CHARS = 4_096;
|
|
6
|
+
const MAX_STORAGE_STATE_BYTES = 2 * 1024 * 1024;
|
|
7
|
+
const MAX_STORAGE_STATE_DEPTH = 16;
|
|
8
|
+
const MAX_STORAGE_STATE_NODES = 10_000;
|
|
9
|
+
const SHA256_PATTERN = /^sha256:[a-f0-9]{64}$/u;
|
|
10
|
+
|
|
11
|
+
function targetError(code, message) {
|
|
12
|
+
const error = new Error(message);
|
|
13
|
+
error.name = "RecordedSkillBrowserTargetError";
|
|
14
|
+
error.code = code;
|
|
15
|
+
return error;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function canonicalValue(value) {
|
|
19
|
+
if (Array.isArray(value)) return value.map(canonicalValue);
|
|
20
|
+
if (!value || typeof value !== "object") return value;
|
|
21
|
+
return Object.fromEntries(
|
|
22
|
+
Object.keys(value)
|
|
23
|
+
.sort()
|
|
24
|
+
.map((key) => [key, canonicalValue(value[key])]),
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function deepFreeze(value) {
|
|
29
|
+
if (!value || typeof value !== "object" || Object.isFrozen(value))
|
|
30
|
+
return value;
|
|
31
|
+
for (const child of Object.values(value)) deepFreeze(child);
|
|
32
|
+
return Object.freeze(value);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function boundedCanonicalStorageState(value) {
|
|
36
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
37
|
+
throw targetError(
|
|
38
|
+
"CC_RECORD_TARGET_INVALID",
|
|
39
|
+
"browser storage state must be a JSON object",
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
const seen = new WeakSet();
|
|
43
|
+
const pending = [{ value, depth: 0 }];
|
|
44
|
+
let nodes = 0;
|
|
45
|
+
while (pending.length > 0) {
|
|
46
|
+
const current = pending.pop();
|
|
47
|
+
const item = current.value;
|
|
48
|
+
nodes += 1;
|
|
49
|
+
if (
|
|
50
|
+
nodes > MAX_STORAGE_STATE_NODES ||
|
|
51
|
+
current.depth > MAX_STORAGE_STATE_DEPTH
|
|
52
|
+
) {
|
|
53
|
+
throw targetError(
|
|
54
|
+
"CC_RECORD_TARGET_INVALID",
|
|
55
|
+
"browser storage state exceeds its structural limits",
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
if (!item || typeof item !== "object") {
|
|
59
|
+
if (
|
|
60
|
+
typeof item === "undefined" ||
|
|
61
|
+
typeof item === "bigint" ||
|
|
62
|
+
typeof item === "function" ||
|
|
63
|
+
typeof item === "symbol" ||
|
|
64
|
+
(typeof item === "number" && !Number.isFinite(item))
|
|
65
|
+
) {
|
|
66
|
+
throw targetError(
|
|
67
|
+
"CC_RECORD_TARGET_INVALID",
|
|
68
|
+
"browser storage state must contain only JSON values",
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (seen.has(item)) {
|
|
74
|
+
throw targetError(
|
|
75
|
+
"CC_RECORD_TARGET_INVALID",
|
|
76
|
+
"browser storage state must not contain cycles or shared objects",
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
seen.add(item);
|
|
80
|
+
if (
|
|
81
|
+
!Array.isArray(item) &&
|
|
82
|
+
Object.getPrototypeOf(item) !== Object.prototype
|
|
83
|
+
) {
|
|
84
|
+
throw targetError(
|
|
85
|
+
"CC_RECORD_TARGET_INVALID",
|
|
86
|
+
"browser storage state must contain plain JSON objects",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
const children = Array.isArray(item) ? item : Object.values(item);
|
|
90
|
+
if (children.length > MAX_STORAGE_STATE_NODES) {
|
|
91
|
+
throw targetError(
|
|
92
|
+
"CC_RECORD_TARGET_INVALID",
|
|
93
|
+
"browser storage state exceeds its structural limits",
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
for (const child of children) {
|
|
97
|
+
pending.push({ value: child, depth: current.depth + 1 });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const canonical = canonicalValue(value);
|
|
101
|
+
if (
|
|
102
|
+
Buffer.byteLength(JSON.stringify(canonical), "utf8") >
|
|
103
|
+
MAX_STORAGE_STATE_BYTES
|
|
104
|
+
) {
|
|
105
|
+
throw targetError(
|
|
106
|
+
"CC_RECORD_TARGET_INVALID",
|
|
107
|
+
"browser storage state exceeds the 2 MiB limit",
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
return deepFreeze(canonical);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function digest(value, domain) {
|
|
114
|
+
const bytes = Buffer.isBuffer(value)
|
|
115
|
+
? value
|
|
116
|
+
: Buffer.from(
|
|
117
|
+
typeof value === "string"
|
|
118
|
+
? value
|
|
119
|
+
: JSON.stringify(canonicalValue(value)),
|
|
120
|
+
);
|
|
121
|
+
return `sha256:${createHash("sha256")
|
|
122
|
+
.update(domain)
|
|
123
|
+
.update("\0")
|
|
124
|
+
.update(bytes)
|
|
125
|
+
.digest("hex")}`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function isLoopback(hostname) {
|
|
129
|
+
const normalized = String(hostname || "").toLowerCase();
|
|
130
|
+
return (
|
|
131
|
+
normalized === "localhost" ||
|
|
132
|
+
normalized === "127.0.0.1" ||
|
|
133
|
+
normalized === "[::1]" ||
|
|
134
|
+
normalized === "::1"
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function safeUrl(value, { originOnly = false } = {}) {
|
|
139
|
+
if (
|
|
140
|
+
typeof value !== "string" ||
|
|
141
|
+
value.length < 1 ||
|
|
142
|
+
value.length > MAX_URL_CHARS
|
|
143
|
+
) {
|
|
144
|
+
throw targetError(
|
|
145
|
+
"CC_RECORD_TARGET_INVALID",
|
|
146
|
+
`browser target URL must be no longer than ${MAX_URL_CHARS} characters`,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
let parsed;
|
|
150
|
+
try {
|
|
151
|
+
parsed = new URL(String(value));
|
|
152
|
+
} catch {
|
|
153
|
+
throw targetError(
|
|
154
|
+
"CC_RECORD_TARGET_INVALID",
|
|
155
|
+
"browser target must be an absolute URL",
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
if (
|
|
159
|
+
parsed.username ||
|
|
160
|
+
parsed.password ||
|
|
161
|
+
(parsed.protocol !== "https:" &&
|
|
162
|
+
!(parsed.protocol === "http:" && isLoopback(parsed.hostname)))
|
|
163
|
+
) {
|
|
164
|
+
throw targetError(
|
|
165
|
+
"CC_RECORD_TARGET_INVALID",
|
|
166
|
+
"browser targets require HTTPS; HTTP is allowed only for loopback testing and URL credentials are forbidden",
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
if (originOnly && parsed.href !== `${parsed.origin}/`) {
|
|
170
|
+
throw targetError(
|
|
171
|
+
"CC_RECORD_TARGET_INVALID",
|
|
172
|
+
"allowed origins must not contain a path, query, or fragment",
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
return parsed;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function createRecordedSkillNetworkPolicy({
|
|
179
|
+
mode = "deny",
|
|
180
|
+
allowedOrigins = [],
|
|
181
|
+
} = {}) {
|
|
182
|
+
if (mode === "deny") {
|
|
183
|
+
if (!Array.isArray(allowedOrigins) || allowedOrigins.length > 0) {
|
|
184
|
+
throw targetError(
|
|
185
|
+
"CC_RECORD_TARGET_INVALID",
|
|
186
|
+
"deny network policy cannot retain allowed origins",
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
const body = { mode: "deny", allowedOrigins: [] };
|
|
190
|
+
return deepFreeze({
|
|
191
|
+
...body,
|
|
192
|
+
digest: digest(body, "cc.record-replay.network-policy/v1"),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (mode !== "allowlist" || !Array.isArray(allowedOrigins)) {
|
|
196
|
+
throw targetError(
|
|
197
|
+
"CC_RECORD_TARGET_INVALID",
|
|
198
|
+
"browser network policy is invalid",
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
const origins = [
|
|
202
|
+
...new Set(
|
|
203
|
+
allowedOrigins.map(
|
|
204
|
+
(value) => safeUrl(value, { originOnly: true }).origin,
|
|
205
|
+
),
|
|
206
|
+
),
|
|
207
|
+
].sort();
|
|
208
|
+
if (origins.length < 1 || origins.length > MAX_ALLOWED_ORIGINS) {
|
|
209
|
+
throw targetError(
|
|
210
|
+
"CC_RECORD_TARGET_INVALID",
|
|
211
|
+
`browser target requires between 1 and ${MAX_ALLOWED_ORIGINS} allowed origins`,
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
const body = { mode: "allowlist", allowedOrigins: origins };
|
|
215
|
+
return deepFreeze({
|
|
216
|
+
...body,
|
|
217
|
+
digest: digest(body, "cc.record-replay.network-policy/v1"),
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function digestRecordedSkillStorageState(storageState) {
|
|
222
|
+
if (storageState == null) return null;
|
|
223
|
+
return digest(
|
|
224
|
+
boundedCanonicalStorageState(storageState),
|
|
225
|
+
"cc.record-replay.browser-storage-state/v1",
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function prepareRecordedSkillBrowserTarget({
|
|
230
|
+
html,
|
|
231
|
+
url,
|
|
232
|
+
allowedOrigins = [],
|
|
233
|
+
storageState,
|
|
234
|
+
identity = "anonymous",
|
|
235
|
+
} = {}) {
|
|
236
|
+
const hasHtml = typeof html === "string" && html.length > 0;
|
|
237
|
+
const hasUrl = typeof url === "string" && url.length > 0;
|
|
238
|
+
if (hasHtml === hasUrl) {
|
|
239
|
+
throw targetError(
|
|
240
|
+
"CC_RECORD_TARGET_INVALID",
|
|
241
|
+
"provide exactly one self-contained HTML fixture or URL target",
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
const safeIdentity = String(identity || "anonymous").trim();
|
|
245
|
+
if (!/^[A-Za-z][A-Za-z0-9._-]{0,127}$/u.test(safeIdentity)) {
|
|
246
|
+
throw targetError(
|
|
247
|
+
"CC_RECORD_TARGET_INVALID",
|
|
248
|
+
"browser identity label is invalid",
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
if (hasHtml) {
|
|
252
|
+
if (
|
|
253
|
+
html.length > MAX_HTML_CHARS ||
|
|
254
|
+
allowedOrigins.length > 0 ||
|
|
255
|
+
storageState != null
|
|
256
|
+
) {
|
|
257
|
+
throw targetError(
|
|
258
|
+
"CC_RECORD_TARGET_INVALID",
|
|
259
|
+
"self-contained HTML recording cannot use network origins or browser credentials",
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
const networkPolicy = createRecordedSkillNetworkPolicy({ mode: "deny" });
|
|
263
|
+
return deepFreeze({
|
|
264
|
+
adapter: "self-contained-html",
|
|
265
|
+
html,
|
|
266
|
+
url: null,
|
|
267
|
+
targetDigest: digest(html, "cc.record-replay.ui-fixture/v1"),
|
|
268
|
+
networkPolicy,
|
|
269
|
+
storageState: null,
|
|
270
|
+
storageStateDigest: null,
|
|
271
|
+
identity: safeIdentity,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
const target = safeUrl(url);
|
|
275
|
+
const networkPolicy = createRecordedSkillNetworkPolicy({
|
|
276
|
+
mode: "allowlist",
|
|
277
|
+
allowedOrigins:
|
|
278
|
+
allowedOrigins.length > 0 ? allowedOrigins : [target.origin],
|
|
279
|
+
});
|
|
280
|
+
if (!networkPolicy.allowedOrigins.includes(target.origin)) {
|
|
281
|
+
throw targetError(
|
|
282
|
+
"CC_RECORD_TARGET_INVALID",
|
|
283
|
+
"target origin must be present in the network allowlist",
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
const normalizedStorageState =
|
|
287
|
+
storageState == null ? null : boundedCanonicalStorageState(storageState);
|
|
288
|
+
return deepFreeze({
|
|
289
|
+
adapter: "url-origin",
|
|
290
|
+
html: null,
|
|
291
|
+
url: target.href,
|
|
292
|
+
targetDigest: digest(target.href, "cc.record-replay.ui-url/v1"),
|
|
293
|
+
networkPolicy,
|
|
294
|
+
storageState: normalizedStorageState,
|
|
295
|
+
storageStateDigest: digestRecordedSkillStorageState(normalizedStorageState),
|
|
296
|
+
identity: safeIdentity,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export function recordedSkillBrowserEnvironment(target) {
|
|
301
|
+
if (
|
|
302
|
+
!target ||
|
|
303
|
+
!["self-contained-html", "url-origin"].includes(target.adapter) ||
|
|
304
|
+
!SHA256_PATTERN.test(String(target.targetDigest || ""))
|
|
305
|
+
) {
|
|
306
|
+
throw targetError(
|
|
307
|
+
"CC_RECORD_TARGET_INVALID",
|
|
308
|
+
"prepared browser target is invalid",
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
return deepFreeze({
|
|
312
|
+
adapter: target.adapter,
|
|
313
|
+
browser: "chromium",
|
|
314
|
+
targetDigest: target.targetDigest,
|
|
315
|
+
selectorContract: "record-replay-dom-v1",
|
|
316
|
+
networkPolicy: Object.freeze({
|
|
317
|
+
mode: target.networkPolicy.mode,
|
|
318
|
+
allowedOrigins: Object.freeze([...target.networkPolicy.allowedOrigins]),
|
|
319
|
+
digest: target.networkPolicy.digest,
|
|
320
|
+
}),
|
|
321
|
+
identity: target.identity,
|
|
322
|
+
storageStateDigest: target.storageStateDigest,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export function assertRecordedSkillBrowserBinding(
|
|
327
|
+
target,
|
|
328
|
+
{ source, environment } = {},
|
|
329
|
+
) {
|
|
330
|
+
let reviewedPolicy;
|
|
331
|
+
try {
|
|
332
|
+
reviewedPolicy = createRecordedSkillNetworkPolicy({
|
|
333
|
+
mode: environment?.networkPolicy?.mode,
|
|
334
|
+
allowedOrigins: environment?.networkPolicy?.allowedOrigins || [],
|
|
335
|
+
});
|
|
336
|
+
} catch {
|
|
337
|
+
reviewedPolicy = null;
|
|
338
|
+
}
|
|
339
|
+
if (
|
|
340
|
+
!source ||
|
|
341
|
+
target?.adapter !== source.adapter ||
|
|
342
|
+
target?.targetDigest !== source.targetDigest ||
|
|
343
|
+
environment?.adapter !== source.adapter ||
|
|
344
|
+
environment?.targetDigest !== source.targetDigest
|
|
345
|
+
) {
|
|
346
|
+
throw targetError(
|
|
347
|
+
"CC_RECORD_TARGET_DRIFT",
|
|
348
|
+
"browser target no longer matches the reviewed recording",
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
if (
|
|
352
|
+
(environment.storageStateDigest || null) !==
|
|
353
|
+
(target.storageStateDigest || null)
|
|
354
|
+
) {
|
|
355
|
+
throw targetError(
|
|
356
|
+
"CC_RECORD_CREDENTIAL_DRIFT",
|
|
357
|
+
"browser storage state no longer matches the reviewed credential binding",
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
if (
|
|
361
|
+
environment.identity !== target.identity ||
|
|
362
|
+
reviewedPolicy?.digest !== environment.networkPolicy?.digest ||
|
|
363
|
+
reviewedPolicy?.digest !== target.networkPolicy?.digest
|
|
364
|
+
) {
|
|
365
|
+
throw targetError(
|
|
366
|
+
"CC_RECORD_ENVIRONMENT_DRIFT",
|
|
367
|
+
"browser identity or network policy no longer matches the reviewed recording",
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
return true;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export function requestAllowedByRecordedSkillPolicy(rawUrl, target) {
|
|
374
|
+
let parsed;
|
|
375
|
+
try {
|
|
376
|
+
parsed = new URL(String(rawUrl));
|
|
377
|
+
} catch {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
if (["about:", "data:"].includes(parsed.protocol)) return true;
|
|
381
|
+
if (parsed.protocol === "blob:") {
|
|
382
|
+
return (
|
|
383
|
+
target.networkPolicy.mode === "allowlist" &&
|
|
384
|
+
target.networkPolicy.allowedOrigins.includes(parsed.origin)
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
if (!["http:", "https:"].includes(parsed.protocol)) return false;
|
|
388
|
+
return (
|
|
389
|
+
target.networkPolicy.mode === "allowlist" &&
|
|
390
|
+
target.networkPolicy.allowedOrigins.includes(parsed.origin)
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export function navigationAllowedByRecordedSkillPolicy(rawUrl, target) {
|
|
395
|
+
let parsed;
|
|
396
|
+
try {
|
|
397
|
+
parsed = new URL(String(rawUrl));
|
|
398
|
+
} catch {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
return (
|
|
402
|
+
["http:", "https:"].includes(parsed.protocol) &&
|
|
403
|
+
target.networkPolicy.mode === "allowlist" &&
|
|
404
|
+
target.networkPolicy.allowedOrigins.includes(parsed.origin)
|
|
405
|
+
);
|
|
406
|
+
}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { executionBroker } from "../process-execution-broker/index.js";
|
|
3
|
+
import {
|
|
4
|
+
createRecordedSkillNetworkPolicy,
|
|
5
|
+
navigationAllowedByRecordedSkillPolicy,
|
|
6
|
+
prepareRecordedSkillBrowserTarget,
|
|
7
|
+
requestAllowedByRecordedSkillPolicy,
|
|
8
|
+
} from "./browser-target-policy.js";
|
|
2
9
|
|
|
3
10
|
const ACTION_CAPABILITIES = Object.freeze({
|
|
4
11
|
observe: "ui.observe",
|
|
@@ -7,11 +14,7 @@ const ACTION_CAPABILITIES = Object.freeze({
|
|
|
7
14
|
type: "ui.interact",
|
|
8
15
|
select: "ui.interact",
|
|
9
16
|
});
|
|
10
|
-
const DRIVER_CAPABILITIES = Object.freeze([
|
|
11
|
-
"ui.interact",
|
|
12
|
-
"ui.observe",
|
|
13
|
-
]);
|
|
14
|
-
const DENIED_SCHEMES = new Set(["file:", "http:", "https:", "ws:", "wss:"]);
|
|
17
|
+
const DRIVER_CAPABILITIES = Object.freeze(["ui.interact", "ui.observe"]);
|
|
15
18
|
|
|
16
19
|
function driverError(code, message, details = {}) {
|
|
17
20
|
const error = new Error(message);
|
|
@@ -68,11 +71,17 @@ function requestMetadata(request) {
|
|
|
68
71
|
}
|
|
69
72
|
return Object.freeze({
|
|
70
73
|
scheme,
|
|
71
|
-
method: String(request.method?.() || "GET")
|
|
74
|
+
method: String(request.method?.() || "GET")
|
|
75
|
+
.toUpperCase()
|
|
76
|
+
.slice(0, 16),
|
|
72
77
|
});
|
|
73
78
|
}
|
|
74
79
|
|
|
75
|
-
async function locatorState(
|
|
80
|
+
async function locatorState(
|
|
81
|
+
locator,
|
|
82
|
+
timeoutMs,
|
|
83
|
+
{ allowDetached = false } = {},
|
|
84
|
+
) {
|
|
76
85
|
const count = await locator.count();
|
|
77
86
|
if (count !== 1) {
|
|
78
87
|
if (allowDetached && count === 0) {
|
|
@@ -136,12 +145,22 @@ async function assertAction(locator, action, timeoutMs) {
|
|
|
136
145
|
*/
|
|
137
146
|
export async function launchPlaywrightRecordedSkillDriver({
|
|
138
147
|
html,
|
|
148
|
+
url,
|
|
149
|
+
allowedOrigins = [],
|
|
150
|
+
storageState,
|
|
151
|
+
identity = "anonymous",
|
|
139
152
|
playwright,
|
|
140
153
|
timeoutMs = 5_000,
|
|
141
154
|
settleMs = 25,
|
|
142
155
|
viewport = { width: 960, height: 640 },
|
|
143
156
|
} = {}) {
|
|
144
|
-
const
|
|
157
|
+
const target = prepareRecordedSkillBrowserTarget({
|
|
158
|
+
html,
|
|
159
|
+
url,
|
|
160
|
+
allowedOrigins,
|
|
161
|
+
storageState,
|
|
162
|
+
identity,
|
|
163
|
+
});
|
|
145
164
|
if (!Number.isInteger(timeoutMs) || timeoutMs < 100 || timeoutMs > 30_000) {
|
|
146
165
|
throw driverError(
|
|
147
166
|
"CC_REPLAY_UI_ARGUMENT_INVALID",
|
|
@@ -163,11 +182,23 @@ export async function launchPlaywrightRecordedSkillDriver({
|
|
|
163
182
|
);
|
|
164
183
|
}
|
|
165
184
|
|
|
166
|
-
const
|
|
185
|
+
const executablePath = runtime.chromium.executablePath?.();
|
|
186
|
+
const browser = executablePath
|
|
187
|
+
? await executionBroker.runWithProcessContext(
|
|
188
|
+
{
|
|
189
|
+
origin: "record-replay:chromium-driver",
|
|
190
|
+
policy: "allow",
|
|
191
|
+
allowedCommands: [executablePath],
|
|
192
|
+
auditContext: { actor: "record-replay-driver" },
|
|
193
|
+
},
|
|
194
|
+
() => runtime.chromium.launch({ headless: true, executablePath }),
|
|
195
|
+
)
|
|
196
|
+
: await runtime.chromium.launch({ headless: true });
|
|
167
197
|
const context = await browser.newContext({
|
|
168
198
|
viewport: safeViewport,
|
|
169
199
|
acceptDownloads: false,
|
|
170
200
|
serviceWorkers: "block",
|
|
201
|
+
storageState: target.storageState || undefined,
|
|
171
202
|
});
|
|
172
203
|
const deniedRequests = [];
|
|
173
204
|
const receipts = [];
|
|
@@ -175,19 +206,32 @@ export async function launchPlaywrightRecordedSkillDriver({
|
|
|
175
206
|
try {
|
|
176
207
|
await context.route("**/*", async (route) => {
|
|
177
208
|
const metadata = requestMetadata(route.request());
|
|
178
|
-
if (
|
|
209
|
+
if (!requestAllowedByRecordedSkillPolicy(route.request().url(), target)) {
|
|
179
210
|
deniedRequests.push(metadata);
|
|
180
211
|
await route.abort("blockedbyclient");
|
|
181
212
|
return;
|
|
182
213
|
}
|
|
183
214
|
await route.continue();
|
|
184
215
|
});
|
|
185
|
-
await context.setOffline(true);
|
|
216
|
+
if (target.networkPolicy.mode === "deny") await context.setOffline(true);
|
|
186
217
|
page = await context.newPage();
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
218
|
+
if (target.adapter === "self-contained-html") {
|
|
219
|
+
await page.setContent(target.html, {
|
|
220
|
+
waitUntil: "domcontentloaded",
|
|
221
|
+
timeout: timeoutMs,
|
|
222
|
+
});
|
|
223
|
+
} else {
|
|
224
|
+
await page.goto(target.url, {
|
|
225
|
+
waitUntil: "domcontentloaded",
|
|
226
|
+
timeout: timeoutMs,
|
|
227
|
+
});
|
|
228
|
+
if (!navigationAllowedByRecordedSkillPolicy(page.url(), target)) {
|
|
229
|
+
throw driverError(
|
|
230
|
+
"CC_REPLAY_UI_NETWORK_ATTEMPT",
|
|
231
|
+
"recorded UI target redirected outside its reviewed origin policy",
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
191
235
|
} catch {
|
|
192
236
|
await browser.close();
|
|
193
237
|
throw driverError(
|
|
@@ -199,18 +243,31 @@ export async function launchPlaywrightRecordedSkillDriver({
|
|
|
199
243
|
await browser.close();
|
|
200
244
|
throw driverError(
|
|
201
245
|
"CC_REPLAY_UI_FIXTURE_NETWORKED",
|
|
202
|
-
"recorded UI
|
|
246
|
+
"recorded UI target attempted access outside its reviewed network policy while loading",
|
|
203
247
|
{ deniedRequestCount: deniedRequests.length },
|
|
204
248
|
);
|
|
205
249
|
}
|
|
206
250
|
|
|
207
251
|
const executor = Object.freeze({
|
|
208
252
|
capabilities: DRIVER_CAPABILITIES,
|
|
253
|
+
networkPolicyDigest: target.networkPolicy.digest,
|
|
209
254
|
async execute(action, { isolation, capability } = {}) {
|
|
210
|
-
|
|
255
|
+
let replayNetworkPolicy;
|
|
256
|
+
try {
|
|
257
|
+
replayNetworkPolicy = createRecordedSkillNetworkPolicy({
|
|
258
|
+
mode: isolation?.network,
|
|
259
|
+
allowedOrigins: isolation?.allowedOrigins || [],
|
|
260
|
+
});
|
|
261
|
+
} catch {
|
|
262
|
+
replayNetworkPolicy = null;
|
|
263
|
+
}
|
|
264
|
+
if (
|
|
265
|
+
isolation?.sandboxed !== true ||
|
|
266
|
+
replayNetworkPolicy?.digest !== target.networkPolicy.digest
|
|
267
|
+
) {
|
|
211
268
|
throw driverError(
|
|
212
269
|
"CC_REPLAY_UI_ISOLATION_REQUIRED",
|
|
213
|
-
"UI replay driver requires
|
|
270
|
+
"UI replay driver requires the exact reviewed browser network policy",
|
|
214
271
|
);
|
|
215
272
|
}
|
|
216
273
|
const kind = String(action?.kind || "");
|
|
@@ -278,7 +335,7 @@ export async function launchPlaywrightRecordedSkillDriver({
|
|
|
278
335
|
screenshot,
|
|
279
336
|
"cc.record-replay.ui-screenshot/v1",
|
|
280
337
|
),
|
|
281
|
-
networkPolicy:
|
|
338
|
+
networkPolicy: target.networkPolicy.mode,
|
|
282
339
|
deniedRequestCount: 0,
|
|
283
340
|
});
|
|
284
341
|
receipts.push(evidence);
|
|
@@ -297,7 +354,13 @@ export async function launchPlaywrightRecordedSkillDriver({
|
|
|
297
354
|
return Object.freeze({
|
|
298
355
|
executor,
|
|
299
356
|
browserVersion: String(browser.version?.() || "unknown").slice(0, 128),
|
|
300
|
-
|
|
357
|
+
adapter: target.adapter,
|
|
358
|
+
targetDigest: target.targetDigest,
|
|
359
|
+
fixtureDigest:
|
|
360
|
+
target.adapter === "self-contained-html" ? target.targetDigest : null,
|
|
361
|
+
storageStateDigest: target.storageStateDigest,
|
|
362
|
+
identity: target.identity,
|
|
363
|
+
networkPolicy: target.networkPolicy,
|
|
301
364
|
summary() {
|
|
302
365
|
return Object.freeze({
|
|
303
366
|
schema: "chainlesschain.recorded-skill-ui-driver-summary/v1",
|