chainlesschain 0.166.77 → 0.166.79
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 +9 -8
- package/completions/_cc +1 -1
- package/completions/cc.bash +1 -1
- package/completions/cc.fish +1 -1
- package/completions/cc.ps1 +1 -1
- package/package.json +1 -1
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +10 -0
- package/src/assets/linux-subreaper/linux-arm64/supervisor +0 -0
- package/src/assets/linux-subreaper/linux-x64/manifest.json +10 -0
- package/src/assets/linux-subreaper/linux-x64/supervisor +0 -0
- package/src/assets/web-panel/assets/{AIOps-CpiCBhRh.js → AIOps-CwD6Pm_Y.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CnU-Xvx-.js → ActionButton-Du5Rp-O6.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BJW-CNtf.js → Analytics-DY9l72ma.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-UFQJL3G9.js → AppLayout-7t1WIaCJ.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-Dr_IUDoY.js → Artifacts-BLIA5yny.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-aglWo6rr.js → Audit-BC_N0QTg.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-Dm_TCiXC.js → BackgroundAgents-CA7SxDtg.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DUdX4-gA.js → Backup-BZ4AzS1_.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BTcLjy1o.js → BaseInput-BhiggGaH.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-Bhy9qZrl.js → Chat-CDdBoIBI.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-hsBsrl31.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-CblrPa21.js → Checkbox-asoMKSEK.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-SEAHzOlr.js → Codegen-B0gElLdm.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DJz8iFOR.js → Col-DrNzLpF6.js} +1 -1
- package/src/assets/web-panel/assets/{Community-RufKhcQt.js → Community-DCzB5qkI.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Dlifx08U.js → Compact-Db-Eua_j.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DdhQWcHh.js → Compliance-B76NByjl.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BLNn6oOm.js → Cowork-C-nK6Qpk.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-Dv-JWY2d.js → Cron-C-GlQO19.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-k7Pz7O-b.js → Crosschain-Cuuz9IIh.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C_10syUW.js → DID-gwFaT973.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CMyH6Szx.js → Dashboard-DHDt5jEf.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DjmD2Saa.js → Dropdown-CJ9kog-Y.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-36_IRUSo.js → EmailListRenderer-DOSXFRiQ.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-CmtU0XmM.js → EvolutionSettings-CHYMP7rR.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DEgf9kyP.js → FamilyGuardDashboard-C1gzG5EK.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DGO1wQls.js → Federation-CEdNVWUw.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Doj1FmKW.js → FormItemContext-CwVOWPX8.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-GzOU27iT.js → GenericCardRenderer-CgNUs3kT.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Dd7D1EDK.js → Git-DM4MNnQo.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-6IY8LcjI.js → Governance-DdOtjkvd.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BB9gl8q1.js → Inference-28PidFfr.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CeCed5wd.js → KnowledgeGraph-Bpj_qNUK.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CYOeHuaI.js → Logs-C6Ix19Ay.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-Bk8Zqc2R.js → MarkdownRenderer-Bj6mtPbf.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-D-_xgHgM.js → Marketplace-DqkhRSMP.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-NnaUTF5t.js → McpTools-1WQ2SjaE.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CndN9pMt.js → Memory-BWTi7v6R.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BXblFmhY.js → MobileBridge-DB4wu3UE.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CC26Dm2k.js → MobileProjects-Bh9pWx2f.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BhaqWCiW.js → Mtc-BVF1Wrno.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-D6fktM2w.js → MtcAudit-DtNfslPf.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-CFvahz7s.js → Multisig-4qcXP0bf.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Co73Ivya.js → NLProgramming-BRJl5Ehw.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-B4g33L1o.js → Notes-BRY_bgMk.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-lXd17EbN.js → NotificationSettings-DirXMFz4.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BiOB0GIi.js → OrderTableRenderer-BlrY8lwu.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-JQ7_wQIA.js → Organization-CVzQ1vO-.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-gwgJgozQ.js → Overflow-A3rXTPG4.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-D9L_0gie.js → P2P-Db9ABWz0.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CbOPsFE9.js → PdhVaultBrowser-CPv0H2OZ.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-Cz42HNQf.js → Permissions-COnW4sIR.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-DjorYtrF.js → PersonalDataHub-C1hG7rp7.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-DyWPhmm5.js → Pipeline---GLRDEe.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DyfLMl2j.js → Privacy-aaN9R3Lu.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CyqDx1OE.js → ProjectInit-C-kw49hE.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DsBw0Csy.js → ProjectSettings-y5tTkBTC.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DZHlhyPB.js +1 -0
- package/src/assets/web-panel/assets/{Providers-CCI_klN-.js → Providers-LqxnV72o.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DNsnlDdS.js → QrScannerModal-D_q-Y5F0.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-B9r2iaee.js → QuickAsk-_E_KB5o8.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BJDe03GR.js → Recommend-BN8S5WJA.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-J7JR3rRo.js → RemoteSession-BFzrY_aW.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-DR39AJeV.js → Reputation-C1HCLaTV.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Dh77m3NZ.js → Row-B8T2-Qv7.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BUdg28nJ.js → RssFeed-CNQLk8v1.js} +3 -3
- package/src/assets/web-panel/assets/{Search-BNC7sGhj.js → Search-BOx720Kc.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DISENGI7.js → Security-Ds8z6PF6.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BBBGpJ1-.js → Services-C0-YkRSF.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DMcIoIv2.js → Skeleton-DUHlSySD.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-QAyFbI3r.js → Skills-C8CBbbh0.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CSg5wLH7.js → Sla-lQltyYfB.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DMPxTc5x.js → SpeechSettings-B5vyOma-.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CPG7l30y.js → SyncSettings-BKDPu_y-.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Y1kOVvVL.js → Tasks-Bgvf7LTx.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-jt9NagL0.js → Templates-BMZyYYS7.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DauuJICx.js → Tenant-7PYTig8f.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-E9rnKeGq.js → Terminal-C2W0LMdR.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-Cc7z2APG.js → TimelineRenderer-CqREew_l.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CV0UthRA.js → Tokens-BhTyxTuD.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BFcJJGfu.js → Trigger-DxNSSZy_.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BAydbNJA.js → Trust-Dy_wfbIh.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DcOS6sqL.js → UkeySign-DJC5ANqx.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BLHJZvif.js → VideoEditing-CNFevrO4.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-4QFLKHwW.js → Wallet-CXzuS1YK.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BocEOOSj.js → WebAuthn-BWS6HP8c.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-DCfF7D0B.js → WorkflowEditor-swiN_7Vj.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CxvfsYGr.js → chat-NwH7qlBs.js} +1 -1
- package/src/assets/web-panel/assets/{colors-KtQB9DmQ.js → colors-h6nRhBTw.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Dx4J6arN.js → compact-item-BQ6B6rP2.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Cq0olgzo.js → createContext-CQkJuRcG.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Bz6vqBGV.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Bf9-h3D-.js → hasIn-Diwl1WyI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpO6DKuu.js → index-0ZztPzIm.js} +1 -1
- package/src/assets/web-panel/assets/index-1b7DEw-w.js +1 -0
- package/src/assets/web-panel/assets/{index-DQDR-_ai.js → index-AzeSQJDK.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMcC4cbj.js → index-B3QgcUBV.js} +1 -1
- package/src/assets/web-panel/assets/{index-BO6XvO-C.js → index-B5gj_uCC.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClUfSChI.js → index-BI3ALCgN.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3xfiItB.js → index-BRl3KUj0.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFdEDvFn.js → index-BYYb8oeV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqnggDos.js → index-BcKDUGYf.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_8UcDan.js → index-BcjlIMP9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmQuG0fr.js → index-BheCvudN.js} +1 -1
- package/src/assets/web-panel/assets/{index-iE9tqEN5.js → index-BjcARUtr.js} +1 -1
- package/src/assets/web-panel/assets/{index-nmyDOh_b.js → index-BnQUin2K.js} +1 -1
- package/src/assets/web-panel/assets/{index-Br1mDMfO.js → index-Bs6HyCfP.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZWjYfWt.js → index-BvPz6vZ8.js} +1 -1
- package/src/assets/web-panel/assets/{index-0fi8DIVQ.js → index-C3Ye1ISy.js} +1 -1
- package/src/assets/web-panel/assets/{index-hSzyoXri.js → index-C7-T-u0L.js} +3 -3
- package/src/assets/web-panel/assets/{index-DfrFNMvz.js → index-CRWpixu2.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9yaUHm9.js → index-CatBQDSQ.js} +1 -1
- package/src/assets/web-panel/assets/index-CfD4tMuW.js +1 -0
- package/src/assets/web-panel/assets/{index-DMR-keCL.js → index-CqH-oOR3.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cy865Hhq.js → index-CwsoVDi-.js} +1 -1
- package/src/assets/web-panel/assets/{index-DI5bRqNG.js → index-CyBtEVLM.js} +1 -1
- package/src/assets/web-panel/assets/{index-gt5N6VM_.js → index-D5P498Rk.js} +1 -1
- package/src/assets/web-panel/assets/{index-6dDDSCHD.js → index-DKaB4xTf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKtQyb2o.js → index-DQYZa1Ci.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaIclw-E.js → index-DZ9CNcbJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-_FIz-0tp.js → index-DZAsByy4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBRlZdZj.js → index-D_HY0nyN.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsCdl2Od.js → index-Da8frO_A.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cfsn7N18.js → index-DjB8IC9D.js} +1 -1
- package/src/assets/web-panel/assets/{index-CeYP_kT9.js → index-Dwpthe2b.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8WuPI-h.js → index-Fm95dO4u.js} +1 -1
- package/src/assets/web-panel/assets/{index-CK2U_AHi.js → index-GTefQSbY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DnU-dUWd.js → index-OEWSrqit.js} +1 -1
- package/src/assets/web-panel/assets/{index-DDAe1UmZ.js → index-TYMmUsxZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2BfSIrn.js → index-iHNOr_wL.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cz7f4Jaq.js → index-mxxZtsHp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHmdMKYl.js → index-pYwYBVeQ.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DvzKJ6o5.js → initDefaultProps-BeUrpC_H.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D1yTvmxW.js → motion-CHW5EXt1.js} +1 -1
- package/src/assets/web-panel/assets/{move-DxtSIF8K.js → move-CWaoWJvF.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BDsQgIHY.js → mtc-parser-CEC6Us1u.js} +1 -1
- package/src/assets/web-panel/assets/{omit-UVBJW8kh.js → omit-1D-kP_Qj.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-D4QqtTyX.js → pickAttrs-CsS0myLl.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-QXmu6vBf.js → placementArrow-bMThOvkI.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-D-PmXO9M.js → responsiveObserve-B72knbW8.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CKbGxEZJ.js → slide-C3bI_2yy.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BbgXPkXm.js → statusUtils-0-FmcCAS.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DOr9rk68.js → styleChecker-DXUyqoWY.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-B2wO2r36.js → useFlexGapSupport-BSSnL3f1.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-SeVGBK34.js → useFs-B0Cvvl0S.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DUJBCxjD.js → usePersonalDataHub-6D-d4WU5.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CF4EYsig.js → vnode-zjIrlxT_.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-pRUs5pqI.js → zoom-Hw7NEisu.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +1 -1
- package/src/command-manifest.json +1 -1
- package/src/commands/checkpoint.js +42 -7
- package/src/commands/orchestrate.js +85 -25
- package/src/commands/session-location.js +5 -0
- package/src/commands/session-show.js +109 -1
- package/src/commands/session.js +26 -2
- package/src/commands/tokens.js +9 -4
- package/src/data/changelog.json +26 -0
- package/src/generated/cc-agent-protocol.schema.json +71 -0
- package/src/harness/jsonl-session-store.js +357 -114
- package/src/harness/mcp-client.js +44 -1
- package/src/lib/agent-router.js +35 -7
- package/src/lib/agent-sandbox.js +302 -2
- package/src/lib/app-server/server.js +14 -0
- package/src/lib/background-agent-supervisor.js +14 -4
- package/src/lib/causal-observability.js +64 -1
- package/src/lib/checkpoint-summary-projection.js +98 -0
- package/src/lib/checkpoint-timeline-authority.js +15 -51
- package/src/lib/claude-code-bridge.js +302 -60
- package/src/lib/codex-app-server-adapter.js +161 -35
- package/src/lib/cost-budget.js +4 -0
- package/src/lib/doctor-checkup.js +31 -2
- package/src/lib/durable-security-store.js +6 -1
- package/src/lib/evolution/evolution-artifact-identity.js +21 -0
- package/src/lib/evolution/evolution-artifact-ports.js +5 -11
- package/src/lib/evolution/evolution-eval-cohort-receipt-reconciliation.js +389 -0
- package/src/lib/execution-location-failure-site.js +63 -0
- package/src/lib/execution-location-target.js +102 -8
- package/src/lib/external-agent-adapters.js +2 -0
- package/src/lib/image-file-boundary.js +154 -0
- package/src/lib/image-input.js +16 -3
- package/src/lib/llm-pricing.js +114 -8
- package/src/lib/lsp/code-intelligence.js +7 -1
- package/src/lib/mcp-call-ledger-store.js +7 -2
- package/src/lib/model-capabilities.js +21 -10
- package/src/lib/model-context-catalog.js +60 -1
- package/src/lib/openai-responses.js +7 -1
- package/src/lib/orchestrator.js +8 -2
- package/src/lib/process-execution-broker/index.js +93 -1
- package/src/lib/process-execution-broker/linux-subreaper-artifact.js +120 -0
- package/src/lib/process-execution-broker/linux-subreaper-helper.js +344 -0
- package/src/lib/process-execution-broker/linux-subreaper-process.js +326 -0
- package/src/lib/process-execution-broker/linux-subreaper-supervisor.c +360 -0
- package/src/lib/process-execution-broker/owned-posix-process-group-worker.mjs +131 -0
- package/src/lib/process-execution-broker/owned-posix-process-group.js +267 -0
- package/src/lib/process-execution-broker/process-ownership-journal.js +297 -0
- package/src/lib/process-execution-broker/process-ownership-quarantine.js +91 -0
- package/src/lib/runtime-usage-ledger.js +3 -0
- package/src/lib/sandbox-docker-egress.js +507 -0
- package/src/lib/sandbox-egress-proxy.js +167 -10
- package/src/lib/sandbox-egress-worker-thread.js +38 -0
- package/src/lib/sandbox-egress-worker.js +196 -0
- package/src/lib/secure-fs.js +158 -42
- package/src/lib/session-branch-history.js +240 -0
- package/src/lib/session-history-origins.js +285 -0
- package/src/lib/session-input-receipt.js +110 -0
- package/src/lib/session-resource-budget.js +8 -8
- package/src/lib/session-transcript-history.js +456 -0
- package/src/lib/session-transcript-page.js +164 -0
- package/src/lib/session-transcript-reference.js +38 -0
- package/src/lib/session-usage.js +8 -0
- package/src/lib/token-tracker.js +32 -54
- package/src/lib/usage-pricing-context.js +93 -0
- package/src/runtime/agent-core.js +141 -21
- package/src/runtime/headless-stream.js +202 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-D0WrJQaQ.js +0 -1
- package/src/assets/web-panel/assets/Projects-CRaSI25Z.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CmgDNkoO.js +0 -1
- package/src/assets/web-panel/assets/index-BpIZ2S01.js +0 -1
- package/src/assets/web-panel/assets/index-C-VmKuyv.js +0 -1
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/** Join a sealed admission inventory to presented final Eval receipts.
|
|
2
|
+
* Missing receipts stay unresolved; a caller-supplied set cannot prove global coverage.
|
|
3
|
+
*/
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import { isProxy } from "node:util/types";
|
|
6
|
+
import {
|
|
7
|
+
resolveEvolutionEvalCohortEnrollment,
|
|
8
|
+
resolveEvolutionEvalCohortReconciliation,
|
|
9
|
+
} from "./evolution-eval-cohort-enrollment.js";
|
|
10
|
+
import {
|
|
11
|
+
computeEvolutionEvalContextDigest,
|
|
12
|
+
computeEvolutionEvalLaunchRequestDigest,
|
|
13
|
+
isEvolutionEvalReceiptVerifier,
|
|
14
|
+
verifyEvolutionEvalReceipt,
|
|
15
|
+
} from "./evolution-eval-gate.js";
|
|
16
|
+
import { verifyPmExplorationEffectAttemptCohort } from "./pm-exploration-benchmark.js";
|
|
17
|
+
|
|
18
|
+
export const EVOLUTION_EVAL_COHORT_RECEIPT_RECONCILIATION_SCHEMA =
|
|
19
|
+
"chainlesschain.evolution-eval-cohort-receipt-reconciliation/v1";
|
|
20
|
+
export const EVOLUTION_EVAL_COHORT_RECEIPT_RECONCILIATION_FAILED_CODE =
|
|
21
|
+
"CC_EVOLUTION_EVAL_COHORT_RECEIPT_RECONCILIATION_FAILED";
|
|
22
|
+
export const PM_EXPLORATION_ADMISSION_BOUND_COHORT_SCHEMA =
|
|
23
|
+
"chainlesschain.pm-exploration-admission-bound-cohort/v1";
|
|
24
|
+
|
|
25
|
+
function fail(message) {
|
|
26
|
+
const error = new Error(message);
|
|
27
|
+
error.code = EVOLUTION_EVAL_COHORT_RECEIPT_RECONCILIATION_FAILED_CODE;
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function snapshot(value, budget = { nodes: 0, chars: 0 }, depth = 0) {
|
|
32
|
+
if (++budget.nodes > 50_000 || depth > 50)
|
|
33
|
+
fail("cohort receipt evidence exceeds structural limits");
|
|
34
|
+
if (value === null || typeof value === "boolean") return value;
|
|
35
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
36
|
+
if (typeof value === "string") {
|
|
37
|
+
budget.chars += value.length;
|
|
38
|
+
if (budget.chars > 4_000_000)
|
|
39
|
+
fail("cohort receipt evidence exceeds size limit");
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
if (!value || typeof value !== "object" || isProxy(value))
|
|
43
|
+
fail("cohort receipt evidence must contain plain JSON data");
|
|
44
|
+
if (Array.isArray(value)) {
|
|
45
|
+
if (
|
|
46
|
+
Object.getPrototypeOf(value) !== Array.prototype ||
|
|
47
|
+
Reflect.ownKeys(value).length !== value.length + 1
|
|
48
|
+
)
|
|
49
|
+
fail("cohort receipt array must be dense own data");
|
|
50
|
+
return Array.from({ length: value.length }, (_, index) => {
|
|
51
|
+
const property = Object.getOwnPropertyDescriptor(value, String(index));
|
|
52
|
+
if (!property || !("value" in property))
|
|
53
|
+
fail("cohort receipt array must be own data");
|
|
54
|
+
return snapshot(property.value, budget, depth + 1);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (![Object.prototype, null].includes(Object.getPrototypeOf(value)))
|
|
58
|
+
fail("cohort receipt evidence must be plain data");
|
|
59
|
+
return Object.fromEntries(
|
|
60
|
+
Reflect.ownKeys(value).map((key) => {
|
|
61
|
+
const property = Object.getOwnPropertyDescriptor(value, key);
|
|
62
|
+
if (
|
|
63
|
+
typeof key !== "string" ||
|
|
64
|
+
!property?.enumerable ||
|
|
65
|
+
!("value" in property)
|
|
66
|
+
)
|
|
67
|
+
fail("cohort receipt fields must be own data");
|
|
68
|
+
budget.chars += key.length;
|
|
69
|
+
if (budget.chars > 4_000_000)
|
|
70
|
+
fail("cohort receipt evidence exceeds size limit");
|
|
71
|
+
return [key, snapshot(property.value, budget, depth + 1)];
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function exact(value, keys, label) {
|
|
77
|
+
if (
|
|
78
|
+
!value ||
|
|
79
|
+
Array.isArray(value) ||
|
|
80
|
+
typeof value !== "object" ||
|
|
81
|
+
Reflect.ownKeys(value).length !== keys.length ||
|
|
82
|
+
keys.some((key) => !Object.hasOwn(value, key))
|
|
83
|
+
)
|
|
84
|
+
fail(`${label} must contain exactly its registered fields`);
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function captureRecord(value, keys, label) {
|
|
89
|
+
if (
|
|
90
|
+
!value ||
|
|
91
|
+
Array.isArray(value) ||
|
|
92
|
+
typeof value !== "object" ||
|
|
93
|
+
isProxy(value) ||
|
|
94
|
+
![Object.prototype, null].includes(Object.getPrototypeOf(value)) ||
|
|
95
|
+
Reflect.ownKeys(value).length !== keys.length
|
|
96
|
+
)
|
|
97
|
+
fail(`${label} must contain exactly its own data fields`);
|
|
98
|
+
return Object.fromEntries(
|
|
99
|
+
keys.map((key) => {
|
|
100
|
+
const property = Object.getOwnPropertyDescriptor(value, key);
|
|
101
|
+
if (!property?.enumerable || !("value" in property))
|
|
102
|
+
fail(`${label} must contain exactly its own data fields`);
|
|
103
|
+
return [key, property.value];
|
|
104
|
+
}),
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function canonical(value) {
|
|
109
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
110
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
111
|
+
return `{${Object.keys(value)
|
|
112
|
+
.sort()
|
|
113
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
114
|
+
.join(",")}}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function hash(
|
|
118
|
+
value,
|
|
119
|
+
schema = EVOLUTION_EVAL_COHORT_RECEIPT_RECONCILIATION_SCHEMA,
|
|
120
|
+
) {
|
|
121
|
+
return `sha256:${createHash("sha256")
|
|
122
|
+
.update(`${schema}\0${canonical(value)}`)
|
|
123
|
+
.digest("hex")}`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function frozen(value) {
|
|
127
|
+
if (value && typeof value === "object") {
|
|
128
|
+
for (const child of Object.values(value)) frozen(child);
|
|
129
|
+
Object.freeze(value);
|
|
130
|
+
}
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Re-audit the sealed admission set after signature checks. */
|
|
135
|
+
export async function reconcileEvolutionEvalCohortReceipts(
|
|
136
|
+
authority,
|
|
137
|
+
verifier,
|
|
138
|
+
input,
|
|
139
|
+
) {
|
|
140
|
+
if (!isEvolutionEvalReceiptVerifier(verifier))
|
|
141
|
+
fail("a branded final Eval receipt verifier is required");
|
|
142
|
+
const source = exact(
|
|
143
|
+
snapshot(input),
|
|
144
|
+
["cohortId", "slots"],
|
|
145
|
+
"cohort receipt source",
|
|
146
|
+
);
|
|
147
|
+
if (
|
|
148
|
+
typeof source.cohortId !== "string" ||
|
|
149
|
+
!Array.isArray(source.slots) ||
|
|
150
|
+
source.slots.length > 32
|
|
151
|
+
)
|
|
152
|
+
fail("cohort receipt slots are invalid");
|
|
153
|
+
const lookup = { cohortId: source.cohortId };
|
|
154
|
+
const enrollment = resolveEvolutionEvalCohortEnrollment(authority, lookup);
|
|
155
|
+
const sealed = await resolveEvolutionEvalCohortReconciliation(
|
|
156
|
+
authority,
|
|
157
|
+
lookup,
|
|
158
|
+
);
|
|
159
|
+
if (source.slots.length !== enrollment.evidence.slots.length)
|
|
160
|
+
fail("cohort receipt source must cover every enrolled slot");
|
|
161
|
+
const admitted = new Map(
|
|
162
|
+
sealed.inventory.admissions.map((entry) => [entry.slotId, entry]),
|
|
163
|
+
);
|
|
164
|
+
const slots = [];
|
|
165
|
+
let signedReceiptCount = 0;
|
|
166
|
+
let receiptUnavailableCount = 0;
|
|
167
|
+
for (const [index, item] of source.slots.entries()) {
|
|
168
|
+
const entry = exact(
|
|
169
|
+
item,
|
|
170
|
+
["slotId", "launchRequest", "receipt", "receiptContext"],
|
|
171
|
+
"cohort receipt slot",
|
|
172
|
+
);
|
|
173
|
+
const registered = enrollment.evidence.slots[index];
|
|
174
|
+
if (entry.slotId !== registered.slotId)
|
|
175
|
+
fail("cohort receipt slots differ from enrolled order");
|
|
176
|
+
const admission = admitted.get(entry.slotId);
|
|
177
|
+
if (entry.receipt === null) {
|
|
178
|
+
if (entry.launchRequest !== null || entry.receiptContext !== null)
|
|
179
|
+
fail("missing receipt cannot carry a substituted source");
|
|
180
|
+
if (admission) receiptUnavailableCount += 1;
|
|
181
|
+
slots.push({
|
|
182
|
+
slotId: entry.slotId,
|
|
183
|
+
status: admission ? "receipt-unavailable" : "unadmitted",
|
|
184
|
+
admissionDigest: admission?.admissionDigest ?? null,
|
|
185
|
+
runId: admission?.runId ?? null,
|
|
186
|
+
receiptDigest: null,
|
|
187
|
+
decision: null,
|
|
188
|
+
});
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (!admission || !entry.launchRequest || !entry.receiptContext)
|
|
192
|
+
fail("signed receipt has no matching admitted slot or context");
|
|
193
|
+
const request = exact(
|
|
194
|
+
entry.launchRequest,
|
|
195
|
+
[
|
|
196
|
+
"suiteRef",
|
|
197
|
+
"candidateId",
|
|
198
|
+
"baselineId",
|
|
199
|
+
"targetEnvironmentRef",
|
|
200
|
+
"evaluationContext",
|
|
201
|
+
],
|
|
202
|
+
"cohort launch request",
|
|
203
|
+
);
|
|
204
|
+
const context = exact(
|
|
205
|
+
entry.receiptContext,
|
|
206
|
+
[
|
|
207
|
+
"runId",
|
|
208
|
+
"runNonce",
|
|
209
|
+
"suiteDigest",
|
|
210
|
+
"policyDigest",
|
|
211
|
+
"evaluationAuthorityRoot",
|
|
212
|
+
"targetEnvironmentRef",
|
|
213
|
+
"evaluationContextDigest",
|
|
214
|
+
"candidateId",
|
|
215
|
+
"baselineId",
|
|
216
|
+
"environmentDigest",
|
|
217
|
+
"tenantId",
|
|
218
|
+
"provenanceAudience",
|
|
219
|
+
"trainerAuthority",
|
|
220
|
+
"trainerRevision",
|
|
221
|
+
],
|
|
222
|
+
"cohort receipt context",
|
|
223
|
+
);
|
|
224
|
+
const run = exact(
|
|
225
|
+
request.evaluationContext,
|
|
226
|
+
["planDigest", "targetMatrixRoot", "cellId", "runtimeId"],
|
|
227
|
+
"cohort evaluation context",
|
|
228
|
+
);
|
|
229
|
+
if (
|
|
230
|
+
computeEvolutionEvalLaunchRequestDigest(request) !==
|
|
231
|
+
admission.requestDigest ||
|
|
232
|
+
run.planDigest !== registered.evaluationPlanDigest ||
|
|
233
|
+
run.cellId !== entry.slotId ||
|
|
234
|
+
request.candidateId !== context.candidateId ||
|
|
235
|
+
request.baselineId !== context.baselineId ||
|
|
236
|
+
request.targetEnvironmentRef !== context.targetEnvironmentRef ||
|
|
237
|
+
context.runId !== admission.runId ||
|
|
238
|
+
context.runNonce !== admission.runNonce ||
|
|
239
|
+
context.tenantId !== enrollment.evidence.descriptor.tenantId ||
|
|
240
|
+
context.policyDigest !== registered.policyDigest ||
|
|
241
|
+
context.evaluationAuthorityRoot !== registered.evaluationAuthorityRoot ||
|
|
242
|
+
context.evaluationContextDigest !==
|
|
243
|
+
computeEvolutionEvalContextDigest({
|
|
244
|
+
...run,
|
|
245
|
+
tenantId: context.tenantId,
|
|
246
|
+
targetEnvironmentRef: context.targetEnvironmentRef,
|
|
247
|
+
environmentDigest: context.environmentDigest,
|
|
248
|
+
candidateId: context.candidateId,
|
|
249
|
+
baselineId: context.baselineId,
|
|
250
|
+
suiteDigest: context.suiteDigest,
|
|
251
|
+
policyDigest: context.policyDigest,
|
|
252
|
+
evaluationAuthorityRoot: context.evaluationAuthorityRoot,
|
|
253
|
+
})
|
|
254
|
+
)
|
|
255
|
+
fail("signed receipt differs from admitted request or enrolled cell");
|
|
256
|
+
const verified = await verifyEvolutionEvalReceipt(
|
|
257
|
+
verifier,
|
|
258
|
+
entry.receipt,
|
|
259
|
+
context,
|
|
260
|
+
);
|
|
261
|
+
signedReceiptCount += 1;
|
|
262
|
+
slots.push({
|
|
263
|
+
slotId: entry.slotId,
|
|
264
|
+
status: "signed-receipt",
|
|
265
|
+
admissionDigest: admission.admissionDigest,
|
|
266
|
+
runId: admission.runId,
|
|
267
|
+
receiptDigest: verified.receiptDigest,
|
|
268
|
+
decision: verified.decision,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
const finalSeal = await resolveEvolutionEvalCohortReconciliation(
|
|
272
|
+
authority,
|
|
273
|
+
lookup,
|
|
274
|
+
);
|
|
275
|
+
if (canonical(finalSeal) !== canonical(sealed))
|
|
276
|
+
fail("sealed Ledger inventory changed during receipt verification");
|
|
277
|
+
const core = {
|
|
278
|
+
schema: EVOLUTION_EVAL_COHORT_RECEIPT_RECONCILIATION_SCHEMA,
|
|
279
|
+
cohortId: source.cohortId,
|
|
280
|
+
enrollmentDigest: sealed.enrollmentDigest,
|
|
281
|
+
sealDigest: sealed.sealDigest,
|
|
282
|
+
admissionInventoryAuthenticated: true,
|
|
283
|
+
signedReceiptCount,
|
|
284
|
+
receiptUnavailableCount,
|
|
285
|
+
unadmittedSlotCount: sealed.inventory.unadmittedSlotIds.length,
|
|
286
|
+
slots,
|
|
287
|
+
presentedReceiptsAuthenticated: true,
|
|
288
|
+
receiptSetCompletenessAuthenticated: false,
|
|
289
|
+
executionCoverageAuthenticated: false,
|
|
290
|
+
cohortCompletenessAuthenticated: false,
|
|
291
|
+
promotionAuthority: false,
|
|
292
|
+
};
|
|
293
|
+
return frozen({ ...core, reconciliationDigest: hash(core) });
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/** Bind the independently verified PM denominator to the signed admission/receipt census. */
|
|
297
|
+
export async function reconcilePmExplorationAdmissionBoundCohort(
|
|
298
|
+
authority,
|
|
299
|
+
verifier,
|
|
300
|
+
input,
|
|
301
|
+
) {
|
|
302
|
+
if (!isEvolutionEvalReceiptVerifier(verifier))
|
|
303
|
+
fail("a branded final Eval receipt verifier is required");
|
|
304
|
+
const source = captureRecord(
|
|
305
|
+
input,
|
|
306
|
+
["cohortId", "receiptSlots", "cohortSource", "cohort", "registration"],
|
|
307
|
+
"PM admission-bound cohort source",
|
|
308
|
+
);
|
|
309
|
+
const receiptSlots = snapshot(source.receiptSlots);
|
|
310
|
+
const registration = exact(
|
|
311
|
+
snapshot(source.registration),
|
|
312
|
+
["cohortId", "planDigest", "slots"],
|
|
313
|
+
"PM cohort registration",
|
|
314
|
+
);
|
|
315
|
+
// This verifier snapshots its source and expected context before its first await.
|
|
316
|
+
const pm = await verifyPmExplorationEffectAttemptCohort(
|
|
317
|
+
verifier,
|
|
318
|
+
{ source: source.cohortSource, cohort: source.cohort },
|
|
319
|
+
registration,
|
|
320
|
+
);
|
|
321
|
+
const joined = await reconcileEvolutionEvalCohortReceipts(
|
|
322
|
+
authority,
|
|
323
|
+
verifier,
|
|
324
|
+
{ cohortId: source.cohortId, slots: receiptSlots },
|
|
325
|
+
);
|
|
326
|
+
const enrollment = resolveEvolutionEvalCohortEnrollment(authority, {
|
|
327
|
+
cohortId: source.cohortId,
|
|
328
|
+
});
|
|
329
|
+
if (
|
|
330
|
+
pm.cohortId !== source.cohortId ||
|
|
331
|
+
registration.cohortId !== source.cohortId ||
|
|
332
|
+
pm.planDigest !== enrollment.evidence.plan.planDigest ||
|
|
333
|
+
registration.planDigest !== pm.planDigest ||
|
|
334
|
+
pm.registeredSlotCount !== enrollment.evidence.manifest.slotIds.length ||
|
|
335
|
+
pm.perArmDenominator !==
|
|
336
|
+
enrollment.evidence.manifest.plannedTestObservationsPerArm ||
|
|
337
|
+
canonical(registration.slots.map((slot) => slot.slotId)) !==
|
|
338
|
+
canonical(enrollment.evidence.manifest.slotIds)
|
|
339
|
+
)
|
|
340
|
+
fail("PM denominator differs from signed cohort enrollment");
|
|
341
|
+
for (const [index, attempt] of pm.attempts.entries()) {
|
|
342
|
+
const admitted = joined.slots[index];
|
|
343
|
+
if (
|
|
344
|
+
attempt.slotId !== admitted.slotId ||
|
|
345
|
+
(admitted.status === "signed-receipt" &&
|
|
346
|
+
(attempt.kind === "receipt-unavailable" ||
|
|
347
|
+
attempt.runId !== admitted.runId ||
|
|
348
|
+
attempt.receiptDigest !== admitted.receiptDigest)) ||
|
|
349
|
+
(admitted.status !== "signed-receipt" &&
|
|
350
|
+
(attempt.kind !== "receipt-unavailable" ||
|
|
351
|
+
attempt.runId !== null ||
|
|
352
|
+
attempt.receiptDigest !== null))
|
|
353
|
+
)
|
|
354
|
+
fail("PM attempt differs from its sealed admission and final receipt");
|
|
355
|
+
}
|
|
356
|
+
if (
|
|
357
|
+
pm.authenticatedAttemptCount !== joined.signedReceiptCount ||
|
|
358
|
+
(pm.missingReceiptCount ?? 0) !==
|
|
359
|
+
joined.receiptUnavailableCount + joined.unadmittedSlotCount
|
|
360
|
+
)
|
|
361
|
+
fail("PM attempt counts differ from sealed admission inventory");
|
|
362
|
+
const core = {
|
|
363
|
+
schema: PM_EXPLORATION_ADMISSION_BOUND_COHORT_SCHEMA,
|
|
364
|
+
cohortId: source.cohortId,
|
|
365
|
+
planDigest: pm.planDigest,
|
|
366
|
+
enrollmentDigest: joined.enrollmentDigest,
|
|
367
|
+
sealDigest: joined.sealDigest,
|
|
368
|
+
receiptReconciliationDigest: joined.reconciliationDigest,
|
|
369
|
+
attemptCohortDigest: pm.cohortDigest,
|
|
370
|
+
registeredSlotCount: pm.registeredSlotCount,
|
|
371
|
+
signedReceiptCount: joined.signedReceiptCount,
|
|
372
|
+
admittedMissingReceiptCount: joined.receiptUnavailableCount,
|
|
373
|
+
unadmittedSlotCount: joined.unadmittedSlotCount,
|
|
374
|
+
perArmDenominator: pm.perArmDenominator,
|
|
375
|
+
baseline: pm.baseline,
|
|
376
|
+
candidate: pm.candidate,
|
|
377
|
+
admissionAndAttemptBindingAuthenticated: true,
|
|
378
|
+
receiptSetCompletenessAuthenticated: false,
|
|
379
|
+
executionCoverageAuthenticated: false,
|
|
380
|
+
cohortCompletenessAuthenticated: false,
|
|
381
|
+
reportAuthenticated: false,
|
|
382
|
+
requiresIndependentPilotApproval: true,
|
|
383
|
+
qualifiesForPromotion: false,
|
|
384
|
+
};
|
|
385
|
+
return frozen({
|
|
386
|
+
...core,
|
|
387
|
+
bindingDigest: hash(core, PM_EXPLORATION_ADMISSION_BOUND_COHORT_SCHEMA),
|
|
388
|
+
});
|
|
389
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Diagnostic locations are public source labels, never target paths, stack
|
|
2
|
+
// text or error messages. They do not grant authority or trigger a retry.
|
|
3
|
+
const SOURCES = Object.freeze({
|
|
4
|
+
"commands/session-location.js": "session-location",
|
|
5
|
+
"harness/jsonl-session-store.js": "session-store",
|
|
6
|
+
"harness/session-index.js": "session-index",
|
|
7
|
+
"harness/transcript-integrity.js": "transcript-integrity",
|
|
8
|
+
"lib/secure-fs.js": "private-storage",
|
|
9
|
+
"lib/secure-file-identity.js": "file-identity",
|
|
10
|
+
"lib/session-anti-rollback-anchor.js": "session-anchor",
|
|
11
|
+
"lib/with-file-lock.js": "file-lock",
|
|
12
|
+
"lib/execution-location-local-supervisor.mjs": "local-supervisor",
|
|
13
|
+
"lib/execution-location-contract.js": "location-contract",
|
|
14
|
+
});
|
|
15
|
+
const LABELS = new Set(Object.values(SOURCES));
|
|
16
|
+
const PREFIX = "CC_EXECUTION_LOCATION_FAILURE_SITE=";
|
|
17
|
+
const MAX_DIAGNOSTIC_CHARS = 8192;
|
|
18
|
+
|
|
19
|
+
// PowerShell diagnostics are deliberately bounded to fixed native operation
|
|
20
|
+
// labels and HRESULTs; neither paths nor exception text cross the boundary.
|
|
21
|
+
export function readExecutionLocationStorageFailure(stderr) {
|
|
22
|
+
const match = String(stderr || "")
|
|
23
|
+
.slice(0, MAX_DIAGNOSTIC_CHARS)
|
|
24
|
+
.match(
|
|
25
|
+
/\[windows-acl:(initialize|traversal|lookup|repair-lock|repair-inspect|repair-write|verify|timeout(?:-(?:startup|initialize|traversal|lookup|repair-lock|repair-inspect|repair-write|verify))?|spawn|output)(:0x[0-9a-f]{8})?\]/u,
|
|
26
|
+
);
|
|
27
|
+
return match ? `${match[1]}${match[2] || ""}` : null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function executionLocationFailureSite(error) {
|
|
31
|
+
const stack = String(error?.stack || "").slice(0, MAX_DIAGNOSTIC_CHARS);
|
|
32
|
+
for (const frame of stack.split(/\r?\n/u).slice(1)) {
|
|
33
|
+
if (!/^\s+at /u.test(frame)) continue;
|
|
34
|
+
const normalized = frame.replaceAll("\\", "/");
|
|
35
|
+
for (const [source, label] of Object.entries(SOURCES)) {
|
|
36
|
+
const suffix = `/packages/cli/src/${source}:`;
|
|
37
|
+
const index = normalized.lastIndexOf(suffix);
|
|
38
|
+
if (index < 0) continue;
|
|
39
|
+
const position = normalized.slice(index + suffix.length);
|
|
40
|
+
const line = position.match(/^([1-9][0-9]{0,5}):[0-9]+\)?$/u)?.[1];
|
|
41
|
+
if (line) return `${label}:${line}`;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function formatExecutionLocationFailureSite(error) {
|
|
48
|
+
const site = executionLocationFailureSite(error);
|
|
49
|
+
return site === null ? "" : `${PREFIX}${site}\n`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function readExecutionLocationFailureSite(stderr) {
|
|
53
|
+
const text = String(stderr || "").slice(0, MAX_DIAGNOSTIC_CHARS);
|
|
54
|
+
for (const line of text.split(/\r?\n/u)) {
|
|
55
|
+
if (!line.startsWith(PREFIX)) continue;
|
|
56
|
+
const match = line
|
|
57
|
+
.slice(PREFIX.length)
|
|
58
|
+
.match(/^([a-z-]+):([1-9][0-9]{0,5})$/u);
|
|
59
|
+
if (match && LABELS.has(match[1])) return `${match[1]}:${match[2]}`;
|
|
60
|
+
}
|
|
61
|
+
// An uncaught supervisor exception already has a stack on stderr.
|
|
62
|
+
return executionLocationFailureSite({ stack: text });
|
|
63
|
+
}
|
|
@@ -4,6 +4,10 @@ import { tmpdir } from "node:os";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { TextDecoder } from "node:util";
|
|
7
|
+
import {
|
|
8
|
+
readExecutionLocationFailureSite,
|
|
9
|
+
readExecutionLocationStorageFailure,
|
|
10
|
+
} from "./execution-location-failure-site.js";
|
|
7
11
|
import {
|
|
8
12
|
EXECUTION_LOCATION_TARGET_ATTESTATION_SCHEMA,
|
|
9
13
|
createExecutionLocationTargetAttestation,
|
|
@@ -18,7 +22,11 @@ import {
|
|
|
18
22
|
import { canonicalJson } from "./scheduler-kernel/contract.js";
|
|
19
23
|
import { executionBroker } from "./process-execution-broker/index.js";
|
|
20
24
|
import { assertExecutionLocationRunnerLeaseAuthority } from "./execution-location-runner-lifecycle.js";
|
|
21
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
_resolveWindowsAclTimeout,
|
|
27
|
+
ensurePrivateDirectory,
|
|
28
|
+
repairPrivatePaths,
|
|
29
|
+
} from "./secure-fs.js";
|
|
22
30
|
import { getSessionAntiRollbackDirectory } from "./session-anti-rollback-anchor.js";
|
|
23
31
|
import {
|
|
24
32
|
MAX_EXECUTION_LOCATION_RESULT_BUNDLE_BYTES,
|
|
@@ -657,6 +665,11 @@ function localTargetEnvironment(profile, lifecycleEnvironment) {
|
|
|
657
665
|
// Windows. Keep all CLI state beneath a dedicated child directory.
|
|
658
666
|
CHAINLESSCHAIN_HOME: path.join(profile.transport.home, ".chainlesschain"),
|
|
659
667
|
CHAINLESSCHAIN_SECURITY_ANCHOR_HOME: profile.transport.securityHome,
|
|
668
|
+
// This numeric, bounded operation allowance is part of local storage
|
|
669
|
+
// configuration. Forward no other caller-specific environment or secrets.
|
|
670
|
+
CC_SECURE_FS_WINDOWS_ACL_TIMEOUT_MS: String(
|
|
671
|
+
_resolveWindowsAclTimeout(15_000),
|
|
672
|
+
),
|
|
660
673
|
FORCE_COLOR: "0",
|
|
661
674
|
HOME: profile.transport.home,
|
|
662
675
|
LOCALAPPDATA: path.join(profile.transport.home, "AppData", "Local"),
|
|
@@ -706,6 +719,7 @@ export function prepareLocalTargetState(profile, cliArgs, deps = {}) {
|
|
|
706
719
|
anchorBase: profile.transport.securityHome,
|
|
707
720
|
});
|
|
708
721
|
const sessionDigest = createHash("sha256").update(sessionId).digest("hex");
|
|
722
|
+
const platform = deps.platform || process.platform;
|
|
709
723
|
const directories = [
|
|
710
724
|
stateHome,
|
|
711
725
|
path.join(stateHome, "sessions"),
|
|
@@ -715,11 +729,19 @@ export function prepareLocalTargetState(profile, cliArgs, deps = {}) {
|
|
|
715
729
|
path.join(antiRollbackDirectory, "namespace"),
|
|
716
730
|
path.join(antiRollbackDirectory, "records"),
|
|
717
731
|
path.join(antiRollbackDirectory, "records", sessionDigest.slice(0, 2)),
|
|
732
|
+
// Windows known-folder APIs can return an empty path for nonexistent
|
|
733
|
+
// isolated profile directories, making first-use caches relative to cwd.
|
|
734
|
+
...(platform === "win32"
|
|
735
|
+
? [
|
|
736
|
+
path.join(profile.transport.home, "AppData"),
|
|
737
|
+
path.join(profile.transport.home, "AppData", "Local"),
|
|
738
|
+
path.join(profile.transport.home, "AppData", "Roaming"),
|
|
739
|
+
]
|
|
740
|
+
: []),
|
|
718
741
|
];
|
|
719
742
|
const uniqueDirectories = [...new Set(directories)];
|
|
720
743
|
const ensure = deps.ensurePrivateDirectory || ensurePrivateDirectory;
|
|
721
744
|
const repair = deps.repairPrivatePaths || repairPrivatePaths;
|
|
722
|
-
const platform = deps.platform || process.platform;
|
|
723
745
|
for (const directory of uniqueDirectories) {
|
|
724
746
|
ensure(
|
|
725
747
|
directory,
|
|
@@ -961,6 +983,65 @@ function targetInvocation(profile, cliArgs, deps = {}, options = {}) {
|
|
|
961
983
|
});
|
|
962
984
|
}
|
|
963
985
|
|
|
986
|
+
// Target output can contain session text, paths, or credentials. Report only
|
|
987
|
+
// a fixed diagnostic category; this is never an authorization/retry decision.
|
|
988
|
+
function targetCommandFailureCategory(result) {
|
|
989
|
+
const stderr = String(result?.stderr || "").slice(0, MAX_PROBE_BYTES);
|
|
990
|
+
if (readExecutionLocationStorageFailure(stderr)) return "windows-acl";
|
|
991
|
+
const categories = [
|
|
992
|
+
["stdin-empty", /session replica stdin is empty/u],
|
|
993
|
+
["stdin-read-unavailable", /(?:EAGAIN|EINVAL)[^\r\n]*read/u],
|
|
994
|
+
["stdin-identity", /local target stdin file (?:is invalid|changed)/u],
|
|
995
|
+
[
|
|
996
|
+
"target-facts-changed",
|
|
997
|
+
/target facts changed before location handoff append/u,
|
|
998
|
+
],
|
|
999
|
+
["filesystem-access", /\b(?:EACCES|EPERM)\b|Access is denied/iu],
|
|
1000
|
+
["filesystem-missing", /\bENOENT\b/u],
|
|
1001
|
+
["module-load", /\b(?:ERR_MODULE_NOT_FOUND|MODULE_NOT_FOUND)\b/u],
|
|
1002
|
+
[
|
|
1003
|
+
"file-identity",
|
|
1004
|
+
/(?:identity changed|pathname and descriptor identities differ|physical, non-symlink|single-link file)/u,
|
|
1005
|
+
],
|
|
1006
|
+
[
|
|
1007
|
+
"storage-integrity",
|
|
1008
|
+
/(?:[Aa]nti-rollback|[Tt]ranscript digest|[Hh]ash chain|[Aa]nchor|[Rr]eplica)[^\r\n]*(?:invalid|mismatch|failed|conflict)/u,
|
|
1009
|
+
],
|
|
1010
|
+
[
|
|
1011
|
+
"deployment-authority",
|
|
1012
|
+
/(?:authenticated evolution ingress|evolution deployment)/u,
|
|
1013
|
+
],
|
|
1014
|
+
["memory-limit", /heap out of memory|Reached heap limit/iu],
|
|
1015
|
+
];
|
|
1016
|
+
return (
|
|
1017
|
+
categories.find(([, pattern]) => pattern.test(stderr))?.[0] || "unknown"
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
function targetProcessFailure(result) {
|
|
1022
|
+
// Native spawn errors include executable paths and argv. Preserve only fixed
|
|
1023
|
+
// categories and the same content-free diagnostics as a nonzero target exit.
|
|
1024
|
+
// A timeout is an unknown outcome: this function never retries the command.
|
|
1025
|
+
const categories = new Map([
|
|
1026
|
+
["ETIMEDOUT", "process-timeout"],
|
|
1027
|
+
["ENOBUFS", "process-output-limit"],
|
|
1028
|
+
["ENOENT", "process-unavailable"],
|
|
1029
|
+
["EACCES", "process-access"],
|
|
1030
|
+
["EPERM", "process-access"],
|
|
1031
|
+
]);
|
|
1032
|
+
const failureCategory = categories.get(result.error.code) || "process-spawn";
|
|
1033
|
+
const failureSite = readExecutionLocationFailureSite(result.stderr);
|
|
1034
|
+
const storageFailure = readExecutionLocationStorageFailure(result.stderr);
|
|
1035
|
+
const error = new Error(
|
|
1036
|
+
`target process failed (${failureCategory})${failureSite ? ` at ${failureSite}` : ""}${storageFailure ? ` [${storageFailure}]` : ""}`,
|
|
1037
|
+
);
|
|
1038
|
+
error.code = "CC_EXECUTION_LOCATION_TARGET_COMMAND_FAILED";
|
|
1039
|
+
error.failureCategory = failureCategory;
|
|
1040
|
+
if (failureSite) error.failureSite = failureSite;
|
|
1041
|
+
if (storageFailure) error.storageFailure = storageFailure;
|
|
1042
|
+
return error;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
964
1045
|
function runTargetCommand(profile, cliArgs, deps = {}, options = {}) {
|
|
965
1046
|
const invocation = targetInvocation(profile, cliArgs, deps, options);
|
|
966
1047
|
const spawnSync =
|
|
@@ -976,9 +1057,14 @@ function runTargetCommand(profile, cliArgs, deps = {}, options = {}) {
|
|
|
976
1057
|
) {
|
|
977
1058
|
throw new Error("target command output boundary is invalid");
|
|
978
1059
|
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1060
|
+
// Hosted Windows Local targets can spend most of the generic 30-second
|
|
1061
|
+
// window on owner-only ACL checks before the CLI command runs. Keep the
|
|
1062
|
+
// existing bounded 120-second ceiling for this attested target platform.
|
|
1063
|
+
const defaultTimeoutMs =
|
|
1064
|
+
profile.target === "local" && profile.expected.platform === "win32"
|
|
1065
|
+
? MAX_TARGET_COMMAND_TIMEOUT_MS
|
|
1066
|
+
: DEFAULT_TARGET_COMMAND_TIMEOUT_MS;
|
|
1067
|
+
const timeoutMs = Number(options.timeoutMs ?? defaultTimeoutMs);
|
|
982
1068
|
if (
|
|
983
1069
|
!Number.isSafeInteger(timeoutMs) ||
|
|
984
1070
|
timeoutMs < 1 ||
|
|
@@ -1008,12 +1094,20 @@ function runTargetCommand(profile, cliArgs, deps = {}, options = {}) {
|
|
|
1008
1094
|
],
|
|
1009
1095
|
...(invocation.spawnOptions || {}),
|
|
1010
1096
|
});
|
|
1011
|
-
if (result?.error) throw result
|
|
1097
|
+
if (result?.error) throw targetProcessFailure(result);
|
|
1012
1098
|
if (!result || result.status !== 0) {
|
|
1099
|
+
const failureCategory = targetCommandFailureCategory(result);
|
|
1100
|
+
const failureSite = readExecutionLocationFailureSite(result?.stderr);
|
|
1101
|
+
const storageFailure = readExecutionLocationStorageFailure(
|
|
1102
|
+
result?.stderr,
|
|
1103
|
+
);
|
|
1013
1104
|
const error = new Error(
|
|
1014
|
-
`target command failed with status ${result?.status ?? "unknown"}`,
|
|
1105
|
+
`target command failed with status ${result?.status ?? "unknown"} (${failureCategory})${failureSite ? ` at ${failureSite}` : ""}${storageFailure ? ` [${storageFailure}]` : ""}`,
|
|
1015
1106
|
);
|
|
1016
1107
|
error.code = "CC_EXECUTION_LOCATION_TARGET_COMMAND_FAILED";
|
|
1108
|
+
error.failureCategory = failureCategory;
|
|
1109
|
+
if (failureSite) error.failureSite = failureSite;
|
|
1110
|
+
if (storageFailure) error.storageFailure = storageFailure;
|
|
1017
1111
|
throw error;
|
|
1018
1112
|
}
|
|
1019
1113
|
return options.interactive ? null : result.stdout;
|
|
@@ -1187,7 +1281,7 @@ export function probeExecutionLocationTargetResourceLimit(
|
|
|
1187
1281
|
} finally {
|
|
1188
1282
|
invocation.cleanup?.();
|
|
1189
1283
|
}
|
|
1190
|
-
if (result?.error) throw result
|
|
1284
|
+
if (result?.error) throw targetProcessFailure(result);
|
|
1191
1285
|
const expectedMarker = `CC_EXECUTION_LOCATION_RESOURCE_PROBE_ARMED:${kind}`;
|
|
1192
1286
|
const status = Number(result?.status);
|
|
1193
1287
|
const signal = result?.signal == null ? null : String(result.signal);
|
|
@@ -15,6 +15,8 @@ export const EXTERNAL_AGENT_ERROR = Object.freeze({
|
|
|
15
15
|
TIMEOUT: "EXTERNAL_AGENT_TIMEOUT",
|
|
16
16
|
EXIT_NONZERO: "EXTERNAL_AGENT_EXIT_NONZERO",
|
|
17
17
|
SPAWN_FAILED: "EXTERNAL_AGENT_SPAWN_FAILED",
|
|
18
|
+
CLEANUP_UNCONFIRMED: "EXTERNAL_AGENT_CLEANUP_UNCONFIRMED",
|
|
19
|
+
EXECUTION_BLOCKED: "EXTERNAL_AGENT_EXECUTION_BLOCKED",
|
|
18
20
|
PROTOCOL_FAILED: "EXTERNAL_AGENT_PROTOCOL_FAILED",
|
|
19
21
|
UNSUPPORTED_OPTION: "EXTERNAL_AGENT_UNSUPPORTED_OPTION",
|
|
20
22
|
});
|