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
|
@@ -0,0 +1,853 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Versioned, machine-readable schema for ~/.chainlesschain/config.json.
|
|
3
|
+
*
|
|
4
|
+
* The descriptor table is the source of truth used by config set/validate,
|
|
5
|
+
* secret redaction, `config keys`, and the exported JSON Schema. Open maps are
|
|
6
|
+
* explicit: arbitrary top-level keys are rejected. Open maps such as
|
|
7
|
+
* `features.*` are declared as such; plugin keys remain closed until their
|
|
8
|
+
* owner calls registerPluginConfigSchema().
|
|
9
|
+
*/
|
|
10
|
+
import { DEFAULT_CONFIG, LLM_PROVIDERS } from "../constants.js";
|
|
11
|
+
|
|
12
|
+
export const CONFIG_SCHEMA_VERSION = "1.0.0";
|
|
13
|
+
export const CONFIG_SCHEMA_ID =
|
|
14
|
+
"https://chainlesschain.com/schemas/cli-config/v1.json";
|
|
15
|
+
|
|
16
|
+
const descriptor = (key, type, options = {}) => ({
|
|
17
|
+
key,
|
|
18
|
+
type,
|
|
19
|
+
scope: "user",
|
|
20
|
+
managedLock: true,
|
|
21
|
+
...options,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const DESCRIPTORS = [
|
|
25
|
+
descriptor("setupCompleted", "boolean", {
|
|
26
|
+
default: DEFAULT_CONFIG.setupCompleted,
|
|
27
|
+
description: "Whether initial CLI setup has completed",
|
|
28
|
+
}),
|
|
29
|
+
descriptor("completedAt", ["string", "null"], {
|
|
30
|
+
default: DEFAULT_CONFIG.completedAt,
|
|
31
|
+
description: "ISO timestamp at which setup completed",
|
|
32
|
+
}),
|
|
33
|
+
descriptor("edition", "string", {
|
|
34
|
+
enum: ["personal", "enterprise"],
|
|
35
|
+
default: DEFAULT_CONFIG.edition,
|
|
36
|
+
description: "ChainlessChain edition",
|
|
37
|
+
}),
|
|
38
|
+
descriptor("features", "object", {
|
|
39
|
+
default: DEFAULT_CONFIG.features,
|
|
40
|
+
open: true,
|
|
41
|
+
description: "Feature flag map",
|
|
42
|
+
}),
|
|
43
|
+
descriptor("paths.projectRoot", ["string", "null"], {
|
|
44
|
+
default: DEFAULT_CONFIG.paths.projectRoot,
|
|
45
|
+
description: "Override the detected project root",
|
|
46
|
+
}),
|
|
47
|
+
descriptor("paths.database", ["string", "null"], {
|
|
48
|
+
default: DEFAULT_CONFIG.paths.database,
|
|
49
|
+
description: "Override the SQLite database path",
|
|
50
|
+
}),
|
|
51
|
+
descriptor("llm.provider", "string", {
|
|
52
|
+
enum: [...Object.keys(LLM_PROVIDERS), "local", "llamacpp", "mediapipe"],
|
|
53
|
+
default: DEFAULT_CONFIG.llm.provider,
|
|
54
|
+
description: "LLM provider id",
|
|
55
|
+
}),
|
|
56
|
+
descriptor("llm.apiKey", ["string", "null"], {
|
|
57
|
+
default: DEFAULT_CONFIG.llm.apiKey,
|
|
58
|
+
secret: true,
|
|
59
|
+
description: "LLM provider API key",
|
|
60
|
+
}),
|
|
61
|
+
descriptor("llm.apiKeyHelper", ["string", "null"], {
|
|
62
|
+
description: "Command that prints an API key to stdout",
|
|
63
|
+
}),
|
|
64
|
+
descriptor("llm.baseUrl", "string", {
|
|
65
|
+
default: DEFAULT_CONFIG.llm.baseUrl,
|
|
66
|
+
description: "LLM provider API endpoint",
|
|
67
|
+
}),
|
|
68
|
+
descriptor("llm.model", "string", {
|
|
69
|
+
default: DEFAULT_CONFIG.llm.model,
|
|
70
|
+
description: "Default model id",
|
|
71
|
+
}),
|
|
72
|
+
descriptor("llm.visionModel", ["string", "null"], {
|
|
73
|
+
description: "Model used for image turns",
|
|
74
|
+
}),
|
|
75
|
+
descriptor("llm.fallbackModel", ["string", "null"], {
|
|
76
|
+
deprecated: true,
|
|
77
|
+
migration: "llm.fallbackModels",
|
|
78
|
+
description: "Legacy single fallback model",
|
|
79
|
+
}),
|
|
80
|
+
descriptor("llm.fallbackModels", ["array", "string"], {
|
|
81
|
+
description: "Ordered fallback model ids",
|
|
82
|
+
}),
|
|
83
|
+
descriptor("llm.preferAndroidLocal", "boolean", {
|
|
84
|
+
default: DEFAULT_CONFIG.llm.preferAndroidLocal,
|
|
85
|
+
description: "Prefer the Android local Ollama-compatible endpoint",
|
|
86
|
+
}),
|
|
87
|
+
descriptor("llm.pricing", "object", {
|
|
88
|
+
open: true,
|
|
89
|
+
description: "Per-model pricing overrides",
|
|
90
|
+
}),
|
|
91
|
+
descriptor("llm.streamStallTimeoutMs", "number", {
|
|
92
|
+
minimum: 0,
|
|
93
|
+
description: "Abort an inactive model stream after this many milliseconds",
|
|
94
|
+
}),
|
|
95
|
+
descriptor("llm.temperature", "number", {
|
|
96
|
+
minimum: 0,
|
|
97
|
+
maximum: 2,
|
|
98
|
+
description: "Default sampling temperature",
|
|
99
|
+
}),
|
|
100
|
+
descriptor("llm.maxTokens", "number", {
|
|
101
|
+
minimum: 1,
|
|
102
|
+
description: "Default maximum output tokens",
|
|
103
|
+
}),
|
|
104
|
+
descriptor("enterprise.serverUrl", ["string", "null"], {
|
|
105
|
+
default: DEFAULT_CONFIG.enterprise.serverUrl,
|
|
106
|
+
description: "Enterprise server URL",
|
|
107
|
+
}),
|
|
108
|
+
descriptor("enterprise.apiKey", ["string", "null"], {
|
|
109
|
+
default: DEFAULT_CONFIG.enterprise.apiKey,
|
|
110
|
+
secret: true,
|
|
111
|
+
description: "Enterprise API key",
|
|
112
|
+
}),
|
|
113
|
+
descriptor("enterprise.tenantId", ["string", "null"], {
|
|
114
|
+
default: DEFAULT_CONFIG.enterprise.tenantId,
|
|
115
|
+
description: "Enterprise tenant id",
|
|
116
|
+
}),
|
|
117
|
+
descriptor("services.autoStart", "boolean", {
|
|
118
|
+
default: DEFAULT_CONFIG.services.autoStart,
|
|
119
|
+
description: "Start backing services automatically",
|
|
120
|
+
}),
|
|
121
|
+
descriptor("services.dockerComposePath", ["string", "null"], {
|
|
122
|
+
default: DEFAULT_CONFIG.services.dockerComposePath,
|
|
123
|
+
description: "Path to a Docker Compose file",
|
|
124
|
+
}),
|
|
125
|
+
descriptor("update.channel", "string", {
|
|
126
|
+
enum: ["stable", "beta"],
|
|
127
|
+
default: DEFAULT_CONFIG.update.channel,
|
|
128
|
+
description: "CLI update channel",
|
|
129
|
+
}),
|
|
130
|
+
descriptor("update.autoCheck", "boolean", {
|
|
131
|
+
default: DEFAULT_CONFIG.update.autoCheck,
|
|
132
|
+
description: "Check for updates on startup",
|
|
133
|
+
}),
|
|
134
|
+
descriptor("cli.theme", "string", {
|
|
135
|
+
enum: ["auto", "dark", "light", "mono"],
|
|
136
|
+
description: "Interactive color theme",
|
|
137
|
+
}),
|
|
138
|
+
descriptor("cli.tuiMode", "string", {
|
|
139
|
+
enum: ["auto", "inline", "fullscreen"],
|
|
140
|
+
description: "Interactive TUI mode",
|
|
141
|
+
}),
|
|
142
|
+
descriptor("cli.fastMode", "boolean", {
|
|
143
|
+
description: "Prefer lower-latency model behavior",
|
|
144
|
+
}),
|
|
145
|
+
descriptor("cli.promptSuggestions", "boolean", {
|
|
146
|
+
default: DEFAULT_CONFIG.cli.promptSuggestions,
|
|
147
|
+
description: "Show background prompt suggestions in the interactive REPL",
|
|
148
|
+
}),
|
|
149
|
+
descriptor("cli.keybindings", "object", {
|
|
150
|
+
default: DEFAULT_CONFIG.cli.keybindings,
|
|
151
|
+
open: true,
|
|
152
|
+
description: "Interactive REPL action-to-key binding overrides",
|
|
153
|
+
}),
|
|
154
|
+
descriptor("voice", "object", {
|
|
155
|
+
default: DEFAULT_CONFIG.voice,
|
|
156
|
+
description: "Interactive voice-dictation settings",
|
|
157
|
+
}),
|
|
158
|
+
descriptor("voice.backends", "object", {
|
|
159
|
+
default: DEFAULT_CONFIG.voice.backends,
|
|
160
|
+
open: true,
|
|
161
|
+
description: "Available host speech-to-text backend capability map",
|
|
162
|
+
}),
|
|
163
|
+
descriptor("voice.allowCloud", "boolean", {
|
|
164
|
+
default: DEFAULT_CONFIG.voice.allowCloud,
|
|
165
|
+
description: "Allow cloud speech transcription after local-first probes",
|
|
166
|
+
}),
|
|
167
|
+
descriptor("context.autoPin", ["boolean", "object"], {
|
|
168
|
+
open: true,
|
|
169
|
+
description: "Keep the original task through context compaction",
|
|
170
|
+
}),
|
|
171
|
+
descriptor("permissions.askTimeoutMs", "number", {
|
|
172
|
+
minimum: 0,
|
|
173
|
+
description: "Idle timeout for interactive permission prompts",
|
|
174
|
+
}),
|
|
175
|
+
descriptor("webSearch", "object", {
|
|
176
|
+
description: "Web-search provider options",
|
|
177
|
+
}),
|
|
178
|
+
descriptor("webSearch.provider", "string", {
|
|
179
|
+
enum: [
|
|
180
|
+
"auto",
|
|
181
|
+
"tavily",
|
|
182
|
+
"brave",
|
|
183
|
+
"bocha",
|
|
184
|
+
"qianfan",
|
|
185
|
+
"duckduckgo",
|
|
186
|
+
"searxng",
|
|
187
|
+
"baidu",
|
|
188
|
+
],
|
|
189
|
+
description: "Web-search provider",
|
|
190
|
+
}),
|
|
191
|
+
descriptor("webSearch.maxResults", "number", {
|
|
192
|
+
minimum: 1,
|
|
193
|
+
description: "Default maximum search result count",
|
|
194
|
+
}),
|
|
195
|
+
descriptor("webSearch.apiKey", ["string", "null"], {
|
|
196
|
+
secret: true,
|
|
197
|
+
description: "Web-search provider API key",
|
|
198
|
+
}),
|
|
199
|
+
...["tavily", "brave", "bocha", "qianfan"].map((provider) =>
|
|
200
|
+
descriptor(`webSearch.${provider}ApiKey`, ["string", "null"], {
|
|
201
|
+
secret: true,
|
|
202
|
+
description: `${provider} web-search API key`,
|
|
203
|
+
}),
|
|
204
|
+
),
|
|
205
|
+
descriptor("webSearch.instanceUrl", "string", {
|
|
206
|
+
description: "SearXNG instance URL",
|
|
207
|
+
}),
|
|
208
|
+
descriptor("webSearch.qianfanUrl", "string", {
|
|
209
|
+
description: "Qianfan search endpoint",
|
|
210
|
+
}),
|
|
211
|
+
descriptor("cloud", "object", {
|
|
212
|
+
open: true,
|
|
213
|
+
description: "Private cloud-runner options",
|
|
214
|
+
}),
|
|
215
|
+
descriptor("cloud.token", ["string", "null"], {
|
|
216
|
+
secret: true,
|
|
217
|
+
description: "Private cloud-runner bearer token",
|
|
218
|
+
}),
|
|
219
|
+
descriptor("channels", "object", {
|
|
220
|
+
open: true,
|
|
221
|
+
description: "Inbound channel configuration",
|
|
222
|
+
}),
|
|
223
|
+
descriptor("session", "object", {
|
|
224
|
+
open: true,
|
|
225
|
+
description: "Session persistence and mirror options",
|
|
226
|
+
}),
|
|
227
|
+
descriptor("plugins", "object", {
|
|
228
|
+
description: "Plugin-owned configuration namespace",
|
|
229
|
+
}),
|
|
230
|
+
descriptor("plugins.registryTokens", "object", {
|
|
231
|
+
open: true,
|
|
232
|
+
secretChildren: true,
|
|
233
|
+
description: "Per-registry authentication tokens",
|
|
234
|
+
}),
|
|
235
|
+
descriptor("hub", "object", {
|
|
236
|
+
open: true,
|
|
237
|
+
description: "Hub service configuration",
|
|
238
|
+
}),
|
|
239
|
+
descriptor("hub.llm", ["string", "object"], {
|
|
240
|
+
open: true,
|
|
241
|
+
description: "Hub LLM routing configuration",
|
|
242
|
+
}),
|
|
243
|
+
descriptor("hub.llm.apiKey", ["string", "null"], {
|
|
244
|
+
secret: true,
|
|
245
|
+
description: "Hub-specific LLM API key",
|
|
246
|
+
}),
|
|
247
|
+
descriptor("hub.llm.provider", "string", {
|
|
248
|
+
description: "Hub-specific LLM provider",
|
|
249
|
+
}),
|
|
250
|
+
descriptor("hub.llm.model", "string", {
|
|
251
|
+
description: "Hub-specific LLM model",
|
|
252
|
+
}),
|
|
253
|
+
descriptor("hub.llm.baseUrl", "string", {
|
|
254
|
+
description: "Hub-specific LLM endpoint",
|
|
255
|
+
}),
|
|
256
|
+
descriptor("hub.llm.apiKeyEnv", "string", {
|
|
257
|
+
description: "Environment variable containing the hub LLM API key",
|
|
258
|
+
}),
|
|
259
|
+
descriptor("remoteControl", "object", {
|
|
260
|
+
open: true,
|
|
261
|
+
description: "Remote-control connection settings",
|
|
262
|
+
}),
|
|
263
|
+
descriptor("credentialProxy", "object", {
|
|
264
|
+
description: "Credential proxy policy",
|
|
265
|
+
}),
|
|
266
|
+
descriptor("credentialProxy.enabled", "boolean", {
|
|
267
|
+
description: "Mask credentials inherited by child processes",
|
|
268
|
+
}),
|
|
269
|
+
descriptor("credentialProxy.mode", "string", {
|
|
270
|
+
enum: ["mask", "deny"],
|
|
271
|
+
description: "Mask or remove credential variables",
|
|
272
|
+
}),
|
|
273
|
+
descriptor("credentialProxy.allow", "array", {
|
|
274
|
+
description: "Credential environment variable allowlist",
|
|
275
|
+
}),
|
|
276
|
+
descriptor("credentialProxy.deny", "array", {
|
|
277
|
+
description: "Additional credential environment variables to mask",
|
|
278
|
+
}),
|
|
279
|
+
descriptor("advisor.enabled", "boolean", {
|
|
280
|
+
default: DEFAULT_CONFIG.advisor.enabled,
|
|
281
|
+
description: "Enable the independent advisor/critic pass",
|
|
282
|
+
}),
|
|
283
|
+
descriptor("advisor.provider", ["string", "null"], {
|
|
284
|
+
description: "Advisor-specific LLM provider",
|
|
285
|
+
}),
|
|
286
|
+
descriptor("advisor.model", ["string", "null"], {
|
|
287
|
+
description: "Advisor-specific model",
|
|
288
|
+
}),
|
|
289
|
+
descriptor("advisor.budgetUsd", "number", {
|
|
290
|
+
minimum: 0,
|
|
291
|
+
description: "Maximum advisor spend in USD per run",
|
|
292
|
+
}),
|
|
293
|
+
descriptor("advisor.repeatErrorThreshold", "integer", {
|
|
294
|
+
minimum: 2,
|
|
295
|
+
description: "Repeated-error count that triggers advisor review",
|
|
296
|
+
}),
|
|
297
|
+
descriptor("advisorEnabled", "boolean", {
|
|
298
|
+
deprecated: true,
|
|
299
|
+
migration: "advisor.enabled",
|
|
300
|
+
description: "Legacy advisor enabled alias",
|
|
301
|
+
}),
|
|
302
|
+
descriptor("advisorProvider", ["string", "null"], {
|
|
303
|
+
deprecated: true,
|
|
304
|
+
migration: "advisor.provider",
|
|
305
|
+
description: "Legacy advisor provider alias",
|
|
306
|
+
}),
|
|
307
|
+
descriptor("advisorModel", ["string", "null"], {
|
|
308
|
+
deprecated: true,
|
|
309
|
+
migration: "advisor.model",
|
|
310
|
+
description: "Legacy advisor model alias",
|
|
311
|
+
}),
|
|
312
|
+
descriptor("advisorBudgetUsd", "number", {
|
|
313
|
+
minimum: 0,
|
|
314
|
+
deprecated: true,
|
|
315
|
+
migration: "advisor.budgetUsd",
|
|
316
|
+
description: "Legacy advisor budget alias",
|
|
317
|
+
}),
|
|
318
|
+
descriptor("advisorRepeatErrorThreshold", "integer", {
|
|
319
|
+
minimum: 2,
|
|
320
|
+
deprecated: true,
|
|
321
|
+
migration: "advisor.repeatErrorThreshold",
|
|
322
|
+
description: "Legacy advisor repeated-error alias",
|
|
323
|
+
}),
|
|
324
|
+
descriptor("telemetry", "object", {
|
|
325
|
+
open: true,
|
|
326
|
+
description: "Telemetry and local observability settings",
|
|
327
|
+
}),
|
|
328
|
+
descriptor("ui", "object", {
|
|
329
|
+
open: true,
|
|
330
|
+
description: "Desktop UI compatibility settings",
|
|
331
|
+
}),
|
|
332
|
+
];
|
|
333
|
+
|
|
334
|
+
const BY_KEY = new Map(DESCRIPTORS.map((entry) => [entry.key, entry]));
|
|
335
|
+
// Extension namespaces cannot publish plaintext just because their common
|
|
336
|
+
// credential field uses a compound spelling. This is a closed leaf-name
|
|
337
|
+
// vocabulary (not a broad substring guess); plugin schemas can additionally
|
|
338
|
+
// mark any custom field with `secret: true`.
|
|
339
|
+
const SECRET_LEAF_RE =
|
|
340
|
+
/^(?:api[_-]?key|access[_-]?token|refresh[_-]?token|auth[_-]?token|bearer[_-]?token|bot[_-]?token|client[_-]?secret|secret[_-]?access[_-]?key|private[_-]?key|secret|token|password|passwd|credential|credentials)$/i;
|
|
341
|
+
const FORBIDDEN_SEGMENTS = new Set(["__proto__", "prototype", "constructor"]);
|
|
342
|
+
|
|
343
|
+
export function validateConfigKeySyntax(key) {
|
|
344
|
+
const text = String(key || "");
|
|
345
|
+
const parts = text.split(".");
|
|
346
|
+
if (
|
|
347
|
+
!text ||
|
|
348
|
+
parts.some(
|
|
349
|
+
(part) =>
|
|
350
|
+
!part || FORBIDDEN_SEGMENTS.has(part) || !/^[A-Za-z0-9_-]+$/.test(part),
|
|
351
|
+
)
|
|
352
|
+
) {
|
|
353
|
+
const error = new Error(`Invalid configuration key: ${text || "(empty)"}`);
|
|
354
|
+
error.code = "CONFIG_KEY_INVALID";
|
|
355
|
+
throw error;
|
|
356
|
+
}
|
|
357
|
+
return text;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function parentDescriptors(key) {
|
|
361
|
+
const parents = [];
|
|
362
|
+
const parts = key.split(".");
|
|
363
|
+
for (let index = parts.length - 1; index > 0; index -= 1) {
|
|
364
|
+
const found = BY_KEY.get(parts.slice(0, index).join("."));
|
|
365
|
+
if (found) parents.push(found);
|
|
366
|
+
}
|
|
367
|
+
return parents;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function implicitContainerDescriptor(key) {
|
|
371
|
+
const prefix = `${key}.`;
|
|
372
|
+
const descendants = DESCRIPTORS.filter((entry) =>
|
|
373
|
+
entry.key.startsWith(prefix),
|
|
374
|
+
);
|
|
375
|
+
if (descendants.length === 0) return null;
|
|
376
|
+
return {
|
|
377
|
+
key,
|
|
378
|
+
type: "object",
|
|
379
|
+
scope: descendants.every((entry) => entry.scope === descendants[0].scope)
|
|
380
|
+
? descendants[0].scope
|
|
381
|
+
: "user",
|
|
382
|
+
managedLock: descendants.some((entry) => entry.managedLock !== false),
|
|
383
|
+
implicit: true,
|
|
384
|
+
description: `Configuration group for ${key}`,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** Return the exact descriptor, or a descriptor inherited from an open map. */
|
|
389
|
+
export function getConfigDescriptor(key) {
|
|
390
|
+
const normalized = validateConfigKeySyntax(key);
|
|
391
|
+
const exact = BY_KEY.get(normalized);
|
|
392
|
+
if (exact) return { ...exact };
|
|
393
|
+
const container = implicitContainerDescriptor(normalized);
|
|
394
|
+
if (container) return container;
|
|
395
|
+
const openParent = parentDescriptors(normalized).find((entry) => entry.open);
|
|
396
|
+
if (!openParent) return null;
|
|
397
|
+
const leaf = normalized.split(".").at(-1);
|
|
398
|
+
return {
|
|
399
|
+
key: normalized,
|
|
400
|
+
type: "any",
|
|
401
|
+
scope: openParent.scope,
|
|
402
|
+
managedLock: openParent.managedLock,
|
|
403
|
+
extension: true,
|
|
404
|
+
secret:
|
|
405
|
+
openParent.secretChildren === true || SECRET_LEAF_RE.test(String(leaf)),
|
|
406
|
+
description: `Extension value under ${openParent.key}`,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export function isKnownConfigKey(key) {
|
|
411
|
+
try {
|
|
412
|
+
return getConfigDescriptor(key) !== null;
|
|
413
|
+
} catch {
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
export function isSecretConfigKey(key) {
|
|
419
|
+
const leaf = String(key || "")
|
|
420
|
+
.split(".")
|
|
421
|
+
.at(-1);
|
|
422
|
+
try {
|
|
423
|
+
const entry = getConfigDescriptor(key);
|
|
424
|
+
if (entry?.secret === true) return true;
|
|
425
|
+
return SECRET_LEAF_RE.test(leaf || "");
|
|
426
|
+
} catch {
|
|
427
|
+
// Redaction is an independent security boundary and may receive a raw,
|
|
428
|
+
// invalid document before validation. Preserve the closed leaf-name
|
|
429
|
+
// fallback even when the full dotted path is deliberately rejected.
|
|
430
|
+
return SECRET_LEAF_RE.test(leaf || "");
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export function getConfigDescriptors() {
|
|
435
|
+
return DESCRIPTORS.map((entry) => ({ ...entry }));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Register typed plugin-owned keys without opening arbitrary global keys.
|
|
440
|
+
* Entries use keys relative to `plugins.<pluginId>` and may declare `secret`.
|
|
441
|
+
*/
|
|
442
|
+
export function registerPluginConfigSchema(pluginId, entries = []) {
|
|
443
|
+
const id = String(pluginId || "").trim();
|
|
444
|
+
validateConfigKeySyntax(`plugins.${id}`);
|
|
445
|
+
if (!id || id.includes(".")) {
|
|
446
|
+
throw new Error("Plugin config schema id must be one path segment");
|
|
447
|
+
}
|
|
448
|
+
const namespace = `plugins.${id}`;
|
|
449
|
+
if (
|
|
450
|
+
BY_KEY.has(namespace) ||
|
|
451
|
+
DESCRIPTORS.some((entry) => entry.key.startsWith(`${namespace}.`))
|
|
452
|
+
) {
|
|
453
|
+
throw new Error(`Plugin config namespace is reserved: ${namespace}`);
|
|
454
|
+
}
|
|
455
|
+
const pending = [];
|
|
456
|
+
const pendingKeys = new Set();
|
|
457
|
+
for (const value of entries) {
|
|
458
|
+
const relative = validateConfigKeySyntax(value?.key);
|
|
459
|
+
const key = `${namespace}.${relative}`;
|
|
460
|
+
if (BY_KEY.has(key) || pendingKeys.has(key)) {
|
|
461
|
+
throw new Error(`Configuration key is already registered: ${key}`);
|
|
462
|
+
}
|
|
463
|
+
const next = descriptor(key, value.type || "any", {
|
|
464
|
+
...value,
|
|
465
|
+
key,
|
|
466
|
+
scope: "plugin",
|
|
467
|
+
});
|
|
468
|
+
pending.push(next);
|
|
469
|
+
pendingKeys.add(key);
|
|
470
|
+
}
|
|
471
|
+
// Resolve inheritance only after every descriptor exists so callers are not
|
|
472
|
+
// forced to order a secretChildren parent before its children.
|
|
473
|
+
for (const next of pending) {
|
|
474
|
+
const inheritedSecret = [...DESCRIPTORS, ...pending].some(
|
|
475
|
+
(entry) =>
|
|
476
|
+
next.key.startsWith(`${entry.key}.`) &&
|
|
477
|
+
(entry.secret === true || entry.secretChildren === true),
|
|
478
|
+
);
|
|
479
|
+
if (inheritedSecret) next.secret = true;
|
|
480
|
+
}
|
|
481
|
+
for (const next of pending) {
|
|
482
|
+
DESCRIPTORS.push(next);
|
|
483
|
+
BY_KEY.set(next.key, next);
|
|
484
|
+
}
|
|
485
|
+
return pending.map((entry) => ({ ...entry }));
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function typesFor(entry) {
|
|
489
|
+
return Array.isArray(entry?.type) ? entry.type : [entry?.type || "any"];
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function actualType(value) {
|
|
493
|
+
if (value === null) return "null";
|
|
494
|
+
if (Array.isArray(value)) return "array";
|
|
495
|
+
return typeof value;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function valueIssue(key, code, message) {
|
|
499
|
+
return { key, code, message };
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function isPersistedSecretRef(value) {
|
|
503
|
+
return Boolean(
|
|
504
|
+
value &&
|
|
505
|
+
typeof value === "object" &&
|
|
506
|
+
!Array.isArray(value) &&
|
|
507
|
+
Object.keys(value).length === 1 &&
|
|
508
|
+
typeof value.__cc_secret_ref === "string" &&
|
|
509
|
+
value.__cc_secret_ref.length > 0,
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
export function validateConfigValue(key, value, options = {}) {
|
|
514
|
+
let entry;
|
|
515
|
+
try {
|
|
516
|
+
entry = getConfigDescriptor(key);
|
|
517
|
+
} catch (error) {
|
|
518
|
+
return [valueIssue(String(key || ""), error.code, error.message)];
|
|
519
|
+
}
|
|
520
|
+
if (!entry) {
|
|
521
|
+
return options.allowUnknown
|
|
522
|
+
? []
|
|
523
|
+
: [
|
|
524
|
+
valueIssue(
|
|
525
|
+
key,
|
|
526
|
+
"CONFIG_KEY_UNKNOWN",
|
|
527
|
+
`Unknown configuration key: ${key}`,
|
|
528
|
+
),
|
|
529
|
+
];
|
|
530
|
+
}
|
|
531
|
+
if (isPersistedSecretRef(value)) {
|
|
532
|
+
if (entry.secret === true) return [];
|
|
533
|
+
return [
|
|
534
|
+
valueIssue(
|
|
535
|
+
key,
|
|
536
|
+
"CONFIG_SECRET_REF_INVALID",
|
|
537
|
+
`Secret reference is not allowed at non-secret key: ${key}`,
|
|
538
|
+
),
|
|
539
|
+
];
|
|
540
|
+
}
|
|
541
|
+
const allowed = typesFor(entry);
|
|
542
|
+
const got = actualType(value);
|
|
543
|
+
const typeMatches =
|
|
544
|
+
allowed.includes("any") ||
|
|
545
|
+
allowed.includes(got) ||
|
|
546
|
+
(got === "number" &&
|
|
547
|
+
allowed.includes("integer") &&
|
|
548
|
+
Number.isInteger(value));
|
|
549
|
+
if (!typeMatches) {
|
|
550
|
+
return [
|
|
551
|
+
valueIssue(
|
|
552
|
+
key,
|
|
553
|
+
"CONFIG_TYPE_INVALID",
|
|
554
|
+
`${key} must be ${allowed.join(" | ")}; received ${got}`,
|
|
555
|
+
),
|
|
556
|
+
];
|
|
557
|
+
}
|
|
558
|
+
if (entry.enum && !entry.enum.includes(value)) {
|
|
559
|
+
return [
|
|
560
|
+
valueIssue(
|
|
561
|
+
key,
|
|
562
|
+
"CONFIG_ENUM_INVALID",
|
|
563
|
+
`${key} must be one of: ${entry.enum.join(", ")}`,
|
|
564
|
+
),
|
|
565
|
+
];
|
|
566
|
+
}
|
|
567
|
+
if (typeof value === "number") {
|
|
568
|
+
if (!Number.isFinite(value)) {
|
|
569
|
+
return [
|
|
570
|
+
valueIssue(key, "CONFIG_NUMBER_INVALID", `${key} must be finite`),
|
|
571
|
+
];
|
|
572
|
+
}
|
|
573
|
+
if (entry.minimum != null && value < entry.minimum) {
|
|
574
|
+
return [
|
|
575
|
+
valueIssue(
|
|
576
|
+
key,
|
|
577
|
+
"CONFIG_NUMBER_RANGE",
|
|
578
|
+
`${key} must be >= ${entry.minimum}`,
|
|
579
|
+
),
|
|
580
|
+
];
|
|
581
|
+
}
|
|
582
|
+
if (entry.maximum != null && value > entry.maximum) {
|
|
583
|
+
return [
|
|
584
|
+
valueIssue(
|
|
585
|
+
key,
|
|
586
|
+
"CONFIG_NUMBER_RANGE",
|
|
587
|
+
`${key} must be <= ${entry.maximum}`,
|
|
588
|
+
),
|
|
589
|
+
];
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return [];
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
export function coerceConfigValue(key, raw, options = {}) {
|
|
596
|
+
const entry = getConfigDescriptor(key);
|
|
597
|
+
if (!entry && !options.allowUnknown) {
|
|
598
|
+
const error = new Error(`Unknown configuration key: ${key}`);
|
|
599
|
+
error.code = "CONFIG_KEY_UNKNOWN";
|
|
600
|
+
throw error;
|
|
601
|
+
}
|
|
602
|
+
if (typeof raw !== "string") {
|
|
603
|
+
const issues = validateConfigValue(key, raw, options);
|
|
604
|
+
if (issues.length)
|
|
605
|
+
throw Object.assign(new Error(issues[0].message), issues[0]);
|
|
606
|
+
return raw;
|
|
607
|
+
}
|
|
608
|
+
const types = typesFor(entry);
|
|
609
|
+
let value = raw;
|
|
610
|
+
if (raw === "null" && types.includes("null")) {
|
|
611
|
+
value = null;
|
|
612
|
+
} else if (types.includes("boolean")) {
|
|
613
|
+
if (raw !== "true" && raw !== "false") {
|
|
614
|
+
const error = new Error(`${key} must be true or false`);
|
|
615
|
+
error.code = "CONFIG_TYPE_INVALID";
|
|
616
|
+
throw error;
|
|
617
|
+
}
|
|
618
|
+
value = raw === "true";
|
|
619
|
+
} else if (types.includes("number") || types.includes("integer")) {
|
|
620
|
+
value = Number(raw);
|
|
621
|
+
if (
|
|
622
|
+
!Number.isFinite(value) ||
|
|
623
|
+
(types.includes("integer") && !Number.isInteger(value))
|
|
624
|
+
) {
|
|
625
|
+
const error = new Error(
|
|
626
|
+
`${key} must be a finite ${types.includes("integer") ? "integer" : "number"}`,
|
|
627
|
+
);
|
|
628
|
+
error.code = "CONFIG_TYPE_INVALID";
|
|
629
|
+
throw error;
|
|
630
|
+
}
|
|
631
|
+
} else if (
|
|
632
|
+
(types.includes("array") && raw.trim().startsWith("[")) ||
|
|
633
|
+
(types.includes("object") && raw.trim().startsWith("{")) ||
|
|
634
|
+
((types.includes("array") || types.includes("object")) &&
|
|
635
|
+
!types.includes("string"))
|
|
636
|
+
) {
|
|
637
|
+
try {
|
|
638
|
+
value = JSON.parse(raw);
|
|
639
|
+
} catch {
|
|
640
|
+
const error = new Error(`${key} must be valid JSON`);
|
|
641
|
+
error.code = "CONFIG_TYPE_INVALID";
|
|
642
|
+
throw error;
|
|
643
|
+
}
|
|
644
|
+
} else if (types.includes("any")) {
|
|
645
|
+
if (raw === "true") value = true;
|
|
646
|
+
else if (raw === "false") value = false;
|
|
647
|
+
else if (raw === "null") value = null;
|
|
648
|
+
else if (raw.trim() !== "" && Number.isFinite(Number(raw)))
|
|
649
|
+
value = Number(raw);
|
|
650
|
+
}
|
|
651
|
+
const issues = validateConfigValue(key, value, options);
|
|
652
|
+
if (issues.length)
|
|
653
|
+
throw Object.assign(new Error(issues[0].message), issues[0]);
|
|
654
|
+
return value;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
function walkConfig(value, prefix, issues, options) {
|
|
658
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
659
|
+
for (const [name, child] of Object.entries(value)) {
|
|
660
|
+
const key = prefix ? `${prefix}.${name}` : name;
|
|
661
|
+
let entry;
|
|
662
|
+
try {
|
|
663
|
+
entry = getConfigDescriptor(key);
|
|
664
|
+
} catch (error) {
|
|
665
|
+
issues.push(valueIssue(key, error.code, error.message));
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
668
|
+
if (!entry) {
|
|
669
|
+
if (!options.allowUnknown) {
|
|
670
|
+
issues.push(
|
|
671
|
+
valueIssue(
|
|
672
|
+
key,
|
|
673
|
+
"CONFIG_KEY_UNKNOWN",
|
|
674
|
+
`Unknown configuration key: ${key}`,
|
|
675
|
+
),
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
issues.push(...validateConfigValue(key, child, options));
|
|
681
|
+
if (
|
|
682
|
+
child &&
|
|
683
|
+
typeof child === "object" &&
|
|
684
|
+
!Array.isArray(child) &&
|
|
685
|
+
!isPersistedSecretRef(child)
|
|
686
|
+
) {
|
|
687
|
+
walkConfig(child, key, issues, options);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
export function validateConfigDocument(config, options = {}) {
|
|
693
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
694
|
+
return {
|
|
695
|
+
valid: false,
|
|
696
|
+
schemaVersion: CONFIG_SCHEMA_VERSION,
|
|
697
|
+
issues: [
|
|
698
|
+
valueIssue(
|
|
699
|
+
"",
|
|
700
|
+
"CONFIG_ROOT_INVALID",
|
|
701
|
+
"Configuration root must be an object",
|
|
702
|
+
),
|
|
703
|
+
],
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
const issues = [];
|
|
707
|
+
walkConfig(config, "", issues, options);
|
|
708
|
+
return {
|
|
709
|
+
valid: issues.length === 0,
|
|
710
|
+
schemaVersion: CONFIG_SCHEMA_VERSION,
|
|
711
|
+
issues,
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
export function migrateConfigDocument(config) {
|
|
716
|
+
const next = structuredClone(config || {});
|
|
717
|
+
const migrations = [];
|
|
718
|
+
const legacy = next?.llm?.fallbackModel;
|
|
719
|
+
if (legacy != null) {
|
|
720
|
+
if (next?.llm?.fallbackModels == null) {
|
|
721
|
+
next.llm.fallbackModels = Array.isArray(legacy) ? legacy : [legacy];
|
|
722
|
+
}
|
|
723
|
+
delete next.llm.fallbackModel;
|
|
724
|
+
migrations.push({ from: "llm.fallbackModel", to: "llm.fallbackModels" });
|
|
725
|
+
}
|
|
726
|
+
const advisorAliases = [
|
|
727
|
+
["advisorEnabled", "enabled"],
|
|
728
|
+
["advisorProvider", "provider"],
|
|
729
|
+
["advisorModel", "model"],
|
|
730
|
+
["advisorBudgetUsd", "budgetUsd"],
|
|
731
|
+
["advisorRepeatErrorThreshold", "repeatErrorThreshold"],
|
|
732
|
+
];
|
|
733
|
+
for (const [legacyKey, nestedKey] of advisorAliases) {
|
|
734
|
+
if (!Object.prototype.hasOwnProperty.call(next, legacyKey)) continue;
|
|
735
|
+
if (next.advisor == null) next.advisor = {};
|
|
736
|
+
if (typeof next.advisor !== "object" || Array.isArray(next.advisor)) {
|
|
737
|
+
// Preserve both invalid values so validation can report them; migration
|
|
738
|
+
// must never crash or silently replace a malformed nested document.
|
|
739
|
+
continue;
|
|
740
|
+
}
|
|
741
|
+
if (!Object.prototype.hasOwnProperty.call(next.advisor, nestedKey)) {
|
|
742
|
+
next.advisor[nestedKey] = next[legacyKey];
|
|
743
|
+
}
|
|
744
|
+
delete next[legacyKey];
|
|
745
|
+
migrations.push({ from: legacyKey, to: `advisor.${nestedKey}` });
|
|
746
|
+
}
|
|
747
|
+
return { config: next, migrations };
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
function schemaType(type) {
|
|
751
|
+
if (type === "any") return {};
|
|
752
|
+
return { type };
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
function objectPropertiesFor(schema) {
|
|
756
|
+
if (Array.isArray(schema.anyOf)) {
|
|
757
|
+
let objectBranch = schema.anyOf.find((entry) => entry?.type === "object");
|
|
758
|
+
if (!objectBranch) {
|
|
759
|
+
objectBranch = { type: "object" };
|
|
760
|
+
schema.anyOf.push(objectBranch);
|
|
761
|
+
}
|
|
762
|
+
objectBranch.properties ||= {};
|
|
763
|
+
objectBranch.additionalProperties ??= false;
|
|
764
|
+
return objectBranch.properties;
|
|
765
|
+
}
|
|
766
|
+
schema.type = "object";
|
|
767
|
+
schema.properties ||= {};
|
|
768
|
+
schema.additionalProperties ??= false;
|
|
769
|
+
return schema.properties;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
function markObjectBranchesOpen(schema) {
|
|
773
|
+
if (!schema || typeof schema !== "object") return;
|
|
774
|
+
if (schema.type === "object") schema.additionalProperties = true;
|
|
775
|
+
if (Array.isArray(schema.anyOf)) {
|
|
776
|
+
for (const branch of schema.anyOf) markObjectBranchesOpen(branch);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
function buildJsonSchema() {
|
|
781
|
+
const root = {
|
|
782
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
783
|
+
$id: CONFIG_SCHEMA_ID,
|
|
784
|
+
title: "ChainlessChain CLI configuration",
|
|
785
|
+
type: "object",
|
|
786
|
+
additionalProperties: false,
|
|
787
|
+
properties: {},
|
|
788
|
+
$defs: {
|
|
789
|
+
secretRef: {
|
|
790
|
+
type: "object",
|
|
791
|
+
additionalProperties: false,
|
|
792
|
+
required: ["__cc_secret_ref"],
|
|
793
|
+
properties: {
|
|
794
|
+
__cc_secret_ref: { type: "string", minLength: 1 },
|
|
795
|
+
},
|
|
796
|
+
},
|
|
797
|
+
},
|
|
798
|
+
"x-chainlesschain-schema-version": CONFIG_SCHEMA_VERSION,
|
|
799
|
+
};
|
|
800
|
+
const orderedDescriptors = [...DESCRIPTORS].sort(
|
|
801
|
+
(left, right) => left.key.split(".").length - right.key.split(".").length,
|
|
802
|
+
);
|
|
803
|
+
for (const entry of orderedDescriptors) {
|
|
804
|
+
const parts = entry.key.split(".");
|
|
805
|
+
let properties = root.properties;
|
|
806
|
+
for (let index = 0; index < parts.length; index += 1) {
|
|
807
|
+
const part = parts[index];
|
|
808
|
+
const leaf = index === parts.length - 1;
|
|
809
|
+
if (!properties[part]) {
|
|
810
|
+
properties[part] = leaf
|
|
811
|
+
? {}
|
|
812
|
+
: { type: "object", additionalProperties: false, properties: {} };
|
|
813
|
+
}
|
|
814
|
+
if (!leaf) {
|
|
815
|
+
properties = objectPropertiesFor(properties[part]);
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
const types = typesFor(entry);
|
|
819
|
+
const declaredSchema =
|
|
820
|
+
types.length === 1
|
|
821
|
+
? schemaType(types[0])
|
|
822
|
+
: { anyOf: types.map((type) => schemaType(type)) };
|
|
823
|
+
const leafSchema = entry.secret
|
|
824
|
+
? { anyOf: [declaredSchema, { $ref: "#/$defs/secretRef" }] }
|
|
825
|
+
: declaredSchema;
|
|
826
|
+
if (entry.enum) leafSchema.enum = [...entry.enum];
|
|
827
|
+
if (entry.default !== undefined)
|
|
828
|
+
leafSchema.default = structuredClone(entry.default);
|
|
829
|
+
if (entry.minimum !== undefined) leafSchema.minimum = entry.minimum;
|
|
830
|
+
if (entry.maximum !== undefined) leafSchema.maximum = entry.maximum;
|
|
831
|
+
if (entry.description) leafSchema.description = entry.description;
|
|
832
|
+
if (entry.open) {
|
|
833
|
+
leafSchema.additionalProperties = true;
|
|
834
|
+
markObjectBranchesOpen(leafSchema);
|
|
835
|
+
}
|
|
836
|
+
if (entry.secret) leafSchema["x-secret"] = true;
|
|
837
|
+
if (entry.secretChildren) leafSchema["x-secret-children"] = true;
|
|
838
|
+
leafSchema["x-scope"] = entry.scope;
|
|
839
|
+
leafSchema["x-managed-lock"] = entry.managedLock;
|
|
840
|
+
if (entry.deprecated) leafSchema.deprecated = true;
|
|
841
|
+
if (entry.migration) leafSchema["x-migration"] = entry.migration;
|
|
842
|
+
properties[part] = { ...properties[part], ...leafSchema };
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return root;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
export const CONFIG_SCHEMA = Object.freeze(buildJsonSchema());
|
|
849
|
+
|
|
850
|
+
/** Include any plugin schemas registered in the current process. */
|
|
851
|
+
export function getConfigJsonSchema() {
|
|
852
|
+
return buildJsonSchema();
|
|
853
|
+
}
|