chainlesschain 0.165.5 → 0.165.8
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 +2 -1
- package/src/assets/web-panel/assets/{AIOps-CEeYTeDB.js → AIOps-B3gWmXjo.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BeRUQ3V2.js → ActionButton-G9pdT-0e.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DrV718XF.js → Analytics-Ca30J7m2.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-Cd2Frt7Q.js → AppLayout-BtVTm8PU.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CUJMlORU.js → Artifacts-BhViNa6u.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CXJcfT6p.js → Audit-DhKq-FnY.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DOv6Z7H9.js → BackgroundAgents-BL0SVbnE.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BwdDyBI0.js → Backup-BWkblnFi.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BmLn4kYH.js → BaseInput-ClaRNrF8.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-COg8pAW2.js → Chat-sZE2Z77o.js} +4 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BAfKOnRe.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-BCP4uoU8.js → Checkbox-Cvhay5WM.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-pRt6Y9JI.js → Codegen-BpejL-4N.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DLaprKhS.js → Col-g2Ki6g_1.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DyATsz5f.js → Community-D2xKbNo9.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BXAaupZK.js → Compact-DbL1Pds3.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DpcJBELr.js → Compliance-DGtZCV4c.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DG4EFWyd.js → Cowork-4kQpoNsI.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-F6Oy5n2P.js → Cron-BxTYXXAN.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BOdgtalX.js → Crosschain-k0J0LT2N.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DT1dSkjH.js → DID-BaqhoPgN.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-NBUIqWzC.js → Dashboard-T4RVPIM1.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CSpHeMYB.js → Dropdown-DszOToWq.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CEG0xISr.js → EmailListRenderer-C9KJU7HF.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BTZ0BZna.js → FamilyGuardDashboard-Cmr0JnsA.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BuuCTn2V.js → Federation-BI-_2xZX.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-KAVceevk.js → FormItemContext-DsnDEPsl.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DnHpcQvW.js → GenericCardRenderer-BLncAKKK.js} +1 -1
- package/src/assets/web-panel/assets/{Git-C_B_0HwB.js → Git-BPQhGXDn.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DPSZuzuu.js → Governance-CyElbUQW.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BV-06V7q.js → Inference-CcSntBQD.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-wpDuupn6.js → KnowledgeGraph-p6e7HZ2r.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Bseca1_I.js → Logs-CNEtr-wz.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-Bj9xI0YH.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-d3kM4DDL.js → Marketplace-Dd2notAJ.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DQ_xZ23i.js → McpTools-BBsN2CSW.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-CRIeYO4L.js → Memory-Dg2uTvwx.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BsllIa9l.js → MobileBridge-r1YMRiJV.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BUuQy30X.js → MobileProjects-C-89kSm4.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BOFDIzrC.js → Mtc-CrPZcVgf.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BQg-vyvG.js → MtcAudit-sxi7hqJb.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-Bo1jrPdN.js → Multisig-CAgOMfF1.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Bmod8alw.js → NLProgramming-DafaPts3.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CGGFL8w-.js → Notes-CJM-xUW_.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-BsZvCJxC.js → NotificationSettings-L0ZjfAh_.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-C1-Quo_h.js → OrderTableRenderer-BB1CvCK0.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BjOeDYOi.js → Organization-DeLtgAD8.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DwVV3l5A.js → Overflow-CKC2b10z.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Cu3DQT9W.js → P2P-eyf2rzY1.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Cg0gR7dH.js → PdhVaultBrowser-5upNIOW8.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CsAXxRN5.js → Permissions-B8p3W6JK.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-C-nNmnYp.js → PersonalDataHub-BnRMxTq3.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-BOnW7nNc.js → Pipeline-DjCNI1li.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-ClLSyGKt.js → Privacy-u6gXLbWT.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DuLvjjq7.js → ProjectInit-BZAw4tkM.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DQYYbDD9.js → ProjectSettings-B1Tr72q7.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Drw8MBGK.js → Projects-DO7HFuBQ.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-ckqHQe6K.js → Providers-BjCztyhj.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DW5BXk-G.js → QrScannerModal-ZWyCUbR1.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DDLnhNTp.js → QuickAsk-DhDjeW4G.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-PJQ2C91U.js → Recommend-R_CN2MuU.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-s6wmda34.js → RemoteSession-uxFcujeu.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-DC2sb-I3.js → Reputation-DX8D7rks.js} +1 -1
- package/src/assets/web-panel/assets/{Row-hPGk1eGj.js → Row-BYahQILD.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-RIvfZql0.js → RssFeed-CUSQ2tm-.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DFg1G1eR.js → Search-CnN_S8Cs.js} +1 -1
- package/src/assets/web-panel/assets/{Security-D6H5p8Dp.js → Security-DcZlh-O4.js} +4 -4
- package/src/assets/web-panel/assets/{Services-nxYiFV_w.js → Services-ZhBOjzIX.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BmgFNAdB.js → Skeleton-D5Qnq_lI.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CsaaD2av.js → Skills-BC9cZ3Be.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-yM5y9yvK.js → Sla-DauJ3E8_.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-DbNeZ_fh.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-CFVhEyyr.js → SyncSettings-DUvJbSct.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-DdO02Inn.js → Tasks-BXa-5noQ.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Eo2d8Llu.js → Templates-JxaiUt_3.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-ChESOXgy.js → Tenant-BW4ERQN8.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BJ7oDxTI.js → Terminal-DltUbdtv.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-hWX0fUvz.js → TimelineRenderer-CMoZz0Tc.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DVBZQnd-.js → Tokens-D_VEV60K.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-D89cQfVq.js → Trigger-CCXTCs0R.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BIVSb4-V.js → Trust-lkGRIPcG.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B58gWopl.js → UkeySign-BfGeQ9HX.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DhHI7bmG.js → VideoEditing-BEC7pYvc.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-C4FheWS_.js → Wallet-BZdG24o0.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DnPRq-Bx.js → WebAuthn-yoEddedp.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-BerRPjpJ.js → WorkflowEditor-BXZEprOW.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BzZ52iKr.js → chat-gg0bzZal.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BI_E4BAn.js → colors-DjRVRuin.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-d50mr3yk.js → compact-item-su-dieAc.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-C6FsQ1IH.js → createContext-Ci3S8oKF.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CxbFX9uH.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DLZEMgLP.js → hasIn-D8F10heH.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-aBumtY.js → index-11wtYQiF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CjuKZBqJ.js → index-1IgxgALJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-9H_M2jju.js → index-1agckWSq.js} +1 -1
- package/src/assets/web-panel/assets/{index-DE0V6cp-.js → index-5JqhujnR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Y2-q7QLm.js → index-6Tniqk1s.js} +1 -1
- package/src/assets/web-panel/assets/{index-DoFtCVZ7.js → index-8Z-8BIlN.js} +1 -1
- package/src/assets/web-panel/assets/{index-KNGgO4Wm.js → index-BCI5v0yB.js} +1 -1
- package/src/assets/web-panel/assets/{index-DY4j5zkF.js → index-BDJntYmJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZjjdQ62.js → index-BGzixOGZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTpIOTfR.js → index-BMMOVoLD.js} +1 -1
- package/src/assets/web-panel/assets/{index-BB9SqVSt.js → index-BTFpdBtt.js} +1 -1
- package/src/assets/web-panel/assets/{index-AHr7ryWf.js → index-Ba_HyPnE.js} +1 -1
- package/src/assets/web-panel/assets/{index-Pvf30m8Q.js → index-BbF1IHof.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRN5TRTQ.js → index-BgT9su_e.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUaEHfQ0.js → index-BzPB6kGZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdKt9fOd.js → index-C6ygzplr.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dec0Kf_Z.js → index-CC3ZDjzY.js} +1 -1
- package/src/assets/web-panel/assets/{index-IPkwSAW_.js → index-CEmXRhAE.js} +1 -1
- package/src/assets/web-panel/assets/index-CJGOlduY.js +1 -0
- package/src/assets/web-panel/assets/{index-C3k8kevG.js → index-CMPqd5Cv.js} +1 -1
- package/src/assets/web-panel/assets/{index-A5CDWP7y.js → index-COWd8uGx.js} +1 -1
- package/src/assets/web-panel/assets/{index-CO8DAF7U.js → index-CPIYSp4H.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVzuawCX.js → index-CR0h6seT.js} +1 -1
- package/src/assets/web-panel/assets/{index-Co7s9LsB.js → index-CUmDhC4j.js} +1 -1
- package/src/assets/web-panel/assets/index-CkBCN5yH.js +1 -0
- package/src/assets/web-panel/assets/{index-CLoTQr0W.js → index-CusgZPtc.js} +1 -1
- package/src/assets/web-panel/assets/{index-B81mo1Et.js → index-DBAETXft.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcSUl9fA.js → index-DIJ2qFOC.js} +1 -1
- package/src/assets/web-panel/assets/{index-Q5Tn735s.js → index-Dbq4NMET.js} +1 -1
- package/src/assets/web-panel/assets/{index-GXE0D8Nx.js → index-DkMEF5VT.js} +1 -1
- package/src/assets/web-panel/assets/{index-TWG-_D1M.js → index-DkfQR3hM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BAE3hwev.js → index-DnLucOn9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgkoH3_g.js → index-DugB_aKa.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRGx3w6T.js → index-DyLUarhZ.js} +3 -3
- package/src/assets/web-panel/assets/{index-BeM4hfht.js → index-T6_6ygJZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsscwxPE.js → index-Tu8eWqh-.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bmr_vxXD.js → index-W7XUgdVL.js} +1 -1
- package/src/assets/web-panel/assets/{index-BoNZlzhQ.js → index-dHZinfko.js} +1 -1
- package/src/assets/web-panel/assets/{index-DqkbHHg8.js → index-jyNgp5FI.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-D-4Hzgej.js → initDefaultProps-Cv4p8e4w.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D4Wl4xU7.js → motion-B8EwmMOw.js} +1 -1
- package/src/assets/web-panel/assets/{move-Cd5eQvL0.js → move-B8R9F8TK.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-B4ilslCW.js → mtc-parser-DoFYz5Bp.js} +1 -1
- package/src/assets/web-panel/assets/{omit-Ckarx-tf.js → omit-CHWYLBjI.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-QJ0bpCmc.js → pickAttrs-CXuPDO77.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CKHm-tq8.js → placementArrow-BaAtUUon.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CV6a_w_Y.js → responsiveObserve-DCc4zcDD.js} +1 -1
- package/src/assets/web-panel/assets/{slide-mHpeQFgk.js → slide-B_lx89oZ.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DIaQNQWA.js → statusUtils-DE8DPmR0.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-PJpzavV8.js → styleChecker-1ktXOsL_.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-BH7zTw8S.js → useFlexGapSupport-xH89-wjh.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BDNG3JDd.js → useFs-DscvfW5p.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CY2VWdUg.js → usePersonalDataHub-RdMKQta7.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-D0kw9jhz.js → vnode-Z3wTni2T.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-B5g7TN7r.js → zoom-B0iChCsm.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +3 -3
- package/src/commands/agent.js +105 -62
- package/src/commands/background-session.js +100 -10
- package/src/commands/git.js +39 -0
- package/src/commands/mcp.js +5 -0
- package/src/commands/plugin.js +160 -29
- package/src/commands/remote-control.js +295 -110
- package/src/commands/session-group.js +131 -0
- package/src/commands/session-location.js +48 -0
- package/src/commands/session-message.js +171 -0
- package/src/commands/session.js +22 -0
- package/src/commands/sync-providers.js +4 -1
- package/src/commands/update.js +1 -0
- package/src/data/changelog.json +41 -2
- package/src/gateways/ws/ws-agent-handler.js +20 -12
- package/src/harness/jsonl-session-store.js +279 -37
- package/src/harness/mcp-client.js +832 -91
- package/src/harness/session-index.js +15 -4
- package/src/lib/agent-worktree.js +8 -1
- package/src/lib/auto-mode-safety-classifier.js +3 -17
- package/src/lib/background-agent-keeper-protocol.js +26 -6
- package/src/lib/background-agent-supervisor.js +17 -1
- package/src/lib/background-session-transport.js +153 -27
- package/src/lib/browser-evidence.js +1405 -0
- package/src/lib/chrome-connector.js +465 -79
- package/src/lib/claude-project-auto-memory.js +481 -0
- package/src/lib/claude-project-storage-layout.js +104 -0
- package/src/lib/cloud/cloud-client.js +40 -0
- package/src/lib/execution-location-local-supervisor.mjs +226 -0
- package/src/lib/execution-location-runner-lifecycle.js +991 -0
- package/src/lib/execution-location-target-preflight.js +333 -0
- package/src/lib/execution-location-target.js +783 -13
- package/src/lib/file-lines.js +6 -1
- package/src/lib/gateway-client-resilience.js +571 -0
- package/src/lib/gitlab-mr-worktree.js +176 -0
- package/src/lib/hooks-v2-producers.js +119 -15
- package/src/lib/hooks-v2-workspace-context.js +44 -1
- package/src/lib/host-resource-budget.js +295 -0
- package/src/lib/ide-context.js +15 -2
- package/src/lib/llm-config-defaults.js +43 -0
- package/src/lib/mcp-client.js +2 -0
- package/src/lib/mcp-headers-helper.js +47 -5
- package/src/lib/mcp-lifecycle-authority.js +887 -0
- package/src/lib/mcp-oauth.js +156 -26
- package/src/lib/mcp-tls.js +330 -0
- package/src/lib/output-styles.js +12 -0
- package/src/lib/paths.js +260 -32
- package/src/lib/permission-request.js +48 -0
- package/src/lib/plugin-runtime/bin.js +3 -1
- package/src/lib/plugin-runtime/hooks.js +3 -1
- package/src/lib/plugin-runtime/install.js +730 -71
- package/src/lib/plugin-runtime/lsp.js +4 -4
- package/src/lib/plugin-runtime/marketplace-archive-source.js +366 -0
- package/src/lib/plugin-runtime/marketplace-catalog.js +63 -6
- package/src/lib/plugin-runtime/marketplace-command-descriptor.js +343 -0
- package/src/lib/plugin-runtime/marketplace-command-source.js +580 -0
- package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1 -0
- package/src/lib/plugin-runtime/marketplace-source-adapter.js +188 -0
- package/src/lib/plugin-runtime/marketplace-source-cache.js +11 -1
- package/src/lib/plugin-runtime/mcp.js +3 -1
- package/src/lib/plugin-runtime/monitors.js +3 -1
- package/src/lib/plugin-runtime/remote-source.js +583 -58
- package/src/lib/plugin-runtime/settings.js +3 -1
- package/src/lib/plugin-runtime/trust.js +274 -13
- package/src/lib/plugin-security.js +393 -41
- package/src/lib/plugin-source-identity.js +850 -0
- package/src/lib/process-execution-broker/credential-agent.js +210 -41
- package/src/lib/process-execution-broker/index.js +15 -1
- package/src/lib/process-execution-broker/linux-cgroup-v2.js +391 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +50 -28
- package/src/lib/project-mcp-trust.js +165 -10
- package/src/lib/remote-approval-bridge.js +136 -46
- package/src/lib/remote-control.js +217 -31
- package/src/lib/resume-session.js +9 -6
- package/src/lib/session-core-singletons.js +26 -11
- package/src/lib/session-host-lease.js +52 -16
- package/src/lib/session-lifecycle-scope.js +153 -0
- package/src/lib/session-message-fabric.js +1252 -0
- package/src/lib/session-projection.js +286 -3
- package/src/lib/session-runtime-retention.js +155 -0
- package/src/lib/session-store-guard.js +3 -1
- package/src/lib/session-workbench-store.js +466 -0
- package/src/lib/settings-loader.cjs +29 -0
- package/src/lib/spellcheck.js +211 -0
- package/src/lib/sub-agent-context.js +9 -9
- package/src/lib/sync-cli-db.js +485 -129
- package/src/lib/sync-credentials.js +31 -20
- package/src/lib/web-fetch.js +112 -40
- package/src/lib/web-search.js +127 -61
- package/src/lib/workspace-trust.js +793 -0
- package/src/repl/agent-repl.js +175 -19
- package/src/repl/permission-prompt.js +29 -8
- package/src/repl/repl-keybindings.js +55 -0
- package/src/runtime/agent-core.js +362 -20
- package/src/runtime/bootstrap.js +37 -13
- package/src/runtime/coding-agent-contract-shared.cjs +11 -4
- package/src/runtime/headless-runner.js +281 -102
- package/src/runtime/headless-stream.js +199 -30
- package/src/runtime/mcp-config.js +298 -6
- package/src/runtime/policies/agent-policy.js +10 -0
- package/src/runtime/status-diagnostics-lite.js +9 -1
- package/src/assets/web-panel/assets/ChatBubbleRenderer-4gGkdGgA.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-B4RLp2zs.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-DPy1XMYh.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CagEcIex.js +0 -1
- package/src/assets/web-panel/assets/index-pzT9PpOU.js +0 -1
- package/src/assets/web-panel/assets/index-z1kFadaX.js +0 -1
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import executionBroker from "../process-execution-broker/index.js";
|
|
5
|
+
import {
|
|
6
|
+
assertMarketplaceCommandModeSupported,
|
|
7
|
+
MARKETPLACE_COMMAND_DESCRIPTOR_ERROR,
|
|
8
|
+
MARKETPLACE_COMMAND_SAFE_ENVIRONMENT_KEYS,
|
|
9
|
+
normalizeMarketplaceCommandDescriptor,
|
|
10
|
+
} from "./marketplace-command-descriptor.js";
|
|
11
|
+
import {
|
|
12
|
+
assertSafeInstalledPluginStructure,
|
|
13
|
+
buildMarketplacePayloadSbom,
|
|
14
|
+
} from "./marketplace-artifact-readback.js";
|
|
15
|
+
|
|
16
|
+
export const MARKETPLACE_HEADERS_HELPER_ERROR = Object.freeze({
|
|
17
|
+
INVALID_OUTPUT: "CC_MARKETPLACE_HEADERS_HELPER_OUTPUT_INVALID",
|
|
18
|
+
PROCESS_FAILED: "CC_MARKETPLACE_HEADERS_HELPER_PROCESS_FAILED",
|
|
19
|
+
PROCESS_TIMEOUT: "CC_MARKETPLACE_HEADERS_HELPER_TIMEOUT",
|
|
20
|
+
PROCESS_OUTPUT_LIMIT: "CC_MARKETPLACE_HEADERS_HELPER_OUTPUT_LIMIT",
|
|
21
|
+
PROCESS_START: "CC_MARKETPLACE_HEADERS_HELPER_PROCESS_START_FAILED",
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export const MARKETPLACE_COMMAND_SOURCE_ERROR = Object.freeze({
|
|
25
|
+
INVALID_OUTPUT: "CC_MARKETPLACE_COMMAND_SOURCE_OUTPUT_INVALID",
|
|
26
|
+
PROCESS_FAILED: "CC_MARKETPLACE_COMMAND_SOURCE_PROCESS_FAILED",
|
|
27
|
+
PROCESS_TIMEOUT: "CC_MARKETPLACE_COMMAND_SOURCE_TIMEOUT",
|
|
28
|
+
PROCESS_OUTPUT_LIMIT: "CC_MARKETPLACE_COMMAND_SOURCE_OUTPUT_LIMIT",
|
|
29
|
+
PROCESS_START: "CC_MARKETPLACE_COMMAND_SOURCE_PROCESS_START_FAILED",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export const MARKETPLACE_HEADERS_HELPER_LIMITS = Object.freeze({
|
|
33
|
+
maxHeaders: 64,
|
|
34
|
+
maxHeaderValueBytes: 16 * 1024,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const HEADER_NAME = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/u;
|
|
38
|
+
const TRANSPORT_OWNED_HEADERS = new Set([
|
|
39
|
+
"accept",
|
|
40
|
+
"connection",
|
|
41
|
+
"content-length",
|
|
42
|
+
"content-type",
|
|
43
|
+
"host",
|
|
44
|
+
"transfer-encoding",
|
|
45
|
+
"upgrade",
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
function runtimeError(code, message) {
|
|
49
|
+
const error = new Error(message);
|
|
50
|
+
error.code = code;
|
|
51
|
+
return error;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function outputError(kind, suffix, message) {
|
|
55
|
+
const codes =
|
|
56
|
+
kind === "headers"
|
|
57
|
+
? MARKETPLACE_HEADERS_HELPER_ERROR
|
|
58
|
+
: MARKETPLACE_COMMAND_SOURCE_ERROR;
|
|
59
|
+
return runtimeError(codes[suffix], message);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function hasInvalidHeaderValueCharacter(value) {
|
|
63
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
64
|
+
const code = value.charCodeAt(index);
|
|
65
|
+
if (code <= 0x08 || (code >= 0x0a && code <= 0x1f) || code === 0x7f) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function normalizeHeaderMap(value) {
|
|
73
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
74
|
+
throw runtimeError(
|
|
75
|
+
MARKETPLACE_HEADERS_HELPER_ERROR.INVALID_OUTPUT,
|
|
76
|
+
"Marketplace headers helper must emit a JSON object of string headers",
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
80
|
+
const keys = Reflect.ownKeys(descriptors);
|
|
81
|
+
if (
|
|
82
|
+
keys.length > MARKETPLACE_HEADERS_HELPER_LIMITS.maxHeaders ||
|
|
83
|
+
keys.some(
|
|
84
|
+
(key) => typeof key !== "string" || !("value" in descriptors[key]),
|
|
85
|
+
)
|
|
86
|
+
) {
|
|
87
|
+
throw runtimeError(
|
|
88
|
+
MARKETPLACE_HEADERS_HELPER_ERROR.INVALID_OUTPUT,
|
|
89
|
+
"Marketplace headers helper emitted unsupported headers",
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
const headers = {};
|
|
93
|
+
for (const name of keys.sort()) {
|
|
94
|
+
const valueAtName = descriptors[name].value;
|
|
95
|
+
if (
|
|
96
|
+
!HEADER_NAME.test(name) ||
|
|
97
|
+
typeof valueAtName !== "string" ||
|
|
98
|
+
hasInvalidHeaderValueCharacter(valueAtName) ||
|
|
99
|
+
Buffer.byteLength(valueAtName, "utf8") >
|
|
100
|
+
MARKETPLACE_HEADERS_HELPER_LIMITS.maxHeaderValueBytes ||
|
|
101
|
+
TRANSPORT_OWNED_HEADERS.has(name.toLowerCase())
|
|
102
|
+
) {
|
|
103
|
+
throw runtimeError(
|
|
104
|
+
MARKETPLACE_HEADERS_HELPER_ERROR.INVALID_OUTPUT,
|
|
105
|
+
"Marketplace headers helper emitted an invalid header",
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
headers[name] = valueAtName;
|
|
109
|
+
}
|
|
110
|
+
return Object.freeze(headers);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function canonicalExecutable(plan, deps, platform) {
|
|
114
|
+
let original;
|
|
115
|
+
let executable;
|
|
116
|
+
try {
|
|
117
|
+
original = deps.lstatSync(plan.executable);
|
|
118
|
+
executable = deps.realpathSync(plan.executable);
|
|
119
|
+
} catch {
|
|
120
|
+
throw runtimeError(
|
|
121
|
+
MARKETPLACE_COMMAND_DESCRIPTOR_ERROR.INVALID,
|
|
122
|
+
"Marketplace command executable is unavailable",
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
if (original.isSymbolicLink() || !original.isFile()) {
|
|
126
|
+
throw runtimeError(
|
|
127
|
+
MARKETPLACE_COMMAND_DESCRIPTOR_ERROR.INVALID,
|
|
128
|
+
"Marketplace command executable must be a regular non-symlink file",
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
let finalStat;
|
|
132
|
+
try {
|
|
133
|
+
finalStat = deps.lstatSync(executable);
|
|
134
|
+
} catch {
|
|
135
|
+
throw runtimeError(
|
|
136
|
+
MARKETPLACE_COMMAND_DESCRIPTOR_ERROR.INVALID,
|
|
137
|
+
"Marketplace command executable is unavailable",
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
if (finalStat.isSymbolicLink() || !finalStat.isFile()) {
|
|
141
|
+
throw runtimeError(
|
|
142
|
+
MARKETPLACE_COMMAND_DESCRIPTOR_ERROR.INVALID,
|
|
143
|
+
"Marketplace command executable changed while validating",
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
if (platform !== "win32" && (finalStat.mode & 0o111) === 0) {
|
|
147
|
+
throw runtimeError(
|
|
148
|
+
MARKETPLACE_COMMAND_DESCRIPTOR_ERROR.INVALID,
|
|
149
|
+
"Marketplace command executable is not executable",
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
return executable;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function canonicalCwd(plan, deps) {
|
|
156
|
+
let cwd;
|
|
157
|
+
let stat;
|
|
158
|
+
try {
|
|
159
|
+
cwd = deps.realpathSync(plan.cwd);
|
|
160
|
+
stat = deps.lstatSync(cwd);
|
|
161
|
+
} catch {
|
|
162
|
+
throw runtimeError(
|
|
163
|
+
MARKETPLACE_COMMAND_DESCRIPTOR_ERROR.INVALID,
|
|
164
|
+
"Marketplace command working directory is unavailable",
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
168
|
+
throw runtimeError(
|
|
169
|
+
MARKETPLACE_COMMAND_DESCRIPTOR_ERROR.INVALID,
|
|
170
|
+
"Marketplace command working directory must be a real directory",
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
return cwd;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function terminateProcessTree(child, { platform, kill, spawnSync } = {}) {
|
|
177
|
+
const activePlatform = platform || process.platform;
|
|
178
|
+
const processKill = kill || process.kill.bind(process);
|
|
179
|
+
const pid = Number(child?.pid);
|
|
180
|
+
if (activePlatform !== "win32" && Number.isInteger(pid) && pid > 0) {
|
|
181
|
+
try {
|
|
182
|
+
processKill(-pid, "SIGKILL");
|
|
183
|
+
return;
|
|
184
|
+
} catch {
|
|
185
|
+
// The child may already have exited or not own a process group.
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (activePlatform === "win32" && Number.isInteger(pid) && pid > 0) {
|
|
189
|
+
try {
|
|
190
|
+
(spawnSync || executionBroker.spawnSync.bind(executionBroker))(
|
|
191
|
+
"taskkill",
|
|
192
|
+
["/PID", String(pid), "/T", "/F"],
|
|
193
|
+
{
|
|
194
|
+
shell: false,
|
|
195
|
+
windowsHide: true,
|
|
196
|
+
origin: "marketplace:descriptor:taskkill",
|
|
197
|
+
policy: "allow",
|
|
198
|
+
scope: "marketplace",
|
|
199
|
+
},
|
|
200
|
+
);
|
|
201
|
+
return;
|
|
202
|
+
} catch {
|
|
203
|
+
// Fall through to the direct child handle.
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
child?.kill?.("SIGKILL");
|
|
208
|
+
} catch {
|
|
209
|
+
// Best effort: the process may have already exited.
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function sanitizedMarketplaceEnvironment(descriptorEnvironment, platform) {
|
|
214
|
+
const allowed = new Set(MARKETPLACE_COMMAND_SAFE_ENVIRONMENT_KEYS);
|
|
215
|
+
const inherited = {};
|
|
216
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
217
|
+
const normalized = platform === "win32" ? key.toUpperCase() : key;
|
|
218
|
+
if (
|
|
219
|
+
allowed.has(normalized) &&
|
|
220
|
+
typeof value === "string" &&
|
|
221
|
+
value.length <= 8 * 1024
|
|
222
|
+
) {
|
|
223
|
+
// Preserve the actual key spelling. Windows environment lookup is case
|
|
224
|
+
// insensitive, while POSIX callers may require the conventional spelling.
|
|
225
|
+
inherited[key] = value;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return { ...inherited, ...descriptorEnvironment };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Launch a bounded direct-argv Marketplace descriptor. This intentionally
|
|
233
|
+
* never starts a shell and never inherits the host environment.
|
|
234
|
+
*/
|
|
235
|
+
export function runMarketplaceProcessDescriptor(descriptor, options = {}) {
|
|
236
|
+
const kind = options.kind === "headers" ? "headers" : "source";
|
|
237
|
+
const plan = normalizeMarketplaceCommandDescriptor(descriptor, {
|
|
238
|
+
kind,
|
|
239
|
+
allowType: options.allowType === true,
|
|
240
|
+
label:
|
|
241
|
+
kind === "headers"
|
|
242
|
+
? "Marketplace headers helper descriptor"
|
|
243
|
+
: "Marketplace command source descriptor",
|
|
244
|
+
});
|
|
245
|
+
const platform = options.platform || process.platform;
|
|
246
|
+
if (kind === "source")
|
|
247
|
+
assertMarketplaceCommandModeSupported(plan.mode, platform);
|
|
248
|
+
const realpathSync = options.realpathSync || fs.realpathSync.native;
|
|
249
|
+
const deps = {
|
|
250
|
+
lstatSync: options.lstatSync || fs.lstatSync,
|
|
251
|
+
realpathSync,
|
|
252
|
+
};
|
|
253
|
+
const executable = canonicalExecutable(plan, deps, platform);
|
|
254
|
+
const cwd = canonicalCwd(plan, deps);
|
|
255
|
+
const spawn = options.spawn || executionBroker.spawn.bind(executionBroker);
|
|
256
|
+
const spawnOptions = {
|
|
257
|
+
cwd,
|
|
258
|
+
// An empty environment breaks ordinary Windows binaries (notably Node,
|
|
259
|
+
// which needs SystemRoot/temporary-directory state). Retain only the
|
|
260
|
+
// descriptor's narrow runtime whitelist; credentials and arbitrary host
|
|
261
|
+
// configuration remain absent unless explicitly permitted by the schema.
|
|
262
|
+
env: sanitizedMarketplaceEnvironment(plan.env, platform),
|
|
263
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
264
|
+
shell: false,
|
|
265
|
+
windowsHide: true,
|
|
266
|
+
detached: platform !== "win32",
|
|
267
|
+
origin:
|
|
268
|
+
kind === "headers"
|
|
269
|
+
? "marketplace:headers-helper"
|
|
270
|
+
: "marketplace:command-source",
|
|
271
|
+
policy: "allow",
|
|
272
|
+
scope: "marketplace",
|
|
273
|
+
// Descriptor arguments may contain an access token supplied by a local
|
|
274
|
+
// operator. Keep all argv out of broker audit records.
|
|
275
|
+
auditRedactArgIndexes: plan.args.map((_, index) => index),
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
return new Promise((resolve, reject) => {
|
|
279
|
+
let child;
|
|
280
|
+
try {
|
|
281
|
+
child = spawn(executable, [...plan.args], spawnOptions);
|
|
282
|
+
} catch {
|
|
283
|
+
reject(
|
|
284
|
+
outputError(
|
|
285
|
+
kind,
|
|
286
|
+
"PROCESS_START",
|
|
287
|
+
"Marketplace command process could not be started",
|
|
288
|
+
),
|
|
289
|
+
);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (!child?.stdout || !child?.stderr) {
|
|
293
|
+
terminateProcessTree(child, {
|
|
294
|
+
platform,
|
|
295
|
+
kill: options.kill,
|
|
296
|
+
spawnSync: options.spawnSync,
|
|
297
|
+
});
|
|
298
|
+
reject(
|
|
299
|
+
outputError(
|
|
300
|
+
kind,
|
|
301
|
+
"PROCESS_START",
|
|
302
|
+
"Marketplace command process did not expose output streams",
|
|
303
|
+
),
|
|
304
|
+
);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
let state = "running";
|
|
309
|
+
let stdout = "";
|
|
310
|
+
let totalOutputBytes = 0;
|
|
311
|
+
const settle = (callback, value) => {
|
|
312
|
+
if (state === "settled") return;
|
|
313
|
+
state = "settled";
|
|
314
|
+
clearTimeout(timeout);
|
|
315
|
+
callback(value);
|
|
316
|
+
};
|
|
317
|
+
const fail = (error) => {
|
|
318
|
+
if (state !== "running") return;
|
|
319
|
+
state = "terminating";
|
|
320
|
+
clearTimeout(timeout);
|
|
321
|
+
terminateProcessTree(child, {
|
|
322
|
+
platform,
|
|
323
|
+
kill: options.kill,
|
|
324
|
+
spawnSync: options.spawnSync,
|
|
325
|
+
});
|
|
326
|
+
settle(reject, error);
|
|
327
|
+
};
|
|
328
|
+
const appendOutput = (chunk, keep) => {
|
|
329
|
+
const buffer = Buffer.isBuffer(chunk)
|
|
330
|
+
? chunk
|
|
331
|
+
: Buffer.from(String(chunk), "utf8");
|
|
332
|
+
totalOutputBytes += buffer.byteLength;
|
|
333
|
+
if (totalOutputBytes > plan.maxOutputBytes) {
|
|
334
|
+
fail(
|
|
335
|
+
outputError(
|
|
336
|
+
kind,
|
|
337
|
+
"PROCESS_OUTPUT_LIMIT",
|
|
338
|
+
"Marketplace command process exceeded its bounded output limit",
|
|
339
|
+
),
|
|
340
|
+
);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (keep) stdout += buffer.toString("utf8");
|
|
344
|
+
};
|
|
345
|
+
const timeout = setTimeout(
|
|
346
|
+
() =>
|
|
347
|
+
fail(
|
|
348
|
+
outputError(
|
|
349
|
+
kind,
|
|
350
|
+
"PROCESS_TIMEOUT",
|
|
351
|
+
"Marketplace command process exceeded its timeout",
|
|
352
|
+
),
|
|
353
|
+
),
|
|
354
|
+
plan.timeoutMs,
|
|
355
|
+
);
|
|
356
|
+
timeout.unref?.();
|
|
357
|
+
child.stdout.on("data", (chunk) => {
|
|
358
|
+
if (state === "running") appendOutput(chunk, true);
|
|
359
|
+
});
|
|
360
|
+
child.stderr.on("data", (chunk) => {
|
|
361
|
+
if (state === "running") appendOutput(chunk, false);
|
|
362
|
+
});
|
|
363
|
+
child.once("error", () =>
|
|
364
|
+
fail(
|
|
365
|
+
outputError(
|
|
366
|
+
kind,
|
|
367
|
+
"PROCESS_START",
|
|
368
|
+
"Marketplace command process failed to start",
|
|
369
|
+
),
|
|
370
|
+
),
|
|
371
|
+
);
|
|
372
|
+
child.once("close", (code, signal) => {
|
|
373
|
+
if (state !== "running") return;
|
|
374
|
+
if (code !== 0) {
|
|
375
|
+
fail(
|
|
376
|
+
outputError(
|
|
377
|
+
kind,
|
|
378
|
+
"PROCESS_FAILED",
|
|
379
|
+
`Marketplace command process exited unsuccessfully (code ${code ?? "null"}, signal ${signal || "none"})`,
|
|
380
|
+
),
|
|
381
|
+
);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
settle(resolve, stdout);
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** Run a descriptor whose stdout must be a bounded JSON object of HTTP headers. */
|
|
390
|
+
export async function runMarketplaceHeadersHelper(descriptor, options = {}) {
|
|
391
|
+
const stdout = await runMarketplaceProcessDescriptor(descriptor, {
|
|
392
|
+
...options,
|
|
393
|
+
kind: "headers",
|
|
394
|
+
});
|
|
395
|
+
let parsed;
|
|
396
|
+
try {
|
|
397
|
+
parsed = JSON.parse(stdout.trim());
|
|
398
|
+
} catch {
|
|
399
|
+
throw runtimeError(
|
|
400
|
+
MARKETPLACE_HEADERS_HELPER_ERROR.INVALID_OUTPUT,
|
|
401
|
+
"Marketplace headers helper stdout must be one JSON header object",
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
return normalizeHeaderMap(parsed);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function sourcePathFromOutput(value, deps) {
|
|
408
|
+
if (
|
|
409
|
+
!value ||
|
|
410
|
+
typeof value !== "object" ||
|
|
411
|
+
Array.isArray(value) ||
|
|
412
|
+
Object.getPrototypeOf(value) !== Object.prototype ||
|
|
413
|
+
Object.keys(value).length !== 1 ||
|
|
414
|
+
typeof value.source !== "string" ||
|
|
415
|
+
value.source.length === 0 ||
|
|
416
|
+
value.source.includes("\0") ||
|
|
417
|
+
!path.isAbsolute(value.source)
|
|
418
|
+
) {
|
|
419
|
+
throw runtimeError(
|
|
420
|
+
MARKETPLACE_COMMAND_SOURCE_ERROR.INVALID_OUTPUT,
|
|
421
|
+
'Marketplace command source stdout must be {"source": "/absolute/plugin/path"}',
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
let source;
|
|
425
|
+
let original;
|
|
426
|
+
let stat;
|
|
427
|
+
try {
|
|
428
|
+
original = deps.lstatSync(value.source);
|
|
429
|
+
source = deps.realpathSync(value.source);
|
|
430
|
+
stat = deps.lstatSync(source);
|
|
431
|
+
} catch {
|
|
432
|
+
throw runtimeError(
|
|
433
|
+
MARKETPLACE_COMMAND_SOURCE_ERROR.INVALID_OUTPUT,
|
|
434
|
+
"Marketplace command source returned an unavailable plugin directory",
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
if (
|
|
438
|
+
original.isSymbolicLink() ||
|
|
439
|
+
stat.isSymbolicLink() ||
|
|
440
|
+
!stat.isDirectory()
|
|
441
|
+
) {
|
|
442
|
+
throw runtimeError(
|
|
443
|
+
MARKETPLACE_COMMAND_SOURCE_ERROR.INVALID_OUTPUT,
|
|
444
|
+
"Marketplace command source must return a real plugin directory",
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
return source;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Run a Marketplace command source and turn its one JSON response into a
|
|
452
|
+
* validated local plugin directory. `mode: link` is intentionally limited to
|
|
453
|
+
* POSIX at this boundary; the immutable installer still snapshots the payload
|
|
454
|
+
* before activation, so a command cannot make an installed version mutable.
|
|
455
|
+
*/
|
|
456
|
+
export async function runMarketplaceCommandSource(descriptor, options = {}) {
|
|
457
|
+
const plan = normalizeMarketplaceCommandDescriptor(descriptor, {
|
|
458
|
+
kind: "source",
|
|
459
|
+
allowType: options.allowType === true,
|
|
460
|
+
label: "Marketplace command source descriptor",
|
|
461
|
+
});
|
|
462
|
+
const stdout = await runMarketplaceProcessDescriptor(plan, {
|
|
463
|
+
...options,
|
|
464
|
+
kind: "source",
|
|
465
|
+
});
|
|
466
|
+
let parsed;
|
|
467
|
+
try {
|
|
468
|
+
parsed = JSON.parse(stdout.trim());
|
|
469
|
+
} catch {
|
|
470
|
+
throw runtimeError(
|
|
471
|
+
MARKETPLACE_COMMAND_SOURCE_ERROR.INVALID_OUTPUT,
|
|
472
|
+
"Marketplace command source stdout must be one JSON object",
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
const deps = {
|
|
476
|
+
lstatSync: options.lstatSync || fs.lstatSync,
|
|
477
|
+
realpathSync: options.realpathSync || fs.realpathSync.native,
|
|
478
|
+
};
|
|
479
|
+
const source = sourcePathFromOutput(parsed, deps);
|
|
480
|
+
try {
|
|
481
|
+
assertSafeInstalledPluginStructure(source);
|
|
482
|
+
} catch {
|
|
483
|
+
throw runtimeError(
|
|
484
|
+
MARKETPLACE_COMMAND_SOURCE_ERROR.INVALID_OUTPUT,
|
|
485
|
+
"Marketplace command source returned an unsafe plugin structure",
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
let payload;
|
|
489
|
+
try {
|
|
490
|
+
payload = buildMarketplacePayloadSbom(source);
|
|
491
|
+
} catch {
|
|
492
|
+
throw runtimeError(
|
|
493
|
+
MARKETPLACE_COMMAND_SOURCE_ERROR.INVALID_OUTPUT,
|
|
494
|
+
"Marketplace command source payload could not be verified",
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
return Object.freeze({
|
|
498
|
+
source,
|
|
499
|
+
mode: plan.mode,
|
|
500
|
+
payloadSha256: payload.digest,
|
|
501
|
+
fileCount: payload.fileCount,
|
|
502
|
+
totalBytes: payload.totalBytes,
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function headersEntries(value) {
|
|
507
|
+
if (!value) return [];
|
|
508
|
+
if (Array.isArray(value)) return value;
|
|
509
|
+
if (typeof value.forEach === "function") {
|
|
510
|
+
const entries = [];
|
|
511
|
+
value.forEach((headerValue, name) => entries.push([name, headerValue]));
|
|
512
|
+
return entries;
|
|
513
|
+
}
|
|
514
|
+
return Object.entries(value);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
function mergeHeaders(existing, dynamic) {
|
|
518
|
+
const merged = {};
|
|
519
|
+
const seen = new Set();
|
|
520
|
+
for (const [name, value] of headersEntries(existing)) {
|
|
521
|
+
const normalized = String(name).toLowerCase();
|
|
522
|
+
seen.add(normalized);
|
|
523
|
+
merged[name] = String(value);
|
|
524
|
+
}
|
|
525
|
+
for (const [name, value] of Object.entries(dynamic)) {
|
|
526
|
+
if (!seen.has(name.toLowerCase())) merged[name] = value;
|
|
527
|
+
}
|
|
528
|
+
return merged;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Decorate a fetch implementation so helper headers can leave the process
|
|
533
|
+
* only for the catalog origin. The artifact client invokes this per redirect
|
|
534
|
+
* hop, which naturally drops headers on every cross-origin hop.
|
|
535
|
+
*/
|
|
536
|
+
export function createSameOriginMarketplaceHeaderFetch(
|
|
537
|
+
fetchImpl,
|
|
538
|
+
trustedOrigin,
|
|
539
|
+
dynamicHeaders,
|
|
540
|
+
) {
|
|
541
|
+
if (typeof fetchImpl !== "function") {
|
|
542
|
+
throw runtimeError(
|
|
543
|
+
MARKETPLACE_HEADERS_HELPER_ERROR.PROCESS_START,
|
|
544
|
+
"Marketplace transport is unavailable",
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
const headers = normalizeHeaderMap(dynamicHeaders);
|
|
548
|
+
const origin = new URL(trustedOrigin).origin;
|
|
549
|
+
return (url, options = {}) => {
|
|
550
|
+
let matchesOrigin = false;
|
|
551
|
+
try {
|
|
552
|
+
matchesOrigin = new URL(String(url)).origin === origin;
|
|
553
|
+
} catch {
|
|
554
|
+
// Let the underlying transport preserve its own URL error behavior.
|
|
555
|
+
}
|
|
556
|
+
return fetchImpl(url, {
|
|
557
|
+
...options,
|
|
558
|
+
...(matchesOrigin
|
|
559
|
+
? { headers: mergeHeaders(options.headers, headers) }
|
|
560
|
+
: {}),
|
|
561
|
+
});
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* A non-secret binding fingerprint for short-lived in-memory authority maps.
|
|
567
|
+
* It intentionally hashes header names only; helper values are credentials and
|
|
568
|
+
* must never become cache/provenance/display material.
|
|
569
|
+
*/
|
|
570
|
+
export function marketplaceHeaderNamesFingerprint(headers) {
|
|
571
|
+
return crypto
|
|
572
|
+
.createHash("sha256")
|
|
573
|
+
.update(
|
|
574
|
+
Object.keys(headers || {})
|
|
575
|
+
.map((key) => key.toLowerCase())
|
|
576
|
+
.sort()
|
|
577
|
+
.join("\0"),
|
|
578
|
+
)
|
|
579
|
+
.digest("hex");
|
|
580
|
+
}
|
|
@@ -21,6 +21,7 @@ export const MAX_MARKETPLACE_ARTIFACT_REDIRECTS = 3;
|
|
|
21
21
|
export const DEFAULT_MARKETPLACE_ARTIFACT_TIMEOUT_MS = 15_000;
|
|
22
22
|
export const MAX_MARKETPLACE_ARTIFACT_URL_LENGTH = 4096;
|
|
23
23
|
export const MARKETPLACE_REMOTE_ARTIFACT_LIMITS = Object.freeze({
|
|
24
|
+
archive: 64 * 1024 * 1024,
|
|
24
25
|
signature: 16 * 1024,
|
|
25
26
|
publicKey: 64 * 1024,
|
|
26
27
|
sbom: 16 * 1024 * 1024,
|