chainlesschain 0.162.188 → 0.162.193
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 +61 -11
- package/bin/chainlesschain.js +7 -52
- package/completions/_cc +209 -0
- package/completions/cc.bash +18 -0
- package/completions/cc.fish +13 -0
- package/completions/cc.ps1 +226 -0
- package/package.json +10 -2
- package/src/assets/web-panel/assets/{AIOps-Brr1LVcE.js → AIOps-DBLkaTje.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DQU74DKG.js → ActionButton-BAy-Qebo.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CYp9178y.js → Analytics-Dfb1Mlau.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DW4SCYsW.js → AppLayout-BbFkN8m0.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CYlD_ed1.js → Artifacts-kM4-cEEH.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CWl1rZOi.js → Audit-BSQfYWf3.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BOR-LPsa.js → BackgroundAgents-CWDbI_fG.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DLpG7j1X.js → Backup-BxLPbq_Q.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-B35K9wdr.js → BaseInput-DuIbdrp6.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CwUJb9gB.js → Chat-NEmjGahU.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-1v6aMS1m.js → ChatBubbleRenderer-DfJEo-5_.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-pi3-tPNW.js → Checkbox-CaoeG3Ns.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-FyNF35eL.js → Codegen-BFf_g3xY.js} +1 -1
- package/src/assets/web-panel/assets/{Col-tGt_JDEr.js → Col-CNOd8mdQ.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CC7LonQX.js → Community-BhpDqz-i.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BGXrHHjE.js → Compact-CQ42T7Z6.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DSW0TBZ8.js → Compliance-DI5PcLMN.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-Bhk7rbvE.js → Cowork-wYYZe0wR.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DxyiQ2NZ.js → Cron-Dlq03DD_.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-B2ZkxHok.js → Crosschain-BzqS8PP3.js} +1 -1
- package/src/assets/web-panel/assets/{DID-yOJV99eJ.js → DID-It55Yem7.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CKsttz7D.js → Dashboard-9HkH6oxn.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CVFldXSL.js → Dropdown-00e2YWRB.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Bufv638J.js → EmailListRenderer-By-ugRDL.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-4ncjoIjL.js → FamilyGuardDashboard-C396yu5m.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DsknEDoX.js → Federation-BME5sbZY.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Cqe5jWXA.js → FormItemContext-B4TEZCr-.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-NAJaFKxc.js → GenericCardRenderer-_9CX9ieY.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CszKQpnl.js → Git-BrS6WVSr.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BXGodXi6.js → Governance-BMdCWnKF.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CkoYuG2c.js → Inference-Bcp3vzcA.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DFlEr_T0.js → KnowledgeGraph-DlLuqGY5.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CVaENddA.js → Logs-D-W_6x09.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-DElGPxCZ.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-CDlLT0fw.js → Marketplace-Dzn2guvI.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DdwOyszN.js → McpTools-uPict-KL.js} +6 -6
- package/src/assets/web-panel/assets/{Memory-DKQnkKuG.js → Memory-BCw43kOb.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DGseqlzJ.js → MobileBridge-DmV8Wv7F.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-COBbEOlj.js → MobileProjects-C-HaCmSM.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-O61Vwyli.js → Mtc-C6jxJ34Y.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-Dw2SyasS.js → MtcAudit-Za8ExwhQ.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-hSu_l8kf.js → Multisig-KKDbuEgb.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CX1Epurr.js → NLProgramming-Dj97zbCk.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-R9xX8o8_.js → Notes-DBXvMraU.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-jtSNLCuK.js → NotificationSettings-DOxITLYl.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-7DVjZwMM.js +1 -0
- package/src/assets/web-panel/assets/{Organization-Pu2WO-U3.js → Organization-D1i73mjb.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BjnqUyFp.js → Overflow-kW6Q3rvg.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-jjkvz44c.js → P2P-C-v_8p2v.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-tUbbY64W.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-D4yDpivd.js → Permissions-DkHxEZ58.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-0qsL6iH1.js → PersonalDataHub-DWuMPGrK.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-Cx7Ybrk2.js → Pipeline-30IYXWWm.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-PbfR_M_V.js → Privacy-DZNQ4RrH.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CyV6Gsub.js → ProjectInit-De2MCElf.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-C7KZ2Wdk.js → ProjectSettings-5uHk9wsC.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DQDjO-yK.js → Projects-XjDfrFLb.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DyFVBBMX.js → Providers-Bgwj6gcE.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CzB1BC9_.js → QrScannerModal-gKql9umv.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Bk636mC1.js → QuickAsk-BWvmwkh7.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DoWxHIT3.js → Recommend-Uok4hZPd.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-oOVIv9wq.js → RemoteSession-DLJzTk9a.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-BucoReGG.js → Reputation-ZVwIPMSO.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DzmOdJU7.js → Row-CN04HxWR.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-C1tK7KGU.js → RssFeed-BdSrEG4g.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CSnInOqk.js → Search-5PwVd0IR.js} +1 -1
- package/src/assets/web-panel/assets/{Security-dlejr15l.js → Security-DdBo4zjN.js} +3 -3
- package/src/assets/web-panel/assets/{Services-BioPZuNh.js → Services-D3letU7M.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DWMibwpC.js → Skeleton--Jb83f1v.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BAAnx1B2.js → Skills-Bg-CulHX.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-jWNp4hNO.js → Sla-7QOa7S-X.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-y5kqKha-.js → SpeechSettings-DQwppjRw.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-B9GNsc3e.js → SyncSettings-dNPQGL-s.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BDBYKRen.js → Tasks-Ggs-Z48q.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DRiE5eaN.js → Templates-78TYHgRO.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BGlAvExF.js → Tenant-xHwwv9vO.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B8uzrbNY.js → Terminal-BJXSJfm4.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-Df48iveY.js → TimelineRenderer-fLbjRhJw.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CcmHndN6.js → Tokens-oMSBSBmB.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DPkWxmQ2.js → Trigger-CfnY_wX_.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DTb5a5AV.js → Trust-AdyTgYKO.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CBmg5vch.js → UkeySign-C5K_81dS.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-B0mZrz4O.js → VideoEditing-vcGVDqki.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Bxs7_mpd.js → Wallet-hhOc3hlY.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-C8x3cMxU.js → WebAuthn-CVloC11s.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-DPrNznrP.js → WorkflowEditor-CYeE32R5.js} +1 -1
- package/src/assets/web-panel/assets/{chat-D3bYWu7S.js → chat-CNROR5bN.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DY-PwMu4.js → colors-Cjx-cnwU.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-LDk10Kw6.js → compact-item-DOIfelvD.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-C-2MZnFq.js → createContext-DfA7UZ8u.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-ChcCBGs7.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BQIBjcnB.js → hasIn-BMSCzcfM.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQVb2dWp.js → index-5-HXgOX5.js} +1 -1
- package/src/assets/web-panel/assets/{index-BdXnYMCZ.js → index-AWg-0M1S.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cx6D_dx2.js → index-B4iYzpkL.js} +1 -1
- package/src/assets/web-panel/assets/{index-_HRO_cIu.js → index-B5Udeb_6.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlRYqt3S.js → index-B7gf77CJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BrnRO9yE.js → index-BEMwBBHk.js} +1 -1
- package/src/assets/web-panel/assets/{index-VCh5zNJo.js → index-BM1y_9hM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRI3ngNg.js → index-BUonmKSE.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3GNvExG.js → index-BbQ2eQ8H.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSvo_bp0.js → index-BemJ2u_E.js} +1 -1
- package/src/assets/web-panel/assets/{index-L6qixyLc.js → index-BolaOQxx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BI4KgcYC.js → index-BxOk9vkG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CY4KnaO9.js → index-By61ojUx.js} +1 -1
- package/src/assets/web-panel/assets/{index-L3smcoQX.js → index-C2K9SNVX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BX2b9Orc.js → index-C3L5gdiD.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cz4b6Z_7.js → index-C7xn0Nub.js} +1 -1
- package/src/assets/web-panel/assets/{index-COG61sRv.js → index-CAnvhwg6.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7FC8cP2.js → index-CEKMcOyU.js} +1 -1
- package/src/assets/web-panel/assets/{index-BN-xdSWZ.js → index-CNC5onm4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DY2FIrmz.js → index-CVL27kXC.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiTvBAr-.js → index-CVm1_i3t.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhRt9cYJ.js → index-CdYBye8B.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5pgtZnY.js → index-ClNMrqEY.js} +1 -1
- package/src/assets/web-panel/assets/{index-7xKu7Fns.js → index-Cs6l7uRu.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4K1weKc.js → index-CshQbilz.js} +1 -1
- package/src/assets/web-panel/assets/{index-k7C_oDCO.js → index-Cyweh0Hy.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3Oq-DLL.js → index-DBpWXFed.js} +3 -3
- package/src/assets/web-panel/assets/{index-DYyLJPlF.js → index-DHtpHZAQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dh-tkpKQ.js → index-DLmn0BoK.js} +1 -1
- package/src/assets/web-panel/assets/{index-8JC9BJa1.js → index-DPAWBrMf.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dd2Km97U.js → index-DjEsxO5h.js} +1 -1
- package/src/assets/web-panel/assets/{index-KFZO_lcx.js → index-FBc_CJBd.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTIZpPtG.js → index-Icdoqmzt.js} +1 -1
- package/src/assets/web-panel/assets/index-Q2IajL54.js +1 -0
- package/src/assets/web-panel/assets/index-bRkHgOMc.js +1 -0
- package/src/assets/web-panel/assets/{index-lmm9p-jm.js → index-dCd8cSUq.js} +1 -1
- package/src/assets/web-panel/assets/{index-HasPt4-h.js → index-m2vG9gG_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaslYch6.js → index-mTpHoEzr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbR6ROOa.js → index-ti_lnTWl.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-zQPSHf2C.js → initDefaultProps-Bu8k7H1Y.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CKCStGVk.js → motion-s3iVK41k.js} +1 -1
- package/src/assets/web-panel/assets/{move-BufVDGYF.js → move-B6B-E5Jz.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DcaFxy5D.js → mtc-parser-BiYgTidA.js} +1 -1
- package/src/assets/web-panel/assets/{omit-EScpkGdo.js → omit-pU1RdUDA.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-72hG_qfT.js → pickAttrs-Cdoq_SeM.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CMFWiH20.js → placementArrow-DIuvAn2K.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DKQHS41p.js → responsiveObserve-8w16YR2D.js} +1 -1
- package/src/assets/web-panel/assets/{slide-QVAFHTIQ.js → slide-VZ01cZe3.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DIz38e2G.js → statusUtils-lh8YMN8Z.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-zK5cyLby.js → styleChecker-CmDyreec.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DhZngk62.js → useFlexGapSupport-hiJWMU5y.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BvV2cvkg.js → useFs-Thnu-Iaj.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CRmxb9l3.js → usePersonalDataHub-LBdOxjwY.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CgQIbobP.js → vnode-Cg6lFY_X.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-D4XrrO0R.js → zoom-DVfsR1YO.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/cli-help.js +181 -0
- package/src/command-help-index.json +181 -0
- package/src/command-manifest.json +1107 -175
- package/src/command-surface-policy.js +197 -0
- package/src/commands/agent.js +98 -33
- package/src/commands/artifacts.js +400 -2
- package/src/commands/background-session.js +41 -3
- package/src/commands/checkpoint-managed.js +1059 -0
- package/src/commands/checkpoint-restore-recovery.js +1476 -0
- package/src/commands/checkpoint.js +950 -22
- package/src/commands/compact.js +101 -25
- package/src/commands/config.js +506 -20
- package/src/commands/doctor.js +4 -1
- package/src/commands/hub.js +1 -1
- package/src/commands/mcp.js +688 -24
- package/src/commands/pack.js +16 -2
- package/src/commands/plugin.js +20 -12
- package/src/commands/session-mcp-recovery.js +218 -0
- package/src/commands/session.js +470 -110
- package/src/commands/setup.js +36 -10
- package/src/commands/skill.js +181 -110
- package/src/commands/status.js +21 -5
- package/src/commands/team-distributed.js +3324 -0
- package/src/commands/team.js +1130 -74
- package/src/commands/update.js +68 -6
- package/src/constants.js +11 -0
- package/src/data/changelog.json +26 -0
- package/src/gateways/ws/action-protocol.js +10 -0
- package/src/gateways/ws/session-protocol.js +555 -27
- package/src/gateways/ws/ws-agent-handler.js +541 -14
- package/src/gateways/ws/ws-session-gateway.js +129 -22
- package/src/gateways/ws/ws-session-state.js +431 -0
- package/src/harness/background-task-manager.js +233 -36
- package/src/harness/jsonl-session-store.js +2551 -167
- package/src/harness/mcp-client.js +802 -61
- package/src/harness/prompt-compressor.js +227 -27
- package/src/harness/session-index.js +89 -38
- package/src/harness/session-list-index.js +254 -0
- package/src/harness/structured-handoff.js +410 -0
- package/src/lazy-dispatch.js +747 -84
- package/src/lib/__tests__/logger.test.js +50 -2
- package/src/lib/advisor-runtime.js +1047 -0
- package/src/lib/agent-core.js +2 -0
- package/src/lib/agent-sandbox.js +120 -26
- package/src/lib/agent-session-export.js +20 -0
- package/src/lib/agent-team/task-lease.js +271 -3
- package/src/lib/agent-team/team-adjudication.js +1501 -0
- package/src/lib/agent-team/team-budget.js +4 -1
- package/src/lib/agent-team/team-control-store.js +582 -0
- package/src/lib/agent-team/team-distributed-queue.js +5246 -0
- package/src/lib/agent-team/team-process-checkpoint.js +211 -0
- package/src/lib/agent-team/team-runner.js +543 -24
- package/src/lib/agent-team/team-worktree.js +1403 -95
- package/src/lib/artifact-store.js +131 -8
- package/src/lib/background-agent-supervisor.js +185 -13
- package/src/lib/background-interaction-journal.js +37 -9
- package/src/lib/background-launch-profile.js +1058 -0
- package/src/lib/checkpoint-restore-already-completed-controller.js +902 -0
- package/src/lib/checkpoint-restore-orchestrator.js +987 -0
- package/src/lib/checkpoint-restore-partial-rollback-controller.js +1953 -0
- package/src/lib/checkpoint-restore-recovery-controller.js +689 -0
- package/src/lib/checkpoint-restore-recovery.js +884 -0
- package/src/lib/checkpoint-restore-retention.js +126 -0
- package/src/lib/checkpoint-restore-saga.js +5079 -0
- package/src/lib/checkpoint-restore-session-recovery.js +1178 -0
- package/src/lib/checkpoint-restore-workspace-target-verifier.js +270 -0
- package/src/lib/checkpoint-store.js +1688 -97
- package/src/lib/checkpoint-timeline-authority.js +522 -0
- package/src/lib/checkpoint-timeline.js +642 -0
- package/src/lib/config-keys.js +18 -119
- package/src/lib/config-manager.js +446 -27
- package/src/lib/config-redaction.js +57 -0
- package/src/lib/config-schema.js +853 -0
- package/src/lib/cowork-mcp-tools.js +5 -0
- package/src/lib/cowork-task-runner.js +458 -63
- package/src/lib/delivery-coordinator.js +1234 -0
- package/src/lib/delivery-evidence.js +450 -0
- package/src/lib/doctor-checkup.js +199 -14
- package/src/lib/executable-path.js +34 -0
- package/src/lib/fatal-handler.js +16 -0
- package/src/lib/file-checkpoint.js +4909 -186
- package/src/lib/file-lines.js +125 -0
- package/src/lib/headless-config-command.js +16 -5
- package/src/lib/hook-runner.cjs +139 -38
- package/src/lib/hooks-v2-workspace-context.js +10 -0
- package/src/lib/impacted-gate-selector.js +424 -0
- package/src/lib/interaction-adapter.js +62 -0
- package/src/lib/jsonl-session-store.js +1 -35
- package/src/lib/logger.js +66 -14
- package/src/lib/managed-checkpoint-render.js +60 -0
- package/src/lib/managed-tool-checkpoint.js +194 -0
- package/src/lib/mcp-call-ledger-store.js +1069 -0
- package/src/lib/mcp-call-ledger.js +747 -0
- package/src/lib/mcp-client.js +5 -0
- package/src/lib/mcp-conflict-scheduler.js +468 -0
- package/src/lib/mcp-effect-contract.js +102 -0
- package/src/lib/mcp-headers-helper-trust.js +145 -0
- package/src/lib/mcp-headers-helper.js +616 -0
- package/src/lib/mcp-host-recovery-runtime.js +131 -0
- package/src/lib/mcp-ledger-recovery-admission.js +1065 -0
- package/src/lib/mcp-recovery-adjudication.js +443 -0
- package/src/lib/output-context.js +86 -0
- package/src/lib/packer/file-identity.js +170 -0
- package/src/lib/packer/index.js +3 -0
- package/src/lib/packer/native-update-state.js +277 -0
- package/src/lib/packer/pack-update-applier.js +1983 -136
- package/src/lib/packer/pack-update-checker.js +34 -0
- package/src/lib/packer/pack-update-downloader.js +875 -86
- package/src/lib/packer/pack-update-signature.js +86 -0
- package/src/lib/packer/pkg-config-generator.js +6 -0
- package/src/lib/paths.js +65 -10
- package/src/lib/plan-mode.js +831 -14
- package/src/lib/plan-persistence.js +540 -0
- package/src/lib/plugin-runtime/hooks.js +227 -69
- package/src/lib/plugin-runtime/plugin-options.js +189 -44
- package/src/lib/pr-automation-policy.js +146 -8
- package/src/lib/process-execution-broker/credential-agent.js +7 -0
- package/src/lib/process-execution-broker/index.js +491 -13
- package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +28 -1
- package/src/lib/process-execution-broker/linux-generic-bwrap.js +28 -4
- package/src/lib/process-execution-broker/platform-sandbox.js +92 -70
- 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 +284 -19
- package/src/lib/process-execution-broker/workspace-transaction.js +4459 -0
- package/src/lib/project-instructions.js +165 -29
- package/src/lib/project-mcp-trust.js +67 -0
- package/src/lib/public-ide-capability-manifest.js +272 -0
- package/src/lib/public-ide-capability-validation.js +351 -0
- package/src/lib/secret-store.js +267 -43
- package/src/lib/secure-file-identity.js +433 -0
- package/src/lib/secure-fs.js +1089 -0
- package/src/lib/security-audit.js +58 -0
- package/src/lib/service-manager.js +34 -13
- package/src/lib/session-budget-runtime.js +1452 -0
- package/src/lib/session-host-snapshot.js +388 -0
- package/src/lib/session-message-provenance.js +429 -0
- package/src/lib/session-projection.js +804 -0
- package/src/lib/session-resource-budget.js +1495 -0
- package/src/lib/settings-hooks.cjs +138 -22
- package/src/lib/settings-loader.cjs +25 -2
- package/src/lib/side-effect-ledger-store.js +45 -23
- package/src/lib/skill-execution-identity.js +217 -0
- package/src/lib/skill-loader.js +299 -18
- package/src/lib/sub-agent-context.js +236 -28
- package/src/lib/sub-agent-registry.js +5 -0
- package/src/lib/subagent-contract.js +94 -0
- package/src/lib/todo-manager.js +185 -18
- package/src/lib/todo-persistence.js +417 -0
- package/src/lib/turn-binding-store.js +41 -23
- package/src/lib/turn-binding.js +160 -2
- package/src/lib/with-file-lock.js +165 -24
- package/src/lib/ws-chat-handler.js +21 -0
- package/src/program-base.js +18 -0
- package/src/repl/advisor-command.js +103 -0
- package/src/repl/agent-repl.js +2175 -146
- package/src/repl/btw-command.js +93 -10
- package/src/repl/clipboard-image.js +119 -0
- package/src/repl/config-summary.js +64 -108
- package/src/repl/prompt-editor.js +233 -0
- package/src/repl/prompt-interactions.js +344 -0
- package/src/repl/prompt-stash.js +354 -0
- package/src/repl/prompt-suggestions.js +312 -0
- package/src/repl/repl-keybindings.js +227 -0
- package/src/repl/session-recap.js +217 -0
- package/src/repl/slash-command-registry.js +22 -0
- package/src/repl/terminal-layout.js +88 -0
- package/src/runtime/agent-core.js +1630 -447
- package/src/runtime/coding-agent-contract-shared.cjs +13 -1
- package/src/runtime/coding-agent-managed-tool-policy.cjs +7 -2
- package/src/runtime/diagnostics.js +32 -13
- package/src/runtime/headless-runner.js +310 -118
- package/src/runtime/headless-stream.js +356 -95
- package/src/runtime/mcp-config.js +148 -14
- package/src/runtime/policies/agent-policy.js +14 -0
- package/src/runtime/status-diagnostics-lite.js +137 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-7iWGwZ-r.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BU2Yqq5H.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-69ca_WeR.js +0 -7
- package/src/assets/web-panel/assets/devWarning-B4dXIJqD.js +0 -1
- package/src/assets/web-panel/assets/index-C-C7DaG6.js +0 -1
- package/src/assets/web-panel/assets/index-DkfWzWtd.js +0 -1
|
@@ -14,13 +14,140 @@
|
|
|
14
14
|
* through the existing hook-runner (which applies the project-hook trust model).
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import crypto from "node:crypto";
|
|
17
18
|
import fs from "fs";
|
|
19
|
+
import path from "node:path";
|
|
18
20
|
import { discoverPlugins } from "./scopes.js";
|
|
19
21
|
import { partitionByTrust, warnUntrustedOnce } from "./trust.js";
|
|
20
22
|
import { componentCapabilityDenial } from "./capabilities.js";
|
|
21
23
|
import { mergePluginSandboxPolicies } from "./sandbox-policy.js";
|
|
22
24
|
|
|
23
|
-
export const _deps = {
|
|
25
|
+
export const _deps = {
|
|
26
|
+
discoverPlugins,
|
|
27
|
+
readFileSync: fs.readFileSync,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function sha256Content(content) {
|
|
31
|
+
return crypto.createHash("sha256").update(String(content)).digest("hex");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function pluginAuthorityError({
|
|
35
|
+
code,
|
|
36
|
+
error,
|
|
37
|
+
plugin = null,
|
|
38
|
+
sourceFile = null,
|
|
39
|
+
digest = null,
|
|
40
|
+
stage,
|
|
41
|
+
}) {
|
|
42
|
+
return Object.freeze({
|
|
43
|
+
code,
|
|
44
|
+
kind: "plugin",
|
|
45
|
+
authorityBearing: true,
|
|
46
|
+
pluginId: plugin?.name || null,
|
|
47
|
+
pluginVersion: plugin?.version || null,
|
|
48
|
+
sourceFile:
|
|
49
|
+
typeof sourceFile === "string" && sourceFile
|
|
50
|
+
? path.resolve(sourceFile)
|
|
51
|
+
: null,
|
|
52
|
+
digest: typeof digest === "string" && digest ? digest : null,
|
|
53
|
+
stage,
|
|
54
|
+
message: error?.message || String(error || code),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function normalizedAuthorityErrors(errors) {
|
|
59
|
+
return Object.freeze(
|
|
60
|
+
(Array.isArray(errors) ? errors : []).map((entry) =>
|
|
61
|
+
Object.freeze({ ...(entry || {}) }),
|
|
62
|
+
),
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function attachAuthorityErrors(target, errors) {
|
|
67
|
+
Object.defineProperty(target, "_authorityErrors", {
|
|
68
|
+
value: normalizedAuthorityErrors(errors),
|
|
69
|
+
enumerable: false,
|
|
70
|
+
writable: false,
|
|
71
|
+
configurable: false,
|
|
72
|
+
});
|
|
73
|
+
return target;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function attachPluginAuthoritySource(target, { sourceFile, digest }) {
|
|
77
|
+
Object.defineProperty(target, "authoritySource", {
|
|
78
|
+
value: Object.freeze({
|
|
79
|
+
kind: "plugin",
|
|
80
|
+
sourceFile: path.resolve(sourceFile),
|
|
81
|
+
digest,
|
|
82
|
+
}),
|
|
83
|
+
enumerable: true,
|
|
84
|
+
writable: false,
|
|
85
|
+
configurable: false,
|
|
86
|
+
});
|
|
87
|
+
return target;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function loadPluginHookSource(plugin, component, authorityErrors) {
|
|
91
|
+
const sourceFile = component.absPath
|
|
92
|
+
? component.absPath
|
|
93
|
+
: component.inline
|
|
94
|
+
? plugin.manifest?.manifestPath
|
|
95
|
+
: null;
|
|
96
|
+
if (!sourceFile) {
|
|
97
|
+
authorityErrors.push(
|
|
98
|
+
pluginAuthorityError({
|
|
99
|
+
code: "CC_PLUGIN_HOOK_READ_FAILED",
|
|
100
|
+
error: new Error("plugin hook source is missing"),
|
|
101
|
+
plugin,
|
|
102
|
+
sourceFile: plugin.manifest?.manifestPath || null,
|
|
103
|
+
stage: "read",
|
|
104
|
+
}),
|
|
105
|
+
);
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let raw;
|
|
110
|
+
try {
|
|
111
|
+
raw = _deps.readFileSync(sourceFile, "utf8");
|
|
112
|
+
} catch (error) {
|
|
113
|
+
authorityErrors.push(
|
|
114
|
+
pluginAuthorityError({
|
|
115
|
+
code: "CC_PLUGIN_HOOK_READ_FAILED",
|
|
116
|
+
error,
|
|
117
|
+
plugin,
|
|
118
|
+
sourceFile,
|
|
119
|
+
stage: "read",
|
|
120
|
+
}),
|
|
121
|
+
);
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const digest = sha256Content(raw);
|
|
126
|
+
try {
|
|
127
|
+
const parsed = JSON.parse(raw);
|
|
128
|
+
return {
|
|
129
|
+
parsed: component.inline
|
|
130
|
+
? parsed && typeof parsed === "object"
|
|
131
|
+
? parsed.hooks
|
|
132
|
+
: null
|
|
133
|
+
: parsed,
|
|
134
|
+
sourceFile,
|
|
135
|
+
digest,
|
|
136
|
+
};
|
|
137
|
+
} catch (error) {
|
|
138
|
+
authorityErrors.push(
|
|
139
|
+
pluginAuthorityError({
|
|
140
|
+
code: "CC_PLUGIN_HOOK_PARSE_FAILED",
|
|
141
|
+
error,
|
|
142
|
+
plugin,
|
|
143
|
+
sourceFile,
|
|
144
|
+
digest,
|
|
145
|
+
stage: "parse",
|
|
146
|
+
}),
|
|
147
|
+
);
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
24
151
|
|
|
25
152
|
// One-time stderr notice when a plugin's hooks are refused at the COMPONENT
|
|
26
153
|
// level because the plugin opted into the capability model but did not declare
|
|
@@ -71,11 +198,20 @@ function normalizeHookMap(parsed) {
|
|
|
71
198
|
* @returns {Record<string, Array>} event name → concatenated hook entries
|
|
72
199
|
*/
|
|
73
200
|
export function collectPluginHooks(opts = {}) {
|
|
201
|
+
const merged = {};
|
|
202
|
+
const authorityErrors = [];
|
|
74
203
|
let plugins = [];
|
|
75
204
|
try {
|
|
76
|
-
plugins = discoverPlugins({ cwd: opts.cwd, scopes: opts.scopes });
|
|
77
|
-
} catch {
|
|
78
|
-
|
|
205
|
+
plugins = _deps.discoverPlugins({ cwd: opts.cwd, scopes: opts.scopes });
|
|
206
|
+
} catch (error) {
|
|
207
|
+
authorityErrors.push(
|
|
208
|
+
pluginAuthorityError({
|
|
209
|
+
code: "CC_PLUGIN_HOOK_DISCOVERY_FAILED",
|
|
210
|
+
error,
|
|
211
|
+
stage: "discover",
|
|
212
|
+
}),
|
|
213
|
+
);
|
|
214
|
+
return attachAuthorityErrors(merged, authorityErrors);
|
|
79
215
|
}
|
|
80
216
|
// A hook runs a shell command — gate it behind trust so a cloned repo's
|
|
81
217
|
// project plugin can't run commands the moment the agent starts.
|
|
@@ -84,7 +220,6 @@ export function collectPluginHooks(opts = {}) {
|
|
|
84
220
|
skipped.filter((p) => p.manifest?.components?.hooks).map((p) => p.name),
|
|
85
221
|
"hooks",
|
|
86
222
|
);
|
|
87
|
-
const merged = {};
|
|
88
223
|
const denied = [];
|
|
89
224
|
for (const p of trusted) {
|
|
90
225
|
if (!p.manifest || p.manifest.ok !== true) continue;
|
|
@@ -98,75 +233,92 @@ export function collectPluginHooks(opts = {}) {
|
|
|
98
233
|
denied.push({ name: p.name, reason: denial.reason });
|
|
99
234
|
continue;
|
|
100
235
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
} else if (h.inline) {
|
|
109
|
-
// Hooks declared inline in plugin.json — the normalized component keeps
|
|
110
|
-
// only counts, so re-read the raw manifest for the actual entries (same
|
|
111
|
-
// approach as the MCP collector). Without this, inline hooks never fire.
|
|
112
|
-
try {
|
|
113
|
-
const raw = JSON.parse(
|
|
114
|
-
_deps.readFileSync(p.manifest.manifestPath, "utf8"),
|
|
115
|
-
);
|
|
116
|
-
parsed = raw && typeof raw === "object" ? raw.hooks : null;
|
|
117
|
-
} catch {
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
} else {
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
const map = normalizeHookMap(parsed);
|
|
236
|
+
// Inline declarations are re-read from the manifest because discovery's
|
|
237
|
+
// normalized component retains only counts. Both source forms bind every
|
|
238
|
+
// executable hook to the exact bytes that authorized it.
|
|
239
|
+
const source = loadPluginHookSource(p, h, authorityErrors);
|
|
240
|
+
if (!source) continue;
|
|
241
|
+
const map = normalizeHookMap(source.parsed);
|
|
124
242
|
for (const [event, entries] of Object.entries(map)) {
|
|
125
243
|
if (!Array.isArray(entries)) continue;
|
|
126
|
-
const tagged = entries
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
244
|
+
const tagged = entries
|
|
245
|
+
.map((group) => {
|
|
246
|
+
if (
|
|
247
|
+
!group ||
|
|
248
|
+
typeof group !== "object" ||
|
|
249
|
+
!Array.isArray(group.hooks)
|
|
250
|
+
) {
|
|
251
|
+
return group;
|
|
252
|
+
}
|
|
253
|
+
let groupSandboxPolicy;
|
|
254
|
+
try {
|
|
255
|
+
groupSandboxPolicy = mergePluginSandboxPolicies(
|
|
256
|
+
p.manifest.sandboxPolicy,
|
|
257
|
+
group.sandboxPolicy,
|
|
258
|
+
);
|
|
259
|
+
} catch (error) {
|
|
260
|
+
authorityErrors.push(
|
|
261
|
+
pluginAuthorityError({
|
|
262
|
+
code: "CC_PLUGIN_HOOK_SANDBOX_INVALID",
|
|
263
|
+
error,
|
|
264
|
+
plugin: p,
|
|
265
|
+
sourceFile: source.sourceFile,
|
|
266
|
+
digest: source.digest,
|
|
267
|
+
stage: "sandbox-policy",
|
|
268
|
+
}),
|
|
269
|
+
);
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
const groupConfig = { ...group };
|
|
273
|
+
delete groupConfig.sandboxPolicy;
|
|
274
|
+
return {
|
|
275
|
+
...groupConfig,
|
|
276
|
+
hooks: group.hooks
|
|
277
|
+
.map((hook) => {
|
|
278
|
+
if (!hook || typeof hook !== "object") return hook;
|
|
279
|
+
let sandboxPolicy;
|
|
280
|
+
try {
|
|
281
|
+
sandboxPolicy = mergePluginSandboxPolicies(
|
|
282
|
+
groupSandboxPolicy,
|
|
283
|
+
hook.sandboxPolicy,
|
|
284
|
+
);
|
|
285
|
+
} catch (error) {
|
|
286
|
+
authorityErrors.push(
|
|
287
|
+
pluginAuthorityError({
|
|
288
|
+
code: "CC_PLUGIN_HOOK_SANDBOX_INVALID",
|
|
289
|
+
error,
|
|
290
|
+
plugin: p,
|
|
291
|
+
sourceFile: source.sourceFile,
|
|
292
|
+
digest: source.digest,
|
|
293
|
+
stage: "sandbox-policy",
|
|
294
|
+
}),
|
|
295
|
+
);
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
const hookConfig = { ...hook };
|
|
299
|
+
delete hookConfig.sandboxPolicy;
|
|
300
|
+
delete hookConfig.authoritySource;
|
|
301
|
+
return attachPluginAuthoritySource(
|
|
302
|
+
{
|
|
303
|
+
...hookConfig,
|
|
304
|
+
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
305
|
+
origin: "plugin:hook",
|
|
306
|
+
pluginId: p.name,
|
|
307
|
+
pluginVersion: p.version || null,
|
|
308
|
+
pluginSource: p.manifest?.manifestPath || null,
|
|
309
|
+
},
|
|
310
|
+
source,
|
|
148
311
|
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
...hookConfig,
|
|
155
|
-
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
156
|
-
origin: "plugin:hook",
|
|
157
|
-
pluginId: p.name,
|
|
158
|
-
pluginVersion: p.version || null,
|
|
159
|
-
pluginSource: p.manifest?.manifestPath || null,
|
|
160
|
-
};
|
|
161
|
-
})
|
|
162
|
-
.filter(Boolean),
|
|
163
|
-
};
|
|
164
|
-
}).filter(Boolean);
|
|
312
|
+
})
|
|
313
|
+
.filter(Boolean),
|
|
314
|
+
};
|
|
315
|
+
})
|
|
316
|
+
.filter(Boolean);
|
|
165
317
|
merged[event] = (merged[event] || []).concat(tagged);
|
|
166
318
|
}
|
|
167
319
|
}
|
|
168
320
|
warnHookCapabilityDeniedOnce(denied);
|
|
169
|
-
return merged;
|
|
321
|
+
return attachAuthorityErrors(merged, authorityErrors);
|
|
170
322
|
}
|
|
171
323
|
|
|
172
324
|
/**
|
|
@@ -179,7 +331,10 @@ export function collectPluginHooks(opts = {}) {
|
|
|
179
331
|
export function mergePluginHooks(settingsHooks, opts = {}) {
|
|
180
332
|
const plugin = collectPluginHooks(opts);
|
|
181
333
|
const events = Object.keys(plugin);
|
|
182
|
-
|
|
334
|
+
const pluginAuthorityErrors = plugin._authorityErrors || [];
|
|
335
|
+
if (events.length === 0 && pluginAuthorityErrors.length === 0) {
|
|
336
|
+
return settingsHooks;
|
|
337
|
+
}
|
|
183
338
|
const out =
|
|
184
339
|
settingsHooks && typeof settingsHooks === "object"
|
|
185
340
|
? { ...settingsHooks }
|
|
@@ -189,5 +344,8 @@ export function mergePluginHooks(settingsHooks, opts = {}) {
|
|
|
189
344
|
plugin[event],
|
|
190
345
|
);
|
|
191
346
|
}
|
|
192
|
-
return out
|
|
347
|
+
return attachAuthorityErrors(out, [
|
|
348
|
+
...(settingsHooks?._authorityErrors || []),
|
|
349
|
+
...pluginAuthorityErrors,
|
|
350
|
+
]);
|
|
193
351
|
}
|
|
@@ -27,11 +27,7 @@ import {
|
|
|
27
27
|
validateOptions,
|
|
28
28
|
redactSensitiveOptions,
|
|
29
29
|
} from "./capabilities.js";
|
|
30
|
-
import {
|
|
31
|
-
createSecretStore,
|
|
32
|
-
isSecretRef,
|
|
33
|
-
secretRef,
|
|
34
|
-
} from "../secret-store.js";
|
|
30
|
+
import { createSecretStore, isSecretRef, secretRef } from "../secret-store.js";
|
|
35
31
|
import { withFileLock } from "../with-file-lock.js";
|
|
36
32
|
|
|
37
33
|
export const _deps = {
|
|
@@ -91,6 +87,69 @@ function withOptionStoreLock(p, body) {
|
|
|
91
87
|
return _deps.withFileLock(p, body, { failIfUnavailable: true });
|
|
92
88
|
}
|
|
93
89
|
|
|
90
|
+
function hashSecretNamespace(value, length = 64) {
|
|
91
|
+
return crypto
|
|
92
|
+
.createHash("sha256")
|
|
93
|
+
.update(String(value))
|
|
94
|
+
.digest("hex")
|
|
95
|
+
.slice(0, length);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function normalizedStoreIdentity(storePath) {
|
|
99
|
+
const resolved = path.resolve(String(storePath));
|
|
100
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function pluginSecretRefPrefix(storePath, name, key) {
|
|
104
|
+
const storeNamespace = hashSecretNamespace(
|
|
105
|
+
normalizedStoreIdentity(storePath),
|
|
106
|
+
24,
|
|
107
|
+
);
|
|
108
|
+
const optionNamespace = hashSecretNamespace(
|
|
109
|
+
JSON.stringify([String(name), String(key)]),
|
|
110
|
+
);
|
|
111
|
+
return `plugin-options/${storeNamespace}/${optionNamespace}/`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function createPluginSecretRef(storePath, name, key) {
|
|
115
|
+
return `${pluginSecretRefPrefix(storePath, name, key)}${crypto.randomUUID()}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function isOwnedPluginSecretRef(ref, storePath, name, key) {
|
|
119
|
+
if (typeof ref !== "string") return false;
|
|
120
|
+
return (
|
|
121
|
+
ref === `${name}/${key}` ||
|
|
122
|
+
ref.startsWith(pluginSecretRefPrefix(storePath, name, key))
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function collectSecretRefs(value, refs = new Set()) {
|
|
127
|
+
if (isSecretRef(value)) {
|
|
128
|
+
refs.add(value.__cc_secret_ref);
|
|
129
|
+
return refs;
|
|
130
|
+
}
|
|
131
|
+
if (Array.isArray(value)) {
|
|
132
|
+
for (const entry of value) collectSecretRefs(entry, refs);
|
|
133
|
+
return refs;
|
|
134
|
+
}
|
|
135
|
+
if (value && typeof value === "object") {
|
|
136
|
+
for (const child of Object.values(value)) collectSecretRefs(child, refs);
|
|
137
|
+
}
|
|
138
|
+
return refs;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function deleteSecretRefsBestEffort(store, refs) {
|
|
142
|
+
if (!store || typeof store.delete !== "function") return;
|
|
143
|
+
for (const ref of refs) {
|
|
144
|
+
try {
|
|
145
|
+
store.delete(ref);
|
|
146
|
+
} catch {
|
|
147
|
+
// Metadata is authoritative. A stale keychain entry is preferable to
|
|
148
|
+
// rolling back a successfully committed plugin option document.
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
94
153
|
/** Load a plugin's option VALUES at the given scope (`user` | `project`). */
|
|
95
154
|
export function loadPluginOptionValues(
|
|
96
155
|
name,
|
|
@@ -121,66 +180,152 @@ export function loadPluginOptionValues(
|
|
|
121
180
|
return out;
|
|
122
181
|
}
|
|
123
182
|
|
|
124
|
-
|
|
125
|
-
|
|
183
|
+
function persistPluginOptionValuesLocked(
|
|
184
|
+
p,
|
|
126
185
|
name,
|
|
127
186
|
values,
|
|
128
187
|
scope,
|
|
129
|
-
{
|
|
188
|
+
{ store, schema, secretStore, touchedKeys = null },
|
|
130
189
|
) {
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
190
|
+
const previous =
|
|
191
|
+
store[name] &&
|
|
192
|
+
typeof store[name] === "object" &&
|
|
193
|
+
!Array.isArray(store[name])
|
|
194
|
+
? store[name]
|
|
195
|
+
: {};
|
|
196
|
+
const input = values && typeof values === "object" ? values : {};
|
|
197
|
+
const persisted = { ...input };
|
|
198
|
+
const normalized = schema || {};
|
|
199
|
+
let secrets = null;
|
|
200
|
+
const getSecrets = () => {
|
|
201
|
+
if (!secrets) secrets = (secretStore || _deps.secretStore)();
|
|
202
|
+
return secrets;
|
|
203
|
+
};
|
|
204
|
+
const rejectedSensitive = [];
|
|
205
|
+
const stagedSecretRefs = [];
|
|
206
|
+
const replacedSecretRefs = new Set();
|
|
207
|
+
try {
|
|
144
208
|
for (const [key, desc] of Object.entries(normalized)) {
|
|
145
|
-
if (
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
// Project files are shareable and must never
|
|
209
|
+
if (!desc?.sensitive) continue;
|
|
210
|
+
const hasInput = Object.prototype.hasOwnProperty.call(input, key);
|
|
211
|
+
const previousRef = isSecretRef(previous[key])
|
|
212
|
+
? previous[key].__cc_secret_ref
|
|
213
|
+
: null;
|
|
214
|
+
|
|
215
|
+
// Project files are shareable and must never retain a sensitive value.
|
|
216
|
+
// This gate also sanitizes an existing invalid value during an unrelated
|
|
217
|
+
// patch, so patching cannot accidentally preserve project-scope secrets.
|
|
152
218
|
if (scope === "project") {
|
|
153
|
-
|
|
154
|
-
|
|
219
|
+
if (hasInput) {
|
|
220
|
+
delete persisted[key];
|
|
221
|
+
rejectedSensitive.push(key);
|
|
222
|
+
}
|
|
155
223
|
continue;
|
|
156
224
|
}
|
|
157
|
-
|
|
225
|
+
|
|
226
|
+
// A patch leaves untouched secret references byte-for-byte. Only keys in
|
|
227
|
+
// the patch participate in the secret-store transaction.
|
|
228
|
+
if (touchedKeys && !touchedKeys.has(key)) continue;
|
|
229
|
+
|
|
230
|
+
if (!hasInput || input[key] == null || input[key] === "") {
|
|
158
231
|
delete persisted[key];
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
232
|
+
} else {
|
|
233
|
+
// Every write gets a new immutable reference. Namespaces are hashes of
|
|
234
|
+
// the option-store path and the unambiguous [plugin, key] tuple, so
|
|
235
|
+
// names containing '/' cannot collide with another plugin/key pair.
|
|
236
|
+
const ref = createPluginSecretRef(p, name, key);
|
|
237
|
+
stagedSecretRefs.push(ref);
|
|
238
|
+
getSecrets().set(ref, input[key]);
|
|
239
|
+
persisted[key] = secretRef(ref);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (previousRef && isOwnedPluginSecretRef(previousRef, p, name, key)) {
|
|
243
|
+
replacedSecretRefs.add(previousRef);
|
|
165
244
|
}
|
|
166
|
-
getSecrets().set(`${name}/${key}`, input[key]);
|
|
167
|
-
persisted[key] = secretRef(`${name}/${key}`);
|
|
168
245
|
}
|
|
169
246
|
if (rejectedSensitive.length > 0) {
|
|
170
247
|
persisted.__cc_rejected_sensitive = [
|
|
171
248
|
...new Set(rejectedSensitive),
|
|
172
249
|
].sort();
|
|
173
250
|
} else if (
|
|
174
|
-
Object.prototype.hasOwnProperty.call(
|
|
175
|
-
persisted,
|
|
176
|
-
"__cc_rejected_sensitive",
|
|
177
|
-
)
|
|
251
|
+
Object.prototype.hasOwnProperty.call(persisted, "__cc_rejected_sensitive")
|
|
178
252
|
) {
|
|
179
253
|
delete persisted.__cc_rejected_sensitive;
|
|
180
254
|
}
|
|
181
255
|
store[name] = persisted;
|
|
182
256
|
writeJsonObject(p, store);
|
|
183
|
-
|
|
257
|
+
} catch (error) {
|
|
258
|
+
// The old metadata is still authoritative. Remove every newly staged
|
|
259
|
+
// value so a failed JSON save cannot leak an orphaned credential.
|
|
260
|
+
deleteSecretRefsBestEffort(secrets, stagedSecretRefs);
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const activeSecretRefs = collectSecretRefs(store);
|
|
265
|
+
const staleSecretRefs = [...replacedSecretRefs].filter(
|
|
266
|
+
(ref) => !activeSecretRefs.has(ref),
|
|
267
|
+
);
|
|
268
|
+
if (staleSecretRefs.length > 0) {
|
|
269
|
+
try {
|
|
270
|
+
deleteSecretRefsBestEffort(getSecrets(), staleSecretRefs);
|
|
271
|
+
} catch {
|
|
272
|
+
// The JSON commit succeeded; unavailable cleanup must not undo it.
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return { name, scope, path: p };
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Persist a plugin's option VALUES at a scope (replaces the plugin's entry). */
|
|
279
|
+
export function setPluginOptionValues(
|
|
280
|
+
name,
|
|
281
|
+
values,
|
|
282
|
+
scope,
|
|
283
|
+
{ cwd, schema, secretStore } = {},
|
|
284
|
+
) {
|
|
285
|
+
const p =
|
|
286
|
+
scope === "project" ? _deps.projectStorePath(cwd) : _deps.userStorePath();
|
|
287
|
+
return withOptionStoreLock(p, () => {
|
|
288
|
+
const store = readJsonObject(p, { failIfUnavailable: true });
|
|
289
|
+
return persistPluginOptionValuesLocked(p, name, values, scope, {
|
|
290
|
+
store,
|
|
291
|
+
schema,
|
|
292
|
+
secretStore,
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Merge option updates under the same lock used for the durable JSON commit.
|
|
299
|
+
* This is the command-safe API: callers never perform a lock-free read/modify/
|
|
300
|
+
* write cycle that could overwrite a concurrent writer's unrelated keys.
|
|
301
|
+
*/
|
|
302
|
+
export function patchPluginOptionValues(
|
|
303
|
+
name,
|
|
304
|
+
updates,
|
|
305
|
+
scope,
|
|
306
|
+
{ cwd, schema, secretStore } = {},
|
|
307
|
+
) {
|
|
308
|
+
const p =
|
|
309
|
+
scope === "project" ? _deps.projectStorePath(cwd) : _deps.userStorePath();
|
|
310
|
+
return withOptionStoreLock(p, () => {
|
|
311
|
+
const store = readJsonObject(p, { failIfUnavailable: true });
|
|
312
|
+
const previous =
|
|
313
|
+
store[name] &&
|
|
314
|
+
typeof store[name] === "object" &&
|
|
315
|
+
!Array.isArray(store[name])
|
|
316
|
+
? store[name]
|
|
317
|
+
: {};
|
|
318
|
+
const patch =
|
|
319
|
+
updates && typeof updates === "object" && !Array.isArray(updates)
|
|
320
|
+
? updates
|
|
321
|
+
: {};
|
|
322
|
+
const values = { ...previous, ...patch };
|
|
323
|
+
return persistPluginOptionValuesLocked(p, name, values, scope, {
|
|
324
|
+
store,
|
|
325
|
+
schema,
|
|
326
|
+
secretStore,
|
|
327
|
+
touchedKeys: new Set(Object.keys(patch)),
|
|
328
|
+
});
|
|
184
329
|
});
|
|
185
330
|
}
|
|
186
331
|
|