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
@@ -36,6 +36,11 @@ import {
36
36
  } from "../lib/lsp/workspace-roots.js";
37
37
  import { getPlanModeManager } from "../lib/plan-mode.js";
38
38
  import { CLISkillLoader } from "../lib/skill-loader.js";
39
+ import {
40
+ admitSkillPrompt,
41
+ debitSkillPromptBudget,
42
+ resolveSkillLimits,
43
+ } from "../lib/skill-budget.js";
39
44
  import { executeHooks, HookEvents } from "../lib/hook-manager.js";
40
45
  import { detectPython } from "../lib/cli-anything-bridge.js";
41
46
  import { findProjectRoot, loadProjectConfig } from "../lib/project-detector.js";
@@ -52,7 +57,11 @@ import {
52
57
  } from "./coding-agent-contract.js";
53
58
  import { createToolContext } from "../tools/tool-context.js";
54
59
  import { createToolTelemetryRecord } from "../tools/tool-telemetry.js";
55
- import { isAbortError, throwIfAborted } from "../lib/abort-utils.js";
60
+ import {
61
+ isAbortError,
62
+ raceWithAbort,
63
+ throwIfAborted,
64
+ } from "../lib/abort-utils.js";
56
65
  import {
57
66
  classifyEditReplay,
58
67
  editIdempotencyKey,
@@ -100,6 +109,10 @@ import {
100
109
  McpEffect,
101
110
  snapshotMcpJsonRpcInput,
102
111
  } from "../lib/mcp-call-ledger.js";
112
+ import {
113
+ admitMcpToolResult,
114
+ isMcpToolResultAdmissionError,
115
+ } from "../lib/mcp-tool-result.js";
103
116
  import {
104
117
  MCP_OUTCOME_UNKNOWN_CODE,
105
118
  markMcpLedgerOutcomeUnknown,
@@ -112,6 +125,7 @@ import {
112
125
  buildExtractiveHandoff,
113
126
  formatStructuredHandoff,
114
127
  } from "../harness/structured-handoff.js";
128
+ import { isMcpRpcError } from "../harness/mcp-client.js";
115
129
  import { projectCanonicalResumeMessages } from "../lib/session-message-provenance.js";
116
130
 
117
131
  export { formatProviderHttpError };
@@ -968,11 +982,16 @@ export function getAgentToolDescriptors(options = {}) {
968
982
  const _defaultSkillLoader = new CLISkillLoader();
969
983
 
970
984
  /**
971
- * Re-scan all skill layers (Claude-Code `/reload-skills` parity): drops the
972
- * default loader's cache so newly added/edited SKILL.md dirs are picked up
973
- * without restarting the session. Returns the resolved skill count.
985
+ * Re-scan all skill layers (Claude-Code `/reload-skills` parity): revokes this
986
+ * process's Skill execution generation, then drops the default loader cache so
987
+ * newly added/edited SKILL.md dirs are picked up without restarting. Returns
988
+ * the resolved skill count.
974
989
  */
975
990
  export function reloadSkills() {
991
+ _defaultSkillLoader.revokeExecutionAuthorizations({
992
+ message: "Skill execution authorization was revoked by /reload-skills",
993
+ reasonCode: "reload-skills",
994
+ });
976
995
  _defaultSkillLoader.clearCache();
977
996
  return _defaultSkillLoader.loadAll().length;
978
997
  }
@@ -1246,13 +1265,34 @@ export function buildSystemPrompt(cwd, opts = {}) {
1246
1265
  turnId: opts.turnId,
1247
1266
  loadedBecause: "persona_auto",
1248
1267
  });
1268
+ // Re-admit custom/injected loader output at the final model boundary. Do
1269
+ // the complete aggregate pass before appending anything so an oversized
1270
+ // later persona cannot leave an earlier partial projection in the prompt.
1271
+ const limits = resolveSkillLimits(loader.getLimits?.());
1272
+ const promptBudget = { limits, bytes: 0, tokens: 0 };
1273
+ const personaProjections = [];
1274
+ for (const personaSkill of personaSkills) {
1275
+ const displayName =
1276
+ typeof personaSkill?.displayName === "string"
1277
+ ? personaSkill.displayName
1278
+ : typeof personaSkill?.id === "string"
1279
+ ? personaSkill.id
1280
+ : "Skill";
1281
+ const body = personaSkill?.body;
1282
+ admitSkillPrompt(body, limits);
1283
+ if (!body.trim()) continue;
1284
+ const projection = `\n\n## Persona: ${displayName}\n${body}`;
1285
+ debitSkillPromptBudget(
1286
+ promptBudget,
1287
+ admitSkillPrompt(projection, limits),
1288
+ );
1289
+ personaProjections.push(projection);
1290
+ }
1249
1291
  if (typeof opts.onSkillsLoaded === "function") {
1250
1292
  opts.onSkillsLoaded(personaSkills, loader.getCacheLedger());
1251
1293
  }
1252
- for (const p of personaSkills) {
1253
- if (p.body?.trim()) {
1254
- prompt += `\n\n## Persona: ${p.displayName}\n${p.body}`;
1255
- }
1294
+ for (const projection of personaProjections) {
1295
+ prompt += projection;
1256
1296
  }
1257
1297
  } catch {
1258
1298
  // Non-critical — skill loader may not be available
@@ -1773,6 +1813,11 @@ export async function executeTool(name, args, context = {}) {
1773
1813
  typeof context.externalToolDescriptors === "object"
1774
1814
  ? context.externalToolDescriptors[name] || null
1775
1815
  : null;
1816
+ const localToolExecutor =
1817
+ context.externalToolExecutors &&
1818
+ typeof context.externalToolExecutors === "object"
1819
+ ? context.externalToolExecutors[name] || null
1820
+ : null;
1776
1821
  const runtimeDescriptor =
1777
1822
  getRuntimeToolDescriptor(name) || localToolDescriptor;
1778
1823
  const admission = context.toolAdmission;
@@ -2046,6 +2091,69 @@ export async function executeTool(name, args, context = {}) {
2046
2091
  ruleAllowed = true;
2047
2092
  }
2048
2093
 
2094
+ // MCP annotations are peer-provided hints, never execution authority. A
2095
+ // server that claims readOnlyHint=true therefore still needs a request-level
2096
+ // approval unless the host independently authorized this exact tool as a
2097
+ // trusted read. An explicit settings allow can suppress the default prompt,
2098
+ // but it cannot suppress a host-owned `ask`/requiresConfirmation decision.
2099
+ // Plan mode has already applied its stricter hard ceiling above, so this gate
2100
+ // covers normal interactive/Auto execution without creating a Plan escape.
2101
+ if (localToolExecutor?.kind === "mcp") {
2102
+ const mcpEffectContract = mcpLedgerEffectContract(
2103
+ localToolDescriptor,
2104
+ hostToolPolicy,
2105
+ );
2106
+ const trustedHostRead =
2107
+ mcpEffectContract.effect === McpEffect.READ &&
2108
+ mcpEffectContract.trusted === true;
2109
+ const settingsAskWasConfirmed =
2110
+ settingsVerdict.decision === "ask" && ruleAllowed;
2111
+ const hostRequiresConfirmation =
2112
+ !settingsAskWasConfirmed &&
2113
+ (hostToolPolicy?.requiresConfirmation === true ||
2114
+ hostToolPolicy?.decision === "ask");
2115
+ const defaultRequiresConfirmation = !trustedHostRead && !ruleAllowed;
2116
+
2117
+ if (hostRequiresConfirmation || defaultRequiresConfirmation) {
2118
+ const approved = await requestInteractivePermission(
2119
+ name,
2120
+ args,
2121
+ context,
2122
+ cwd,
2123
+ {
2124
+ tool: name,
2125
+ args,
2126
+ rule: null,
2127
+ reason: hostRequiresConfirmation
2128
+ ? "host policy requires confirmation for this MCP tool"
2129
+ : `MCP effect is ${mcpEffectContract.effect} and lacks a trusted host read authorization`,
2130
+ source: hostRequiresConfirmation
2131
+ ? "host-managed MCP policy"
2132
+ : "MCP effect contract",
2133
+ mcpEffect: mcpEffectContract.effect,
2134
+ mcpTrusted: mcpEffectContract.trusted === true,
2135
+ },
2136
+ );
2137
+ if (!approved) {
2138
+ return {
2139
+ error: `[MCP Permission] Tool "${name}" requires confirmation because its effect is ${mcpEffectContract.effect} and it does not have an applicable trusted host read authorization — denied.`,
2140
+ policy: {
2141
+ decision: "ask",
2142
+ via: hostRequiresConfirmation
2143
+ ? "host-mcp-policy"
2144
+ : "mcp-effect-contract",
2145
+ code: "CC_MCP_EFFECT_CONFIRMATION_REQUIRED",
2146
+ effect: mcpEffectContract.effect,
2147
+ trusted: mcpEffectContract.trusted === true,
2148
+ },
2149
+ };
2150
+ }
2151
+ // The approval is scoped to this request and also satisfies the later
2152
+ // generic external-tool/ApprovalGate prompt for the same invocation.
2153
+ ruleAllowed = true;
2154
+ }
2155
+ }
2156
+
2049
2157
  // Sensitive-file write guard (Claude-Code 2.1.160 parity): shell startup
2050
2158
  // files / PowerShell profiles / git+husky hooks execute code on the user's
2051
2159
  // next shell or commit — even otherwise-permitted edit flows confirm first.
@@ -3279,11 +3387,18 @@ function mcpLedgerEffectContract(descriptor, hostPolicy) {
3279
3387
  )
3280
3388
  ? descriptorContract.declaredEffect
3281
3389
  : "unknown";
3390
+ // Host authority may raise an unknown/read declaration to a stricter effect,
3391
+ // but it may never downgrade the conservative peer risk floor. In
3392
+ // particular, an accidentally stale host `read` policy cannot turn a newly
3393
+ // declared write/destructive tool into a trusted read.
3282
3394
  const effect =
3283
- authorizedEffect ||
3284
- (declaredEffect === "destructive" || declaredEffect === "write"
3285
- ? declaredEffect
3286
- : "unknown");
3395
+ declaredEffect === "destructive" || authorizedEffect === "destructive"
3396
+ ? "destructive"
3397
+ : declaredEffect === "write" || authorizedEffect === "write"
3398
+ ? "write"
3399
+ : declaredEffect === "unknown"
3400
+ ? "unknown"
3401
+ : authorizedEffect || "unknown";
3287
3402
  const annotations = descriptorContract.annotations || {};
3288
3403
 
3289
3404
  return {
@@ -3301,7 +3416,15 @@ function mcpLedgerEffectContract(descriptor, hostPolicy) {
3301
3416
  : null,
3302
3417
  trusted:
3303
3418
  authorizedEffect != null &&
3304
- (hostContract.trusted === true || hostPolicy?.sourceTrusted === true),
3419
+ (hostContract.trusted === true || hostPolicy?.sourceTrusted === true) &&
3420
+ // Trust is valid only when the host authorization is at least as strict
3421
+ // as the merged effect. A stale host `read` classification cannot lend
3422
+ // trust to a server that now declares write/destructive behavior.
3423
+ authorizedEffect === effect &&
3424
+ // Trusted-read execution/parallelism requires the intersection promised
3425
+ // by the roadmap: a server read declaration plus host authorization.
3426
+ // An unmarked tool stays untrusted even when a host policy predicts read.
3427
+ (effect !== "read" || declaredEffect === "read"),
3305
3428
  source:
3306
3429
  hostContract.provenance ||
3307
3430
  descriptorContract.provenance ||
@@ -3354,21 +3477,41 @@ const MCP_PROTOCOL_RESULT_INVALID_CODE = "CC_MCP_PROTOCOL_RESULT_INVALID";
3354
3477
  const MCP_RESULT_PROJECTION_FAILED_CODE = "CC_MCP_RESULT_PROJECTION_FAILED";
3355
3478
 
3356
3479
  function safeMcpProperty(value, property) {
3480
+ if (!value || (typeof value !== "object" && typeof value !== "function")) {
3481
+ return undefined;
3482
+ }
3357
3483
  try {
3358
- return value?.[property];
3484
+ if (isProxy(value)) return undefined;
3485
+ const descriptor = Object.getOwnPropertyDescriptor(value, property);
3486
+ return descriptor && Object.hasOwn(descriptor, "value")
3487
+ ? descriptor.value
3488
+ : undefined;
3359
3489
  } catch {
3360
3490
  return undefined;
3361
3491
  }
3362
3492
  }
3363
3493
 
3364
3494
  function safeMcpErrorMessage(error) {
3495
+ if (safeMcpProperty(error, "mcpErrorCode") === "CC_MCP_RPC_ERROR") {
3496
+ const rpcCode = safeMcpProperty(error, "rpcCode");
3497
+ return Number.isSafeInteger(rpcCode)
3498
+ ? `MCP server returned a JSON-RPC error (code ${rpcCode})`
3499
+ : "MCP server returned a JSON-RPC error";
3500
+ }
3501
+ // HTTP status bodies are peer-controlled. The production transport omits
3502
+ // them at source, and this boundary independently prevents any MCP client
3503
+ // honoring the stable transport error code from projecting one into tool
3504
+ // results, models, or sessions.
3505
+ if (safeMcpProperty(error, "code") === "CC_MCP_HTTP_STATUS") {
3506
+ const status = safeMcpProperty(error, "status");
3507
+ return Number.isInteger(status) && status >= 100 && status <= 599
3508
+ ? `MCP HTTP request failed with status ${status}`
3509
+ : "MCP HTTP request failed";
3510
+ }
3365
3511
  const message = safeMcpProperty(error, "message");
3366
3512
  if (typeof message === "string" && message) return message;
3367
- try {
3368
- return String(error || "unknown error");
3369
- } catch {
3370
- return "unknown error";
3371
- }
3513
+ if (typeof error === "string" && error) return error;
3514
+ return "unknown error";
3372
3515
  }
3373
3516
 
3374
3517
  function safeMcpErrorCode(error, fallback) {
@@ -3376,6 +3519,15 @@ function safeMcpErrorCode(error, fallback) {
3376
3519
  return typeof code === "string" && code ? code : fallback;
3377
3520
  }
3378
3521
 
3522
+ function projectMcpCallError(error) {
3523
+ const projected = new Error(safeMcpErrorMessage(error));
3524
+ const code = isMcpRpcError(error)
3525
+ ? "CC_MCP_RPC_ERROR"
3526
+ : safeMcpErrorCode(error, null);
3527
+ if (code) projected.code = code;
3528
+ return projected;
3529
+ }
3530
+
3379
3531
  function invalidMcpProtocolResult(cause) {
3380
3532
  const error = new TypeError("MCP result could not be inspected safely", {
3381
3533
  cause,
@@ -5654,10 +5806,16 @@ async function executeToolInner(
5654
5806
  }
5655
5807
 
5656
5808
  case "run_skill": {
5657
- const allSkills = await filterSkillsByCwd(
5658
- skillLoader.getResolvedSkills().filter(skillAllowed),
5659
- cwd,
5809
+ throwIfAborted(signal, "run_skill interrupted before discovery");
5810
+ const allSkills = await raceWithAbort(
5811
+ filterSkillsByCwd(
5812
+ skillLoader.getResolvedSkills().filter(skillAllowed),
5813
+ cwd,
5814
+ ),
5815
+ signal,
5816
+ "run_skill interrupted during discovery",
5660
5817
  );
5818
+ throwIfAborted(signal, "run_skill interrupted during discovery");
5661
5819
  if (allSkills.length === 0) {
5662
5820
  return attachDescriptor({
5663
5821
  error: _skillAllowlist
@@ -5668,28 +5826,57 @@ async function executeToolInner(
5668
5826
  let match = allSkills.find(
5669
5827
  (s) => s.id === args.skill_name || s.dirName === args.skill_name,
5670
5828
  );
5829
+ let admittedSkillBody = "";
5671
5830
  if (!match || !match.hasHandler) {
5672
5831
  return attachDescriptor({
5673
5832
  error: `Skill "${args.skill_name}" not found or has no handler. Use list_skills to see available skills.`,
5674
5833
  });
5675
5834
  }
5835
+ const skillExecutionLease = skillLoader.acquireSkillExecution?.(match, {
5836
+ signal,
5837
+ });
5838
+ const skillExecutionSignal = skillExecutionLease?.signal || signal;
5676
5839
  try {
5840
+ skillExecutionLease?.assertActive?.();
5677
5841
  if (typeof skillLoader.materializeSkillForExecution === "function") {
5678
- match = await skillLoader.materializeSkillForExecution(match, {
5679
- sessionId,
5680
- turnId,
5681
- loadedBecause: "run_skill",
5682
- bodyIncluded: false,
5683
- });
5842
+ match = await raceWithAbort(
5843
+ skillLoader.materializeSkillForExecution(match, {
5844
+ sessionId,
5845
+ turnId,
5846
+ loadedBecause: "run_skill",
5847
+ bodyIncluded: true,
5848
+ signal: skillExecutionSignal,
5849
+ }),
5850
+ skillExecutionSignal,
5851
+ "run_skill interrupted during authorization",
5852
+ );
5684
5853
  } else if (typeof skillLoader.materializeSkill === "function") {
5685
5854
  match = skillLoader.materializeSkill(match, {
5686
5855
  sessionId,
5687
5856
  turnId,
5688
5857
  loadedBecause: "run_skill",
5689
- bodyIncluded: false,
5858
+ bodyIncluded: true,
5859
+ signal: skillExecutionSignal,
5690
5860
  });
5691
5861
  }
5862
+ skillExecutionLease?.assertActive?.();
5863
+ throwIfAborted(
5864
+ skillExecutionSignal,
5865
+ "run_skill interrupted during materialization",
5866
+ );
5867
+ // A custom loader is not an authority to raise host model-input caps.
5868
+ // Re-admit at the final consumer before constructing the child task.
5869
+ admittedSkillBody = match?.body;
5870
+ admitSkillPrompt(admittedSkillBody, skillLoader.getLimits?.());
5692
5871
  } catch (error) {
5872
+ skillExecutionLease?.release?.();
5873
+ if (
5874
+ signal?.aborted ||
5875
+ skillExecutionSignal?.aborted ||
5876
+ isAbortError(error)
5877
+ ) {
5878
+ throw error;
5879
+ }
5693
5880
  return attachDescriptor({
5694
5881
  error: `Skill "${args.skill_name}" body could not be loaded: ${error.message}`,
5695
5882
  ...(error?.code ? { code: error.code } : {}),
@@ -5721,67 +5908,84 @@ async function executeToolInner(
5721
5908
  : null;
5722
5909
  let skillSubRef = null;
5723
5910
  // Run skill through isolated sub-agent context
5724
- const subCtx = SubAgentContext.create({
5725
- role: `skill-${args.skill_name}`,
5726
- task:
5727
- `Execute the "${args.skill_name}" skill using only the approved tools.\n\n` +
5728
- `Authoritative skill instructions:\n${String(match.body || "").substring(0, 48000)}\n\n` +
5729
- `User input:\n${String(args.input || "").substring(0, 8000)}`,
5730
- allowedTools: isolatedSkillTools,
5731
- hookParentTraceId: hookTraceId || null,
5732
- toolAdmission,
5733
- cwd,
5734
- llmOptions: llmOptions || null,
5735
- ...(sessionBudget ? { sessionBudget } : {}),
5736
- ...(permissionRules ? { permissionRules } : {}),
5737
- ...(hostManagedToolPolicy
5738
- ? {
5739
- hostManagedToolPolicy: {
5740
- ...hostManagedToolPolicy,
5741
- toolDefinitions: [],
5742
- },
5743
- }
5744
- : {}),
5745
- ...(planManager ? { planManager } : {}),
5746
- ...(sandbox ? { sandbox } : {}),
5747
- ...(Array.isArray(additionalDirectories)
5748
- ? { additionalDirectories: [...additionalDirectories] }
5749
- : {}),
5750
- ...(approvalGate ? { approvalGate } : {}),
5751
- ...(shellPolicyOverrides ? { shellPolicyOverrides } : {}),
5752
- ...(classifyAllShell ? { classifyAllShell: true } : {}),
5753
- ...(unattendedActionPolicy ? { unattendedActionPolicy } : {}),
5754
- ...(mcpCallLedger ? { mcpCallLedger } : {}),
5755
- ...(mcpConflictScheduler ? { mcpConflictScheduler } : {}),
5756
- onUsage: skillUsageSink
5757
- ? (u) => {
5758
- try {
5759
- skillUsageSink.push(
5760
- u && u.attribution
5761
- ? u
5762
- : {
5763
- provider: u?.provider ?? null,
5764
- model: u?.model ?? null,
5765
- usage: u?.usage || null,
5766
- ...(u?.source ? { source: u.source } : {}),
5767
- attribution: {
5768
- origin: "skill",
5769
- skill: args.skill_name,
5770
- subagentId: skillSubRef?.id || null,
5771
- parentSessionId: sessionId || null,
5772
- depth: (subAgentDepth || 0) + 1,
5911
+ let subCtx;
5912
+ try {
5913
+ skillExecutionLease?.assertActive?.();
5914
+ subCtx = SubAgentContext.create({
5915
+ role: `skill-${args.skill_name}`,
5916
+ task:
5917
+ `Execute the "${args.skill_name}" skill using only the approved tools.\n\n` +
5918
+ `Authoritative skill instructions:\n${admittedSkillBody}\n\n` +
5919
+ `User input:\n${String(args.input || "").substring(0, 8000)}`,
5920
+ allowedTools: isolatedSkillTools,
5921
+ hookParentTraceId: hookTraceId || null,
5922
+ signal: skillExecutionSignal,
5923
+ toolAdmission,
5924
+ cwd,
5925
+ llmOptions: llmOptions || null,
5926
+ ...(sessionBudget ? { sessionBudget } : {}),
5927
+ ...(permissionRules ? { permissionRules } : {}),
5928
+ ...(hostManagedToolPolicy
5929
+ ? {
5930
+ hostManagedToolPolicy: {
5931
+ ...hostManagedToolPolicy,
5932
+ toolDefinitions: [],
5933
+ },
5934
+ }
5935
+ : {}),
5936
+ ...(planManager ? { planManager } : {}),
5937
+ ...(sandbox ? { sandbox } : {}),
5938
+ ...(Array.isArray(additionalDirectories)
5939
+ ? { additionalDirectories: [...additionalDirectories] }
5940
+ : {}),
5941
+ ...(approvalGate ? { approvalGate } : {}),
5942
+ ...(shellPolicyOverrides ? { shellPolicyOverrides } : {}),
5943
+ ...(classifyAllShell ? { classifyAllShell: true } : {}),
5944
+ ...(unattendedActionPolicy ? { unattendedActionPolicy } : {}),
5945
+ ...(mcpCallLedger ? { mcpCallLedger } : {}),
5946
+ ...(mcpConflictScheduler ? { mcpConflictScheduler } : {}),
5947
+ onUsage: skillUsageSink
5948
+ ? (u) => {
5949
+ try {
5950
+ skillUsageSink.push(
5951
+ u && u.attribution
5952
+ ? u
5953
+ : {
5954
+ provider: u?.provider ?? null,
5955
+ model: u?.model ?? null,
5956
+ usage: u?.usage || null,
5957
+ ...(u?.source ? { source: u.source } : {}),
5958
+ attribution: {
5959
+ origin: "skill",
5960
+ skill: args.skill_name,
5961
+ subagentId: skillSubRef?.id || null,
5962
+ parentSessionId: sessionId || null,
5963
+ depth: (subAgentDepth || 0) + 1,
5964
+ },
5773
5965
  },
5774
- },
5775
- );
5776
- } catch (_e) {
5777
- // usage forwarding is best-effort
5966
+ );
5967
+ } catch (_e) {
5968
+ // usage forwarding is best-effort
5969
+ }
5778
5970
  }
5779
- }
5780
- : null,
5781
- });
5971
+ : null,
5972
+ });
5973
+ } catch (error) {
5974
+ skillExecutionLease?.release?.();
5975
+ throw error;
5976
+ }
5782
5977
  skillSubRef = subCtx;
5783
5978
  try {
5784
- const result = await subCtx.run(args.input);
5979
+ const result = await raceWithAbort(
5980
+ subCtx.run(args.input),
5981
+ skillExecutionSignal,
5982
+ "run_skill interrupted while the isolated child was running",
5983
+ );
5984
+ skillExecutionLease?.assertActive?.();
5985
+ throwIfAborted(
5986
+ skillExecutionSignal,
5987
+ "run_skill interrupted before child handoff",
5988
+ );
5785
5989
  const resolvedFailure =
5786
5990
  subCtx.status === "failed" ||
5787
5991
  result?.success === false ||
@@ -5809,6 +6013,13 @@ async function executeToolInner(
5809
6013
  toolsUsed: result.toolsUsed,
5810
6014
  });
5811
6015
  } catch (err) {
6016
+ if (
6017
+ signal?.aborted ||
6018
+ skillExecutionSignal?.aborted ||
6019
+ isAbortError(err)
6020
+ ) {
6021
+ throw err;
6022
+ }
5812
6023
  return attachDescriptor({
5813
6024
  success: false,
5814
6025
  isolated: true,
@@ -5816,6 +6027,8 @@ async function executeToolInner(
5816
6027
  code: err?.code || "CC_SKILL_ISOLATED_EXECUTION_FAILED",
5817
6028
  error: `Isolated skill execution failed: ${err.message}`,
5818
6029
  });
6030
+ } finally {
6031
+ skillExecutionLease?.release?.();
5819
6032
  }
5820
6033
  }
5821
6034
 
@@ -5823,6 +6036,7 @@ async function executeToolInner(
5823
6036
  // reaching here. Keep the runtime fence explicit so a custom/legacy
5824
6037
  // loader can never re-enable arbitrary handler.js imports in the CLI
5825
6038
  // process or hand a Skill the raw MCP client/process broker.
6039
+ skillExecutionLease?.release?.();
5826
6040
  return attachDescriptor({
5827
6041
  error: `Skill "${args.skill_name}" cannot execute handler.js directly. Add isolation: true and use the controlled agent-tool path.`,
5828
6042
  code: "CC_SKILL_DIRECT_HANDLER_BLOCKED",
@@ -5907,13 +6121,15 @@ async function executeToolInner(
5907
6121
  error: `Could not resolve which MCP server owns resource "${uri}". Pass 'server' explicitly.`,
5908
6122
  });
5909
6123
  }
5910
- const result = await mcpClient.readResource(server, uri);
6124
+ const result = signal
6125
+ ? await mcpClient.readResource(server, uri, { signal })
6126
+ : await mcpClient.readResource(server, uri);
5911
6127
  return attachDescriptor(
5912
6128
  result && typeof result === "object" ? result : { result },
5913
6129
  );
5914
6130
  } catch (err) {
5915
6131
  return attachDescriptor({
5916
- error: `MCP resource access failed: ${err.message}`,
6132
+ error: `MCP resource access failed: ${safeMcpErrorMessage(err)}`,
5917
6133
  });
5918
6134
  }
5919
6135
  }
@@ -6015,19 +6231,31 @@ async function executeToolInner(
6015
6231
  });
6016
6232
  }
6017
6233
 
6018
- const transportFailure = async (callError) => {
6019
- if (mcpTransportOutcomeIsUnsafe(ledgerEffectContract)) {
6234
+ const transportFailure = async (callError, phase = "call") => {
6235
+ const definitiveRpcFailure = isMcpRpcError(callError);
6236
+ if (
6237
+ mcpTransportOutcomeIsUnsafe(ledgerEffectContract) &&
6238
+ !definitiveRpcFailure
6239
+ ) {
6240
+ const resultAdmissionFailure =
6241
+ isMcpToolResultAdmissionError(callError);
6020
6242
  return attachDescriptor(
6021
6243
  mcpOutcomeUnknownPayload(ledger, ledgerTicket, {
6022
- phase: "call",
6023
- reasonCode: MCP_TRANSPORT_OUTCOME_UNKNOWN_CODE,
6244
+ phase,
6245
+ reasonCode: resultAdmissionFailure
6246
+ ? safeMcpErrorCode(
6247
+ callError,
6248
+ MCP_PROTOCOL_RESULT_INVALID_CODE,
6249
+ )
6250
+ : MCP_TRANSPORT_OUTCOME_UNKNOWN_CODE,
6024
6251
  }),
6025
6252
  );
6026
6253
  }
6254
+ const projectedError = projectMcpCallError(callError);
6027
6255
  try {
6028
6256
  await ledgerTicket.settle({
6029
6257
  status: "failed",
6030
- error: callError,
6258
+ error: projectedError,
6031
6259
  });
6032
6260
  } catch (ledgerError) {
6033
6261
  return attachDescriptor(
@@ -6041,20 +6269,29 @@ async function executeToolInner(
6041
6269
  );
6042
6270
  }
6043
6271
  return attachDescriptor({
6044
- error: `MCP tool execution failed: ${safeMcpErrorMessage(callError)}`,
6272
+ error: `MCP tool execution failed: ${projectedError.message}`,
6045
6273
  mcpLedgerId: safeMcpProperty(ledgerTicket, "ledgerId") || null,
6046
6274
  });
6047
6275
  };
6048
6276
 
6049
6277
  let pendingResult;
6050
6278
  try {
6051
- pendingResult = Reflect.apply(mcpClient.callTool, mcpClient, [
6279
+ const callArguments = [
6052
6280
  localToolExecutor.serverName,
6053
6281
  localToolExecutor.toolName,
6054
6282
  mcpWireInput,
6055
- ]);
6283
+ ];
6284
+ if (signal) callArguments.push({ signal });
6285
+ pendingResult = Reflect.apply(
6286
+ mcpClient.callTool,
6287
+ mcpClient,
6288
+ callArguments,
6289
+ );
6056
6290
  } catch (callError) {
6057
- return await transportFailure(callError);
6291
+ return await transportFailure(
6292
+ callError,
6293
+ isMcpToolResultAdmissionError(callError) ? "result" : "call",
6294
+ );
6058
6295
  }
6059
6296
 
6060
6297
  let result;
@@ -6091,7 +6328,10 @@ async function executeToolInner(
6091
6328
  try {
6092
6329
  result = await pendingResult;
6093
6330
  } catch (callError) {
6094
- return await transportFailure(callError);
6331
+ return await transportFailure(
6332
+ callError,
6333
+ isMcpToolResultAdmissionError(callError) ? "result" : "call",
6334
+ );
6095
6335
  }
6096
6336
  } else {
6097
6337
  let then;
@@ -6136,6 +6376,16 @@ async function executeToolInner(
6136
6376
  result = pendingResult;
6137
6377
  }
6138
6378
 
6379
+ try {
6380
+ result = admitMcpToolResult(
6381
+ localToolExecutor.serverName,
6382
+ result,
6383
+ localToolExecutor.toolResultConfig,
6384
+ ).result;
6385
+ } catch (resultError) {
6386
+ return await transportFailure(resultError, "result");
6387
+ }
6388
+
6139
6389
  let protocolError;
6140
6390
  try {
6141
6391
  if (
@@ -6683,12 +6933,21 @@ export const MAX_SUB_AGENTS_PER_RUN = 32;
6683
6933
  * `substring(0, 5000)` that sliced mid-content with no marker and undercut even
6684
6934
  * read_file's own 50k self-limit. Tools that self-limit (read_file, notebook
6685
6935
  * render) stay below this; it is the final safety net for the ones that don't
6686
- * (run_shell, search_files, run_code, MCP). Override with CC_MAX_TOOL_RESULT_CHARS.
6936
+ * (run_shell, search_files, run_code, MCP). CC_MAX_TOOL_RESULT_CHARS may only
6937
+ * tighten the host ceiling; it cannot raise or disable it.
6687
6938
  */
6688
- export const MAX_TOOL_RESULT_CHARS = (() => {
6689
- const n = Number(process.env.CC_MAX_TOOL_RESULT_CHARS);
6690
- return Number.isFinite(n) && n > 0 ? Math.floor(n) : 50000;
6691
- })();
6939
+ export const MAX_TOOL_RESULT_CHARS_HARD_LIMIT = 50000;
6940
+
6941
+ export function resolveMaxToolResultChars(configured) {
6942
+ const value = Number(configured);
6943
+ return Number.isFinite(value) && value > 0
6944
+ ? Math.min(MAX_TOOL_RESULT_CHARS_HARD_LIMIT, Math.max(1, Math.floor(value)))
6945
+ : MAX_TOOL_RESULT_CHARS_HARD_LIMIT;
6946
+ }
6947
+
6948
+ export const MAX_TOOL_RESULT_CHARS = resolveMaxToolResultChars(
6949
+ process.env.CC_MAX_TOOL_RESULT_CHARS,
6950
+ );
6692
6951
 
6693
6952
  /**
6694
6953
  * Cap a serialized tool result to `max` chars, appending a visible truncation
@@ -6698,10 +6957,11 @@ export const MAX_TOOL_RESULT_CHARS = (() => {
6698
6957
  */
6699
6958
  export function capToolResultString(serialized, max = MAX_TOOL_RESULT_CHARS) {
6700
6959
  const s = String(serialized ?? "");
6701
- if (s.length <= max) return s;
6960
+ const effectiveMax = resolveMaxToolResultChars(max);
6961
+ if (s.length <= effectiveMax) return s;
6702
6962
  return (
6703
- s.slice(0, max) +
6704
- `\n…[tool output truncated: showing the first ${max} of ${s.length} chars` +
6963
+ s.slice(0, effectiveMax) +
6964
+ `\n…[tool output truncated: showing the first ${effectiveMax} of ${s.length} chars` +
6705
6965
  ` — narrow the request (read a line range, grep, or paginate) to see the rest]`
6706
6966
  );
6707
6967
  }
@@ -8143,6 +8403,42 @@ function _ollamaInitState() {
8143
8403
  };
8144
8404
  }
8145
8405
 
8406
+ function _streamUiCallbacks(onToken, onThinking) {
8407
+ let pending = [];
8408
+ const capture = (callback) =>
8409
+ typeof callback === "function"
8410
+ ? (value) => {
8411
+ try {
8412
+ const result = callback(value);
8413
+ if (result && typeof result.then === "function") {
8414
+ pending.push(Promise.resolve(result));
8415
+ }
8416
+ } catch (error) {
8417
+ pending.push(Promise.reject(error));
8418
+ }
8419
+ }
8420
+ : callback;
8421
+ return {
8422
+ onToken: capture(onToken),
8423
+ onThinking: capture(onThinking),
8424
+ async settle() {
8425
+ if (pending.length === 0) return;
8426
+ const current = pending;
8427
+ pending = [];
8428
+ const outcomes = await Promise.allSettled(current);
8429
+ const fatal = outcomes.find(
8430
+ (outcome) =>
8431
+ outcome.status === "rejected" &&
8432
+ outcome.reason?.isOutputBackpressureFailure === true,
8433
+ );
8434
+ if (fatal) throw fatal.reason;
8435
+ // Generic UI callback failures retain their historical best-effort
8436
+ // semantics. Branded output failures are lifecycle failures and abort the
8437
+ // provider stream instead of allowing its terminal queue to grow.
8438
+ },
8439
+ };
8440
+ }
8441
+
8146
8442
  function _ollamaReduceLine(state, line, onToken) {
8147
8443
  const s = (line || "").trim();
8148
8444
  if (!s) return state;
@@ -8213,6 +8509,7 @@ export function _accumulateOllamaStream(lines, onToken) {
8213
8509
  * showing raw errors"). Pure + exported for unit tests.
8214
8510
  */
8215
8511
  export function _streamErrorDisposition(err, signal, partialText) {
8512
+ if (err?.isOutputBackpressureFailure === true) return "rethrow";
8216
8513
  if (isAbortError(err)) return "rethrow";
8217
8514
  if (signal && signal.aborted) return "rethrow";
8218
8515
  if (typeof partialText === "string" && partialText.trim()) return "preserve";
@@ -8427,6 +8724,7 @@ async function _chatOllamaStreaming(
8427
8724
  throw new Error(await formatProviderResponseError("ollama", response));
8428
8725
  }
8429
8726
  const state = _ollamaInitState();
8727
+ const ui = _streamUiCallbacks(onToken);
8430
8728
  const reader = response.body.getReader();
8431
8729
  const decoder = new TextDecoder();
8432
8730
  let buf = "";
@@ -8439,11 +8737,15 @@ async function _chatOllamaStreaming(
8439
8737
  buf += decoder.decode(value, { stream: true });
8440
8738
  let idx;
8441
8739
  while ((idx = buf.indexOf("\n")) >= 0) {
8442
- _ollamaReduceLine(state, buf.slice(0, idx), onToken);
8740
+ _ollamaReduceLine(state, buf.slice(0, idx), ui.onToken);
8741
+ await ui.settle();
8443
8742
  buf = buf.slice(idx + 1);
8444
8743
  }
8445
8744
  }
8446
- if (buf.trim()) _ollamaReduceLine(state, buf, onToken);
8745
+ if (buf.trim()) {
8746
+ _ollamaReduceLine(state, buf, ui.onToken);
8747
+ await ui.settle();
8748
+ }
8447
8749
  } catch (err) {
8448
8750
  if (_streamErrorDisposition(err, signal, state.content) === "rethrow")
8449
8751
  throw err;
@@ -8613,6 +8915,7 @@ async function _chatAnthropicStreaming(
8613
8915
  throw new Error(await formatProviderResponseError("anthropic", response));
8614
8916
  }
8615
8917
  const state = _anthropicInitState();
8918
+ const ui = _streamUiCallbacks(onToken, onThinking);
8616
8919
  const reader = response.body.getReader();
8617
8920
  const decoder = new TextDecoder();
8618
8921
  let buf = "";
@@ -8625,10 +8928,15 @@ async function _chatAnthropicStreaming(
8625
8928
  buf += decoder.decode(value, { stream: true });
8626
8929
  const lines = buf.split("\n");
8627
8930
  buf = lines.pop() || "";
8628
- for (const line of lines)
8629
- _anthropicReduceLine(state, line, onToken, onThinking);
8931
+ for (const line of lines) {
8932
+ _anthropicReduceLine(state, line, ui.onToken, ui.onThinking);
8933
+ await ui.settle();
8934
+ }
8935
+ }
8936
+ if (buf.trim()) {
8937
+ _anthropicReduceLine(state, buf, ui.onToken, ui.onThinking);
8938
+ await ui.settle();
8630
8939
  }
8631
- if (buf.trim()) _anthropicReduceLine(state, buf, onToken, onThinking);
8632
8940
  } catch (err) {
8633
8941
  if (_streamErrorDisposition(err, signal, state.text) === "rethrow")
8634
8942
  throw err;
@@ -8765,6 +9073,7 @@ async function _chatOpenAIStreaming(
8765
9073
  throw new Error(await formatProviderResponseError(provider, response));
8766
9074
  }
8767
9075
  const state = _openaiInitState();
9076
+ const ui = _streamUiCallbacks(onToken);
8768
9077
  const reader = response.body.getReader();
8769
9078
  const decoder = new TextDecoder();
8770
9079
  let buf = "";
@@ -8777,9 +9086,15 @@ async function _chatOpenAIStreaming(
8777
9086
  buf += decoder.decode(value, { stream: true });
8778
9087
  const lines = buf.split("\n");
8779
9088
  buf = lines.pop() || "";
8780
- for (const line of lines) _openaiReduceLine(state, line, onToken);
9089
+ for (const line of lines) {
9090
+ _openaiReduceLine(state, line, ui.onToken);
9091
+ await ui.settle();
9092
+ }
9093
+ }
9094
+ if (buf.trim()) {
9095
+ _openaiReduceLine(state, buf, ui.onToken);
9096
+ await ui.settle();
8781
9097
  }
8782
- if (buf.trim()) _openaiReduceLine(state, buf, onToken);
8783
9098
  } catch (err) {
8784
9099
  if (_streamErrorDisposition(err, signal, state.text) === "rethrow")
8785
9100
  throw err;