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
|
@@ -78,19 +78,55 @@ function settingsFiles(cwd, explicitFile) {
|
|
|
78
78
|
return list;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
function
|
|
81
|
+
function sha256Content(content) {
|
|
82
|
+
return crypto
|
|
83
|
+
.createHash("sha256")
|
|
84
|
+
.update(Buffer.isBuffer(content) ? content : String(content))
|
|
85
|
+
.digest("hex");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function readJsonRecord(
|
|
89
|
+
file,
|
|
90
|
+
onWarn,
|
|
91
|
+
{ kind = "settings", errors = null } = {},
|
|
92
|
+
) {
|
|
93
|
+
if (!_deps.fs.existsSync(file)) return null;
|
|
94
|
+
let raw = null;
|
|
82
95
|
try {
|
|
83
|
-
|
|
84
|
-
const parsed = JSON.parse(
|
|
85
|
-
|
|
96
|
+
raw = _deps.fs.readFileSync(file, "utf-8");
|
|
97
|
+
const parsed = JSON.parse(raw);
|
|
98
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
99
|
+
throw new TypeError("settings root must be a JSON object");
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
data: parsed,
|
|
103
|
+
digest: sha256Content(raw),
|
|
104
|
+
sourceFile: path.resolve(file),
|
|
105
|
+
};
|
|
86
106
|
} catch (err) {
|
|
87
107
|
const msg = `hooks: ignoring malformed ${file} (${err.message})`;
|
|
108
|
+
const record = Object.freeze({
|
|
109
|
+
code:
|
|
110
|
+
kind === "managed"
|
|
111
|
+
? "CC_MANAGED_SETTINGS_INVALID"
|
|
112
|
+
: "CC_SETTINGS_HOOKS_INVALID",
|
|
113
|
+
kind,
|
|
114
|
+
sourceFile: path.resolve(file),
|
|
115
|
+
digest: raw == null ? null : sha256Content(raw),
|
|
116
|
+
authorityBearing: true,
|
|
117
|
+
message: msg,
|
|
118
|
+
});
|
|
119
|
+
if (Array.isArray(errors)) errors.push(record);
|
|
88
120
|
if (typeof onWarn === "function") onWarn(msg);
|
|
89
121
|
else process.stderr.write(msg + "\n");
|
|
90
|
-
return null;
|
|
122
|
+
return null;
|
|
91
123
|
}
|
|
92
124
|
}
|
|
93
125
|
|
|
126
|
+
function readJson(file, onWarn) {
|
|
127
|
+
return readJsonRecord(file, onWarn)?.data || null;
|
|
128
|
+
}
|
|
129
|
+
|
|
94
130
|
function managedSettingsFile(env = process.env) {
|
|
95
131
|
if (env.CC_MANAGED_SETTINGS) return path.resolve(env.CC_MANAGED_SETTINGS);
|
|
96
132
|
if (process.platform === "win32") {
|
|
@@ -100,7 +136,31 @@ function managedSettingsFile(env = process.env) {
|
|
|
100
136
|
return "/etc/chainlesschain/managed-settings.json";
|
|
101
137
|
}
|
|
102
138
|
|
|
103
|
-
function
|
|
139
|
+
function attachAuthoritySource(target, source) {
|
|
140
|
+
if (!source) return target;
|
|
141
|
+
const authoritySource = Object.freeze({
|
|
142
|
+
kind:
|
|
143
|
+
source.kind === "managed"
|
|
144
|
+
? "managed"
|
|
145
|
+
: source.kind === "plugin"
|
|
146
|
+
? "plugin"
|
|
147
|
+
: "settings",
|
|
148
|
+
sourceFile:
|
|
149
|
+
typeof source.sourceFile === "string" && source.sourceFile
|
|
150
|
+
? path.resolve(source.sourceFile)
|
|
151
|
+
: null,
|
|
152
|
+
digest: String(source.digest || ""),
|
|
153
|
+
});
|
|
154
|
+
Object.defineProperty(target, "authoritySource", {
|
|
155
|
+
value: authoritySource,
|
|
156
|
+
enumerable: true,
|
|
157
|
+
writable: false,
|
|
158
|
+
configurable: false,
|
|
159
|
+
});
|
|
160
|
+
return target;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function appendHookBlock(merged, data, authoritySource) {
|
|
104
164
|
const block =
|
|
105
165
|
data && data.hooks && typeof data.hooks === "object" ? data.hooks : null;
|
|
106
166
|
if (!block) return false;
|
|
@@ -109,9 +169,9 @@ function appendHookBlock(merged, data) {
|
|
|
109
169
|
if (!Array.isArray(groups)) continue;
|
|
110
170
|
for (const g of groups) {
|
|
111
171
|
if (!g || typeof g !== "object" || !Array.isArray(g.hooks)) continue;
|
|
112
|
-
const cmds = g.hooks
|
|
113
|
-
(h) => h && h.type === "command" && h.command
|
|
114
|
-
|
|
172
|
+
const cmds = g.hooks
|
|
173
|
+
.filter((h) => h && h.type === "command" && h.command)
|
|
174
|
+
.map((h) => attachAuthoritySource({ ...h }, authoritySource));
|
|
115
175
|
if (cmds.length === 0) continue;
|
|
116
176
|
if (!merged[event]) merged[event] = [];
|
|
117
177
|
merged[event].push({ matcher: g.matcher ?? null, hooks: cmds });
|
|
@@ -123,7 +183,7 @@ function appendHookBlock(merged, data) {
|
|
|
123
183
|
|
|
124
184
|
/**
|
|
125
185
|
* Load + concatenate the `hooks` blocks across the hierarchy.
|
|
126
|
-
* @returns {{ hooks: Record<string, Array<{matcher:string|null, hooks:Array<{type,command,timeout}>}>>, files:string[] }}
|
|
186
|
+
* @returns {{ hooks: Record<string, Array<{matcher:string|null, hooks:Array<{type,command,timeout,authoritySource?}>}>>, files:string[], authorityErrors?:Array<object> }}
|
|
127
187
|
*/
|
|
128
188
|
function loadHooks({
|
|
129
189
|
cwd = process.cwd(),
|
|
@@ -133,15 +193,23 @@ function loadHooks({
|
|
|
133
193
|
} = {}) {
|
|
134
194
|
const merged = {};
|
|
135
195
|
const files = [];
|
|
196
|
+
const authorityErrors = [];
|
|
136
197
|
const managedFile = managedSettingsFile(env);
|
|
137
198
|
let managed = null;
|
|
199
|
+
let managedRecord = null;
|
|
138
200
|
if (_deps.fs.existsSync(managedFile)) {
|
|
139
|
-
|
|
140
|
-
|
|
201
|
+
const managedErrors = [];
|
|
202
|
+
managedRecord = readJsonRecord(managedFile, onWarn, {
|
|
203
|
+
kind: "managed",
|
|
204
|
+
errors: managedErrors,
|
|
205
|
+
});
|
|
206
|
+
managed = managedRecord?.data || null;
|
|
207
|
+
if (!managedRecord) {
|
|
141
208
|
const error = new Error(
|
|
142
209
|
`managed settings are unreadable or malformed: ${managedFile}`,
|
|
143
210
|
);
|
|
144
211
|
error.code = "CC_MANAGED_SETTINGS_INVALID";
|
|
212
|
+
if (managedErrors[0]) error.authorityError = managedErrors[0];
|
|
145
213
|
throw error;
|
|
146
214
|
}
|
|
147
215
|
}
|
|
@@ -160,12 +228,33 @@ function loadHooks({
|
|
|
160
228
|
const resolved = path.resolve(file);
|
|
161
229
|
if (seenPaths.has(resolved)) continue;
|
|
162
230
|
seenPaths.add(resolved);
|
|
163
|
-
const
|
|
164
|
-
|
|
231
|
+
const record = readJsonRecord(file, onWarn, {
|
|
232
|
+
kind: "settings",
|
|
233
|
+
errors: authorityErrors,
|
|
234
|
+
});
|
|
235
|
+
const contributed = record
|
|
236
|
+
? appendHookBlock(merged, record.data, {
|
|
237
|
+
kind: "settings",
|
|
238
|
+
sourceFile: record.sourceFile,
|
|
239
|
+
digest: record.digest,
|
|
240
|
+
})
|
|
241
|
+
: false;
|
|
165
242
|
if (contributed) files.push(file);
|
|
166
243
|
}
|
|
167
|
-
if (
|
|
244
|
+
if (
|
|
245
|
+
managedRecord &&
|
|
246
|
+
appendHookBlock(merged, managed, {
|
|
247
|
+
kind: "managed",
|
|
248
|
+
sourceFile: managedRecord.sourceFile,
|
|
249
|
+
digest: managedRecord.digest,
|
|
250
|
+
})
|
|
251
|
+
) {
|
|
252
|
+
files.push(managedFile);
|
|
253
|
+
}
|
|
168
254
|
const result = { hooks: merged, files };
|
|
255
|
+
if (authorityErrors.length > 0) {
|
|
256
|
+
result.authorityErrors = authorityErrors;
|
|
257
|
+
}
|
|
169
258
|
if (managed) {
|
|
170
259
|
result.managed = managed;
|
|
171
260
|
result.managedFile = managedFile;
|
|
@@ -173,6 +262,32 @@ function loadHooks({
|
|
|
173
262
|
return result;
|
|
174
263
|
}
|
|
175
264
|
|
|
265
|
+
/**
|
|
266
|
+
* Preserve loader failures across plugin-hook merging without making them look
|
|
267
|
+
* like a hook event. The runtime consumes this non-enumerable, immutable host
|
|
268
|
+
* metadata and blocks tool execution rather than running a partial authority
|
|
269
|
+
* set. Returns an object even when there are no valid hooks but errors exist.
|
|
270
|
+
*/
|
|
271
|
+
function attachAuthorityErrors(hooks, errors) {
|
|
272
|
+
const target = hooks && typeof hooks === "object" ? hooks : {};
|
|
273
|
+
const normalized = Array.isArray(errors)
|
|
274
|
+
? errors.map((entry) =>
|
|
275
|
+
Object.freeze({
|
|
276
|
+
sourceFile: entry?.sourceFile || entry?.file || null,
|
|
277
|
+
code: entry?.code || "CC_HOOK_AUTHORITY_INVALID",
|
|
278
|
+
message: entry?.message || null,
|
|
279
|
+
}),
|
|
280
|
+
)
|
|
281
|
+
: [];
|
|
282
|
+
Object.defineProperty(target, "_authorityErrors", {
|
|
283
|
+
value: Object.freeze(normalized),
|
|
284
|
+
enumerable: false,
|
|
285
|
+
writable: false,
|
|
286
|
+
configurable: false,
|
|
287
|
+
});
|
|
288
|
+
return target;
|
|
289
|
+
}
|
|
290
|
+
|
|
176
291
|
/**
|
|
177
292
|
* Compile a matcher into a test fn (pipe / wildcard / regex). Inlined twin of
|
|
178
293
|
* hook-manager.compileMatcher so this .cjs has no ESM dependency.
|
|
@@ -224,7 +339,7 @@ function umbrellaFor(tool) {
|
|
|
224
339
|
* `event` is stamped on each hook so a supervisor can key runs by (event+cmd).
|
|
225
340
|
*
|
|
226
341
|
* @returns {Array<{command:string, timeout?:number, event:string,
|
|
227
|
-
* async:boolean, asyncRewake:boolean}>}
|
|
342
|
+
* async:boolean, asyncRewake:boolean, authoritySource?:object}>}
|
|
228
343
|
*/
|
|
229
344
|
function collectHooks(hooksBlock, event, toolName) {
|
|
230
345
|
const groups = (hooksBlock && hooksBlock[event]) || [];
|
|
@@ -245,8 +360,8 @@ function collectHooks(hooksBlock, event, toolName) {
|
|
|
245
360
|
for (const g of groups) {
|
|
246
361
|
const fn = compileMatcher(g.matcher);
|
|
247
362
|
if (fn(umbrella) || (raw && fn(raw)) || (mcpServer && fn(mcpServer))) {
|
|
248
|
-
for (const h of g.hooks)
|
|
249
|
-
|
|
363
|
+
for (const h of g.hooks) {
|
|
364
|
+
const collected = {
|
|
250
365
|
command: h.command,
|
|
251
366
|
timeout: h.timeout,
|
|
252
367
|
event,
|
|
@@ -260,16 +375,16 @@ function collectHooks(hooksBlock, event, toolName) {
|
|
|
260
375
|
...(h.environmentAllowlist != null
|
|
261
376
|
? { environmentAllowlist: h.environmentAllowlist }
|
|
262
377
|
: {}),
|
|
263
|
-
...(h.envAllowlist != null
|
|
264
|
-
? { envAllowlist: h.envAllowlist }
|
|
265
|
-
: {}),
|
|
378
|
+
...(h.envAllowlist != null ? { envAllowlist: h.envAllowlist } : {}),
|
|
266
379
|
...(h.sandboxPolicy !== undefined
|
|
267
380
|
? { sandboxPolicy: h.sandboxPolicy }
|
|
268
381
|
: {}),
|
|
269
382
|
...(h.requiredBoundaries !== undefined
|
|
270
383
|
? { requiredBoundaries: h.requiredBoundaries }
|
|
271
384
|
: {}),
|
|
272
|
-
}
|
|
385
|
+
};
|
|
386
|
+
out.push(attachAuthoritySource(collected, h.authoritySource));
|
|
387
|
+
}
|
|
273
388
|
}
|
|
274
389
|
}
|
|
275
390
|
return out;
|
|
@@ -413,6 +528,7 @@ function projectHookTrustNotice({ cwd = process.cwd(), settingsFile } = {}) {
|
|
|
413
528
|
|
|
414
529
|
module.exports = {
|
|
415
530
|
loadHooks,
|
|
531
|
+
attachAuthorityErrors,
|
|
416
532
|
projectHookTrustNotice,
|
|
417
533
|
collectHooks,
|
|
418
534
|
compileMatcher,
|
|
@@ -294,13 +294,22 @@ function addRule({ cwd = process.cwd(), kind, rule, scope = "project" } = {}) {
|
|
|
294
294
|
* model / env vars for a run without editing .chainlesschain/config.json.
|
|
295
295
|
*
|
|
296
296
|
* @param {object} [opts] { cwd, settingsFile, onWarn }
|
|
297
|
-
* @returns {{
|
|
297
|
+
* @returns {{
|
|
298
|
+
* model: string|null,
|
|
299
|
+
* modelSource: string|null,
|
|
300
|
+
* env: Record<string,string>,
|
|
301
|
+
* envSources: Record<string,string>,
|
|
302
|
+
* files: string[]
|
|
303
|
+
* }}
|
|
298
304
|
*/
|
|
299
305
|
function loadSettingsConfig(opts = {}) {
|
|
300
306
|
const cwd = opts.cwd || process.cwd();
|
|
301
307
|
let model = null;
|
|
308
|
+
let modelSource = null;
|
|
302
309
|
const env = {};
|
|
310
|
+
const envSources = {};
|
|
303
311
|
let sandbox = null;
|
|
312
|
+
let managedSandbox = null;
|
|
304
313
|
const files = [];
|
|
305
314
|
for (const file of settingsPaths(cwd, opts.settingsFile)) {
|
|
306
315
|
const data = readSettingsFile(file, { onWarn: opts.onWarn });
|
|
@@ -308,12 +317,14 @@ function loadSettingsConfig(opts = {}) {
|
|
|
308
317
|
let contributed = false;
|
|
309
318
|
if (typeof data.model === "string" && data.model.trim()) {
|
|
310
319
|
model = data.model.trim();
|
|
320
|
+
modelSource = file;
|
|
311
321
|
contributed = true;
|
|
312
322
|
}
|
|
313
323
|
if (data.env && typeof data.env === "object" && !Array.isArray(data.env)) {
|
|
314
324
|
for (const [k, v] of Object.entries(data.env)) {
|
|
315
325
|
if (typeof v === "string") {
|
|
316
326
|
env[k] = v;
|
|
327
|
+
envSources[k] = file;
|
|
317
328
|
contributed = true;
|
|
318
329
|
}
|
|
319
330
|
}
|
|
@@ -334,12 +345,14 @@ function loadSettingsConfig(opts = {}) {
|
|
|
334
345
|
let contributed = false;
|
|
335
346
|
if (typeof data.model === "string" && data.model.trim()) {
|
|
336
347
|
model = data.model.trim();
|
|
348
|
+
modelSource = managed.file;
|
|
337
349
|
contributed = true;
|
|
338
350
|
}
|
|
339
351
|
if (data.env && typeof data.env === "object" && !Array.isArray(data.env)) {
|
|
340
352
|
for (const [k, v] of Object.entries(data.env)) {
|
|
341
353
|
if (typeof v === "string") {
|
|
342
354
|
env[k] = v;
|
|
355
|
+
envSources[k] = managed.file;
|
|
343
356
|
contributed = true;
|
|
344
357
|
}
|
|
345
358
|
}
|
|
@@ -349,12 +362,22 @@ function loadSettingsConfig(opts = {}) {
|
|
|
349
362
|
typeof data.sandbox === "object" &&
|
|
350
363
|
!Array.isArray(data.sandbox)
|
|
351
364
|
) {
|
|
365
|
+
managedSandbox = JSON.parse(JSON.stringify(data.sandbox));
|
|
352
366
|
sandbox = mergeSandboxSettings(sandbox, data.sandbox);
|
|
353
367
|
contributed = true;
|
|
354
368
|
}
|
|
355
369
|
if (contributed) files.push(managed.file);
|
|
356
370
|
}
|
|
357
|
-
return {
|
|
371
|
+
return {
|
|
372
|
+
model,
|
|
373
|
+
modelSource,
|
|
374
|
+
env,
|
|
375
|
+
envSources,
|
|
376
|
+
sandbox,
|
|
377
|
+
managedSandbox,
|
|
378
|
+
files,
|
|
379
|
+
managedFile: managed.settings ? managed.file : null,
|
|
380
|
+
};
|
|
358
381
|
}
|
|
359
382
|
|
|
360
383
|
function mergeSandboxSettings(base, overlay) {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import {
|
|
13
13
|
appendEvent as storeAppendEvent,
|
|
14
14
|
readEvents as storeReadEvents,
|
|
15
|
+
findLatestEvent as storeFindLatestEvent,
|
|
15
16
|
} from "../harness/jsonl-session-store.js";
|
|
16
17
|
import {
|
|
17
18
|
SideEffectLedger,
|
|
@@ -24,14 +25,38 @@ export const SIDE_EFFECT_LEDGER_EVENT = "side_effect_ledger";
|
|
|
24
25
|
export const _deps = {
|
|
25
26
|
appendEvent: storeAppendEvent,
|
|
26
27
|
readEvents: storeReadEvents,
|
|
28
|
+
findLatestEvent: storeFindLatestEvent,
|
|
27
29
|
};
|
|
28
30
|
|
|
31
|
+
function findLatestLedgerEvent(sessionId) {
|
|
32
|
+
if (
|
|
33
|
+
typeof _deps.findLatestEvent === "function" &&
|
|
34
|
+
_deps.findLatestEvent !== storeFindLatestEvent
|
|
35
|
+
) {
|
|
36
|
+
return _deps.findLatestEvent(sessionId, SIDE_EFFECT_LEDGER_EVENT);
|
|
37
|
+
}
|
|
38
|
+
// Existing tests and embedders historically injected only readEvents.
|
|
39
|
+
if (_deps.readEvents !== storeReadEvents) {
|
|
40
|
+
const events = _deps.readEvents(sessionId) || [];
|
|
41
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
42
|
+
const event = events[index];
|
|
43
|
+
if (event?.type === SIDE_EFFECT_LEDGER_EVENT) return event;
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return storeFindLatestEvent(sessionId, SIDE_EFFECT_LEDGER_EVENT);
|
|
48
|
+
}
|
|
49
|
+
|
|
29
50
|
export class SideEffectLedgerPersistenceError extends Error {
|
|
30
51
|
constructor(operation, sessionId, cause) {
|
|
31
|
-
const detail =
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
52
|
+
const detail =
|
|
53
|
+
cause?.message || String(cause || "unknown persistence error");
|
|
54
|
+
super(
|
|
55
|
+
`Side-effect ledger ${operation} failed for ${sessionId}: ${detail}`,
|
|
56
|
+
{
|
|
57
|
+
cause,
|
|
58
|
+
},
|
|
59
|
+
);
|
|
35
60
|
this.name = "SideEffectLedgerPersistenceError";
|
|
36
61
|
this.code =
|
|
37
62
|
operation === "read"
|
|
@@ -91,9 +116,9 @@ export function persistSideEffectLedger(sessionId, ledger, opts = {}) {
|
|
|
91
116
|
*/
|
|
92
117
|
export function loadSideEffectLedger(sessionId, opts = {}) {
|
|
93
118
|
const failIfUnavailable = opts.failIfUnavailable !== false;
|
|
94
|
-
let
|
|
119
|
+
let event = null;
|
|
95
120
|
try {
|
|
96
|
-
|
|
121
|
+
event = findLatestLedgerEvent(sessionId);
|
|
97
122
|
} catch (error) {
|
|
98
123
|
const fallback = persistenceFailure(
|
|
99
124
|
"read",
|
|
@@ -103,25 +128,22 @@ export function loadSideEffectLedger(sessionId, opts = {}) {
|
|
|
103
128
|
);
|
|
104
129
|
if (fallback === false) return new SideEffectLedger(opts);
|
|
105
130
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
e.data &&
|
|
112
|
-
Array.isArray(e.data.ops)
|
|
113
|
-
) {
|
|
114
|
-
try {
|
|
115
|
-
return SideEffectLedger.fromJSON(e.data, opts);
|
|
116
|
-
} catch (error) {
|
|
117
|
-
const fallback = persistenceFailure(
|
|
118
|
-
"read",
|
|
119
|
-
sessionId || "<missing-session>",
|
|
120
|
-
error,
|
|
121
|
-
failIfUnavailable,
|
|
131
|
+
if (event) {
|
|
132
|
+
try {
|
|
133
|
+
if (!Array.isArray(event?.data?.ops)) {
|
|
134
|
+
throw new TypeError(
|
|
135
|
+
"latest side-effect ledger snapshot must contain an ops array",
|
|
122
136
|
);
|
|
123
|
-
if (fallback === false) return new SideEffectLedger(opts);
|
|
124
137
|
}
|
|
138
|
+
return SideEffectLedger.fromJSON(event.data, opts);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
const fallback = persistenceFailure(
|
|
141
|
+
"read",
|
|
142
|
+
sessionId || "<missing-session>",
|
|
143
|
+
error,
|
|
144
|
+
failIfUnavailable,
|
|
145
|
+
);
|
|
146
|
+
if (fallback === false) return new SideEffectLedger(opts);
|
|
125
147
|
}
|
|
126
148
|
}
|
|
127
149
|
return new SideEffectLedger(opts);
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
export const SKILL_EXECUTION_IDENTITY_VERSION = 1;
|
|
6
|
+
|
|
7
|
+
const EXECUTION_REASONS = new Set(["run_skill", "cli_skill_run"]);
|
|
8
|
+
|
|
9
|
+
function sha256(parts) {
|
|
10
|
+
const digest = createHash("sha256");
|
|
11
|
+
for (const part of parts) {
|
|
12
|
+
const bytes = Buffer.isBuffer(part) ? part : Buffer.from(String(part));
|
|
13
|
+
digest.update(String(bytes.length));
|
|
14
|
+
digest.update("\0");
|
|
15
|
+
digest.update(bytes);
|
|
16
|
+
digest.update("\0");
|
|
17
|
+
}
|
|
18
|
+
return `sha256:${digest.digest("hex")}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function canonicalRealPath(value) {
|
|
22
|
+
let result = fs.realpathSync(path.resolve(value)).replace(/\\/g, "/");
|
|
23
|
+
if (process.platform === "win32") result = result.toLowerCase();
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function securityError(code, message, details = {}) {
|
|
28
|
+
const error = new Error(
|
|
29
|
+
message,
|
|
30
|
+
details.cause ? { cause: details.cause } : {},
|
|
31
|
+
);
|
|
32
|
+
error.name = "SkillExecutionSecurityError";
|
|
33
|
+
error.code = code;
|
|
34
|
+
if (details.skillId) error.skillId = details.skillId;
|
|
35
|
+
if (details.previousDigest) error.previousDigest = details.previousDigest;
|
|
36
|
+
if (details.currentDigest) error.currentDigest = details.currentDigest;
|
|
37
|
+
return error;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readStableRegularFile(file, options = {}) {
|
|
41
|
+
let before;
|
|
42
|
+
try {
|
|
43
|
+
before = fs.lstatSync(file);
|
|
44
|
+
} catch (cause) {
|
|
45
|
+
if (options.optional && cause?.code === "ENOENT") return null;
|
|
46
|
+
throw securityError(
|
|
47
|
+
"CC_SKILL_COMPONENT_UNAVAILABLE",
|
|
48
|
+
`Skill component is unavailable: ${path.basename(file)}`,
|
|
49
|
+
{ cause },
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (before.isSymbolicLink() || !before.isFile()) {
|
|
53
|
+
throw securityError(
|
|
54
|
+
"CC_SKILL_COMPONENT_UNSAFE",
|
|
55
|
+
`Skill component must be a regular, non-symlink file: ${path.basename(file)}`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const bytes = fs.readFileSync(file);
|
|
60
|
+
const after = fs.lstatSync(file);
|
|
61
|
+
if (
|
|
62
|
+
before.size !== after.size ||
|
|
63
|
+
before.mtimeMs !== after.mtimeMs ||
|
|
64
|
+
before.ino !== after.ino
|
|
65
|
+
) {
|
|
66
|
+
throw securityError(
|
|
67
|
+
"CC_SKILL_SNAPSHOT_RACE",
|
|
68
|
+
`Skill component changed while its identity was being captured: ${path.basename(file)}`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return Object.freeze({
|
|
72
|
+
bytes,
|
|
73
|
+
size: bytes.length,
|
|
74
|
+
digest: sha256([bytes]),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Capture the exact files the legacy runtime could execute or interpret.
|
|
80
|
+
* SKILL.md covers frontmatter, instructions, and embedded MCP declarations;
|
|
81
|
+
* handler.js covers the only handler path used by current CLI dispatch.
|
|
82
|
+
*/
|
|
83
|
+
export function captureSkillExecutionSnapshot(options = {}) {
|
|
84
|
+
if (!options.skillDir) {
|
|
85
|
+
throw new TypeError("captureSkillExecutionSnapshot requires skillDir");
|
|
86
|
+
}
|
|
87
|
+
const rootRealPath = canonicalRealPath(options.skillDir);
|
|
88
|
+
const skillMdPath = path.join(rootRealPath, "SKILL.md");
|
|
89
|
+
const handlerPath = path.join(rootRealPath, "handler.js");
|
|
90
|
+
const skillMd = readStableRegularFile(skillMdPath);
|
|
91
|
+
const handler = readStableRegularFile(handlerPath, { optional: true });
|
|
92
|
+
const skillId = String(options.skillId || path.basename(rootRealPath));
|
|
93
|
+
const source = String(options.source || "unknown");
|
|
94
|
+
const identityDigest = sha256([
|
|
95
|
+
`skill-execution-identity-v${SKILL_EXECUTION_IDENTITY_VERSION}`,
|
|
96
|
+
source,
|
|
97
|
+
skillId,
|
|
98
|
+
rootRealPath,
|
|
99
|
+
]);
|
|
100
|
+
const contentDigest = sha256([
|
|
101
|
+
`skill-execution-content-v${SKILL_EXECUTION_IDENTITY_VERSION}`,
|
|
102
|
+
"SKILL.md",
|
|
103
|
+
skillMd.digest,
|
|
104
|
+
"handler.js",
|
|
105
|
+
handler?.digest || "absent",
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
return Object.freeze({
|
|
109
|
+
schemaVersion: SKILL_EXECUTION_IDENTITY_VERSION,
|
|
110
|
+
identityDigest,
|
|
111
|
+
contentDigest,
|
|
112
|
+
rootRealPath,
|
|
113
|
+
handlerPresent: handler !== null,
|
|
114
|
+
skillFileBytes: skillMd.size,
|
|
115
|
+
componentDigests: Object.freeze({
|
|
116
|
+
"SKILL.md": skillMd.digest,
|
|
117
|
+
"handler.js": handler?.digest || null,
|
|
118
|
+
}),
|
|
119
|
+
// Kept only in the short-lived verification snapshot. Callers must store
|
|
120
|
+
// executionIdentityMetadata(snapshot), never this content-bearing object.
|
|
121
|
+
skillMdContent: skillMd.bytes.toString("utf8"),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Produce the content-free descriptor safe to retain in loader caches. */
|
|
126
|
+
export function executionIdentityMetadata(snapshot) {
|
|
127
|
+
return Object.freeze({
|
|
128
|
+
schemaVersion: snapshot.schemaVersion,
|
|
129
|
+
identityDigest: snapshot.identityDigest,
|
|
130
|
+
contentDigest: snapshot.contentDigest,
|
|
131
|
+
rootRealPath: snapshot.rootRealPath,
|
|
132
|
+
handlerPresent: snapshot.handlerPresent,
|
|
133
|
+
componentDigests: Object.freeze({ ...snapshot.componentDigests }),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function describeSkillExecutionAuthority(skill = {}) {
|
|
138
|
+
const hasHandler = skill.hasHandler === true;
|
|
139
|
+
const isolated = skill.isolation === true;
|
|
140
|
+
return Object.freeze({
|
|
141
|
+
schemaVersion: SKILL_EXECUTION_IDENTITY_VERSION,
|
|
142
|
+
mode: !hasHandler
|
|
143
|
+
? "instructions-only"
|
|
144
|
+
: isolated
|
|
145
|
+
? "controlled-agent-tools"
|
|
146
|
+
: "blocked-direct-handler",
|
|
147
|
+
directHandlerAllowed: false,
|
|
148
|
+
controlledToolEntryRequired: hasHandler,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function isSkillExecutionContext(context = {}) {
|
|
153
|
+
return (
|
|
154
|
+
context.forExecution === true ||
|
|
155
|
+
EXECUTION_REASONS.has(String(context.loadedBecause || ""))
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* The only currently mediated handler-skill route is agent-core's explicit
|
|
161
|
+
* isolated-skill branch. It executes an agent loop whose tool calls re-enter
|
|
162
|
+
* host policy; it never imports handler.js. Every direct-handler route is
|
|
163
|
+
* denied until a restricted worker/RPC transport exists.
|
|
164
|
+
*/
|
|
165
|
+
export function assertControlledSkillExecution(skill, context = {}) {
|
|
166
|
+
if (!isSkillExecutionContext(context) || skill?.hasHandler !== true) {
|
|
167
|
+
return describeSkillExecutionAuthority(skill);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const reason = String(context.loadedBecause || "");
|
|
171
|
+
if (reason === "run_skill" && skill.isolation === true) {
|
|
172
|
+
return describeSkillExecutionAuthority(skill);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
throw securityError(
|
|
176
|
+
"CC_SKILL_DIRECT_HANDLER_BLOCKED",
|
|
177
|
+
`Skill "${skill.id || "unknown"}" cannot execute handler.js directly. ` +
|
|
178
|
+
"Use an isolated agent/tool route so every external call re-enters host policy.",
|
|
179
|
+
{ skillId: skill.id },
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function skillDigestDriftError(skill, previousDigest, currentDigest) {
|
|
184
|
+
return securityError(
|
|
185
|
+
"CC_SKILL_DIGEST_DRIFT",
|
|
186
|
+
`Skill "${skill.id || "unknown"}" changed after discovery and was not reauthorized.`,
|
|
187
|
+
{
|
|
188
|
+
skillId: skill.id,
|
|
189
|
+
previousDigest,
|
|
190
|
+
currentDigest,
|
|
191
|
+
},
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function skillIdentityChangedError(skill) {
|
|
196
|
+
return securityError(
|
|
197
|
+
"CC_SKILL_IDENTITY_CHANGED",
|
|
198
|
+
`Skill "${skill.id || "unknown"}" changed identity after discovery; reload the skill registry before use.`,
|
|
199
|
+
{ skillId: skill.id },
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function skillReauthorizationError(skill, cause) {
|
|
204
|
+
return securityError(
|
|
205
|
+
"CC_SKILL_REAUTHORIZE_FAILED",
|
|
206
|
+
`Skill "${skill.id || "unknown"}" digest reauthorization failed.`,
|
|
207
|
+
{ skillId: skill.id, cause },
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function skillTrustRequiredError(skill) {
|
|
212
|
+
return securityError(
|
|
213
|
+
"CC_SKILL_TRUST_REQUIRED",
|
|
214
|
+
`Skill "${skill.id || "unknown"}" requires host authorization for its current source and content digest before first execution.`,
|
|
215
|
+
{ skillId: skill.id },
|
|
216
|
+
);
|
|
217
|
+
}
|