chainlesschain 0.165.6 → 0.165.9
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/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-vfoDb6HZ.js → AIOps-DxwjrnEA.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Cm5f7p93.js → ActionButton-JdbYowzn.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-yRuvgWxa.js → Analytics-C06GCahv.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BROsC4h1.js → AppLayout-BUVEEyi1.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-CimHApb1.js → Artifacts-D_ORzkJd.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DI8kr8zI.js → Audit-8o_Y5ejG.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DSLzKy-n.js → BackgroundAgents-DrkHd5VU.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DkH_n2r1.js → Backup-CKBZCX11.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CKSrUoRA.js → BaseInput-C8HkI399.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-ClwfMXUS.js → Chat-zb2H2Wux.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CjMaqfL7.js → ChatBubbleRenderer-BDcNpU_F.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BYTehcQG.js → Checkbox-MwPtQmNz.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-B8AMcp6J.js → Codegen-3p5QCkFK.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BNSogPo3.js → Col-BPLlhn52.js} +1 -1
- package/src/assets/web-panel/assets/{Community-JxPvGb8O.js → Community-C-3dBNOM.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DF7bFAgE.js → Compact-BUcy-F_b.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Bvhqnwrq.js → Compliance-CI8NxT8m.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BDS0CJvM.js → Cowork-DaDEBS-Q.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DqvRfxoQ.js → Cron-BSv9HXu5.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CDcIvnqS.js → Crosschain-yuiKlJmv.js} +1 -1
- package/src/assets/web-panel/assets/{DID-D7jaUxU3.js → DID-D6LfldB0.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-B5A18wEV.js → Dashboard-CBhLqG61.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-_6IVkGag.js → Dropdown-BG8pIl3O.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-C9PeiKCG.js → EmailListRenderer-CY92VIE6.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DXjuEHrX.js → FamilyGuardDashboard-1Q_ehauM.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-B4IAR9zv.js → Federation-D3XirJIU.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CxQeSNx1.js → FormItemContext-DfI9UuGZ.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-B8GS-Y3N.js → GenericCardRenderer-IeCZk2m7.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BS8SouUX.js → Git-DzK4IJAZ.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Dq9aYb5Q.js → Governance-BHf5KfmQ.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BrCEe9AJ.js → Inference-BmaxSALS.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DybOpiY2.js → KnowledgeGraph-BgePFLA9.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DBpzbRfx.js → Logs-nqgxpOc4.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-xkX6izBt.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Cc7CCSCu.js → Marketplace-Bu8to-86.js} +1 -1
- package/src/assets/web-panel/assets/McpTools-BFWTzEk0.js +4 -0
- package/src/assets/web-panel/assets/{Memory-KCqlp9ol.js → Memory-B026G2GA.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Bys84ySN.js → MobileBridge-CM2Eeg6I.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-B-6qU-je.js → MobileProjects-B79Ob3hy.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BgY-fvCq.js → Mtc-CxevSZuV.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-B8pCmqQJ.js → MtcAudit-X396cPEX.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BbOmYutA.js → Multisig-HWIB_aZ1.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BocLQz_M.js → NLProgramming-gnYD1Xwy.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CSwbxEop.js → Notes-Dn2Gf_J1.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CqFNSYG3.js → NotificationSettings-BRKBQ5rq.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-C6gMfAk7.js → OrderTableRenderer-Dy___Cgo.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-QrDXVdMJ.js → Organization-cqfccxnt.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Cxntotjt.js → Overflow-CSX4FHN3.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CIdBOwNq.js → P2P-Bwa4aghp.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CT5aP8rD.js → PdhVaultBrowser-Dhszyjig.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-DH7OM8XU.js → Permissions-CXzTyk6e.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CnJqbWce.js → PersonalDataHub-CFCAAJbb.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-5C3HG1kH.js → Pipeline-BPJbx6xt.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B4yIp7xK.js → Privacy-BbiXvEHz.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BMvt-2M0.js → ProjectInit-B-s7-wSD.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CvSTEMRG.js → ProjectSettings-Dyug206y.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BKBJxEek.js → Projects-BtAI5Fwo.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-BdwUqFWN.js → Providers-JpIPmz6N.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DtnCKlTm.js → QrScannerModal-CZdoN64A.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-sTbgwyNr.js → QuickAsk-BwvnoRIT.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Bzr14gSb.js → Recommend-ASMlMQrD.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-C_TF5IaJ.js → RemoteSession-BiJzKFKi.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-GCAM4H2K.js → Reputation-C80TWLIO.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Dir0r6OQ.js → Row-C1VNmjmX.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CpGnlecX.js → RssFeed-T2MyGUlG.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DMMamC6u.js → Search-DXM6O83L.js} +1 -1
- package/src/assets/web-panel/assets/{Security-yqay5yG-.js → Security-nv69kU7W.js} +3 -3
- package/src/assets/web-panel/assets/{Services-C5i2wh9G.js → Services-AyHWe7Qj.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-vUqk35yj.js → Skeleton-D6PWLxFI.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DzcSkhot.js → Skills-BqVeOmNQ.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CB6qbYNr.js → Sla-BegIPl9M.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BHUI7cox.js → SpeechSettings-CKJn3xk-.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-D-RrsxTJ.js → SyncSettings-Th4cnAMl.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-DFxdOJiq.js → Tasks-BuKfBroh.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-SKAob_Aq.js → Templates-CMuWN8Ac.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BPfsfHQ-.js → Tenant-C4je8E8Q.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-8iw7FpUf.js → Terminal-agJESOcO.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-C4Gjj5Su.js → TimelineRenderer-D2qDuVZ_.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-COYhN18e.js → Tokens-Cvmn99rH.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-B-JzXcf6.js → Trigger-D_QYIHH8.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BJ5bg0nI.js → Trust-BmzvQLnX.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BG_ByRMf.js → UkeySign-D_LopHwH.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-B3kOnSiU.js → VideoEditing-DoWl3PhQ.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CcoGFnK7.js → Wallet-5NYcAkxe.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DdT8vRC_.js → WebAuthn-B-_Q3ewp.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-CZu3M9N8.js → WorkflowEditor-CHET-gi2.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DxJt3Qba.js → chat-C6nvb-n6.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DdYfwJaB.js → colors-CTDE9LTX.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BG3SUzwj.js → compact-item-KnemdF8D.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-By51z2-1.js → createContext-DUJR3Uek.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-1DqLH1KX.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-B0apZ3KJ.js → hasIn-CFNTaby8.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZxtP8jG7.js → index-65HO56Bv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Da_WBdLX.js → index-B8RtbSkV.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBPf3TpM.js → index-BHqSqnW7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BP94CrBV.js → index-BTetEUWd.js} +1 -1
- package/src/assets/web-panel/assets/{index-p1_8SbI1.js → index-BXWg1crv.js} +1 -1
- package/src/assets/web-panel/assets/{index-BWF8_mkx.js → index-BdiC4LOs.js} +1 -1
- package/src/assets/web-panel/assets/index-BhJtcPWo.js +1 -0
- package/src/assets/web-panel/assets/{index-SQqOlR3d.js → index-BuizJo2E.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpjZhgNd.js → index-BwZM1rod.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzmQElZy.js → index-C96N9xeL.js} +1 -1
- package/src/assets/web-panel/assets/{index-bP_VlDb4.js → index-CHfUdnJH.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZFbps9po.js → index-CKvBF3Ov.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaIz0NAW.js → index-CSD9_I2_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BewKYrX9.js → index-Cc7dbl_p.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNIxXMmN.js → index-CcF0D7UZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Q2SCX-MI.js → index-Ceu92a8D.js} +1 -1
- package/src/assets/web-panel/assets/{index-DE76D-kA.js → index-CnLpuTAU.js} +1 -1
- package/src/assets/web-panel/assets/index-Cq8MWPDT.js +1 -0
- package/src/assets/web-panel/assets/{index-BkvcEo4p.js → index-CquKnw5r.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cp6e-hGw.js → index-CyEtHvEE.js} +1 -1
- package/src/assets/web-panel/assets/{index-BLIbGOLX.js → index-DF-fcTvQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DCn8IcxV.js → index-DF1Y0Vuw.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bissefox.js → index-DJyPeBBk.js} +3 -3
- package/src/assets/web-panel/assets/{index-BZ_0qm4g.js → index-DP-PbO11.js} +1 -1
- package/src/assets/web-panel/assets/{index-kf57LJ93.js → index-DZgCRMxk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYINoRLK.js → index-DfJzS3Qa.js} +1 -1
- package/src/assets/web-panel/assets/{index-3jWkIu5j.js → index-DqPpJkte.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5rLiEo0.js → index-DzReoLyh.js} +1 -1
- package/src/assets/web-panel/assets/{index-CW93tZDv.js → index-JGTiDeOW.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1C9i79A.js → index-NUR0If7O.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAhHirVH.js → index-NtAcnJYW.js} +1 -1
- package/src/assets/web-panel/assets/{index-RD6O-0C6.js → index-OmuhFYKE.js} +1 -1
- package/src/assets/web-panel/assets/{index-oxRrmFO9.js → index-Wlc7o_C8.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3rWuPMW.js → index-bxTPfdri.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIrJfqO4.js → index-k6uorYmf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BfWYsB9t.js → index-ox6mIwE2.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bos5_aMV.js → index-rVDD7AAR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWEuZWCK.js → index-u0h6QqVV.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dz49VOyQ.js → index-v-mtxmWH.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BWJktcg8.js → initDefaultProps-qEt8dI-t.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BEXBzUFV.js → motion-DetKPWy-.js} +1 -1
- package/src/assets/web-panel/assets/{move-BUKwn2sx.js → move-BeNYeDV2.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-FTI7btqQ.js → mtc-parser-C0q0MK_T.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CsLtSPH3.js → omit-DLKkrKpE.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DWZxsT_S.js → pickAttrs-Bw1tWsY8.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Bcfs43CX.js → placementArrow-DeesBLbd.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-a9bcC1p-.js → responsiveObserve-bqLhxHhn.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BDTzgOXN.js → slide-DGCXRoQm.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Iq1j_HUg.js → statusUtils-H-re3Egl.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DAZEYxeh.js → styleChecker-BXg4qGX_.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DVkjyDrh.js → useFlexGapSupport-CKLb2KA6.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-wXTpNTHt.js → useFs-CTAhHeyw.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CtQM_aZr.js → usePersonalDataHub-BQ4pDh5g.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-hjEoG85v.js → vnode-jrSK6j4j.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BHVpyKg_.js → zoom-fOQE24pw.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 +91 -60
- package/src/commands/git.js +39 -0
- package/src/commands/plugin.js +17 -2
- package/src/commands/session-group.js +131 -0
- package/src/commands/session-location.js +48 -0
- package/src/commands/session.js +11 -0
- package/src/commands/sync-providers.js +4 -1
- package/src/commands/update.js +1 -0
- package/src/data/changelog.json +40 -1
- package/src/gateways/ws/mcp-topic-handlers.js +167 -0
- 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 +701 -91
- package/src/harness/session-index.js +15 -4
- package/src/lib/agent-network.js +166 -29
- package/src/lib/agent-router.js +62 -6
- package/src/lib/agent-sandbox.js +7 -1
- 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/browser-evidence.js +1405 -0
- package/src/lib/chrome-connector.js +465 -79
- package/src/lib/claude-code-bridge.js +159 -54
- 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/cowork-workflow.js +69 -6
- 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/external-agent-adapters.js +269 -0
- 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/ipfs-storage.js +127 -25
- package/src/lib/llm-config-defaults.js +43 -0
- package/src/lib/mcp-lifecycle-authority.js +887 -0
- package/src/lib/mcp-oauth.js +101 -20
- package/src/lib/mcp-tls.js +103 -3
- package/src/lib/orchestrator.js +47 -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 +117 -1
- package/src/lib/plugin-runtime/lsp.js +4 -4
- package/src/lib/plugin-runtime/marketplace-archive-source.js +40 -5
- package/src/lib/plugin-runtime/marketplace-catalog.js +13 -2
- 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-source-adapter.js +33 -8
- 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 +151 -6
- package/src/lib/plugin-runtime/settings.js +3 -1
- package/src/lib/plugin-runtime/trust.js +274 -13
- 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/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 +168 -21
- package/src/lib/session-projection.js +244 -4
- package/src/lib/session-store-guard.js +3 -1
- package/src/lib/session-workbench-store.js +466 -0
- package/src/lib/shell-approval.js +7 -5
- 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/workflow-engine.js +42 -11
- package/src/lib/workspace-trust.js +793 -0
- package/src/repl/agent-repl.js +124 -5
- package/src/repl/permission-prompt.js +10 -12
- package/src/runtime/agent-core.js +311 -18
- package/src/runtime/agent-runtime.js +12 -1
- package/src/runtime/bootstrap.js +37 -13
- package/src/runtime/coding-agent-contract-shared.cjs +11 -4
- package/src/runtime/headless-runner.js +234 -36
- package/src/runtime/headless-stream.js +181 -6
- package/src/runtime/mcp-config.js +298 -8
- package/src/runtime/policies/agent-policy.js +8 -0
- package/src/runtime/status-diagnostics-lite.js +9 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-CFyt8iUd.js +0 -1
- package/src/assets/web-panel/assets/McpTools-DFaIhOfu.js +0 -7
- package/src/assets/web-panel/assets/devWarning-DorRZcI9.js +0 -1
- package/src/assets/web-panel/assets/index-BETiL0a3.js +0 -1
- package/src/assets/web-panel/assets/index-BhAVHuW8.js +0 -1
package/src/lib/paths.js
CHANGED
|
@@ -1,49 +1,277 @@
|
|
|
1
|
+
import { existsSync, lstatSync } from "node:fs";
|
|
1
2
|
import { homedir } from "node:os";
|
|
2
|
-
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
3
|
+
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
3
4
|
import { CONFIG_DIR_NAME } from "../constants.js";
|
|
4
5
|
import { getPlatform } from "./platform.js";
|
|
6
|
+
import {
|
|
7
|
+
CLAUDE_CONFIG_DIR_ENV,
|
|
8
|
+
resolveClaudeProjectStorageDir,
|
|
9
|
+
usesClaudeConfigDirectory,
|
|
10
|
+
} from "./claude-project-storage-layout.js";
|
|
5
11
|
import {
|
|
6
12
|
assertSafeOwnerOnlyPath,
|
|
7
13
|
ensurePrivateDirectory,
|
|
8
14
|
repairPrivatePaths,
|
|
9
15
|
} from "./secure-fs.js";
|
|
10
16
|
|
|
17
|
+
const securedClaudeProjectStorageEntries = new Map();
|
|
18
|
+
|
|
19
|
+
function pathContains(parent, candidate) {
|
|
20
|
+
const relation = relative(parent, candidate);
|
|
21
|
+
return (
|
|
22
|
+
relation === "" ||
|
|
23
|
+
(!relation.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) &&
|
|
24
|
+
relation !== ".." &&
|
|
25
|
+
!isAbsolute(relation))
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function nearestGitWorktreeRoot(cwd) {
|
|
30
|
+
let current = resolve(cwd);
|
|
31
|
+
for (;;) {
|
|
32
|
+
if (existsSync(join(current, ".git"))) return current;
|
|
33
|
+
const parent = dirname(current);
|
|
34
|
+
if (parent === current) return null;
|
|
35
|
+
current = parent;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function configHomeError(message) {
|
|
40
|
+
const error = new Error(message);
|
|
41
|
+
error.code = "CONFIG_HOME_UNSAFE";
|
|
42
|
+
return error;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isBroadSharedConfigRoot(resolvedHome, env) {
|
|
46
|
+
const platform = getPlatform();
|
|
47
|
+
const candidates =
|
|
48
|
+
platform === "win32"
|
|
49
|
+
? [
|
|
50
|
+
"C:\\Users",
|
|
51
|
+
"C:\\Users\\Public",
|
|
52
|
+
"C:\\Windows",
|
|
53
|
+
"C:\\ProgramData",
|
|
54
|
+
"C:\\Program Files",
|
|
55
|
+
"C:\\Program Files (x86)",
|
|
56
|
+
env?.PUBLIC,
|
|
57
|
+
env?.ProgramData,
|
|
58
|
+
env?.PROGRAMDATA,
|
|
59
|
+
env?.SystemRoot,
|
|
60
|
+
env?.WINDIR,
|
|
61
|
+
]
|
|
62
|
+
: [
|
|
63
|
+
"/tmp",
|
|
64
|
+
"/var/tmp",
|
|
65
|
+
"/usr",
|
|
66
|
+
"/etc",
|
|
67
|
+
"/var",
|
|
68
|
+
"/home",
|
|
69
|
+
"/root",
|
|
70
|
+
"/run",
|
|
71
|
+
"/opt",
|
|
72
|
+
"/srv",
|
|
73
|
+
"/mnt",
|
|
74
|
+
"/media",
|
|
75
|
+
];
|
|
76
|
+
return candidates.some((candidate) => {
|
|
77
|
+
if (typeof candidate !== "string" || !candidate) return false;
|
|
78
|
+
try {
|
|
79
|
+
const normalized = resolve(candidate);
|
|
80
|
+
return platform === "win32"
|
|
81
|
+
? normalized.toLowerCase() === resolvedHome.toLowerCase()
|
|
82
|
+
: normalized === resolvedHome;
|
|
83
|
+
} catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Reject broad shared directories before any owner-only chmod/DACL repair.
|
|
91
|
+
* Unlike the generic secure-fs guard, config/data roots are high-value and
|
|
92
|
+
* must never target a shared system parent such as C:\\Users or /home.
|
|
93
|
+
*/
|
|
94
|
+
export function assertSafeConfigDataRoot(dirPath, options = {}) {
|
|
95
|
+
const resolvedPath = resolve(dirPath);
|
|
96
|
+
if (isBroadSharedConfigRoot(resolvedPath, options.env || process.env)) {
|
|
97
|
+
throw configHomeError(
|
|
98
|
+
"Config/data root must not be a broad shared system directory",
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
assertSafeOwnerOnlyPath(resolvedPath);
|
|
102
|
+
return resolvedPath;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function resolveConfiguredHome(configured, variableName, cwd, env) {
|
|
106
|
+
const windowsLiteral = configured.replaceAll("/", "\\");
|
|
107
|
+
if (
|
|
108
|
+
windowsLiteral.startsWith("\\\\?\\") ||
|
|
109
|
+
windowsLiteral.startsWith("\\\\.\\")
|
|
110
|
+
) {
|
|
111
|
+
throw configHomeError(
|
|
112
|
+
`${variableName} must not use a Windows device namespace`,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (!isAbsolute(configured)) {
|
|
116
|
+
throw configHomeError(
|
|
117
|
+
`${variableName} must be an absolute path for owner-only storage`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
const resolvedHome = resolve(configured);
|
|
121
|
+
try {
|
|
122
|
+
assertSafeConfigDataRoot(resolvedHome, { env });
|
|
123
|
+
} catch (error) {
|
|
124
|
+
if (error?.code === "CONFIG_HOME_UNSAFE") throw error;
|
|
125
|
+
throw configHomeError(
|
|
126
|
+
`${variableName} must not be a broad shared system directory`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
const resolvedCwd = resolve(cwd);
|
|
130
|
+
const worktreeRoot = nearestGitWorktreeRoot(resolvedCwd);
|
|
131
|
+
if (
|
|
132
|
+
pathContains(resolvedHome, resolvedCwd) ||
|
|
133
|
+
pathContains(resolvedCwd, resolvedHome) ||
|
|
134
|
+
(worktreeRoot &&
|
|
135
|
+
(pathContains(worktreeRoot, resolvedHome) ||
|
|
136
|
+
pathContains(resolvedHome, worktreeRoot)))
|
|
137
|
+
) {
|
|
138
|
+
throw configHomeError(
|
|
139
|
+
`${variableName} must not be the current working directory, its worktree, or any nested/ancestor path`,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
// This is deliberately a no-IO validation. Directory creation/ACL repair
|
|
143
|
+
// remains in ensureHomeDir(), but broad roots and device aliases are refused
|
|
144
|
+
// before any caller can ask the secure-fs layer to mutate them.
|
|
145
|
+
return resolvedHome;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Resolve the CLI's authoritative config/data root. CHAINLESSCHAIN_HOME is a
|
|
150
|
+
* native explicit override and takes precedence over CLAUDE_CONFIG_DIR; the
|
|
151
|
+
* latter is only a compatible fallback for an otherwise unconfigured CLI.
|
|
152
|
+
*/
|
|
153
|
+
export function resolveConfigDataRoot(options = {}) {
|
|
154
|
+
const env = options.env || process.env;
|
|
155
|
+
const cwd = options.cwd || process.cwd();
|
|
156
|
+
const nativeHome = env.CHAINLESSCHAIN_HOME;
|
|
157
|
+
if (nativeHome) {
|
|
158
|
+
return Object.freeze({
|
|
159
|
+
path: resolveConfiguredHome(nativeHome, "CHAINLESSCHAIN_HOME", cwd, env),
|
|
160
|
+
source: "chainlesschain",
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
if (usesClaudeConfigDirectory(env)) {
|
|
164
|
+
const configured = env[CLAUDE_CONFIG_DIR_ENV].trim();
|
|
165
|
+
return Object.freeze({
|
|
166
|
+
path: resolveConfiguredHome(configured, CLAUDE_CONFIG_DIR_ENV, cwd, env),
|
|
167
|
+
source: "claude",
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return Object.freeze({
|
|
171
|
+
path: join(homedir(), CONFIG_DIR_NAME),
|
|
172
|
+
source: "default",
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
11
176
|
export function getHomeDir() {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
177
|
+
return resolveConfigDataRoot().path;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Claude-compatible session storage is opt-in and only activates when the
|
|
182
|
+
* launcher supplied both CLAUDE_CONFIG_DIR and a safe project directory name.
|
|
183
|
+
* Legacy callers continue to use `<home>/sessions`.
|
|
184
|
+
*/
|
|
185
|
+
export function getClaudeProjectStorageDir(options = {}) {
|
|
186
|
+
const env = options.env || process.env;
|
|
187
|
+
const root = resolveConfigDataRoot({ ...options, env });
|
|
188
|
+
if (root.source !== "claude") return null;
|
|
189
|
+
return resolveClaudeProjectStorageDir(root.path, { env });
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function getSessionStoreDir(options = {}) {
|
|
193
|
+
return (
|
|
194
|
+
getClaudeProjectStorageDir(options) ||
|
|
195
|
+
join(resolveConfigDataRoot(options).path, "sessions")
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Secure a Claude-compatible project storage tree without trusting inherited
|
|
201
|
+
* Windows ACLs on pre-existing descendants. The config root is repaired
|
|
202
|
+
* first, then every child is created below that verified boundary and repaired
|
|
203
|
+
* together in one Windows ACL batch. This keeps the security invariant while
|
|
204
|
+
* avoiding a PowerShell process for every storage subdirectory.
|
|
205
|
+
*/
|
|
206
|
+
export function ensureClaudeProjectStorageTree(
|
|
207
|
+
homeDir,
|
|
208
|
+
projectDir,
|
|
209
|
+
options = {},
|
|
210
|
+
) {
|
|
211
|
+
const home = resolve(homeDir);
|
|
212
|
+
const projectsDir = join(home, "projects");
|
|
213
|
+
const project = resolve(projectDir);
|
|
214
|
+
const extraDirectories = Array.isArray(options.extraDirectories)
|
|
215
|
+
? options.extraDirectories.map((entry) => resolve(entry))
|
|
216
|
+
: [];
|
|
217
|
+
if (!pathContains(projectsDir, project) || project === projectsDir) {
|
|
218
|
+
throw configHomeError(
|
|
219
|
+
"Claude project storage path must remain below projects",
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
if (extraDirectories.some((entry) => !pathContains(project, entry))) {
|
|
223
|
+
throw configHomeError(
|
|
224
|
+
"Claude project storage descendants must remain below the project root",
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
ensurePrivateDirectory(home, {
|
|
229
|
+
applyWindowsAcl: true,
|
|
230
|
+
failIfUnavailable: true,
|
|
231
|
+
});
|
|
232
|
+
const descendants = [projectsDir, project, ...extraDirectories];
|
|
233
|
+
if (getPlatform() === "win32") {
|
|
234
|
+
const repairTargets = [];
|
|
235
|
+
for (const directory of descendants) {
|
|
236
|
+
ensurePrivateDirectory(directory, {
|
|
237
|
+
applyWindowsAcl: false,
|
|
238
|
+
failIfUnavailable: true,
|
|
239
|
+
});
|
|
240
|
+
let current = null;
|
|
241
|
+
try {
|
|
242
|
+
const entry = lstatSync(directory);
|
|
243
|
+
current = `${entry.dev}:${entry.ino}`;
|
|
244
|
+
} catch {
|
|
245
|
+
// ensurePrivateDirectory above either created the directory or threw;
|
|
246
|
+
// retain a fail-closed repair target if a filesystem race removed it.
|
|
247
|
+
}
|
|
248
|
+
// The secure-fs layer caches verified Windows ACLs per path. Keep a
|
|
249
|
+
// matching tree cache so repeated session writes do not re-run a batch,
|
|
250
|
+
// but force a repair whenever this helper first observes a descendant.
|
|
251
|
+
if (securedClaudeProjectStorageEntries.get(directory) !== current) {
|
|
252
|
+
repairTargets.push(directory);
|
|
253
|
+
}
|
|
24
254
|
}
|
|
25
|
-
if (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
|
|
255
|
+
if (repairTargets.length > 0) {
|
|
256
|
+
// A private parent is not proof that an older child has no broad explicit
|
|
257
|
+
// ACE. Repair all newly observed descendants in one fail-closed batch.
|
|
258
|
+
repairPrivatePaths(repairTargets, { platform: "win32" });
|
|
259
|
+
for (const directory of repairTargets) {
|
|
260
|
+
securedClaudeProjectStorageEntries.set(
|
|
261
|
+
directory,
|
|
262
|
+
(() => {
|
|
263
|
+
const entry = lstatSync(directory);
|
|
264
|
+
return `${entry.dev}:${entry.ino}`;
|
|
265
|
+
})(),
|
|
266
|
+
);
|
|
267
|
+
}
|
|
31
268
|
}
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
relativeCwd === "" ||
|
|
36
|
-
(!relativeCwd.startsWith("..") && !isAbsolute(relativeCwd))
|
|
37
|
-
) {
|
|
38
|
-
const error = new Error(
|
|
39
|
-
"CHAINLESSCHAIN_HOME must not be the current working directory or one of its ancestors",
|
|
40
|
-
);
|
|
41
|
-
error.code = "CONFIG_HOME_UNSAFE";
|
|
42
|
-
throw error;
|
|
269
|
+
} else {
|
|
270
|
+
for (const directory of descendants) {
|
|
271
|
+
ensurePrivateDirectory(directory, { failIfUnavailable: true });
|
|
43
272
|
}
|
|
44
|
-
return configured;
|
|
45
273
|
}
|
|
46
|
-
return
|
|
274
|
+
return project;
|
|
47
275
|
}
|
|
48
276
|
|
|
49
277
|
export function getBinDir() {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonicalize the part of a tool request that is classified and shown to the
|
|
3
|
+
* user for approval. Keeping this in one place prevents the safety classifier
|
|
4
|
+
* and the permission prompt from silently reasoning about different inputs.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
function quoteArgvToken(value) {
|
|
8
|
+
const token = String(value);
|
|
9
|
+
if (token && !/[\s|;&"'\\]/u.test(token)) return token;
|
|
10
|
+
return `"${token.replace(/\\/gu, "\\\\").replace(/"/gu, '\\"')}"`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function normalizePermissionRequest({ tool, args } = {}) {
|
|
14
|
+
const normalizedArgs = args && typeof args === "object" ? args : {};
|
|
15
|
+
const command =
|
|
16
|
+
typeof normalizedArgs.command === "string"
|
|
17
|
+
? normalizedArgs.command
|
|
18
|
+
: Array.isArray(normalizedArgs.argv)
|
|
19
|
+
? normalizedArgs.argv.map(quoteArgvToken).join(" ")
|
|
20
|
+
: "";
|
|
21
|
+
const source = String(
|
|
22
|
+
normalizedArgs.path ??
|
|
23
|
+
normalizedArgs.file_path ??
|
|
24
|
+
normalizedArgs.source ??
|
|
25
|
+
normalizedArgs.from ??
|
|
26
|
+
"",
|
|
27
|
+
);
|
|
28
|
+
const destination = String(
|
|
29
|
+
normalizedArgs.destination ??
|
|
30
|
+
normalizedArgs.new_path ??
|
|
31
|
+
normalizedArgs.to ??
|
|
32
|
+
"",
|
|
33
|
+
);
|
|
34
|
+
const detail =
|
|
35
|
+
command ||
|
|
36
|
+
(source && destination
|
|
37
|
+
? `${source} -> ${destination}`
|
|
38
|
+
: source || destination);
|
|
39
|
+
|
|
40
|
+
return Object.freeze({
|
|
41
|
+
tool: String(tool || "unknown").trim() || "unknown",
|
|
42
|
+
args: normalizedArgs,
|
|
43
|
+
command,
|
|
44
|
+
source,
|
|
45
|
+
destination,
|
|
46
|
+
detail,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -81,7 +81,9 @@ export function collectPluginBinCommands(opts = {}) {
|
|
|
81
81
|
}
|
|
82
82
|
return [];
|
|
83
83
|
}
|
|
84
|
-
const { trusted, skipped } = partitionByTrust(plugins
|
|
84
|
+
const { trusted, skipped } = partitionByTrust(plugins, {
|
|
85
|
+
workspaceRoot: opts.cwd,
|
|
86
|
+
});
|
|
85
87
|
warnUntrustedOnce(
|
|
86
88
|
skipped
|
|
87
89
|
.filter((p) => p.manifest?.components?.bin?.length)
|
|
@@ -215,7 +215,9 @@ export function collectPluginHooks(opts = {}) {
|
|
|
215
215
|
}
|
|
216
216
|
// A hook runs a shell command — gate it behind trust so a cloned repo's
|
|
217
217
|
// project plugin can't run commands the moment the agent starts.
|
|
218
|
-
const { trusted, skipped } = partitionByTrust(plugins
|
|
218
|
+
const { trusted, skipped } = partitionByTrust(plugins, {
|
|
219
|
+
workspaceRoot: opts.cwd,
|
|
220
|
+
});
|
|
219
221
|
warnUntrustedOnce(
|
|
220
222
|
skipped.filter((p) => p.manifest?.components?.hooks).map((p) => p.name),
|
|
221
223
|
"hooks",
|
|
@@ -326,6 +326,10 @@ export function installFromDirectory(srcDir, opts = {}) {
|
|
|
326
326
|
// and may ship its own `.plugin-lock.json` or provenance metadata.
|
|
327
327
|
_deps.rmSync(path.join(staged, LOCK_FILENAME), { force: true });
|
|
328
328
|
_deps.rmSync(path.join(staged, SOURCE_METADATA_FILENAME), { force: true });
|
|
329
|
+
assertStagedRegistryCommandPayload(
|
|
330
|
+
staged,
|
|
331
|
+
opts[SOURCE_POLICY_PREFLIGHT]?.registryAuthority,
|
|
332
|
+
);
|
|
329
333
|
|
|
330
334
|
const remoteSbomPayloadComparison = buildRemoteSbomPayloadComparison({
|
|
331
335
|
remoteArtifactEvidence:
|
|
@@ -657,6 +661,19 @@ function preflightManagedSource(source, opts, action, options = {}) {
|
|
|
657
661
|
);
|
|
658
662
|
}
|
|
659
663
|
}
|
|
664
|
+
if (registryAuthority.sourceType === "command") {
|
|
665
|
+
const command = opts.sourceMetadata.catalogAuthority?.commandSource;
|
|
666
|
+
if (
|
|
667
|
+
!command ||
|
|
668
|
+
command.descriptorIdentity !== registryAuthority.declaredSource ||
|
|
669
|
+
command.payloadSha256 !== registryAuthority.payloadSha256 ||
|
|
670
|
+
command.mode !== registryAuthority.commandMode
|
|
671
|
+
) {
|
|
672
|
+
throw new Error(
|
|
673
|
+
"registry source authority does not match command source authority",
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
660
677
|
}
|
|
661
678
|
// Resolve managed identity before exists/clone/cache/process work. The
|
|
662
679
|
// manifest name is checked again by installFromDirectory after materializing
|
|
@@ -693,6 +710,7 @@ function preflightManagedSource(source, opts, action, options = {}) {
|
|
|
693
710
|
decision,
|
|
694
711
|
materialized,
|
|
695
712
|
sourceAuthority,
|
|
713
|
+
registryAuthority,
|
|
696
714
|
};
|
|
697
715
|
const boundSourceMetadata = opts.sourceMetadata
|
|
698
716
|
? bindSourcePolicyAuthority(opts.sourceMetadata, {
|
|
@@ -3638,7 +3656,16 @@ function normalizeSourceMetadata(value) {
|
|
|
3638
3656
|
value.resolvedSource,
|
|
3639
3657
|
catalogAuthority.archiveSource,
|
|
3640
3658
|
)
|
|
3641
|
-
:
|
|
3659
|
+
: catalogAuthority?.commandSource
|
|
3660
|
+
? commandSourceAuthorityDigest(
|
|
3661
|
+
value.resolvedSource,
|
|
3662
|
+
catalogAuthority.commandSource,
|
|
3663
|
+
)
|
|
3664
|
+
: pluginSourceAuthorityDigest(
|
|
3665
|
+
value.resolvedSource,
|
|
3666
|
+
"git",
|
|
3667
|
+
value.ref,
|
|
3668
|
+
)
|
|
3642
3669
|
: null);
|
|
3643
3670
|
const policyDigest = normalizeSourceAuthorityDigest(value.policyDigest);
|
|
3644
3671
|
if (resolvedSourceDigest) {
|
|
@@ -3650,6 +3677,7 @@ function normalizeSourceMetadata(value) {
|
|
|
3650
3677
|
if (catalogAuthority) metadata.catalogAuthority = catalogAuthority;
|
|
3651
3678
|
assertCatalogRemoteArtifactBindings(metadata);
|
|
3652
3679
|
assertCatalogArchiveSourceBindings(metadata);
|
|
3680
|
+
assertCatalogCommandSourceBindings(metadata);
|
|
3653
3681
|
return metadata;
|
|
3654
3682
|
}
|
|
3655
3683
|
|
|
@@ -3681,6 +3709,20 @@ function assertCatalogArchiveSourceBindings(metadata) {
|
|
|
3681
3709
|
}
|
|
3682
3710
|
}
|
|
3683
3711
|
|
|
3712
|
+
function assertCatalogCommandSourceBindings(metadata) {
|
|
3713
|
+
const command = metadata.catalogAuthority?.commandSource;
|
|
3714
|
+
if (!command) return;
|
|
3715
|
+
if (
|
|
3716
|
+
metadata.type !== "registry" ||
|
|
3717
|
+
!metadata.registry ||
|
|
3718
|
+
metadata.resolvedSource !== command.descriptorIdentity
|
|
3719
|
+
) {
|
|
3720
|
+
throw new Error(
|
|
3721
|
+
"marketplace command authority requires matching registry source metadata",
|
|
3722
|
+
);
|
|
3723
|
+
}
|
|
3724
|
+
}
|
|
3725
|
+
|
|
3684
3726
|
function normalizeSourceAuthorityDigest(value) {
|
|
3685
3727
|
const normalized = cleanBounded(value, 64)?.toLowerCase() || null;
|
|
3686
3728
|
return normalized && /^[a-f0-9]{64}$/u.test(normalized) ? normalized : null;
|
|
@@ -3718,11 +3760,28 @@ function archiveSourceAuthorityDigest(source, archive) {
|
|
|
3718
3760
|
.digest("hex");
|
|
3719
3761
|
}
|
|
3720
3762
|
|
|
3763
|
+
function commandSourceAuthorityDigest(source, command) {
|
|
3764
|
+
return crypto
|
|
3765
|
+
.createHash("sha256")
|
|
3766
|
+
.update(
|
|
3767
|
+
canonicalJson({
|
|
3768
|
+
kind: "command",
|
|
3769
|
+
descriptorIdentity: sanitizeSource(source),
|
|
3770
|
+
mode: command.mode || command.commandMode || null,
|
|
3771
|
+
payloadSha256: command.payloadSha256 || null,
|
|
3772
|
+
}),
|
|
3773
|
+
)
|
|
3774
|
+
.digest("hex");
|
|
3775
|
+
}
|
|
3776
|
+
|
|
3721
3777
|
function registryResolvedSourceAuthorityDigest(authority) {
|
|
3722
3778
|
if (!authority) return null;
|
|
3723
3779
|
if (authority.sourceType === "archive") {
|
|
3724
3780
|
return archiveSourceAuthorityDigest(authority.declaredSource, authority);
|
|
3725
3781
|
}
|
|
3782
|
+
if (authority.sourceType === "command") {
|
|
3783
|
+
return commandSourceAuthorityDigest(authority.declaredSource, authority);
|
|
3784
|
+
}
|
|
3726
3785
|
return pluginSourceAuthorityDigest(
|
|
3727
3786
|
authority.declaredSource,
|
|
3728
3787
|
"git",
|
|
@@ -4030,6 +4089,12 @@ function normalizeCatalogAuthority(value) {
|
|
|
4030
4089
|
value.remoteArtifactEvidence,
|
|
4031
4090
|
);
|
|
4032
4091
|
const archiveSource = normalizeArchiveSourceAuthority(value.archiveSource);
|
|
4092
|
+
const commandSource = normalizeCommandSourceAuthority(value.commandSource);
|
|
4093
|
+
if (archiveSource && commandSource) {
|
|
4094
|
+
throw new Error(
|
|
4095
|
+
"catalogAuthority cannot combine archive and command source authority",
|
|
4096
|
+
);
|
|
4097
|
+
}
|
|
4033
4098
|
const remoteSbomPayloadComparison = assertRemoteSbomPayloadComparison(
|
|
4034
4099
|
value.remoteSbomPayloadComparison,
|
|
4035
4100
|
{
|
|
@@ -4137,6 +4202,7 @@ function normalizeCatalogAuthority(value) {
|
|
|
4137
4202
|
...(artifactExpectations ? { artifactExpectations } : {}),
|
|
4138
4203
|
...(remoteArtifactEvidence ? { remoteArtifactEvidence } : {}),
|
|
4139
4204
|
...(archiveSource ? { archiveSource } : {}),
|
|
4205
|
+
...(commandSource ? { commandSource } : {}),
|
|
4140
4206
|
...(remoteSbomPayloadComparison ? { remoteSbomPayloadComparison } : {}),
|
|
4141
4207
|
...(publisherDeclaration ? { publisherDeclaration } : {}),
|
|
4142
4208
|
...(publisherAuthority ? { publisherAuthority } : {}),
|
|
@@ -4213,6 +4279,42 @@ function normalizeArchiveSourceAuthority(value) {
|
|
|
4213
4279
|
};
|
|
4214
4280
|
}
|
|
4215
4281
|
|
|
4282
|
+
function normalizeCommandSourceAuthority(value) {
|
|
4283
|
+
if (value == null) return null;
|
|
4284
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
4285
|
+
throw new Error("catalogAuthority.commandSource must be an object");
|
|
4286
|
+
}
|
|
4287
|
+
const descriptorIdentity = cleanBounded(value.descriptorIdentity, 128);
|
|
4288
|
+
const payloadSha256 = cleanBounded(value.payloadSha256, 64)?.toLowerCase();
|
|
4289
|
+
const mode = value.mode;
|
|
4290
|
+
const fileCount = Number(value.fileCount);
|
|
4291
|
+
const totalBytes = Number(value.totalBytes);
|
|
4292
|
+
if (
|
|
4293
|
+
value.schemaVersion !== "cc-plugin-marketplace-command-source/v1" ||
|
|
4294
|
+
value.status !== "descriptor-executed-and-verified" ||
|
|
4295
|
+
!/^command:[a-f0-9]{32}$/u.test(descriptorIdentity || "") ||
|
|
4296
|
+
!/^[a-f0-9]{64}$/u.test(payloadSha256 || "") ||
|
|
4297
|
+
!["copy", "link"].includes(mode) ||
|
|
4298
|
+
!Number.isSafeInteger(fileCount) ||
|
|
4299
|
+
fileCount <= 0 ||
|
|
4300
|
+
fileCount > 10_000 ||
|
|
4301
|
+
!Number.isSafeInteger(totalBytes) ||
|
|
4302
|
+
totalBytes <= 0 ||
|
|
4303
|
+
totalBytes > 256 * 1024 * 1024
|
|
4304
|
+
) {
|
|
4305
|
+
throw new Error("catalogAuthority.commandSource authority is invalid");
|
|
4306
|
+
}
|
|
4307
|
+
return {
|
|
4308
|
+
schemaVersion: value.schemaVersion,
|
|
4309
|
+
status: value.status,
|
|
4310
|
+
descriptorIdentity,
|
|
4311
|
+
mode,
|
|
4312
|
+
payloadSha256,
|
|
4313
|
+
fileCount,
|
|
4314
|
+
totalBytes,
|
|
4315
|
+
};
|
|
4316
|
+
}
|
|
4317
|
+
|
|
4216
4318
|
function normalizeArtifactExpectations(value) {
|
|
4217
4319
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
4218
4320
|
const digest = (candidate, label) => {
|
|
@@ -4618,6 +4720,20 @@ function writeDurableFileAtomic(directory, target, value) {
|
|
|
4618
4720
|
}
|
|
4619
4721
|
}
|
|
4620
4722
|
|
|
4723
|
+
function assertStagedRegistryCommandPayload(staged, authority) {
|
|
4724
|
+
if (authority?.sourceType !== "command") return;
|
|
4725
|
+
const payload = buildMarketplacePayloadSbom(staged);
|
|
4726
|
+
if (
|
|
4727
|
+
payload.digest !== authority.payloadSha256 ||
|
|
4728
|
+
payload.fileCount !== authority.fileCount ||
|
|
4729
|
+
payload.totalBytes !== authority.totalBytes
|
|
4730
|
+
) {
|
|
4731
|
+
throw new Error(
|
|
4732
|
+
"registry command source payload changed before immutable installation",
|
|
4733
|
+
);
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4736
|
+
|
|
4621
4737
|
/**
|
|
4622
4738
|
* Copy `src` → `dst`, refusing to write outside `root` and skipping symlinks
|
|
4623
4739
|
* (which could later resolve outside the plugin sandbox). Directories recurse.
|
|
@@ -63,7 +63,9 @@ export function ensurePluginLspServers(opts = {}) {
|
|
|
63
63
|
|
|
64
64
|
// An LSP server spawns a binary — gate it behind trust. Untrusted project
|
|
65
65
|
// plugins (e.g. from a cloned repo) don't get to launch processes silently.
|
|
66
|
-
const { trusted, skipped } = partitionByTrust(plugins
|
|
66
|
+
const { trusted, skipped } = partitionByTrust(plugins, {
|
|
67
|
+
workspaceRoot: cwd,
|
|
68
|
+
});
|
|
67
69
|
warnUntrustedOnce(
|
|
68
70
|
skipped
|
|
69
71
|
.filter((p) => (p.manifest?.components?.lsp || []).length > 0)
|
|
@@ -95,9 +97,7 @@ export function ensurePluginLspServers(opts = {}) {
|
|
|
95
97
|
pluginId: p.name,
|
|
96
98
|
pluginVersion: p.version,
|
|
97
99
|
pluginSource: s.absPath || p.manifest.manifestPath,
|
|
98
|
-
...(s.sandboxPolicy
|
|
99
|
-
? { sandboxPolicy: s.sandboxPolicy }
|
|
100
|
-
: {}),
|
|
100
|
+
...(s.sandboxPolicy ? { sandboxPolicy: s.sandboxPolicy } : {}),
|
|
101
101
|
});
|
|
102
102
|
registered.push({ plugin: p.name, languageId: s.languageId, id: s.id });
|
|
103
103
|
} catch {
|