chainlesschain 0.164.0 → 0.165.2

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 (228) hide show
  1. package/README.md +248 -2
  2. package/package.json +7 -4
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-D2MEn7fI.js → AIOps-lS1R0Cza.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-lCW_4Gf0.js → ActionButton-BmlgBPsj.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-Bs7i-nsS.js → Analytics-CNKczv1S.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-CK7B6S_j.js → AppLayout-BuZGJARQ.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-C8ILjpyo.js → Artifacts-Dm73Sl-O.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-Bb9cNaWc.js → Audit-BGMW7A5e.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-sC9ooXIf.js → BackgroundAgents-BQ6M54JR.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-D-DrsplT.js → Backup-DBzGP0bR.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-uCNZpwSK.js → BaseInput-D1mLCoOV.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-CsDK1uE9.js → Chat-BUfcN7p8.js} +6 -6
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-OqSDt50w.js → ChatBubbleRenderer-CY5m8ZHg.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-JhTXM1-K.js → Checkbox-Du0Yg5Pi.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-BbzZLnyD.js → Codegen-B2RXziHW.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-D4VW4m4j.js → Col-DWhekOrR.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-BXrYawxV.js → Community-HQhrkon4.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-DCihGy1u.js → Compact-izHNb4uz.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-DlyZ-lk8.js → Compliance-BDwLy41-.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-DvGZrhbO.js → Cowork-DFJhLa7K.js} +3 -3
  22. package/src/assets/web-panel/assets/{Cron-DUncZi8h.js → Cron-DYY9RG7-.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-C_hLuUcm.js → Crosschain-rr7tJTtv.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-b6YSUqxr.js → DID-D2sfHRLi.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-uvM15Cfb.js → Dashboard-q_eGdhha.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-D1-Nd4qY.js → Dropdown-Cufrh2Bz.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-8ApvL6Zc.js → EmailListRenderer-B-kdv10f.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-LYJt8811.js → FamilyGuardDashboard-D21XjgfG.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-BbI3HGpv.js → Federation-CAwRTLZH.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-DSoEKuFu.js → FormItemContext-vx3daNDF.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-B0S9OWd5.js → GenericCardRenderer-CRWY2wU4.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-DIs9Zhf3.js → Git-Q6SwauyD.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-jzZXrxcl.js → Governance-BJ1q4IQZ.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-JUPjf2ZI.js → Inference-CSWjROgD.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-DxnfJvlP.js → KnowledgeGraph-fzuQsWuY.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-iXiz8BEE.js → Logs-DVF8Mnns.js} +2 -2
  37. package/src/assets/web-panel/assets/MarkdownRenderer-BLif4QSg.js +1 -0
  38. package/src/assets/web-panel/assets/{Marketplace-Y3Xch312.js → Marketplace-BQP7LOA4.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-D7kGGbO7.js → McpTools-BNlJCmNc.js} +4 -4
  40. package/src/assets/web-panel/assets/{Memory-Do_hVxzh.js → Memory-DLLg5WQ4.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-CtrR0Tas.js → MobileBridge-CR2skNAF.js} +1 -1
  42. package/src/assets/web-panel/assets/MobileProjects-BxVavObl.js +1 -0
  43. package/src/assets/web-panel/assets/{Mtc-qo5QCTGd.js → Mtc-B17pgqMI.js} +4 -4
  44. package/src/assets/web-panel/assets/{MtcAudit-cq5mnjYj.js → MtcAudit-4UmV5cIL.js} +2 -2
  45. package/src/assets/web-panel/assets/{Multisig-Bq0MAQHw.js → Multisig-DoMEXEcU.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-DdWE6Vi2.js → NLProgramming-h9DMXFX4.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-BxMBFcIp.js → Notes-Cihn-xX8.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-RTrAcbUe.js → NotificationSettings-BE6ZGa3R.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-DJbpGqzT.js → OrderTableRenderer-CnwojoSI.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-SQzIPdqC.js → Organization-B2vpwmjb.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-02yECh22.js → Overflow-C4z28R0-.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-BNg4pNCM.js → P2P-BVlFkwhW.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-BxPJZsD3.js → PdhVaultBrowser-BXbEdL5B.js} +3 -3
  54. package/src/assets/web-panel/assets/{Permissions-CLnDnPAz.js → Permissions-C28xs4lp.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-C5m0AjGf.js → PersonalDataHub-Dgl_rBjM.js} +4 -4
  56. package/src/assets/web-panel/assets/{Pipeline-VwOf5Dhv.js → Pipeline-3QUIhrKI.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-CC0W2hZd.js → Privacy-8Gh33OZ5.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-Dz893Bob.js → ProjectInit-BNmg4tZi.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-CxQkvl0k.js → ProjectSettings-vgMfeCf9.js} +2 -2
  60. package/src/assets/web-panel/assets/Projects-BhtAVilc.js +1 -0
  61. package/src/assets/web-panel/assets/{Providers-DeB9IkxK.js → Providers-CXoOa8eX.js} +1 -1
  62. package/src/assets/web-panel/assets/{QrScannerModal-OCeoaswn.js → QrScannerModal-BhfTF0oS.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-DenotaAj.js → QuickAsk-C746HEAj.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-Cies_jjI.js → Recommend-BSej8Eo0.js} +1 -1
  65. package/src/assets/web-panel/assets/RemoteSession-f3gmnlG3.js +5 -0
  66. package/src/assets/web-panel/assets/{Reputation-CW0mvxgZ.js → Reputation-CyvybpkN.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-SEd32qZU.js → Row-DwV2PeYn.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-BSwnJ3Lm.js → RssFeed-11GrzjZy.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-xe2m8bkC.js → Search-BjKXkrAY.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-Mq2F9Nro.js → Security-eWiFb9Yk.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-BKGw2V3P.js → Services-CdCsMAtt.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-DW95-Rxf.js → Skeleton-4Q2UTKQ5.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-CHgChCv_.js → Skills-v4rtYrRj.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-tKh6k3R7.js → Sla-CRhsFvd_.js} +1 -1
  75. package/src/assets/web-panel/assets/SpeechSettings-DLjKsDVu.js +1 -0
  76. package/src/assets/web-panel/assets/{SyncSettings-D0Fw8fVL.js → SyncSettings-D16zonl7.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-20x1GB3D.js → Tasks-Xxozz0i_.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-DJ-lts-a.js → Templates-CXJpPtCT.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-BFdGpbs7.js → Tenant-XRV0L1ZF.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-Xpx61vHL.js → Terminal-CYuO1i_w.js} +2 -2
  81. package/src/assets/web-panel/assets/{TimelineRenderer-C6UIvyZQ.js → TimelineRenderer-BXqitWsu.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-Dellq08f.js → Tokens-BvPrDHIy.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-VKw8d0J-.js → Trigger-DhCrSTf5.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-DNftdKT5.js → Trust-DmsuZD6K.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-DX9VAKJI.js → UkeySign-D_yrts5C.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-B2h3jO8q.js → VideoEditing-B01ihPrm.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-CjGkof7f.js → Wallet-DpUjKa-N.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-2Zfcu55P.js → WebAuthn-CL07yON6.js} +4 -4
  89. package/src/assets/web-panel/assets/{WorkflowEditor-B9eZ8UxZ.js → WorkflowEditor-CLMflnRr.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-CQNfD-YO.js → chat-DtUqe8h_.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-D4usyFT2.js → colors-DPKrgVfy.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-s4TpjvjX.js → compact-item-BTt2GtOm.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-BRCSvYxj.js → createContext-D_VeUc1J.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-Bj5nUW2v.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-AdkUbkV-.js → hasIn-1kndiylj.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BIoG5yYf.js → index-2eyAXE3d.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-nXyk8GZ9.js → index-4bna2_SR.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-B2V-eKfK.js → index-8nz_fmlj.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-D_XBHopw.js → index-B9KvcS7R.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-s_buFMEG.js → index-BAXfRKfG.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DZT36ZYq.js → index-BHpBMWCh.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BMcimU-2.js → index-BaZAbw9A.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DzRjHxEv.js → index-BepLZwgB.js} +1 -1
  104. package/src/assets/web-panel/assets/{index--00U6vXZ.js → index-Bhudc_Ez.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-C7Y8Aluc.js → index-BlDNVgBt.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BtobShro.js → index-By5n8up9.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Cvyt-zhm.js → index-CHG-KcS4.js} +1 -1
  108. package/src/assets/web-panel/assets/index-CPcM-eqo.js +1 -0
  109. package/src/assets/web-panel/assets/{index-MMN9V6JF.js → index-CX81qSM4.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Bad4VNvz.js → index-CauoBQkH.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CCsM_Ybx.js → index-CcO04eDn.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DARsAyUp.js → index-CtF7EN49.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-C5KAQFPQ.js → index-CzjkKUmR.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-RfMr79MW.js → index-D95OFht7.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DdCB70SS.js → index-DFIZ_1Sf.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CYdoQsa1.js → index-DG2MZQ3f.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BPhkFZ1I.js → index-DJ8vXGOa.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-_IRVsV9X.js → index-Dbbymxpj.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DVKfQ0Ux.js → index-DdkplL9R.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CkwiSLhU.js → index-DfGl8CqG.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CJVEOa4i.js → index-DfKBRdSS.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-C1mJtE6q.js → index-DsJCDUJG.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BgiXR_-_.js → index-Dwqmtk65.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CJCFe2Qf.js → index-DxdTdBix.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-C484EJiS.js → index-FzdwcSy2.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-B4JJCfQ2.js → index-GsoUQ2M7.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CQhAVU5t.js → index-brCInrzq.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CKC1t3Ic.js → index-dVc-CXY4.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BQ3DXBtD.js → index-fk2Rjacw.js} +3 -3
  130. package/src/assets/web-panel/assets/{index-Cduu2Hhr.js → index-l1BETrDb.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Bw2MEnUk.js → index-m31Ka8hZ.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D2GjI2oe.js → index-ocf06EVQ.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-CJdQrZth.js → index-sDoMHTNA.js} +1 -1
  134. package/src/assets/web-panel/assets/index-xeSyVoRe.js +1 -0
  135. package/src/assets/web-panel/assets/{initDefaultProps-Blmpk7HL.js → initDefaultProps-CvyYJd7z.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-DPBJMv1n.js → motion-DYZkhUdz.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-ButdzCM7.js → move-slnJRVT1.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-cyRC_QCe.js → mtc-parser-DVc0CKmy.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-1epSV7hz.js → omit-BCXAtHCq.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-DuPY8xJs.js → pickAttrs-DBsemz_K.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-6XZqarhe.js → placementArrow-BRtkJ-nv.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-B40pXBWM.js → responsiveObserve-Cebq7EZn.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-jbZ9Wu4n.js → slide-DT7qvId2.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-BKQQcVy4.js → statusUtils-pQiITLkG.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-NiKfWjUT.js → styleChecker-c-19BVKQ.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-bQUCvPeb.js → useFlexGapSupport-DsS5-0bE.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-CUGji7ph.js → useFs-CxGiMe5n.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-4veyN2N2.js → usePersonalDataHub-D9btVID5.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-1-nLug-Z.js → vnode-CUYFsFEN.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-dhCeRDMo.js → zoom-CXmn_35j.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/cowork.js +559 -62
  154. package/src/commands/plugin.js +819 -64
  155. package/src/commands/session-location.js +318 -7
  156. package/src/constants.js +2 -2
  157. package/src/data/changelog.json +28 -2
  158. package/src/gateways/ws/action-protocol.js +293 -19
  159. package/src/gateways/ws/message-dispatcher.js +30 -0
  160. package/src/gateways/ws/remote-session-protocol.js +542 -35
  161. package/src/gateways/ws/ws-approval-gate.js +5 -0
  162. package/src/gateways/ws/ws-server.js +462 -38
  163. package/src/harness/jsonl-session-store.js +638 -2
  164. package/src/harness/prompt-compressor.js +4 -0
  165. package/src/harness/remote-session-audit.js +1 -0
  166. package/src/harness/remote-session-crypto.js +750 -50
  167. package/src/harness/remote-session-registry.js +795 -27
  168. package/src/lib/auto-mode-config.js +98 -3
  169. package/src/lib/background-agent-keeper-client.js +29 -0
  170. package/src/lib/background-agent-keeper-protocol.js +158 -10
  171. package/src/lib/background-agent-supervisor.js +870 -48
  172. package/src/lib/background-session-transport.js +23 -6
  173. package/src/lib/background-turn-bootstrap-protocol.js +64 -0
  174. package/src/lib/cowork-task-runner.js +70 -0
  175. package/src/lib/cowork-workflow.js +887 -62
  176. package/src/lib/delivery-production-adapter.js +38 -2
  177. package/src/lib/doctor-checkup.js +34 -10
  178. package/src/lib/dynamic-workflow-draft.js +535 -0
  179. package/src/lib/dynamic-workflow-facade.js +1105 -17
  180. package/src/lib/dynamic-workflow-runtime.js +2974 -0
  181. package/src/lib/execution-location-contract.js +111 -7
  182. package/src/lib/execution-location-runtime.js +3 -1
  183. package/src/lib/execution-location-target.js +910 -0
  184. package/src/lib/llm-providers.js +1 -0
  185. package/src/lib/mcp-call-ledger-store.js +35 -0
  186. package/src/lib/mcp-call-ledger.js +30 -0
  187. package/src/lib/mcp-stdio-package-materialization.js +1 -1
  188. package/src/lib/plugin-runtime/__tests__/remote-source.test.js +34 -16
  189. package/src/lib/plugin-runtime/install.js +4956 -657
  190. package/src/lib/plugin-runtime/manifest.js +3 -1
  191. package/src/lib/plugin-runtime/marketplace-artifact-readback.js +671 -31
  192. package/src/lib/plugin-runtime/marketplace-catalog.js +68 -2
  193. package/src/lib/plugin-runtime/marketplace-impact.js +208 -15
  194. package/src/lib/plugin-runtime/marketplace-network.js +317 -0
  195. package/src/lib/plugin-runtime/marketplace-pac-worker.js +15 -0
  196. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +25 -2
  197. package/src/lib/plugin-runtime/marketplace-source-cache.js +359 -0
  198. package/src/lib/plugin-runtime/policy.js +21 -6
  199. package/src/lib/plugin-runtime/publisher-trust.js +332 -0
  200. package/src/lib/plugin-runtime/remote-source.js +323 -27
  201. package/src/lib/plugin-runtime/scopes.js +317 -41
  202. package/src/lib/plugin-runtime/transaction-journal.js +806 -0
  203. package/src/lib/public-ide-capability-manifest.js +1 -1
  204. package/src/lib/remote-approval-bridge.js +745 -108
  205. package/src/lib/remote-control.js +2 -0
  206. package/src/lib/remote-membership-coordinator.js +612 -46
  207. package/src/lib/remote-membership-host-store.js +59 -10
  208. package/src/lib/runtime-provenance-ledger.js +171 -46
  209. package/src/lib/shell-approval.js +169 -6
  210. package/src/lib/sub-agent-context.js +268 -2
  211. package/src/lib/task-model-selector.js +1 -1
  212. package/src/lib/with-file-lock.js +167 -42
  213. package/src/repl/agent-repl.js +70 -29
  214. package/src/repl/remote-approval.js +29 -7
  215. package/src/runtime/agent-core.js +1695 -194
  216. package/src/runtime/headless-runner.js +22 -5
  217. package/src/runtime/headless-stream.js +19 -3
  218. package/src/workers/background-agent-keeper.js +279 -58
  219. package/src/workers/background-agent-worker.js +7 -0
  220. package/src/workers/background-turn-bootstrap.js +29 -2
  221. package/src/assets/web-panel/assets/MarkdownRenderer-GmB6DOr6.js +0 -1
  222. package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +0 -1
  223. package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +0 -1
  224. package/src/assets/web-panel/assets/RemoteSession-Dxzl5n2T.js +0 -5
  225. package/src/assets/web-panel/assets/SpeechSettings-D6UL3dA5.js +0 -1
  226. package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +0 -1
  227. package/src/assets/web-panel/assets/index-C61cnl3K.js +0 -1
  228. package/src/assets/web-panel/assets/index-D4XFHxBr.js +0 -1
@@ -121,6 +121,14 @@ function normalizedRepoPath(value) {
121
121
  .trim();
122
122
  }
123
123
 
124
+ function githubRepositoryFromRemoteUrl(value) {
125
+ const remoteUrl = String(value || "").trim();
126
+ const match = remoteUrl.match(
127
+ /^(?:https:\/\/github\.com\/|git@github\.com:|ssh:\/\/git@github\.com\/)([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?\/?$/u,
128
+ );
129
+ return match ? `${match[1]}/${match[2]}` : null;
130
+ }
131
+
124
132
  function normalizedPathSet(values) {
125
133
  return uniqueStrings(values).map(normalizedRepoPath).filter(Boolean).sort();
126
134
  }
@@ -211,6 +219,13 @@ export function validateGitHubDeliveryProductionConfig(config) {
211
219
  ) {
212
220
  unmet.push("github-repo-invalid");
213
221
  }
222
+ if (
223
+ !/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u.test(
224
+ String(config.git?.remote || "origin").trim(),
225
+ )
226
+ ) {
227
+ unmet.push("git-remote-invalid");
228
+ }
214
229
  const requiredChecks = Array.isArray(config.ci?.requiredChecks)
215
230
  ? config.ci.requiredChecks.map((item) => String(item).trim())
216
231
  : [];
@@ -423,6 +438,25 @@ export class GitHubDeliveryProductionAdapter {
423
438
  return this._read("git", args, `git-${label}`);
424
439
  }
425
440
 
441
+ _verifiedPushRemote() {
442
+ const remote = String(this.config.git?.remote || "origin").trim();
443
+ const remoteUrl = this._git(
444
+ ["remote", "get-url", "--push", remote],
445
+ "push-remote",
446
+ ).trim();
447
+ const actualRepository = githubRepositoryFromRemoteUrl(remoteUrl);
448
+ const expectedRepository = String(this.config.github?.repo || "").trim();
449
+ if (
450
+ !actualRepository ||
451
+ actualRepository.toLowerCase() !== expectedRepository.toLowerCase()
452
+ ) {
453
+ throw new Error(
454
+ "configured Git push remote is not bound to the authoritative GitHub repository",
455
+ );
456
+ }
457
+ return remote;
458
+ }
459
+
426
460
  _gh(args, label = args[0]) {
427
461
  const repo = String(this.config.github?.repo || "").trim();
428
462
  const fullArgs =
@@ -1202,9 +1236,10 @@ export class GitHubDeliveryProductionAdapter {
1202
1236
  if (context.state?.pr?.number) {
1203
1237
  const branch = this._git(["branch", "--show-current"], "branch").trim();
1204
1238
  if (!branch) throw new Error("cannot push a fix from detached HEAD");
1239
+ const remote = this._verifiedPushRemote();
1205
1240
  this._mutate(
1206
1241
  "git",
1207
- ["push", "origin", `${nextCommit}:refs/heads/${branch}`],
1242
+ ["push", remote, `${nextCommit}:refs/heads/${branch}`],
1208
1243
  "git-push-fix",
1209
1244
  );
1210
1245
  const pr = this._readPr(context.state.pr.number);
@@ -1438,9 +1473,10 @@ export class GitHubDeliveryProductionAdapter {
1438
1473
  commitSha: payload.commitSha,
1439
1474
  });
1440
1475
  }
1476
+ const remote = this._verifiedPushRemote();
1441
1477
  this._mutate(
1442
1478
  "git",
1443
- ["push", "origin", `${payload.commitSha}:refs/heads/${branch}`],
1479
+ ["push", remote, `${payload.commitSha}:refs/heads/${branch}`],
1444
1480
  "git-push-pr",
1445
1481
  );
1446
1482
  const sideEffects = [
@@ -462,7 +462,6 @@ async function pluginSection(opts, _deps2) {
462
462
  const checks = [];
463
463
  try {
464
464
  const { listInstalled } = await import("./plugin-runtime/install.js");
465
- const { readPluginLock } = await import("./plugin-runtime/signature.js");
466
465
  const plugins = listInstalled({ cwd: opts.cwd || process.cwd() }) || [];
467
466
  if (plugins.length === 0) {
468
467
  checks.push(
@@ -475,22 +474,47 @@ async function pluginSection(opts, _deps2) {
475
474
  );
476
475
  } else {
477
476
  let unsigned = 0;
477
+ const runtimeBlocked = [];
478
+ const retainedRecovery = [];
478
479
  for (const p of plugins) {
479
- try {
480
- const lock = p.dir ? readPluginLock(p.dir) : null;
481
- if (!lock || !lock.signature) unsigned++;
482
- } catch {
483
- unsigned++;
480
+ if (p.activePointer?.recoveryPath) {
481
+ retainedRecovery.push(`${p.name} (${p.activePointer.recoveryPath})`);
482
+ }
483
+ if (p.runtimeBlocked === true) {
484
+ runtimeBlocked.push(
485
+ `${p.name} (${p.activePointer?.status || "unknown pointer state"})`,
486
+ );
487
+ continue;
484
488
  }
489
+ if (p.integrity?.signature?.present !== true) unsigned++;
485
490
  }
486
491
  checks.push(
487
492
  check(
488
493
  "plugins",
489
494
  `Installed plugins: ${plugins.length}`,
490
- unsigned > 0 ? CHECK_LEVELS.WARN : CHECK_LEVELS.OK,
491
- unsigned > 0
492
- ? `${unsigned} without a signature lock — they will be refused if plugins.requireSignedPlugins is enabled`
493
- : "all have signature locks",
495
+ unsigned > 0 ||
496
+ runtimeBlocked.length > 0 ||
497
+ retainedRecovery.length > 0
498
+ ? CHECK_LEVELS.WARN
499
+ : CHECK_LEVELS.OK,
500
+ [
501
+ runtimeBlocked.length > 0
502
+ ? `runtime blocked: ${runtimeBlocked.join(", ")}`
503
+ : null,
504
+ retainedRecovery.length > 0
505
+ ? `retained install recovery: ${retainedRecovery.join(", ")}; remove the blocked plugin before another mutation`
506
+ : null,
507
+ unsigned > 0
508
+ ? `${unsigned} active without a signature lock — they will be refused if plugins.requireSignedPlugins is enabled`
509
+ : null,
510
+ runtimeBlocked.length === 0 &&
511
+ retainedRecovery.length === 0 &&
512
+ unsigned === 0
513
+ ? "all active plugins have signature locks"
514
+ : null,
515
+ ]
516
+ .filter(Boolean)
517
+ .join("; "),
494
518
  ),
495
519
  );
496
520
  }
@@ -0,0 +1,535 @@
1
+ import { createHash } from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { types as utilTypes } from "node:util";
5
+ import { createDynamicWorkflowManifest } from "./dynamic-workflow-facade.js";
6
+ import { containsSecret } from "./secret-scan.js";
7
+ import {
8
+ sameFileStatIdentity,
9
+ samePathHandleFileIdentity,
10
+ withTrustedFileParentSync,
11
+ } from "./secure-file-identity.js";
12
+ import { canonicalJson } from "./scheduler-kernel/contract.js";
13
+ import {
14
+ MAX_WORKFLOW_DEFINITION_BYTES,
15
+ WORKFLOW_DEFINITION_SCHEMA,
16
+ } from "./workflow-definition-contract.js";
17
+
18
+ export const DYNAMIC_WORKFLOW_DRAFT_SCHEMA = "cc-dynamic-workflow-draft/v1";
19
+ export const DYNAMIC_WORKFLOW_GENERATION_SCHEMA =
20
+ "cc-dynamic-workflow-generation/v1";
21
+ export const DYNAMIC_WORKFLOW_REVIEW_SCHEMA = "cc-dynamic-workflow-review/v1";
22
+ export const MAX_DYNAMIC_WORKFLOW_PROMPT_BYTES = 16 * 1024;
23
+ export const MAX_DYNAMIC_WORKFLOW_DRAFT_BYTES =
24
+ MAX_WORKFLOW_DEFINITION_BYTES + 256 * 1024;
25
+
26
+ const SHA256_RE = /^sha256:[a-f0-9]{64}$/u;
27
+ const DRAFT_FIELDS = new Set([
28
+ "schema",
29
+ "status",
30
+ "promptDigest",
31
+ "generator",
32
+ "createdAt",
33
+ "definitionSchema",
34
+ "definitionDigest",
35
+ "definition",
36
+ "projection",
37
+ "draftDigest",
38
+ ]);
39
+ const GENERATOR_FIELDS = new Set(["provider", "model"]);
40
+ const PROJECTION_FIELDS = new Set([
41
+ "adapter",
42
+ "engineCapabilities",
43
+ "usedCapabilities",
44
+ "plan",
45
+ "governance",
46
+ "runtimeClaims",
47
+ ]);
48
+
49
+ function digest(domain, value) {
50
+ return `sha256:${createHash("sha256")
51
+ .update(domain, "utf8")
52
+ .update(canonicalJson(value, "dynamicWorkflowDraft"), "utf8")
53
+ .digest("hex")}`;
54
+ }
55
+
56
+ function canonicalTimestamp(value, field) {
57
+ const raw = typeof value === "function" ? value() : value;
58
+ const date = raw == null ? new Date() : new Date(raw);
59
+ if (!Number.isFinite(date.getTime())) {
60
+ throw new TypeError(`${field} must be a canonical timestamp`);
61
+ }
62
+ return date.toISOString();
63
+ }
64
+
65
+ function boundedString(value, field, max = 256) {
66
+ if (typeof value !== "string") throw new TypeError(`${field} is required`);
67
+ const output = value.trim();
68
+ let hasControlCharacter = false;
69
+ for (let index = 0; index < output.length; index += 1) {
70
+ const code = output.charCodeAt(index);
71
+ if (code <= 0x1f || code === 0x7f) {
72
+ hasControlCharacter = true;
73
+ break;
74
+ }
75
+ }
76
+ if (!output || output.length > max || hasControlCharacter) {
77
+ throw new TypeError(`${field} is invalid`);
78
+ }
79
+ return output;
80
+ }
81
+
82
+ function assertExactObject(value, fields, field) {
83
+ if (
84
+ !value ||
85
+ typeof value !== "object" ||
86
+ Array.isArray(value) ||
87
+ utilTypes.isProxy(value) ||
88
+ ![Object.prototype, null].includes(Object.getPrototypeOf(value))
89
+ ) {
90
+ throw new TypeError(`${field} must be a plain object`);
91
+ }
92
+ const keys = Reflect.ownKeys(value);
93
+ if (
94
+ keys.length !== fields.size ||
95
+ keys.some((key) => typeof key !== "string" || !fields.has(key))
96
+ ) {
97
+ throw new TypeError(`${field} contains missing or unknown fields`);
98
+ }
99
+ for (const key of keys) {
100
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
101
+ if (
102
+ !descriptor ||
103
+ descriptor.enumerable !== true ||
104
+ !Object.hasOwn(descriptor, "value")
105
+ ) {
106
+ throw new TypeError(`${field}.${key} must be an enumerable data field`);
107
+ }
108
+ }
109
+ }
110
+
111
+ function snapshotJson(value, field) {
112
+ let encoded;
113
+ try {
114
+ encoded = canonicalJson(value, field);
115
+ } catch {
116
+ throw new TypeError(`${field} must contain canonical JSON`);
117
+ }
118
+ if (Buffer.byteLength(encoded, "utf8") > MAX_DYNAMIC_WORKFLOW_DRAFT_BYTES) {
119
+ throw new TypeError(`${field} exceeds the draft byte limit`);
120
+ }
121
+ return JSON.parse(encoded);
122
+ }
123
+
124
+ function parseGeneratedDefinition(value) {
125
+ if (typeof value !== "string") {
126
+ throw new TypeError("workflow generator must return text");
127
+ }
128
+ const bytes = Buffer.byteLength(value, "utf8");
129
+ if (bytes <= 0 || bytes > MAX_WORKFLOW_DEFINITION_BYTES) {
130
+ throw new TypeError("workflow generator response exceeds its byte limit");
131
+ }
132
+ const trimmed = value.trim();
133
+ const fenced = /^```(?:json)?\s*\r?\n([\s\S]*?)\r?\n```$/iu.exec(trimmed);
134
+ const json = fenced ? fenced[1] : trimmed;
135
+ if (!fenced && !json.startsWith("{")) {
136
+ throw new TypeError("workflow generator response must be one JSON object");
137
+ }
138
+ let definition;
139
+ try {
140
+ definition = JSON.parse(json);
141
+ } catch {
142
+ throw new TypeError("workflow generator response is not valid JSON");
143
+ }
144
+ if (
145
+ !definition ||
146
+ typeof definition !== "object" ||
147
+ Array.isArray(definition)
148
+ ) {
149
+ throw new TypeError("workflow generator response must be one JSON object");
150
+ }
151
+ if (
152
+ definition.facade?.generation != null ||
153
+ definition.facade?.review != null
154
+ ) {
155
+ throw new TypeError("workflow generator may not declare review authority");
156
+ }
157
+ if (containsSecret(JSON.stringify(definition))) {
158
+ throw new TypeError(
159
+ "workflow generator response contains secret-shaped data",
160
+ );
161
+ }
162
+ return definition;
163
+ }
164
+
165
+ function projectionFromManifest(manifest) {
166
+ return Object.freeze({
167
+ adapter: manifest.adapter,
168
+ engineCapabilities: manifest.engineCapabilities,
169
+ usedCapabilities: manifest.usedCapabilities,
170
+ plan: manifest.plan,
171
+ governance: manifest.governance,
172
+ runtimeClaims: manifest.runtimeClaims,
173
+ });
174
+ }
175
+
176
+ function assertReviewableManifest(manifest) {
177
+ const { requirements, estimates, budget } = manifest.governance;
178
+ const problems = [];
179
+ if (
180
+ requirements.capabilityDeclarationInvalid ||
181
+ canonicalJson(requirements.capabilities) !==
182
+ canonicalJson(manifest.usedCapabilities)
183
+ ) {
184
+ problems.push("capabilities-must-exactly-match-plan");
185
+ }
186
+ if (
187
+ requirements.executionLocationDeclarationInvalid ||
188
+ requirements.executionLocations.length === 0
189
+ ) {
190
+ problems.push("execution-location-required");
191
+ }
192
+ if (!requirements.permissions || requirements.permissionDeclarationInvalid) {
193
+ problems.push("permission-declaration-required");
194
+ }
195
+ if (!requirements.sandbox) problems.push("sandbox-declaration-required");
196
+ if (!requirements.dataBoundary) {
197
+ problems.push("data-boundary-declaration-required");
198
+ }
199
+ if (
200
+ requirements.credentialValuePresent ||
201
+ requirements.credentialDeclarationInvalid
202
+ ) {
203
+ problems.push("credential-reference-invalid");
204
+ }
205
+ if (Object.values(estimates).some((value) => value == null)) {
206
+ problems.push("estimates-required");
207
+ }
208
+ if (Object.values(budget).some((value) => value == null)) {
209
+ problems.push("budget-required");
210
+ }
211
+ const taskCalls = manifest.plan.worstCaseTaskCalls;
212
+ if (taskCalls == null)
213
+ problems.push("runtime-expansion-unsupported-for-draft");
214
+ if (
215
+ budget.maxExpandedTasks != null &&
216
+ (budget.maxExpandedTasks > 64 || taskCalls > budget.maxExpandedTasks)
217
+ ) {
218
+ problems.push("expanded-task-budget-invalid");
219
+ }
220
+ if (
221
+ budget.maxParallel != null &&
222
+ (budget.maxParallel > 64 || budget.maxParallel > budget.maxExpandedTasks)
223
+ ) {
224
+ problems.push("parallel-budget-invalid");
225
+ }
226
+ if (
227
+ taskCalls != null &&
228
+ estimates.tokensPerTask != null &&
229
+ budget.maxTokens != null &&
230
+ taskCalls * estimates.tokensPerTask > budget.maxTokens
231
+ ) {
232
+ problems.push("token-budget-exceeded");
233
+ }
234
+ if (
235
+ taskCalls != null &&
236
+ estimates.usdPerTask != null &&
237
+ budget.maxUsd != null &&
238
+ taskCalls * estimates.usdPerTask > budget.maxUsd
239
+ ) {
240
+ problems.push("usd-budget-exceeded");
241
+ }
242
+ const durationSlots = manifest.plan.steps.reduce(
243
+ (total, step) => total + (step.worstCaseDurationSlots ?? 0),
244
+ 0,
245
+ );
246
+ if (
247
+ estimates.durationMsPerTask != null &&
248
+ budget.maxDurationMs != null &&
249
+ durationSlots * estimates.durationMsPerTask > budget.maxDurationMs
250
+ ) {
251
+ problems.push("duration-budget-exceeded");
252
+ }
253
+ if (problems.length > 0) {
254
+ throw new TypeError(
255
+ `generated workflow is not reviewable: ${problems.join(", ")}`,
256
+ );
257
+ }
258
+ }
259
+
260
+ function generationPrompt(prompt) {
261
+ return [
262
+ "Return exactly one JSON object and no prose.",
263
+ "Create a cc dynamic workflow definition with id, name, non-empty steps, and facade.",
264
+ "Each step needs id and message; use dependsOn for the DAG.",
265
+ "facade.requirements must exactly declare the capabilities used by the plan, one or more executionLocations, explicit permissions, sandbox, dataBoundary, and credential references containing only name/source/scope.",
266
+ "facade.estimates must declare positive tokensPerTask, usdPerTask, and durationMsPerTask.",
267
+ "facade.budget must declare maxExpandedTasks (at most 64), maxParallel (at most maxExpandedTasks), maxTokens, maxUsd, and maxDurationMs covering the projected plan.",
268
+ "Do not include credentials, secrets, generation metadata, review metadata, or unsupported capabilities.",
269
+ "Requested workflow:",
270
+ prompt,
271
+ ].join("\n");
272
+ }
273
+
274
+ function draftMaterial(value) {
275
+ const material = { ...value };
276
+ delete material.draftDigest;
277
+ return material;
278
+ }
279
+
280
+ export async function generateDynamicWorkflowDraft(input = {}, deps = {}) {
281
+ const prompt = typeof input.prompt === "string" ? input.prompt.trim() : "";
282
+ const promptBytes = Buffer.byteLength(prompt, "utf8");
283
+ if (promptBytes <= 0 || promptBytes > MAX_DYNAMIC_WORKFLOW_PROMPT_BYTES) {
284
+ throw new TypeError(
285
+ `workflow prompt must be 1..${MAX_DYNAMIC_WORKFLOW_PROMPT_BYTES} bytes`,
286
+ );
287
+ }
288
+ const provider = boundedString(input.provider, "provider", 128);
289
+ const model = boundedString(input.model, "model", 256);
290
+ if (typeof deps.chat !== "function") {
291
+ throw new TypeError("workflow draft chat provider is required");
292
+ }
293
+ const createdAt = canonicalTimestamp(deps.now, "createdAt");
294
+ const promptDigest = digest(
295
+ "chainlesschain.dynamic-workflow.prompt.v1\0",
296
+ prompt,
297
+ );
298
+ const response = await deps.chat(
299
+ [
300
+ {
301
+ role: "system",
302
+ content:
303
+ "You generate bounded workflow JSON for explicit human review. You never execute or persist it.",
304
+ },
305
+ { role: "user", content: generationPrompt(prompt) },
306
+ ],
307
+ { maxTokens: 8192 },
308
+ );
309
+ const proposed = parseGeneratedDefinition(response);
310
+ const definition = {
311
+ ...proposed,
312
+ facade: {
313
+ ...(proposed.facade || {}),
314
+ generation: {
315
+ schema: DYNAMIC_WORKFLOW_GENERATION_SCHEMA,
316
+ promptDigest,
317
+ provider,
318
+ model,
319
+ generatedAt: createdAt,
320
+ },
321
+ },
322
+ };
323
+ const manifest = createDynamicWorkflowManifest(definition);
324
+ assertReviewableManifest(manifest);
325
+ const material = Object.freeze({
326
+ schema: DYNAMIC_WORKFLOW_DRAFT_SCHEMA,
327
+ status: "pending-review",
328
+ promptDigest,
329
+ generator: Object.freeze({ provider, model }),
330
+ createdAt,
331
+ definitionSchema: WORKFLOW_DEFINITION_SCHEMA,
332
+ definitionDigest: manifest.definitionDigest,
333
+ definition: manifest.definition,
334
+ projection: projectionFromManifest(manifest),
335
+ });
336
+ return Object.freeze({
337
+ ...material,
338
+ draftDigest: digest("chainlesschain.dynamic-workflow.draft.v1\0", material),
339
+ });
340
+ }
341
+
342
+ export function verifyDynamicWorkflowDraft(value) {
343
+ assertExactObject(value, DRAFT_FIELDS, "workflow draft");
344
+ assertExactObject(
345
+ value.generator,
346
+ GENERATOR_FIELDS,
347
+ "workflow draft generator",
348
+ );
349
+ assertExactObject(
350
+ value.projection,
351
+ PROJECTION_FIELDS,
352
+ "workflow draft projection",
353
+ );
354
+ const snapshot = snapshotJson(value, "workflow draft");
355
+ if (
356
+ snapshot.schema !== DYNAMIC_WORKFLOW_DRAFT_SCHEMA ||
357
+ snapshot.status !== "pending-review" ||
358
+ !SHA256_RE.test(snapshot.promptDigest) ||
359
+ !SHA256_RE.test(snapshot.definitionDigest) ||
360
+ !SHA256_RE.test(snapshot.draftDigest) ||
361
+ snapshot.definitionSchema !== WORKFLOW_DEFINITION_SCHEMA ||
362
+ canonicalTimestamp(snapshot.createdAt, "createdAt") !== snapshot.createdAt
363
+ ) {
364
+ throw new TypeError("workflow draft identity is invalid");
365
+ }
366
+ const provider = boundedString(snapshot.generator.provider, "provider", 128);
367
+ const model = boundedString(snapshot.generator.model, "model", 256);
368
+ const generation = snapshot.definition?.facade?.generation;
369
+ if (
370
+ generation?.schema !== DYNAMIC_WORKFLOW_GENERATION_SCHEMA ||
371
+ generation.promptDigest !== snapshot.promptDigest ||
372
+ generation.provider !== provider ||
373
+ generation.model !== model ||
374
+ generation.generatedAt !== snapshot.createdAt ||
375
+ snapshot.definition?.facade?.review != null
376
+ ) {
377
+ throw new TypeError("workflow draft generation authority is invalid");
378
+ }
379
+ if (containsSecret(JSON.stringify(snapshot.definition))) {
380
+ throw new TypeError("workflow draft contains secret-shaped data");
381
+ }
382
+ const manifest = createDynamicWorkflowManifest(snapshot.definition);
383
+ assertReviewableManifest(manifest);
384
+ if (
385
+ manifest.definitionDigest !== snapshot.definitionDigest ||
386
+ canonicalJson(projectionFromManifest(manifest)) !==
387
+ canonicalJson(snapshot.projection)
388
+ ) {
389
+ throw new TypeError(
390
+ "workflow draft projection does not match its definition",
391
+ );
392
+ }
393
+ const expectedDigest = digest(
394
+ "chainlesschain.dynamic-workflow.draft.v1\0",
395
+ draftMaterial(snapshot),
396
+ );
397
+ if (expectedDigest !== snapshot.draftDigest) {
398
+ throw new TypeError("workflow draft digest mismatch");
399
+ }
400
+ return Object.freeze(snapshot);
401
+ }
402
+
403
+ export function reviewDynamicWorkflowDraft(input = {}, deps = {}) {
404
+ const draft = verifyDynamicWorkflowDraft(input.draft);
405
+ const expectedDraftDigest = String(input.expectedDraftDigest || "")
406
+ .trim()
407
+ .toLowerCase();
408
+ if (!SHA256_RE.test(expectedDraftDigest)) {
409
+ throw new TypeError("expected draft digest is required");
410
+ }
411
+ if (expectedDraftDigest !== draft.draftDigest) {
412
+ throw new TypeError("workflow draft changed before review");
413
+ }
414
+ if (!new Set(["accept", "reject"]).has(input.decision)) {
415
+ throw new TypeError("workflow review decision must be accept or reject");
416
+ }
417
+ const reviewer = boundedString(input.reviewer, "reviewer", 256);
418
+ const reason =
419
+ input.reason == null
420
+ ? null
421
+ : boundedString(input.reason, "review reason", 2048);
422
+ if (reason && containsSecret(reason)) {
423
+ throw new TypeError("workflow review reason contains secret-shaped data");
424
+ }
425
+ const reviewedAt = canonicalTimestamp(deps.now, "reviewedAt");
426
+ let definition = null;
427
+ let acceptedDefinitionDigest = null;
428
+ if (input.decision === "accept") {
429
+ const reviewedDefinition = {
430
+ ...draft.definition,
431
+ facade: {
432
+ ...draft.definition.facade,
433
+ review: {
434
+ schema: DYNAMIC_WORKFLOW_REVIEW_SCHEMA,
435
+ decision: "accepted",
436
+ draftDigest: draft.draftDigest,
437
+ sourceDefinitionDigest: draft.definitionDigest,
438
+ reviewer,
439
+ reason,
440
+ reviewedAt,
441
+ },
442
+ },
443
+ };
444
+ const manifest = createDynamicWorkflowManifest(reviewedDefinition);
445
+ assertReviewableManifest(manifest);
446
+ definition = manifest.definition;
447
+ acceptedDefinitionDigest = manifest.definitionDigest;
448
+ }
449
+ const material = Object.freeze({
450
+ schema: DYNAMIC_WORKFLOW_REVIEW_SCHEMA,
451
+ status: input.decision === "accept" ? "accepted" : "rejected",
452
+ draftDigest: draft.draftDigest,
453
+ promptDigest: draft.promptDigest,
454
+ sourceDefinitionDigest: draft.definitionDigest,
455
+ acceptedDefinitionDigest,
456
+ reviewer,
457
+ reason,
458
+ reviewedAt,
459
+ definition,
460
+ });
461
+ return Object.freeze({
462
+ ...material,
463
+ reviewDigest: digest(
464
+ "chainlesschain.dynamic-workflow.review.v1\0",
465
+ material,
466
+ ),
467
+ });
468
+ }
469
+
470
+ function parseDraftFile(raw) {
471
+ const text =
472
+ typeof raw === "string" ? raw : Buffer.from(raw).toString("utf8");
473
+ const bytes = Buffer.byteLength(text, "utf8");
474
+ if (bytes <= 0 || bytes > MAX_DYNAMIC_WORKFLOW_DRAFT_BYTES) {
475
+ throw new TypeError(
476
+ `workflow draft file must be 1..${MAX_DYNAMIC_WORKFLOW_DRAFT_BYTES} bytes`,
477
+ );
478
+ }
479
+ let value;
480
+ try {
481
+ value = JSON.parse(text);
482
+ } catch {
483
+ throw new TypeError("workflow draft file is not valid JSON");
484
+ }
485
+ return verifyDynamicWorkflowDraft(value);
486
+ }
487
+
488
+ export function readDynamicWorkflowDraftFile(filePath, deps = {}) {
489
+ const runtimeFs = deps.fs || fs;
490
+ const resolved = path.resolve(filePath);
491
+ return withTrustedFileParentSync(
492
+ runtimeFs,
493
+ resolved,
494
+ ({ canonicalPath, parentDevice }) => {
495
+ const before = runtimeFs.lstatSync(canonicalPath, { bigint: true });
496
+ if (
497
+ !before.isFile() ||
498
+ before.isSymbolicLink() ||
499
+ Number(before.nlink) !== 1 ||
500
+ Number(before.size) <= 0 ||
501
+ Number(before.size) > MAX_DYNAMIC_WORKFLOW_DRAFT_BYTES
502
+ ) {
503
+ throw new TypeError(
504
+ "workflow draft must be a bounded, regular, single-link file",
505
+ );
506
+ }
507
+ let descriptor;
508
+ try {
509
+ let flags = Number(runtimeFs.constants.O_RDONLY || 0);
510
+ if (typeof runtimeFs.constants.O_NOFOLLOW === "number") {
511
+ flags |= runtimeFs.constants.O_NOFOLLOW;
512
+ }
513
+ descriptor = runtimeFs.openSync(canonicalPath, flags);
514
+ const opened = runtimeFs.fstatSync(descriptor, { bigint: true });
515
+ if (
516
+ !opened.isFile() ||
517
+ Number(opened.nlink) !== 1 ||
518
+ !samePathHandleFileIdentity(before, opened, parentDevice)
519
+ ) {
520
+ throw new TypeError("workflow draft identity changed while opening");
521
+ }
522
+ const draft = parseDraftFile(
523
+ runtimeFs.readFileSync(descriptor, "utf8"),
524
+ );
525
+ const after = runtimeFs.fstatSync(descriptor, { bigint: true });
526
+ if (!sameFileStatIdentity(opened, after)) {
527
+ throw new TypeError("workflow draft changed while being read");
528
+ }
529
+ return draft;
530
+ } finally {
531
+ if (descriptor !== undefined) runtimeFs.closeSync(descriptor);
532
+ }
533
+ },
534
+ );
535
+ }