chainlesschain 0.162.179 → 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 (251) 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-BF13YdB-.js → AIOps-cq0dwbnf.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-B9y67AjF.js → ActionButton-CvcgGl3w.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-FcdDHoSC.js → Analytics-hM2-jFqg.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-CRm_zwSp.js → AppLayout-B9_Gsd_g.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-Cbo7-usf.js → Artifacts-B7bu52Og.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-vMaLpkHC.js → Audit-DThfDgqB.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-FiUY692t.js → BackgroundAgents-DjlFiD4v.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-BK80j_GQ.js → Backup-CK9xJKnG.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-ChNMuYR1.js → BaseInput-DEiSU8K8.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-928UREpm.js → Chat-CpT96czj.js} +5 -5
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-BKPPNmZI.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-dFW-zDbe.js → Checkbox-C1GfDnO0.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-BCcNJUj2.js → Codegen-3DAKgiLx.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-DcEkLv70.js → Col-74cOwZU1.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-DihBRRqg.js → Community-tn9Kkz9j.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-DGYxwWET.js → Compact-BcoXH7m4.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-OnYe1vS4.js → Compliance-DIPGUBgi.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-CmWB54c2.js → Cowork-doD5_91c.js} +2 -2
  21. package/src/assets/web-panel/assets/{Cron-BrANb2uw.js → Cron-C-IDvubz.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-2HgWzSxg.js → Crosschain-CdcCoBdj.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-DdDwNI6K.js → DID-DdH5aMMA.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-D6PnE78-.js → Dashboard-DHLA4mm0.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-ClzvSN4O.js → Dropdown-dEeCt7Md.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-BUk9B727.js → EmailListRenderer-BMaecFv9.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-C8hi3v7i.js → FamilyGuardDashboard-DUaUukTN.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-B5SP8xkg.js → Federation-CMBE0_rp.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-DWzJ8AU5.js → FormItemContext-PG-JDbXq.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-3E3Q3rjG.js → GenericCardRenderer-Bcb0p88m.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-z8IdCMId.js → Git-Bgv15myB.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-CgqCF9lX.js → Governance-DB8YTArI.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-zgS-AuH9.js → Inference-BQMwCWaS.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-BdbgmESJ.js → KnowledgeGraph-B1_ZziiB.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-BHpknnjy.js → Logs-DovEEnt_.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-D201OL4T.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-Di9sAR7j.js → Marketplace-BlCXSpyB.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-DtnR9Z_A.js → McpTools-CsCR09Wj.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-BaX9uuXD.js → Memory-CBVRLKno.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-xelyKWTY.js → MobileBridge-C9OIafgA.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-BiFTOGBN.js → MobileProjects-D_zoJ8Xs.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-bV3OzTiO.js → Mtc-vE-HdvLj.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-BkwvFTdZ.js → MtcAudit-CPLaekCd.js} +2 -2
  44. package/src/assets/web-panel/assets/{Multisig-_6HQQ-oC.js → Multisig-C_UP9C2o.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-BBYhmWQZ.js → NLProgramming-2nODJcU1.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-Cq-6dQnU.js → Notes-BhE-SJGu.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-ILZ9zkX6.js → NotificationSettings-D21q7BNU.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-DgmTBEvk.js → OrderTableRenderer-0b62GYOD.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-CkLnWwCk.js → Organization-CEqmw_sb.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-CWVHZbhf.js → Overflow-MW-gMDO_.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-BXbqETkr.js → P2P-CY0hjI_G.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser--0JR-0ex.js → PdhVaultBrowser-BbWh7Man.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-Cz9_tfSy.js → Permissions-ChqEA_4Q.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-Dq7OWYtx.js → PersonalDataHub-B3YrbYfD.js} +5 -5
  55. package/src/assets/web-panel/assets/{Pipeline-DHPUNcc-.js → Pipeline-B8WBhhlW.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-CEAbrDkS.js → Privacy-Cmb0PXNx.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-CJYfclXE.js → ProjectInit-hF6zW3Nz.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-oCTgPCgp.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-BLTZtzTG.js → Providers-B8yux8Dx.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-C0b0TQB3.js → QrScannerModal-N76cQluO.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-tOl6N_gM.js → QuickAsk-ClvZ0KYR.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-DPzKr8yr.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-Cji1Vl79.js → Reputation-DJIZzQeG.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-D-NERWf2.js → Row-COzxu_bb.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-DzlgmAlB.js → RssFeed-CoYsJQuE.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-Cs0SWSa4.js → Search-DC77Mq9S.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-DL7EzcUO.js → Security-Loy2EdMO.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-CT-PzgTd.js → Services-GUD07Eu0.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-tByJWdJg.js → Skeleton-DWzkptYU.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-Dnr_6TTl.js → Skills-CEDn1r-Z.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-4O-yq0LY.js → Sla-ub_k4pXh.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-BYBVg1oR.js → SpeechSettings-D7HLX9CA.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-CpOYPbE5.js → SyncSettings-DbwOvl6m.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-CGVhOVh6.js → Tasks-CBQzoAu5.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-BuHFxR4X.js → Templates-BNVeIhud.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-DxDxHzgf.js → Tenant-PS9AzhXU.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-B9g_nISg.js → Terminal-Cgb4eLB_.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-DlrBC_4A.js → TimelineRenderer-CrmXMOkg.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-DvBlYZ6i.js → Tokens-DD-VDHw1.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-Dg8G9bhF.js → Trigger-BsoN_n-n.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-COICx4E-.js → Trust-n8LmN4ZV.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-B4pOBv7T.js → UkeySign-C9_7MImA.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-Qt4NMA8Q.js → VideoEditing-DyBteNgn.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-X1EkQc2Z.js → Wallet-BS5ixeXI.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-CyeEFBE5.js → WebAuthn-spc4UImU.js} +3 -3
  88. package/src/assets/web-panel/assets/{WorkflowEditor-nwzbMiVQ.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-5Isz5lhJ.js → colors-BGoCLkxI.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-DsFQS3Oy.js → compact-item-fYZBetMO.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-OcEXp2uz.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-CZvC4p09.js → hasIn-CE7ZuEnV.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BF1sab0Q.js → index--lap6cf7.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-C7yeL3rf.js → index-ATcSr_2O.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-VkFXA9N-.js → index-B2U-ObMq.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-DSmGGg5h.js → index-B3CDgvNW.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-jrNIrpq4.js → index-B4wiTEOM.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-B8ibl7bc.js → index-B8BsdNV_.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DOLozRk8.js → index-BEVm0lCS.js} +10 -10
  102. package/src/assets/web-panel/assets/{index-BPgc_bdR.js → index-BNZDILcO.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BTZZzlMO.js → index-BU_2qiDk.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Vubi6Tf5.js → index-BV551878.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-nXrnztXp.js → index-BfPL-m46.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CN8lPVpQ.js → index-BowH1eLQ.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BgE2BZl2.js → index-BsMfoaeo.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Cd5b2JHB.js → index-BunaQCa0.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CQlGw0nQ.js → index-C0v6YKKO.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Do6FJK32.js → index-C4SJVjs4.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Bqvo1f9T.js → index-C9Y3k0HI.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-LUdgPZg9.js → index-CIpVrf5P.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BpD2O7_p.js → index-CRLjEP1H.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-r_9NG6P7.js → index-CRnUE8Cb.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-FIgMAfBh.js → index-Cip8emOQ.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-RsQ1lFDV.js → index-CpIGIB85.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DGJupV0S.js → index-D1r9tT3J.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BpglwPWl.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-CG3B2wCF.js → index-De0quFDw.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CxA2PDK1.js → index-DoXk5KJ8.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DaGKOVvQ.js → index-DsvfrESp.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-C7CtJYXq.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-Bu9NXvIa.js → index-MtOuq2i6.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BsZkTaa3.js → index-Puq6Luf1.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CPE4zHXF.js → index-QIpnpZgz.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Bsb-iylv.js → index-RMZ8a7Yt.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DMtGRQqw.js → index-WUrJ6S1j.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-C3lWvhk4.js → index-YjcumOZ4.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-CmVbCGx_.js → index-lJBjB1QX.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-A5SHQW_M.js → index-ukg99D1V.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-CFJgt6qM.js → index-zb7rVOhV.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-Cdgep9YT.js → initDefaultProps-CYHMs1ag.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-7yn1ACEm.js → motion-DDB2Ffk5.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-D8o133Xc.js → move-Bg3cD-dX.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-CClHIG9V.js → mtc-parser-B5nedjTS.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-CLnrPE2d.js → omit-BHyuUILu.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-1CTWoZWl.js → pickAttrs-C9YQnEN9.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-xNNtS4Sp.js → placementArrow-DBUFYUe7.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-ypzAofs7.js → responsiveObserve-nBs2Obnk.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-QsrY9UwD.js → slide-DkCEaXNU.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-DSdThzOB.js → statusUtils-aqE1Wi6U.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-B_kKM8Ob.js → styleChecker-CN5bhfHB.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-CcdTBNV9.js → useFlexGapSupport-B_oX_kvJ.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-BuAH2XFU.js → useFs-rCuXHeme.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-B3zWiG4A.js → usePersonalDataHub-DZR9Abyd.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-B45Rc-CQ.js → vnode-ConCYQlX.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-DaYZDU5f.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/commands/hub.js +30 -24
  155. package/src/data/changelog.json +27 -1
  156. package/src/gateways/ws/background-agent-protocol.js +38 -0
  157. package/src/gateways/ws/message-dispatcher.js +1 -0
  158. package/src/gateways/ws/remote-session-protocol.js +65 -6
  159. package/src/gateways/ws/ws-server.js +8 -1
  160. package/src/harness/feature-flags.js +15 -8
  161. package/src/harness/mcp-client.js +618 -43
  162. package/src/lazy-dispatch.js +30 -1
  163. package/src/lib/agent-authority.js +22 -0
  164. package/src/lib/agent-core.js +2 -0
  165. package/src/lib/agent-sandbox.js +161 -0
  166. package/src/lib/agent-team/team-runner.js +22 -0
  167. package/src/lib/artifact-store.js +35 -0
  168. package/src/lib/async-hook-supervisor.cjs +13 -2
  169. package/src/lib/audit-mtc.js +3 -2
  170. package/src/lib/background-agent-supervisor.js +104 -3
  171. package/src/lib/background-interaction-journal.js +407 -0
  172. package/src/lib/background-interaction-resolver.js +23 -34
  173. package/src/lib/background-session-transport.js +12 -2
  174. package/src/lib/capability-manifest.js +41 -3
  175. package/src/lib/capability-negotiation.js +1 -1
  176. package/src/lib/channels/channel-manager.js +33 -0
  177. package/src/lib/channels/telegram-channel.js +23 -5
  178. package/src/lib/channels/webhook-channel.js +38 -15
  179. package/src/lib/chrome-connector.js +169 -23
  180. package/src/lib/config-manager.js +23 -9
  181. package/src/lib/context-breakdown.js +31 -0
  182. package/src/lib/cowork-cron.js +274 -32
  183. package/src/lib/cross-chain-mtc.js +3 -2
  184. package/src/lib/durable-security-store.js +124 -0
  185. package/src/lib/event-runtime-host.js +67 -6
  186. package/src/lib/event-runtime-store.js +163 -0
  187. package/src/lib/goal-store.js +32 -12
  188. package/src/lib/headless-manifest.js +2 -1
  189. package/src/lib/hook-environment.cjs +58 -0
  190. package/src/lib/hook-manager.js +12 -5
  191. package/src/lib/hook-runner.cjs +122 -28
  192. package/src/lib/hook-runner.js +1 -0
  193. package/src/lib/hooks-v2-producers.js +36 -0
  194. package/src/lib/hooks-v2-runtime.js +329 -52
  195. package/src/lib/interaction-adapter.js +60 -19
  196. package/src/lib/interaction-binding.js +64 -0
  197. package/src/lib/json-schema-output.js +439 -14
  198. package/src/lib/json-schema-validate.js +514 -883
  199. package/src/lib/lan-pairing-tokens.js +115 -57
  200. package/src/lib/lsp/__tests__/lsp-client.test.js +32 -0
  201. package/src/lib/lsp/__tests__/lsp-manager.test.js +25 -0
  202. package/src/lib/lsp/lsp-client.js +4 -0
  203. package/src/lib/lsp/lsp-manager.js +3 -0
  204. package/src/lib/lsp/lsp-server-registry.js +18 -0
  205. package/src/lib/mcp-client.js +1 -0
  206. package/src/lib/mcp-oauth.js +35 -21
  207. package/src/lib/packer/pkg-config-generator.js +1 -0
  208. package/src/lib/permission-decision.js +99 -0
  209. package/src/lib/plugin-monitor-supervisor.js +3 -0
  210. package/src/lib/plugin-runtime/capabilities.js +50 -0
  211. package/src/lib/plugin-runtime/capability-consent.js +42 -35
  212. package/src/lib/plugin-runtime/hooks.js +36 -9
  213. package/src/lib/plugin-runtime/install.js +23 -7
  214. package/src/lib/plugin-runtime/lsp.js +4 -0
  215. package/src/lib/plugin-runtime/manifest.js +50 -2
  216. package/src/lib/plugin-runtime/mcp.js +30 -5
  217. package/src/lib/plugin-runtime/monitors.js +11 -0
  218. package/src/lib/plugin-runtime/plugin-options.js +94 -38
  219. package/src/lib/plugin-runtime/policy.js +29 -2
  220. package/src/lib/plugin-runtime/sandbox-policy.js +84 -0
  221. package/src/lib/plugin-runtime/scopes.js +7 -3
  222. package/src/lib/plugin-runtime/trust.js +36 -31
  223. package/src/lib/process-execution-broker/credential-agent.js +114 -16
  224. package/src/lib/process-execution-broker/credential-transport-worker.js +312 -0
  225. package/src/lib/process-execution-broker/credential-transport.js +378 -0
  226. package/src/lib/process-execution-broker/index.js +408 -19
  227. package/src/lib/process-execution-broker/platform-sandbox.js +561 -21
  228. package/src/lib/process-execution-broker/windows-sandbox.ps1 +999 -0
  229. package/src/lib/project-mcp-trust.js +21 -26
  230. package/src/lib/protocol-replay.js +19 -12
  231. package/src/lib/settings-hooks.cjs +13 -0
  232. package/src/lib/skill-loader.js +83 -10
  233. package/src/lib/sync-credentials.js +5 -4
  234. package/src/lib/turn-binding.js +8 -6
  235. package/src/repl/agent-repl.js +113 -28
  236. package/src/repl/repl-turn-binding.js +5 -2
  237. package/src/runtime/agent-core.js +331 -26
  238. package/src/runtime/coding-agent-contract-shared.cjs +3 -3
  239. package/src/runtime/headless-runner.js +101 -4
  240. package/src/runtime/headless-stream.js +209 -23
  241. package/src/runtime/mcp-config.js +29 -17
  242. package/src/runtime/policies/agent-policy.js +2 -0
  243. package/src/workers/background-agent-worker.js +128 -13
  244. package/src/assets/web-panel/assets/ChatBubbleRenderer-DvySUzxJ.js +0 -1
  245. package/src/assets/web-panel/assets/MarkdownRenderer-DkxCweb1.js +0 -1
  246. package/src/assets/web-panel/assets/Projects-ClomCrN0.js +0 -1
  247. package/src/assets/web-panel/assets/RemoteSession-pRgaWsUK.js +0 -4
  248. package/src/assets/web-panel/assets/chat-Bvl-ojg2.js +0 -1
  249. package/src/assets/web-panel/assets/devWarning-CSVgo71Z.js +0 -1
  250. package/src/assets/web-panel/assets/index-DMIWh9fu.js +0 -1
  251. package/src/assets/web-panel/assets/index-ssTvV1l6.js +0 -1
@@ -0,0 +1,407 @@
1
+ /**
2
+ * Durable pending/settlement journal for background human interactions.
3
+ *
4
+ * Each mutation appends a full snapshot to the session's tamper-evident JSONL
5
+ * transcript. The worker persists a terminal settlement before delivering it
6
+ * to the suspended child, so retries can be classified as the same idempotent
7
+ * answer or a conflicting second settlement even after a process restart.
8
+ */
9
+
10
+ import { createHash } from "node:crypto";
11
+ import {
12
+ appendEvent as storeAppendEvent,
13
+ readEvents as storeReadEvents,
14
+ } from "../harness/jsonl-session-store.js";
15
+ import {
16
+ normalizeInteractionBinding,
17
+ sameInteractionBinding,
18
+ } from "./interaction-binding.js";
19
+
20
+ export const BACKGROUND_INTERACTION_JOURNAL_EVENT =
21
+ "background_interaction_journal";
22
+ export const BACKGROUND_INTERACTION_JOURNAL_VERSION = 1;
23
+ export const MAX_BACKGROUND_INTERACTION_RECORDS = 256;
24
+
25
+ const TERMINAL_STATUSES = new Set(["resolved", "rejected", "cancelled"]);
26
+
27
+ export const _deps = {
28
+ appendEvent: storeAppendEvent,
29
+ readEvents: storeReadEvents,
30
+ };
31
+
32
+ function journalError(message, code, details = {}) {
33
+ const error = new Error(message);
34
+ error.code = code;
35
+ Object.assign(error, details);
36
+ return error;
37
+ }
38
+
39
+ function cloneJson(value) {
40
+ if (value === undefined) return null;
41
+ return JSON.parse(JSON.stringify(value));
42
+ }
43
+
44
+ function canonicalize(value) {
45
+ if (value === undefined) return "__undefined__";
46
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
47
+ if (Array.isArray(value)) {
48
+ return `[${value.map((entry) => canonicalize(entry)).join(",")}]`;
49
+ }
50
+ return `{${Object.keys(value)
51
+ .sort()
52
+ .map((key) => `${JSON.stringify(key)}:${canonicalize(value[key])}`)
53
+ .join(",")}}`;
54
+ }
55
+
56
+ function fingerprint(value) {
57
+ return createHash("sha256").update(canonicalize(value)).digest("hex");
58
+ }
59
+
60
+ function normalizeError(error, fallbackCode = "INTERACTION_REJECTED") {
61
+ if (!error) return null;
62
+ if (typeof error === "string") {
63
+ return { code: fallbackCode, message: error };
64
+ }
65
+ return {
66
+ code: String(error.code || fallbackCode),
67
+ message: String(error.message || error),
68
+ };
69
+ }
70
+
71
+ function normalizeSettlement(outcome = {}) {
72
+ const status = String(outcome.status || "");
73
+ if (!TERMINAL_STATUSES.has(status)) {
74
+ throw journalError(
75
+ `Invalid background interaction settlement status: ${status || "<missing>"}`,
76
+ "INTERACTION_SETTLEMENT_INVALID",
77
+ );
78
+ }
79
+ return {
80
+ status,
81
+ answer: status === "resolved" ? cloneJson(outcome.answer) : null,
82
+ error:
83
+ status === "resolved"
84
+ ? null
85
+ : normalizeError(
86
+ outcome.error,
87
+ status === "cancelled"
88
+ ? "INTERACTION_CANCELLED"
89
+ : "INTERACTION_REJECTED",
90
+ ),
91
+ };
92
+ }
93
+
94
+ export class BackgroundInteractionJournal {
95
+ constructor(options = {}) {
96
+ this.backgroundAgentId = String(options.backgroundAgentId || "");
97
+ if (!this.backgroundAgentId) {
98
+ throw journalError(
99
+ "backgroundAgentId is required for the interaction journal",
100
+ "INTERACTION_JOURNAL_INVALID",
101
+ );
102
+ }
103
+ this._now = options.now || Date.now;
104
+ this.records = [];
105
+ }
106
+
107
+ static fromJSON(snapshot, options = {}) {
108
+ if (
109
+ !snapshot ||
110
+ snapshot.version !== BACKGROUND_INTERACTION_JOURNAL_VERSION ||
111
+ typeof snapshot.backgroundAgentId !== "string" ||
112
+ !Array.isArray(snapshot.records)
113
+ ) {
114
+ throw journalError(
115
+ "Invalid background interaction journal snapshot",
116
+ "INTERACTION_JOURNAL_CORRUPT",
117
+ );
118
+ }
119
+ const journal = new BackgroundInteractionJournal({
120
+ backgroundAgentId: snapshot.backgroundAgentId,
121
+ now: options.now,
122
+ });
123
+ journal.records = snapshot.records.map((record) => ({
124
+ requestId: String(record.requestId || ""),
125
+ binding: normalizeInteractionBinding(record.binding),
126
+ payload: cloneJson(record.payload || {}),
127
+ payloadFingerprint: String(record.payloadFingerprint || ""),
128
+ status: String(record.status || "pending"),
129
+ createdAt: Number(record.createdAt) || 0,
130
+ settledAt: record.settledAt == null ? null : Number(record.settledAt),
131
+ settlement: record.settlement ? cloneJson(record.settlement) : null,
132
+ settlementFingerprint: record.settlementFingerprint
133
+ ? String(record.settlementFingerprint)
134
+ : null,
135
+ }));
136
+ return journal;
137
+ }
138
+
139
+ toJSON() {
140
+ return {
141
+ version: BACKGROUND_INTERACTION_JOURNAL_VERSION,
142
+ backgroundAgentId: this.backgroundAgentId,
143
+ records: cloneJson(this.records),
144
+ };
145
+ }
146
+
147
+ get(requestId) {
148
+ return (
149
+ this.records.find((record) => record.requestId === String(requestId)) ||
150
+ null
151
+ );
152
+ }
153
+
154
+ pending() {
155
+ return this.records.filter((record) => record.status === "pending");
156
+ }
157
+
158
+ recordPending({ requestId, binding, payload = {}, createdAt } = {}) {
159
+ const id = String(requestId || "");
160
+ const normalizedBinding = normalizeInteractionBinding(binding);
161
+ if (!id || normalizedBinding.sequence === null) {
162
+ throw journalError(
163
+ "A requestId and complete interaction binding are required",
164
+ "INTERACTION_REQUEST_INVALID",
165
+ );
166
+ }
167
+ const safePayload = cloneJson(payload);
168
+ const payloadFingerprint = fingerprint(safePayload);
169
+ const existing = this.get(id);
170
+ if (existing) {
171
+ if (
172
+ sameInteractionBinding(existing.binding, normalizedBinding) &&
173
+ existing.payloadFingerprint === payloadFingerprint
174
+ ) {
175
+ return { applied: false, record: cloneJson(existing) };
176
+ }
177
+ throw journalError(
178
+ `Interaction request ${id} was replayed with different binding or payload`,
179
+ "INTERACTION_REQUEST_CONFLICT",
180
+ { requestId: id },
181
+ );
182
+ }
183
+
184
+ const record = {
185
+ requestId: id,
186
+ binding: normalizedBinding,
187
+ payload: safePayload,
188
+ payloadFingerprint,
189
+ status: "pending",
190
+ createdAt: Number(createdAt) || this._now(),
191
+ settledAt: null,
192
+ settlement: null,
193
+ settlementFingerprint: null,
194
+ };
195
+ this.records.push(record);
196
+ this._prune();
197
+ return { applied: true, record: cloneJson(record) };
198
+ }
199
+
200
+ settle(requestId, binding, outcome = {}) {
201
+ const id = String(requestId || "");
202
+ const record = this.get(id);
203
+ if (!record) {
204
+ throw journalError(
205
+ `Unknown background interaction request: ${id || "<missing>"}`,
206
+ "INTERACTION_REQUEST_UNKNOWN",
207
+ { requestId: id },
208
+ );
209
+ }
210
+ if (!sameInteractionBinding(record.binding, binding)) {
211
+ throw journalError(
212
+ `Interaction response binding does not match request ${id}`,
213
+ "INTERACTION_BINDING_MISMATCH",
214
+ { requestId: id },
215
+ );
216
+ }
217
+ const settlement = normalizeSettlement(outcome);
218
+ const settlementFingerprint = fingerprint(settlement);
219
+ if (record.status !== "pending") {
220
+ if (record.settlementFingerprint === settlementFingerprint) {
221
+ return { applied: false, record: cloneJson(record) };
222
+ }
223
+ throw journalError(
224
+ `Interaction request ${id} is already settled`,
225
+ "INTERACTION_ALREADY_SETTLED",
226
+ { requestId: id, status: record.status },
227
+ );
228
+ }
229
+
230
+ record.status = settlement.status;
231
+ record.settledAt = this._now();
232
+ record.settlement = settlement;
233
+ record.settlementFingerprint = settlementFingerprint;
234
+ return { applied: true, record: cloneJson(record) };
235
+ }
236
+
237
+ rejectPending(error = {}) {
238
+ const rejected = [];
239
+ for (const record of this.pending()) {
240
+ const result = this.settle(record.requestId, record.binding, {
241
+ status: "rejected",
242
+ error,
243
+ });
244
+ rejected.push(result.record);
245
+ }
246
+ return rejected;
247
+ }
248
+
249
+ _prune() {
250
+ while (this.records.length > MAX_BACKGROUND_INTERACTION_RECORDS) {
251
+ const terminalIndex = this.records.findIndex((record) =>
252
+ TERMINAL_STATUSES.has(record.status),
253
+ );
254
+ if (terminalIndex === -1) {
255
+ throw journalError(
256
+ `Background interaction journal exceeded ${MAX_BACKGROUND_INTERACTION_RECORDS} pending requests`,
257
+ "INTERACTION_PENDING_LIMIT",
258
+ );
259
+ }
260
+ this.records.splice(terminalIndex, 1);
261
+ }
262
+ }
263
+ }
264
+
265
+ export class BackgroundInteractionPersistenceError extends Error {
266
+ constructor(operation, sessionId, cause) {
267
+ const detail =
268
+ cause?.message || String(cause || "unknown persistence error");
269
+ super(
270
+ `Background interaction journal ${operation} failed for ${sessionId}: ${detail}`,
271
+ { cause },
272
+ );
273
+ this.name = "BackgroundInteractionPersistenceError";
274
+ this.code =
275
+ operation === "read"
276
+ ? "INTERACTION_JOURNAL_READ_FAILED"
277
+ : "INTERACTION_JOURNAL_PERSIST_FAILED";
278
+ this.operation = operation;
279
+ this.sessionId = sessionId;
280
+ }
281
+ }
282
+
283
+ export function persistBackgroundInteractionJournal(
284
+ sessionId,
285
+ journal,
286
+ options = {},
287
+ ) {
288
+ const failIfUnavailable = options.failIfUnavailable !== false;
289
+ try {
290
+ if (!sessionId || !(journal instanceof BackgroundInteractionJournal)) {
291
+ throw new TypeError("sessionId and interaction journal are required");
292
+ }
293
+ _deps.appendEvent(
294
+ sessionId,
295
+ BACKGROUND_INTERACTION_JOURNAL_EVENT,
296
+ journal.toJSON(),
297
+ );
298
+ return true;
299
+ } catch (error) {
300
+ if (!failIfUnavailable) return false;
301
+ throw new BackgroundInteractionPersistenceError(
302
+ "write",
303
+ sessionId || "<missing-session>",
304
+ error,
305
+ );
306
+ }
307
+ }
308
+
309
+ export function loadBackgroundInteractionJournal(
310
+ sessionId,
311
+ backgroundAgentId,
312
+ options = {},
313
+ ) {
314
+ const failIfUnavailable = options.failIfUnavailable !== false;
315
+ try {
316
+ if (!sessionId || !backgroundAgentId) {
317
+ throw new TypeError("sessionId and backgroundAgentId are required");
318
+ }
319
+ const events = _deps.readEvents(sessionId) || [];
320
+ for (let index = events.length - 1; index >= 0; index--) {
321
+ const event = events[index];
322
+ if (
323
+ event?.type === BACKGROUND_INTERACTION_JOURNAL_EVENT &&
324
+ event.data?.backgroundAgentId === backgroundAgentId
325
+ ) {
326
+ return BackgroundInteractionJournal.fromJSON(event.data, options);
327
+ }
328
+ }
329
+ return new BackgroundInteractionJournal({
330
+ backgroundAgentId,
331
+ now: options.now,
332
+ });
333
+ } catch (error) {
334
+ if (!failIfUnavailable) {
335
+ return new BackgroundInteractionJournal({
336
+ backgroundAgentId,
337
+ now: options.now,
338
+ });
339
+ }
340
+ throw new BackgroundInteractionPersistenceError(
341
+ "read",
342
+ sessionId || "<missing-session>",
343
+ error,
344
+ );
345
+ }
346
+ }
347
+
348
+ /**
349
+ * Clone-mutate-persist transaction. The live journal is not changed when the
350
+ * append fails, so a caller may safely retry the same settlement.
351
+ */
352
+ export function updateBackgroundInteractionJournal(
353
+ sessionId,
354
+ journal,
355
+ mutate,
356
+ options = {},
357
+ ) {
358
+ const draft = BackgroundInteractionJournal.fromJSON(journal.toJSON(), {
359
+ now: options.now || journal._now,
360
+ });
361
+ const result = mutate(draft);
362
+ if (!options.persistIf || options.persistIf(result) !== false) {
363
+ persistBackgroundInteractionJournal(sessionId, draft, options);
364
+ }
365
+ return { journal: draft, result };
366
+ }
367
+
368
+ /**
369
+ * Recovery entry point used when a worker is observed lost or starts again.
370
+ * An optional state-file fallback lets pre-journal pendingQuestion records be
371
+ * imported once and deterministically rejected.
372
+ */
373
+ export function rejectPendingBackgroundInteractions(
374
+ sessionId,
375
+ backgroundAgentId,
376
+ options = {},
377
+ ) {
378
+ let journal = loadBackgroundInteractionJournal(
379
+ sessionId,
380
+ backgroundAgentId,
381
+ options,
382
+ );
383
+ const fallback = options.fallbackRequest;
384
+ const hasFallback =
385
+ fallback?.requestId &&
386
+ normalizeInteractionBinding(fallback.binding).sequence !== null &&
387
+ !journal.get(fallback.requestId);
388
+ if (!journal.pending().length && !hasFallback) {
389
+ return { journal, rejected: [], changed: false };
390
+ }
391
+ const mutation = updateBackgroundInteractionJournal(
392
+ sessionId,
393
+ journal,
394
+ (draft) => {
395
+ if (hasFallback) draft.recordPending(fallback);
396
+ return draft.rejectPending({
397
+ code: options.code || "INTERACTION_WORKER_LOST",
398
+ message:
399
+ options.message ||
400
+ "The background worker exited before the interaction settled",
401
+ });
402
+ },
403
+ options,
404
+ );
405
+ journal = mutation.journal;
406
+ return { journal, rejected: mutation.result, changed: true };
407
+ }
@@ -13,6 +13,16 @@
13
13
  */
14
14
 
15
15
  import { randomUUID } from "node:crypto";
16
+ import {
17
+ hasCompleteInteractionBinding,
18
+ normalizeInteractionBinding,
19
+ sameInteractionBinding,
20
+ } from "./interaction-binding.js";
21
+
22
+ export {
23
+ normalizeInteractionBinding,
24
+ sameInteractionBinding,
25
+ } from "./interaction-binding.js";
16
26
 
17
27
  export const BACKGROUND_INTERACTION_PROTOCOL_VERSION = 1;
18
28
  export const DEFAULT_BACKGROUND_INTERACTION_TIMEOUT_MS = 60_000;
@@ -30,31 +40,6 @@ function asNullableString(value) {
30
40
  return String(value);
31
41
  }
32
42
 
33
- function normalizeBinding(binding = {}) {
34
- return {
35
- backgroundAgentId: asNullableString(binding.backgroundAgentId),
36
- sessionId: asNullableString(binding.sessionId),
37
- turnId: asNullableString(binding.turnId),
38
- toolUseId: asNullableString(binding.toolUseId),
39
- sequence:
40
- Number.isSafeInteger(binding.sequence) && binding.sequence > 0
41
- ? binding.sequence
42
- : null,
43
- };
44
- }
45
-
46
- function sameBinding(left, right) {
47
- const a = normalizeBinding(left);
48
- const b = normalizeBinding(right);
49
- return (
50
- a.backgroundAgentId === b.backgroundAgentId &&
51
- a.sessionId === b.sessionId &&
52
- a.turnId === b.turnId &&
53
- a.toolUseId === b.toolUseId &&
54
- a.sequence === b.sequence
55
- );
56
- }
57
-
58
43
  function validRequest(message) {
59
44
  return (
60
45
  message &&
@@ -65,12 +50,16 @@ function validRequest(message) {
65
50
  message.requestId.length <= 256 &&
66
51
  message.payload &&
67
52
  typeof message.payload === "object" &&
68
- normalizeBinding(message.binding).sequence !== null
53
+ hasCompleteInteractionBinding(message.binding)
69
54
  );
70
55
  }
71
56
 
72
57
  function sendIpc(target, message, onError = () => {}) {
73
- if (!target || typeof target.send !== "function" || target.connected === false)
58
+ if (
59
+ !target ||
60
+ typeof target.send !== "function" ||
61
+ target.connected === false
62
+ )
74
63
  return false;
75
64
  try {
76
65
  target.send(message, (error) => {
@@ -138,7 +127,8 @@ export function createBackgroundInteractionClient(options = {}) {
138
127
  return;
139
128
  }
140
129
  const entry = pending.get(message.requestId);
141
- if (!entry || !sameBinding(entry.binding, message.binding)) return;
130
+ if (!entry || !sameInteractionBinding(entry.binding, message.binding))
131
+ return;
142
132
 
143
133
  if (message.status === "resolved") {
144
134
  settle(entry, entry.resolve, message.answer);
@@ -170,7 +160,7 @@ export function createBackgroundInteractionClient(options = {}) {
170
160
 
171
161
  sequence += 1;
172
162
  const requestId = `${backgroundAgentId}:${idFactory()}`;
173
- const binding = normalizeBinding({
163
+ const binding = normalizeInteractionBinding({
174
164
  backgroundAgentId,
175
165
  sessionId: payload.sessionId ?? sessionId,
176
166
  turnId: payload.turnId ?? turnId,
@@ -301,7 +291,7 @@ export function attachInteractionRequestHandler(
301
291
  protocolVersion: BACKGROUND_INTERACTION_PROTOCOL_VERSION,
302
292
  requestId:
303
293
  typeof message?.requestId === "string" ? message.requestId : "",
304
- binding: normalizeBinding(message?.binding),
294
+ binding: normalizeInteractionBinding(message?.binding),
305
295
  status: "rejected",
306
296
  error: { code, message: detail },
307
297
  };
@@ -315,7 +305,7 @@ export function attachInteractionRequestHandler(
315
305
  message.protocolVersion === BACKGROUND_INTERACTION_PROTOCOL_VERSION
316
306
  ) {
317
307
  const active = inflight.get(message.requestId);
318
- if (active && sameBinding(active.binding, message.binding)) {
308
+ if (active && sameInteractionBinding(active.binding, message.binding)) {
319
309
  inflight.delete(message.requestId);
320
310
  active.controller.abort(message.reason || "cancelled");
321
311
  }
@@ -331,12 +321,11 @@ export function attachInteractionRequestHandler(
331
321
  return;
332
322
  }
333
323
 
334
- const binding = normalizeBinding(message.binding);
324
+ const binding = normalizeInteractionBinding(message.binding);
335
325
  const expectedAgentId = asNullableString(options.backgroundAgentId);
336
326
  const expectedSessionId = asNullableString(options.sessionId);
337
327
  if (
338
- (expectedAgentId &&
339
- binding.backgroundAgentId !== expectedAgentId) ||
328
+ (expectedAgentId && binding.backgroundAgentId !== expectedAgentId) ||
340
329
  (expectedSessionId && binding.sessionId !== expectedSessionId)
341
330
  ) {
342
331
  rejectRequest(
@@ -198,7 +198,8 @@ export function startBackgroundSessionServer(opts) {
198
198
  case "interaction_response": {
199
199
  try {
200
200
  // Support both field names: requestId (client) and intId (wire legacy)
201
- const { requestId, intId, answer, result, error } = message;
201
+ const { requestId, intId, binding, answer, result, error } =
202
+ message;
202
203
  const resolvedId = requestId || intId;
203
204
  if (!resolvedId) {
204
205
  writeMessage(socket, {
@@ -208,14 +209,23 @@ export function startBackgroundSessionServer(opts) {
208
209
  return;
209
210
  }
210
211
  // Single-object callback matching worker expectation: { requestId, answer, error }
211
- onInteractionResponse?.({
212
+ const settlement = onInteractionResponse?.({
212
213
  requestId: resolvedId,
214
+ binding,
213
215
  answer: answer ?? result,
214
216
  error,
215
217
  });
216
218
  writeMessage(socket, {
217
219
  type: "received",
218
220
  requestId: resolvedId,
221
+ accepted:
222
+ typeof settlement === "object"
223
+ ? settlement.accepted === true
224
+ : settlement === true,
225
+ duplicate:
226
+ typeof settlement === "object"
227
+ ? settlement.duplicate === true
228
+ : false,
219
229
  });
220
230
  } catch (err) {
221
231
  writeMessage(socket, {
@@ -49,6 +49,14 @@ export const CAPABILITY_MANIFEST = Object.freeze({
49
49
  description:
50
50
  'tool_use / tool_result lines carry a pairing `id` ("tu-<n>")',
51
51
  }),
52
+ Object.freeze({
53
+ key: "permission_decision",
54
+ field: "permission_decision",
55
+ companionFields: Object.freeze(["permission_decision_id"]),
56
+ minVersion: 1,
57
+ description:
58
+ "gated tool_result lines may carry a redacted permission decision and its correlation id",
59
+ }),
52
60
  Object.freeze({
53
61
  key: "trace_id",
54
62
  field: "trace_id",
@@ -135,6 +143,24 @@ export function toFieldGate(m = CAPABILITY_MANIFEST) {
135
143
  return out;
136
144
  }
137
145
 
146
+ /**
147
+ * Every negotiable line field → the primary gate field that controls it.
148
+ * Companion fields are kept under the same logical feature so negotiation can
149
+ * never emit a decision without its id (or an orphan id without its decision).
150
+ * @returns {Record<string, string>}
151
+ */
152
+ export function toGateableFieldGate(m = CAPABILITY_MANIFEST) {
153
+ const out = {};
154
+ for (const f of wireFeaturesOf(m)) {
155
+ if (!f?.field) continue;
156
+ out[f.field] = f.field;
157
+ for (const companion of f.companionFields || []) {
158
+ if (companion) out[companion] = f.field;
159
+ }
160
+ }
161
+ return out;
162
+ }
163
+
138
164
  /**
139
165
  * The server negotiation offer shape consumed by
140
166
  * capability-negotiation.js `negotiateProtocol(server, …)`.
@@ -199,7 +225,12 @@ export function capabilityDigest(m = CAPABILITY_MANIFEST) {
199
225
  protocolVersion: Number(mm.protocolVersion) || 1,
200
226
  minProtocolVersion: Number(mm.minProtocolVersion) || 1,
201
227
  wire: wireFeaturesOf(mm)
202
- .map((f) => [f.key, f.field, Number(f.minVersion) || 1])
228
+ .map((f) => [
229
+ f.key,
230
+ f.field,
231
+ [...(f.companionFields || [])].sort(),
232
+ Number(f.minVersion) || 1,
233
+ ])
203
234
  .sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0)),
204
235
  runtime: [...(mm.runtimeFeatures || [])].sort(),
205
236
  mcp: [...(mm.mcpFeatures || [])].sort(),
@@ -224,7 +255,7 @@ export function renderBehaviorMatrix(m = CAPABILITY_MANIFEST) {
224
255
  return wireFeaturesOf(m).map((f) => ({
225
256
  feature: f.key,
226
257
  minVersion: Number(f.minVersion) || 1,
227
- field: f.field,
258
+ field: [f.field, ...(f.companionFields || [])].join(", "),
228
259
  negotiable: true,
229
260
  description: String(f.description || ""),
230
261
  }));
@@ -280,6 +311,7 @@ export function diffCapabilities(prev, next = CAPABILITY_MANIFEST) {
280
311
  for (const f of wireFeaturesOf(m)) {
281
312
  out.set(f.key, {
282
313
  field: f.field,
314
+ companionFields: [...(f.companionFields || [])].sort(),
283
315
  minVersion: Number(f.minVersion) || 1,
284
316
  });
285
317
  }
@@ -294,7 +326,13 @@ export function diffCapabilities(prev, next = CAPABILITY_MANIFEST) {
294
326
  const changedWireFeatures = [];
295
327
  for (const [key, nv] of n) {
296
328
  const pv = p.get(key);
297
- if (pv && (pv.field !== nv.field || pv.minVersion !== nv.minVersion)) {
329
+ if (
330
+ pv &&
331
+ (pv.field !== nv.field ||
332
+ pv.minVersion !== nv.minVersion ||
333
+ JSON.stringify(pv.companionFields) !==
334
+ JSON.stringify(nv.companionFields))
335
+ ) {
298
336
  changedWireFeatures.push({ feature: key, from: pv, to: nv });
299
337
  }
300
338
  }
@@ -210,7 +210,7 @@ const FEATURE_TO_FIELD = toFieldGate();
210
210
  * baseline). Mutates `gate` in place and returns it.
211
211
  *
212
212
  * @param {{features:string[], ok:boolean}} result
213
- * @param {{seq?:boolean, trace_id?:boolean, tool_use_id?:boolean}} gate
213
+ * @param {{seq?:boolean, trace_id?:boolean, tool_use_id?:boolean, permission_decision?:boolean}} gate
214
214
  */
215
215
  export function applyNegotiationToGate(result, gate = {}) {
216
216
  if (!result || result.ok === false) return gate;