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
@@ -281,6 +281,8 @@ export const ROLE_TOOL_WHITELIST = {
281
281
  "read_file",
282
282
  "write_file",
283
283
  "edit_file",
284
+ "delete_file",
285
+ "move_file",
284
286
  "run_shell",
285
287
  "search_files",
286
288
  "list_dir",
@@ -297,6 +299,8 @@ export const ROLE_TOOL_WHITELIST = {
297
299
  "read_file",
298
300
  "write_file",
299
301
  "edit_file",
302
+ "delete_file",
303
+ "move_file",
300
304
  "run_shell",
301
305
  "search_files",
302
306
  "list_dir",
@@ -11,6 +11,8 @@
11
11
 
12
12
  import { EventEmitter } from "node:events";
13
13
  import crypto from "node:crypto";
14
+ import { EventRuntimeProducer } from "./event-runtime-producer.js";
15
+ import { EventRuntimeStore } from "./event-runtime-store.js";
14
16
 
15
17
  /**
16
18
  * @typedef {Object} InteractionRequest
@@ -27,8 +29,11 @@ import crypto from "node:crypto";
27
29
  */
28
30
 
29
31
  class AgentIPCBus extends EventEmitter {
30
- constructor() {
32
+ constructor({ runtimeStore = null } = {}) {
31
33
  super();
34
+ this._runtimeProducer = runtimeStore
35
+ ? new EventRuntimeProducer({ store: runtimeStore, emitter: this })
36
+ : null;
32
37
  /** @type {Map<string, {req: InteractionRequest, resolve: Function, reject: Function, timer?: NodeJS.Timeout}>} */
33
38
  this._pendingRequests = new Map();
34
39
  /** @type {Map<string, Function>} resolvers by agentId */
@@ -58,6 +63,10 @@ class AgentIPCBus extends EventEmitter {
58
63
  this.emit("agent:unregistered", { agentId });
59
64
  }
60
65
 
66
+ isAgentRegistered(agentId) {
67
+ return this._agentResolvers.has(agentId);
68
+ }
69
+
61
70
  /**
62
71
  * Child agent calls this to request human interaction
63
72
  * @param {string} agentId
@@ -91,6 +100,19 @@ class AgentIPCBus extends EventEmitter {
91
100
  }, fullReq.timeoutMs);
92
101
 
93
102
  this._pendingRequests.set(requestId, { req: fullReq, resolve, reject, timer });
103
+ try {
104
+ this._runtimeProducer?.publish(
105
+ { type: "interaction_request", request: fullReq },
106
+ { origin: "agent-ipc", id: `interaction:${requestId}` },
107
+ );
108
+ } catch (error) {
109
+ // Durable publication is fail-closed for configured runtime mode: do
110
+ // not leave a request that cannot be recovered after a crash.
111
+ this._pendingRequests.delete(requestId);
112
+ clearTimeout(timer);
113
+ reject(error);
114
+ return;
115
+ }
94
116
  this.emit("request", fullReq);
95
117
  });
96
118
  }
@@ -106,6 +128,10 @@ class AgentIPCBus extends EventEmitter {
106
128
  if (entry.timer) clearTimeout(entry.timer);
107
129
  this._pendingRequests.delete(requestId);
108
130
  entry.resolve(response);
131
+ try {
132
+ const id = `interaction:${requestId}`;
133
+ this._runtimeProducer?.store.acknowledgeInbox(id, { response });
134
+ } catch {}
109
135
  this.emit("request:resolved", { requestId, response });
110
136
  return true;
111
137
  }
@@ -326,6 +352,10 @@ class AgentIPCBus extends EventEmitter {
326
352
  }
327
353
 
328
354
  // Singleton
329
- const ipcBus = new AgentIPCBus();
355
+ const ipcBus = new AgentIPCBus(
356
+ process.env.CC_EVENT_RUNTIME_DURABLE === "1"
357
+ ? { runtimeStore: new EventRuntimeStore() }
358
+ : {},
359
+ );
330
360
  export default ipcBus;
331
361
  export { AgentIPCBus };
@@ -1,10 +1,12 @@
1
1
  /** OS-isolated shell execution for the coding agent. */
2
- import { spawnSync } from "node:child_process";
3
2
  import path from "node:path";
4
3
  import { proxyEnv } from "./sandbox-egress-proxy.js";
4
+ import executionBroker from "./process-execution-broker/index.js";
5
5
 
6
6
  export const DEFAULT_SANDBOX_IMAGE = "node:22-bookworm-slim";
7
- export const _deps = { spawnSync };
7
+ export const _deps = {
8
+ spawnSync: (...args) => executionBroker.spawnSync(...args),
9
+ };
8
10
 
9
11
  function stringList(value) {
10
12
  if (!Array.isArray(value)) return [];
@@ -126,6 +128,10 @@ export function executeSandboxedShell(command, sandbox, options = {}) {
126
128
  }
127
129
  args.push(sandbox.image, "sh", "-lc", String(command || ""));
128
130
  const result = _deps.spawnSync("docker", args, {
131
+ origin: "agent-sandbox:docker",
132
+ scope: "sandbox",
133
+ policy: "allow",
134
+ shell: false,
129
135
  encoding: "utf8",
130
136
  timeout: options.timeout,
131
137
  maxBuffer: options.maxBuffer,
@@ -189,6 +195,10 @@ function executeBubblewrapShell(command, sandbox, options, hostCwd, policy) {
189
195
  ? { ...(options.env || {}), ...proxyEnv(egress.port, "127.0.0.1") }
190
196
  : options.env;
191
197
  const result = _deps.spawnSync("bwrap", args, {
198
+ origin: "agent-sandbox:bubblewrap",
199
+ scope: "sandbox",
200
+ policy: "allow",
201
+ shell: false,
192
202
  cwd: hostCwd,
193
203
  env: bwrapEnv,
194
204
  encoding: "utf8",
@@ -244,6 +254,10 @@ export function probeSandboxAvailability(sandbox, deps = _deps) {
244
254
  ? ["bwrap", ["--version"]]
245
255
  : ["docker", ["version", "--format", "{{.Server.Version}}"]];
246
256
  const result = deps.spawnSync(probeArgs[0], probeArgs[1], {
257
+ origin: "agent-sandbox:probe",
258
+ scope: "sandbox",
259
+ policy: "allow",
260
+ shell: false,
247
261
  encoding: "utf8",
248
262
  timeout: 10000,
249
263
  windowsHide: true,
@@ -27,6 +27,7 @@ import { isEntryExpired, effectiveFireAt } from "./schedule-planner.js";
27
27
  import { SUBAGENT_PERMISSION_MODES } from "./subagent-contract.js";
28
28
  import { parseGoalCondition } from "./goal-condition-engine.js";
29
29
  import { normalizeActionClass } from "./unattended-action-policy.js";
30
+ import { withFileLock } from "./with-file-lock.js";
30
31
 
31
32
  export const SCHEDULE_KINDS = Object.freeze(["wakeup", "cron", "monitor"]);
32
33
 
@@ -155,6 +156,10 @@ function isSchedulableStatus(entry) {
155
156
  : entry.status === "active";
156
157
  }
157
158
 
159
+ function hasLiveExecutionLease(entry, now) {
160
+ return Number(entry.executionLease?.expiresAt) > Number(now);
161
+ }
162
+
158
163
  /** Statuses an entry can never leave — safe to prune. */
159
164
  export const TERMINAL_STATUSES = Object.freeze([
160
165
  "fired",
@@ -487,6 +492,7 @@ export class AgentScheduleStore {
487
492
  // (defense-in-depth: retireExpired need not have run first).
488
493
  if (isEntryExpired(entry, now)) return false;
489
494
  if (!isSchedulableStatus(entry)) return false;
495
+ if (hasLiveExecutionLease(entry, now)) return false;
490
496
  // The effective fire time applies the entry's OWN deterministic jitter
491
497
  // (`entry.jitterMs`, default 0 → base fire time, byte-identical to the
492
498
  // prior `dueAt`/`nextAt` comparison). A jittered entry fires slightly
@@ -496,6 +502,52 @@ export class AgentScheduleStore {
496
502
  });
497
503
  }
498
504
 
505
+ /**
506
+ * Atomically claim due entries for one agenda runner. The lease is retained
507
+ * on the durable entry, so a second process cannot fire the same item while
508
+ * the first is working; an abandoned process becomes reclaimable after the
509
+ * lease expires. This is deliberately separate from `due()` for backwards
510
+ * compatibility with read-only callers and injected test stores.
511
+ */
512
+ claimDue(atMs = null, leaseMs = 120000) {
513
+ const now = atMs != null ? Number(atMs) : this._now();
514
+ const ttl = Math.max(1000, Number(leaseMs) || 120000);
515
+ this._ensureDir();
516
+ return withFileLock(path.join(this.dir, ".agenda-claims"), () => {
517
+ const claimed = [];
518
+ for (const kind of SCHEDULE_KINDS) {
519
+ const entries = this._readAll(kind);
520
+ let changed = false;
521
+ for (const entry of entries) {
522
+ if (!isSchedulableStatus(entry) || isEntryExpired(entry, now)) continue;
523
+ if (hasLiveExecutionLease(entry, now)) continue;
524
+ const fireAt = effectiveFireAt(entry);
525
+ if (fireAt == null || fireAt > now) continue;
526
+ entry.executionLease = {
527
+ owner: `${process.pid}:${randomUUID()}`,
528
+ claimedAt: now,
529
+ expiresAt: now + ttl,
530
+ };
531
+ claimed.push({ ...entry, executionLease: { ...entry.executionLease } });
532
+ changed = true;
533
+ }
534
+ if (changed) this._writeAll(kind, entries);
535
+ }
536
+ return claimed;
537
+ }, { failIfUnavailable: true });
538
+ }
539
+
540
+ /** Release a failed/aborted claim so a later runner can retry it. */
541
+ releaseClaim(id) {
542
+ for (const kind of SCHEDULE_KINDS) {
543
+ const updated = this._mutate(kind, id, (entry) => {
544
+ delete entry.executionLease;
545
+ });
546
+ if (updated) return updated;
547
+ }
548
+ return null;
549
+ }
550
+
499
551
  /**
500
552
  * Retire every schedulable entry whose `expiresAt` has passed (status →
501
553
  * "expired", stamping `expiredAt`), across all kinds, so it never fires again.
@@ -632,6 +684,9 @@ export class AgentScheduleStore {
632
684
  const entry = entries.find((e) => e.id === id);
633
685
  if (!entry) return null;
634
686
  fn(entry);
687
+ // Every lifecycle mutation settles the claim before the write becomes
688
+ // visible, including a recurring cron/monitor entry that remains active.
689
+ delete entry.executionLease;
635
690
  this._writeAll(kind, entries);
636
691
  return entry;
637
692
  }
@@ -30,6 +30,110 @@ export const TOOL_TIER = Object.freeze({
30
30
  EXTENSION: "extension",
31
31
  });
32
32
 
33
+ const ADMISSION_BOOLEAN_FIELDS = Object.freeze([
34
+ "enforce",
35
+ "capabilityGranted",
36
+ "policyAllowed",
37
+ "permissionGranted",
38
+ "budgetOk",
39
+ "uiSupported",
40
+ ]);
41
+ const ADMISSION_TEXT_FIELDS = Object.freeze([
42
+ "source",
43
+ "version",
44
+ "scope",
45
+ "tier",
46
+ ]);
47
+ const ADMISSION_TEXT_PATTERN = /^[A-Za-z0-9@][A-Za-z0-9_.:/@+-]{0,127}$/;
48
+ const RESERVED_TOOL_NAMES = new Set(["__proto__", "prototype", "constructor"]);
49
+
50
+ /**
51
+ * Parse the IDE-to-CLI CC_TOOL_ADMISSION envelope. Only decision/provenance
52
+ * fields are accepted; arguments, prompts and credentials have no place in
53
+ * this contract. Invalid input throws so a host that opted into enforcement
54
+ * cannot silently fall back to an ungoverned session.
55
+ */
56
+ export function parseToolAdmissionConfig(input) {
57
+ if (input == null || input === "") return null;
58
+ let raw;
59
+ try {
60
+ raw = typeof input === "string" ? input : JSON.stringify(input);
61
+ } catch {
62
+ throw new Error("tool admission config is not valid JSON");
63
+ }
64
+ if (typeof raw !== "string") {
65
+ throw new Error("tool admission config must be an object");
66
+ }
67
+ if (Buffer.byteLength(raw, "utf8") > 32768) {
68
+ throw new Error("tool admission config exceeds 32 KiB");
69
+ }
70
+ let value;
71
+ try {
72
+ value = typeof input === "string" ? JSON.parse(input) : input;
73
+ } catch {
74
+ throw new Error("tool admission config is not valid JSON");
75
+ }
76
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
77
+ throw new Error("tool admission config must be an object");
78
+ }
79
+ if (value.enforce !== true) {
80
+ throw new Error("tool admission config must set enforce=true");
81
+ }
82
+
83
+ const sanitize = (entry, label) => {
84
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
85
+ throw new Error(`${label} must be an object`);
86
+ }
87
+ const out = {};
88
+ for (const field of ADMISSION_BOOLEAN_FIELDS) {
89
+ if (entry[field] !== undefined) {
90
+ if (typeof entry[field] !== "boolean") {
91
+ throw new Error(`${label}.${field} must be boolean`);
92
+ }
93
+ out[field] = entry[field];
94
+ }
95
+ }
96
+ for (const field of ADMISSION_TEXT_FIELDS) {
97
+ if (entry[field] !== undefined) {
98
+ if (
99
+ typeof entry[field] !== "string" ||
100
+ !ADMISSION_TEXT_PATTERN.test(entry[field])
101
+ ) {
102
+ throw new Error(`${label}.${field} must be a safe identifier`);
103
+ }
104
+ out[field] = entry[field];
105
+ }
106
+ }
107
+ return out;
108
+ };
109
+
110
+ const config = sanitize(value, "toolAdmission");
111
+ config.enforce = true;
112
+ if (value.tools !== undefined) {
113
+ if (
114
+ !value.tools ||
115
+ typeof value.tools !== "object" ||
116
+ Array.isArray(value.tools)
117
+ ) {
118
+ throw new Error("toolAdmission.tools must be an object");
119
+ }
120
+ const entries = Object.entries(value.tools);
121
+ if (entries.length > 256)
122
+ throw new Error("toolAdmission.tools exceeds 256 entries");
123
+ config.tools = {};
124
+ for (const [name, entry] of entries) {
125
+ if (
126
+ !/^[A-Za-z0-9_.:-]{1,160}$/.test(name) ||
127
+ RESERVED_TOOL_NAMES.has(name)
128
+ ) {
129
+ throw new Error(`invalid tool admission name: ${name}`);
130
+ }
131
+ config.tools[name] = sanitize(entry, `toolAdmission.tools.${name}`);
132
+ }
133
+ }
134
+ return config;
135
+ }
136
+
33
137
  /** Normalize a tier label; anything unrecognized → EXTENSION (fail-closed). */
34
138
  export function normalizeToolTier(value) {
35
139
  const s = String(value || "")
@@ -14,7 +14,7 @@
14
14
  * rule). Cached per process (5 min) so multi-call runs don't re-spawn it.
15
15
  */
16
16
 
17
- import { execSync } from "node:child_process";
17
+ import { executionBroker } from "./process-execution-broker/index.js";
18
18
 
19
19
  const TTL_MS = 5 * 60 * 1000;
20
20
  const _cache = new Map(); // helper command → { key, at }
@@ -31,7 +31,15 @@ export function resolveApiKeyFromHelper(helperCmd, opts = {}) {
31
31
  const now = opts.now || Date.now;
32
32
  const hit = _cache.get(cmd);
33
33
  if (hit && now() - hit.at < TTL_MS) return hit.key;
34
- const exec = opts.exec || execSync;
34
+ const exec =
35
+ opts.exec ||
36
+ ((command, options) =>
37
+ executionBroker.execSync(command, {
38
+ ...options,
39
+ origin: "credential:api-key-helper",
40
+ policy: "allow",
41
+ scope: "credential",
42
+ }));
35
43
  try {
36
44
  const out = exec(cmd, {
37
45
  encoding: "utf-8",
@@ -128,11 +128,23 @@ class AsyncHookSupervisor {
128
128
  if (process.platform === "win32") {
129
129
  const r = this._deps.spawnSync(
130
130
  "taskkill",
131
- ["/pid", String(pid), "/T", "/F"],
131
+ ["/PID", String(pid), "/T", "/F"],
132
132
  { windowsHide: true },
133
133
  );
134
+ // A shell can publish a just-created descendant between the first
135
+ // tree snapshot and termination. Repeat once so that race cannot
136
+ // leave a short-lived hook grandchild orphaned.
137
+ if (!r?.error && r?.status === 0) {
138
+ this._deps.spawnSync(
139
+ "taskkill",
140
+ ["/PID", String(pid), "/T", "/F"],
141
+ { windowsHide: true },
142
+ );
143
+ }
134
144
  // If taskkill couldn't launch, fall back to a direct kill.
135
- if (r && r.error) child.kill(signal);
145
+ if (r && (r.error || (r.status != null && r.status !== 0))) {
146
+ child.kill(signal);
147
+ }
136
148
  } else {
137
149
  // Negative pid → the whole process group (requires the detached spawn).
138
150
  try {
@@ -239,7 +251,7 @@ class AsyncHookSupervisor {
239
251
 
240
252
  let child;
241
253
  try {
242
- child = this._deps.spawn(hook.command, {
254
+ const spawnOptions = {
243
255
  cwd: opts.cwd || process.cwd(),
244
256
  shell: true,
245
257
  // POSIX: own process group so a timeout / stopAll can signal the whole
@@ -250,7 +262,17 @@ class AsyncHookSupervisor {
250
262
  ...process.env,
251
263
  CLAUDE_HOOK_EVENT: hook.event || payload.hook_event_name || "",
252
264
  },
253
- });
265
+ };
266
+ child = opts.broker && hook.origin === "plugin:hook"
267
+ ? opts.broker.spawn(hook.command, [], {
268
+ ...spawnOptions,
269
+ origin: hook.origin,
270
+ policy: "allow",
271
+ pluginId: hook.pluginId || null,
272
+ pluginVersion: hook.pluginVersion || null,
273
+ pluginSource: hook.pluginSource || null,
274
+ })
275
+ : this._deps.spawn(hook.command, spawnOptions);
254
276
  } catch (err) {
255
277
  this._record(hook, {
256
278
  ok: false,
@@ -0,0 +1,71 @@
1
+ /**
2
+ * background-interaction-resolver — 监听 agent 子进程发来的交互请求,
3
+ * 转发给后台会话 transport 并通过 pendingInteractions 追踪回复。
4
+ *
5
+ * 当 agent 调用 onPrompt/onApprove 等需要用户交互的方法时,子进程通过 IPC
6
+ * 发送 { type: "interaction-request", intId, requestType, prompt, options } 消息。
7
+ * 本模块监听这些消息,加入本地 pending map,并广播给所有 attach 客户端。
8
+ */
9
+
10
+ const INTERACTION_TIMEOUT_MS = 5 * 60 * 1000; // 5 分钟超时
11
+
12
+ /**
13
+ * 挂载交互请求监听到 agent 子进程。
14
+ *
15
+ * @param {import('node:child_process').ChildProcess} child - agent 子进程实例
16
+ * @param {Map<string, { resolve: Function, reject: Function, timer: NodeJS.Timeout }>} pendingInteractions - 待处理交互映射
17
+ * @param {Function} broadcast - 广播消息给所有 attach 客户端的函数
18
+ * @returns {Function} 卸载函数,调用后停止监听
19
+ */
20
+ export function attachInteractionRequestHandler(
21
+ child,
22
+ pendingInteractions,
23
+ broadcast,
24
+ ) {
25
+ if (!child) {
26
+ return () => {};
27
+ }
28
+
29
+ const handler = (message) => {
30
+ if (!message || typeof message !== "object") return;
31
+ if (message.type !== "interaction-request") return;
32
+
33
+ const { intId, requestType, prompt, options = {} } = message;
34
+ if (!intId) return;
35
+
36
+ // 加入 pending 映射,设置超时
37
+ const timer = setTimeout(() => {
38
+ const entry = pendingInteractions.get(intId);
39
+ if (!entry) return;
40
+ pendingInteractions.delete(intId);
41
+ // 超时返回默认值:confirm 返回 false,其他返回 null
42
+ const defaultAnswer = requestType === "confirm" ? false : null;
43
+ entry.resolve(defaultAnswer);
44
+ broadcast?.({
45
+ type: "interaction-timeout",
46
+ intId,
47
+ });
48
+ }, INTERACTION_TIMEOUT_MS);
49
+ // 不保持事件循环存活
50
+ timer.unref?.();
51
+
52
+ // 这里不存 resolve/reject — 调用方 (worker) 已经在 agentAskUser 中存了
53
+ // 我们只负责广播给 attach 客户端
54
+ // 但为了超时能触发 worker 的 resolve,需要把 entry 透传?不,worker 自己存 entry
55
+ // 只需要广播消息即可
56
+ broadcast?.({
57
+ type: "interaction_request",
58
+ intId,
59
+ requestType,
60
+ prompt,
61
+ options,
62
+ });
63
+ };
64
+
65
+ child.on("message", handler);
66
+
67
+ // 返回卸载函数
68
+ return () => {
69
+ child.off("message", handler);
70
+ };
71
+ }
@@ -16,9 +16,11 @@
16
16
  * Protocol (one JSON object per line, both directions):
17
17
  * client → worker: {type:"hello", token} · {type:"prompt", text}
18
18
  * · {type:"status"} · {type:"stop"} · {type:"detach"}
19
+ * · {type:"interaction_response", requestId, result, error?}
19
20
  * worker → client: {type:"hello", ...status} · {type:"accepted", queued}
20
21
  * · {type:"status", ...status} · {type:"error", message}
21
22
  * · {type:"turn-started"|"turn-ended"|"idle", ...}
23
+ * · {type:"interaction_request", requestId, payload}
22
24
  */
23
25
 
24
26
  import net from "node:net";
@@ -85,13 +87,24 @@ function writeMessage(socket, message) {
85
87
  * @param {(text:string)=>{queued:number}} opts.onPrompt queue a follow-up
86
88
  * prompt; throw to reject (message is relayed to the client)
87
89
  * @param {()=>void} [opts.onStop] kill the current agent turn
90
+ * @param {(requestId:string, result:any, error?:string)=>void} [opts.onInteractionResponse]
91
+ * handle a user's response to a pending interaction request
88
92
  * @param {(count:number)=>void} [opts.onClientChange]
89
93
  * @param {()=>object} [opts.getStatus] session status payload for hello/status
90
94
  * @returns {Promise<{pipePath:string, clientCount:()=>number,
91
95
  * broadcast:(msg:object)=>void, close:()=>Promise<void>}>}
92
96
  */
93
97
  export function startBackgroundSessionServer(opts) {
94
- const { id, dir, token, onPrompt, onStop, onClientChange, getStatus } = opts;
98
+ const {
99
+ id,
100
+ dir,
101
+ token,
102
+ onPrompt,
103
+ onStop,
104
+ onInteractionResponse,
105
+ onClientChange,
106
+ getStatus,
107
+ } = opts;
95
108
  const pipePath = opts.pipePath || transportPipePath(id, dir);
96
109
  if (process.platform !== "win32") {
97
110
  try {
@@ -182,6 +195,36 @@ export function startBackgroundSessionServer(opts) {
182
195
  socket.end();
183
196
  return;
184
197
  }
198
+ case "interaction_response": {
199
+ try {
200
+ // Support both field names: requestId (client) and intId (wire legacy)
201
+ const { requestId, intId, answer, result, error } = message;
202
+ const resolvedId = requestId || intId;
203
+ if (!resolvedId) {
204
+ writeMessage(socket, {
205
+ type: "error",
206
+ message: "interaction_response requires requestId or intId",
207
+ });
208
+ return;
209
+ }
210
+ // Single-object callback matching worker expectation: { requestId, answer, error }
211
+ onInteractionResponse?.({
212
+ requestId: resolvedId,
213
+ answer: answer ?? result,
214
+ error,
215
+ });
216
+ writeMessage(socket, {
217
+ type: "received",
218
+ requestId: resolvedId,
219
+ });
220
+ } catch (err) {
221
+ writeMessage(socket, {
222
+ type: "error",
223
+ message: err?.message || String(err),
224
+ });
225
+ }
226
+ return;
227
+ }
185
228
  default:
186
229
  writeMessage(socket, {
187
230
  type: "error",
@@ -218,6 +261,21 @@ export function startBackgroundSessionServer(opts) {
218
261
  broadcast: (message) => {
219
262
  for (const socket of clients) writeMessage(socket, message);
220
263
  },
264
+ broadcastInteractionRequest: (intId, payload) => {
265
+ for (const socket of clients)
266
+ writeMessage(socket, {
267
+ type: "interaction_request",
268
+ intId,
269
+ requestId: intId,
270
+ question:
271
+ payload.question || payload.prompt || "Agent needs your input",
272
+ prompt: payload.question || payload.prompt || "",
273
+ hint: payload.hint || "",
274
+ options: payload.options || null,
275
+ multiSelect: payload.multiSelect || false,
276
+ defaultValue: payload.defaultValue,
277
+ });
278
+ },
221
279
  close: () =>
222
280
  new Promise((done) => {
223
281
  for (const socket of clients) socket.destroy();
@@ -225,24 +225,32 @@ function extractCliSections(bodyLines, header) {
225
225
  *
226
226
  * @returns {{ source: string, releases: Array }}
227
227
  */
228
- export function loadChangelog() {
228
+ export function loadChangelog({
229
+ fsApi = fs,
230
+ pathApi = path,
231
+ dirname = __dirname,
232
+ } = {}) {
229
233
  const changelogCandidates = [
230
- path.join(__dirname, "..", "..", "CHANGELOG.md"), // packages/cli/CHANGELOG.md
231
- path.join(__dirname, "..", "..", "..", "..", "CHANGELOG.md"), // repo root
234
+ pathApi.join(dirname, "..", "..", "CHANGELOG.md"), // packages/cli/CHANGELOG.md
235
+ pathApi.join(dirname, "..", "..", "..", "..", "CHANGELOG.md"), // repo root
232
236
  ];
233
237
  for (const p of changelogCandidates) {
234
- if (fs.existsSync(p)) {
235
- return {
236
- source: "CHANGELOG.md",
237
- releases: parseChangelog(fs.readFileSync(p, "utf-8")),
238
- };
238
+ if (fsApi.existsSync(p)) {
239
+ const releases = parseChangelog(fsApi.readFileSync(p, "utf-8"));
240
+ // A parent-level CHANGELOG can exist in a global Node.js installation
241
+ // (for example C:\\nvm4w\\nodejs\\CHANGELOG.md). Do not treat an
242
+ // unrelated, successfully-read file with zero CLI releases as the
243
+ // authoritative source; continue to the bundled artifact instead.
244
+ if (releases.length > 0) {
245
+ return { source: "CHANGELOG.md", releases };
246
+ }
239
247
  }
240
248
  }
241
249
  // Installed npm package: CHANGELOG.md isn't shipped, use the bundled artifact.
242
- const jsonPath = path.join(__dirname, "..", "data", "changelog.json");
243
- if (fs.existsSync(jsonPath)) {
250
+ const jsonPath = pathApi.join(dirname, "..", "data", "changelog.json");
251
+ if (fsApi.existsSync(jsonPath)) {
244
252
  try {
245
- const data = JSON.parse(fs.readFileSync(jsonPath, "utf-8"));
253
+ const data = JSON.parse(fsApi.readFileSync(jsonPath, "utf-8"));
246
254
  if (Array.isArray(data.releases)) return data;
247
255
  } catch {
248
256
  /* fall through to empty */
@@ -20,6 +20,7 @@ import {
20
20
  canApprove,
21
21
  describeAuthorityChain,
22
22
  } from "../agent-authority.js";
23
+ import { EventRuntimeStore } from "../event-runtime-store.js";
23
24
 
24
25
  export const CHANNEL_KINDS = ["webhook", "telegram"];
25
26
 
@@ -120,6 +121,9 @@ export async function startChannels(specsInput, opts = {}) {
120
121
  const config = opts.config || {};
121
122
  const log = opts.log || ((msg) => logger.info(msg));
122
123
  const deps = opts.deps || {};
124
+ const eventRuntimeStore =
125
+ opts.eventRuntimeStore ||
126
+ (process.env.CC_EVENT_RUNTIME_DURABLE === "1" ? new EventRuntimeStore() : null);
123
127
  // Every inbound event is stamped with its channel authority (`steer`, never
124
128
  // `approve`) before the caller's handler sees it — so a channel message can
125
129
  // never be mistaken for a user approval no matter what it contains.
@@ -149,6 +153,7 @@ export async function startChannels(specsInput, opts = {}) {
149
153
  port: spec.arg ? Number(spec.arg) : cfg.port,
150
154
  onEvent,
151
155
  log,
156
+ eventRuntimeStore,
152
157
  });
153
158
  started.push({ kind: "webhook", describe: handle.describe, ...handle });
154
159
  } else if (spec.kind === "telegram") {
@@ -161,6 +166,7 @@ export async function startChannels(specsInput, opts = {}) {
161
166
  ...cfg,
162
167
  onEvent,
163
168
  log,
169
+ eventRuntimeStore,
164
170
  });
165
171
  started.push({
166
172
  kind: "telegram",