chainlesschain 0.162.174 → 0.162.176

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 (281) hide show
  1. package/package.json +10 -10
  2. package/src/assets/web-panel/assets/{AIOps-Dcl-X1Hw.js → AIOps-BDLu5Elz.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-ClMh9HzT.js → ActionButton-DH5us-CK.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-DPj0rSQ5.js → Analytics-BZ0u8IFG.js} +3 -3
  5. package/src/assets/web-panel/assets/AppLayout-Duu8xR14.js +9 -0
  6. package/src/assets/web-panel/assets/{Artifacts-L8781rE8.js → Artifacts-Br2YBbh_.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-CffB6WIP.js → Audit-C3C6a482.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-BkLhayyY.js → BackgroundAgents-CzHvebcj.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-BQnwFI78.js → Backup-DZNHYDFd.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-xuUGHQch.js → BaseInput-VRiC4fIx.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-feQXwWrg.js → Chat-Cm08WWAD.js} +5 -5
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-CGHYrugQ.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-DVaIiUGW.js → Checkbox-DtByk7d7.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-D2kEnzeU.js → Codegen-CphXXOfD.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-azDoyusS.js → Col-Hz86TnLR.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-OZdnPWM5.js → Community-HP03ltpD.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-VDMvBN-C.js → Compact-B_N1mqQz.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-CPJ_zgQ1.js → Compliance-CVztRpi8.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-iRBwcsOA.js → Cowork-wUVOyZih.js} +4 -4
  20. package/src/assets/web-panel/assets/{Cron-DrxrspUz.js → Cron-DW5TLJKw.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-D-rkAZXF.js → Crosschain-CrAFGhWH.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-5Pp1Xnmr.js → DID-pA-oD8ke.js} +2 -2
  23. package/src/assets/web-panel/assets/Dashboard-CXrd5gAw.js +3 -0
  24. package/src/assets/web-panel/assets/{Dropdown-BWj_E0Ie.js → Dropdown-EweJcsek.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-BT-wgSEh.js → EmailListRenderer-C9xVLPG4.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-1PzH23pa.js → FamilyGuardDashboard-CDcEEqlu.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-BxMIXGC6.js → Federation-DtZda9A_.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-CyJobBln.js → FormItemContext-CiYdcVz3.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-YkjFuQTN.js → GenericCardRenderer-DA13uwA0.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-C2a98Wp_.js → Git-DzRhZD1O.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-DKL3Fl84.js → Governance-D5RMgOSb.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-BJ2cQC_3.js → Inference-BgrPfSNk.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DBAsOngt.js → KnowledgeGraph-DzjnD571.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-COt8g9LO.js → Logs-BhWzVDtN.js} +2 -2
  35. package/src/assets/web-panel/assets/{MarkdownRenderer-3Lfht1Fd.js → MarkdownRenderer-BDape9cx.js} +1 -1
  36. package/src/assets/web-panel/assets/{Marketplace-C9Zk9Pb2.js → Marketplace-DJtL5GV7.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-DDWDFWPO.js → McpTools-CZcQygI7.js} +5 -5
  38. package/src/assets/web-panel/assets/{Memory-BRmVye_o.js → Memory-DUWSDUUu.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-CppBbWpD.js → MobileBridge-BTwq2WKY.js} +1 -1
  40. package/src/assets/web-panel/assets/MobileProjects-NZvvfDME.js +1 -0
  41. package/src/assets/web-panel/assets/{Mtc-CcWpeGa6.js → Mtc-BiGugEQm.js} +6 -6
  42. package/src/assets/web-panel/assets/{MtcAudit-BcllEq0K.js → MtcAudit-DY7a6gUe.js} +4 -4
  43. package/src/assets/web-panel/assets/{Multisig-BFD1CarL.js → Multisig-BQbDu_w7.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-QNXXYvjz.js → NLProgramming-CM2wXTLv.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-07YwgQVy.js → Notes-DI6gGs1v.js} +4 -4
  46. package/src/assets/web-panel/assets/{NotificationSettings-bOccEInE.js → NotificationSettings-BsZOLWAB.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-DlRi29WL.js → OrderTableRenderer-C48mu09U.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-CBaezzEr.js → Organization-Cds0_tXr.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-Bl5NohFO.js → Overflow-WunYMD87.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-CLMal9Aw.js → P2P-Bo6j4DDv.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-CGO0NITk.js → PdhVaultBrowser-Bh2XPD5f.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-CPSw48E2.js → Permissions-EMvMMC8N.js} +3 -3
  53. package/src/assets/web-panel/assets/{PersonalDataHub-CDM5n134.js → PersonalDataHub-AX3ypUDV.js} +2 -2
  54. package/src/assets/web-panel/assets/{Pipeline-BdsqG7WV.js → Pipeline-BOx8HOgL.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-B6L4E-M7.js → Privacy-tBeTVQVM.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-DXPyZKRs.js → ProjectInit-CVYg1W4M.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-BrCC3xYT.js → ProjectSettings-Dvt5I7y1.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-BYmuHC2q.js → Projects-Cc7FC9-e.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-CbCe2eUl.js → Providers-Ct8xqY-E.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-DkukgCrR.js → QrScannerModal-Cni8Ooja.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-D-htOrV8.js → QuickAsk-BJVLKdxr.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-Bm7SIfzu.js → Recommend-DPG8Rbbm.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-C9rP-iMc.js → RemoteSession-DsdR7dCt.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-kGlUgbsl.js → Reputation-Csg1YM-b.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-PBupbbUA.js → Row-D9DoFoEf.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-njlwKUGK.js → RssFeed-BsvKrXMS.js} +2 -2
  67. package/src/assets/web-panel/assets/{Search-DLdEmgBw.js → Search-DFUStfgQ.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-SXGPSHdu.js → Security-ILg1zxdK.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-CuFGnNsb.js → Services-Dd41PCaY.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-CtUC0mDa.js → Skeleton-Bzo1cN80.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-P1qgOVFn.js → Skills-BDHh17P0.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-CsppE8YV.js → Sla-jl7UTiRY.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-Cq1oG56m.js → SpeechSettings-BePa-RF6.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-DdKW6V-C.js → SyncSettings-DiqqDKGZ.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-BCc9san5.js → Tasks-DYQ_6lxj.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-CcHC1dMA.js → Templates-JiDeI06L.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-CA4PqU22.js → Tenant-hhgI6zwS.js} +1 -1
  78. package/src/assets/web-panel/assets/Terminal-CjTZPa37.js +3 -0
  79. package/src/assets/web-panel/assets/{TimelineRenderer-DHWTSvOy.js → TimelineRenderer-B8uB5Llk.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-Ddz-P_yh.js → Tokens-C3b_6r2z.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-ePmrmLZ1.js → Trigger-tIP7HKVe.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-DmuK1CCE.js → Trust-vjoc11vJ.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-CqqBuRrT.js → UkeySign-DUPBnGuH.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-BGlR3uWM.js → VideoEditing-CBvhUY5T.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-Ba_Qx6Ga.js → Wallet-DUaQ0uA5.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-29neXKt2.js → WebAuthn-DllSivjE.js} +5 -5
  87. package/src/assets/web-panel/assets/{WorkflowEditor-lD0lR0UQ.js → WorkflowEditor-xc8D3uO6.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-B3stH01u.js → chat-BVicU7oA.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-Czly56MN.js → colors-DJzLmhLm.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-C0TkbkAJ.js → compact-item-BvYRfThE.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-BJmpSlf1.js → createContext-DGXxCBKR.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-BT46Y_QI.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-D1q-zw7u.js → hasIn-SBDJB1y4.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-DV-twjNO.js → index-1SdDS6lR.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-B-kTvMq7.js → index-9gdI7uUW.js} +1 -1
  96. package/src/assets/web-panel/assets/index-B7nuIywP.js +1 -0
  97. package/src/assets/web-panel/assets/{index-Bm_-RKal.js → index-BJZf9DhV.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CQftlZn-.js → index-BO1itZaY.js} +3 -3
  99. package/src/assets/web-panel/assets/{index-Dw3L_smW.js → index-BTrBGBJs.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-C7sFKQ53.js → index-BYqz4Wrr.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DlvsSuBC.js → index-Bf-ctERC.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-ChESIe5r.js → index-CKyEivf8.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DaqEHaCg.js → index-CdGY9P8a.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DZeoKL6t.js → index-Cf-O_g_8.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-XWV8JWMc.js → index-CloCgBUR.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CpMIdPJ0.js → index-CoJAO1Lm.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CgS8XUBU.js → index-Crk5NTb0.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DmUta2lw.js → index-Cs2rmLFt.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Dpz_7sf-.js → index-CtwqO5qo.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DRcQsPez.js → index-D7HimK0M.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BEt2-3x5.js → index-DCdRAgjy.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CHvPlzWJ.js → index-DCqRS6da.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BDHXx65P.js → index-DHVLJ8q0.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-K4YaPDOn.js → index-DKrvvWm4.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-C1pOqU7D.js → index-DMarmfrv.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DAhrn9EJ.js → index-DRfiXB_p.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-cPjWjvmW.js → index-Dm_77jgR.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-C27TnOoT.js → index-DnjPdvR6.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-upY9rkGZ.js → index-DonCnfMr.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CbvNJUwu.js → index-DvUTDYXX.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BVwJ3jht.js → index-FxZzRyE1.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DIF6XHIi.js → index-MjC4G09d.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-B8KqsomG.js → index-VMfwIH5G.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-8GKykbS4.js → index-YJkzy8ZF.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DpGs96FC.js → index-d5BVd-cL.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DO8xOwxi.js → index-e4fXH_WO.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Cu_4HaUS.js → index-hxTODbM1.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Cf7Gr3NG.js → index-lpaGoTH3.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DBqAm8es.js → index-wcCL-miV.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-ZDUhX41Z.js → index-xfluRkCT.js} +1 -1
  131. package/src/assets/web-panel/assets/index-ycwAfC-i.js +1 -0
  132. package/src/assets/web-panel/assets/{index-z8ATo2aQ.js → index-z1ZylsLq.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-QWEXi6-t.js → initDefaultProps-C1zO1KnY.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-BfrQwvV1.js → motion-CWLtEGmC.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-Dn7x0H9t.js → move-DzD_C3Vm.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-F61D_TgE.js → mtc-parser-D880PYJl.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-4SQZ39PF.js → omit-CFR_z2ov.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-C7DTe126.js → pickAttrs-srIhgrSC.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-40NeyzDK.js → placementArrow-C1rXpibP.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-BiUJ6qWs.js → responsiveObserve-C30gRcSS.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-CacJTM3f.js → slide-CvtKiMfV.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-K812HB-k.js → statusUtils-DNHO7ITG.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-CKeHA2eM.js → styleChecker-Dt_Sl-g4.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-CKl4FqXF.js → useFlexGapSupport-Cjev42Gh.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-DPoiJjSZ.js → useFs-Baxglj2V.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-aHwBspmt.js → usePersonalDataHub-B4NkcLaP.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-DrA-GuCT.js → vnode-mIRkdT7o.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-G3LMswgy.js → zoom-HzI5DlH_.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/auth/npm-auth.js +30 -5
  151. package/src/commands/agenda.js +64 -2
  152. package/src/commands/agent.js +45 -3
  153. package/src/commands/background-session.js +103 -0
  154. package/src/commands/config.js +70 -5
  155. package/src/commands/context.js +36 -2
  156. package/src/commands/hub.js +19 -1
  157. package/src/commands/memory.js +21 -6
  158. package/src/commands/permissions.js +57 -1
  159. package/src/commands/plugin.js +2 -0
  160. package/src/commands/review.js +23 -11
  161. package/src/commands/routine.js +31 -8
  162. package/src/commands/session.js +11 -3
  163. package/src/commands/team.js +20 -7
  164. package/src/commands/update.js +65 -10
  165. package/src/esm-bridge.js +3 -0
  166. package/src/gateways/terminal/PtyManager.js +8 -1
  167. package/src/gateways/ws/message-dispatcher.js +3 -0
  168. package/src/gateways/ws/session-protocol.js +26 -0
  169. package/src/gateways/ws/ws-agent-handler.js +107 -69
  170. package/src/gateways/ws/ws-server.js +92 -4
  171. package/src/harness/jsonl-session-store.js +13 -6
  172. package/src/harness/mcp-client.js +200 -1
  173. package/src/index.js +123 -55
  174. package/src/lazy-dispatch.js +86 -85
  175. package/src/lib/__tests__/personal-data-hub-aichat-wizard.test.js +15 -0
  176. package/src/lib/agent-coordinator.js +4 -0
  177. package/src/lib/agent-ipc-bus.js +32 -2
  178. package/src/lib/agent-sandbox.js +16 -2
  179. package/src/lib/agent-schedule-store.js +55 -0
  180. package/src/lib/agent-tool-admission.js +104 -0
  181. package/src/lib/api-key-helper.js +10 -2
  182. package/src/lib/async-hook-supervisor.cjs +26 -4
  183. package/src/lib/background-interaction-resolver.js +71 -0
  184. package/src/lib/background-session-transport.js +59 -1
  185. package/src/lib/changelog.js +19 -11
  186. package/src/lib/channels/channel-manager.js +6 -0
  187. package/src/lib/channels/telegram-channel.js +11 -1
  188. package/src/lib/channels/webhook-channel.js +15 -3
  189. package/src/lib/checkpoint-store.js +10 -2
  190. package/src/lib/cloud/bundle.js +12 -2
  191. package/src/lib/code-review.js +32 -8
  192. package/src/lib/computer-use/control-backend.js +18 -3
  193. package/src/lib/context-breakdown.js +46 -0
  194. package/src/lib/context-source-ledger.js +43 -0
  195. package/src/lib/crash-reporter.js +6 -0
  196. package/src/lib/diff-review-follow-up.js +154 -0
  197. package/src/lib/downloader.js +17 -3
  198. package/src/lib/ensure-utf8.js +11 -3
  199. package/src/lib/event-runtime-producer.js +58 -0
  200. package/src/lib/event-runtime-store.js +354 -0
  201. package/src/lib/event-runtime-worker.js +109 -0
  202. package/src/lib/execution-backend.js +72 -21
  203. package/src/lib/git-integration.js +19 -4
  204. package/src/lib/hook-manager.js +34 -15
  205. package/src/lib/hook-runner.cjs +48 -3
  206. package/src/lib/hooks-v2-producers.js +15 -0
  207. package/src/lib/hooks-v2-runtime.js +70 -21
  208. package/src/lib/host-adb-bridge.js +111 -21
  209. package/src/lib/ide-context.js +128 -1
  210. package/src/lib/interaction-adapter.js +39 -0
  211. package/src/lib/ipc-attach-protocol.js +98 -0
  212. package/src/lib/json-schema-validate.js +190 -36
  213. package/src/lib/lan-pairing-preflight.js +13 -2
  214. package/src/lib/lsp/__tests__/lsp-server-registry.test.js +18 -0
  215. package/src/lib/lsp/lsp-client.js +18 -1
  216. package/src/lib/lsp/lsp-manager.js +4 -0
  217. package/src/lib/lsp/lsp-server-registry.js +11 -0
  218. package/src/lib/mcp-oauth.js +8 -2
  219. package/src/lib/npm-invocation.js +29 -0
  220. package/src/lib/packer/pkg-runner.js +13 -2
  221. package/src/lib/packer/precheck.js +33 -16
  222. package/src/lib/packer/web-panel-builder.js +16 -2
  223. package/src/lib/permission-rules.cjs +5 -1
  224. package/src/lib/personal-data-hub-aichat-wizard.js +22 -6
  225. package/src/lib/personal-data-hub-wiring.js +27 -3
  226. package/src/lib/plan-mode.js +204 -11
  227. package/src/lib/plugin-monitor-supervisor.js +39 -4
  228. package/src/lib/plugin-runtime/bin.js +45 -0
  229. package/src/lib/plugin-runtime/hooks.js +14 -1
  230. package/src/lib/plugin-runtime/install.js +2 -1
  231. package/src/lib/plugin-runtime/lsp.js +3 -0
  232. package/src/lib/plugin-runtime/mcp.js +8 -1
  233. package/src/lib/plugin-runtime/monitors.js +4 -0
  234. package/src/lib/plugin-runtime/plugin-options.js +74 -7
  235. package/src/lib/plugin-runtime/signature.js +45 -0
  236. package/src/lib/pr-create.js +21 -8
  237. package/src/lib/pr-link-ledger.js +15 -3
  238. package/src/lib/process-execution-broker/credential-agent.js +295 -0
  239. package/src/lib/process-execution-broker/index.js +440 -14
  240. package/src/lib/process-execution-broker/patch-child-process.js +2 -3
  241. package/src/lib/process-execution-broker/platform-sandbox.js +351 -0
  242. package/src/lib/process-manager.js +18 -3
  243. package/src/lib/provenance-api.js +6 -0
  244. package/src/lib/proxy-bootstrap.js +19 -0
  245. package/src/lib/publish-workspace.js +14 -6
  246. package/src/lib/repl-rewind.js +9 -4
  247. package/src/lib/secret-store.js +159 -0
  248. package/src/lib/service-manager.js +64 -29
  249. package/src/lib/session-hooks.js +328 -473
  250. package/src/lib/session-telemetry-middleware.js +6 -0
  251. package/src/lib/settings-hook-events.cjs +61 -1
  252. package/src/lib/settings-hooks.cjs +4 -0
  253. package/src/lib/side-effect-ledger.js +22 -0
  254. package/src/lib/sub-agent-context.js +5 -0
  255. package/src/lib/sub-agent-profiles.js +4 -0
  256. package/src/lib/trace-api.js +6 -0
  257. package/src/lib/turn-context.js +14 -8
  258. package/src/lib/unattended-action-policy.js +83 -0
  259. package/src/lib/update-notice.js +9 -45
  260. package/src/lib/with-file-lock.js +7 -0
  261. package/src/lib/ws-server.js +1 -0
  262. package/src/repl/agent-repl.js +71 -13
  263. package/src/repl/clipboard-copy.js +8 -2
  264. package/src/repl/pr-comments.js +30 -7
  265. package/src/runtime/agent-core.js +439 -87
  266. package/src/runtime/agent-runtime.js +1 -0
  267. package/src/runtime/coding-agent-contract-shared.cjs +52 -0
  268. package/src/runtime/coding-agent-policy.cjs +20 -0
  269. package/src/runtime/diagnostics.js +73 -8
  270. package/src/runtime/headless-runner.js +63 -0
  271. package/src/runtime/headless-stream.js +269 -17
  272. package/src/runtime/mcp-config.js +16 -1
  273. package/src/workers/background-agent-worker.js +80 -1
  274. package/src/assets/web-panel/assets/AppLayout-7iSKDmlI.js +0 -9
  275. package/src/assets/web-panel/assets/ChatBubbleRenderer-DcbUHeGW.js +0 -1
  276. package/src/assets/web-panel/assets/Dashboard-BAKYNavw.js +0 -3
  277. package/src/assets/web-panel/assets/MobileProjects-C4GKn1dH.js +0 -1
  278. package/src/assets/web-panel/assets/Terminal-Fj7ea0In.js +0 -3
  279. package/src/assets/web-panel/assets/devWarning-CDI8Sbaj.js +0 -1
  280. package/src/assets/web-panel/assets/index-96LBR96V.js +0 -1
  281. package/src/assets/web-panel/assets/index-DyQkiW24.js +0 -1
@@ -79,6 +79,7 @@ import {
79
79
  reconcileSideEffects,
80
80
  classifyToolSideEffect,
81
81
  } from "../lib/side-effect-ledger.js";
82
+ import { DiffReviewFollowUpTracker } from "../lib/diff-review-follow-up.js";
82
83
  import {
83
84
  loadSideEffectLedger,
84
85
  persistSideEffectLedger,
@@ -240,26 +241,106 @@ export function createStreamCoalescer({
240
241
  export function planSnapshot(pm) {
241
242
  let items = [];
242
243
  let risk = null;
244
+ let planId = null;
245
+ let planVersion = null;
246
+ let previousPlanId = null;
247
+ let executionLock = null;
243
248
  try {
244
249
  const plan = pm.currentPlan;
250
+ planId = plan?.id || null;
251
+ planVersion = plan?.version || null;
252
+ previousPlanId = plan?.revisionOf || null;
245
253
  items = (plan?.items || []).map((i) => ({
246
254
  id: i.id,
247
255
  title: i.title,
248
256
  tool: i.tool,
249
257
  impact: i.estimatedImpact || "low",
250
258
  status: i.status,
259
+ ...(i.turn ? { turn: i.turn } : {}),
260
+ ...(i.toolUseId ? { tool_use_id: i.toolUseId } : {}),
261
+ ...(i.startedAt ? { started_at: i.startedAt } : {}),
262
+ ...(i.completedAt ? { completed_at: i.completedAt } : {}),
263
+ ...(i.error ? { error: String(i.error).slice(0, 1000) } : {}),
251
264
  }));
252
265
  if (items.length > 0) {
253
266
  const r = pm.getRiskAssessment();
254
267
  if (r) risk = { level: r.level, totalScore: r.totalScore };
255
268
  }
269
+ executionLock = pm.getExecutionLock?.() || null;
256
270
  } catch {
257
271
  /* snapshot is best-effort */
258
272
  }
259
- return { active: pm.isActive(), state: pm.state || null, items, risk };
273
+ return {
274
+ active: pm.isActive(),
275
+ state: pm.state || null,
276
+ plan_id: planId,
277
+ plan_version: planVersion,
278
+ previous_plan_id: previousPlanId,
279
+ items,
280
+ risk,
281
+ ...(executionLock ? { execution_lock: executionLock } : {}),
282
+ };
260
283
  }
261
284
 
262
285
  const MAX_PLAN_REVIEW_SNAPSHOT_CHARS = 24000;
286
+ const MAX_PLAN_REVIEW_COMMENTS = 64;
287
+ const MAX_PLAN_REVIEW_COMMENT_CHARS = 2000;
288
+
289
+ function boundedReviewString(value, limit) {
290
+ return String(value == null ? "" : value).slice(0, limit);
291
+ }
292
+
293
+ function normalizePlanReviewComments(values) {
294
+ const out = [];
295
+ let remaining = MAX_PLAN_REVIEW_SNAPSHOT_CHARS;
296
+ for (const raw of Array.isArray(values)
297
+ ? values.slice(0, MAX_PLAN_REVIEW_COMMENTS)
298
+ : []) {
299
+ if (!raw || typeof raw !== "object" || remaining <= 0) continue;
300
+ const text = boundedReviewString(
301
+ raw.text,
302
+ Math.min(MAX_PLAN_REVIEW_COMMENT_CHARS, remaining),
303
+ ).trim();
304
+ if (!text) continue;
305
+ remaining -= text.length;
306
+ const positive = (value) => {
307
+ const number = Number(value);
308
+ return Number.isInteger(number) && number > 0 ? number : null;
309
+ };
310
+ out.push({
311
+ id: boundedReviewString(raw.id, 160) || `comment-${out.length + 1}`,
312
+ sourceLine: positive(raw.sourceLine),
313
+ itemId: boundedReviewString(raw.itemId, 160) || null,
314
+ text,
315
+ file: boundedReviewString(raw.file, 1024) || null,
316
+ line: positive(raw.line),
317
+ column: positive(raw.column),
318
+ turn: positive(raw.turn),
319
+ });
320
+ }
321
+ return out;
322
+ }
323
+
324
+ function normalizePlanExecutionLock(value) {
325
+ if (!value || typeof value !== "object") return null;
326
+ const strings = (input, limit = 128) => [
327
+ ...new Set(
328
+ (Array.isArray(input) ? input : [])
329
+ .slice(0, limit)
330
+ .map((entry) => boundedReviewString(entry, 160))
331
+ .filter(Boolean),
332
+ ),
333
+ ];
334
+ return {
335
+ planId: boundedReviewString(value.planId, 160),
336
+ permissionMode: boundedReviewString(value.permissionMode, 64) || "default",
337
+ approvedItemIds: strings(value.approvedItemIds),
338
+ allowedTools: strings(value.allowedTools),
339
+ ...(value.createdAt
340
+ ? { createdAt: boundedReviewString(value.createdAt, 64) }
341
+ : {}),
342
+ };
343
+ }
263
344
 
264
345
  function planReviewFromInput(obj) {
265
346
  const review =
@@ -270,7 +351,8 @@ function planReviewFromInput(obj) {
270
351
  : typeof review?.snapshot === "string"
271
352
  ? review.snapshot
272
353
  : "";
273
- if (!snapshot.trim()) return null;
354
+ const comments = normalizePlanReviewComments(review?.comments);
355
+ if (!snapshot.trim() && comments.length === 0) return null;
274
356
  const text =
275
357
  snapshot.length > MAX_PLAN_REVIEW_SNAPSHOT_CHARS
276
358
  ? snapshot.slice(0, MAX_PLAN_REVIEW_SNAPSHOT_CHARS) +
@@ -282,22 +364,43 @@ function planReviewFromInput(obj) {
282
364
  typeof review?.reviewedAt === "string" ? review.reviewedAt : null,
283
365
  conversationId:
284
366
  typeof review?.conversationId === "string" ? review.conversationId : null,
367
+ revision:
368
+ Number.isInteger(review?.revision) && review.revision > 0
369
+ ? review.revision
370
+ : null,
371
+ comments,
372
+ executionLock: normalizePlanExecutionLock(review?.executionLock),
285
373
  snapshot: text,
286
374
  };
287
375
  }
288
376
 
289
377
  function planReviewSystemMessage(review) {
290
- if (!review?.snapshot) return null;
378
+ if (!review || (!review.snapshot && !review.comments?.length)) return null;
291
379
  const meta = [
292
380
  review.action ? `action=${review.action}` : null,
293
381
  review.reviewedAt ? `reviewedAt=${review.reviewedAt}` : null,
294
382
  review.conversationId ? `conversationId=${review.conversationId}` : null,
383
+ review.revision ? `revision=${review.revision}` : null,
295
384
  ]
296
385
  .filter(Boolean)
297
386
  .join(" ");
298
- return (
299
- "[PLAN REVIEW SNAPSHOT]" + (meta ? ` ${meta}` : "") + "\n" + review.snapshot
300
- );
387
+ const sections = [
388
+ "[PLAN REVIEW SNAPSHOT]" + (meta ? ` ${meta}` : ""),
389
+ review.snapshot || "(no Markdown snapshot)",
390
+ ];
391
+ if (review.comments?.length) {
392
+ sections.push(
393
+ "[PLAN REVIEW STRUCTURED COMMENTS]",
394
+ JSON.stringify(review.comments),
395
+ );
396
+ }
397
+ if (review.executionLock) {
398
+ sections.push(
399
+ "[PLAN REVIEW REQUESTED EXECUTION LOCK - AUDIT ONLY]",
400
+ JSON.stringify(review.executionLock),
401
+ );
402
+ }
403
+ return sections.join("\n");
301
404
  }
302
405
  import { withQuietStdout } from "./quiet-stdout.js";
303
406
 
@@ -329,7 +432,8 @@ export function parseInputEvent(line) {
329
432
  // Plan-mode control events (chat-panel plan UI):
330
433
  // {"type":"plan","action":"enter"|"approve"|"reject"}
331
434
  if (obj && typeof obj === "object" && obj.type === "plan") {
332
- const action = String(obj.action || "").toLowerCase();
435
+ const rawAction = String(obj.action || "").toLowerCase();
436
+ const action = rawAction === "requestchanges" ? "revise" : rawAction;
333
437
  if (!action) return null;
334
438
  const planReview = planReviewFromInput(obj);
335
439
  return planReview ? { plan: action, planReview } : { plan: action };
@@ -583,7 +687,7 @@ function buildSideEffectRecovery(ledger) {
583
687
  async function runTurn(
584
688
  messages,
585
689
  loopOptions,
586
- { runLoop, emit, costBudget, nextToolUseId, sideEffects },
690
+ { runLoop, emit, costBudget, nextToolUseId, sideEffects, turnNumber },
587
691
  ) {
588
692
  const usage = {
589
693
  input_tokens: 0,
@@ -595,10 +699,14 @@ async function runTurn(
595
699
  let finalText = "";
596
700
  let endReason = "complete";
597
701
  let stopForCost = false;
702
+ let responseCompleted = false;
598
703
  // P0-2: the side-effect op currently in flight (at most one — the loop runs
599
704
  // tools serially). Non-null only between a dangerous tool's tool-executing
600
705
  // and its tool-result.
601
706
  let currentSideEffectOpId = null;
707
+ const diffReviewFollowUps = new DiffReviewFollowUpTracker(
708
+ sideEffects?.ledger,
709
+ );
602
710
 
603
711
  // Collapse consecutive same-role turns before the model call ONLY when the
604
712
  // caller flags a resume-degenerate transcript (`mergeRoles`): a resumed
@@ -629,13 +737,28 @@ async function runTurn(
629
737
  // agent-sdk docs/PROTOCOL.md §1.2.1): the matching tool_result below
630
738
  // echoes the same id so UIs can pair calls without adjacency.
631
739
  const toolUseId = nextToolUseId ? nextToolUseId() : undefined;
632
- toolCalls.push({ id: toolUseId, tool: event.tool, args: event.args });
740
+ const pm = getPlanModeManager();
741
+ const planItem = pm.startPlanItemForTool(event.tool, {
742
+ toolUseId,
743
+ turn: turnNumber,
744
+ });
745
+ toolCalls.push({
746
+ id: toolUseId,
747
+ tool: event.tool,
748
+ args: event.args,
749
+ planItemId: planItem?.id || null,
750
+ });
633
751
  emit({
634
752
  type: "tool_use",
635
753
  ...(toolUseId ? { id: toolUseId } : {}),
754
+ ...(planItem?.id ? { plan_item_id: planItem.id } : {}),
755
+ ...(planItem?.turn ? { turn: planItem.turn } : {}),
636
756
  tool: event.tool,
637
757
  args: event.args,
638
758
  });
759
+ if (planItem) {
760
+ emit({ type: "plan_update", ...planSnapshot(pm) });
761
+ }
639
762
  // P0-2: record an irreversible effect as STARTED (persisted before it
640
763
  // settles) so a crash before the matching tool-result leaves a
641
764
  // reconcilable "in flight" marker instead of a silent replay — mirrors
@@ -673,6 +796,13 @@ async function runTurn(
673
796
  // P0-2: settle the in-flight side-effect (commit on success, fail on
674
797
  // a clean error) and persist the updated ledger snapshot.
675
798
  if (sideEffects && currentSideEffectOpId) {
799
+ if (event.result?._diffReviewAudit) {
800
+ diffReviewFollowUps.observe(
801
+ sideEffects.ledger,
802
+ currentSideEffectOpId,
803
+ event.result._diffReviewAudit,
804
+ );
805
+ }
676
806
  if (err)
677
807
  sideEffects.ledger.fail(
678
808
  currentSideEffectOpId,
@@ -688,14 +818,29 @@ async function runTurn(
688
818
  const lastCall =
689
819
  toolCalls.length > 0 ? toolCalls[toolCalls.length - 1] : null;
690
820
  if (lastCall) lastCall.is_error = Boolean(err);
821
+ const pm = getPlanModeManager();
822
+ const settledItem = lastCall?.planItemId
823
+ ? pm.settlePlanItem(lastCall.planItemId, {
824
+ success: !err,
825
+ error: err,
826
+ result: event.result,
827
+ })
828
+ : null;
691
829
  emit({
692
830
  type: "tool_result",
693
831
  ...(lastCall?.id ? { id: lastCall.id } : {}),
832
+ ...(lastCall?.planItemId
833
+ ? { plan_item_id: lastCall.planItemId }
834
+ : {}),
835
+ ...(settledItem?.turn ? { turn: settledItem.turn } : {}),
694
836
  tool: event.tool,
695
837
  is_error: Boolean(err),
696
838
  error: err,
697
839
  result: event.result,
698
840
  });
841
+ if (settledItem) {
842
+ emit({ type: "plan_update", ...planSnapshot(pm) });
843
+ }
699
844
  break;
700
845
  }
701
846
  case "token-usage":
@@ -735,6 +880,7 @@ async function runTurn(
735
880
  break;
736
881
  case "response-complete":
737
882
  finalText = event.content || "";
883
+ responseCompleted = true;
738
884
  break;
739
885
  case "run-ended":
740
886
  if (event.reason) endReason = event.reason;
@@ -747,6 +893,18 @@ async function runTurn(
747
893
  // just the switch) so no further paid LLM call is made.
748
894
  if (stopForCost) break;
749
895
  }
896
+ if (
897
+ sideEffects &&
898
+ diffReviewFollowUps.complete(sideEffects.ledger, {
899
+ status:
900
+ responseCompleted || endReason === "complete"
901
+ ? "completed-without-reproposal"
902
+ : "interrupted",
903
+ reason: responseCompleted || endReason === "complete" ? null : endReason,
904
+ }).length > 0
905
+ ) {
906
+ sideEffects.persist();
907
+ }
750
908
  return { finalText, endReason, usage, toolCalls };
751
909
  }
752
910
 
@@ -1137,6 +1295,7 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1137
1295
  options: qOptions,
1138
1296
  multiSelect,
1139
1297
  timeoutMs,
1298
+ metadata,
1140
1299
  } = {}) =>
1141
1300
  new Promise((resolve, reject) => {
1142
1301
  const id = `q-${++questionSeq}`;
@@ -1151,6 +1310,7 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1151
1310
  question: typeof question === "string" ? question : "",
1152
1311
  options: Array.isArray(qOptions) ? qOptions : null,
1153
1312
  multiSelect: multiSelect === true,
1313
+ ...(metadata && typeof metadata === "object" ? { metadata } : {}),
1154
1314
  });
1155
1315
  });
1156
1316
 
@@ -1458,6 +1618,39 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1458
1618
  }
1459
1619
  }
1460
1620
 
1621
+ // MCP servers may pause a tool flow with `elicitation/create`. Register the
1622
+ // handler only after MCP resolution so the client is initialized before use.
1623
+ // Reuse the structured Desktop/headless question channel, while preserving
1624
+ // the MCP response shape (`action` + object `content`) at this boundary.
1625
+ if (mcp?.mcpClient?.setElicitationHandler && interactiveQuestions) {
1626
+ mcp.mcpClient.setElicitationHandler(async (request) => {
1627
+ const { emitHooksV2Event } = await import("../lib/hooks-v2-producers.js");
1628
+ emitHooksV2Event("MCPElicitation", {
1629
+ server: request.server || null,
1630
+ request_id: request.requestId ?? null,
1631
+ message: request.message || "MCP server requests additional input",
1632
+ requested_schema: request.requestedSchema || null,
1633
+ session_id: sessionId,
1634
+ });
1635
+ const answer = await interactionAskUser({
1636
+ question: request.message || "MCP server requests additional input",
1637
+ timeoutMs: request.timeoutMs,
1638
+ metadata: {
1639
+ kind: "mcp_elicitation",
1640
+ server: request.server,
1641
+ requestId: request.requestId,
1642
+ requestedSchema: request.requestedSchema || null,
1643
+ },
1644
+ });
1645
+ if (answer == null) return { action: "cancel" };
1646
+ return {
1647
+ action: "accept",
1648
+ content:
1649
+ answer && typeof answer === "object" ? answer : { value: answer },
1650
+ };
1651
+ });
1652
+ }
1653
+
1461
1654
  // Seed MCP roots for --add-dir (roots/list_changed parity): advertise the full
1462
1655
  // workspace-root list to connected MCP servers when the stream session started
1463
1656
  // with extra roots. No --add-dir → workspaceRootDirs = [cwd] → no-op. Mirrors
@@ -1563,6 +1756,7 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1563
1756
  approvalGate,
1564
1757
  permissionRules,
1565
1758
  settingsHooks,
1759
+ toolAdmission: options.toolAdmission || null,
1566
1760
  classifyAllShell,
1567
1761
  enabledToolNames,
1568
1762
  disabledTools,
@@ -1812,10 +2006,14 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1812
2006
  // exits plan mode. Every control answers with a `plan_update` event.
1813
2007
  if (parsed.plan) {
1814
2008
  const pm = getPlanModeManager();
1815
- const reviewMessage =
1816
- parsed.plan === "approve" || parsed.plan === "reject"
1817
- ? planReviewSystemMessage(parsed.planReview)
1818
- : null;
2009
+ const reviewMessage = [
2010
+ "approve",
2011
+ "reject",
2012
+ "revise",
2013
+ "regenerate",
2014
+ ].includes(parsed.plan)
2015
+ ? planReviewSystemMessage(parsed.planReview)
2016
+ : null;
1819
2017
  if (reviewMessage) {
1820
2018
  messages.push({ role: "system", content: reviewMessage });
1821
2019
  }
@@ -1848,7 +2046,47 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1848
2046
  });
1849
2047
  continue;
1850
2048
  }
1851
- if (parsed.plan === "approve") {
2049
+ if (parsed.plan === "revise" || parsed.plan === "regenerate") {
2050
+ if (!pm.isActive()) {
2051
+ emit({
2052
+ type: "plan_update",
2053
+ ...planSnapshot(pm),
2054
+ session_id: sessionId,
2055
+ note: "nothing to revise",
2056
+ });
2057
+ continue;
2058
+ }
2059
+ const revision = pm.beginPlanRevision({
2060
+ reason: parsed.plan,
2061
+ });
2062
+ if (revision.error) {
2063
+ emit({
2064
+ type: "plan_update",
2065
+ ...planSnapshot(pm),
2066
+ session_id: sessionId,
2067
+ note: revision.error,
2068
+ });
2069
+ continue;
2070
+ }
2071
+ messages.push({
2072
+ role: "system",
2073
+ content:
2074
+ `[PLAN REVISION REQUESTED] Plan ${revision.previousPlan.id} is frozen. ` +
2075
+ `Create version ${revision.plan.version} as plan ${revision.plan.id}. ` +
2076
+ (parsed.plan === "regenerate"
2077
+ ? "Regenerate the plan from scratch using the review snapshot."
2078
+ : "Revise the plan using the inline comments and reviewer notes."),
2079
+ });
2080
+ emit({
2081
+ type: "plan_update",
2082
+ ...planSnapshot(pm),
2083
+ session_id: sessionId,
2084
+ });
2085
+ parsed.text =
2086
+ parsed.plan === "regenerate"
2087
+ ? "Regenerate the plan from the review feedback."
2088
+ : "Revise the plan from the review feedback.";
2089
+ } else if (parsed.plan === "approve") {
1852
2090
  if (!pm.isActive() || !(pm.currentPlan?.items?.length > 0)) {
1853
2091
  emit({
1854
2092
  type: "plan_update",
@@ -1858,10 +2096,17 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1858
2096
  });
1859
2097
  continue;
1860
2098
  }
1861
- pm.approvePlan();
2099
+ const approval = pm.approvePlan({
2100
+ permissionMode: options.permissionMode || "default",
2101
+ });
2102
+ const executionLock = approval.executionLock;
1862
2103
  messages.push({
1863
2104
  role: "system",
1864
- content: `[PLAN APPROVED] The user has approved your plan with ${pm.currentPlan.items.length} items. You can now use all tools including write_file, edit_file, run_shell, and run_skill. Execute the plan items in order.`,
2105
+ content:
2106
+ `[PLAN APPROVED] The user has approved your plan with ${pm.currentPlan.items.length} items. ` +
2107
+ `Permission mode is ${executionLock.permissionMode}. The execution lock permits only: ` +
2108
+ `${executionLock.allowedTools.join(", ")}. Execute the approved plan items in order; ` +
2109
+ "request a plan revision before using any other tool.",
1865
2110
  });
1866
2111
  emit({
1867
2112
  type: "plan_update",
@@ -2166,7 +2411,14 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
2166
2411
  // Resume-degenerate role merge for the first live model call only.
2167
2412
  mergeRoles: mergeRolesThisTurn,
2168
2413
  },
2169
- { runLoop, emit, costBudget, nextToolUseId, sideEffects },
2414
+ {
2415
+ runLoop,
2416
+ emit,
2417
+ costBudget,
2418
+ nextToolUseId,
2419
+ sideEffects,
2420
+ turnNumber: turns,
2421
+ },
2170
2422
  );
2171
2423
  } catch (err) {
2172
2424
  currentAbort = null;
@@ -34,6 +34,7 @@ import {
34
34
  isInJetbrainsContext,
35
35
  } from "../lib/jetbrains-bridge.js";
36
36
  import { collectPluginMcpServers } from "../lib/plugin-runtime/mcp.js";
37
+ import { EventRuntimeStore } from "../lib/event-runtime-store.js";
37
38
 
38
39
  /**
39
40
  * Normalize a parsed config object into a `{ name: serverConfig }` map.
@@ -150,7 +151,9 @@ export function mcpAuthHint(url, errMessage) {
150
151
  */
151
152
  export async function setupMcpFromConfig(servers, deps = {}) {
152
153
  const writeErr = deps.writeErr || (() => {});
153
- const createClient = deps.createClient || (() => new MCPClient());
154
+ const createClient =
155
+ deps.createClient ||
156
+ (() => new MCPClient({ eventRuntimeStore: deps.eventRuntimeStore || null }));
154
157
  servers = filterMcpServersByPolicy(servers, deps.mcpPolicy, writeErr);
155
158
 
156
159
  // `deps.into` lets a second batch (e.g. registered servers) accumulate into
@@ -191,6 +194,12 @@ export async function setupMcpFromConfig(servers, deps = {}) {
191
194
  if (deps.sessionId != null && typeof mcpClient.setSessionId === "function") {
192
195
  mcpClient.setSessionId(deps.sessionId);
193
196
  }
197
+ if (typeof mcpClient.setElicitationHandler === "function" &&
198
+ typeof deps.elicitationHandler === "function") {
199
+ mcpClient.setElicitationHandler(deps.elicitationHandler, {
200
+ timeoutMs: deps.elicitationTimeoutMs,
201
+ });
202
+ }
194
203
 
195
204
  for (const [name, cfg] of Object.entries(servers)) {
196
205
  // Skip a name already connected — an earlier batch (ad-hoc --mcp-config)
@@ -745,6 +754,11 @@ export async function resolveAgentMcp(args = {}, deps = {}) {
745
754
  const doIde = deps.loadIdeMcp || loadIdeMcp;
746
755
  const doPdh = deps.loadPdhMcp || loadPdhMcp;
747
756
  const doJetbrains = deps.loadJetbrainsMcp || loadJetbrainsMcp;
757
+ const runtimeEnv = args.env || process.env;
758
+ const eventRuntimeStore =
759
+ deps.eventRuntimeStore ||
760
+ args.eventRuntimeStore ||
761
+ (runtimeEnv.CC_EVENT_RUNTIME_DURABLE === "1" ? new EventRuntimeStore() : null);
748
762
  // Thread the agent session id down to setupMcpFromConfig so spawned stdio MCP
749
763
  // servers get CC_SESSION_ID / CLAUDE_CODE_SESSION_ID (Claude-Code parity).
750
764
  let mcpPolicy = deps.mcpPolicy || null;
@@ -759,6 +773,7 @@ export async function resolveAgentMcp(args = {}, deps = {}) {
759
773
  const fwd = {
760
774
  ...deps,
761
775
  ...(args.sessionId != null ? { sessionId: args.sessionId } : {}),
776
+ ...(eventRuntimeStore ? { eventRuntimeStore } : {}),
762
777
  mcpPolicy,
763
778
  };
764
779
  let result = null;
@@ -25,6 +25,7 @@ import {
25
25
  } from "../lib/background-agent-supervisor.js";
26
26
  import { startBackgroundSessionServer } from "../lib/background-session-transport.js";
27
27
  import { idlePhaseFor } from "../lib/background-agent-phase.js";
28
+ import { attachInteractionRequestHandler } from "../lib/background-interaction-resolver.js";
28
29
 
29
30
  const jobFile = process.argv[2];
30
31
  let job;
@@ -37,7 +38,10 @@ let phase = "turn";
37
38
  let turnCount = 0;
38
39
  let lastExit = { code: 0, signal: null };
39
40
  let transportState = null;
41
+ let detachInteractionHandler = null;
40
42
  const promptQueue = [];
43
+ // P0-2: 保存 pending 的交互请求,等 attach 客户端连接后转发
44
+ const pendingInteractions = new Map();
41
45
 
42
46
  // Backpressure (Gap 4): an attached client can push prompts faster than
43
47
  // turns drain — an unbounded queue grows without limit and every entry is a
@@ -114,7 +118,7 @@ function startTurn(argv, promptText) {
114
118
  child = spawn(process.execPath, [job.cliEntry, ...argv], {
115
119
  cwd: job.cwd,
116
120
  env: { ...process.env, CC_BACKGROUND_AGENT_ID: job.id },
117
- stdio: ["ignore", log.fd, log.fd],
121
+ stdio: ["ignore", log.fd, log.fd, "ipc"], // P0-2: 开启 IPC 通道用于人机交互
118
122
  windowsHide: true,
119
123
  // POSIX: give the agent child its own process group so an orphan reclaim
120
124
  // (worker crashed → supervisor kills the recorded agentPid) or /stop can
@@ -146,9 +150,71 @@ function startTurn(argv, promptText) {
146
150
  turn: turnCount,
147
151
  prompt: promptText || null,
148
152
  });
153
+
154
+ // P0-2: 挂载人机交互请求处理器,转发给 attach 客户端
155
+ detachInteractionHandler = attachInteractionRequestHandler(
156
+ child,
157
+ async (payload, msg) => {
158
+ const requestId = msg.requestId;
159
+ // 如果有 attach 客户端,转发给它等待响应
160
+ if (server && server.clientCount() > 0) {
161
+ return new Promise((resolve, reject) => {
162
+ const timer = setTimeout(
163
+ () => {
164
+ pendingInteractions.delete(requestId);
165
+ if (payload.defaultValue !== undefined) {
166
+ resolve(payload.defaultValue);
167
+ } else {
168
+ reject(new Error(`Interaction timed out: ${payload.question}`));
169
+ }
170
+ },
171
+ payload.timeoutMs || 5 * 60 * 1000,
172
+ );
173
+ timer.unref?.();
174
+ pendingInteractions.set(requestId, {
175
+ resolve,
176
+ reject,
177
+ timer,
178
+ payload,
179
+ });
180
+ server.broadcastInteractionRequest(requestId, payload);
181
+ });
182
+ }
183
+ // 没有客户端连接,返回默认值(如果有的话)
184
+ if (payload.defaultValue !== undefined) {
185
+ return payload.defaultValue;
186
+ }
187
+ // 没有默认值,记录到 state 让用户后续 attach 时能看到
188
+ mergeState({
189
+ pendingQuestion: {
190
+ intId: requestId,
191
+ requestId,
192
+ prompt: payload.prompt || payload.question,
193
+ hint: payload.hint,
194
+ options: payload.options,
195
+ multiSelect: payload.multiSelect,
196
+ timeoutMs: payload.timeoutMs,
197
+ askedAt: Date.now(),
198
+ },
199
+ });
200
+ // 等待用户 attach 后回复
201
+ return new Promise((resolve) => {
202
+ pendingInteractions.set(requestId, { resolve });
203
+ });
204
+ },
205
+ );
206
+
149
207
  child.on("exit", (code, signal) => {
150
208
  lastExit = { code, signal };
151
209
  child = null;
210
+ // 清理交互处理器
211
+ detachInteractionHandler?.();
212
+ detachInteractionHandler = null;
213
+ // 清理所有 pending 交互
214
+ for (const [, pending] of pendingInteractions) {
215
+ pending.reject?.(new Error("Agent exited"));
216
+ }
217
+ pendingInteractions.clear();
152
218
  server?.broadcast({ type: "turn-ended", turn: turnCount, exitCode: code });
153
219
  maybeContinue();
154
220
  });
@@ -259,6 +325,19 @@ async function main() {
259
325
  finalize(lastExit.code, lastExit.signal);
260
326
  }
261
327
  },
328
+ onInteractionResponse: ({ requestId, intId, answer, error }) => {
329
+ // Support both field names: requestId (from transport) and intId (legacy)
330
+ const resolvedId = requestId ?? intId;
331
+ const entry = pendingInteractions.get(resolvedId);
332
+ if (!entry) return;
333
+ pendingInteractions.delete(resolvedId);
334
+ clearTimeout(entry.timer);
335
+ if (error) {
336
+ entry.reject(new Error(error));
337
+ } else {
338
+ entry.resolve(answer);
339
+ }
340
+ },
262
341
  });
263
342
  transportState = { pipe: server.pipePath, token };
264
343
  mergeState({ transport: transportState });