chainlesschain 0.165.4 → 0.165.5

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.
Files changed (180) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/{AIOps-C__nnraW.js → AIOps-CEeYTeDB.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-CsKWHEZ-.js → ActionButton-BeRUQ3V2.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-BhIjfjWO.js → Analytics-DrV718XF.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-BjuXFzWZ.js → AppLayout-Cd2Frt7Q.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-k6whDkZJ.js → Artifacts-CUJMlORU.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-C4FBMYRh.js → Audit-CXJcfT6p.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-C_vRrSXk.js → BackgroundAgents-DOv6Z7H9.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-CngFZeVp.js → Backup-BwdDyBI0.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-B_H9EBRm.js → BaseInput-BmLn4kYH.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-DLEC5kt7.js → Chat-COg8pAW2.js} +4 -4
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-4gGkdGgA.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-m3ClR4xh.js → Checkbox-BCP4uoU8.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-CmLSFrgp.js → Codegen-pRt6Y9JI.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-DFGQteHN.js → Col-DLaprKhS.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-EUUVORHE.js → Community-DyATsz5f.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-2PSg0Yr7.js → Compact-BXAaupZK.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-CcKur7gB.js → Compliance-DpcJBELr.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-DK_Fezfa.js → Cowork-DG4EFWyd.js} +2 -2
  21. package/src/assets/web-panel/assets/{Cron-Dbw89xl7.js → Cron-F6Oy5n2P.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-CH66h_Ec.js → Crosschain-BOdgtalX.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-D1igRb17.js → DID-DT1dSkjH.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-DVAsrobk.js → Dashboard-NBUIqWzC.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-Dl7W8AQs.js → Dropdown-CSpHeMYB.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-D5tpaEQC.js → EmailListRenderer-CEG0xISr.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-O_VQf8gq.js → FamilyGuardDashboard-BTZ0BZna.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-BTVcgS9n.js → Federation-BuuCTn2V.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-BRnkJAIz.js → FormItemContext-KAVceevk.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-8OWSCkDj.js → GenericCardRenderer-DnHpcQvW.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-WXLYTQj2.js → Git-C_B_0HwB.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-BezaUhtc.js → Governance-DPSZuzuu.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-CuRay3Gu.js → Inference-BV-06V7q.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-DfWLDW1m.js → KnowledgeGraph-wpDuupn6.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-C55y2pPY.js → Logs-Bseca1_I.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-B4RLp2zs.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-Dk08Uycg.js → Marketplace-d3kM4DDL.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-C11fSB5V.js → McpTools-DQ_xZ23i.js} +3 -3
  39. package/src/assets/web-panel/assets/{Memory-mr0eZc97.js → Memory-CRIeYO4L.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-C0iCSRbb.js → MobileBridge-BsllIa9l.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-CY-xMG8Z.js → MobileProjects-BUuQy30X.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-Bplqc_Wc.js → Mtc-BOFDIzrC.js} +2 -2
  43. package/src/assets/web-panel/assets/{MtcAudit-BlzwsoSM.js → MtcAudit-BQg-vyvG.js} +5 -5
  44. package/src/assets/web-panel/assets/{Multisig-BBLmTty6.js → Multisig-Bo1jrPdN.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-DtT1uf1W.js → NLProgramming-Bmod8alw.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-DcqQAxTK.js → Notes-CGGFL8w-.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-cb0kWoZe.js → NotificationSettings-BsZvCJxC.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-kw9HZQNN.js → OrderTableRenderer-C1-Quo_h.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-DlTlbkUN.js → Organization-BjOeDYOi.js} +2 -2
  50. package/src/assets/web-panel/assets/{Overflow-pp1qs-oY.js → Overflow-DwVV3l5A.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-BESLnyYz.js → P2P-Cu3DQT9W.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-B-J1mGuf.js → PdhVaultBrowser-Cg0gR7dH.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-B36PeT1_.js → Permissions-CsAXxRN5.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-CTK2ad-3.js → PersonalDataHub-C-nNmnYp.js} +4 -4
  55. package/src/assets/web-panel/assets/{Pipeline-zJNGXsac.js → Pipeline-BOnW7nNc.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-b9fz0Qf0.js → Privacy-ClLSyGKt.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-DjZbZgiB.js → ProjectInit-DuLvjjq7.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-C-hHJXlD.js → ProjectSettings-DQYYbDD9.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-Drw8MBGK.js +1 -0
  60. package/src/assets/web-panel/assets/Providers-ckqHQe6K.js +1 -0
  61. package/src/assets/web-panel/assets/{QrScannerModal-A0yoQ3-3.js → QrScannerModal-DW5BXk-G.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-DrFgFJNC.js → QuickAsk-DDLnhNTp.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-KC8hF1g4.js → Recommend-PJQ2C91U.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-DGTPIk6u.js → RemoteSession-s6wmda34.js} +2 -2
  65. package/src/assets/web-panel/assets/{Reputation-QmbwM7Yk.js → Reputation-DC2sb-I3.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-BxjJylia.js → Row-hPGk1eGj.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-B7Wda1J6.js → RssFeed-RIvfZql0.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-_plQ_YSA.js → Search-DFg1G1eR.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-CD2YJZfx.js → Security-D6H5p8Dp.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-qQE7NmwE.js → Services-nxYiFV_w.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-DgQqkFf7.js → Skeleton-BmgFNAdB.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-C4C0oFFt.js → Skills-CsaaD2av.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-Px2N2B5c.js → Sla-yM5y9yvK.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-DN6C3lQd.js → SpeechSettings-DPy1XMYh.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-jm5aH_m7.js → SyncSettings-CFVhEyyr.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-DlkJcv67.js → Tasks-DdO02Inn.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-DyrTHUBs.js → Templates-Eo2d8Llu.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-mC434PtL.js → Tenant-ChESOXgy.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-o0_s3NgK.js → Terminal-BJ7oDxTI.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-DAGlAXOw.js → TimelineRenderer-hWX0fUvz.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-BnulS_bs.js → Tokens-DVBZQnd-.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-suQbVXYM.js → Trigger-D89cQfVq.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-DbIJAPo5.js → Trust-BIVSb4-V.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-CQNpbIHi.js → UkeySign-B58gWopl.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-D8aWCERk.js → VideoEditing-DhHI7bmG.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-CuLpYfZc.js → Wallet-C4FheWS_.js} +3 -3
  87. package/src/assets/web-panel/assets/{WebAuthn-CsfG8ZMc.js → WebAuthn-DnPRq-Bx.js} +3 -3
  88. package/src/assets/web-panel/assets/{WorkflowEditor-BYsEAZbd.js → WorkflowEditor-BerRPjpJ.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-FT4Um3-I.js → chat-BzZ52iKr.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-CKbS_Wlt.js → colors-BI_E4BAn.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-CFJtzuJM.js → compact-item-d50mr3yk.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-B9kSRW6K.js → createContext-C6FsQ1IH.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-CagEcIex.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-DR-x0Xpi.js → hasIn-DLZEMgLP.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-DdkIhfi-.js → index-9H_M2jju.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BfFCQHL3.js → index-A5CDWP7y.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-7jHr_A_k.js → index-AHr7ryWf.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BVPU43b1.js → index-B81mo1Et.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-B3ZX81mK.js → index-BAE3hwev.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DMGmg497.js → index-BB9SqVSt.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-B7osrXqy.js → index-BRGx3w6T.js} +3 -3
  102. package/src/assets/web-panel/assets/{index-Bt4fS2eL.js → index-BTpIOTfR.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-WE08gMJP.js → index-BZjjdQ62.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BwR7yc2h.js → index-BcSUl9fA.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DtkFqPVA.js → index-BeM4hfht.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BGbPnC5x.js → index-Bmr_vxXD.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DjEP7WkH.js → index-BoNZlzhQ.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-r2VI1Ikk.js → index-C3k8kevG.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DeSgw-WV.js → index-CLoTQr0W.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-C_enk9I_.js → index-CO8DAF7U.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CJmIQ9XR.js → index-CRN5TRTQ.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Dap9c3eD.js → index-CUaEHfQ0.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-KqDaCApw.js → index-CVzuawCX.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BK3TiKVq.js → index-CdKt9fOd.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-OSzjTzGM.js → index-CgkoH3_g.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DW4BWjTk.js → index-CjuKZBqJ.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C2JvmYRc.js → index-Co7s9LsB.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-DiNUEpSQ.js → index-D-aBumtY.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-BW-t9n-q.js → index-DE0V6cp-.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Bzz0C1BZ.js → index-DY4j5zkF.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-Cr2FLUsD.js → index-Dec0Kf_Z.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DShSkww-.js → index-DoFtCVZ7.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DTxNy0ZU.js → index-DqkbHHg8.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CvrCCqJt.js → index-DsscwxPE.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DWdqx7zI.js → index-GXE0D8Nx.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-tqSEHPRT.js → index-IPkwSAW_.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DcfxhKXR.js → index-KNGgO4Wm.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CGaXUsIs.js → index-Pvf30m8Q.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-D4LfPvWA.js → index-Q5Tn735s.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BI5hP_qy.js → index-TWG-_D1M.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-QBSeNVO3.js → index-Y2-q7QLm.js} +1 -1
  132. package/src/assets/web-panel/assets/index-pzT9PpOU.js +1 -0
  133. package/src/assets/web-panel/assets/index-z1kFadaX.js +1 -0
  134. package/src/assets/web-panel/assets/{initDefaultProps-Dd7n7VgI.js → initDefaultProps-D-4Hzgej.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BwxouRw1.js → motion-D4Wl4xU7.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-DObN0PG9.js → move-Cd5eQvL0.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-B3nOUQc7.js → mtc-parser-B4ilslCW.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-o9WU2Nbl.js → omit-Ckarx-tf.js} +1 -1
  139. package/src/assets/web-panel/assets/parsers-YNLm7sQ0.js +4 -0
  140. package/src/assets/web-panel/assets/{pickAttrs-CL_vvfQ_.js → pickAttrs-QJ0bpCmc.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-CYrM2tyK.js → placementArrow-CKHm-tq8.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-k_06cQ96.js → responsiveObserve-CV6a_w_Y.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-CPKG0pxS.js → slide-mHpeQFgk.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-BDDEeLTw.js → statusUtils-DIaQNQWA.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-Cmb7RTh7.js → styleChecker-PJpzavV8.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-e2IedC4N.js → useFlexGapSupport-BH7zTw8S.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-CE_gxVnm.js → useFs-BDNG3JDd.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-BkMIIKMz.js → usePersonalDataHub-CY2VWdUg.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-DW886XV1.js → vnode-D0kw9jhz.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-Dwo_adaf.js → zoom-B5g7TN7r.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/command-help-index.json +1 -1
  153. package/src/commands/artifacts.js +235 -0
  154. package/src/commands/cowork.js +86 -57
  155. package/src/commands/session-location.js +20 -1
  156. package/src/commands/session.js +64 -69
  157. package/src/data/changelog.json +16 -3
  158. package/src/gateways/ws/message-dispatcher.js +57 -0
  159. package/src/lib/artifact-access-ledger.js +1 -0
  160. package/src/lib/artifact-deletion-ledger.js +1 -0
  161. package/src/lib/artifact-recovery.js +970 -0
  162. package/src/lib/artifact-workbench-projection.js +171 -0
  163. package/src/lib/dynamic-workflow-runtime.js +408 -1
  164. package/src/lib/execution-location-target.js +4 -2
  165. package/src/lib/mcp-stdio-executable-identity.js +16 -0
  166. package/src/lib/mcp-stdio-native-code-policy.js +74 -0
  167. package/src/lib/mcp-stdio-package-materialization.js +12 -3
  168. package/src/lib/process-execution-broker/index.js +112 -0
  169. package/src/lib/process-execution-broker/platform-sandbox.js +57 -3
  170. package/src/lib/process-execution-broker/workspace-transaction.js +26 -0
  171. package/src/lib/session-projection.js +126 -10
  172. package/src/runtime/agent-core.js +12 -0
  173. package/src/assets/web-panel/assets/ChatBubbleRenderer-xijcWkJe.js +0 -1
  174. package/src/assets/web-panel/assets/MarkdownRenderer-hDpWdiBc.js +0 -1
  175. package/src/assets/web-panel/assets/Projects-BC9KSDM6.js +0 -1
  176. package/src/assets/web-panel/assets/Providers-Dz-CAYYU.js +0 -1
  177. package/src/assets/web-panel/assets/devWarning-DJZ0gAMu.js +0 -1
  178. package/src/assets/web-panel/assets/index-Bizb4hkw.js +0 -1
  179. package/src/assets/web-panel/assets/index-OHSl-xCh.js +0 -1
  180. package/src/assets/web-panel/assets/parsers-UEvh_ShA.js +0 -4
@@ -0,0 +1,171 @@
1
+ import { publicArtifactMetadata } from "./artifact-store.js";
2
+ import { readArtifactAccessLedger } from "./artifact-access-ledger.js";
3
+ import { readArtifactCleanupLedger } from "./artifact-cleanup-ledger.js";
4
+ import { readArtifactDeletionLedger } from "./artifact-deletion-ledger.js";
5
+ import {
6
+ buildArtifactRecoveryPlan,
7
+ readArtifactOrphanGcLedger,
8
+ } from "./artifact-recovery.js";
9
+
10
+ export const ARTIFACT_WORKBENCH_PROJECTION_SCHEMA = "cc-artifact-workbench/v1";
11
+ export const MAX_ARTIFACT_WORKBENCH_ACTIVITY = 200;
12
+
13
+ function returnedResultLineage(lineage) {
14
+ if (lineage?.schema !== "cc-execution-location-result-artifact-lineage/v1") {
15
+ return null;
16
+ }
17
+ const fields = [
18
+ "sessionId",
19
+ "requestId",
20
+ "reviewDigest",
21
+ "item",
22
+ "kind",
23
+ "mediaType",
24
+ "byteLength",
25
+ "sourceDigest",
26
+ ];
27
+ if (fields.some((field) => lineage[field] == null)) return null;
28
+ return Object.freeze(
29
+ Object.fromEntries(fields.map((field) => [field, lineage[field]])),
30
+ );
31
+ }
32
+
33
+ function accessActivity(event) {
34
+ return Object.freeze({
35
+ type: "access",
36
+ occurredAt: event.authorizedAt,
37
+ artifactId: event.artifactId,
38
+ artifactSessionId: event.artifactSessionId,
39
+ recordDigest: event.recordDigest,
40
+ action: event.action,
41
+ client: event.client,
42
+ settlementId: event.accessId,
43
+ eventDigest: event.eventDigest,
44
+ });
45
+ }
46
+
47
+ function deletionActivity(event) {
48
+ return Object.freeze({
49
+ type: "deletion",
50
+ phase: event.phase,
51
+ occurredAt: event.occurredAt,
52
+ artifactId: event.artifactId,
53
+ artifactSessionId: event.artifactSessionId,
54
+ recordDigest: event.recordDigest,
55
+ action: event.reason,
56
+ client: event.client,
57
+ settlementId: event.deletionId,
58
+ eventDigest: event.eventDigest,
59
+ });
60
+ }
61
+
62
+ function cleanupActivity(event) {
63
+ return Object.freeze({
64
+ type: "cleanup",
65
+ phase: event.phase,
66
+ occurredAt: event.occurredAt,
67
+ artifactId: null,
68
+ artifactSessionId: null,
69
+ recordDigest: null,
70
+ action: "expired",
71
+ client: event.client,
72
+ settlementId: event.cleanupId,
73
+ itemCount: event.itemCount,
74
+ eventDigest: event.eventDigest,
75
+ });
76
+ }
77
+
78
+ function orphanGcActivity(event) {
79
+ return Object.freeze({
80
+ type: "orphan-gc",
81
+ phase: event.phase,
82
+ occurredAt: event.occurredAt,
83
+ artifactId: null,
84
+ artifactSessionId: null,
85
+ recordDigest: null,
86
+ action: event.decision,
87
+ client: "administrator",
88
+ settlementId: event.adjudicationId,
89
+ outcome: event.outcome,
90
+ eventDigest: event.eventDigest,
91
+ });
92
+ }
93
+
94
+ function occurredAtMs(event) {
95
+ const parsed = Date.parse(event.occurredAt || "");
96
+ return Number.isFinite(parsed) ? parsed : 0;
97
+ }
98
+
99
+ export function buildArtifactWorkbenchProjection(store, options = {}) {
100
+ if (!store?.dir) {
101
+ throw new TypeError("artifact workbench requires an ArtifactStore");
102
+ }
103
+ const recovery = (
104
+ options.buildArtifactRecoveryPlan || buildArtifactRecoveryPlan
105
+ )(store, options.recoveryOptions || {});
106
+ const access = (options.readArtifactAccessLedger || readArtifactAccessLedger)(
107
+ store,
108
+ options.accessOptions || {},
109
+ );
110
+ const deletion = (
111
+ options.readArtifactDeletionLedger || readArtifactDeletionLedger
112
+ )(store, options.deletionOptions || {});
113
+ const cleanup = (
114
+ options.readArtifactCleanupLedger || readArtifactCleanupLedger
115
+ )(store, options.cleanupOptions || {});
116
+ const orphanGc = (
117
+ options.readArtifactOrphanGcLedger || readArtifactOrphanGcLedger
118
+ )(store, options.orphanGcOptions || {});
119
+ const accessByArtifact = new Map();
120
+ for (const event of access.events) {
121
+ const events = accessByArtifact.get(event.artifactId) || [];
122
+ events.push(event);
123
+ accessByArtifact.set(event.artifactId, events);
124
+ }
125
+ const artifacts = store.list().map((entry) => {
126
+ const metadata = publicArtifactMetadata(entry);
127
+ const accesses = accessByArtifact.get(entry.id) || [];
128
+ const latestAccess = accesses.at(-1) || null;
129
+ return Object.freeze({
130
+ ...metadata,
131
+ returnedResult: returnedResultLineage(metadata.lineage),
132
+ history: Object.freeze({
133
+ accessCount: accesses.length,
134
+ latestAccess: latestAccess
135
+ ? Object.freeze({
136
+ action: latestAccess.action,
137
+ client: latestAccess.client,
138
+ authorizedAt: latestAccess.authorizedAt,
139
+ eventDigest: latestAccess.eventDigest,
140
+ })
141
+ : null,
142
+ }),
143
+ });
144
+ });
145
+ const allActivity = [
146
+ ...access.events.map(accessActivity),
147
+ ...deletion.events.map(deletionActivity),
148
+ ...cleanup.events.map(cleanupActivity),
149
+ ...orphanGc.events.map(orphanGcActivity),
150
+ ].sort((left, right) => {
151
+ const time = occurredAtMs(right) - occurredAtMs(left);
152
+ return time || right.eventDigest.localeCompare(left.eventDigest);
153
+ });
154
+ const activity = allActivity.slice(0, MAX_ARTIFACT_WORKBENCH_ACTIVITY);
155
+ return Object.freeze({
156
+ schema: ARTIFACT_WORKBENCH_PROJECTION_SCHEMA,
157
+ observedAt: recovery.observedAt,
158
+ artifacts: Object.freeze(artifacts),
159
+ recovery,
160
+ history: Object.freeze({
161
+ accessHeadDigest: access.headDigest,
162
+ deletionHeadDigest: deletion.headDigest,
163
+ cleanupHeadDigest: cleanup.headDigest,
164
+ orphanGcHeadDigest: orphanGc.headDigest,
165
+ totalEventCount: allActivity.length,
166
+ returnedEventCount: activity.length,
167
+ truncated: allActivity.length > activity.length,
168
+ activity: Object.freeze(activity),
169
+ }),
170
+ });
171
+ }
@@ -71,6 +71,7 @@ const MAX_CALLS_PER_EFFECT = 128;
71
71
  const MAX_INPUT_REQUESTS = 64;
72
72
  const MAX_INPUT_OPTIONS = 32;
73
73
  const MAX_INPUT_RESPONSE_BYTES = 64 * 1024;
74
+ const MAX_WORKBENCH_RUN_FILES = 1024;
74
75
  const MAX_PROJECTED_ARTIFACTS_PER_EFFECT = 256;
75
76
  const MAX_PROVIDER_TOKEN_COUNT = 1_000_000_000;
76
77
  const MAX_PROVIDER_USD_RATE_PER_MILLION = 1_000_000;
@@ -1518,6 +1519,31 @@ export function verifyDynamicWorkflowRuntimeState(value) {
1518
1519
  ) {
1519
1520
  issues.push("authority-binding-invalid");
1520
1521
  }
1522
+ if (state.executionBudget !== undefined && state.executionBudget !== null) {
1523
+ const budget = state.executionBudget;
1524
+ const fields = [
1525
+ "maxExpandedTasks",
1526
+ "maxParallel",
1527
+ "maxTokens",
1528
+ "maxUsd",
1529
+ "maxDurationMs",
1530
+ ];
1531
+ const validBudget =
1532
+ budget &&
1533
+ typeof budget === "object" &&
1534
+ !Array.isArray(budget) &&
1535
+ Object.keys(budget).length === fields.length &&
1536
+ fields.every((field) => Object.hasOwn(budget, field)) &&
1537
+ fields.every((field) => {
1538
+ const amount = budget[field];
1539
+ if (amount === null) return true;
1540
+ if (!Number.isFinite(amount) || amount < 0) return false;
1541
+ return (
1542
+ field === "maxUsd" || (Number.isSafeInteger(amount) && amount >= 1)
1543
+ );
1544
+ });
1545
+ if (!validBudget) issues.push("execution-budget-invalid");
1546
+ }
1521
1547
  if (
1522
1548
  !Number.isSafeInteger(state.revision) ||
1523
1549
  state.revision < 1 ||
@@ -1981,6 +2007,11 @@ function stateBindings(execution, runId) {
1981
2007
  "workflow execution policy",
1982
2008
  64 * 1024,
1983
2009
  ),
2010
+ executionBudget: snapshotJson(
2011
+ execution.workflow?.facade?.budget || null,
2012
+ "workflow execution budget",
2013
+ 16 * 1024,
2014
+ ),
1984
2015
  };
1985
2016
  }
1986
2017
 
@@ -1994,7 +2025,10 @@ function bindingsMatch(state, bindings) {
1994
2025
  "executionAuthoritySessionId",
1995
2026
  ].every((field) => state[field] === bindings[field]) &&
1996
2027
  canonicalJson(state.executionPolicy) ===
1997
- canonicalJson(bindings.executionPolicy)
2028
+ canonicalJson(bindings.executionPolicy) &&
2029
+ (state.executionBudget === undefined ||
2030
+ canonicalJson(state.executionBudget) ===
2031
+ canonicalJson(bindings.executionBudget))
1998
2032
  );
