chainlesschain 0.166.117 → 0.166.121
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 +36 -4
- package/package.json +3 -3
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-C9tSCImB.js → AIOps-DYEi6MCC.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CXKExmT_.js → ActionButton-kLXp42k3.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DE8WBWHo.js → Analytics-BOgKma-R.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BdpwNM08.js → AppLayout-D8z-uRpv.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-94TQpe38.js → Artifacts-TFX0t24T.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DdDEv5Ej.js → Audit-GjRCAv0V.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-TU9nlV7j.js → BackgroundAgents-CpQcMxi1.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-C0GPoUUq.js → Backup-BuQNWrhT.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-iyrVn2I6.js → BaseInput-QuOtSaFy.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-Dqo8spwp.js → Chat-BC0W1L_3.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CDqHSzc4.js → ChatBubbleRenderer-B6SagRW5.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BF_XJvQi.js → Checkbox-BsdQ1Ku0.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-5tUWoOa9.js → Codegen-CPsAAoqV.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BQxSeRvG.js → Col-C9LgCMN0.js} +1 -1
- package/src/assets/web-panel/assets/{Community-B2Ra7w-J.js → Community-Xj0vGvD5.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-GjxJwlr0.js → Compact-CXoqTgrf.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BTUP6RTA.js → Compliance-CeshjrVy.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DiwfL16s.js → Cowork-DjXRRrg1.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-1ceOo5ux.js → Cron-vGoU419C.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-aHYxLu0u.js → Crosschain-DZaChZ5s.js} +1 -1
- package/src/assets/web-panel/assets/{DID-eeTjzOLV.js → DID-BojMQqQM.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CT3fpkvX.js → Dashboard-pKAYt4UL.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-B3UpOy-N.js → Dropdown-CqJa8N05.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Ba2Rvoru.js → EmailListRenderer-fZ4_KAvw.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-CGtn93on.js → EvolutionSettings-C3kenWes.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-C0IUdHQt.js → FamilyGuardDashboard-B3tqj1Hu.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-1QIDwemn.js → Federation-CS1M1oJN.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-NGbSsdje.js → FormItemContext-C5q-KYPu.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DzVZc2Ba.js → GenericCardRenderer-Bl43BLxD.js} +1 -1
- package/src/assets/web-panel/assets/{Git-B_1TDbSr.js → Git-BiN2Uo-z.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BDl_ySyI.js → Governance-weglJWG4.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CAp-wcCK.js → Inference-B4qBxVSK.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DRjRcxul.js → KnowledgeGraph-iePl1vLv.js} +1 -1
- package/src/assets/web-panel/assets/Logs-t2lKo4HX.js +2 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-CxSrBHYC.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-DfiXL6UO.js → Marketplace-D0Y_OmXs.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-D9rIvFjN.js → McpTools-B7zxPsFE.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-D-p7yDzj.js → Memory-DDpmVHpl.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-D0XT5B6m.js → MobileBridge-BLXNdKH0.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CL9cHVIk.js → MobileProjects-CF6DqNfk.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CME4kDmC.js → Mtc-7OFckDUe.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-BjGOXFnn.js → MtcAudit-2QFWPXVR.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-CSzc53e0.js → Multisig-D9opE0iP.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BYjZnaH8.js → NLProgramming-jOD2E7Rs.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BUPOYE0C.js → Notes-CgtysN6L.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-BK8YADru.js → NotificationSettings-Itz3X5DM.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-C2ylWgSI.js +1 -0
- package/src/assets/web-panel/assets/{Organization-B0WNlhMd.js → Organization-CKgpbSoy.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CED6ZO87.js → Overflow-C0Pi9LvB.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CBdc8fkP.js → P2P-DdIDorai.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DuauYi03.js → PdhVaultBrowser-DVJz6cGr.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-kfgY0ukN.js → Permissions-D19dtcL0.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CDY3I1Do.js → PersonalDataHub-A-QMQUJW.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-B9x0wKSK.js → Pipeline-7YF1yhkH.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Cqhcr_Qv.js → Privacy-CcsoAU7d.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CFhoyo57.js → ProjectInit-CMU0Z5in.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DCBjV2Hm.js → ProjectSettings-D3l0RXK6.js} +2 -2
- package/src/assets/web-panel/assets/Projects-BCcHN_fQ.js +1 -0
- package/src/assets/web-panel/assets/{Providers-BuCIWZY1.js → Providers-DB0pw3DM.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CEXNL5CB.js → QrScannerModal-SVvLX_VH.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DgK8aLAU.js → QuickAsk-B4dJgwL4.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BxEYQRAs.js → Recommend-9GxSlYt5.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-PRsxNsYU.js → RemoteSession-C5vzfpTM.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-S-tQH70r.js → Reputation-7AeSkJz1.js} +1 -1
- package/src/assets/web-panel/assets/{Row-U1Ws3CJl.js → Row-Dc3RwqWR.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BftCyeii.js → RssFeed-Y8iSgp9o.js} +3 -3
- package/src/assets/web-panel/assets/{Search-o4gK0cPy.js → Search-bxkz-UtW.js} +1 -1
- package/src/assets/web-panel/assets/{Security-U2ZRpsbA.js → Security-cs5yf-AE.js} +3 -3
- package/src/assets/web-panel/assets/{Services-D0tRjWl_.js → Services-2va9CJFi.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DzZ8TFsB.js → Skeleton-n8HOSPcE.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-B1cC7rju.js → Skills-BcV5aWYc.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CtIHOR0J.js → Sla-B73zPlDG.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CD8ZlQpW.js → SpeechSettings-OhhEZsxi.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BilFQWQk.js → SyncSettings-4HT8618-.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Bmg2qLXl.js → Tasks-Dw7nEG94.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D6yofyC1.js → Templates-BX7zHI9M.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BzttD-Gp.js → Tenant-SrFN1ZTF.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DyRXeYuH.js → Terminal-B-ohas9S.js} +3 -3
- package/src/assets/web-panel/assets/{TimelineRenderer-Bdmkx-Tr.js → TimelineRenderer-exEpcIMD.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-10RcVAVJ.js → Tokens-Fucr0-Ek.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CKV-9DdV.js → Trigger-CPlH4qBU.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BEc-sW1q.js → Trust-DCNisGxI.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BSql8piX.js → UkeySign-Crf4bea0.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-C4OH2f4s.js → VideoEditing-JAq5jURW.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BSSvWKmv.js → Wallet-BaOfcyqF.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-LxIzXo9d.js → WebAuthn-DMtCTRsk.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-DWwdfcte.js → WorkflowEditor-BAKiA5p0.js} +1 -1
- package/src/assets/web-panel/assets/{addon-fit-CK6X9sAG.js → addon-fit-CbkjSUJl.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DWxYYLD5.js → chat-D3MA12Z1.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BxEcQqtg.js → colors-C7xYOAG-.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DNbezFOJ.js → compact-item-ClybpIV-.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DaJXc5nx.js → createContext-Dyp-8LSs.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CTazgK0z.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BMrw3sg3.js → hasIn-D4xsaFD1.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cm9DYzhC.js → index-B-eU0wCl.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaByEdBj.js → index-B7jiI-31.js} +1 -1
- package/src/assets/web-panel/assets/{index-T4T84G6X.js → index-BKyEhMUl.js} +1 -1
- package/src/assets/web-panel/assets/{index-LRb0QX6S.js → index-BMybVxE3.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dwg38xTG.js → index-BagQvwmy.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bum_aSyd.js → index-BcmJBS7G.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCCd8Rj6.js → index-BfZW-iaH.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9b6UaZl.js → index-BmBqpU1f.js} +1 -1
- package/src/assets/web-panel/assets/{index-6W0V5G2t.js → index-Bn8O_DC1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BR4nWOmR.js → index-BpLWtYzy.js} +1 -1
- package/src/assets/web-panel/assets/{index-2c0bL3SE.js → index-CHJUN9dR.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpSp97J8.js → index-CNBhQp0_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DEvdSKT4.js → index-CS7E_bsQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BNZDGV2q.js → index-CSOgUWox.js} +1 -1
- package/src/assets/web-panel/assets/{index-VD-dTYQE.js → index-CiRxc4Y0.js} +1 -1
- package/src/assets/web-panel/assets/index-CrZlBv0O.js +1 -0
- package/src/assets/web-panel/assets/{index-CpwgF7vh.js → index-CvsWZZzU.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcuytRTa.js → index-Cvwa0445.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_b9_6wQ.js → index-CxSVA3yj.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaxzeSIM.js → index-D5aA2hc_.js} +1 -1
- package/src/assets/web-panel/assets/{index-cCqCEa9X.js → index-D6ETHrUX.js} +3 -3
- package/src/assets/web-panel/assets/{index-DzZHBzCb.js → index-D6GFzqYv.js} +1 -1
- package/src/assets/web-panel/assets/{index-hPy_f08G.js → index-DDDP6-gb.js} +1 -1
- package/src/assets/web-panel/assets/{index-NEW5EN2w.js → index-DJVzi25x.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dr18agDl.js → index-DMlcfkHz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DarVV5yG.js → index-DNeHM7F3.js} +1 -1
- package/src/assets/web-panel/assets/{index-7zzLqfvI.js → index-DT57ltH_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BAV07GDK.js → index-DWHngGhj.js} +1 -1
- package/src/assets/web-panel/assets/{index-cKBpcInt.js → index-DuGdqMTo.js} +1 -1
- package/src/assets/web-panel/assets/index-DyNp52Uj.js +1 -0
- package/src/assets/web-panel/assets/{index-CL-36X3A.js → index-KvhXXaLi.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiEdfbB9.js → index-Rk6e-ajq.js} +1 -1
- package/src/assets/web-panel/assets/{index-rFaCnjXi.js → index-ZmHm5rHI.js} +1 -1
- package/src/assets/web-panel/assets/{index-IX0g0s2t.js → index-_9loRV63.js} +1 -1
- package/src/assets/web-panel/assets/{index-C25ig6EV.js → index-avRJM_PM.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bs2QyMPQ.js → index-ciHSB-CC.js} +1 -1
- package/src/assets/web-panel/assets/{index-pzYLf5qu.js → index-faSaFsUp.js} +1 -1
- package/src/assets/web-panel/assets/{index-DL0k35f0.js → index-nV4PAkOC.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ca2hwPMo.js → index-v5sQDXJx.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BWVLgWhF.js → initDefaultProps-xrojGNIo.js} +1 -1
- package/src/assets/web-panel/assets/{markdown-Yo_c6Krv.js → markdown-Bq2x0XsR.js} +1 -1
- package/src/assets/web-panel/assets/markdown-DUKxbhE4.js +51 -0
- package/src/assets/web-panel/assets/{motion-KJZ1xfDE.js → motion-DzhD1BmE.js} +1 -1
- package/src/assets/web-panel/assets/{move-DGqU6H7M.js → move-BAq6xac8.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-Dg0xkI5J.js → mtc-parser-CbbkHqsY.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B6RnMJAQ.js → omit-DvK7nt_t.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-Ctw2i3jb.js → pickAttrs-B8N30ZEF.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-D3F3x8Jm.js → placementArrow-cUxaRoU7.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-W6eHE0nM.js → responsiveObserve-CxMioios.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BlFf8sY5.js → slide-CQx7R0mc.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Cd6LMwmy.js → statusUtils-kUphM3-c.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Bg5-U4Y1.js → styleChecker-BrGZ1xWq.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DTkLS3tn.js → useFlexGapSupport-Sb5Vj_ag.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CwYGzoBt.js → useFs-DrMnDCO5.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-PCgFQXZP.js → usePersonalDataHub-C48ZIkOr.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CJM7MkrB.js → vnode-BQP6PZY_.js} +1 -1
- package/src/assets/web-panel/assets/{xterm-BZcWGsqw.js → xterm-zbskxxGA.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CP0mgaFi.js → zoom-DOJny9bH.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +28 -2
- package/src/harness/jsonl-session-store.js +2 -1
- package/src/lib/artifact-store.js +129 -20
- package/src/lib/bounded-artifact-file-read.js +128 -46
- package/src/lib/evolution/agent-evolution-ingress.js +41 -7
- package/src/lib/evolution/agent-evolution-runtime-composition.js +65 -27
- package/src/lib/evolution/evidence-json-text.js +124 -8
- package/src/lib/evolution/evolution-artifact-ports.js +1005 -83
- package/src/lib/evolution/evolution-evidence-artifact-adapter.js +59 -15
- package/src/lib/evolution/evolution-evidence-projector.js +59 -3
- package/src/lib/evolution/evolution-evidence-storage-layout.js +115 -0
- package/src/lib/evolution/evolution-file-witness.js +7 -3
- package/src/lib/evolution/evolution-ledger-file-manifest-catalog.js +6 -2
- package/src/lib/evolution/evolution-ledger-file-manifest-head-store.js +6 -2
- package/src/lib/evolution/evolution-ledger.js +226 -55
- package/src/lib/evolution/evolution-private-storage.js +20 -0
- package/src/lib/evolution/evolution-run-ledger-adapter.js +298 -11
- package/src/lib/evolution/evolution-windows-directory-durability.js +215 -32
- package/src/lib/evolution/local-ui-evolution-runtime.js +3 -38
- package/src/lib/evolution/local-ui-signing-authority.js +69 -0
- package/src/lib/ollama-provider-fetch.js +33 -0
- package/src/lib/provider-stream.js +14 -13
- package/src/lib/session-history-origins.js +71 -32
- package/src/lib/session-message-provenance.js +26 -2
- package/src/lib/session-runtime-retention.js +10 -1
- package/src/lib/session-transcript-migration.js +67 -12
- package/src/lib/storage-failure-cause-codes.js +449 -0
- package/src/runtime/agent-core.js +54 -33
- package/src/runtime/headless-stream.js +89 -10
- package/src/assets/web-panel/assets/Logs-qSuwMwk7.js +0 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BgnYTegK.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-B5F8bnWt.js +0 -1
- package/src/assets/web-panel/assets/Projects-C51w0LnM.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CRyXoGo9.js +0 -1
- package/src/assets/web-panel/assets/index-C-W0Ntk_.js +0 -1
- package/src/assets/web-panel/assets/index-CCk_qhBx.js +0 -1
- package/src/assets/web-panel/assets/markdown-CsiA8-E5.js +0 -50
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { readBoundedDescriptor } from "./evolution/bounded-descriptor-read.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
withEvolutionDirectoryFileIdentity,
|
|
7
|
+
withEvolutionFileIdentity,
|
|
8
|
+
} from "./evolution/evolution-file-identity.js";
|
|
6
9
|
import { artifactPhysicalIdentity } from "./evolution/evolution-artifact-identity.js";
|
|
7
10
|
|
|
8
11
|
export const ARTIFACT_BOUNDED_READ_FAILED_CODE =
|
|
@@ -67,10 +70,10 @@ function sameStat(left, right) {
|
|
|
67
70
|
);
|
|
68
71
|
}
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
function assertReadArguments(args) {
|
|
74
|
+
const [target, expectedSize, maximumBytes] = args;
|
|
72
75
|
if (
|
|
73
|
-
|
|
76
|
+
args.length !== 3 ||
|
|
74
77
|
typeof target !== "string" ||
|
|
75
78
|
!path.isAbsolute(target) ||
|
|
76
79
|
path.resolve(target) !== target ||
|
|
@@ -83,49 +86,128 @@ export function readBoundedArtifactFile(target, expectedSize, maximumBytes) {
|
|
|
83
86
|
throw new TypeError(
|
|
84
87
|
"bounded artifact read requires a canonical path and finite size bounds",
|
|
85
88
|
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function readWithIdentity(target, expectedSize, maximumBytes, samePathHandle) {
|
|
92
|
+
const before = fs.lstatSync(target, { bigint: true });
|
|
93
|
+
safeStat(before, expectedSize, maximumBytes, "artifact path");
|
|
94
|
+
if (canonical(fs.realpathSync.native(target)) !== canonical(target))
|
|
95
|
+
fail("artifact path is not physically canonical");
|
|
96
|
+
const fd = fs.openSync(
|
|
97
|
+
target,
|
|
98
|
+
fs.constants.O_RDONLY |
|
|
99
|
+
(fs.constants.O_NOFOLLOW || 0) |
|
|
100
|
+
(fs.constants.O_NONBLOCK || 0),
|
|
101
|
+
);
|
|
86
102
|
try {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
103
|
+
const opened = fs.fstatSync(fd, { bigint: true });
|
|
104
|
+
safeStat(opened, expectedSize, maximumBytes, "artifact descriptor");
|
|
105
|
+
if (!samePathHandle(before, opened) || !sameMetadata(before, opened))
|
|
106
|
+
fail("artifact path and descriptor identities differ");
|
|
107
|
+
const bytes = readBoundedDescriptor(
|
|
108
|
+
fs,
|
|
109
|
+
fd,
|
|
110
|
+
Number(opened.size),
|
|
111
|
+
maximumBytes,
|
|
112
|
+
);
|
|
113
|
+
const closed = fs.fstatSync(fd, { bigint: true });
|
|
114
|
+
const after = fs.lstatSync(target, { bigint: true });
|
|
115
|
+
safeStat(closed, expectedSize, maximumBytes, "artifact descriptor");
|
|
116
|
+
safeStat(after, expectedSize, maximumBytes, "artifact path");
|
|
117
|
+
if (!sameStat(opened, closed))
|
|
118
|
+
fail("artifact descriptor changed during bounded read");
|
|
119
|
+
if (
|
|
120
|
+
!sameStat(before, after) ||
|
|
121
|
+
!samePathHandle(after, closed) ||
|
|
122
|
+
!sameMetadata(after, closed) ||
|
|
123
|
+
canonical(fs.realpathSync.native(target)) !== canonical(target)
|
|
124
|
+
)
|
|
125
|
+
fail("artifact pathname changed during bounded read");
|
|
126
|
+
return bytes;
|
|
127
|
+
} finally {
|
|
128
|
+
fs.closeSync(fd);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function wrapReadFailure(cause) {
|
|
133
|
+
if (cause?.code === ARTIFACT_BOUNDED_READ_FAILED_CODE) throw cause;
|
|
134
|
+
fail("artifact bounded descriptor read failed", cause);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Read one stable window only. Callers retain hash/signature and root checks. */
|
|
138
|
+
export function readBoundedArtifactFile(target, expectedSize, maximumBytes) {
|
|
139
|
+
assertReadArguments(arguments);
|
|
140
|
+
try {
|
|
141
|
+
return withEvolutionFileIdentity(DIRECTORY_FS, target, (samePathHandle) =>
|
|
142
|
+
readWithIdentity(target, expectedSize, maximumBytes, samePathHandle),
|
|
143
|
+
);
|
|
144
|
+
} catch (cause) {
|
|
145
|
+
wrapReadFailure(cause);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* A synchronous batch shares one authenticated parent handle, never file
|
|
151
|
+
* contents or authority. Each child keeps the complete independent read
|
|
152
|
+
* window above. The parent is reattested before the batch can return.
|
|
153
|
+
*/
|
|
154
|
+
export function withBoundedArtifactDirectoryRead(directory, callback) {
|
|
155
|
+
if (
|
|
156
|
+
arguments.length !== 2 ||
|
|
157
|
+
typeof directory !== "string" ||
|
|
158
|
+
!path.isAbsolute(directory) ||
|
|
159
|
+
path.resolve(directory) !== directory ||
|
|
160
|
+
typeof callback !== "function" ||
|
|
161
|
+
callback.constructor?.name === "AsyncFunction"
|
|
162
|
+
)
|
|
163
|
+
throw new TypeError(
|
|
164
|
+
"bounded artifact directory read requires a canonical directory and synchronous callback",
|
|
165
|
+
);
|
|
166
|
+
let callbackFailure = null;
|
|
167
|
+
try {
|
|
168
|
+
return withEvolutionDirectoryFileIdentity(
|
|
169
|
+
DIRECTORY_FS,
|
|
170
|
+
directory,
|
|
171
|
+
(samePathHandle, _sameStableHandle, { parentPath }) => {
|
|
172
|
+
if (canonical(parentPath) !== canonical(directory))
|
|
173
|
+
fail("artifact batch parent is not physically canonical");
|
|
174
|
+
let active = true;
|
|
175
|
+
const read = Object.freeze((...args) => {
|
|
176
|
+
if (!active) fail("artifact batch read window is closed");
|
|
177
|
+
assertReadArguments(args);
|
|
178
|
+
const [target, expectedSize, maximumBytes] = args;
|
|
179
|
+
if (canonical(path.dirname(target)) !== canonical(parentPath))
|
|
180
|
+
fail(
|
|
181
|
+
"artifact batch read must name a direct child of its captured parent",
|
|
182
|
+
);
|
|
183
|
+
try {
|
|
184
|
+
return readWithIdentity(
|
|
185
|
+
target,
|
|
186
|
+
expectedSize,
|
|
187
|
+
maximumBytes,
|
|
188
|
+
samePathHandle,
|
|
189
|
+
);
|
|
190
|
+
} catch (cause) {
|
|
191
|
+
wrapReadFailure(cause);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
try {
|
|
195
|
+
const result = callback(read);
|
|
196
|
+
if (result && typeof result.then === "function")
|
|
197
|
+
throw new TypeError(
|
|
198
|
+
"artifact batch callback must not return a promise",
|
|
199
|
+
);
|
|
200
|
+
return result;
|
|
201
|
+
} catch (cause) {
|
|
202
|
+
callbackFailure = cause;
|
|
203
|
+
throw cause;
|
|
204
|
+
} finally {
|
|
205
|
+
active = false;
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
);
|
|
127
209
|
} catch (cause) {
|
|
128
|
-
if (cause
|
|
129
|
-
|
|
210
|
+
if (cause === callbackFailure) throw cause;
|
|
211
|
+
wrapReadFailure(cause);
|
|
130
212
|
}
|
|
131
213
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import { types } from "node:util";
|
|
3
3
|
import evolutionRun from "@chainlesschain/session-core/evolution-run";
|
|
4
|
+
import { storageFailureCauseSuffix } from "../storage-failure-cause-codes.js";
|
|
4
5
|
|
|
5
6
|
import { EvolutionEvidenceArtifactAdapter } from "./evolution-evidence-artifact-adapter.js";
|
|
6
7
|
import {
|
|
@@ -8,7 +9,14 @@ import {
|
|
|
8
9
|
EVOLUTION_SKILL_DECISION_PROJECTION_RULESET_DIGEST,
|
|
9
10
|
EVOLUTION_PROJECTION_RULESET_DIGEST,
|
|
10
11
|
} from "./evolution-evidence-projector.js";
|
|
11
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
EvolutionRunLedgerAdapter,
|
|
14
|
+
captureEvolutionRunAppendNext,
|
|
15
|
+
} from "./evolution-run-ledger-adapter.js";
|
|
16
|
+
import {
|
|
17
|
+
evidenceStorageLayoutForRun,
|
|
18
|
+
validateEvidenceStorageLayout,
|
|
19
|
+
} from "./evolution-evidence-storage-layout.js";
|
|
12
20
|
import { captureEvolutionRunWikiMaintenanceProducer } from "./evolution-run-wiki-maintenance-source.js";
|
|
13
21
|
import { WIKI_MAINTENANCE_TRIGGER_KIND } from "./wiki-maintenance-trigger-ledger-adapter.js";
|
|
14
22
|
import { captureEvolutionReleaseTrain } from "./evolution-release-train.js";
|
|
@@ -152,6 +160,7 @@ function ingressFailure(cause) {
|
|
|
152
160
|
`Agent evolution ingress failed: ${cause?.message || String(cause)}`,
|
|
153
161
|
{ cause },
|
|
154
162
|
);
|
|
163
|
+
error.message += storageFailureCauseSuffix(cause);
|
|
155
164
|
error.code = AGENT_EVOLUTION_INGRESS_FAILED_CODE;
|
|
156
165
|
return error;
|
|
157
166
|
}
|
|
@@ -165,6 +174,7 @@ function guardIngress(operation) {
|
|
|
165
174
|
export function createAgentEvolutionIngress({
|
|
166
175
|
evidenceAdapter,
|
|
167
176
|
runAdapter,
|
|
177
|
+
evidenceStorageLayout = "legacy",
|
|
168
178
|
sourceEnvelopeAuthority,
|
|
169
179
|
openCacheSourceRun = null,
|
|
170
180
|
wikiMaintenanceProducer = null,
|
|
@@ -173,6 +183,7 @@ export function createAgentEvolutionIngress({
|
|
|
173
183
|
now = () => new Date(),
|
|
174
184
|
idGenerator = () => crypto.randomUUID(),
|
|
175
185
|
} = {}) {
|
|
186
|
+
validateEvidenceStorageLayout(evidenceStorageLayout);
|
|
176
187
|
if (!(evidenceAdapter instanceof EvolutionEvidenceArtifactAdapter)) {
|
|
177
188
|
throw new TypeError("an EvolutionEvidenceArtifactAdapter is required");
|
|
178
189
|
}
|
|
@@ -245,10 +256,24 @@ export function createAgentEvolutionIngress({
|
|
|
245
256
|
return timestamp(iso, "ingress timestamp");
|
|
246
257
|
};
|
|
247
258
|
|
|
259
|
+
const assertLoadedLayout = (loaded) => {
|
|
260
|
+
if (
|
|
261
|
+
evidenceStorageLayoutForRun(loaded.events, evidenceStorageLayout) !==
|
|
262
|
+
evidenceStorageLayout
|
|
263
|
+
)
|
|
264
|
+
throw new Error("Authenticated Run Evidence storage layout changed");
|
|
265
|
+
};
|
|
266
|
+
|
|
248
267
|
const appendStarted = () => {
|
|
249
268
|
const loaded = runAdapter.load();
|
|
269
|
+
assertLoadedLayout(loaded);
|
|
250
270
|
if (loaded.events.length > 0) return loaded.projection;
|
|
251
271
|
const occurredAt = currentTimestamp();
|
|
272
|
+
const data = {
|
|
273
|
+
occurredAt,
|
|
274
|
+
runtime: "agent",
|
|
275
|
+
...(evidenceStorageLayout === "legacy" ? {} : { evidenceStorageLayout }),
|
|
276
|
+
};
|
|
252
277
|
return runAdapter.appendEvent({
|
|
253
278
|
schema: EVOLUTION_RUN_EVENT_SCHEMA,
|
|
254
279
|
tenantId: descriptor.tenantId,
|
|
@@ -257,10 +282,10 @@ export function createAgentEvolutionIngress({
|
|
|
257
282
|
sequence: 1,
|
|
258
283
|
type: EVENT_TYPES.RUN_STARTED,
|
|
259
284
|
subjectId: descriptor.runId,
|
|
260
|
-
payloadDigest: digest(
|
|
285
|
+
payloadDigest: digest(data),
|
|
261
286
|
artifactRef: null,
|
|
262
287
|
keyRef: null,
|
|
263
|
-
data
|
|
288
|
+
data,
|
|
264
289
|
}).projection;
|
|
265
290
|
};
|
|
266
291
|
|
|
@@ -347,13 +372,14 @@ export function createAgentEvolutionIngress({
|
|
|
347
372
|
"Agent evidence persistence returned an unbound result",
|
|
348
373
|
);
|
|
349
374
|
}
|
|
350
|
-
const
|
|
351
|
-
|
|
375
|
+
const appendNext = captureEvolutionRunAppendNext(runAdapter);
|
|
376
|
+
// Custom ports keep their established load-before-append phase.
|
|
377
|
+
const current = appendNext === null ? runAdapter.load() : null;
|
|
378
|
+
const event = {
|
|
352
379
|
schema: EVOLUTION_RUN_EVENT_SCHEMA,
|
|
353
380
|
tenantId: descriptor.tenantId,
|
|
354
381
|
runId: descriptor.runId,
|
|
355
382
|
eventId,
|
|
356
|
-
sequence: current.events.length + 1,
|
|
357
383
|
type: EVENT_TYPES.RAW_EVENT_REFERENCED,
|
|
358
384
|
subjectId: persisted.evidenceId,
|
|
359
385
|
payloadDigest: persisted.manifest.digest,
|
|
@@ -371,7 +397,14 @@ export function createAgentEvolutionIngress({
|
|
|
371
397
|
candidateSetDigest: skillDecisionRequest.candidateSetDigest,
|
|
372
398
|
}),
|
|
373
399
|
},
|
|
374
|
-
}
|
|
400
|
+
};
|
|
401
|
+
const appended =
|
|
402
|
+
appendNext !== null
|
|
403
|
+
? appendNext(event)
|
|
404
|
+
: runAdapter.appendEvent({
|
|
405
|
+
...event,
|
|
406
|
+
sequence: current.events.length + 1,
|
|
407
|
+
});
|
|
375
408
|
if (kind === "model-input") {
|
|
376
409
|
lastModelResponse = null;
|
|
377
410
|
modelAdmissionPending = true;
|
|
@@ -677,6 +710,7 @@ export function createAgentEvolutionIngress({
|
|
|
677
710
|
serialize(async () => {
|
|
678
711
|
if (admissionFailure !== null) throw admissionFailure;
|
|
679
712
|
const loaded = runAdapter.load();
|
|
713
|
+
assertLoadedLayout(loaded);
|
|
680
714
|
let projection;
|
|
681
715
|
if (loaded.projection?.status === "completed") {
|
|
682
716
|
projection = loaded.projection;
|
|
@@ -14,6 +14,11 @@ import {
|
|
|
14
14
|
EvolutionEvidenceReader,
|
|
15
15
|
} from "./evolution-evidence-projector.js";
|
|
16
16
|
import { EvolutionArtifactPorts } from "./evolution-artifact-ports.js";
|
|
17
|
+
import {
|
|
18
|
+
createTypedEvidenceArtifactPorts,
|
|
19
|
+
evidenceStorageLayoutForRun,
|
|
20
|
+
validateEvidenceStorageLayout,
|
|
21
|
+
} from "./evolution-evidence-storage-layout.js";
|
|
17
22
|
import {
|
|
18
23
|
captureEvolutionLedgerFileBackend,
|
|
19
24
|
createEvolutionLedgerFileBackend,
|
|
@@ -172,16 +177,14 @@ function layout(stateRootDir, tenantId, runId, initialize = true, fsImpl = fs) {
|
|
|
172
177
|
const result = Object.freeze({
|
|
173
178
|
rootDir,
|
|
174
179
|
artifactDir: path.join(scope, "artifacts"),
|
|
180
|
+
evidenceArtifactDir: path.join(scope, "evidence-artifacts"),
|
|
175
181
|
rawDir: path.join(scope, "raw"),
|
|
176
182
|
ledgerRootDir: path.join(scope, "ledger-events"),
|
|
177
183
|
ledgerAuthorityRootDir: path.join(scope, "ledger-authority"),
|
|
178
184
|
witnessFilePath: path.join(scope, "witness", "checkpoint.json"),
|
|
179
185
|
});
|
|
180
186
|
if (initialize) {
|
|
181
|
-
ensureDirectoryTreeDurable(
|
|
182
|
-
fsImpl,
|
|
183
|
-
path.dirname(result.witnessFilePath),
|
|
184
|
-
);
|
|
187
|
+
ensureDirectoryTreeDurable(fsImpl, path.dirname(result.witnessFilePath));
|
|
185
188
|
}
|
|
186
189
|
return result;
|
|
187
190
|
}
|
|
@@ -224,6 +227,7 @@ export function createAgentEvolutionRuntimeComposition({
|
|
|
224
227
|
stateRootDir,
|
|
225
228
|
authorities: authorityInput,
|
|
226
229
|
evidenceTtlMs,
|
|
230
|
+
evidenceStorageLayout = "legacy",
|
|
227
231
|
witnessId: witnessIdInput,
|
|
228
232
|
clock: clockInput = Date.now,
|
|
229
233
|
evidenceIdGenerator,
|
|
@@ -240,6 +244,7 @@ export function createAgentEvolutionRuntimeComposition({
|
|
|
240
244
|
witnessMaximumBytes,
|
|
241
245
|
ledgerV2: ledgerV2Input = null,
|
|
242
246
|
} = {}) {
|
|
247
|
+
validateEvidenceStorageLayout(evidenceStorageLayout);
|
|
243
248
|
const ledgerV2 =
|
|
244
249
|
ledgerV2Input === null
|
|
245
250
|
? null
|
|
@@ -445,14 +450,6 @@ export function createAgentEvolutionRuntimeComposition({
|
|
|
445
450
|
attestationVerifier: ports.attestationVerifier,
|
|
446
451
|
now: () => new Date(clock()),
|
|
447
452
|
});
|
|
448
|
-
const evidenceAdapter = new EvolutionEvidenceArtifactAdapter({
|
|
449
|
-
tenantId,
|
|
450
|
-
audience,
|
|
451
|
-
projector,
|
|
452
|
-
bundleVerifier,
|
|
453
|
-
artifactPorts,
|
|
454
|
-
...(evidenceTtlMs === undefined ? {} : { ttlMs: evidenceTtlMs }),
|
|
455
|
-
});
|
|
456
453
|
const ledgerArtifactResolver =
|
|
457
454
|
artifactPorts.createEvolutionLedgerArtifactResolver({
|
|
458
455
|
purpose: "evolution-ledger",
|
|
@@ -516,6 +513,46 @@ export function createAgentEvolutionRuntimeComposition({
|
|
|
516
513
|
ledgerArtifactResolver,
|
|
517
514
|
now: clock,
|
|
518
515
|
});
|
|
516
|
+
const createEvidenceAdapter = (run, runStorage, mainPorts, emptyLayout) => {
|
|
517
|
+
const loaded = run.load();
|
|
518
|
+
const selectedLayout = evidenceStorageLayoutForRun(
|
|
519
|
+
loaded.events,
|
|
520
|
+
emptyLayout,
|
|
521
|
+
);
|
|
522
|
+
return {
|
|
523
|
+
selectedLayout,
|
|
524
|
+
adapter: new EvolutionEvidenceArtifactAdapter({
|
|
525
|
+
tenantId,
|
|
526
|
+
audience,
|
|
527
|
+
projector,
|
|
528
|
+
bundleVerifier,
|
|
529
|
+
...(selectedLayout === "legacy"
|
|
530
|
+
? { artifactPorts: mainPorts }
|
|
531
|
+
: {
|
|
532
|
+
typedArtifactPorts: createTypedEvidenceArtifactPorts({
|
|
533
|
+
rootDir: runStorage.evidenceArtifactDir,
|
|
534
|
+
tenantId,
|
|
535
|
+
audience,
|
|
536
|
+
artifactAuthority: {
|
|
537
|
+
envelopeSigner: ports.artifactEnvelopeSigner,
|
|
538
|
+
envelopeVerifier: ports.artifactEnvelopeVerifier,
|
|
539
|
+
currentAuthorityResolver:
|
|
540
|
+
ports.artifactCurrentAuthorityResolver,
|
|
541
|
+
},
|
|
542
|
+
now: clock,
|
|
543
|
+
existingRun: loaded.events.length > 0,
|
|
544
|
+
}),
|
|
545
|
+
}),
|
|
546
|
+
...(evidenceTtlMs === undefined ? {} : { ttlMs: evidenceTtlMs }),
|
|
547
|
+
}),
|
|
548
|
+
};
|
|
549
|
+
};
|
|
550
|
+
const { adapter: evidenceAdapter, selectedLayout } = createEvidenceAdapter(
|
|
551
|
+
runAdapter,
|
|
552
|
+
storage,
|
|
553
|
+
artifactPorts,
|
|
554
|
+
evidenceStorageLayout,
|
|
555
|
+
);
|
|
519
556
|
let wikiMaintenance = null;
|
|
520
557
|
let wikiMaintainer = null;
|
|
521
558
|
if (wikiConfiguration !== null) {
|
|
@@ -707,6 +744,7 @@ export function createAgentEvolutionRuntimeComposition({
|
|
|
707
744
|
const evolutionIngress = createAgentEvolutionIngress({
|
|
708
745
|
evidenceAdapter,
|
|
709
746
|
runAdapter,
|
|
747
|
+
evidenceStorageLayout: selectedLayout,
|
|
710
748
|
openCacheSourceRun: (input) => {
|
|
711
749
|
const sourceRunId = identifier(input, "cache source runId");
|
|
712
750
|
const sourceStorage = layout(
|
|
@@ -758,22 +796,22 @@ export function createAgentEvolutionRuntimeComposition({
|
|
|
758
796
|
...(lockTimeoutMs === undefined ? {} : { lockTimeoutMs }),
|
|
759
797
|
...(witnessMaximumBytes === undefined ? {} : { witnessMaximumBytes }),
|
|
760
798
|
});
|
|
799
|
+
const sourceRunAdapter = new EvolutionRunLedgerAdapter({
|
|
800
|
+
descriptor: { ...runAdapter.descriptor, runId: sourceRunId },
|
|
801
|
+
artifactPorts: sourcePorts,
|
|
802
|
+
ledger: sourceBackend.ledger,
|
|
803
|
+
ledgerArtifactResolver: sourceResolver,
|
|
804
|
+
now: clock,
|
|
805
|
+
});
|
|
806
|
+
const sourceEvidence = createEvidenceAdapter(
|
|
807
|
+
sourceRunAdapter,
|
|
808
|
+
sourceStorage,
|
|
809
|
+
sourcePorts,
|
|
810
|
+
"legacy",
|
|
811
|
+
);
|
|
761
812
|
return {
|
|
762
|
-
runAdapter:
|
|
763
|
-
|
|
764
|
-
artifactPorts: sourcePorts,
|
|
765
|
-
ledger: sourceBackend.ledger,
|
|
766
|
-
ledgerArtifactResolver: sourceResolver,
|
|
767
|
-
now: clock,
|
|
768
|
-
}),
|
|
769
|
-
evidenceAdapter: new EvolutionEvidenceArtifactAdapter({
|
|
770
|
-
tenantId,
|
|
771
|
-
audience,
|
|
772
|
-
projector,
|
|
773
|
-
bundleVerifier,
|
|
774
|
-
artifactPorts: sourcePorts,
|
|
775
|
-
...(evidenceTtlMs === undefined ? {} : { ttlMs: evidenceTtlMs }),
|
|
776
|
-
}),
|
|
813
|
+
runAdapter: sourceRunAdapter,
|
|
814
|
+
evidenceAdapter: sourceEvidence.adapter,
|
|
777
815
|
};
|
|
778
816
|
},
|
|
779
817
|
sourceEnvelopeAuthority: ports.sourceEnvelope,
|
|
@@ -21,6 +21,43 @@ export const AGENT_CODE_TEXT_RESULT_TOOLS = Object.freeze([
|
|
|
21
21
|
"search_files",
|
|
22
22
|
]);
|
|
23
23
|
|
|
24
|
+
export const AGENT_FENCED_CODE_LANGUAGES = Object.freeze([
|
|
25
|
+
"javascript",
|
|
26
|
+
"js",
|
|
27
|
+
"typescript",
|
|
28
|
+
"ts",
|
|
29
|
+
"jsx",
|
|
30
|
+
"tsx",
|
|
31
|
+
"python",
|
|
32
|
+
"py",
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
function fencedCodeRanges(text, languages) {
|
|
36
|
+
const ranges = [];
|
|
37
|
+
const fences = /^ {0,3}(`{3,}|~{3,})([^\r\n]*)\r?$/gmu;
|
|
38
|
+
let opening = null;
|
|
39
|
+
for (const match of text.matchAll(fences)) {
|
|
40
|
+
const marker = match[1];
|
|
41
|
+
const info = match[2].trim().toLowerCase();
|
|
42
|
+
if (opening === null) {
|
|
43
|
+
opening = {
|
|
44
|
+
marker,
|
|
45
|
+
supported: languages.includes(info),
|
|
46
|
+
start: match.index + match[0].length,
|
|
47
|
+
};
|
|
48
|
+
} else if (
|
|
49
|
+
marker[0] === opening.marker[0] &&
|
|
50
|
+
marker.length >= opening.marker.length &&
|
|
51
|
+
info === ""
|
|
52
|
+
) {
|
|
53
|
+
if (opening.supported) ranges.push([opening.start, match.index]);
|
|
54
|
+
opening = null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Unclosed/unknown fences never acquire code semantics.
|
|
58
|
+
return ranges;
|
|
59
|
+
}
|
|
60
|
+
|
|
24
61
|
/* eslint-disable no-control-regex -- Quoted literals exclude unescaped control bytes. */
|
|
25
62
|
const JSON_STRING_PREFIX =
|
|
26
63
|
/^"(?:[^"\\\x00-\x1f]|\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4}))*"/u;
|
|
@@ -28,6 +65,28 @@ const CODE_DOUBLE_QUOTED_PREFIX = /^"(?:[^"\\\x00-\x1f]|\\[\s\S])*"/u;
|
|
|
28
65
|
const CODE_SINGLE_QUOTED_PREFIX = /^'(?:[^'\\\x00-\x1f]|\\[\s\S])*'/u;
|
|
29
66
|
/* eslint-enable no-control-regex */
|
|
30
67
|
|
|
68
|
+
// Only closed, bounded display formats qualify. Never accept quotes, escapes,
|
|
69
|
+
// commas or nested containers here. Exponent-shaped hashes remain JSON numbers
|
|
70
|
+
// so non-finite/unsafe numeric values cannot evade the existing budget checks.
|
|
71
|
+
const DISPLAY_BRACKET_MARKER = new RegExp(
|
|
72
|
+
"^\\[(?:" +
|
|
73
|
+
"\\d+[ \\t]+\\d+(?:[ \\t]+\\d+)*|" +
|
|
74
|
+
"\\d+[ \\t]*\\/[ \\t]*\\d+(?:[ \\t]+\\d{1,3}%)?|" +
|
|
75
|
+
"\\d+[ \\t]+of[ \\t]+\\d+|" +
|
|
76
|
+
"\\d{1,3}(?:\\.\\d+)?%|" +
|
|
77
|
+
"\\d{4}-\\d{2}-\\d{2}(?:[ T]\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,9})?(?:Z|[+-]\\d{2}:\\d{2})?)?|" +
|
|
78
|
+
"\\d{1,2}:\\d{2}(?::\\d{2}(?:\\.\\d{1,9})?)?|" +
|
|
79
|
+
"v?\\d+\\.\\d+\\.\\d+|" +
|
|
80
|
+
"[0-9]-[0-9]|" +
|
|
81
|
+
"\\[[A-Za-z][A-Za-z0-9_./ #+-]*\\]|" +
|
|
82
|
+
"[ \\t]+\\d+[ \\t]+-(?:eq|ne|lt|le|gt|ge)[ \\t]+\\d+[ \\t]+|" +
|
|
83
|
+
"\\[[ \\t]+-[defrswx][ \\t]+[A-Za-z0-9_./-]+[ \\t]+\\]|" +
|
|
84
|
+
"(?!\\d+[eE]\\d+\\])(?=[0-9a-f]{7,64}\\])(?=[0-9a-f]*[a-f])[0-9][0-9a-f]+|" +
|
|
85
|
+
"[0-9a-f]{7,64}\\.\\.[0-9a-f]{7,64}" +
|
|
86
|
+
")\\]",
|
|
87
|
+
"u",
|
|
88
|
+
);
|
|
89
|
+
|
|
31
90
|
export function isAgentToolArgumentsPath(path) {
|
|
32
91
|
return (
|
|
33
92
|
path.length === 6 &&
|
|
@@ -255,6 +314,14 @@ export function createEvidenceJsonTextBoundary(
|
|
|
255
314
|
);
|
|
256
315
|
}
|
|
257
316
|
index += token.length;
|
|
317
|
+
// A primitive prefix is not a complete source expression. In particular,
|
|
318
|
+
// redacting only `true` from trueSecretValue would expose the suffix of
|
|
319
|
+
// a sensitive quoted assignment. Historical policies retain their parser.
|
|
320
|
+
if (
|
|
321
|
+
policy.proseQuotedPairPolicy &&
|
|
322
|
+
/[\p{ID_Continue}$\\]/u.test(text[index] ?? "")
|
|
323
|
+
)
|
|
324
|
+
return parserReject("code-expression");
|
|
258
325
|
const parsed = JSON.parse(token);
|
|
259
326
|
if (
|
|
260
327
|
typeof parsed === "number" &&
|
|
@@ -271,10 +338,35 @@ export function createEvidenceJsonTextBoundary(
|
|
|
271
338
|
};
|
|
272
339
|
};
|
|
273
340
|
|
|
274
|
-
return (
|
|
341
|
+
return function scanText(
|
|
275
342
|
text,
|
|
276
|
-
{
|
|
277
|
-
|
|
343
|
+
{
|
|
344
|
+
layer = 0,
|
|
345
|
+
objectOnly = false,
|
|
346
|
+
codeText = false,
|
|
347
|
+
fencedCodeLanguages = null,
|
|
348
|
+
visit,
|
|
349
|
+
plain,
|
|
350
|
+
equal,
|
|
351
|
+
},
|
|
352
|
+
) {
|
|
353
|
+
if (!objectOnly && !codeText && fencedCodeLanguages) {
|
|
354
|
+
const ranges = fencedCodeRanges(text, fencedCodeLanguages);
|
|
355
|
+
if (ranges.length > 0) {
|
|
356
|
+
let output = "";
|
|
357
|
+
let offset = 0;
|
|
358
|
+
const options = { layer, visit, plain, equal };
|
|
359
|
+
for (const [start, end] of ranges) {
|
|
360
|
+
output += scanText(text.slice(offset, start), options);
|
|
361
|
+
output += scanText(text.slice(start, end), {
|
|
362
|
+
...options,
|
|
363
|
+
codeText: true,
|
|
364
|
+
});
|
|
365
|
+
offset = end;
|
|
366
|
+
}
|
|
367
|
+
return output + scanText(text.slice(offset), options);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
278
370
|
bytes += Buffer.byteLength(text, "utf8");
|
|
279
371
|
if (bytes > policy.maxDecodedBytes)
|
|
280
372
|
reject("Agent model JSON text exceeds its budget");
|
|
@@ -314,6 +406,26 @@ export function createEvidenceJsonTextBoundary(
|
|
|
314
406
|
char === "{" || char === "["
|
|
315
407
|
? text.slice(index + 1).match(/^\s*(.)/u)?.[1]
|
|
316
408
|
: undefined;
|
|
409
|
+
// Human-readable status markers are not JSON arrays. Only complete,
|
|
410
|
+
// bounded numeric formats qualify; quotes, escapes, commas and nested
|
|
411
|
+
// containers must still go through strict parsing. Leave these spans in
|
|
412
|
+
// plain text so the ordinary credential/PII sanitizer still sees them.
|
|
413
|
+
if (
|
|
414
|
+
char === "[" &&
|
|
415
|
+
policy.bracketMarkerPolicy === "bounded-display-markers-v1"
|
|
416
|
+
) {
|
|
417
|
+
// ANSI CSI controls in terminal output start with ESC followed by [.
|
|
418
|
+
// Limit recognition to numeric parameters and a final control letter.
|
|
419
|
+
const marker =
|
|
420
|
+
(text[index - 1] === "\x1b"
|
|
421
|
+
? /^\[[0-9;:?]{0,64}[A-Za-z]/u.exec(text.slice(index, index + 128))
|
|
422
|
+
: null) ??
|
|
423
|
+
DISPLAY_BRACKET_MARKER.exec(text.slice(index, index + 128));
|
|
424
|
+
if (marker) {
|
|
425
|
+
index += marker[0].length;
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
317
429
|
const container =
|
|
318
430
|
(char === "{" &&
|
|
319
431
|
(next === '"' || next === "}" || next === "'" || next === "\\")) ||
|
|
@@ -405,7 +517,7 @@ export function createEvidenceJsonTextBoundary(
|
|
|
405
517
|
const entryEnd = rhs.end();
|
|
406
518
|
rhs.whitespace();
|
|
407
519
|
if (
|
|
408
|
-
codeText &&
|
|
520
|
+
(codeText || policy.proseQuotedPairPolicy) &&
|
|
409
521
|
/^[+\-*/%?.([<>&|^=!"']/u.test(text[rhs.end()] ?? "")
|
|
410
522
|
)
|
|
411
523
|
requireSafeExpressionKey();
|
|
@@ -417,10 +529,14 @@ export function createEvidenceJsonTextBoundary(
|
|
|
417
529
|
} catch (error) {
|
|
418
530
|
const kind = error?.[PARSE_FAILURE];
|
|
419
531
|
if (kind === undefined) throw error;
|
|
420
|
-
if (
|
|
532
|
+
if (
|
|
533
|
+
(!codeText && !policy.proseQuotedPairPolicy) ||
|
|
534
|
+
kind !== "code-expression"
|
|
535
|
+
)
|
|
421
536
|
rejectParseFailure(error);
|
|
422
|
-
//
|
|
423
|
-
//
|
|
537
|
+
// A standalone prose label or a source key followed by an
|
|
538
|
+
// expression is not a broken JSON container. Sensitive decoded
|
|
539
|
+
// keys still fail closed before scanning resumes.
|
|
424
540
|
// Resume the scan at the next literal so any string value still
|
|
425
541
|
// receives key-aware or ordinary secret scanning.
|
|
426
542
|
requireSafeExpressionKey();
|
|
@@ -447,7 +563,7 @@ export function createEvidenceJsonTextBoundary(
|
|
|
447
563
|
}
|
|
448
564
|
const safe = transform(parsed);
|
|
449
565
|
if (
|
|
450
|
-
codeText &&
|
|
566
|
+
(codeText || policy.proseQuotedPairPolicy) &&
|
|
451
567
|
assignmentKey &&
|
|
452
568
|
!equal(parsed, safe) &&
|
|
453
569
|
/^\s*[+\-*/%?.([<>&|^=!"']/u.test(text.slice(end))
|