chainlesschain 0.165.6 → 0.165.9

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 (251) hide show
  1. package/package.json +2 -1
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/{AIOps-vfoDb6HZ.js → AIOps-DxwjrnEA.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-Cm5f7p93.js → ActionButton-JdbYowzn.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-yRuvgWxa.js → Analytics-C06GCahv.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-BROsC4h1.js → AppLayout-BUVEEyi1.js} +4 -4
  7. package/src/assets/web-panel/assets/{Artifacts-CimHApb1.js → Artifacts-D_ORzkJd.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-DI8kr8zI.js → Audit-8o_Y5ejG.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-DSLzKy-n.js → BackgroundAgents-DrkHd5VU.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-DkH_n2r1.js → Backup-CKBZCX11.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-CKSrUoRA.js → BaseInput-C8HkI399.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-ClwfMXUS.js → Chat-zb2H2Wux.js} +6 -6
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CjMaqfL7.js → ChatBubbleRenderer-BDcNpU_F.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-BYTehcQG.js → Checkbox-MwPtQmNz.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-B8AMcp6J.js → Codegen-3p5QCkFK.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-BNSogPo3.js → Col-BPLlhn52.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-JxPvGb8O.js → Community-C-3dBNOM.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-DF7bFAgE.js → Compact-BUcy-F_b.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-Bvhqnwrq.js → Compliance-CI8NxT8m.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-BDS0CJvM.js → Cowork-DaDEBS-Q.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-DqvRfxoQ.js → Cron-BSv9HXu5.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-CDcIvnqS.js → Crosschain-yuiKlJmv.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-D7jaUxU3.js → DID-D6LfldB0.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-B5A18wEV.js → Dashboard-CBhLqG61.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-_6IVkGag.js → Dropdown-BG8pIl3O.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-C9PeiKCG.js → EmailListRenderer-CY92VIE6.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DXjuEHrX.js → FamilyGuardDashboard-1Q_ehauM.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-B4IAR9zv.js → Federation-D3XirJIU.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-CxQeSNx1.js → FormItemContext-DfI9UuGZ.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-B8GS-Y3N.js → GenericCardRenderer-IeCZk2m7.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-BS8SouUX.js → Git-DzK4IJAZ.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-Dq9aYb5Q.js → Governance-BHf5KfmQ.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-BrCEe9AJ.js → Inference-BmaxSALS.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-DybOpiY2.js → KnowledgeGraph-BgePFLA9.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-DBpzbRfx.js → Logs-nqgxpOc4.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-xkX6izBt.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-Cc7CCSCu.js → Marketplace-Bu8to-86.js} +1 -1
  38. package/src/assets/web-panel/assets/McpTools-BFWTzEk0.js +4 -0
  39. package/src/assets/web-panel/assets/{Memory-KCqlp9ol.js → Memory-B026G2GA.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-Bys84ySN.js → MobileBridge-CM2Eeg6I.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-B-6qU-je.js → MobileProjects-B79Ob3hy.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-BgY-fvCq.js → Mtc-CxevSZuV.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-B8pCmqQJ.js → MtcAudit-X396cPEX.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-BbOmYutA.js → Multisig-HWIB_aZ1.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-BocLQz_M.js → NLProgramming-gnYD1Xwy.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-CSwbxEop.js → Notes-Dn2Gf_J1.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-CqFNSYG3.js → NotificationSettings-BRKBQ5rq.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-C6gMfAk7.js → OrderTableRenderer-Dy___Cgo.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-QrDXVdMJ.js → Organization-cqfccxnt.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-Cxntotjt.js → Overflow-CSX4FHN3.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-CIdBOwNq.js → P2P-Bwa4aghp.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-CT5aP8rD.js → PdhVaultBrowser-Dhszyjig.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-DH7OM8XU.js → Permissions-CXzTyk6e.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-CnJqbWce.js → PersonalDataHub-CFCAAJbb.js} +4 -4
  55. package/src/assets/web-panel/assets/{Pipeline-5C3HG1kH.js → Pipeline-BPJbx6xt.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-B4yIp7xK.js → Privacy-BbiXvEHz.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-BMvt-2M0.js → ProjectInit-B-s7-wSD.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-CvSTEMRG.js → ProjectSettings-Dyug206y.js} +2 -2
  59. package/src/assets/web-panel/assets/{Projects-BKBJxEek.js → Projects-BtAI5Fwo.js} +1 -1
  60. package/src/assets/web-panel/assets/{Providers-BdwUqFWN.js → Providers-JpIPmz6N.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-DtnCKlTm.js → QrScannerModal-CZdoN64A.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-sTbgwyNr.js → QuickAsk-BwvnoRIT.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-Bzr14gSb.js → Recommend-ASMlMQrD.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-C_TF5IaJ.js → RemoteSession-BiJzKFKi.js} +3 -3
  65. package/src/assets/web-panel/assets/{Reputation-GCAM4H2K.js → Reputation-C80TWLIO.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-Dir0r6OQ.js → Row-C1VNmjmX.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-CpGnlecX.js → RssFeed-T2MyGUlG.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-DMMamC6u.js → Search-DXM6O83L.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-yqay5yG-.js → Security-nv69kU7W.js} +3 -3
  70. package/src/assets/web-panel/assets/{Services-C5i2wh9G.js → Services-AyHWe7Qj.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-vUqk35yj.js → Skeleton-D6PWLxFI.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-DzcSkhot.js → Skills-BqVeOmNQ.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-CB6qbYNr.js → Sla-BegIPl9M.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-BHUI7cox.js → SpeechSettings-CKJn3xk-.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-D-RrsxTJ.js → SyncSettings-Th4cnAMl.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-DFxdOJiq.js → Tasks-BuKfBroh.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-SKAob_Aq.js → Templates-CMuWN8Ac.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-BPfsfHQ-.js → Tenant-C4je8E8Q.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-8iw7FpUf.js → Terminal-agJESOcO.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-C4Gjj5Su.js → TimelineRenderer-D2qDuVZ_.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-COYhN18e.js → Tokens-Cvmn99rH.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-B-JzXcf6.js → Trigger-D_QYIHH8.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-BJ5bg0nI.js → Trust-BmzvQLnX.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-BG_ByRMf.js → UkeySign-D_LopHwH.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-B3kOnSiU.js → VideoEditing-DoWl3PhQ.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-CcoGFnK7.js → Wallet-5NYcAkxe.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-DdT8vRC_.js → WebAuthn-B-_Q3ewp.js} +4 -4
  88. package/src/assets/web-panel/assets/{WorkflowEditor-CZu3M9N8.js → WorkflowEditor-CHET-gi2.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-DxJt3Qba.js → chat-C6nvb-n6.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-DdYfwJaB.js → colors-CTDE9LTX.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-BG3SUzwj.js → compact-item-KnemdF8D.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-By51z2-1.js → createContext-DUJR3Uek.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-1DqLH1KX.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-B0apZ3KJ.js → hasIn-CFNTaby8.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-ZxtP8jG7.js → index-65HO56Bv.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Da_WBdLX.js → index-B8RtbSkV.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BBPf3TpM.js → index-BHqSqnW7.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BP94CrBV.js → index-BTetEUWd.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-p1_8SbI1.js → index-BXWg1crv.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BWF8_mkx.js → index-BdiC4LOs.js} +1 -1
  101. package/src/assets/web-panel/assets/index-BhJtcPWo.js +1 -0
  102. package/src/assets/web-panel/assets/{index-SQqOlR3d.js → index-BuizJo2E.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CpjZhgNd.js → index-BwZM1rod.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CzmQElZy.js → index-C96N9xeL.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-bP_VlDb4.js → index-CHfUdnJH.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-ZFbps9po.js → index-CKvBF3Ov.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DaIz0NAW.js → index-CSD9_I2_.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BewKYrX9.js → index-Cc7dbl_p.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CNIxXMmN.js → index-CcF0D7UZ.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Q2SCX-MI.js → index-Ceu92a8D.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DE76D-kA.js → index-CnLpuTAU.js} +1 -1
  112. package/src/assets/web-panel/assets/index-Cq8MWPDT.js +1 -0
  113. package/src/assets/web-panel/assets/{index-BkvcEo4p.js → index-CquKnw5r.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-Cp6e-hGw.js → index-CyEtHvEE.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BLIbGOLX.js → index-DF-fcTvQ.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DCn8IcxV.js → index-DF1Y0Vuw.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Bissefox.js → index-DJyPeBBk.js} +3 -3
  118. package/src/assets/web-panel/assets/{index-BZ_0qm4g.js → index-DP-PbO11.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-kf57LJ93.js → index-DZgCRMxk.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BYINoRLK.js → index-DfJzS3Qa.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-3jWkIu5j.js → index-DqPpJkte.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-B5rLiEo0.js → index-DzReoLyh.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CW93tZDv.js → index-JGTiDeOW.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-C1C9i79A.js → index-NUR0If7O.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-CAhHirVH.js → index-NtAcnJYW.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-RD6O-0C6.js → index-OmuhFYKE.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-oxRrmFO9.js → index-Wlc7o_C8.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-B3rWuPMW.js → index-bxTPfdri.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BIrJfqO4.js → index-k6uorYmf.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BfWYsB9t.js → index-ox6mIwE2.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Bos5_aMV.js → index-rVDD7AAR.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-CWEuZWCK.js → index-u0h6QqVV.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-Dz49VOyQ.js → index-v-mtxmWH.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-BWJktcg8.js → initDefaultProps-qEt8dI-t.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BEXBzUFV.js → motion-DetKPWy-.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-BUKwn2sx.js → move-BeNYeDV2.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-FTI7btqQ.js → mtc-parser-C0q0MK_T.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-CsLtSPH3.js → omit-DLKkrKpE.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-DWZxsT_S.js → pickAttrs-Bw1tWsY8.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-Bcfs43CX.js → placementArrow-DeesBLbd.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-a9bcC1p-.js → responsiveObserve-bqLhxHhn.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-BDTzgOXN.js → slide-DGCXRoQm.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-Iq1j_HUg.js → statusUtils-H-re3Egl.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-DAZEYxeh.js → styleChecker-BXg4qGX_.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-DVkjyDrh.js → useFlexGapSupport-CKLb2KA6.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-wXTpNTHt.js → useFs-CTAhHeyw.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-CtQM_aZr.js → usePersonalDataHub-BQ4pDh5g.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-hjEoG85v.js → vnode-jrSK6j4j.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-BHVpyKg_.js → zoom-fOQE24pw.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/command-help-index.json +3 -3
  152. package/src/commands/agent.js +91 -60
  153. package/src/commands/git.js +39 -0
  154. package/src/commands/plugin.js +17 -2
  155. package/src/commands/session-group.js +131 -0
  156. package/src/commands/session-location.js +48 -0
  157. package/src/commands/session.js +11 -0
  158. package/src/commands/sync-providers.js +4 -1
  159. package/src/commands/update.js +1 -0
  160. package/src/data/changelog.json +40 -1
  161. package/src/gateways/ws/mcp-topic-handlers.js +167 -0
  162. package/src/gateways/ws/ws-agent-handler.js +20 -12
  163. package/src/harness/jsonl-session-store.js +279 -37
  164. package/src/harness/mcp-client.js +701 -91
  165. package/src/harness/session-index.js +15 -4
  166. package/src/lib/agent-network.js +166 -29
  167. package/src/lib/agent-router.js +62 -6
  168. package/src/lib/agent-sandbox.js +7 -1
  169. package/src/lib/agent-worktree.js +8 -1
  170. package/src/lib/auto-mode-safety-classifier.js +3 -17
  171. package/src/lib/background-agent-keeper-protocol.js +26 -6
  172. package/src/lib/background-agent-supervisor.js +17 -1
  173. package/src/lib/browser-evidence.js +1405 -0
  174. package/src/lib/chrome-connector.js +465 -79
  175. package/src/lib/claude-code-bridge.js +159 -54
  176. package/src/lib/claude-project-auto-memory.js +481 -0
  177. package/src/lib/claude-project-storage-layout.js +104 -0
  178. package/src/lib/cloud/cloud-client.js +40 -0
  179. package/src/lib/cowork-workflow.js +69 -6
  180. package/src/lib/execution-location-local-supervisor.mjs +226 -0
  181. package/src/lib/execution-location-runner-lifecycle.js +991 -0
  182. package/src/lib/execution-location-target-preflight.js +333 -0
  183. package/src/lib/execution-location-target.js +783 -13
  184. package/src/lib/external-agent-adapters.js +269 -0
  185. package/src/lib/file-lines.js +6 -1
  186. package/src/lib/gateway-client-resilience.js +571 -0
  187. package/src/lib/gitlab-mr-worktree.js +176 -0
  188. package/src/lib/hooks-v2-producers.js +119 -15
  189. package/src/lib/hooks-v2-workspace-context.js +44 -1
  190. package/src/lib/host-resource-budget.js +295 -0
  191. package/src/lib/ide-context.js +15 -2
  192. package/src/lib/ipfs-storage.js +127 -25
  193. package/src/lib/llm-config-defaults.js +43 -0
  194. package/src/lib/mcp-lifecycle-authority.js +887 -0
  195. package/src/lib/mcp-oauth.js +101 -20
  196. package/src/lib/mcp-tls.js +103 -3
  197. package/src/lib/orchestrator.js +47 -0
  198. package/src/lib/paths.js +260 -32
  199. package/src/lib/permission-request.js +48 -0
  200. package/src/lib/plugin-runtime/bin.js +3 -1
  201. package/src/lib/plugin-runtime/hooks.js +3 -1
  202. package/src/lib/plugin-runtime/install.js +117 -1
  203. package/src/lib/plugin-runtime/lsp.js +4 -4
  204. package/src/lib/plugin-runtime/marketplace-archive-source.js +40 -5
  205. package/src/lib/plugin-runtime/marketplace-catalog.js +13 -2
  206. package/src/lib/plugin-runtime/marketplace-command-descriptor.js +343 -0
  207. package/src/lib/plugin-runtime/marketplace-command-source.js +580 -0
  208. package/src/lib/plugin-runtime/marketplace-source-adapter.js +33 -8
  209. package/src/lib/plugin-runtime/mcp.js +3 -1
  210. package/src/lib/plugin-runtime/monitors.js +3 -1
  211. package/src/lib/plugin-runtime/remote-source.js +151 -6
  212. package/src/lib/plugin-runtime/settings.js +3 -1
  213. package/src/lib/plugin-runtime/trust.js +274 -13
  214. package/src/lib/process-execution-broker/credential-agent.js +210 -41
  215. package/src/lib/process-execution-broker/index.js +15 -1
  216. package/src/lib/process-execution-broker/linux-cgroup-v2.js +391 -0
  217. package/src/lib/process-execution-broker/platform-sandbox.js +50 -28
  218. package/src/lib/project-mcp-trust.js +165 -10
  219. package/src/lib/resume-session.js +9 -6
  220. package/src/lib/session-core-singletons.js +26 -11
  221. package/src/lib/session-host-lease.js +52 -16
  222. package/src/lib/session-lifecycle-scope.js +153 -0
  223. package/src/lib/session-message-fabric.js +168 -21
  224. package/src/lib/session-projection.js +244 -4
  225. package/src/lib/session-store-guard.js +3 -1
  226. package/src/lib/session-workbench-store.js +466 -0
  227. package/src/lib/shell-approval.js +7 -5
  228. package/src/lib/spellcheck.js +211 -0
  229. package/src/lib/sub-agent-context.js +9 -9
  230. package/src/lib/sync-cli-db.js +485 -129
  231. package/src/lib/sync-credentials.js +31 -20
  232. package/src/lib/web-fetch.js +112 -40
  233. package/src/lib/web-search.js +127 -61
  234. package/src/lib/workflow-engine.js +42 -11
  235. package/src/lib/workspace-trust.js +793 -0
  236. package/src/repl/agent-repl.js +124 -5
  237. package/src/repl/permission-prompt.js +10 -12
  238. package/src/runtime/agent-core.js +311 -18
  239. package/src/runtime/agent-runtime.js +12 -1
  240. package/src/runtime/bootstrap.js +37 -13
  241. package/src/runtime/coding-agent-contract-shared.cjs +11 -4
  242. package/src/runtime/headless-runner.js +234 -36
  243. package/src/runtime/headless-stream.js +181 -6
  244. package/src/runtime/mcp-config.js +298 -8
  245. package/src/runtime/policies/agent-policy.js +8 -0
  246. package/src/runtime/status-diagnostics-lite.js +9 -1
  247. package/src/assets/web-panel/assets/MarkdownRenderer-CFyt8iUd.js +0 -1
  248. package/src/assets/web-panel/assets/McpTools-DFaIhOfu.js +0 -7
  249. package/src/assets/web-panel/assets/devWarning-DorRZcI9.js +0 -1
  250. package/src/assets/web-panel/assets/index-BETiL0a3.js +0 -1
  251. package/src/assets/web-panel/assets/index-BhAVHuW8.js +0 -1
@@ -21,9 +21,9 @@
21
21
 
22
22
  import fs from "node:fs";
23
23
  import path from "node:path";
24
- import os from "node:os";
25
24
  import crypto from "node:crypto";
26
25
  import { withFileLock } from "./with-file-lock.js";
26
+ import { ensureDir, getHomeDir } from "./paths.js";
27
27
 
28
28
  const SENSITIVE_FIELDS = ["sync.webdav.password", "sync.oss.secretAccessKey"];
29
29
  const ALLOWED_PROVIDER_IDS = ["webdav", "oss"];
@@ -37,10 +37,7 @@ let _ccDirOverride = null;
37
37
 
38
38
  function _ccDir() {
39
39
  if (_ccDirOverride) return _ccDirOverride;
40
- return (
41
- process.env.CHAINLESSCHAIN_HOME ||
42
- path.join(os.homedir(), ".chainlesschain")
43
- );
40
+ return getHomeDir();
44
41
  }
45
42
 
46
43
  function _keyPath() {
@@ -53,7 +50,13 @@ function _vaultPath() {
53
50
 
54
51
  function _ensureDir() {
55
52
  const dir = _ccDir();
56
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
53
+ // Explicit test-only override keeps the existing isolated fake-filesystem
54
+ // seam lightweight; production roots always go through owner-only setup.
55
+ if (_ccDirOverride) {
56
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
57
+ return;
58
+ }
59
+ ensureDir(dir);
57
60
  }
58
61
 
59
62
  /**
@@ -217,24 +220,32 @@ function setCredentials(providerId, creds) {
217
220
  // Credential metadata is security-critical: never decrypt-modify-encrypt
218
221
  // without exclusion, because a lost update can silently restore/revoke the
219
222
  // wrong provider credentials.
220
- return withFileLock(_vaultPath(), () => {
221
- const all = loadAll();
222
- if (!all.sync || typeof all.sync !== "object") all.sync = {};
223
- all.sync[providerId] = { ...creds };
224
- return saveAll(all);
225
- }, { failIfUnavailable: true });
223
+ return withFileLock(
224
+ _vaultPath(),
225
+ () => {
226
+ const all = loadAll();
227
+ if (!all.sync || typeof all.sync !== "object") all.sync = {};
228
+ all.sync[providerId] = { ...creds };
229
+ return saveAll(all);
230
+ },
231
+ { failIfUnavailable: true },
232
+ );
226
233
  }
227
234
 
228
235
  function clearCredentials(providerId) {
229
236
  assertProviderId(providerId);
230
- return withFileLock(_vaultPath(), () => {
231
- const all = loadAll();
232
- if (all?.sync?.[providerId]) {
233
- delete all.sync[providerId];
234
- return saveAll(all);
235
- }
236
- return true;
237
- }, { failIfUnavailable: true });
237
+ return withFileLock(
238
+ _vaultPath(),
239
+ () => {
240
+ const all = loadAll();
241
+ if (all?.sync?.[providerId]) {
242
+ delete all.sync[providerId];
243
+ return saveAll(all);
244
+ }
245
+ return true;
246
+ },
247
+ { failIfUnavailable: true },
248
+ );
238
249
  }
239
250
 
240
251
  /** Test seam: override the resolved chainlesschain dir without env leak. */
@@ -9,6 +9,7 @@ import http from "node:http";
9
9
  import https from "node:https";
10
10
  import { lookup as dnsLookup } from "node:dns";
11
11
  import { URL } from "node:url";
12
+ import { createHash } from "node:crypto";
12
13
 
13
14
  const DEFAULT_MAX_BYTES = 2_000_000;
14
15
  const DEFAULT_TIMEOUT_MS = 15_000;
@@ -140,6 +141,35 @@ function stripTags(html) {
140
141
  return String(html).replace(/<[^>]+>/g, "");
141
142
  }
142
143
 
144
+ function webFetchCacheKey(parsed, { format, maxBytes, maxRedirects, headers }) {
145
+ // A caller-provided header can carry credentials or change representation.
146
+ // Keep those requests out of the shared host cache entirely.
147
+ if (
148
+ (headers && Object.keys(headers).length > 0) ||
149
+ parsed.username ||
150
+ parsed.password
151
+ ) {
152
+ return null;
153
+ }
154
+ const payload = JSON.stringify({
155
+ url: parsed.toString(),
156
+ format,
157
+ maxBytes,
158
+ maxRedirects,
159
+ });
160
+ // Do not retain a raw URL/query as a long-lived Map key in the host cache.
161
+ return `web-fetch:${createHash("sha256").update(payload).digest("hex")}`;
162
+ }
163
+
164
+ function hostBudgetUnavailable(tool, error) {
165
+ const reason = String(error?.budgetReason || "unavailable").slice(0, 128);
166
+ return {
167
+ error: `${tool} unavailable: host resource budget (${reason})`,
168
+ code: "ERR_HOST_RESOURCE_BUDGET",
169
+ reason,
170
+ };
171
+ }
172
+
143
173
  /**
144
174
  * A `lookup` for http(s).request that resolves the hostname and REJECTS the
145
175
  * connection if any resolved IP is private/loopback/link-local. checkAllowed
@@ -243,6 +273,7 @@ export async function webFetch(url, options = {}) {
243
273
  config = {},
244
274
  headers = {},
245
275
  maxRedirects = 3,
276
+ hostResourceBudget = null,
246
277
  } = options;
247
278
 
248
279
  const check = checkAllowed(url, config);
@@ -250,53 +281,94 @@ export async function webFetch(url, options = {}) {
250
281
  return { error: `web_fetch blocked: ${check.reason}` };
251
282
  }
252
283
 
253
- let parsed = check.url;
254
- let redirects = 0;
255
- let response;
256
- while (true) {
257
- response = await _doRequest(parsed, {
258
- maxBytes,
259
- timeout,
260
- headers,
261
- allowPrivateHosts: config.allowPrivateHosts,
262
- });
263
- if (!response.redirect) break;
264
- if (++redirects > maxRedirects) {
265
- return { error: "too many redirects" };
266
- }
267
- const next = new URL(response.redirect, parsed);
268
- const nextCheck = checkAllowed(next.toString(), config);
269
- if (!nextCheck.allowed) {
270
- return { error: `redirect blocked: ${nextCheck.reason}` };
284
+ const cacheKey = webFetchCacheKey(check.url, {
285
+ format,
286
+ maxBytes,
287
+ maxRedirects,
288
+ headers,
289
+ });
290
+ if (cacheKey && hostResourceBudget?.getWebFetch) {
291
+ try {
292
+ const cached = hostResourceBudget.getWebFetch(cacheKey);
293
+ if (cached) return { ...cached, cached: true };
294
+ } catch (error) {
295
+ return hostBudgetUnavailable("web_fetch", error);
271
296
  }
272
- parsed = nextCheck.url;
273
297
  }
274
298
 
275
- const { statusCode, headers: respHeaders, body } = response;
276
- const contentType = String(respHeaders["content-type"] || "");
277
-
278
- let output = body;
279
- let outputFormat = format;
280
- if (format === "markdown") {
281
- output = /html/i.test(contentType) ? htmlToMarkdown(body) : body;
282
- } else if (format === "text") {
283
- output = /html/i.test(contentType) ? stripTags(body) : body;
284
- } else if (format === "json") {
299
+ let toolLease = null;
300
+ if (hostResourceBudget) {
285
301
  try {
286
- output = JSON.parse(body);
287
- } catch {
288
- return { error: "response is not valid JSON", statusCode, body };
302
+ if (typeof hostResourceBudget.admitTool !== "function") {
303
+ throw new TypeError(
304
+ "host resource budget does not provide admitTool()",
305
+ );
306
+ }
307
+ toolLease = hostResourceBudget.admitTool({ kind: "web-fetch" });
308
+ } catch (error) {
309
+ return hostBudgetUnavailable("web_fetch", error);
289
310
  }
290
311
  }
291
312
 
292
- return {
293
- url: parsed.toString(),
294
- statusCode,
295
- contentType,
296
- format: outputFormat,
297
- bytes: Buffer.byteLength(body, "utf8"),
298
- content: output,
299
- };
313
+ try {
314
+ let parsed = check.url;
315
+ let redirects = 0;
316
+ let response;
317
+ while (true) {
318
+ response = await _doRequest(parsed, {
319
+ maxBytes,
320
+ timeout,
321
+ headers,
322
+ allowPrivateHosts: config.allowPrivateHosts,
323
+ });
324
+ if (!response.redirect) break;
325
+ if (++redirects > maxRedirects) {
326
+ return { error: "too many redirects" };
327
+ }
328
+ const next = new URL(response.redirect, parsed);
329
+ const nextCheck = checkAllowed(next.toString(), config);
330
+ if (!nextCheck.allowed) {
331
+ return { error: `redirect blocked: ${nextCheck.reason}` };
332
+ }
333
+ parsed = nextCheck.url;
334
+ }
335
+
336
+ const { statusCode, headers: respHeaders, body } = response;
337
+ const contentType = String(respHeaders["content-type"] || "");
338
+
339
+ let output = body;
340
+ let outputFormat = format;
341
+ if (format === "markdown") {
342
+ output = /html/i.test(contentType) ? htmlToMarkdown(body) : body;
343
+ } else if (format === "text") {
344
+ output = /html/i.test(contentType) ? stripTags(body) : body;
345
+ } else if (format === "json") {
346
+ try {
347
+ output = JSON.parse(body);
348
+ } catch {
349
+ return { error: "response is not valid JSON", statusCode, body };
350
+ }
351
+ }
352
+
353
+ const result = {
354
+ url: parsed.toString(),
355
+ statusCode,
356
+ contentType,
357
+ format: outputFormat,
358
+ bytes: Buffer.byteLength(body, "utf8"),
359
+ content: output,
360
+ };
361
+ if (cacheKey && hostResourceBudget?.putWebFetch) {
362
+ try {
363
+ hostResourceBudget.putWebFetch(cacheKey, result);
364
+ } catch {
365
+ // Cache failures never weaken the completed, bounded I/O result.
366
+ }
367
+ }
368
+ return result;
369
+ } finally {
370
+ toolLease?.release();
371
+ }
300
372
  }
301
373
 
302
374
  // `lookup` is injectable so tests can resolve a domain to a private IP without
@@ -18,6 +18,7 @@ import { URL } from "url";
18
18
  const DEFAULT_MAX_BYTES = 2_000_000;
19
19
  const DEFAULT_TIMEOUT_MS = 15_000;
20
20
  const DEFAULT_MAX_RESULTS = 8;
21
+ export const MAX_WEB_SEARCH_RESULTS = 20;
21
22
 
22
23
  const KEYED_PROVIDERS = ["tavily", "brave", "bocha", "qianfan"];
23
24
  const KEYLESS_PROVIDERS = ["duckduckgo", "searxng", "baidu"];
@@ -38,7 +39,11 @@ export function resolveApiKey(provider, options = {}, config = {}) {
38
39
  switch (provider) {
39
40
  case "tavily":
40
41
  return (
41
- options.apiKey || config.tavilyApiKey || config.apiKey || env.TAVILY_API_KEY || ""
42
+ options.apiKey ||
43
+ config.tavilyApiKey ||
44
+ config.apiKey ||
45
+ env.TAVILY_API_KEY ||
46
+ ""
42
47
  );
43
48
  case "brave":
44
49
  return (
@@ -51,7 +56,11 @@ export function resolveApiKey(provider, options = {}, config = {}) {
51
56
  );
52
57
  case "bocha":
53
58
  return (
54
- options.apiKey || config.bochaApiKey || config.apiKey || env.BOCHA_API_KEY || ""
59
+ options.apiKey ||
60
+ config.bochaApiKey ||
61
+ config.apiKey ||
62
+ env.BOCHA_API_KEY ||
63
+ ""
55
64
  );
56
65
  case "qianfan":
57
66
  return (
@@ -82,7 +91,10 @@ export function resolveProvider(options = {}, config = {}) {
82
91
  return "duckduckgo";
83
92
  }
84
93
 
85
- function _request(urlStr, { method = "GET", headers = {}, body = null, timeout, maxBytes }) {
94
+ function _request(
95
+ urlStr,
96
+ { method = "GET", headers = {}, body = null, timeout, maxBytes },
97
+ ) {
86
98
  const parsed = new URL(urlStr);
87
99
  const lib = parsed.protocol === "https:" ? _deps.https : _deps.http;
88
100
  return new Promise((resolve, reject) => {
@@ -147,6 +159,22 @@ function _clean(s) {
147
159
  return _decodeEntities(_stripTags(s)).replace(/\s+/g, " ").trim();
148
160
  }
149
161
 
162
+ function normalizeMaxResults(value) {
163
+ const parsed = Number(value);
164
+ const requested =
165
+ Number.isSafeInteger(parsed) && parsed > 0 ? parsed : DEFAULT_MAX_RESULTS;
166
+ return Math.min(requested, MAX_WEB_SEARCH_RESULTS);
167
+ }
168
+
169
+ function hostBudgetUnavailable(error) {
170
+ const reason = String(error?.budgetReason || "unavailable").slice(0, 128);
171
+ return {
172
+ error: `web_search unavailable: host resource budget (${reason})`,
173
+ code: "ERR_HOST_RESOURCE_BUDGET",
174
+ reason,
175
+ };
176
+ }
177
+
150
178
  // ---- Provider adapters: each returns { results: [{title,url,snippet}], answer } ----
151
179
 
152
180
  async function _searchTavily(query, { apiKey, maxResults, timeout, maxBytes }) {
@@ -167,7 +195,9 @@ async function _searchTavily(query, { apiKey, maxResults, timeout, maxBytes }) {
167
195
  maxBytes,
168
196
  });
169
197
  if (res.statusCode >= 400) {
170
- return { error: `tavily HTTP ${res.statusCode}: ${res.body.slice(0, 200)}` };
198
+ return {
199
+ error: `tavily HTTP ${res.statusCode}: ${res.body.slice(0, 200)}`,
200
+ };
171
201
  }
172
202
  let json;
173
203
  try {
@@ -326,10 +356,7 @@ async function _searchQianfan(
326
356
  url: r.url || "",
327
357
  snippet: _clean(r.content || r.web_anchor || ""),
328
358
  }));
329
- const answer =
330
- json.answer ||
331
- json.choices?.[0]?.message?.content ||
332
- "";
359
+ const answer = json.answer || json.choices?.[0]?.message?.content || "";
333
360
  return { results, answer: typeof answer === "string" ? answer : "" };
334
361
  }
335
362
 
@@ -362,7 +389,8 @@ async function _searchBaidu(query, { maxResults, timeout, maxBytes }) {
362
389
  // Markup-agnostic: anchor each result on its <h3 class="t|c-title"> heading,
363
390
  // pull the URL from the anchor inside it (a baidu.com/link?url= redirect that
364
391
  // web_fetch resolves), and take the text up to the next heading as snippet.
365
- const h3re = /<h3[^>]*class="[^"]*\b(?:t|c-title)\b[^"]*"[^>]*>([\s\S]*?)<\/h3>/gi;
392
+ const h3re =
393
+ /<h3[^>]*class="[^"]*\b(?:t|c-title)\b[^"]*"[^>]*>([\s\S]*?)<\/h3>/gi;
366
394
  const marks = [];
367
395
  let m;
368
396
  while ((m = h3re.exec(html)) !== null) {
@@ -381,7 +409,10 @@ async function _searchBaidu(query, { maxResults, timeout, maxBytes }) {
381
409
  return { results, answer: "" };
382
410
  }
383
411
 
384
- async function _searchSearxng(query, { instanceUrl, maxResults, timeout, maxBytes }) {
412
+ async function _searchSearxng(
413
+ query,
414
+ { instanceUrl, maxResults, timeout, maxBytes },
415
+ ) {
385
416
  if (!instanceUrl) return { error: "searxng: missing instanceUrl" };
386
417
  const base = instanceUrl.replace(/\/+$/, "");
387
418
  const url = `${base}/search?q=${encodeURIComponent(query)}&format=json`;
@@ -398,7 +429,9 @@ async function _searchSearxng(query, { instanceUrl, maxResults, timeout, maxByte
398
429
  try {
399
430
  json = JSON.parse(res.body);
400
431
  } catch {
401
- return { error: "searxng: invalid JSON response (is json format enabled?)" };
432
+ return {
433
+ error: "searxng: invalid JSON response (is json format enabled?)",
434
+ };
402
435
  }
403
436
  const results = (json.results || []).slice(0, maxResults).map((r) => ({
404
437
  title: _clean(r.title || ""),
@@ -419,10 +452,7 @@ export async function webSearch(query, options = {}) {
419
452
 
420
453
  const config = options.config || {};
421
454
  const provider = resolveProvider(options, config);
422
- const maxResults =
423
- Number(options.maxResults) ||
424
- Number(config.maxResults) ||
425
- DEFAULT_MAX_RESULTS;
455
+ let maxResults = normalizeMaxResults(options.maxResults ?? config.maxResults);
426
456
  const timeout = Number(options.timeout) || DEFAULT_TIMEOUT_MS;
427
457
  const maxBytes = Number(options.maxBytes) || DEFAULT_MAX_BYTES;
428
458
 
@@ -432,56 +462,92 @@ export async function webSearch(query, options = {}) {
432
462
  };
433
463
  }
434
464
 
435
- const apiKey = resolveApiKey(provider, options, config);
436
- const common = { apiKey, maxResults, timeout, maxBytes };
465
+ const hostResourceBudget = options.hostResourceBudget || null;
466
+ if (hostResourceBudget?.capWebSearchResults) {
467
+ try {
468
+ maxResults = normalizeMaxResults(
469
+ hostResourceBudget.capWebSearchResults(maxResults),
470
+ );
471
+ } catch (error) {
472
+ return hostBudgetUnavailable(error);
473
+ }
474
+ }
437
475
 
438
- let out;
439
- try {
440
- switch (provider) {
441
- case "tavily":
442
- out = await _searchTavily(q, common);
443
- break;
444
- case "brave":
445
- out = await _searchBrave(q, common);
446
- break;
447
- case "bocha":
448
- out = await _searchBocha(q, common);
449
- break;
450
- case "qianfan":
451
- out = await _searchQianfan(q, {
452
- ...common,
453
- endpoint: options.qianfanUrl || config.qianfanUrl,
454
- });
455
- break;
456
- case "searxng":
457
- out = await _searchSearxng(q, {
458
- instanceUrl: options.instanceUrl || config.instanceUrl,
459
- maxResults,
460
- timeout,
461
- maxBytes,
462
- });
463
- break;
464
- case "baidu":
465
- out = await _searchBaidu(q, { maxResults, timeout, maxBytes });
466
- break;
467
- case "duckduckgo":
468
- default:
469
- out = await _searchDuckDuckGo(q, { maxResults, timeout, maxBytes });
470
- break;
476
+ let toolLease = null;
477
+ if (hostResourceBudget) {
478
+ try {
479
+ if (typeof hostResourceBudget.admitTool !== "function") {
480
+ throw new TypeError(
481
+ "host resource budget does not provide admitTool()",
482
+ );
483
+ }
484
+ toolLease = hostResourceBudget.admitTool({ kind: "web-search" });
485
+ } catch (error) {
486
+ return hostBudgetUnavailable(error);
471
487
  }
472
- } catch (err) {
473
- return { error: `web_search (${provider}) failed: ${err.message}`, provider };
474
488
  }
475
489
 
476
- if (out && out.error) return { ...out, provider };
477
- const results = (out && out.results) || [];
478
- return {
479
- query: q,
480
- provider,
481
- count: results.length,
482
- results,
483
- answer: (out && out.answer) || "",
484
- };
490
+ try {
491
+ const apiKey = resolveApiKey(provider, options, config);
492
+ const common = { apiKey, maxResults, timeout, maxBytes };
493
+
494
+ let out;
495
+ try {
496
+ switch (provider) {
497
+ case "tavily":
498
+ out = await _searchTavily(q, common);
499
+ break;
500
+ case "brave":
501
+ out = await _searchBrave(q, common);
502
+ break;
503
+ case "bocha":
504
+ out = await _searchBocha(q, common);
505
+ break;
506
+ case "qianfan":
507
+ out = await _searchQianfan(q, {
508
+ ...common,
509
+ endpoint: options.qianfanUrl || config.qianfanUrl,
510
+ });
511
+ break;
512
+ case "searxng":
513
+ out = await _searchSearxng(q, {
514
+ instanceUrl: options.instanceUrl || config.instanceUrl,
515
+ maxResults,
516
+ timeout,
517
+ maxBytes,
518
+ });
519
+ break;
520
+ case "baidu":
521
+ out = await _searchBaidu(q, { maxResults, timeout, maxBytes });
522
+ break;
523
+ case "duckduckgo":
524
+ default:
525
+ out = await _searchDuckDuckGo(q, {
526
+ maxResults,
527
+ timeout,
528
+ maxBytes,
529
+ });
530
+ break;
531
+ }
532
+ } catch (err) {
533
+ return {
534
+ error: `web_search (${provider}) failed: ${err.message}`,
535
+ provider,
536
+ };
537
+ }
538
+
539
+ if (out && out.error) return { ...out, provider };
540
+ const results = (out && out.results) || [];
541
+ return {
542
+ query: q,
543
+ provider,
544
+ count: results.length,
545
+ results,
546
+ answer: (out && out.answer) || "",
547
+ };
548
+ } finally {
549
+ toolLease?.release();
550
+ }
485
551
  }
486
552
 
487
553
  export const _deps = { http, https };
@@ -5,6 +5,12 @@
5
5
  */
6
6
 
7
7
  import crypto from "crypto";
8
+ import runtimeClaimsContract from "@chainlesschain/session-core/runtime-claims";
9
+
10
+ const { RUNTIME_MODE, createRuntimeClaims } = runtimeClaimsContract;
11
+ const WORKFLOW_SIMULATION_CLAIMS = createRuntimeClaims({
12
+ mode: RUNTIME_MODE.SIMULATED,
13
+ });
8
14
 
9
15
  // ─── Frozen enums (Phase 82 spec) ─────────────────────────────
10
16
 
@@ -14,6 +20,7 @@ export const WORKFLOW_STATUS = Object.freeze({
14
20
  RUNNING: "running",
15
21
  PAUSED: "paused",
16
22
  COMPLETED: "completed",
23
+ SIMULATED: "simulated",
17
24
  FAILED: "failed",
18
25
  ROLLING_BACK: "rolling_back",
19
26
  ROLLED_BACK: "rolled_back",
@@ -24,6 +31,7 @@ export const NODE_STATUS = Object.freeze({
24
31
  PENDING: "pending",
25
32
  RUNNING: "running",
26
33
  COMPLETED: "completed",
34
+ SIMULATED: "simulated",
27
35
  FAILED: "failed",
28
36
  SKIPPED: "skipped",
29
37
  WAITING_APPROVAL: "waiting_approval",
@@ -228,7 +236,10 @@ export function deleteWorkflow(db, workflowId) {
228
236
  }
229
237
 
230
238
  /**
231
- * Execute a workflow, running through stages in topological order.
239
+ * Simulate a workflow by traversing stages in topological order.
240
+ *
241
+ * This legacy designer has no action executor. It must never report a
242
+ * production completion until an execution adapter is explicitly supplied.
232
243
  * @returns {{ id, workflowId, status, log }}
233
244
  */
234
245
  export function executeWorkflow(db, workflowId, input = {}) {
@@ -251,14 +262,14 @@ export function executeWorkflow(db, workflowId, input = {}) {
251
262
  // Topological sort for execution order
252
263
  const order = topologicalSort(stages);
253
264
 
254
- // Execute each stage
265
+ // Plan each stage. No action or approval handler is invoked here.
255
266
  for (const stageId of order) {
256
267
  const stage = stages.find((s) => s.id === stageId);
257
268
  log.push({
258
269
  stageId: stage.id,
259
270
  stageName: stage.name,
260
271
  type: stage.type || "action",
261
- status: "completed",
272
+ status: "simulated",
262
273
  timestamp: new Date().toISOString(),
263
274
  });
264
275
  }
@@ -271,7 +282,7 @@ export function executeWorkflow(db, workflowId, input = {}) {
271
282
  ).run(
272
283
  execId,
273
284
  workflowId,
274
- "completed",
285
+ "simulated",
275
286
  JSON.stringify(input),
276
287
  JSON.stringify(log),
277
288
  order[order.length - 1] || null,
@@ -279,7 +290,14 @@ export function executeWorkflow(db, workflowId, input = {}) {
279
290
  now,
280
291
  );
281
292
 
282
- return { id: execId, workflowId, status: "completed", log };
293
+ return {
294
+ id: execId,
295
+ workflowId,
296
+ status: "simulated",
297
+ log,
298
+ runtimeClaims: WORKFLOW_SIMULATION_CLAIMS,
299
+ terminalEvidence: [],
300
+ };
283
301
  }
284
302
 
285
303
  /**
@@ -332,7 +350,7 @@ export function pauseExecution(db, executionId) {
332
350
  if (
333
351
  exec.status !== "running" &&
334
352
  exec.status !== "pending" &&
335
- exec.status !== "completed"
353
+ exec.status !== "simulated"
336
354
  ) {
337
355
  throw new Error(`Cannot pause execution in status: ${exec.status}`);
338
356
  }
@@ -352,11 +370,15 @@ export function pauseExecution(db, executionId) {
352
370
  executionId,
353
371
  );
354
372
 
355
- return { id: executionId, status: "paused" };
373
+ return {
374
+ id: executionId,
375
+ status: "paused",
376
+ runtimeClaims: WORKFLOW_SIMULATION_CLAIMS,
377
+ };
356
378
  }
357
379
 
358
380
  /**
359
- * Resume a paused execution.
381
+ * Resume a paused simulation.
360
382
  */
361
383
  export function resumeExecution(db, executionId) {
362
384
  ensureWorkflowTables(db);
@@ -371,13 +393,13 @@ export function resumeExecution(db, executionId) {
371
393
  }
372
394
 
373
395
  db.prepare("UPDATE workflow_executions SET status = ? WHERE id = ?").run(
374
- "running",
396
+ "simulated",
375
397
  executionId,
376
398
  );
377
399
 
378
400
  const log = _safeParse(exec.log, []);
379
401
  log.push({
380
- action: "resumed",
402
+ action: "simulation-resumed",
381
403
  timestamp: new Date().toISOString(),
382
404
  });
383
405
  db.prepare("UPDATE workflow_executions SET log = ? WHERE id = ?").run(
@@ -385,7 +407,11 @@ export function resumeExecution(db, executionId) {
385
407
  executionId,
386
408
  );
387
409
 
388
- return { id: executionId, status: "running" };
410
+ return {
411
+ id: executionId,
412
+ status: "simulated",
413
+ runtimeClaims: WORKFLOW_SIMULATION_CLAIMS,
414
+ };
389
415
  }
390
416
 
391
417
  /**
@@ -439,6 +465,11 @@ export function getExecutionLog(db, executionId) {
439
465
  log: _safeParse(exec.log, []),
440
466
  startedAt: exec.started_at,
441
467
  completedAt: exec.completed_at,
468
+ runtimeClaims:
469
+ exec.status === "simulated" || exec.status === "paused"
470
+ ? WORKFLOW_SIMULATION_CLAIMS
471
+ : undefined,
472
+ terminalEvidence: [],
442
473
  };
443
474
  }
444
475