chainlesschain 0.162.180 → 0.162.181

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 (249) hide show
  1. package/package.json +6 -3
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/{AIOps-D_TIL54O.js → AIOps-cq0dwbnf.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-eQwy9r-f.js → ActionButton-CvcgGl3w.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-D2eNuDgT.js → Analytics-hM2-jFqg.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-CFhwOFsf.js → AppLayout-B9_Gsd_g.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-CJUMw6PB.js → Artifacts-B7bu52Og.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-CDB9V58o.js → Audit-DThfDgqB.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-TBppYFjN.js → BackgroundAgents-DjlFiD4v.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-CYEOUpzJ.js → Backup-CK9xJKnG.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-C88fFT2u.js → BaseInput-DEiSU8K8.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-mkr1vC3N.js → Chat-CpT96czj.js} +6 -6
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-C7bofJuA.js → ChatBubbleRenderer-BKPPNmZI.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-CVU4xqti.js → Checkbox-C1GfDnO0.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-rrNcByz3.js → Codegen-3DAKgiLx.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-Cqu-zCvh.js → Col-74cOwZU1.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-RGRlSgXV.js → Community-tn9Kkz9j.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-DBm6epOK.js → Compact-BcoXH7m4.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-BgKw5iaW.js → Compliance-DIPGUBgi.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-BqQcNO3Z.js → Cowork-doD5_91c.js} +2 -2
  21. package/src/assets/web-panel/assets/{Cron-DO5gTFNb.js → Cron-C-IDvubz.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-B8hbJNuN.js → Crosschain-CdcCoBdj.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-B08bFJ2C.js → DID-DdH5aMMA.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-xNdy_ifo.js → Dashboard-DHLA4mm0.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-D-KIZgWL.js → Dropdown-dEeCt7Md.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-DKCvsaGo.js → EmailListRenderer-BMaecFv9.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-D_cfqama.js → FamilyGuardDashboard-DUaUukTN.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-B-UqQD68.js → Federation-CMBE0_rp.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-BWWvWuJW.js → FormItemContext-PG-JDbXq.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-CPchx6N7.js → GenericCardRenderer-Bcb0p88m.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-Vx4co9Ff.js → Git-Bgv15myB.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-D4x0pp_m.js → Governance-DB8YTArI.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-T3KvwPYR.js → Inference-BQMwCWaS.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-Ddv3KUv3.js → KnowledgeGraph-B1_ZziiB.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-DfH-Dkae.js → Logs-DovEEnt_.js} +2 -2
  36. package/src/assets/web-panel/assets/{MarkdownRenderer-DHW3PbCq.js → MarkdownRenderer-D201OL4T.js} +1 -1
  37. package/src/assets/web-panel/assets/{Marketplace-tjgb0R3D.js → Marketplace-BlCXSpyB.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-DHAk5nYX.js → McpTools-CsCR09Wj.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-A2Yx7thM.js → Memory-CBVRLKno.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-BEmTVfN5.js → MobileBridge-C9OIafgA.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-DuFHUgE4.js → MobileProjects-D_zoJ8Xs.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-BDSll0OZ.js → Mtc-vE-HdvLj.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-CuBvluaS.js → MtcAudit-CPLaekCd.js} +2 -2
  44. package/src/assets/web-panel/assets/{Multisig-BmXAA-Sb.js → Multisig-C_UP9C2o.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-ci2stZAe.js → NLProgramming-2nODJcU1.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-D-1RpqnS.js → Notes-BhE-SJGu.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-C0GyitIT.js → NotificationSettings-D21q7BNU.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-U2bN-hj5.js → OrderTableRenderer-0b62GYOD.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-BNZgpPci.js → Organization-CEqmw_sb.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-CDidKmUN.js → Overflow-MW-gMDO_.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-BnreBaXq.js → P2P-CY0hjI_G.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-DwJUxO9j.js → PdhVaultBrowser-BbWh7Man.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-BQGgJPH0.js → Permissions-ChqEA_4Q.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-k_fSkCwL.js → PersonalDataHub-B3YrbYfD.js} +5 -5
  55. package/src/assets/web-panel/assets/{Pipeline-WGqKMqau.js → Pipeline-B8WBhhlW.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-DtHj9Ymq.js → Privacy-Cmb0PXNx.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-B3wH2SFC.js → ProjectInit-hF6zW3Nz.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-Cd0cgcA1.js → ProjectSettings-BFSVfpW0.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-DAWkVFkc.js +1 -0
  60. package/src/assets/web-panel/assets/{Providers-DTpxEXur.js → Providers-B8yux8Dx.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-B2v6gR-C.js → QrScannerModal-N76cQluO.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-D3Nr9xXR.js → QuickAsk-ClvZ0KYR.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-C9inoMky.js → Recommend-B-GfgBpT.js} +1 -1
  64. package/src/assets/web-panel/assets/RemoteSession-mlglCdQi.js +5 -0
  65. package/src/assets/web-panel/assets/{Reputation-41KFG646.js → Reputation-DJIZzQeG.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-DqAaqqCv.js → Row-COzxu_bb.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-CMDpCDKc.js → RssFeed-CoYsJQuE.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-B6mtegNL.js → Search-DC77Mq9S.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-BaePFVZ8.js → Security-Loy2EdMO.js} +3 -3
  70. package/src/assets/web-panel/assets/{Services-DeG3Qscl.js → Services-GUD07Eu0.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-D_QP7F90.js → Skeleton-DWzkptYU.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-DLGyUgIA.js → Skills-CEDn1r-Z.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-BN2pxW1Q.js → Sla-ub_k4pXh.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-BWsZPd8B.js → SpeechSettings-D7HLX9CA.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-VOZRPODW.js → SyncSettings-DbwOvl6m.js} +2 -2
  76. package/src/assets/web-panel/assets/Tasks-CBQzoAu5.js +1 -0
  77. package/src/assets/web-panel/assets/{Templates-eJSob-q0.js → Templates-BNVeIhud.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-Bdwk8Rwy.js → Tenant-PS9AzhXU.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-CsMLKIoV.js → Terminal-Cgb4eLB_.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-D5qkbPKT.js → TimelineRenderer-CrmXMOkg.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-DKgwn8hI.js → Tokens-DD-VDHw1.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-HlEHniGM.js → Trigger-BsoN_n-n.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-CdPcsBpN.js → Trust-n8LmN4ZV.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-vAdXd-vG.js → UkeySign-C9_7MImA.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-9hHBYFnH.js → VideoEditing-DyBteNgn.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-Dxh5d1yR.js → Wallet-BS5ixeXI.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-BsFmLHkp.js → WebAuthn-spc4UImU.js} +3 -3
  88. package/src/assets/web-panel/assets/{WorkflowEditor-Cn0OIwLn.js → WorkflowEditor-D7iVvaBO.js} +1 -1
  89. package/src/assets/web-panel/assets/chat-6CmBkHrL.js +1 -0
  90. package/src/assets/web-panel/assets/{colors-Du9jzLN0.js → colors-BGoCLkxI.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-DhEscfzw.js → compact-item-fYZBetMO.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-CwzEfF3i.js → createContext-BeM-1UVj.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-BzPwHnw8.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-DT_GSE6J.js → hasIn-CE7ZuEnV.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-53z1YUxX.js → index--lap6cf7.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-NA2oBLSB.js → index-ATcSr_2O.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DWL3SYN3.js → index-B2U-ObMq.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-D-QkW1fp.js → index-B3CDgvNW.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BF-ZCVGE.js → index-B4wiTEOM.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-D4kZoXNr.js → index-B8BsdNV_.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DnVVYKCE.js → index-BEVm0lCS.js} +10 -10
  102. package/src/assets/web-panel/assets/{index-DfRDyY1q.js → index-BNZDILcO.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-B8s5FxJY.js → index-BU_2qiDk.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BnHhFnwt.js → index-BV551878.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DhXay17G.js → index-BfPL-m46.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-B6QDWRLk.js → index-BowH1eLQ.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DN60VBn5.js → index-BsMfoaeo.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Cnok8mhZ.js → index-BunaQCa0.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Dny_ZnAO.js → index-C0v6YKKO.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-D8gt0j7r.js → index-C4SJVjs4.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Mobw3PHs.js → index-C9Y3k0HI.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CAVW0cWM.js → index-CIpVrf5P.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CyEhUJcu.js → index-CRLjEP1H.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-DzjzrOli.js → index-CRnUE8Cb.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-D5IytTND.js → index-Cip8emOQ.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BQWENaZf.js → index-CpIGIB85.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CQWxDOvM.js → index-D1r9tT3J.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BrkJ7JPm.js → index-DT3zPSVX.js} +1 -1
  119. package/src/assets/web-panel/assets/index-DacrAdc-.js +1 -0
  120. package/src/assets/web-panel/assets/{index-BFD0cEna.js → index-De0quFDw.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-v5HLYCVa.js → index-DoXk5KJ8.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DtRwLhee.js → index-DsvfrESp.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BgSR2WMG.js → index-Dw1PyYPm.js} +1 -1
  124. package/src/assets/web-panel/assets/index-EHzNJozo.js +1 -0
  125. package/src/assets/web-panel/assets/{index-CGvgnfl9.js → index-MtOuq2i6.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-1LoutPJd.js → index-Puq6Luf1.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-tND8-TDU.js → index-QIpnpZgz.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-D3llLkYM.js → index-RMZ8a7Yt.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-C4SN3by5.js → index-WUrJ6S1j.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-VeHs6qH0.js → index-YjcumOZ4.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Cc9aPkv-.js → index-lJBjB1QX.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-BIYTjbv_.js → index-ukg99D1V.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-gFjYdstW.js → index-zb7rVOhV.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-Cvt59c10.js → initDefaultProps-CYHMs1ag.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-D15pPEzl.js → motion-DDB2Ffk5.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-N55KeXJ7.js → move-Bg3cD-dX.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-CyFO1bYP.js → mtc-parser-B5nedjTS.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-B5IXfxU2.js → omit-BHyuUILu.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-CpVqsulV.js → pickAttrs-C9YQnEN9.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-ME36sMF3.js → placementArrow-DBUFYUe7.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-BXAIR1r-.js → responsiveObserve-nBs2Obnk.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-BkOX3-Dp.js → slide-DkCEaXNU.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-Cy4Aklpt.js → statusUtils-aqE1Wi6U.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-gUd2T206.js → styleChecker-CN5bhfHB.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-CaVD4o99.js → useFlexGapSupport-B_oX_kvJ.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs--pFGl0KD.js → useFs-rCuXHeme.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-D45iP86i.js → usePersonalDataHub-DZR9Abyd.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-BayoChH_.js → vnode-ConCYQlX.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-CpP38poi.js → zoom-CUdDxG5M.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/commands/agent.js +4 -1
  152. package/src/commands/background-session.js +2 -1
  153. package/src/commands/context.js +69 -2
  154. package/src/data/changelog.json +13 -0
  155. package/src/gateways/ws/background-agent-protocol.js +38 -0
  156. package/src/gateways/ws/message-dispatcher.js +1 -0
  157. package/src/gateways/ws/remote-session-protocol.js +65 -6
  158. package/src/gateways/ws/ws-server.js +8 -1
  159. package/src/harness/feature-flags.js +15 -8
  160. package/src/harness/mcp-client.js +618 -43
  161. package/src/lazy-dispatch.js +30 -1
  162. package/src/lib/agent-authority.js +22 -0
  163. package/src/lib/agent-core.js +2 -0
  164. package/src/lib/agent-sandbox.js +161 -0
  165. package/src/lib/agent-team/team-runner.js +22 -0
  166. package/src/lib/artifact-store.js +35 -0
  167. package/src/lib/async-hook-supervisor.cjs +13 -2
  168. package/src/lib/audit-mtc.js +3 -2
  169. package/src/lib/background-agent-supervisor.js +104 -3
  170. package/src/lib/background-interaction-journal.js +407 -0
  171. package/src/lib/background-interaction-resolver.js +23 -34
  172. package/src/lib/background-session-transport.js +12 -2
  173. package/src/lib/capability-manifest.js +41 -3
  174. package/src/lib/capability-negotiation.js +1 -1
  175. package/src/lib/channels/channel-manager.js +33 -0
  176. package/src/lib/channels/telegram-channel.js +23 -5
  177. package/src/lib/channels/webhook-channel.js +38 -15
  178. package/src/lib/chrome-connector.js +169 -23
  179. package/src/lib/config-manager.js +23 -9
  180. package/src/lib/context-breakdown.js +31 -0
  181. package/src/lib/cowork-cron.js +274 -32
  182. package/src/lib/cross-chain-mtc.js +3 -2
  183. package/src/lib/durable-security-store.js +124 -0
  184. package/src/lib/event-runtime-host.js +67 -6
  185. package/src/lib/event-runtime-store.js +163 -0
  186. package/src/lib/goal-store.js +32 -12
  187. package/src/lib/headless-manifest.js +2 -1
  188. package/src/lib/hook-environment.cjs +58 -0
  189. package/src/lib/hook-manager.js +12 -5
  190. package/src/lib/hook-runner.cjs +122 -28
  191. package/src/lib/hook-runner.js +1 -0
  192. package/src/lib/hooks-v2-producers.js +36 -0
  193. package/src/lib/hooks-v2-runtime.js +329 -52
  194. package/src/lib/interaction-adapter.js +60 -19
  195. package/src/lib/interaction-binding.js +64 -0
  196. package/src/lib/json-schema-output.js +439 -14
  197. package/src/lib/json-schema-validate.js +514 -883
  198. package/src/lib/lan-pairing-tokens.js +115 -57
  199. package/src/lib/lsp/__tests__/lsp-client.test.js +32 -0
  200. package/src/lib/lsp/__tests__/lsp-manager.test.js +25 -0
  201. package/src/lib/lsp/lsp-client.js +4 -0
  202. package/src/lib/lsp/lsp-manager.js +3 -0
  203. package/src/lib/lsp/lsp-server-registry.js +18 -0
  204. package/src/lib/mcp-client.js +1 -0
  205. package/src/lib/mcp-oauth.js +35 -21
  206. package/src/lib/packer/pkg-config-generator.js +1 -0
  207. package/src/lib/permission-decision.js +99 -0
  208. package/src/lib/plugin-monitor-supervisor.js +3 -0
  209. package/src/lib/plugin-runtime/capabilities.js +50 -0
  210. package/src/lib/plugin-runtime/capability-consent.js +42 -35
  211. package/src/lib/plugin-runtime/hooks.js +36 -9
  212. package/src/lib/plugin-runtime/install.js +23 -7
  213. package/src/lib/plugin-runtime/lsp.js +4 -0
  214. package/src/lib/plugin-runtime/manifest.js +50 -2
  215. package/src/lib/plugin-runtime/mcp.js +30 -5
  216. package/src/lib/plugin-runtime/monitors.js +11 -0
  217. package/src/lib/plugin-runtime/plugin-options.js +94 -38
  218. package/src/lib/plugin-runtime/policy.js +29 -2
  219. package/src/lib/plugin-runtime/sandbox-policy.js +84 -0
  220. package/src/lib/plugin-runtime/scopes.js +7 -3
  221. package/src/lib/plugin-runtime/trust.js +36 -31
  222. package/src/lib/process-execution-broker/credential-agent.js +114 -16
  223. package/src/lib/process-execution-broker/credential-transport-worker.js +312 -0
  224. package/src/lib/process-execution-broker/credential-transport.js +378 -0
  225. package/src/lib/process-execution-broker/index.js +408 -19
  226. package/src/lib/process-execution-broker/platform-sandbox.js +561 -21
  227. package/src/lib/process-execution-broker/windows-sandbox.ps1 +999 -0
  228. package/src/lib/project-mcp-trust.js +21 -26
  229. package/src/lib/protocol-replay.js +19 -12
  230. package/src/lib/settings-hooks.cjs +13 -0
  231. package/src/lib/skill-loader.js +83 -10
  232. package/src/lib/sync-credentials.js +5 -4
  233. package/src/lib/turn-binding.js +8 -6
  234. package/src/repl/agent-repl.js +113 -28
  235. package/src/repl/repl-turn-binding.js +5 -2
  236. package/src/runtime/agent-core.js +331 -26
  237. package/src/runtime/coding-agent-contract-shared.cjs +3 -3
  238. package/src/runtime/headless-runner.js +101 -4
  239. package/src/runtime/headless-stream.js +209 -23
  240. package/src/runtime/mcp-config.js +29 -17
  241. package/src/runtime/policies/agent-policy.js +2 -0
  242. package/src/workers/background-agent-worker.js +128 -13
  243. package/src/assets/web-panel/assets/Projects-BbgmyQnS.js +0 -1
  244. package/src/assets/web-panel/assets/RemoteSession-Bqk3EYSu.js +0 -4
  245. package/src/assets/web-panel/assets/Tasks-3bDAUz8K.js +0 -1
  246. package/src/assets/web-panel/assets/chat-CJ19O6Dh.js +0 -1
  247. package/src/assets/web-panel/assets/devWarning-BBMFnsja.js +0 -1
  248. package/src/assets/web-panel/assets/index-Do8JMV4N.js +0 -1
  249. package/src/assets/web-panel/assets/index-UYAJ6iNM.js +0 -1
@@ -13,12 +13,16 @@
13
13
  * Store: ~/.chainlesschain/trusted-project-mcp.json { [absPath]: {fingerprint, trustedAt} }
14
14
  */
15
15
 
16
- import fs from "node:fs";
17
16
  import path from "node:path";
18
17
  import { createHash } from "node:crypto";
19
18
  import { getHomeDir } from "./paths.js";
19
+ import { withFileLock } from "./with-file-lock.js";
20
+ import {
21
+ mutateSecurityStore,
22
+ readSecurityStore,
23
+ } from "./durable-security-store.js";
20
24
 
21
- export const _deps = { fs };
25
+ export const _deps = { withFileLock };
22
26
 
23
27
  function storePath(opts = {}) {
24
28
  return (
@@ -33,13 +37,7 @@ export function projectMcpFingerprint(content) {
33
37
  }
34
38
 
35
39
  function readStore(opts) {
36
- try {
37
- const raw = _deps.fs.readFileSync(storePath(opts), "utf-8");
38
- const data = JSON.parse(raw);
39
- return data && typeof data === "object" ? data : {};
40
- } catch {
41
- return {};
42
- }
40
+ return readSecurityStore(storePath(opts), "project MCP trust");
43
41
  }
44
42
 
45
43
  /**
@@ -61,23 +59,20 @@ export function checkProjectMcpTrust(file, content, opts = {}) {
61
59
  /** Record (or re-record) the trusted fingerprint for a file. */
62
60
  export function recordProjectMcpTrust(file, content, opts = {}) {
63
61
  const target = storePath(opts);
64
- const store = readStore(opts);
65
- store[path.resolve(file)] = {
66
- fingerprint: projectMcpFingerprint(content),
67
- trustedAt: new Date(
68
- typeof opts.now === "number" ? opts.now : Date.now(),
69
- ).toISOString(),
70
- };
71
- try {
72
- _deps.fs.mkdirSync(path.dirname(target), { recursive: true });
73
- _deps.fs.writeFileSync(target, JSON.stringify(store, null, 2), {
74
- encoding: "utf-8",
75
- mode: 0o600,
76
- });
77
- return true;
78
- } catch {
79
- return false; // best-effort — a failed record just re-prompts next run
80
- }
62
+ return mutateSecurityStore(
63
+ target,
64
+ "project MCP trust",
65
+ (store) => {
66
+ store[path.resolve(file)] = {
67
+ fingerprint: projectMcpFingerprint(content),
68
+ trustedAt: new Date(
69
+ typeof opts.now === "number" ? opts.now : Date.now(),
70
+ ).toISOString(),
71
+ };
72
+ return true;
73
+ },
74
+ { lock: _deps.withFileLock },
75
+ );
81
76
  }
82
77
 
83
78
  /** Truthy CC_PROJECT_MCP_TRUST → the user explicitly re-trusts this run. */
@@ -15,10 +15,11 @@
15
15
  * client must never receive a vN+1 field; a recording that violates that is
16
16
  * a compat bug this catches deterministically, offline, in CI.
17
17
  *
18
- * The set of gateable wire fields ({seq, trace_id, tool_use_id}) is projected
19
- * from the ONE canonical [[capability-manifest.js]] via `toFieldGate()` — it can
20
- * NOT drift from the negotiated feature list. All non-negotiable frame fields
21
- * (type, content, tool name, …) always pass through untouched.
18
+ * The gateable wire fields are projected from the ONE canonical
19
+ * [[capability-manifest.js]] via `toGateableFieldGate()` — including companion
20
+ * fields controlled by the same logical feature. They cannot drift from the
21
+ * negotiated feature list. All non-negotiable frame fields (type, content,
22
+ * tool name, …) always pass through untouched.
22
23
  *
23
24
  * PURE + deterministic: no fs / process / clock / RNG. The `digest` lets a golden
24
25
  * recording be pinned so any change to negotiation/gating that alters wire output
@@ -30,13 +31,19 @@ import {
30
31
  negotiateProtocol,
31
32
  applyNegotiationToGate,
32
33
  } from "./capability-negotiation.js";
33
- import { toFieldGate } from "./capability-manifest.js";
34
+ import { toGateableFieldGate } from "./capability-manifest.js";
34
35
 
35
- /** Negotiable wire field names ({seq, trace_id, tool_use_id}), single-sourced. */
36
+ /** Negotiable wire field primary gate field, single-sourced. */
37
+ const GATEABLE_FIELD_GATE = Object.freeze(toGateableFieldGate());
38
+
39
+ /** Every negotiable wire field name, including same-feature companions. */
36
40
  export const GATEABLE_FIELDS = Object.freeze(
37
- [...new Set(Object.values(toFieldGate()))].sort(),
41
+ Object.keys(GATEABLE_FIELD_GATE).sort(),
38
42
  );
39
43
 
44
+ const gateOn = (gate, field) =>
45
+ gate[GATEABLE_FIELD_GATE[field] || field] === true;
46
+
40
47
  /**
41
48
  * Run negotiation and fold it into a per-field gate the replay/audit read.
42
49
  * On an incompatible (ok:false) negotiation the gate stays empty → every gateable
@@ -50,8 +57,8 @@ export const GATEABLE_FIELDS = Object.freeze(
50
57
  export function gateFromNegotiation({ server = {}, client = null } = {}) {
51
58
  const negotiation = negotiateProtocol(server, client ?? null);
52
59
  const gate = applyNegotiationToGate(negotiation, {});
53
- const enabledFields = GATEABLE_FIELDS.filter((f) => gate[f] === true);
54
- const gatedFields = GATEABLE_FIELDS.filter((f) => gate[f] !== true);
60
+ const enabledFields = GATEABLE_FIELDS.filter((f) => gateOn(gate, f));
61
+ const gatedFields = GATEABLE_FIELDS.filter((f) => !gateOn(gate, f));
55
62
  return { negotiation, gate, enabledFields, gatedFields };
56
63
  }
57
64
 
@@ -61,14 +68,14 @@ export function gateFromNegotiation({ server = {}, client = null } = {}) {
61
68
  * Returns a shallow copy — the input frame is never mutated.
62
69
  *
63
70
  * @param {object} frame
64
- * @param {object} gate {seq?:boolean, trace_id?:boolean, tool_use_id?:boolean}
71
+ * @param {object} gate negotiated primary-field gate
65
72
  * @returns {object}
66
73
  */
67
74
  export function replayFrame(frame, gate = {}) {
68
75
  if (!frame || typeof frame !== "object") return frame;
69
76
  const out = {};
70
77
  for (const [k, v] of Object.entries(frame)) {
71
- if (GATEABLE_FIELDS.includes(k) && gate[k] !== true) continue;
78
+ if (GATEABLE_FIELDS.includes(k) && !gateOn(gate, k)) continue;
72
79
  out[k] = v;
73
80
  }
74
81
  return out;
@@ -116,7 +123,7 @@ export function auditRecordedSession(frames, ctx = {}) {
116
123
  if (!frame || typeof frame !== "object") return;
117
124
  for (const field of GATEABLE_FIELDS) {
118
125
  if (
119
- gate[field] !== true &&
126
+ !gateOn(gate, field) &&
120
127
  Object.prototype.hasOwnProperty.call(frame, field)
121
128
  ) {
122
129
  violations.push({
@@ -256,6 +256,19 @@ function collectHooks(hooksBlock, event, toolName) {
256
256
  pluginId: h.pluginId || null,
257
257
  pluginVersion: h.pluginVersion || null,
258
258
  pluginSource: h.pluginSource || null,
259
+ ...(h.shell != null ? { shell: h.shell } : {}),
260
+ ...(h.environmentAllowlist != null
261
+ ? { environmentAllowlist: h.environmentAllowlist }
262
+ : {}),
263
+ ...(h.envAllowlist != null
264
+ ? { envAllowlist: h.envAllowlist }
265
+ : {}),
266
+ ...(h.sandboxPolicy !== undefined
267
+ ? { sandboxPolicy: h.sandboxPolicy }
268
+ : {}),
269
+ ...(h.requiredBoundaries !== undefined
270
+ ? { requiredBoundaries: h.requiredBoundaries }
271
+ : {}),
259
272
  });
260
273
  }
261
274
  }
@@ -332,6 +332,7 @@ export class CLISkillLoader {
332
332
  this._cacheStats = {
333
333
  descriptorScans: 0,
334
334
  descriptorCacheHits: 0,
335
+ descriptorUses: new Map(),
335
336
  bodyCacheHits: 0,
336
337
  bodyCacheMisses: 0,
337
338
  bodyLoads: new Map(),
@@ -579,10 +580,16 @@ export class CLISkillLoader {
579
580
  estimatedTokens: cached.estimatedTokens,
580
581
  loads: 0,
581
582
  cacheHits: 0,
583
+ contextLoads: 0,
584
+ contextCacheHits: 0,
582
585
  loadedBecause: [],
583
586
  };
584
587
  prior.loads += 1;
585
588
  if (cacheRead) prior.cacheHits += 1;
589
+ if (context.bodyIncluded === true) {
590
+ prior.contextLoads += 1;
591
+ if (cacheRead) prior.contextCacheHits += 1;
592
+ }
586
593
  const reason = context.loadedBecause || "explicit";
587
594
  if (!prior.loadedBecause.includes(reason)) prior.loadedBecause.push(reason);
588
595
  this._cacheStats.bodyLoads.set(skill.skillMdPath, prior);
@@ -594,12 +601,17 @@ export class CLISkillLoader {
594
601
  sourceType: "skill",
595
602
  sourceId: skill.id,
596
603
  permissionMode: context.permissionMode || "agent",
597
- tokenCount: cached.estimatedTokens,
604
+ // Only text that actually entered a model prompt consumes context
605
+ // tokens. Ordinary run_skill materialization is still recorded, but
606
+ // as a content-size/cache observation rather than a false token charge.
607
+ tokenCount:
608
+ context.bodyIncluded === true ? cached.estimatedTokens : 0,
598
609
  metadata: {
599
610
  source: skill.source,
600
611
  loadedBecause: reason,
601
612
  cacheRead,
602
613
  bodyIncluded: context.bodyIncluded === true,
614
+ estimatedBodyTokens: cached.estimatedTokens,
603
615
  },
604
616
  });
605
617
  } catch {
@@ -612,6 +624,22 @@ export class CLISkillLoader {
612
624
  recordDescriptorUse(skills, context = {}) {
613
625
  for (const skill of Array.isArray(skills) ? skills : []) {
614
626
  const descriptorText = `${skill.id}\n${skill.description || ""}\n${skill.category || ""}`;
627
+ const estimatedTokens = estimateSkillTokens(descriptorText);
628
+ const prior = this._cacheStats.descriptorUses.get(skill.id) || {
629
+ id: skill.id,
630
+ source: skill.source,
631
+ estimatedTokens,
632
+ contextLoads: 0,
633
+ contextTokens: 0,
634
+ loadedBecause: [],
635
+ };
636
+ prior.contextLoads += 1;
637
+ prior.contextTokens += estimatedTokens;
638
+ const reason = context.loadedBecause || "list_skills";
639
+ if (!prior.loadedBecause.includes(reason)) {
640
+ prior.loadedBecause.push(reason);
641
+ }
642
+ this._cacheStats.descriptorUses.set(skill.id, prior);
615
643
  try {
616
644
  this._contextLedger?.recordRead?.({
617
645
  sessionId: context.sessionId || "unknown",
@@ -619,10 +647,10 @@ export class CLISkillLoader {
619
647
  sourceType: "skill_descriptor",
620
648
  sourceId: skill.id,
621
649
  permissionMode: context.permissionMode || "agent",
622
- tokenCount: estimateSkillTokens(descriptorText),
650
+ tokenCount: estimatedTokens,
623
651
  metadata: {
624
652
  source: skill.source,
625
- loadedBecause: context.loadedBecause || "list_skills",
653
+ loadedBecause: reason,
626
654
  bodyLoaded: skill.bodyLoaded === true,
627
655
  },
628
656
  });
@@ -635,10 +663,28 @@ export class CLISkillLoader {
635
663
  /** Content-free cache/cost snapshot for `cc context --sources`. */
636
664
  getCacheLedger() {
637
665
  const descriptors = Array.isArray(this._cache) ? this._cache : [];
638
- const descriptorChars = descriptors.reduce(
639
- (sum, skill) =>
640
- sum +
641
- `${skill.id}\n${skill.displayName}\n${skill.description}\n${skill.category}`.length,
666
+ const descriptorEntries = descriptors.map((skill) => {
667
+ const descriptorText = `${skill.id}\n${skill.displayName}\n${skill.description}\n${skill.category}`;
668
+ const used = this._cacheStats.descriptorUses.get(skill.id);
669
+ return {
670
+ id: skill.id,
671
+ source: skill.source,
672
+ estimatedTokens: estimateSkillTokens(descriptorText),
673
+ contextLoads: Number(used?.contextLoads) || 0,
674
+ contextTokens: Number(used?.contextTokens) || 0,
675
+ loadedBecause: [...(used?.loadedBecause || [])],
676
+ };
677
+ });
678
+ const descriptorTokens = descriptorEntries.reduce(
679
+ (sum, entry) => sum + entry.estimatedTokens,
680
+ 0,
681
+ );
682
+ const descriptorContextLoads = descriptorEntries.reduce(
683
+ (sum, entry) => sum + entry.contextLoads,
684
+ 0,
685
+ );
686
+ const descriptorContextTokens = descriptorEntries.reduce(
687
+ (sum, entry) => sum + entry.contextTokens,
642
688
  0,
643
689
  );
644
690
  const residentPaths = new Set(this._bodyCache.keys());
@@ -649,20 +695,46 @@ export class CLISkillLoader {
649
695
  0,
650
696
  );
651
697
  const bodyLoads = Array.from(this._cacheStats.bodyLoads.values()).map(
652
- (entry) => ({ ...entry, loadedBecause: [...entry.loadedBecause] }),
698
+ (entry) => ({
699
+ ...entry,
700
+ cacheMisses: Math.max(0, entry.loads - entry.cacheHits),
701
+ contextTokens: entry.estimatedTokens * entry.contextLoads,
702
+ loadedBecause: [...entry.loadedBecause],
703
+ }),
704
+ );
705
+ const bodyTotals = bodyLoads.reduce(
706
+ (totals, entry) => {
707
+ totals.estimatedTokensResident += entry.estimatedTokens;
708
+ totals.estimatedTokensServed += entry.estimatedTokens * entry.loads;
709
+ totals.estimatedTokensAvoidedByCache +=
710
+ entry.estimatedTokens * entry.cacheHits;
711
+ totals.contextLoads += entry.contextLoads;
712
+ totals.contextTokens += entry.contextTokens;
713
+ return totals;
714
+ },
715
+ {
716
+ estimatedTokensResident: 0,
717
+ estimatedTokensServed: 0,
718
+ estimatedTokensAvoidedByCache: 0,
719
+ contextLoads: 0,
720
+ contextTokens: 0,
721
+ },
653
722
  );
654
723
  return {
655
724
  descriptors: {
656
725
  resident: descriptors.length,
657
726
  scans: this._cacheStats.descriptorScans,
658
727
  cacheHits: this._cacheStats.descriptorCacheHits,
659
- rawChars: descriptorChars,
660
- estimatedTokens: estimateSkillTokens(descriptorChars),
728
+ estimatedTokens: descriptorTokens,
729
+ contextLoads: descriptorContextLoads,
730
+ contextTokens: descriptorContextTokens,
731
+ entries: descriptorEntries,
661
732
  },
662
733
  bodies: {
663
734
  resident: this._bodyCache.size,
664
735
  cacheHits: this._cacheStats.bodyCacheHits,
665
736
  cacheMisses: this._cacheStats.bodyCacheMisses,
737
+ ...bodyTotals,
666
738
  entries: bodyLoads,
667
739
  },
668
740
  savings: {
@@ -770,6 +842,7 @@ export class CLISkillLoader {
770
842
  this._cacheStats = {
771
843
  descriptorScans: 0,
772
844
  descriptorCacheHits: 0,
845
+ descriptorUses: new Map(),
773
846
  bodyCacheHits: 0,
774
847
  bodyCacheMisses: 0,
775
848
  bodyLoads: new Map(),
@@ -214,14 +214,15 @@ function setCredentials(providerId, creds) {
214
214
  if (!creds || typeof creds !== "object") {
215
215
  throw new Error("sync-credentials: creds must be an object");
216
216
  }
217
- // Serialize the decrypt-modify-encrypt across processes so a concurrent write
218
- // to a different provider doesn't drop this one (best-effort, never hangs).
217
+ // Credential metadata is security-critical: never decrypt-modify-encrypt
218
+ // without exclusion, because a lost update can silently restore/revoke the
219
+ // wrong provider credentials.
219
220
  return withFileLock(_vaultPath(), () => {
220
221
  const all = loadAll();
221
222
  if (!all.sync || typeof all.sync !== "object") all.sync = {};
222
223
  all.sync[providerId] = { ...creds };
223
224
  return saveAll(all);
224
- });
225
+ }, { failIfUnavailable: true });
225
226
  }
226
227
 
227
228
  function clearCredentials(providerId) {
@@ -233,7 +234,7 @@ function clearCredentials(providerId) {
233
234
  return saveAll(all);
234
235
  }
235
236
  return true;
236
- });
237
+ }, { failIfUnavailable: true });
237
238
  }
238
239
 
239
240
  /** Test seam: override the resolved chainlesschain dir without env leak. */
@@ -555,12 +555,14 @@ export function createTurnBindingFeed({
555
555
  // New core events expose the exact decision id. Legacy/custom event
556
556
  // sources retain the deterministic compatibility derivation.
557
557
  const policy = event.result?.policy;
558
- if (policy && (policy.via || policy.decision)) {
559
- log.recordPermissionDecision(
560
- turnId,
561
- event.permission_decision_id ||
562
- `${callId || "call"}:perm:${policy.via || policy.decision}`,
563
- );
558
+ const decisionId =
559
+ event.permission_decision_id ||
560
+ event.permission_decision?.id ||
561
+ (policy && (policy.via || policy.decision)
562
+ ? `${callId || "call"}:perm:${policy.via || policy.decision}`
563
+ : null);
564
+ if (decisionId) {
565
+ log.recordPermissionDecision(turnId, decisionId);
564
566
  dirty = true;
565
567
  }
566
568
  if (event.result?.userEdited === true) {
@@ -48,9 +48,11 @@ import {
48
48
  appendCompactEvent,
49
49
  appendTokenUsage,
50
50
  appendToolCallCompact,
51
+ appendEvent,
51
52
  rebuildMessages,
52
53
  sessionExists,
53
54
  } from "../harness/jsonl-session-store.js";
55
+ import { CLISkillLoader } from "../lib/skill-loader.js";
54
56
  import { storeMemory, consolidateMemory } from "../lib/hierarchical-memory.js";
55
57
  import { CLIContextEngineering } from "../lib/cli-context-engineering.js";
56
58
  import { defaultPrepareCall } from "../lib/turn-context.js";
@@ -64,6 +66,7 @@ import { CLIPermanentMemory } from "../lib/permanent-memory.js";
64
66
  import { CLIAutonomousAgent, GoalStatus } from "../lib/autonomous-agent.js";
65
67
  import {
66
68
  PromptCompressor,
69
+ estimateTokens,
67
70
  getContextWindow,
68
71
  } from "../harness/prompt-compressor.js";
69
72
  import {
@@ -1088,20 +1091,31 @@ export async function startAgentRepl(options = {}) {
1088
1091
  // their existing behaviour byte-identically.
1089
1092
  const _leanNoProjectMemory = options.projectMemory === false;
1090
1093
  let _loadedReplInstructions = null;
1091
- let _replBaseSystem = composeSystemPrompt(
1092
- buildSystemPrompt(process.cwd(), {
1093
- additionalDirectories,
1094
- projectMemory: options.projectMemory,
1095
- }),
1096
- {
1097
- systemPrompt: options.systemPrompt,
1098
- appendSystemPrompt: options.appendSystemPrompt,
1099
- projectMemory: _leanNoProjectMemory ? false : undefined,
1100
- onInstructionsLoaded: (loaded) => {
1101
- _loadedReplInstructions = loaded;
1094
+ let _loadedReplPersonaSkills = [];
1095
+ let _replSkillCacheLedger = null;
1096
+ const _replSkillLoader = options.skillLoader || new CLISkillLoader();
1097
+ const _buildReplBaseSystem = () =>
1098
+ composeSystemPrompt(
1099
+ buildSystemPrompt(process.cwd(), {
1100
+ additionalDirectories,
1101
+ projectMemory: options.projectMemory,
1102
+ sessionId,
1103
+ skillLoader: _replSkillLoader,
1104
+ onSkillsLoaded: (skills, cacheLedger) => {
1105
+ _loadedReplPersonaSkills = Array.isArray(skills) ? skills : [];
1106
+ _replSkillCacheLedger = cacheLedger || null;
1107
+ },
1108
+ }),
1109
+ {
1110
+ systemPrompt: options.systemPrompt,
1111
+ appendSystemPrompt: options.appendSystemPrompt,
1112
+ projectMemory: _leanNoProjectMemory ? false : undefined,
1113
+ onInstructionsLoaded: (loaded) => {
1114
+ _loadedReplInstructions = loaded;
1115
+ },
1102
1116
  },
1103
- },
1104
- );
1117
+ );
1118
+ let _replBaseSystem = _buildReplBaseSystem();
1105
1119
  let _activeOutputStyle = null; // { name, body }
1106
1120
  const messages = [{ role: "system", content: _replBaseSystem }];
1107
1121
  // Resume-degenerate role sanitation (Claude Code 2.1.187 parity): a one-shot
@@ -1184,6 +1198,46 @@ export async function startAgentRepl(options = {}) {
1184
1198
  // for this session via the shared mcp-config engine. Holds {mcpClient,
1185
1199
  // extraToolDefinitions, externalToolExecutors, externalToolDescriptors}.
1186
1200
  let _adhocMcp = null;
1201
+ const _persistReplContextSources = () => {
1202
+ if (!useJsonl || !sessionId) return false;
1203
+ _replSkillCacheLedger =
1204
+ _replSkillLoader.getCacheLedger?.() || _replSkillCacheLedger;
1205
+ const mcpDefinitions = _adhocMcp?.extraToolDefinitions || [];
1206
+ if (
1207
+ mcpDefinitions.length === 0 &&
1208
+ _loadedReplPersonaSkills.length === 0 &&
1209
+ !_replSkillCacheLedger?.descriptors?.resident
1210
+ ) {
1211
+ return false;
1212
+ }
1213
+ try {
1214
+ appendEvent(sessionId, "context_sources", {
1215
+ mcp: mcpDefinitions.map((definition) => ({
1216
+ function: {
1217
+ name: definition?.function?.name || null,
1218
+ description: definition?.function?.description || "",
1219
+ parameters: definition?.function?.parameters || {},
1220
+ },
1221
+ })),
1222
+ skills: _loadedReplPersonaSkills.map((skill) => ({
1223
+ id: skill?.id || skill?.displayName || "skill",
1224
+ displayName: skill?.displayName || skill?.id || "skill",
1225
+ source: skill?.source || "skill",
1226
+ tokens: estimateTokens(
1227
+ `## Persona: ${skill?.displayName || skill?.id || "skill"}\n${
1228
+ typeof skill?.body === "string" ? skill.body : ""
1229
+ }`,
1230
+ ),
1231
+ bodyLoaded: skill?.bodyLoaded === true,
1232
+ })),
1233
+ skillCache: _replSkillCacheLedger,
1234
+ });
1235
+ return true;
1236
+ } catch {
1237
+ // Source attribution must never make an interactive turn fail.
1238
+ return false;
1239
+ }
1240
+ };
1187
1241
  if (options.bundlePath) {
1188
1242
  try {
1189
1243
  const { loadBundle } =
@@ -1338,6 +1392,7 @@ export async function startAgentRepl(options = {}) {
1338
1392
  _adhocMcp = null;
1339
1393
  }
1340
1394
  }
1395
+ _persistReplContextSources();
1341
1396
 
1342
1397
  // Seed connected MCP servers with the startup workspace roots when the session
1343
1398
  // began with extra `--add-dir` roots — otherwise `roots/list` would only ever
@@ -1779,6 +1834,36 @@ export async function startAgentRepl(options = {}) {
1779
1834
  new Promise((resolve) => {
1780
1835
  const label =
1781
1836
  request.message || "MCP server requests additional input";
1837
+ if (request.mode === "url") {
1838
+ rl.question(
1839
+ chalk.yellow(
1840
+ `\n MCP [${request.server}] ${label}\n` +
1841
+ ` Host: ${request.urlHost}\n` +
1842
+ ` URL: ${request.url}\n` +
1843
+ " Open this secure page? [y/N] ",
1844
+ ),
1845
+ async (answer) => {
1846
+ const approved = /^(y|yes)$/i.test(
1847
+ String(answer || "").trim(),
1848
+ );
1849
+ if (!approved) {
1850
+ resolve({ action: "decline" });
1851
+ rl.prompt();
1852
+ return;
1853
+ }
1854
+ try {
1855
+ const { defaultOpenBrowser } =
1856
+ await import("../lib/mcp-oauth.js");
1857
+ const opened = defaultOpenBrowser(request.url);
1858
+ resolve(opened ? { action: "accept" } : { action: "cancel" });
1859
+ } catch {
1860
+ resolve({ action: "cancel" });
1861
+ }
1862
+ rl.prompt();
1863
+ },
1864
+ );
1865
+ return;
1866
+ }
1782
1867
  rl.question(
1783
1868
  chalk.yellow(`\n MCP [${request.server}] ${label}\n > `),
1784
1869
  (answer) => {
@@ -2531,17 +2616,7 @@ export async function startAgentRepl(options = {}) {
2531
2616
  additionalDirectories.push(res.dir);
2532
2617
  // Re-advertise the updated roots in the system prompt; keep the
2533
2618
  // active output-style body layered on top (same as /output-style).
2534
- _replBaseSystem = composeSystemPrompt(
2535
- buildSystemPrompt(process.cwd(), {
2536
- additionalDirectories,
2537
- projectMemory: options.projectMemory,
2538
- }),
2539
- {
2540
- systemPrompt: options.systemPrompt,
2541
- appendSystemPrompt: options.appendSystemPrompt,
2542
- projectMemory: _leanNoProjectMemory ? false : undefined,
2543
- },
2544
- );
2619
+ _replBaseSystem = _buildReplBaseSystem();
2545
2620
  messages[0].content = _activeOutputStyle
2546
2621
  ? `${_replBaseSystem}\n\n${_activeOutputStyle.body}`
2547
2622
  : _replBaseSystem;
@@ -3709,11 +3784,16 @@ export async function startAgentRepl(options = {}) {
3709
3784
  // layers (incl. .claude/skills) without restarting the session.
3710
3785
  if (trimmed === "/reload-skills") {
3711
3786
  try {
3712
- const { reloadSkills } = await import("../runtime/agent-core.js");
3713
- const n = reloadSkills();
3787
+ _replSkillLoader.clearCache();
3788
+ const n = _replSkillLoader.loadAll().length;
3789
+ _replBaseSystem = _buildReplBaseSystem();
3790
+ messages[0].content = _activeOutputStyle
3791
+ ? `${_replBaseSystem}\n\n${_activeOutputStyle.body}`
3792
+ : _replBaseSystem;
3793
+ _persistReplContextSources();
3714
3794
  logger.log(
3715
3795
  chalk.green(
3716
- `✔ skills reloaded — ${n} available (6 layers re-scanned)`,
3796
+ `✔ skills reloaded — ${n} available (${_replSkillLoader.getLayerPaths().length} layers re-scanned)`,
3717
3797
  ),
3718
3798
  );
3719
3799
  } catch (err) {
@@ -5311,7 +5391,9 @@ export async function startAgentRepl(options = {}) {
5311
5391
  },
5312
5392
  });
5313
5393
  }
5314
- _turnBindingProducer?.beginTurn(messages.length);
5394
+ _turnBindingProducer?.beginTurn(messages.length, {
5395
+ worktreeId: options.worktreeId ?? null,
5396
+ });
5315
5397
  } catch (error) {
5316
5398
  _turnBindingCriticalError =
5317
5399
  error instanceof Error ? error : new Error(String(error));
@@ -5527,6 +5609,7 @@ export async function startAgentRepl(options = {}) {
5527
5609
  contextEngine,
5528
5610
  iterationBudget,
5529
5611
  sessionId,
5612
+ skillLoader: _replSkillLoader,
5530
5613
  cwd: process.cwd(),
5531
5614
  additionalDirectories,
5532
5615
  sandbox: _sandbox,
@@ -5568,6 +5651,7 @@ export async function startAgentRepl(options = {}) {
5568
5651
  externalToolDescriptors: _adhocMcp?.externalToolDescriptors,
5569
5652
  chatFn: _fallbackChatFn,
5570
5653
  });
5654
+ _persistReplContextSources();
5571
5655
  _turnAbort = null;
5572
5656
 
5573
5657
  // Strip the one-shot /btw aside now the model has seen it — so it is never
@@ -5933,6 +6017,7 @@ export async function startAgentRepl(options = {}) {
5933
6017
  if (sessionId) {
5934
6018
  try {
5935
6019
  if (useJsonl) {
6020
+ _persistReplContextSources();
5936
6021
  // JSONL: write final compact snapshot for fast rebuild
5937
6022
  appendCompactEvent(sessionId, {
5938
6023
  strategy: "session-end",
@@ -71,7 +71,7 @@ export function createReplTurnBindingProducer({
71
71
  * appended, with `conversationOffset = messages.length` — the exact-match
72
72
  * contract `pickPersistedTurn` relies on.
73
73
  */
74
- beginTurn(conversationOffset) {
74
+ beginTurn(conversationOffset, { worktreeId = null } = {}) {
75
75
  try {
76
76
  if (!feed) {
77
77
  feed = createTurnBindingFeed({
@@ -79,7 +79,10 @@ export function createReplTurnBindingProducer({
79
79
  nonce: runNonce,
80
80
  });
81
81
  }
82
- return feed.beginTurn(conversationOffset, { supersede: true });
82
+ return feed.beginTurn(conversationOffset, {
83
+ supersede: true,
84
+ worktreeId,
85
+ });
83
86
  } catch (error) {
84
87
  return rejectOr(error, "load", null);
85
88
  }