chainlesschain 0.162.197 → 0.162.200

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 (233) hide show
  1. package/bin/chainlesschain.js +14 -6
  2. package/package.json +4 -1
  3. package/scripts/command-lifecycle-report.mjs +94 -0
  4. package/src/assets/web-panel/assets/{AIOps-D3Gu1a5d.js → AIOps-DcQ0bWKy.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-DrwAoKaz.js → ActionButton-GecwfFPt.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-C7Q-gd_3.js → Analytics-CD6iSt9v.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-DgBtae-n.js → AppLayout-CDEtuEYf.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-pQ6LcA-W.js → Artifacts-DS3jAjeW.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-DK61tocB.js → Audit-CcSJA048.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-BOKgDFRh.js → BackgroundAgents-DRo9Morb.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-Bo9G4vTP.js → Backup-Vw5MrWft.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-Do_dE9_v.js → BaseInput-DNHIu823.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-COVvZzOL.js → Chat-DvAsO8-b.js} +4 -4
  14. package/src/assets/web-panel/assets/ChatBubbleRenderer-9aDuObay.js +1 -0
  15. package/src/assets/web-panel/assets/{Checkbox-Z9MJMolt.js → Checkbox-CKCa7tvn.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-BVzWKVbf.js → Codegen-CIFvZdaT.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-C8MnYcbT.js → Col-C79yz7bK.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-DQxqw15l.js → Community-DVvZskLJ.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-BAUmrh3y.js → Compact-oaew61hV.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-jPAkQ3zK.js → Compliance-DqA7wmRx.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-BBQyxbh8.js → Cowork-B-qGadxa.js} +3 -3
  22. package/src/assets/web-panel/assets/{Cron-W5koq8Z5.js → Cron-CUlCl4sS.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-BQhnu5hS.js → Crosschain-CNOlr9DU.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-DD7PlI18.js → DID-DJqFCT_3.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-w_ILuwKI.js → Dashboard-CznGpphf.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-qiDUAyAo.js → Dropdown-_cJw218E.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-PDeBcI5H.js → EmailListRenderer-Dr-1BZ9C.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-SuArscRM.js → FamilyGuardDashboard-Dxf4xtSk.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-BCovZaUn.js → Federation-DOiG3i_1.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-DjlFdVFk.js → FormItemContext-BzbMcFB9.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-DoEZ7fcS.js → GenericCardRenderer-VbBrYttP.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-CV0-6GPI.js → Git-CLG8E6ED.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-B_SFN50w.js → Governance-LGJQfk_q.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-heI0Eo6k.js → Inference-DlQKx9lF.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-Cz5INS5p.js → KnowledgeGraph-DU8vEouV.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-BSFxiHkg.js → Logs-FZIQOdln.js} +2 -2
  37. package/src/assets/web-panel/assets/MarkdownRenderer-BJNWIrbw.js +1 -0
  38. package/src/assets/web-panel/assets/{Marketplace-0TWTpE7k.js → Marketplace-C_xd-zZI.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-CV4-wBLm.js → McpTools-q-YktphS.js} +5 -5
  40. package/src/assets/web-panel/assets/{Memory-x5bH5rw5.js → Memory-Cq9OhDin.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-DaBmUu9G.js → MobileBridge-B03_R98T.js} +1 -1
  42. package/src/assets/web-panel/assets/MobileProjects-DZrk-qmF.js +1 -0
  43. package/src/assets/web-panel/assets/{Mtc-B_zKEBif.js → Mtc-BidCKW28.js} +5 -5
  44. package/src/assets/web-panel/assets/{MtcAudit-BCfKD2yg.js → MtcAudit-r-iaMVM7.js} +2 -2
  45. package/src/assets/web-panel/assets/{Multisig-DgYfj6c_.js → Multisig-CgTUFvff.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-Dz09lFUm.js → NLProgramming-B7NvzfAV.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-Cuj6ugBE.js → Notes-80CWNqJI.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-DK2WXjhg.js → NotificationSettings-0H6xdiY3.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-D1IAOQoo.js → OrderTableRenderer-CKP4AFWy.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-9fqnPvTw.js → Organization-B8sxCV_h.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-n5xHkhow.js → Overflow-CW9JBBhQ.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-B5AUWwH-.js → P2P-bdSQV7oZ.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-CoUDV6dy.js → PdhVaultBrowser-DQad42nW.js} +4 -4
  54. package/src/assets/web-panel/assets/{Permissions-DPRmQf_H.js → Permissions-CueexxTR.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-B37bsbEN.js → PersonalDataHub-fqxflhR8.js} +6 -6
  56. package/src/assets/web-panel/assets/{Pipeline-CCAuPqu9.js → Pipeline-KFwwnIMC.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-B81msZdv.js → Privacy-ClnD9buY.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-B-Py2NbF.js → ProjectInit-CZEz6sm3.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-CYsneiRB.js → ProjectSettings-B6NzpmOI.js} +2 -2
  60. package/src/assets/web-panel/assets/{Projects-Y975Mh6R.js → Projects-DYyuwPCs.js} +1 -1
  61. package/src/assets/web-panel/assets/Providers-C3tz_jdh.js +1 -0
  62. package/src/assets/web-panel/assets/{QrScannerModal-Bj_6gJ0l.js → QrScannerModal-BzuOBbqB.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-BgpBCMPE.js → QuickAsk-CmNO9qSj.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-DhUW3YUA.js → Recommend-VJNj3_NF.js} +1 -1
  65. package/src/assets/web-panel/assets/{RemoteSession-DdeyfbkA.js → RemoteSession-CrbdbSBF.js} +2 -2
  66. package/src/assets/web-panel/assets/{Reputation-fxW421xd.js → Reputation-DTyMd45j.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-De73w1og.js → Row-DHrQ-Icz.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-3US_Q_lj.js → RssFeed-DqWxY9c5.js} +2 -2
  69. package/src/assets/web-panel/assets/{Search-DbZ_DU74.js → Search-ctF1Ks3J.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-DoIU1vMF.js → Security-BrQz8uo5.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-DB_RGqpc.js → Services-D4scVFar.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-DnzLaayC.js → Skeleton-oUScaOjv.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-VzVXHENF.js → Skills-CL-y0eLt.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-DMfvjCAI.js → Sla-DQExhwXj.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-DQQOYWbF.js → SpeechSettings-iNp_I7kN.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-Bmx3FG1P.js → SyncSettings-CTDlMo0A.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-DOQyfb-2.js → Tasks-4kb8l3sc.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-D6hTRT7c.js → Templates-BXcL9oXW.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-CTPQZAzs.js → Tenant-DLE8eS0D.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-B7vII3oH.js → Terminal-DGpUZPPK.js} +2 -2
  81. package/src/assets/web-panel/assets/{TimelineRenderer-BkiFJeXV.js → TimelineRenderer-C1pWXGPC.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-BPPdQMNo.js → Tokens-BYfbfqhZ.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-BxG8JAEI.js → Trigger-K9YfLOCw.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-DHD7nMpM.js → Trust-Ctkq77Hy.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-B4BJpU47.js → UkeySign-C6_CSe9J.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-CRiGpFx2.js → VideoEditing-Be3rpOWs.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-BSDSNiem.js → Wallet-D0UIplxk.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-DLTUh5Zv.js → WebAuthn-CF9bM9I3.js} +5 -5
  89. package/src/assets/web-panel/assets/{WorkflowEditor-tW2MwjhD.js → WorkflowEditor-D0H1XVPY.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-SgsLQ3FC.js → chat-Cgzzbe0o.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-BHjjLIKO.js → colors-BwNxEVS0.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-VceErdKq.js → compact-item-D60Z4Hhs.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-BZ332MYl.js → createContext-MFk58XB0.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-BJiw369i.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-CBTjJOjn.js → hasIn-CRj2SvGO.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DaCCy6lq.js → index--s45_1cb.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-CMVvxIS8.js → index--tquQ2ZG.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BhXZEUAc.js → index-1T1rhokn.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BQSmZGgs.js → index-B-M82_rx.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BeiqkxJG.js → index-BE_el1Zs.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-29wVzi-k.js → index-BhRkR7IO.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-iYQNU9za.js → index-Bo0y96-K.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BRWhLbWF.js → index-CJgu5JUK.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BPXFLYdW.js → index-CLWwdebO.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-Cr4rjlW5.js → index-CNAK5QG_.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CaIS_TNX.js → index-CQjJjPRD.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-1n7xjKDU.js → index-CTDbAfae.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BETEjuNr.js → index-CVI_9sRK.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-By5jBtkV.js → index-CY14oMQK.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DgPvuIn2.js → index-CbiTJkZf.js} +1 -1
  111. package/src/assets/web-panel/assets/index-CiMouosn.js +1 -0
  112. package/src/assets/web-panel/assets/{index-CawpdGTW.js → index-CqWpxMqx.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-_PHrIO4O.js → index-CvB8lYUR.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BOtvPdHt.js → index-D51XwtCY.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CrUgDQkf.js → index-D6HvK_1O.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BY1wexYG.js → index-D9jVIwLJ.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C_B9rFQE.js → index-DA4tE98u.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-B5KAGxNo.js → index-DBwOtXw0.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-BC1xuQgX.js → index-DKdNzTIb.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-B2u26AS3.js → index-DRySdmvN.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DePOeMDM.js → index-DWzyTev7.js} +1 -1
  122. package/src/assets/web-panel/assets/index-DXcKlwy7.js +1 -0
  123. package/src/assets/web-panel/assets/{index-BTlc-Bve.js → index-DYjs7jAP.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CLc19alH.js → index-DbROzMBp.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-fU7wNHDB.js → index-DhFtk5PR.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D_SePDWj.js → index-Di2AbMLg.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-vIXOpcjD.js → index-DvmocQsM.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BcUenmCX.js → index-Dw-o0zEF.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DUkVN794.js → index-DysPoP38.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CtjLcCNU.js → index-LX9pJxm_.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-B40dQn0G.js → index-OI_fXWx0.js} +3 -3
  132. package/src/assets/web-panel/assets/{index-FJ3zC9LK.js → index-eDTOX8Xj.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DdefYBSw.js → index-gWKDsTzF.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-CpumS98o.js → index-q_GDUVAA.js} +1 -1
  135. package/src/assets/web-panel/assets/{initDefaultProps-D1oZNz0D.js → initDefaultProps-C61kZqEd.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-C8k6doMO.js → motion-DZnT5U1L.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-DJ4qSbYt.js → move-L8wzwbel.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-CdpJD85j.js → mtc-parser-DLdYSejc.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-B0V4slKA.js → omit-D53cbS59.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-Di5NiW1F.js → pickAttrs-Bbc5HPtu.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-B5OMHgEM.js → placementArrow-BkvmO860.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-C6U9IWql.js → responsiveObserve-u2y1ryS1.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-BMyTH3rN.js → slide-BBqj7svU.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-C7d6BG7Z.js → statusUtils-GN0mqu2d.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-CR50QnQy.js → styleChecker-BvwPKoBT.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-DBEeoMb8.js → useFlexGapSupport-CCt8tnfY.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-3r099cjv.js → useFs-DXAxl2SV.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-C5IYNdTK.js → usePersonalDataHub-DihlR2dj.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-DmEOLRHf.js → vnode-D7BOX2gi.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-DnpUiVCB.js → zoom-CVbO-nL7.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/command-help-index.json +4 -4
  153. package/src/commands/agent.js +3 -3
  154. package/src/commands/background-session.js +145 -0
  155. package/src/commands/mcp.js +244 -7
  156. package/src/commands/serve.js +1 -1
  157. package/src/commands/session-show.js +129 -0
  158. package/src/commands/session.js +97 -145
  159. package/src/commands/skill.js +87 -50
  160. package/src/data/changelog.json +40 -1
  161. package/src/gateways/ws/session-protocol.js +14 -4
  162. package/src/gateways/ws/ws-agent-handler.js +39 -1
  163. package/src/harness/jsonl-session-store.js +1547 -127
  164. package/src/harness/mcp-client.js +2690 -409
  165. package/src/harness/session-index.js +80 -80
  166. package/src/harness/session-list-index.js +210 -7
  167. package/src/lazy-dispatch.js +76 -8
  168. package/src/lib/abort-utils.js +68 -0
  169. package/src/lib/agent-core.js +1 -59
  170. package/src/lib/background-interaction-journal.js +2 -2
  171. package/src/lib/chat-core.js +24 -6
  172. package/src/lib/command-lifecycle-report.js +516 -0
  173. package/src/lib/cowork-mcp-tools.js +47 -2
  174. package/src/lib/cowork-task-runner.js +11 -3
  175. package/src/lib/doctor-checkup.js +9 -7
  176. package/src/lib/learning/skill-improver.js +21 -2
  177. package/src/lib/mcp-call-ledger-store.js +116 -3
  178. package/src/lib/mcp-call-ledger.js +59 -14
  179. package/src/lib/mcp-client.js +1 -0
  180. package/src/lib/mcp-stdio-environment.js +48 -0
  181. package/src/lib/mcp-stdio-executable-identity.js +1133 -0
  182. package/src/lib/mcp-stdio-execution-authority.js +363 -0
  183. package/src/lib/mcp-stdio-package-materialization.js +1424 -0
  184. package/src/lib/mcp-tool-metadata.js +436 -0
  185. package/src/lib/mcp-tool-result.js +367 -0
  186. package/src/lib/observability/index.js +71 -0
  187. package/src/lib/packer/native-update-state.js +979 -1
  188. package/src/lib/packer/pack-update-applier.js +1050 -125
  189. package/src/lib/packer/pkg-config-generator.js +1 -0
  190. package/src/lib/paths.js +53 -0
  191. package/src/lib/pr-link-ledger.js +8 -27
  192. package/src/lib/pr-link-store.js +26 -0
  193. package/src/lib/process-execution-broker/index.js +192 -35
  194. package/src/lib/process-execution-broker/platform-sandbox.js +291 -24
  195. package/src/lib/process-tree-termination.js +253 -0
  196. package/src/lib/recent-session.js +17 -17
  197. package/src/lib/secure-file-identity.js +47 -0
  198. package/src/lib/secure-fs.js +21 -2
  199. package/src/lib/session-anti-rollback-anchor.js +766 -0
  200. package/src/lib/session-host-lease.js +492 -0
  201. package/src/lib/session-host-snapshot.js +9 -5
  202. package/src/lib/session-persistence-failure.js +109 -0
  203. package/src/lib/session-picker.js +26 -3
  204. package/src/lib/session-projection.js +5 -1
  205. package/src/lib/session-search.js +25 -11
  206. package/src/lib/session-tail.js +31 -1
  207. package/src/lib/side-effect-ledger-store.js +2 -2
  208. package/src/lib/skill-budget.js +222 -0
  209. package/src/lib/skill-execution-authority.js +385 -0
  210. package/src/lib/skill-execution-identity.js +39 -2
  211. package/src/lib/skill-loader.js +322 -86
  212. package/src/lib/skill-mcp.js +43 -1
  213. package/src/lib/turn-binding-store.js +2 -2
  214. package/src/repl/agent-repl.js +483 -77
  215. package/src/repl/bg-dashboard.js +81 -28
  216. package/src/repl/chat-repl.js +77 -12
  217. package/src/runtime/agent-core.js +428 -113
  218. package/src/runtime/agent-runtime.js +26 -3
  219. package/src/runtime/cleanup-deadline.js +143 -0
  220. package/src/runtime/headless-runner.js +494 -149
  221. package/src/runtime/headless-stream.js +504 -75
  222. package/src/runtime/mcp-config.js +157 -10
  223. package/src/runtime/mcp-tool-search.js +0 -0
  224. package/src/runtime/output-backpressure.js +419 -0
  225. package/src/runtime/pipe-safety.js +56 -21
  226. package/src/assets/web-panel/assets/ChatBubbleRenderer-BUUyJ5QO.js +0 -1
  227. package/src/assets/web-panel/assets/MarkdownRenderer-1mNozZ8v.js +0 -1
  228. package/src/assets/web-panel/assets/MobileProjects-DqnoFPgR.js +0 -1
  229. package/src/assets/web-panel/assets/Providers-uO-10aP1.js +0 -1
  230. package/src/assets/web-panel/assets/devWarning-DosMaL-k.js +0 -1
  231. package/src/assets/web-panel/assets/index-0O5ePnUq.js +0 -1
  232. package/src/assets/web-panel/assets/index-ChAzPigF.js +0 -1
  233. package/src/lib/skill-process-broker.js +0 -85
@@ -0,0 +1,516 @@
1
+ /**
2
+ * Privacy-preserving command lifecycle telemetry aggregation.
3
+ *
4
+ * The runtime emits one content-free OTLP metric for each migrated command
5
+ * invocation. This module consumes those OTLP payloads and combines them with
6
+ * an explicit collector coverage statement. Alias removal is fail-closed:
7
+ * missing release cycles, weak coverage, undocumented sampling bias or invalid
8
+ * metric points can only produce `insufficient-data`.
9
+ */
10
+
11
+ export const COMMAND_LIFECYCLE_REPORT_SCHEMA =
12
+ "chainlesschain.command-lifecycle-report.v1";
13
+ export const COMMAND_LIFECYCLE_COVERAGE_SCHEMA =
14
+ "chainlesschain.command-lifecycle-coverage.v1";
15
+ export const COMMAND_LIFECYCLE_INVOCATION_METRIC =
16
+ "chainlesschain.cli.command.lifecycle.invocations";
17
+
18
+ export const COMMAND_ALIAS_DECISION_POLICY = Object.freeze({
19
+ minimumObservedMinorCycles: 2,
20
+ minimumEligibleInstallations: 50,
21
+ minimumReportingInstallations: 30,
22
+ minimumCollectorCoverageRatio: 0.5,
23
+ minimumSampleRate: 0.1,
24
+ minimumCommandInvocations: 200,
25
+ minimumReplacementInvocations: 100,
26
+ maximumLegacyShareForRemoval: 0.01,
27
+ requiredPlatforms: Object.freeze(["linux", "macos", "windows"]),
28
+ });
29
+
30
+ const REQUIRED_ATTRIBUTES = Object.freeze([
31
+ "command.name",
32
+ "command.route",
33
+ "command.outcome",
34
+ "cli.version",
35
+ "command.deprecated_since",
36
+ "command.removal_not_before",
37
+ ]);
38
+ const ALLOWED_ATTRIBUTES = new Set(REQUIRED_ATTRIBUTES);
39
+ const EXACT_RELEASE = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/;
40
+ const COMMAND_NAME = /^[a-z0-9][a-z0-9-]{0,63}$/;
41
+
42
+ function parseRelease(value) {
43
+ if (typeof value !== "string") return null;
44
+ const match = EXACT_RELEASE.exec(value);
45
+ if (!match) return null;
46
+ return {
47
+ value,
48
+ major: Number(match[1]),
49
+ minor: Number(match[2]),
50
+ patch: Number(match[3]),
51
+ prerelease: match[4] || null,
52
+ };
53
+ }
54
+
55
+ function compareReleases(left, right) {
56
+ const a = typeof left === "string" ? parseRelease(left) : left;
57
+ const b = typeof right === "string" ? parseRelease(right) : right;
58
+ if (!a || !b) return null;
59
+ for (const key of ["major", "minor", "patch"]) {
60
+ if (a[key] !== b[key]) return a[key] < b[key] ? -1 : 1;
61
+ }
62
+ if (a.prerelease === b.prerelease) return 0;
63
+ if (a.prerelease === null) return 1;
64
+ if (b.prerelease === null) return -1;
65
+ return a.prerelease.localeCompare(b.prerelease);
66
+ }
67
+
68
+ function otlpValue(value) {
69
+ if (!value || typeof value !== "object") return undefined;
70
+ for (const key of ["stringValue", "intValue", "doubleValue", "boolValue"]) {
71
+ if (Object.hasOwn(value, key)) return value[key];
72
+ }
73
+ return undefined;
74
+ }
75
+
76
+ function attributesFor(point) {
77
+ if (!Array.isArray(point?.attributes)) return null;
78
+ const attributes = {};
79
+ for (const item of point.attributes) {
80
+ if (
81
+ !item ||
82
+ typeof item.key !== "string" ||
83
+ !ALLOWED_ATTRIBUTES.has(item.key) ||
84
+ Object.hasOwn(attributes, item.key)
85
+ ) {
86
+ return null;
87
+ }
88
+ attributes[item.key] = otlpValue(item.value);
89
+ }
90
+ return attributes;
91
+ }
92
+
93
+ function pointCount(point) {
94
+ const raw = Object.hasOwn(point || {}, "asInt")
95
+ ? point.asInt
96
+ : point?.asDouble;
97
+ const value = Number(raw);
98
+ return Number.isSafeInteger(value) && value > 0 ? value : null;
99
+ }
100
+
101
+ function metricPayloads(document) {
102
+ if (Array.isArray(document)) {
103
+ return document.flatMap((entry) => metricPayloads(entry));
104
+ }
105
+ if (!document || typeof document !== "object") return [];
106
+ if (document.body) return metricPayloads(document.body);
107
+ if (Array.isArray(document.requests)) {
108
+ return metricPayloads(document.requests);
109
+ }
110
+ return Array.isArray(document.resourceMetrics) ? [document] : [];
111
+ }
112
+
113
+ function lifecycleEntries(manifest) {
114
+ return (manifest?.commands || [])
115
+ .filter(
116
+ (entry) =>
117
+ entry?.lifecycle?.state === "deprecated" &&
118
+ typeof entry.replacement === "string",
119
+ )
120
+ .sort((left, right) => left.name.localeCompare(right.name));
121
+ }
122
+
123
+ function blankCommand(entry) {
124
+ return {
125
+ command: entry.name,
126
+ replacement: entry.replacement,
127
+ deprecatedSince: entry.lifecycle.deprecatedSince,
128
+ removalNotBefore: entry.lifecycle.removalNotBefore,
129
+ minimumReleaseCycles: entry.lifecycle.minimumReleaseCycles,
130
+ legacy: { invocations: 0, completed: 0, error: 0 },
131
+ replacementRoute: { invocations: 0, completed: 0, error: 0 },
132
+ versions: new Set(),
133
+ };
134
+ }
135
+
136
+ function validateCoverage(coverage, policy) {
137
+ const blockers = [];
138
+ if (coverage?.schema !== COMMAND_LIFECYCLE_COVERAGE_SCHEMA) {
139
+ blockers.push("coverage-schema-invalid");
140
+ }
141
+
142
+ const decisionVersion = parseRelease(coverage?.decisionVersion);
143
+ if (!decisionVersion) blockers.push("decision-version-invalid");
144
+
145
+ const observedReleases = Array.isArray(coverage?.observedReleases)
146
+ ? coverage.observedReleases.map(parseRelease)
147
+ : [];
148
+ if (
149
+ observedReleases.length === 0 ||
150
+ observedReleases.some((release) => !release)
151
+ ) {
152
+ blockers.push("observed-releases-invalid");
153
+ }
154
+ const observedMinorCycles = new Set(
155
+ observedReleases
156
+ .filter(Boolean)
157
+ .map((release) => `${release.major}.${release.minor}`),
158
+ );
159
+ if (observedMinorCycles.size < policy.minimumObservedMinorCycles) {
160
+ blockers.push("release-observation-window-incomplete");
161
+ }
162
+
163
+ const startMs = Date.parse(coverage?.window?.startedAt || "");
164
+ const endMs = Date.parse(coverage?.window?.endedAt || "");
165
+ if (
166
+ !Number.isFinite(startMs) ||
167
+ !Number.isFinite(endMs) ||
168
+ endMs <= startMs
169
+ ) {
170
+ blockers.push("observation-window-invalid");
171
+ }
172
+
173
+ const collector = coverage?.collector || {};
174
+ const eligibleInstallations = Number(collector.eligibleInstallations);
175
+ const reportingInstallations = Number(collector.reportingInstallations);
176
+ const sampleRate = Number(collector.sampleRate);
177
+ const coverageRatio =
178
+ Number.isFinite(eligibleInstallations) && eligibleInstallations > 0
179
+ ? reportingInstallations / eligibleInstallations
180
+ : 0;
181
+ if (
182
+ !Number.isSafeInteger(eligibleInstallations) ||
183
+ eligibleInstallations < policy.minimumEligibleInstallations
184
+ ) {
185
+ blockers.push("eligible-installation-cohort-too-small");
186
+ }
187
+ if (
188
+ !Number.isSafeInteger(reportingInstallations) ||
189
+ reportingInstallations < policy.minimumReportingInstallations ||
190
+ reportingInstallations > eligibleInstallations
191
+ ) {
192
+ blockers.push("reporting-installation-cohort-too-small");
193
+ }
194
+ if (coverageRatio < policy.minimumCollectorCoverageRatio) {
195
+ blockers.push("collector-coverage-too-low");
196
+ }
197
+ if (
198
+ !Number.isFinite(sampleRate) ||
199
+ sampleRate < policy.minimumSampleRate ||
200
+ sampleRate > 1
201
+ ) {
202
+ blockers.push("sample-rate-too-low-or-invalid");
203
+ }
204
+
205
+ const platforms = collector.platforms || {};
206
+ for (const platform of policy.requiredPlatforms) {
207
+ if (
208
+ !Number.isSafeInteger(platforms[platform]) ||
209
+ platforms[platform] <= 0
210
+ ) {
211
+ blockers.push(`platform-coverage-missing:${platform}`);
212
+ }
213
+ }
214
+
215
+ const knownBiases = Array.isArray(collector.knownBiases)
216
+ ? collector.knownBiases
217
+ : [];
218
+ if (knownBiases.length === 0) {
219
+ blockers.push("collector-bias-not-documented");
220
+ }
221
+ for (const bias of knownBiases) {
222
+ if (
223
+ !bias ||
224
+ typeof bias.id !== "string" ||
225
+ typeof bias.description !== "string"
226
+ ) {
227
+ blockers.push("collector-bias-entry-invalid");
228
+ continue;
229
+ }
230
+ if (bias.blocking === true) {
231
+ blockers.push(`collector-bias-blocking:${bias.id}`);
232
+ }
233
+ }
234
+
235
+ return {
236
+ ready: blockers.length === 0,
237
+ blockers: [...new Set(blockers)].sort(),
238
+ decisionVersion: decisionVersion?.value || null,
239
+ observedReleases: observedReleases
240
+ .filter(Boolean)
241
+ .map((release) => release.value),
242
+ observedMinorCycles: [...observedMinorCycles].sort(),
243
+ window: {
244
+ startedAt: Number.isFinite(startMs)
245
+ ? new Date(startMs).toISOString()
246
+ : null,
247
+ endedAt: Number.isFinite(endMs) ? new Date(endMs).toISOString() : null,
248
+ },
249
+ collector: {
250
+ eligibleInstallations:
251
+ Number.isSafeInteger(eligibleInstallations) &&
252
+ eligibleInstallations >= 0
253
+ ? eligibleInstallations
254
+ : null,
255
+ reportingInstallations:
256
+ Number.isSafeInteger(reportingInstallations) &&
257
+ reportingInstallations >= 0
258
+ ? reportingInstallations
259
+ : null,
260
+ coverageRatio,
261
+ sampleRate: Number.isFinite(sampleRate) ? sampleRate : null,
262
+ platforms: Object.fromEntries(
263
+ policy.requiredPlatforms.map((platform) => [
264
+ platform,
265
+ Number.isSafeInteger(platforms[platform]) && platforms[platform] >= 0
266
+ ? platforms[platform]
267
+ : 0,
268
+ ]),
269
+ ),
270
+ knownBiases: knownBiases
271
+ .filter(
272
+ (bias) =>
273
+ bias &&
274
+ typeof bias.id === "string" &&
275
+ typeof bias.description === "string",
276
+ )
277
+ .map((bias) => ({
278
+ id: bias.id,
279
+ description: bias.description,
280
+ blocking: bias.blocking === true,
281
+ })),
282
+ },
283
+ };
284
+ }
285
+
286
+ function decisionFor(command, coverage, ingestionReady, policy) {
287
+ const total =
288
+ command.legacy.invocations + command.replacementRoute.invocations;
289
+ const legacyShare = total > 0 ? command.legacy.invocations / total : null;
290
+ const reasons = [];
291
+ const removalComparison = compareReleases(
292
+ coverage.decisionVersion,
293
+ command.removalNotBefore,
294
+ );
295
+ if (!coverage.ready) reasons.push(...coverage.blockers);
296
+ if (!ingestionReady) reasons.push("telemetry-input-invalid");
297
+ if (removalComparison === null || removalComparison < 0) {
298
+ reasons.push("removal-version-not-reached");
299
+ }
300
+
301
+ const observedForCommand = coverage.observedReleases.filter((version) => {
302
+ const afterDeprecation = compareReleases(version, command.deprecatedSince);
303
+ const beforeDecision = compareReleases(version, coverage.decisionVersion);
304
+ return (
305
+ afterDeprecation !== null && afterDeprecation >= 0 && beforeDecision <= 0
306
+ );
307
+ });
308
+ const observedCycles = new Set(
309
+ observedForCommand.map((version) => {
310
+ const parsed = parseRelease(version);
311
+ return `${parsed.major}.${parsed.minor}`;
312
+ }),
313
+ );
314
+ if (observedCycles.size < command.minimumReleaseCycles) {
315
+ reasons.push("command-release-window-incomplete");
316
+ }
317
+ if (total < policy.minimumCommandInvocations) {
318
+ reasons.push("command-sample-too-small");
319
+ }
320
+
321
+ if (reasons.length > 0) {
322
+ return {
323
+ decision: "insufficient-data",
324
+ reasons: [...new Set(reasons)].sort(),
325
+ totalInvocations: total,
326
+ legacyShare,
327
+ observedMinorCycles: [...observedCycles].sort(),
328
+ };
329
+ }
330
+
331
+ if (legacyShare > policy.maximumLegacyShareForRemoval) {
332
+ return {
333
+ decision: "retain",
334
+ reasons: ["legacy-usage-above-removal-threshold"],
335
+ totalInvocations: total,
336
+ legacyShare,
337
+ observedMinorCycles: [...observedCycles].sort(),
338
+ };
339
+ }
340
+ if (
341
+ command.replacementRoute.invocations < policy.minimumReplacementInvocations
342
+ ) {
343
+ return {
344
+ decision: "insufficient-data",
345
+ reasons: ["replacement-sample-too-small"],
346
+ totalInvocations: total,
347
+ legacyShare,
348
+ observedMinorCycles: [...observedCycles].sort(),
349
+ };
350
+ }
351
+ return {
352
+ decision: "remove",
353
+ reasons: ["compatibility-window-and-usage-thresholds-satisfied"],
354
+ totalInvocations: total,
355
+ legacyShare,
356
+ observedMinorCycles: [...observedCycles].sort(),
357
+ };
358
+ }
359
+
360
+ export function buildCommandLifecycleReport({
361
+ documents = [],
362
+ manifest,
363
+ coverage,
364
+ generatedAt = new Date().toISOString(),
365
+ policy = COMMAND_ALIAS_DECISION_POLICY,
366
+ } = {}) {
367
+ const entries = lifecycleEntries(manifest);
368
+ if (entries.length === 0) {
369
+ throw new Error("command manifest has no deprecated compatibility entries");
370
+ }
371
+ const byCommand = new Map(
372
+ entries.map((entry) => [entry.name, blankCommand(entry)]),
373
+ );
374
+ const violations = [];
375
+ let acceptedPoints = 0;
376
+ let rejectedPoints = 0;
377
+ let payloadCount = 0;
378
+
379
+ for (const payload of metricPayloads(documents)) {
380
+ payloadCount += 1;
381
+ for (const resource of payload.resourceMetrics || []) {
382
+ for (const scope of resource.scopeMetrics || []) {
383
+ for (const metric of scope.metrics || []) {
384
+ if (metric?.name !== COMMAND_LIFECYCLE_INVOCATION_METRIC) continue;
385
+ for (const point of metric?.sum?.dataPoints || []) {
386
+ const attributes = attributesFor(point);
387
+ const count = pointCount(point);
388
+ const command = attributes
389
+ ? byCommand.get(attributes["command.name"])
390
+ : null;
391
+ const valid =
392
+ attributes &&
393
+ REQUIRED_ATTRIBUTES.every((key) =>
394
+ Object.hasOwn(attributes, key),
395
+ ) &&
396
+ Object.keys(attributes).length === REQUIRED_ATTRIBUTES.length &&
397
+ count !== null &&
398
+ command &&
399
+ COMMAND_NAME.test(attributes["command.name"]) &&
400
+ ["legacy", "replacement"].includes(attributes["command.route"]) &&
401
+ ["completed", "error"].includes(attributes["command.outcome"]) &&
402
+ parseRelease(attributes["cli.version"]) &&
403
+ attributes["command.deprecated_since"] ===
404
+ command?.deprecatedSince &&
405
+ attributes["command.removal_not_before"] ===
406
+ command?.removalNotBefore;
407
+ if (!valid) {
408
+ rejectedPoints += 1;
409
+ violations.push("invalid-lifecycle-metric-point");
410
+ continue;
411
+ }
412
+
413
+ acceptedPoints += 1;
414
+ const bucket =
415
+ attributes["command.route"] === "legacy"
416
+ ? command.legacy
417
+ : command.replacementRoute;
418
+ bucket.invocations += count;
419
+ bucket[attributes["command.outcome"]] += count;
420
+ command.versions.add(attributes["cli.version"]);
421
+ }
422
+ }
423
+ }
424
+ }
425
+ }
426
+
427
+ const coverageResult = validateCoverage(coverage, policy);
428
+ const ingestionReady = rejectedPoints === 0 && acceptedPoints > 0;
429
+ if (acceptedPoints === 0) violations.push("no-lifecycle-metric-points");
430
+
431
+ const decisions = [...byCommand.values()].map((command) => {
432
+ const recommendation = decisionFor(
433
+ command,
434
+ coverageResult,
435
+ ingestionReady,
436
+ policy,
437
+ );
438
+ return {
439
+ command: command.command,
440
+ replacement: command.replacement,
441
+ deprecatedSince: command.deprecatedSince,
442
+ removalNotBefore: command.removalNotBefore,
443
+ legacy: command.legacy,
444
+ replacementRoute: command.replacementRoute,
445
+ observedVersions: [...command.versions].sort((left, right) =>
446
+ compareReleases(left, right),
447
+ ),
448
+ ...recommendation,
449
+ };
450
+ });
451
+ const summary = decisions.reduce(
452
+ (result, item) => {
453
+ result[item.decision] += 1;
454
+ return result;
455
+ },
456
+ { retain: 0, remove: 0, "insufficient-data": 0 },
457
+ );
458
+
459
+ return {
460
+ schema: COMMAND_LIFECYCLE_REPORT_SCHEMA,
461
+ generatedAt: new Date(generatedAt).toISOString(),
462
+ manifestSchema: manifest?.schema || null,
463
+ policy: {
464
+ ...policy,
465
+ requiredPlatforms: [...policy.requiredPlatforms],
466
+ },
467
+ coverage: coverageResult,
468
+ ingestion: {
469
+ payloadCount,
470
+ acceptedPoints,
471
+ rejectedPoints,
472
+ ready: ingestionReady,
473
+ violations: [...new Set(violations)].sort(),
474
+ },
475
+ summary,
476
+ decisions,
477
+ };
478
+ }
479
+
480
+ export function renderCommandLifecycleReportMarkdown(report) {
481
+ const lines = [
482
+ "# CLI command lifecycle decision report",
483
+ "",
484
+ `Generated: ${report.generatedAt}`,
485
+ "",
486
+ `Coverage ready: **${report.coverage.ready ? "yes" : "no"}**`,
487
+ `Telemetry input ready: **${report.ingestion.ready ? "yes" : "no"}**`,
488
+ `Decisions: ${report.summary.remove} remove, ${report.summary.retain} retain, ${report.summary["insufficient-data"]} insufficient-data.`,
489
+ "",
490
+ ];
491
+ if (report.coverage.blockers.length > 0) {
492
+ lines.push(
493
+ "Coverage blockers: " +
494
+ report.coverage.blockers.map((item) => `\`${item}\``).join(", "),
495
+ "",
496
+ );
497
+ }
498
+ if (report.ingestion.violations.length > 0) {
499
+ lines.push(
500
+ "Input violations: " +
501
+ report.ingestion.violations.map((item) => `\`${item}\``).join(", "),
502
+ "",
503
+ );
504
+ }
505
+ lines.push(
506
+ "| Legacy entry | Replacement | Legacy | Replacement | Legacy share | Decision | Reasons |",
507
+ "| --- | --- | ---: | ---: | ---: | --- | --- |",
508
+ );
509
+ for (const item of report.decisions) {
510
+ lines.push(
511
+ `| \`${item.command}\` | \`${item.replacement}\` | ${item.legacy.invocations} | ${item.replacementRoute.invocations} | ${item.legacyShare === null ? "n/a" : `${(item.legacyShare * 100).toFixed(2)}%`} | **${item.decision}** | ${item.reasons.join(", ")} |`,
512
+ );
513
+ }
514
+ lines.push("");
515
+ return lines.join("\n");
516
+ }
@@ -21,6 +21,10 @@
21
21
  */
22
22
  import { validateMcpServerConfig } from "./skill-mcp.js";
23
23
  import { mcpEffectDescriptorFields } from "./mcp-effect-contract.js";
24
+ import {
25
+ MCP_STDIO_LOCAL_CODE_TRUST_REQUIRED_CODE,
26
+ issueMcpStdioExecutionAuthority,
27
+ } from "./mcp-stdio-execution-authority.js";
24
28
 
25
29
  export const _deps = {
26
30
  importMcpClient: async () => {
@@ -90,6 +94,7 @@ export function toAgentTool(serverName, tool) {
90
94
  * @param {{ mcpServers?: Array<object> }} template
91
95
  * @param {object} [opts]
92
96
  * @param {(msg: string, err?: Error) => void} [opts.onWarn]
97
+ * @param {(request: object) => boolean|Promise<boolean>} [opts.approveLocalCodeExecution]
93
98
  * @returns {Promise<{
94
99
  * mcpClient: object|null,
95
100
  * mounted: string[],
@@ -121,15 +126,55 @@ export async function mountTemplateMcpTools(template, opts = {}) {
121
126
  .filter(Boolean);
122
127
  if (validated.length === 0) return empty;
123
128
 
129
+ const skipped = [];
130
+ const authorized = [];
131
+ for (const server of validated) {
132
+ let approved = false;
133
+ try {
134
+ approved =
135
+ typeof opts.approveLocalCodeExecution === "function" &&
136
+ (await opts.approveLocalCodeExecution({
137
+ templateId: template?.id || null,
138
+ serverName: server.name,
139
+ command: server.command,
140
+ args: [...server.args],
141
+ cwd: server.cwd || null,
142
+ envKeys: Object.keys(server.env || {}).sort(),
143
+ })) === true;
144
+ } catch (error) {
145
+ const message = error?.message || String(error);
146
+ skipped.push({ name: server.name, error: message });
147
+ opts.onWarn?.(
148
+ `[cowork-mcp] Local-code approval failed for "${server.name}": ${message}`,
149
+ error,
150
+ );
151
+ continue;
152
+ }
153
+ if (!approved) {
154
+ const message = `${MCP_STDIO_LOCAL_CODE_TRUST_REQUIRED_CODE}: template MCP server requires explicit local-code approval`;
155
+ skipped.push({ name: server.name, error: message });
156
+ opts.onWarn?.(`[cowork-mcp] Skipped "${server.name}": ${message}`);
157
+ continue;
158
+ }
159
+ const config = { ...server };
160
+ config.mcpStdioExecutionAuthority = issueMcpStdioExecutionAuthority({
161
+ serverName: server.name,
162
+ config,
163
+ approvalKind: "explicit-config",
164
+ approvalSource: `cowork-template:${template?.id || "unknown"}:${server.name}`,
165
+ });
166
+ authorized.push(config);
167
+ }
168
+ if (authorized.length === 0) return { ...empty, skipped };
169
+
124
170
  const MCPClient = await _deps.importMcpClient();
125
171
  const mcpClient = new MCPClient();
126
172
  const mounted = [];
127
- const skipped = [];
128
173
  const extraToolDefinitions = [];
129
174
  const externalToolDescriptors = {};
130
175
  const externalToolExecutors = {};
131
176
 
132
- for (const server of validated) {
177
+ for (const server of authorized) {
133
178
  try {
134
179
  await mcpClient.connect(server.name, server);
135
180
  mounted.push(server.name);
@@ -313,6 +313,7 @@ export function prepareCoworkMcpRuntime(mcp, options = {}) {
313
313
  }
314
314
  let recoveryNotice = null;
315
315
  let recoveryState = null;
316
+ let recoveryAuthority = null;
316
317
  let bindingAllowed = false;
317
318
  let expectedHeadHash = null;
318
319
  try {
@@ -321,6 +322,7 @@ export function prepareCoworkMcpRuntime(mcp, options = {}) {
321
322
  String(options.templateId || "free"),
322
323
  );
323
324
  const recovery = projected.recovery;
325
+ recoveryAuthority = recovery;
324
326
  expectedHeadHash = projected.expectedHeadHash;
325
327
  bindingAllowed = projected.bindingAllowed;
326
328
  recoveryNotice = formatMcpLedgerRecoveryNotice(recovery);
@@ -361,9 +363,12 @@ export function prepareCoworkMcpRuntime(mcp, options = {}) {
361
363
  }
362
364
  }
363
365
 
364
- const sink = createSessionMcpLedgerSink(sessionId, {
365
- appendEvent: _deps.appendSessionEvent,
366
- });
366
+ const sink = createSessionMcpLedgerSink(
367
+ sessionId,
368
+ _deps.appendSessionEvent === appendSessionEvent
369
+ ? { recovery: recoveryAuthority }
370
+ : { appendEvent: _deps.appendSessionEvent },
371
+ );
367
372
  const recoveryController =
368
373
  createMcpRecoveryAdmissionController(recoveryState);
369
374
  return {
@@ -395,6 +400,7 @@ export function prepareCoworkMcpRuntime(mcp, options = {}) {
395
400
  * @param {number} [options.maxIterations] - Override iteration limit
396
401
  * @param {number} [options.tokenBudget] - Override token budget
397
402
  * @param {string} [options.mcpSessionId] - Stable MCP ledger session for resume
403
+ * @param {(request: object) => boolean|Promise<boolean>} [options.approveMcpLocalCodeExecution]
398
404
  * @returns {Promise<{ taskId: string, status: string, result: object }>}
399
405
  */
400
406
  export async function runCoworkTask(options = {}) {
@@ -410,6 +416,7 @@ export async function runCoworkTask(options = {}) {
410
416
  onProgress = null,
411
417
  signal = null,
412
418
  mcpSessionId = null,
419
+ approveMcpLocalCodeExecution = null,
413
420
  } = options;
414
421
 
415
422
  if (!userMessage || typeof userMessage !== "string") {
@@ -458,6 +465,7 @@ export async function runCoworkTask(options = {}) {
458
465
 
459
466
  // Mount template-declared MCP servers (best-effort, failures are tolerated)
460
467
  const mcp = await mountTemplateMcpTools(template, {
468
+ approveLocalCodeExecution: approveMcpLocalCodeExecution,
461
469
  onWarn: (msg) => {
462
470
  if (onProgress) onProgress({ type: "mcp-warning", message: msg });
463
471
  },
@@ -604,22 +604,24 @@ async function transcriptSection(_opts, _deps2) {
604
604
  const { verifyAllSessions } =
605
605
  await import("../harness/jsonl-session-store.js");
606
606
  const results = verifyAllSessions({ limit: 200 });
607
- const tampered = results.filter((r) => r.status === "tampered");
608
- if (tampered.length > 0) {
607
+ const integrityFailures = results.filter((result) =>
608
+ ["tampered", "missing", "conflict"].includes(result.status),
609
+ );
610
+ if (integrityFailures.length > 0) {
609
611
  checks.push(
610
612
  check(
611
613
  "transcript-tamper",
612
614
  "Transcript integrity",
613
615
  CHECK_LEVELS.ERR,
614
- `${tampered.length} tampered transcript(s): ${tampered
616
+ `${integrityFailures.length} transcript integrity failure(s): ${integrityFailures
615
617
  .slice(0, 5)
616
- .map((t) => t.sessionId)
617
- .join(", ")}${tampered.length > 5 ? ", …" : ""}`,
618
+ .map((result) => `${result.sessionId} [${result.status}]`)
619
+ .join(", ")}${integrityFailures.length > 5 ? ", …" : ""}`,
618
620
  {
619
621
  id: "transcript-tamper",
620
622
  safe: false,
621
623
  description: "Inspect the flagged transcripts",
622
- command: `cc session verify ${tampered[0].sessionId}`,
624
+ command: `cc session verify ${integrityFailures[0].sessionId}`,
623
625
  },
624
626
  ),
625
627
  );
@@ -629,7 +631,7 @@ async function transcriptSection(_opts, _deps2) {
629
631
  "transcript-tamper",
630
632
  "Transcript integrity",
631
633
  CHECK_LEVELS.OK,
632
- `${results.length} session(s) checked, no tamper`,
634
+ `${results.length} session(s) checked, no integrity failures`,
633
635
  ),
634
636
  );
635
637
  }