1999
2033
  }
2000
2034
 
@@ -6045,3 +6079,376 @@ export function projectDynamicWorkflowRuntime(stateOrPath, options = {}) {
6045
6079
  stateDigest: state.stateDigest,
6046
6080
  });
6047
6081
  }
6082
+
6083
+ function checkpointRecoverySummary(state, options = {}) {
6084
+ const checkpointStore =
6085
+ options.checkpointStore || new WorkspaceTransactionManager();
6086
+ let prepared = 0;
6087
+ let terminal = 0;
6088
+ let pending = 0;
6089
+ let unavailable = 0;
6090
+ for (const effect of state.effects) {
6091
+ if (effect.status !== "pending") continue;
6092
+ for (const call of effect.calls || []) {
6093
+ if (
6094
+ call.kind !== "tool" ||
6095
+ call.status !== "started" ||
6096
+ Object.hasOwn(call, "artifactReadback") ||
6097
+ !validCheckpointBinding(call.checkpointBinding)
6098
+ ) {
6099
+ continue;
6100
+ }
6101
+ prepared += 1;
6102
+ try {
6103
+ if (
6104
+ checkpointReadbackFromPreparedBinding(
6105
+ call.checkpointBinding,
6106
+ checkpointStore,
6107
+ ) === null
6108
+ ) {
6109
+ pending += 1;
6110
+ } else {
6111
+ terminal += 1;
6112
+ }
6113
+ } catch {
6114
+ unavailable += 1;
6115
+ }
6116
+ }
6117
+ }
6118
+ return Object.freeze({ prepared, terminal, pending, unavailable });
6119
+ }
6120
+
6121
+ function observedBudgetStatus(observed, limit, complete) {
6122
+ if (!Number.isFinite(limit) || !Number.isFinite(observed) || !complete) {
6123
+ return "unknown";
6124
+ }
6125
+ return observed > limit ? "exceeded" : "within";
6126
+ }
6127
+
6128
+ const WORKFLOW_RECOVERY_BACKOFF_MS = Object.freeze([
6129
+ 15_000,
6130
+ 60_000,
6131
+ 5 * 60_000,
6132
+ 15 * 60_000,
6133
+ ]);
6134
+
6135
+ function dynamicWorkflowRecoveryPolicy(state, recovery) {
6136
+ const pendingInput = runtimeInputRequests(state).filter(
6137
+ (request) => request.status === "pending",
6138
+ ).length;
6139
+ const pendingEffects = state.effects.filter(
6140
+ (effect) => effect.status === "pending",
6141
+ );
6142
+ const uncertainEffects = pendingEffects.filter(
6143
+ (effect) => !isKnownUndispatched(effect),
6144
+ ).length;
6145
+ let risk = "none";
6146
+ let severity = "info";
6147
+ let recommendedAction = "none";
6148
+ let requiresApproval = false;
6149
+ let automaticallyExecutable = false;
6150
+
6151
+ if (recovery.terminal > 0) {
6152
+ risk = "terminal_checkpoint_recovery";
6153
+ severity = "warning";
6154
+ recommendedAction = "recover";
6155
+ requiresApproval = true;
6156
+ automaticallyExecutable = true;
6157
+ } else if (pendingInput > 0) {
6158
+ risk = "input_required";
6159
+ severity = "warning";
6160
+ recommendedAction = "reply";
6161
+ requiresApproval = true;
6162
+ } else if (uncertainEffects > 0) {
6163
+ risk = "operator_adjudication_required";
6164
+ severity = "critical";
6165
+ recommendedAction = "reconcile";
6166
+ requiresApproval = true;
6167
+ } else if (state.status === "pause_requested") {
6168
+ risk = "settlement_barrier_pending";
6169
+ severity = "info";
6170
+ recommendedAction = "wait";
6171
+ } else if (
6172
+ ["paused", "failed", "blocked"].includes(state.status) &&
6173
+ pendingEffects.length === 0
6174
+ ) {
6175
+ risk = "restart_ready";
6176
+ severity = "warning";
6177
+ recommendedAction = "resume";
6178
+ requiresApproval = true;
6179
+ automaticallyExecutable = true;
6180
+ }
6181
+
6182
+ const notificationKey = digest(
6183
+ "chainlesschain.dynamic-workflow.recovery-notification.v1\0",
6184
+ {
6185
+ runId: state.runId,
6186
+ revision: state.revision,
6187
+ stateDigest: state.stateDigest,
6188
+ risk,
6189
+ recommendedAction,
6190
+ },
6191
+ );
6192
+ return Object.freeze({
6193
+ schema: "cc-dynamic-workflow-recovery-policy/v1",
6194
+ risk,
6195
+ severity,
6196
+ recommendedAction,
6197
+ requiresApproval,
6198
+ automaticallyExecutable,
6199
+ unattendedMutationAllowed: false,
6200
+ pendingInput,
6201
+ pendingEffects: pendingEffects.length,
6202
+ uncertainEffects,
6203
+ notification: Object.freeze({
6204
+ key: notificationKey,
6205
+ backoffMs: WORKFLOW_RECOVERY_BACKOFF_MS,
6206
+ resetOnStateDigestChange: true,
6207
+ }),
6208
+ });
6209
+ }
6210
+
6211
+ /**
6212
+ * Bounded, content-free view used by the cross-IDE Sessions Workbench. Tool
6213
+ * arguments, prompts, provider output, result bodies, and filesystem bindings
6214
+ * deliberately never cross this projection boundary.
6215
+ */
6216
+ export function projectDynamicWorkflowWorkbenchState(
6217
+ stateOrPath,
6218
+ options = {},
6219
+ ) {
6220
+ const state =
6221
+ typeof stateOrPath === "string"
6222
+ ? readDynamicWorkflowRuntimeState(stateOrPath)
6223
+ : verifyDynamicWorkflowRuntimeState(stateOrPath);
6224
+ const observability = projectDynamicWorkflowObservability(state);
6225
+ const recovery = checkpointRecoverySummary(state, options);
6226
+ const recoveryPolicy = dynamicWorkflowRecoveryPolicy(state, recovery);
6227
+ const recentEffect = state.effects.at(-1) || null;
6228
+ const recentCall = recentEffect?.calls?.at(-1) || null;
6229
+ const lastTransition = state.lineage.at(-1) || null;
6230
+ const budget = state.executionBudget || null;
6231
+ const providerTokens = observability.tokens.providerReported?.totalTokens;
6232
+ const observedTokens = Number.isFinite(providerTokens)
6233
+ ? providerTokens
6234
+ : observability.tokens.missingEffects === 0
6235
+ ? observability.tokens.estimated
6236
+ : null;
6237
+ const tokenComplete =
6238
+ Number.isFinite(providerTokens) ||
6239
+ observability.tokens.missingEffects === 0;
6240
+ const observedUsd = Number.isFinite(observability.cost.estimatedUsd)
6241
+ ? observability.cost.estimatedUsd
6242
+ : null;
6243
+ const costComplete =
6244
+ observability.cost.providerCalls === observability.cost.pricedCalls;
6245
+ const observedDurationMs = observability.duration.totalMs;
6246
+ const durationComplete = observability.effects.pending === 0;
6247
+ const budgetStatus = {
6248
+ tokens: observedBudgetStatus(
6249
+ observedTokens,
6250
+ budget?.maxTokens,
6251
+ tokenComplete,
6252
+ ),
6253
+ usd: observedBudgetStatus(observedUsd, budget?.maxUsd, costComplete),
6254
+ duration: observedBudgetStatus(
6255
+ observedDurationMs,
6256
+ budget?.maxDurationMs,
6257
+ durationComplete,
6258
+ ),
6259
+ };
6260
+ const overallBudgetStatus = Object.values(budgetStatus).includes("exceeded")
6261
+ ? "exceeded"
6262
+ : Object.values(budgetStatus).includes("unknown")
6263
+ ? "unknown"
6264
+ : "within";
6265
+
6266
+ return Object.freeze({
6267
+ schema: "cc-dynamic-workflow-workbench-state/v1",
6268
+ runId: state.runId,
6269
+ workflowId: state.workflowId,
6270
+ status: state.status,
6271
+ revision: state.revision,
6272
+ stateDigest: state.stateDigest,
6273
+ definitionDigest: state.definitionDigest,
6274
+ admissionDigest: state.admissionDigest,
6275
+ executionAuthoritySessionId: state.executionAuthoritySessionId,
6276
+ createdAt: state.createdAt,
6277
+ updatedAt: state.updatedAt,
6278
+ phase: Object.freeze({
6279
+ status: state.status,
6280
+ transition: lastTransition?.type || "run-created",
6281
+ at: lastTransition?.at || state.createdAt,
6282
+ }),
6283
+ agents: Object.freeze({
6284
+ requested: observability.effects.requested,
6285
+ settled: observability.effects.settled,
6286
+ pending: observability.effects.pending,
6287
+ completed: observability.effects.completedTasks,
6288
+ failed: observability.effects.failedTasks,
6289
+ }),
6290
+ input: Object.freeze({
6291
+ requested: runtimeInputRequests(state).length,
6292
+ pending: runtimeInputRequests(state).filter(
6293
+ (request) => request.status === "pending",
6294
+ ).length,
6295
+ }),
6296
+ budget: Object.freeze({
6297
+ limits: budget,
6298
+ observed: Object.freeze({
6299
+ tokens: observedTokens,
6300
+ usd: observedUsd,
6301
+ durationMs: observedDurationMs,
6302
+ }),
6303
+ status: Object.freeze(budgetStatus),
6304
+ overall: overallBudgetStatus,
6305
+ }),
6306
+ artifacts: Object.freeze({ count: observability.artifacts.count }),
6307
+ checkpoints: Object.freeze({ count: observability.checkpoints.count }),
6308
+ recovery,
6309
+ recoveryPolicy,
6310
+ recent: recentEffect
6311
+ ? Object.freeze({
6312
+ effectId: recentEffect.id,
6313
+ stepId: recentEffect.stepId,
6314
+ status: recentEffect.status,
6315
+ taskStatus:
6316
+ recentEffect.result?.status === "completed" ||
6317
+ recentEffect.result?.status === "failed"
6318
+ ? recentEffect.result.status
6319
+ : null,
6320
+ requestedAt: recentEffect.requestedAt,
6321
+ settledAt: recentEffect.settledAt || null,
6322
+ resultDigest: recentEffect.resultDigest || null,
6323
+ call: recentCall
6324
+ ? Object.freeze({
6325
+ id: recentCall.id,
6326
+ kind: recentCall.kind,
6327
+ name: recentCall.name,
6328
+ status: recentCall.status,
6329
+ settlementCode: recentCall.settlementCode,
6330
+ settledAt: recentCall.settledAt,
6331
+ })
6332
+ : null,
6333
+ })
6334
+ : null,
6335
+ });
6336
+ }
6337
+
6338
+ /** Securely discover durable workflow state files below one project root. */
6339
+ export function listDynamicWorkflowWorkbenchStates(cwd, options = {}) {
6340
+ const limit = Math.max(1, Math.min(256, Number(options.limit) || 100));
6341
+ const projectionOptions = Object.hasOwn(options, "checkpointStore")
6342
+ ? options
6343
+ : { ...options, checkpointStore: new WorkspaceTransactionManager() };
6344
+ const directory = path.join(
6345
+ path.resolve(cwd),
6346
+ ".chainlesschain",
6347
+ "cowork",
6348
+ "workflow-runs",
6349
+ );
6350
+ let stat;
6351
+ try {
6352
+ stat = fs.lstatSync(directory);
6353
+ } catch (error) {
6354
+ if (error?.code === "ENOENT") {
6355
+ return Object.freeze({ runs: Object.freeze([]), invalidCount: 0 });
6356
+ }
6357
+ throw error;
6358
+ }
6359
+ if (!stat.isDirectory() || stat.isSymbolicLink()) {
6360
+ throw new Error("dynamic workflow runtime directory is not trusted");
6361
+ }
6362
+ const entries = fs.readdirSync(directory, { withFileTypes: true });
6363
+ if (entries.length > MAX_WORKBENCH_RUN_FILES) {
6364
+ throw new Error("dynamic workflow runtime directory exceeds safe limits");
6365
+ }
6366
+ const runs = [];
6367
+ let invalidCount = 0;
6368
+ for (const entry of entries) {
6369
+ if (
6370
+ !entry.isFile() ||
6371
+ entry.isSymbolicLink() ||
6372
+ !/^[A-Za-z0-9][A-Za-z0-9._-]{0,255}\.json$/u.test(entry.name)
6373
+ ) {
6374
+ continue;
6375
+ }
6376
+ const runId = entry.name.slice(0, -".json".length);
6377
+ try {
6378
+ const statePath = dynamicWorkflowRunStatePath(cwd, runId);
6379
+ const state = readDynamicWorkflowRuntimeState(statePath);
6380
+ if (state.runId !== runId) throw new Error("run identity mismatch");
6381
+ runs.push(projectDynamicWorkflowWorkbenchState(state, projectionOptions));
6382
+ } catch {
6383
+ invalidCount += 1;
6384
+ }
6385
+ }
6386
+ runs.sort(
6387
+ (left, right) =>
6388
+ (Date.parse(right.updatedAt) || 0) - (Date.parse(left.updatedAt) || 0) ||
6389
+ left.runId.localeCompare(right.runId),
6390
+ );
6391
+ return Object.freeze({
6392
+ runs: Object.freeze(runs.slice(0, limit)),
6393
+ invalidCount,
6394
+ });
6395
+ }
6396
+
6397
+ /** Deterministic, non-mutating batch inventory for startup/periodic recovery. */
6398
+ export function buildDynamicWorkflowRecoveryPlan(cwd, options = {}) {
6399
+ const discovered = listDynamicWorkflowWorkbenchStates(cwd, options);
6400
+ const policy = Object.freeze({
6401
+ schema: "cc-dynamic-workflow-recovery-policy-set/v1",
6402
+ unattendedMutationAllowed: false,
6403
+ approvalRequiredFor: Object.freeze([
6404
+ "recover",
6405
+ "resume",
6406
+ "reply",
6407
+ "reconcile",
6408
+ ]),
6409
+ backoffMs: WORKFLOW_RECOVERY_BACKOFF_MS,
6410
+ });
6411
+ const items = discovered.runs.map((run) =>
6412
+ Object.freeze({
6413
+ runId: run.runId,
6414
+ workflowId: run.workflowId,
6415
+ revision: run.revision,
6416
+ stateDigest: run.stateDigest,
6417
+ status: run.status,
6418
+ updatedAt: run.updatedAt,
6419
+ risk: run.recoveryPolicy.risk,
6420
+ severity: run.recoveryPolicy.severity,
6421
+ recommendedAction: run.recoveryPolicy.recommendedAction,
6422
+ requiresApproval: run.recoveryPolicy.requiresApproval,
6423
+ automaticallyExecutable: run.recoveryPolicy.automaticallyExecutable,
6424
+ notificationKey: run.recoveryPolicy.notification.key,
6425
+ recovery: run.recovery,
6426
+ }),
6427
+ );
6428
+ const summary = Object.freeze({
6429
+ total: items.length,
6430
+ invalid: discovered.invalidCount,
6431
+ attention: items.filter((item) => item.risk !== "none").length,
6432
+ critical: items.filter((item) => item.severity === "critical").length,
6433
+ approvalRequired: items.filter((item) => item.requiresApproval).length,
6434
+ automaticallyExecutable: items.filter(
6435
+ (item) => item.automaticallyExecutable,
6436
+ ).length,
6437
+ });
6438
+ const planMaterial = { policy, summary, items };
6439
+ return Object.freeze({
6440
+ schema: "cc-dynamic-workflow-recovery-plan/v1",
6441
+ authority: "cli",
6442
+ mode: "dry-run",
6443
+ generatedAt: isoNow(options.now),
6444
+ projectDigest: digest(
6445
+ "chainlesschain.dynamic-workflow.recovery-project.v1\0",
6446
+ path.resolve(cwd),
6447
+ ),
6448
+ planDigest: digest(
6449
+ "chainlesschain.dynamic-workflow.recovery-plan.v1\0",
6450
+ planMaterial,
6451
+ ),
6452
+ ...planMaterial,
6453
+ });
6454
+ }
@@ -814,9 +814,11 @@ function transferTargetSessionStore(
814
814
  receipt.targetFactsDigest !== receiptMaterial.targetFactsDigest ||
815
815
  receipt.profileDigest !== receiptMaterial.profileDigest ||
816
816
  receipt.targetEvidenceId !== receiptMaterial.targetEvidenceId ||
817
+ // Target prepare records a fresh observedAt, so its attestation digest is
818
+ // expected to differ from the earlier source-side probe. The receipt is
819
+ // rehashed here and the next target `location show` validates that digest
820
+ // against the canonical handoff binding before resume.
817
821
  !SHA256_RE.test(receipt.attestationDigest || "") ||
818
- (receipt.handoffAppended === true &&
819
- receipt.attestationDigest !== attestation.attestationDigest) ||
820
822
  typeof receipt.replicaInstalled !== "boolean" ||
821
823
  typeof receipt.handoffAppended !== "boolean" ||
822
824
  receipt.receiptDigest !== expectedReceiptDigest
@@ -24,6 +24,10 @@ import {
24
24
  reattestMcpStdioPackageMaterialization,
25
25
  resolveMcpStdioPackageMaterialization,
26
26
  } from "./mcp-stdio-package-materialization.js";
27
+ import {
28
+ isMcpStdioCapsuleNativeCodePolicy,
29
+ mcpStdioCapsuleNativeCodePolicyDigest,
30
+ } from "./mcp-stdio-native-code-policy.js";
27
31
  import {
28
32
  isMcpStdioCodeInjectionEnvironmentKey,
29
33
  sanitizeMcpStdioHostEnvironment,
@@ -48,11 +52,13 @@ export const MCP_STDIO_RUNTIME_KIND_INVALID_CODE =
48
52
  export const MCP_STDIO_CAPSULE_SANDBOX_CONTRACT_KIND =
49
53
  "strict-mcp-node-capsule";
50
54
  export const MCP_STDIO_CAPSULE_CODE_SNAPSHOT_BOUNDARY = "code-snapshot";
55
+ export const MCP_STDIO_CAPSULE_NATIVE_ADDON_BOUNDARY = "native-addon-loading";
51
56
  export const MCP_STDIO_CAPSULE_REQUIRED_BOUNDARIES = Object.freeze([
52
57
  MCP_STDIO_CAPSULE_CODE_SNAPSHOT_BOUNDARY,
53
58
  "filesystem",
54
59
  "network",
55
60
  "process-tree",
61
+ MCP_STDIO_CAPSULE_NATIVE_ADDON_BOUNDARY,
56
62
  ]);
57
63
 
58
64
  const STORE_LABEL = "MCP stdio executable identity";
@@ -852,6 +858,10 @@ function issueCapsuleSandboxExecutionContract({
852
858
  materialization,
853
859
  }) {
854
860
  if (!materialization) return null;
861
+ const nativeCodePolicy = materialization.identity?.capsule?.nativeCodePolicy;
862
+ if (!isMcpStdioCapsuleNativeCodePolicy(nativeCodePolicy)) {
863
+ throw new Error("MCP materialized capsule native-code policy is invalid");
864
+ }
855
865
  const capsuleRoot = attestCapsuleRoot(materialization.capsuleRoot);
856
866
  const entryIdentity = attestation.identity.entrypoints.find(
857
867
  (entry) => entry.argIndex === 0,
@@ -878,6 +888,7 @@ function issueCapsuleSandboxExecutionContract({
878
888
  attestation.identity.command,
879
889
  path.resolve(process.execPath),
880
890
  ),
891
+ nativeCodePolicy: Object.freeze({ ...nativeCodePolicy }),
881
892
  });
882
893
  issuedCapsuleSandboxContracts.set(
883
894
  contract,
@@ -888,6 +899,8 @@ function issueCapsuleSandboxExecutionContract({
888
899
  cwd: capsuleRoot.realPath,
889
900
  identityDigest: attestation.identityDigest,
890
901
  requiredBoundaries: MCP_STDIO_CAPSULE_REQUIRED_BOUNDARIES,
902
+ nativeCodePolicyDigest:
903
+ mcpStdioCapsuleNativeCodePolicyDigest(nativeCodePolicy),
891
904
  }),
892
905
  );
893
906
  return contract;
@@ -918,6 +931,9 @@ export function consumeMcpStdioCapsuleSandboxExecutionContract(
918
931
  issued.requiredBoundaries.every((boundary) =>
919
932
  requiredBoundaries.includes(boundary),
920
933
  ) &&
934
+ isMcpStdioCapsuleNativeCodePolicy(contract.nativeCodePolicy) &&
935
+ mcpStdioCapsuleNativeCodePolicyDigest(contract.nativeCodePolicy) ===
936
+ issued.nativeCodePolicyDigest &&
921
937
  args.length === issued.args.length &&
922
938
  args.every((value, index) => value === issued.args[index])
923
939
  );