chainlesschain 0.166.76 → 0.166.78
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 +19 -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-CNaejClV.js → AIOps-DSyZEY2G.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CF_CVKT_.js → ActionButton-DhNyZ577.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-a3Z6J7gv.js → Analytics-HMMpxmyi.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BFtWEnct.js → AppLayout-CwKMM5Ie.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BQ8oeMvX.js → Artifacts-CNzDmph7.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-NOo9bmgk.js → Audit-DxWpUW3V.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-QRc7F3Tp.js → BackgroundAgents-C1R2ST-P.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-UlVgLn2P.js → Backup-B6biTaEV.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BER9LJAr.js → BaseInput-CVnkD2Z5.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-Z8z2Fdfz.js → Chat-Dbewl4Je.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-DdmuBrdQ.js → ChatBubbleRenderer-DVZ6SwC5.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CXPgyB8L.js → Checkbox-BqqiF1JE.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-D1vOsLJ7.js → Codegen-BVMkGumc.js} +1 -1
- package/src/assets/web-panel/assets/{Col-ucLnUJC7.js → Col-DmiRHy96.js} +1 -1
- package/src/assets/web-panel/assets/{Community-COsV9n9t.js → Community-BDlpygqA.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-D0EkBEYh.js → Compact-B2NME_m-.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-C8w9SUjt.js → Compliance-BlzDLE-R.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CmVaKEJS.js → Cowork-C8raPybB.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-B_FiMMV2.js → Cron-DA8Py0zP.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-ByO3YL8N.js → Crosschain-DU2XyHqB.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DwpsLM9r.js → DID-Df098fT_.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-B_8IUvM_.js → Dashboard-D1rT702x.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Bo6WQkuX.js → Dropdown-BweXGo1O.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-C9LiQesx.js → EmailListRenderer-B9ShbgJH.js} +1 -1
- package/src/assets/web-panel/assets/EvolutionSettings-D75_iBoc.js +1 -0
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Dst6VUnO.js → FamilyGuardDashboard-DrznZFVs.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Ci7CoLkJ.js → Federation-DQZ2adIA.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-bdDyUhUM.js → FormItemContext-DN30Dowh.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CrRwOUVi.js → GenericCardRenderer-DRdt0j1e.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Dis8h-Z-.js → Git-wwRgStzk.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DX7OH5w2.js → Governance-CI4Uw0Nh.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Cavv_Q_Z.js → Inference-5TuE2AJI.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Cck8tnZn.js → KnowledgeGraph-oXyvmFSR.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BQt3aGMu.js → Logs-ewudSWuv.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-Cz5nyufm.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-CdmAKNSN.js → Marketplace-DcZeWFrs.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BUlJdyPY.js → McpTools-BcV9p1RS.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-DQRTQDr-.js → Memory-CMhYvugt.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-C0dnxgsl.js → MobileBridge-5RP2uwvT.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DQ5Gy7fa.js → MobileProjects-BIuM9Ze4.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Xl7u2isS.js → Mtc-DmBszTDe.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-C3KX0574.js → MtcAudit-Czdp5ZGt.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-CHEhfkn8.js → Multisig-DRWUuNr-.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Ce38mH-8.js → NLProgramming-IRQQN0-c.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-C7nuTd7c.js → Notes-CGhD1lW9.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-BcoEcyq8.js → NotificationSettings-BtyPgQAh.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-D-t5hKkx.js → OrderTableRenderer-yUaqwCty.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-C_BGi4xi.js → Organization-C3kTVn5i.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BodhraDq.js → Overflow-C2-0iZhq.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BTa3sAIy.js → P2P-CISoEUxA.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BjZslP9T.js → PdhVaultBrowser-NfTVtvKQ.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-u3UDzGef.js → Permissions-CfK0jJhm.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-Cb7ybv65.js → PersonalDataHub-OsVxxh_j.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-CS24k-P7.js → Pipeline-DEmK_Ch2.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Ddj6Kqs7.js → Privacy-D61s73b0.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Bg5uQIgg.js → ProjectInit-DkLF5gHb.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-AmPR8T12.js → ProjectSettings-BA7odTrI.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DGSbAyTK.js → Projects-CdI1GcAG.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-Dc1C3lbB.js → Providers-D9BYyP1r.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-Cv3HXpce.js → QrScannerModal-CXMItUDD.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-3dpbXARb.js → QuickAsk-8-tF9ffZ.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-5aGRVnJK.js → Recommend-C2QGWOSi.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-CTS2jx0p.js → RemoteSession-B1M_v1lx.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BxaKI0hY.js → Reputation-D0WZHgv1.js} +1 -1
- package/src/assets/web-panel/assets/{Row-C23uQdwd.js → Row-D6nf9-c-.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-ssX9YOhm.js → RssFeed-ClZ6M-mN.js} +3 -3
- package/src/assets/web-panel/assets/{Search-C24GogII.js → Search-ZWkt8vuO.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DdAcGKkk.js → Security-BUlQut2m.js} +3 -3
- package/src/assets/web-panel/assets/{Services-D0dCiEuq.js → Services-Cd_3xJOc.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DEY44o0v.js → Skeleton-C8e2-cHW.js} +1 -1
- package/src/assets/web-panel/assets/Skills-DucVRJp1.js +1 -0
- package/src/assets/web-panel/assets/{Sla-B_bbo2vB.js → Sla-Csr5pUwI.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-CXvyaRAT.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-CpIXql0Z.js → SyncSettings-KdsIcV5h.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-B-eHmJm9.js +1 -0
- package/src/assets/web-panel/assets/{Templates-C_44nVPq.js → Templates-BglVeaLK.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CyZ2ey2P.js → Tenant-BBbQ8qan.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DwGNHWnp.js → Terminal-Ca_pCVBi.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BTAHNkqU.js → TimelineRenderer-YD6XG_vZ.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DCJWkUwc.js → Tokens-2lRoeVli.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BCjDO9-E.js → Trigger-C-3XNAU9.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-_YS8WbRb.js → Trust-k-1PxdLG.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-m6R8xGq7.js → UkeySign-FG-qW646.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-xOfk29c4.js → VideoEditing-BNOe1cmd.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-B1Gw0awc.js → Wallet-D5C3i2Kw.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CHK5ft18.js → WebAuthn-BOpztqd3.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-DEp1ukQQ.js → WorkflowEditor-BpVrpUEv.js} +1 -1
- package/src/assets/web-panel/assets/{chat-B2sFizun.js → chat-DIuMHb38.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DJ17YV1E.js → colors-CTFJPyzQ.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-CBhJJgEC.js → compact-item-CONfmJcW.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BZkpvNJy.js → createContext-RkW5CRrz.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DaEBln_q.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-C0ZKo6Ei.js → hasIn-CW4XOjDC.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bc3vVG2X.js → index-7wMSBCU7.js} +1 -1
- package/src/assets/web-panel/assets/{index-vFMwiAN4.js → index-Akmg1WdH.js} +1 -1
- package/src/assets/web-panel/assets/{index-DOBXNMdh.js → index-B54qoVff.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLo8Ls9u.js → index-B8r2t0Ch.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7gv9dvb.js → index-B9XoBoty.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHtpMr1G.js → index-B9aS2VLu.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dxe0YlZe.js → index-BFs1Tznc.js} +1 -1
- package/src/assets/web-panel/assets/{index-DumLgj1t.js → index-BKgaRT0b.js} +1 -1
- package/src/assets/web-panel/assets/{index-BNp6HKFh.js → index-BM7bOUvu.js} +1 -1
- package/src/assets/web-panel/assets/{index-DM0rWF6z.js → index-BMg2JFmW.js} +1 -1
- package/src/assets/web-panel/assets/{index-4oULtRqE.js → index-BRZsPxNn.js} +1 -1
- package/src/assets/web-panel/assets/{index-LPPe0val.js → index-Bf19fKef.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ctguam0K.js → index-BkAbfBF-.js} +1 -1
- package/src/assets/web-panel/assets/{index-DrU5xVpF.js → index-CBjb2A5R.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCOr6Q27.js → index-CEZWQthY.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9gYiACH.js → index-CFGLf88d.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZW84cEf.js → index-CLUa68JH.js} +3 -3
- package/src/assets/web-panel/assets/{index-BoDUYyuo.js → index-CM2X25Er.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyiCbHeL.js → index-CX4T2uKN.js} +1 -1
- package/src/assets/web-panel/assets/{index-CW5o1Gar.js → index-CixqfdRk.js} +1 -1
- package/src/assets/web-panel/assets/{index-5K2z_tgO.js → index-CkRojEip.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOfPp5OV.js → index-Cvmc3f25.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdxJm-HB.js → index-D-lpTPS8.js} +1 -1
- package/src/assets/web-panel/assets/{index-8ueG48gl.js → index-D59GbWCN.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMxOoITz.js → index-DAESljiJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLMr5KMd.js → index-DDHUx4Yz.js} +1 -1
- package/src/assets/web-panel/assets/index-DG1mcYTa.js +1 -0
- package/src/assets/web-panel/assets/{index-BGIvhCPl.js → index-DP5pPedy.js} +1 -1
- package/src/assets/web-panel/assets/index-DRs5Pe8u.js +1 -0
- package/src/assets/web-panel/assets/{index-DjdSFO0d.js → index-DSlXL6Ju.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cn5UzvgR.js → index-DWCJnn2O.js} +1 -1
- package/src/assets/web-panel/assets/{index-Chct9tL8.js → index-DWY7YwDu.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEnd5fiz.js → index-DZTwP364.js} +1 -1
- package/src/assets/web-panel/assets/{index-KzNhWykP.js → index-DidrMvOx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpyrhOeh.js → index-Dj3K5kHs.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZlkPrxb.js → index-YaeGscSw.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dfgxe-fw.js → index-YlMnFNOi.js} +1 -1
- package/src/assets/web-panel/assets/{index-IHgzfc1u.js → index-asWsB34i.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJkoJzTU.js → index-gkjiFjQd.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Cqfoq0TJ.js → initDefaultProps-BOr4igh3.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CIiVJHNu.js → motion-CK469n2j.js} +1 -1
- package/src/assets/web-panel/assets/{move-CFl1o_A8.js → move-DzjudlYQ.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DYoCxcZ1.js → mtc-parser-BQaKUxC6.js} +1 -1
- package/src/assets/web-panel/assets/{omit-C1P2q5TY.js → omit-MciovCFD.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BtTRpJtC.js → pickAttrs-DDPJ4zAz.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Cst2PcNM.js → placementArrow-Cznyb-jI.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CF5kalV2.js → responsiveObserve-AJK3SLzJ.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CtHGqpXN.js → slide-CPQ28wu7.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-N__biHXf.js → statusUtils-CFjzvqf_.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DR8V_H-i.js → styleChecker-BPyFfTuR.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-D274dqun.js → useFlexGapSupport-Dq7N6R05.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BwHLYU5b.js → useFs-C3GS0uTc.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BiA-hVqt.js → usePersonalDataHub-BhgIVzP_.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Bugl94dy.js → vnode-4ZD9-MDr.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DEFl8GCu.js → zoom-Bx4MRVNW.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/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/decision-layer/providers.js +84 -9
- package/src/lib/decision-layer/runtime.js +86 -49
- package/src/lib/direct-model-usage.js +14 -3
- 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/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/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/headless-runner.js +8 -0
- package/src/runtime/headless-stream.js +202 -4
- package/src/assets/web-panel/assets/EvolutionSettings-Pc1IpRfk.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-BIUeeiVA.js +0 -1
- package/src/assets/web-panel/assets/Skills-CYt0Mu2W.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-a2BBjtTL.js +0 -1
- package/src/assets/web-panel/assets/Tasks-BYQKU-GL.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DZhu13vj.js +0 -1
- package/src/assets/web-panel/assets/index-C6iFyQYz.js +0 -1
- package/src/assets/web-panel/assets/index-CztThH9f.js +0 -1
|
@@ -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
|
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
|
|
3
|
+
// CLI keeps its existing eight-image allowance; IDE composers admit four.
|
|
4
|
+
export const MAX_INPUT_IMAGES = 8;
|
|
5
|
+
export const MAX_INPUT_IMAGE_BYTES = 20 * 1024 * 1024;
|
|
6
|
+
export const MAX_INPUT_IMAGE_PIXELS = 40_000_000;
|
|
7
|
+
const MAX_HEADER_BYTES = 1024 * 1024;
|
|
8
|
+
|
|
9
|
+
/** Header admission only, not a full codec decode or animation-frame budget. */
|
|
10
|
+
export function inspectImageHeader(data) {
|
|
11
|
+
const ascii = (start, end) => data.toString("ascii", start, end);
|
|
12
|
+
if (
|
|
13
|
+
data.length >= 33 &&
|
|
14
|
+
data
|
|
15
|
+
.subarray(0, 8)
|
|
16
|
+
.equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])) &&
|
|
17
|
+
data.readUInt32BE(8) === 13 &&
|
|
18
|
+
ascii(12, 16) === "IHDR"
|
|
19
|
+
) {
|
|
20
|
+
return {
|
|
21
|
+
mediaType: "image/png",
|
|
22
|
+
width: data.readUInt32BE(16),
|
|
23
|
+
height: data.readUInt32BE(20),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (data.length >= 13 && ["GIF87a", "GIF89a"].includes(ascii(0, 6))) {
|
|
27
|
+
return {
|
|
28
|
+
mediaType: "image/gif",
|
|
29
|
+
width: data.readUInt16LE(6),
|
|
30
|
+
height: data.readUInt16LE(8),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (data.length >= 30 && ascii(0, 4) === "RIFF" && ascii(8, 12) === "WEBP") {
|
|
34
|
+
const kind = ascii(12, 16);
|
|
35
|
+
if (kind === "VP8X")
|
|
36
|
+
return {
|
|
37
|
+
mediaType: "image/webp",
|
|
38
|
+
width: data.readUIntLE(24, 3) + 1,
|
|
39
|
+
height: data.readUIntLE(27, 3) + 1,
|
|
40
|
+
};
|
|
41
|
+
if (
|
|
42
|
+
kind === "VP8 " &&
|
|
43
|
+
data[23] === 157 &&
|
|
44
|
+
data[24] === 1 &&
|
|
45
|
+
data[25] === 42
|
|
46
|
+
)
|
|
47
|
+
return {
|
|
48
|
+
mediaType: "image/webp",
|
|
49
|
+
width: data.readUInt16LE(26) & 16383,
|
|
50
|
+
height: data.readUInt16LE(28) & 16383,
|
|
51
|
+
};
|
|
52
|
+
if (kind === "VP8L" && data[20] === 47) {
|
|
53
|
+
const bits = data.readUInt32LE(21);
|
|
54
|
+
return {
|
|
55
|
+
mediaType: "image/webp",
|
|
56
|
+
width: (bits & 16383) + 1,
|
|
57
|
+
height: ((bits >>> 14) & 16383) + 1,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (data.length >= 4 && data[0] === 255 && data[1] === 216) {
|
|
62
|
+
let offset = 2;
|
|
63
|
+
while (offset + 4 <= data.length) {
|
|
64
|
+
if (data[offset++] !== 255) break;
|
|
65
|
+
while (data[offset] === 255) offset++;
|
|
66
|
+
const marker = data[offset++];
|
|
67
|
+
if (marker === 217 || marker === 218) break;
|
|
68
|
+
if (marker === 1 || (marker >= 208 && marker <= 215)) continue;
|
|
69
|
+
if (offset + 2 > data.length) break;
|
|
70
|
+
const length = data.readUInt16BE(offset);
|
|
71
|
+
if (length < 2 || offset + length > data.length) break;
|
|
72
|
+
if (
|
|
73
|
+
[
|
|
74
|
+
192, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207,
|
|
75
|
+
].includes(marker) &&
|
|
76
|
+
length >= 8
|
|
77
|
+
) {
|
|
78
|
+
return {
|
|
79
|
+
mediaType: "image/jpeg",
|
|
80
|
+
width: data.readUInt16BE(offset + 5),
|
|
81
|
+
height: data.readUInt16BE(offset + 3),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
offset += length;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
throw new Error(
|
|
88
|
+
"Unsupported or malformed image header (dimensions must occur within the first 1 MiB)",
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function readAtMost(io, fd, data) {
|
|
93
|
+
let offset = 0;
|
|
94
|
+
while (offset < data.length) {
|
|
95
|
+
const count = io.readSync(fd, data, offset, data.length - offset, offset);
|
|
96
|
+
if (count === 0) break;
|
|
97
|
+
offset += count;
|
|
98
|
+
}
|
|
99
|
+
return offset;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Pin one regular-file descriptor and cap allocation/read even if it grows. */
|
|
103
|
+
export function readBoundedImage(
|
|
104
|
+
file,
|
|
105
|
+
expectedMediaType,
|
|
106
|
+
remainingBytes,
|
|
107
|
+
io = fs,
|
|
108
|
+
) {
|
|
109
|
+
// O_NONBLOCK avoids hanging while opening a FIFO on POSIX. fstat then
|
|
110
|
+
// rejects all non-regular files; Windows has no O_NONBLOCK flag here.
|
|
111
|
+
const fd = io.openSync(
|
|
112
|
+
file,
|
|
113
|
+
fs.constants.O_RDONLY | (fs.constants.O_NONBLOCK || 0),
|
|
114
|
+
);
|
|
115
|
+
try {
|
|
116
|
+
const before = io.fstatSync(fd);
|
|
117
|
+
if (!before.isFile()) throw new Error("Image input must be a regular file");
|
|
118
|
+
if (
|
|
119
|
+
!Number.isSafeInteger(before.size) ||
|
|
120
|
+
before.size <= 0 ||
|
|
121
|
+
before.size > MAX_INPUT_IMAGE_BYTES
|
|
122
|
+
)
|
|
123
|
+
throw new Error("Image must contain 1 byte to 20 MiB");
|
|
124
|
+
if (before.size > remainingBytes)
|
|
125
|
+
throw new Error("Total image attachments exceed 20 MiB per message");
|
|
126
|
+
const header = Buffer.alloc(Math.min(before.size, MAX_HEADER_BYTES));
|
|
127
|
+
const headerSize = readAtMost(io, fd, header);
|
|
128
|
+
const info = inspectImageHeader(header.subarray(0, headerSize));
|
|
129
|
+
if (info.mediaType !== expectedMediaType)
|
|
130
|
+
throw new Error("Image extension does not match its file header");
|
|
131
|
+
if (
|
|
132
|
+
!info.width ||
|
|
133
|
+
!info.height ||
|
|
134
|
+
info.width * info.height > MAX_INPUT_IMAGE_PIXELS
|
|
135
|
+
)
|
|
136
|
+
throw new Error(
|
|
137
|
+
"Image dimensions must be positive and at most 40 megapixels",
|
|
138
|
+
);
|
|
139
|
+
const data = Buffer.alloc(before.size + 1);
|
|
140
|
+
const count = readAtMost(io, fd, data);
|
|
141
|
+
const after = io.fstatSync(fd);
|
|
142
|
+
if (
|
|
143
|
+
count !== before.size ||
|
|
144
|
+
after.size !== before.size ||
|
|
145
|
+
after.mtimeMs !== before.mtimeMs ||
|
|
146
|
+
after.ctimeMs !== before.ctimeMs ||
|
|
147
|
+
!data.subarray(0, headerSize).equals(header.subarray(0, headerSize))
|
|
148
|
+
)
|
|
149
|
+
throw new Error("Image changed while being read; select it again");
|
|
150
|
+
return data.subarray(0, count);
|
|
151
|
+
} finally {
|
|
152
|
+
io.closeSync(fd);
|
|
153
|
+
}
|
|
154
|
+
}
|
package/src/lib/image-input.js
CHANGED
|
@@ -15,6 +15,11 @@
|
|
|
15
15
|
import fs from "fs";
|
|
16
16
|
import path from "path";
|
|
17
17
|
import os from "os";
|
|
18
|
+
import {
|
|
19
|
+
MAX_INPUT_IMAGES,
|
|
20
|
+
MAX_INPUT_IMAGE_BYTES,
|
|
21
|
+
readBoundedImage,
|
|
22
|
+
} from "./image-file-boundary.js";
|
|
18
23
|
|
|
19
24
|
/**
|
|
20
25
|
* Candidate on-disk forms for a path token typed in a prompt, so a path copied
|
|
@@ -66,7 +71,10 @@ const EXT_MEDIA = {
|
|
|
66
71
|
export function resolveImages(paths, deps = {}) {
|
|
67
72
|
const _fs = deps.fs || fs;
|
|
68
73
|
if (!Array.isArray(paths) || paths.length === 0) return [];
|
|
69
|
-
|
|
74
|
+
if (paths.length > MAX_INPUT_IMAGES)
|
|
75
|
+
throw new Error(`Attach at most ${MAX_INPUT_IMAGES} images per message`);
|
|
76
|
+
let remainingBytes = MAX_INPUT_IMAGE_BYTES;
|
|
77
|
+
return paths.map((p, index) => {
|
|
70
78
|
const ext = path.extname(String(p)).toLowerCase();
|
|
71
79
|
const mediaType = EXT_MEDIA[ext];
|
|
72
80
|
if (!mediaType) {
|
|
@@ -74,8 +82,13 @@ export function resolveImages(paths, deps = {}) {
|
|
|
74
82
|
`Unsupported image type "${ext || p}" — use png/jpg/jpeg/gif/webp.`,
|
|
75
83
|
);
|
|
76
84
|
}
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
try {
|
|
86
|
+
const data = readBoundedImage(p, mediaType, remainingBytes, _fs);
|
|
87
|
+
remainingBytes -= data.length;
|
|
88
|
+
return { mediaType, data: data.toString("base64") };
|
|
89
|
+
} catch (error) {
|
|
90
|
+
throw new Error(`Image ${index + 1}: ${error.message}`, { cause: error });
|
|
91
|
+
}
|
|
79
92
|
});
|
|
80
93
|
}
|
|
81
94
|
|
package/src/lib/llm-pricing.js
CHANGED
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
* substring against the model id.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import {
|
|
19
|
+
DOCUMENTED_OPENAI_MODELS,
|
|
20
|
+
DOCUMENTED_ANTHROPIC_MODELS,
|
|
21
|
+
GPT6_PRICING_TERMS,
|
|
22
|
+
} from "./model-context-catalog.js";
|
|
23
|
+
|
|
18
24
|
/** Providers whose models run locally and cost nothing to call. */
|
|
19
25
|
export const FREE_PROVIDERS = Object.freeze([
|
|
20
26
|
"ollama",
|
|
@@ -30,6 +36,11 @@ export const FREE_PROVIDERS = Object.freeze([
|
|
|
30
36
|
*/
|
|
31
37
|
export const PRICE_TABLE = Object.freeze({
|
|
32
38
|
anthropic: [
|
|
39
|
+
...Object.entries(DOCUMENTED_ANTHROPIC_MODELS).map(([match, model]) => ({
|
|
40
|
+
match,
|
|
41
|
+
...model.pricing,
|
|
42
|
+
exact: true,
|
|
43
|
+
})),
|
|
33
44
|
// Current Anthropic list prices (USD per 1M tokens), verified 2026-06-21
|
|
34
45
|
// against the claude-api reference. The Opus tier dropped to $5/$25 with
|
|
35
46
|
// Opus 4.5 (Nov 2025) — the old $15/$75 applies only to the retired
|
|
@@ -47,6 +58,14 @@ export const PRICE_TABLE = Object.freeze({
|
|
|
47
58
|
{ match: "haiku", in: 1, out: 5 },
|
|
48
59
|
],
|
|
49
60
|
openai: [
|
|
61
|
+
...Object.entries(DOCUMENTED_OPENAI_MODELS)
|
|
62
|
+
.filter(([, model]) => model.pricing)
|
|
63
|
+
.map(([match, model]) => ({
|
|
64
|
+
match,
|
|
65
|
+
...model.pricing,
|
|
66
|
+
exact: true,
|
|
67
|
+
terms: GPT6_PRICING_TERMS,
|
|
68
|
+
})),
|
|
50
69
|
// GPT-5 family (2026). Matching is longest-pattern-first, so dated/variant
|
|
51
70
|
// ids (gpt-5.5, gpt-5.5-pro, gpt-5.5-instant, …) resolve to the most
|
|
52
71
|
// specific rate; bare "gpt-5" is the catch-all base rate.
|
|
@@ -64,6 +83,10 @@ export const PRICE_TABLE = Object.freeze({
|
|
|
64
83
|
{ match: "o1-mini", in: 1.1, out: 4.4 },
|
|
65
84
|
{ match: "o1", in: 15, out: 60 },
|
|
66
85
|
],
|
|
86
|
+
dashscope: [
|
|
87
|
+
{ match: "qwen-turbo", in: 0.3, out: 0.6 },
|
|
88
|
+
{ match: "qwen-plus", in: 0.8, out: 2 },
|
|
89
|
+
],
|
|
67
90
|
deepseek: [
|
|
68
91
|
// DeepSeek V4 launch-list rates for the versioned 2026-04 model ids.
|
|
69
92
|
// Keep these ahead of the legacy aliases so formal budget gates never
|
|
@@ -139,9 +162,13 @@ export function mergePricing(overrides, base = PRICE_TABLE) {
|
|
|
139
162
|
Number(e.out) >= 0,
|
|
140
163
|
)
|
|
141
164
|
.map((e) => ({
|
|
165
|
+
...(base[providerKey]?.find(
|
|
166
|
+
(entry) => entry.match === e.match.toLowerCase(),
|
|
167
|
+
) || {}),
|
|
142
168
|
match: e.match.toLowerCase(),
|
|
143
169
|
in: Number(e.in),
|
|
144
170
|
out: Number(e.out),
|
|
171
|
+
explicitOverride: true,
|
|
145
172
|
}));
|
|
146
173
|
if (valid.length === 0) continue;
|
|
147
174
|
const overridden = new Set(valid.map((v) => v.match));
|
|
@@ -171,8 +198,23 @@ export function lookupRate(provider, model, table = PRICE_TABLE) {
|
|
|
171
198
|
// Longest pattern first so specific beats generic regardless of table order.
|
|
172
199
|
const sorted = [...entries].sort((a, b) => b.match.length - a.match.length);
|
|
173
200
|
for (const e of sorted) {
|
|
174
|
-
if (m.includes(e.match)) {
|
|
175
|
-
|
|
201
|
+
if (e.exact ? m === e.match : m.includes(e.match)) {
|
|
202
|
+
// An unrecognized new version must not inherit an older Opus price.
|
|
203
|
+
// Explicit operator overrides remain authoritative.
|
|
204
|
+
if (
|
|
205
|
+
e.match === "opus" &&
|
|
206
|
+
Number(/^claude-opus-(\d+)(?:[.-]|$)/u.exec(m)?.[1]) >= 5 &&
|
|
207
|
+
!e.explicitOverride &&
|
|
208
|
+
e.in === 5 &&
|
|
209
|
+
e.out === 25
|
|
210
|
+
)
|
|
211
|
+
continue;
|
|
212
|
+
return {
|
|
213
|
+
in: e.in,
|
|
214
|
+
out: e.out,
|
|
215
|
+
pattern: e.match,
|
|
216
|
+
...(e.terms ? { terms: e.terms } : {}),
|
|
217
|
+
};
|
|
176
218
|
}
|
|
177
219
|
}
|
|
178
220
|
return null;
|
|
@@ -210,10 +252,18 @@ export function estimateCost({
|
|
|
210
252
|
outputTokens = 0,
|
|
211
253
|
cacheReadTokens = 0,
|
|
212
254
|
cacheCreationTokens = 0,
|
|
255
|
+
requestInputTokens,
|
|
256
|
+
serviceTier = "standard",
|
|
257
|
+
regionalProcessing = false,
|
|
213
258
|
table,
|
|
214
259
|
} = {}) {
|
|
215
260
|
const rate = lookupRate(provider, model, table);
|
|
216
|
-
|
|
261
|
+
const tierMultiplier = rate?.terms
|
|
262
|
+
? Object.hasOwn(rate.terms.serviceMultipliers, serviceTier)
|
|
263
|
+
? rate.terms.serviceMultipliers[serviceTier]
|
|
264
|
+
: null
|
|
265
|
+
: 1;
|
|
266
|
+
if (!rate || tierMultiplier == null) {
|
|
217
267
|
return {
|
|
218
268
|
inputCost: 0,
|
|
219
269
|
outputCost: 0,
|
|
@@ -226,16 +276,34 @@ export function estimateCost({
|
|
|
226
276
|
rate: null,
|
|
227
277
|
};
|
|
228
278
|
}
|
|
279
|
+
const promptTokens =
|
|
280
|
+
requestInputTokens ??
|
|
281
|
+
Number(inputTokens) + Number(cacheReadTokens) + Number(cacheCreationTokens);
|
|
282
|
+
const longContext = rate.terms?.longContext;
|
|
283
|
+
const longPrompt = longContext && promptTokens > longContext.threshold;
|
|
284
|
+
const inputMultiplier = longPrompt ? longContext.inputMultiplier : 1;
|
|
285
|
+
const outputMultiplier = longPrompt ? longContext.outputMultiplier : 1;
|
|
286
|
+
const multiplier = tierMultiplier * (regionalProcessing ? 1.1 : 1);
|
|
229
287
|
// Keep full IEEE-754 precision throughout authority and budget arithmetic.
|
|
230
288
|
// Rounding each component to six decimals lets a real sub-microdollar call
|
|
231
289
|
// become zero and can make a hard `maxUsd` gate pass incorrectly. Display
|
|
232
290
|
// surfaces may format these values, but safety decisions consume the raw sum.
|
|
233
|
-
const inputCost =
|
|
234
|
-
|
|
291
|
+
const inputCost =
|
|
292
|
+
(Number(inputTokens) / 1e6) * rate.in * inputMultiplier * multiplier;
|
|
293
|
+
const outputCost =
|
|
294
|
+
(Number(outputTokens) / 1e6) * rate.out * outputMultiplier * multiplier;
|
|
235
295
|
const cacheReadCost =
|
|
236
|
-
(Number(cacheReadTokens) / 1e6) *
|
|
296
|
+
(Number(cacheReadTokens) / 1e6) *
|
|
297
|
+
rate.in *
|
|
298
|
+
(rate.terms?.cacheReadMultiplier ?? cacheReadMultiplier(provider)) *
|
|
299
|
+
inputMultiplier *
|
|
300
|
+
multiplier;
|
|
237
301
|
const cacheCreationCost =
|
|
238
|
-
(Number(cacheCreationTokens) / 1e6) *
|
|
302
|
+
(Number(cacheCreationTokens) / 1e6) *
|
|
303
|
+
rate.in *
|
|
304
|
+
(rate.terms?.cacheWriteMultiplier ?? CACHE_WRITE_MULTIPLIER) *
|
|
305
|
+
inputMultiplier *
|
|
306
|
+
multiplier;
|
|
239
307
|
return {
|
|
240
308
|
inputCost,
|
|
241
309
|
outputCost,
|
|
@@ -259,15 +327,53 @@ export function estimateCost({
|
|
|
259
327
|
*/
|
|
260
328
|
export function priceRollup(aggregate, { table } = {}) {
|
|
261
329
|
const byModel = (aggregate?.byModel || []).map((row) => {
|
|
262
|
-
|
|
330
|
+
let est = estimateCost({
|
|
263
331
|
provider: row.provider,
|
|
264
332
|
model: row.model,
|
|
265
333
|
inputTokens: row.inputTokens,
|
|
266
334
|
outputTokens: row.outputTokens,
|
|
267
335
|
cacheReadTokens: row.cacheReadTokens,
|
|
268
336
|
cacheCreationTokens: row.cacheCreationTokens,
|
|
337
|
+
serviceTier: row.serviceTier ?? row.service_tier ?? "standard",
|
|
338
|
+
regionalProcessing:
|
|
339
|
+
row.regionalProcessing ?? row.regional_processing ?? false,
|
|
269
340
|
table,
|
|
270
341
|
});
|
|
342
|
+
if (Array.isArray(row.pricingBuckets)) {
|
|
343
|
+
const estimates = row.pricingBuckets.map((bucket) =>
|
|
344
|
+
estimateCost({
|
|
345
|
+
provider: row.provider,
|
|
346
|
+
model: row.model,
|
|
347
|
+
...bucket,
|
|
348
|
+
table,
|
|
349
|
+
}),
|
|
350
|
+
);
|
|
351
|
+
est = { ...est, matched: estimates.every((entry) => entry.matched) };
|
|
352
|
+
for (const field of [
|
|
353
|
+
"inputCost",
|
|
354
|
+
"outputCost",
|
|
355
|
+
"cacheReadCost",
|
|
356
|
+
"cacheCreationCost",
|
|
357
|
+
"totalCost",
|
|
358
|
+
]) {
|
|
359
|
+
est[field] = estimates.reduce((sum, entry) => sum + entry[field], 0);
|
|
360
|
+
}
|
|
361
|
+
} else if (
|
|
362
|
+
lookupRate(row.provider, row.model, table)?.terms &&
|
|
363
|
+
row.calls > 1
|
|
364
|
+
) {
|
|
365
|
+
// A legacy aggregate cannot establish which individual requests crossed
|
|
366
|
+
// a pricing threshold. Exclude it rather than inventing a bill.
|
|
367
|
+
est = {
|
|
368
|
+
...est,
|
|
369
|
+
matched: false,
|
|
370
|
+
inputCost: 0,
|
|
371
|
+
outputCost: 0,
|
|
372
|
+
cacheReadCost: 0,
|
|
373
|
+
cacheCreationCost: 0,
|
|
374
|
+
totalCost: 0,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
271
377
|
return {
|
|
272
378
|
...row,
|
|
273
379
|
cost: est.totalCost,
|
|
@@ -685,10 +685,13 @@ export function assertMcpVerifiedProjectionAuthority(
|
|
|
685
685
|
const descriptors = Object.getOwnPropertyDescriptors(authority);
|
|
686
686
|
const fields = Object.keys(descriptors);
|
|
687
687
|
if (
|
|
688
|
-
fields.length !==
|
|
688
|
+
fields.length !==
|
|
689
|
+
VERIFIED_PROJECTION_AUTHORITY_FIELDS.size +
|
|
690
|
+
(descriptors.replayEvents ? 1 : 0) ||
|
|
689
691
|
fields.some(
|
|
690
692
|
(field) =>
|
|
691
|
-
!VERIFIED_PROJECTION_AUTHORITY_FIELDS.has(field)
|
|
693
|
+
(!VERIFIED_PROJECTION_AUTHORITY_FIELDS.has(field) &&
|
|
694
|
+
field !== "replayEvents") ||
|
|
692
695
|
!("value" in descriptors[field]) ||
|
|
693
696
|
!descriptors[field].enumerable,
|
|
694
697
|
)
|
|
@@ -704,6 +707,8 @@ export function assertMcpVerifiedProjectionAuthority(
|
|
|
704
707
|
!Number.isSafeInteger(projectedEventCount) ||
|
|
705
708
|
projectedEventCount < 0 ||
|
|
706
709
|
typeof descriptors.readMessages.value !== "function" ||
|
|
710
|
+
(descriptors.replayEvents &&
|
|
711
|
+
typeof descriptors.replayEvents.value !== "function") ||
|
|
707
712
|
projectedEventCount !== acceptedCount ||
|
|
708
713
|
projectedHeadHash !== headHash
|
|
709
714
|
) {
|