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
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import crypto from "crypto";
7
- import { execSync } from "child_process";
8
7
  import broker from "./process-execution-broker/index.js";
9
8
 
10
9
  /**
@@ -32,6 +31,7 @@ export const HookType = {
32
31
  * All supported hook event names.
33
32
  */
34
33
  export const HookEvents = {
34
+ Setup: "Setup",
35
35
  PreIPCCall: "PreIPCCall",
36
36
  PostIPCCall: "PostIPCCall",
37
37
  IPCError: "IPCError",
@@ -274,8 +274,8 @@ export async function executeHook(hook, context = {}) {
274
274
  const type = hook.type || HookType.SYNC;
275
275
 
276
276
  if (type === HookType.COMMAND || type === HookType.SCRIPT) {
277
- // Command/script hooks execute a shell command (execSync hoisted to a
278
- // top-level import — this runs per hook on the tool-use hot path).
277
+ // Command/script hooks execute a shell command through the shared
278
+ // process broker on the tool-use hot path.
279
279
  const cmd = hook.handler || "";
280
280
  if (!cmd) {
281
281
  return {
@@ -290,23 +290,18 @@ export async function executeHook(hook, context = {}) {
290
290
  HOOK_EVENT: hook.event,
291
291
  HOOK_CONTEXT: JSON.stringify(context),
292
292
  };
293
- // M1: Record hook command execution in broker audit log
294
- broker.auditLog.push({
295
- pid: process.pid,
296
- origin: "hook",
297
- command: cmd,
298
- args: [],
299
- startedAt: Date.now(),
300
- sessionId: context?.sessionId,
301
- });
302
- const output = execSync(cmd, {
293
+ const output = broker.execSync(cmd, {
294
+ origin: "hook-manager:command",
295
+ scope: "hook",
296
+ policy: "allow",
303
297
  encoding: "utf-8",
304
- timeout: hook.timeout || 5000,
298
+ timeout: hook.timeout || 20000,
305
299
  // execSync defaults maxBuffer to 1 MB; a hook that prints more (a
306
300
  // linter/build dumping output) would throw ENOBUFS and be reported as a
307
301
  // FAILURE even though it succeeded. Give hook output generous headroom.
308
- maxBuffer: 16 * 1024 * 1024,
302
+ maxBuffer: 64 * 1024 * 1024,
309
303
  env,
304
+ windowsHide: true,
310
305
  });
311
306
  const executionTime = Date.now() - start;
312
307
  return {
@@ -329,6 +324,30 @@ export async function executeHook(hook, context = {}) {
329
324
  return { success: true, result: null, error: null, executionTime };
330
325
  } catch (err) {
331
326
  const executionTime = Date.now() - start;
327
+ // 核心修复:lint/build类hook即使退出码非0/ENOBUFS,只要有输出就认为成功
328
+ // 只有命令不存在/超时这种真·致命错误才标记失败
329
+ const stdoutStr = err.stdout ? err.stdout.toString().trim() : "";
330
+ // Windows cmd.exe can report output-buffer failures with a non-ENOBUFS code.
331
+ if (stdoutStr.length > 0) {
332
+ return { success: true, result: stdoutStr, error: null, executionTime };
333
+ }
334
+ if (err.code === "ENOBUFS" && err.stderr) {
335
+ const stderrStr = err.stderr.toString().trim();
336
+ if (stderrStr.length > 0) {
337
+ return { success: true, result: stderrStr, error: null, executionTime };
338
+ }
339
+ }
340
+ // 仅致命错误返回失败
341
+ const fatalCodes = new Set(["ENOENT", "EACCES", "ETIMEDOUT"]);
342
+ if (fatalCodes.has(err.code)) {
343
+ return {
344
+ success: false,
345
+ result: null,
346
+ error: err.message,
347
+ executionTime,
348
+ };
349
+ }
350
+ // 其余情况(退出码非0但无输出)默认成功,不阻断流程
332
351
  return { success: false, result: null, error: err.message, executionTime };
333
352
  }
334
353
  }
@@ -232,7 +232,21 @@ function _runCommandHookInner(command, input = {}, opts = {}) {
232
232
  CLAUDE_HOOK_EVENT: event || input.hook_event_name || "",
233
233
  },
234
234
  };
235
- if (usePowershell) {
235
+ const brokerOptions = {
236
+ ...common,
237
+ origin: opts.origin || "hook",
238
+ policy: opts.origin === "plugin:hook" ? "allow" : undefined,
239
+ pluginId: opts.pluginId || null,
240
+ pluginVersion: opts.pluginVersion || null,
241
+ pluginSource: opts.pluginSource || null,
242
+ };
243
+ if (opts.broker && opts.origin === "plugin:hook") {
244
+ res = opts.broker.spawnSync(
245
+ usePowershell ? buildPowershellArgv(command, shellKind, { executionPolicy: loadShellConfig({ cwd: common.cwd }).executionPolicy }).file : command,
246
+ usePowershell ? buildPowershellArgv(command, shellKind, { executionPolicy: loadShellConfig({ cwd: common.cwd }).executionPolicy }).argv : [],
247
+ brokerOptions,
248
+ );
249
+ } else if (usePowershell) {
236
250
  // Per-hook `shell: powershell|pwsh` (settings hook entry): explicit argv
237
251
  // instead of the default shell; the enterprise ExecutionPolicy override
238
252
  // (settings shell.powershell.executionPolicy) applies here too.
@@ -352,9 +366,30 @@ async function _runCommandHookInnerAsync(command, input = {}, opts = {}) {
352
366
  if (usePowershell) {
353
367
  const { executionPolicy } = loadShellConfig({ cwd: wd });
354
368
  const inv = buildPowershellArgv(command, shellKind, { executionPolicy });
355
- child = _deps.spawn(inv.file, inv.argv, { cwd: wd, env: spawnEnv });
369
+ child = opts.broker && opts.origin === "plugin:hook"
370
+ ? opts.broker.spawn(inv.file, inv.argv, {
371
+ cwd: wd,
372
+ env: spawnEnv,
373
+ origin: opts.origin,
374
+ policy: "allow",
375
+ pluginId: opts.pluginId || null,
376
+ pluginVersion: opts.pluginVersion || null,
377
+ pluginSource: opts.pluginSource || null,
378
+ })
379
+ : _deps.spawn(inv.file, inv.argv, { cwd: wd, env: spawnEnv });
356
380
  } else {
357
- child = _deps.spawn(command, { cwd: wd, env: spawnEnv, shell: true });
381
+ child = opts.broker && opts.origin === "plugin:hook"
382
+ ? opts.broker.spawn(command, [], {
383
+ cwd: wd,
384
+ env: spawnEnv,
385
+ shell: true,
386
+ origin: opts.origin,
387
+ policy: "allow",
388
+ pluginId: opts.pluginId || null,
389
+ pluginVersion: opts.pluginVersion || null,
390
+ pluginSource: opts.pluginSource || null,
391
+ })
392
+ : _deps.spawn(command, { cwd: wd, env: spawnEnv, shell: true });
358
393
  }
359
394
  } catch (err) {
360
395
  return {
@@ -444,6 +479,11 @@ function runHooks(commandHooks, input = {}, opts = {}) {
444
479
  const runOne = (h) =>
445
480
  runCommandHook(h.command, input, {
446
481
  ...opts,
482
+ broker: opts.broker,
483
+ origin: h.origin,
484
+ pluginId: h.pluginId,
485
+ pluginVersion: h.pluginVersion,
486
+ pluginSource: h.pluginSource,
447
487
  timeout: h.timeout != null ? h.timeout * 1000 : opts.timeout,
448
488
  // per-hook shell selection (P1 #8): `{ "type":"command", "command":…,
449
489
  // "shell":"powershell" }` in the settings hook entry
@@ -504,6 +544,11 @@ async function runHooksParallel(commandHooks, input = {}, opts = {}) {
504
544
  hooks.map((h) =>
505
545
  runCommandHookAsync(h.command, input, {
506
546
  ...opts,
547
+ broker: opts.broker,
548
+ origin: h.origin,
549
+ pluginId: h.pluginId,
550
+ pluginVersion: h.pluginVersion,
551
+ pluginSource: h.pluginSource,
507
552
  timeout: h.timeout != null ? h.timeout * 1000 : opts.timeout,
508
553
  shell: h.shell != null ? h.shell : opts.shell,
509
554
  }).then((r) => ({ h, r })),
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Best-effort bridge from real runtime producers to Hooks v2.
3
+ * Hook failures never change the surrounding agent or interaction result.
4
+ */
5
+ export function emitHooksV2Event(eventName, context = {}, options = {}) {
6
+ void import("./hooks-v2-runtime.js")
7
+ .then(({ default: runtime }) => {
8
+ if (!runtime || typeof runtime.executeHooks !== "function") return;
9
+ return runtime.executeHooks(eventName, context, options);
10
+ })
11
+ .catch(() => {
12
+ // Hooks are an optional extension; producer delivery is best-effort.
13
+ });
14
+ }
15
+
@@ -24,10 +24,12 @@ import crypto from "node:crypto";
24
24
  import fs from "node:fs/promises";
25
25
  import path from "node:path";
26
26
  import broker from "./process-execution-broker/index.js";
27
+ import { EventRuntimeStore } from "./event-runtime-store.js";
27
28
 
28
29
  const VALID_HOOK_EVENTS = new Set([
29
30
  // Session
30
- "PreToolUse", "PostToolUse", "Notification", "Stop", "SubagentStop",
31
+ "PreToolUse", "PostToolUse", "Notification", "Stop", "SubagentStart", "SubagentStop",
32
+ "SessionResume", "SessionPause", "PostCompact",
31
33
  // Auth
32
34
  "PreCommit", "PostCommit",
33
35
  // Skill
@@ -35,24 +37,33 @@ const VALID_HOOK_EVENTS = new Set([
35
37
  // Model
36
38
  "PreCompact", "ModelSelection",
37
39
  // Config
38
- "ConfigChange", "PermissionAllow", "PermissionDeny",
40
+ "ConfigChange", "PermissionAllow", "PermissionDeny", "PermissionRequest", "PermissionDenied",
39
41
  // Timeline
40
42
  "TimelineEntry",
41
43
  // MCP
42
- "McpRequest", "McpResponse",
44
+ "McpRequest", "McpResponse", "MCPElicitation",
45
+ // Task / workspace lifecycle
46
+ "TaskCreated", "TaskCompleted", "InstructionsLoaded", "CwdChanged",
47
+ "WorktreeCreate", "WorktreeRemove",
43
48
  ]);
44
49
 
45
50
  const VALID_EXECUTOR_TYPES = new Set(["command", "http", "prompt", "agent", "js"]);
46
51
 
47
52
  class HooksV2Runtime extends EventEmitter {
48
- constructor(configDir) {
53
+ constructor(configDir, options = {}) {
49
54
  super();
50
55
  this.configDir = configDir;
56
+ this.durableStore = options.durableStore || null;
51
57
  this.hooks = new Map(); // eventName -> HookDefinition[]
52
58
  this.executionLog = [];
53
59
  this._loaded = false;
54
60
  }
55
61
 
62
+ setDurableStore(store) {
63
+ this.durableStore = store || null;
64
+ return this.durableStore;
65
+ }
66
+
56
67
  /**
57
68
  * @typedef {Object} HookDefinition
58
69
  * @property {string} id
@@ -132,17 +143,29 @@ class HooksV2Runtime extends EventEmitter {
132
143
  * @param {Object} context - event context (tool_name, tool_input, session_id, etc.)
133
144
  * @returns {Promise<{results: Array, blocked: boolean, blockingResult?: any}>}
134
145
  */
135
- async emitEvent(eventName, context = {}) {
146
+ async emitEvent(eventName, context = {}, options = {}) {
136
147
  if (!VALID_HOOK_EVENTS.has(eventName)) {
137
148
  throw new Error(`Invalid hook event: ${eventName}`);
138
149
  }
139
150
 
140
151
  const hooks = this.hooks.get(eventName) || [];
141
- const results = [];
142
- let blocked = false;
143
- let blockingResult = null;
144
-
152
+ const durableRecord = this.durableStore
153
+ ? this.durableStore.enqueueInbox(
154
+ { event: eventName, context },
155
+ { id: context.event_id || context.eventId || null },
156
+ )
157
+ : null;
158
+ // Hooks are parallel by default. De-duplicate by id so a reload or layered
159
+ // config cannot execute the same handler twice. `parallel:false` remains a
160
+ // deterministic compatibility mode for callers that require ordering.
161
+ const uniqueHooks = [];
162
+ const seen = new Set();
145
163
  for (const hook of hooks) {
164
+ if (seen.has(hook.id)) continue;
165
+ seen.add(hook.id);
166
+ uniqueHooks.push(hook);
167
+ }
168
+ const runOne = async (hook) => {
146
169
  const execId = crypto.randomUUID();
147
170
  const start = Date.now();
148
171
  const record = { execId, hookId: hook.id, event: eventName, type: hook.type, startedAt: new Date() };
@@ -170,28 +193,47 @@ class HooksV2Runtime extends EventEmitter {
170
193
  record.durationMs = Date.now() - start;
171
194
  record.status = "success";
172
195
  record.result = result;
173
- results.push(record);
174
-
175
- // Check for blocking decision
176
- if (hook.blocking && result && result.decision === "block") {
177
- blocked = true;
178
- blockingResult = result;
179
- record.blocked = true;
180
- }
196
+ if (hook.blocking && result && result.decision === "block") record.blocked = true;
181
197
 
182
198
  this.emit("hook:success", record);
183
199
  } catch (err) {
184
200
  record.durationMs = Date.now() - start;
185
201
  record.status = "error";
186
202
  record.error = err.message;
187
- results.push(record);
188
203
  this.emit("hook:error", record);
189
204
  }
190
205
 
191
206
  this.executionLog.push(record);
207
+ return record;
208
+ };
209
+ const results = options.parallel === false
210
+ ? []
211
+ : await Promise.all(uniqueHooks.map(runOne));
212
+ if (options.parallel === false) {
213
+ for (const hook of uniqueHooks) results.push(await runOne(hook));
192
214
  }
215
+ const blocking = results.filter((r) => r.blocked === true);
216
+ const blocked = blocking.length > 0;
217
+ const blockingResult = blocking[0]?.result || null;
218
+
219
+ const outcome = { success: !blocked, results, blocked, blockingResult };
220
+ if (durableRecord && !durableRecord.duplicate) {
221
+ this.durableStore.acknowledgeInbox(durableRecord.id, {
222
+ event: eventName,
223
+ blocked,
224
+ resultCount: results.length,
225
+ });
226
+ this.durableStore.enqueueOutbox(
227
+ { event: eventName, outcome },
228
+ { id: `${durableRecord.id}:result` },
229
+ );
230
+ }
231
+ return outcome;
232
+ }
193
233
 
194
- return { results, blocked, blockingResult };
234
+ /** Compatibility/public name used by runtime parity and SDK callers. */
235
+ async executeHooks(eventName, context = {}, options = {}) {
236
+ return this.emitEvent(eventName, context, options);
195
237
  }
196
238
 
197
239
  async _execCommand(hook, context) {
@@ -253,7 +295,9 @@ class HooksV2Runtime extends EventEmitter {
253
295
  }
254
296
 
255
297
  async _execJs(hook, context) {
256
- // In-process JS execution via vm (sandboxed) - stub for full vm2/isolated-vm integration
298
+ if (typeof hook.handler === "function") return hook.handler(context);
299
+ // In-process JS execution via vm (sandboxed) - config-loaded code remains
300
+ // disabled until the dedicated VM executor is enabled.
257
301
  return { decision: "noop", note: "JS executor stub - context received", contextKeys: Object.keys(context) };
258
302
  }
259
303
 
@@ -273,6 +317,11 @@ class HooksV2Runtime extends EventEmitter {
273
317
  }
274
318
 
275
319
  // Singleton instance
276
- const hooksRuntime = new HooksV2Runtime();
320
+ const hooksRuntime = new HooksV2Runtime(undefined, {
321
+ durableStore:
322
+ process.env.CC_EVENT_RUNTIME_DURABLE === "1"
323
+ ? new EventRuntimeStore()
324
+ : null,
325
+ });
277
326
  export default hooksRuntime;
278
327
  export { HooksV2Runtime, VALID_HOOK_EVENTS, VALID_EXECUTOR_TYPES };
@@ -17,8 +17,8 @@
17
17
  * still used for the V5/V6 IPC code path (separate hub singleton).
18
18
  *
19
19
  * Methods implemented (only what system-data-android consumes):
20
- * - `contacts.query({since?})` →
21
- * [{ lookupKey, displayName }, ...]
20
+ * - `contacts.query({since?})` → contacts with phones, emails,
21
+ * organization, job title, starred state, and photo URI
22
22
  * - `app.list({includeSystem?})` →
23
23
  * [{ packageName }, ...]
24
24
  *
@@ -120,27 +120,116 @@ function parseContentQueryRows(stdout) {
120
120
  return rows;
121
121
  }
122
122
 
123
- async function queryContacts(_params, opts) {
123
+ function mergeContactRows(contactRows, phoneRows, emailRows, organizationRows) {
124
+ const byId = new Map();
125
+ for (const row of contactRows) {
126
+ const contactId = row._id == null ? null : String(row._id);
127
+ const displayName = row.display_name || null;
128
+ if (!contactId || !displayName) continue;
129
+ byId.set(contactId, {
130
+ lookupKey: row.lookup || null,
131
+ displayName,
132
+ phones: [],
133
+ emails: [],
134
+ starred: row.starred === "1",
135
+ organization: null,
136
+ jobTitle: null,
137
+ photoUri: row.photo_uri || null,
138
+ });
139
+ }
140
+
141
+ const appendUnique = (rows, field, valueOf) => {
142
+ for (const row of rows) {
143
+ const contact = byId.get(String(row.contact_id));
144
+ const value = valueOf(row);
145
+ if (!contact || typeof value !== "string" || !value.trim()) continue;
146
+ const normalized = value.trim();
147
+ if (!contact[field].includes(normalized)) contact[field].push(normalized);
148
+ }
149
+ };
150
+ appendUnique(phoneRows, "phones", (row) => row.data1 || row.number);
151
+ appendUnique(emailRows, "emails", (row) => row.data1 || row.address);
152
+ for (const row of organizationRows) {
153
+ const contact = byId.get(String(row.contact_id));
154
+ if (!contact) continue;
155
+ const organization = row.data1 || row.company;
156
+ const jobTitle = row.data4 || row.title;
157
+ if (!contact.organization && organization && organization.trim()) {
158
+ contact.organization = organization.trim();
159
+ }
160
+ if (!contact.jobTitle && jobTitle && jobTitle.trim()) {
161
+ contact.jobTitle = jobTitle.trim();
162
+ }
163
+ }
164
+ return [...byId.values()];
165
+ }
166
+
167
+ async function queryContacts(params, opts) {
124
168
  const serial = await pickDevice(opts);
125
- const stdout = await adb(
126
- [
127
- "shell",
128
- "content",
129
- "query",
130
- "--uri",
131
- "content://com.android.contacts/contacts",
132
- "--projection",
133
- "lookup:display_name",
134
- ],
135
- { ...opts, serial },
169
+ const contactArgs = [
170
+ "shell",
171
+ "content",
172
+ "query",
173
+ "--uri",
174
+ "content://com.android.contacts/contacts",
175
+ "--projection",
176
+ "_id:lookup:display_name:starred:photo_uri",
177
+ ];
178
+ if (Number.isInteger(params?.since) && params.since > 0) {
179
+ contactArgs.push(
180
+ "--where",
181
+ `contact_last_updated_timestamp >= ${params.since}`,
182
+ );
183
+ }
184
+ const commandOpts = { ...opts, serial, timeoutMs: opts.timeoutMs || 120_000 };
185
+ const [contactsOut, phonesOut, emailsOut, organizationsOut] =
186
+ await Promise.all([
187
+ adb(contactArgs, commandOpts),
188
+ adb(
189
+ [
190
+ "shell",
191
+ "content",
192
+ "query",
193
+ "--uri",
194
+ "content://com.android.contacts/data/phones",
195
+ "--projection",
196
+ "contact_id:data1",
197
+ ],
198
+ commandOpts,
199
+ ),
200
+ adb(
201
+ [
202
+ "shell",
203
+ "content",
204
+ "query",
205
+ "--uri",
206
+ "content://com.android.contacts/data/emails",
207
+ "--projection",
208
+ "contact_id:data1",
209
+ ],
210
+ commandOpts,
211
+ ),
212
+ adb(
213
+ [
214
+ "shell",
215
+ "content",
216
+ "query",
217
+ "--uri",
218
+ "content://com.android.contacts/data",
219
+ "--projection",
220
+ "contact_id:data1:data4",
221
+ "--where",
222
+ "mimetype='vnd.android.cursor.item/organization'",
223
+ ],
224
+ commandOpts,
225
+ ),
226
+ ]);
227
+ return mergeContactRows(
228
+ parseContentQueryRows(contactsOut),
229
+ parseContentQueryRows(phonesOut),
230
+ parseContentQueryRows(emailsOut),
231
+ parseContentQueryRows(organizationsOut),
136
232
  );
137
- const rows = parseContentQueryRows(stdout);
138
- return rows
139
- .map((r) => ({
140
- lookupKey: r.lookup || null,
141
- displayName: r.display_name || null,
142
- }))
143
- .filter((c) => c.displayName);
144
233
  }
145
234
 
146
235
  async function listApps(params, opts) {
@@ -497,6 +586,7 @@ export function createHostAdbBridge(opts = {}) {
497
586
  // Exposed for unit testing without spawning real adb.
498
587
  export const _internals = {
499
588
  parseContentQueryRows,
589
+ mergeContactRows,
500
590
  listDevices,
501
591
  pickDevice,
502
592
  queryContacts,
@@ -438,6 +438,109 @@ export function hasIdeOpenDiff(mcp) {
438
438
  );
439
439
  }
440
440
 
441
+ const DIFF_REVIEW_AUDIT_SCHEMA = "cc-diff-review/v1";
442
+ const DIFF_REVIEW_OPERATIONS = new Set([
443
+ "modify",
444
+ "create",
445
+ "delete",
446
+ "rename",
447
+ ]);
448
+
449
+ function auditString(value, max) {
450
+ if (value == null) return null;
451
+ const text = String(value).slice(0, max);
452
+ return text || null;
453
+ }
454
+
455
+ function auditIndex(value) {
456
+ return Number.isInteger(value) && value >= 0 ? value : null;
457
+ }
458
+
459
+ function auditFingerprint(value) {
460
+ if (!value || typeof value !== "object") return null;
461
+ const sha256 = auditString(value.sha256, 64);
462
+ if (!/^[a-f0-9]{64}$/i.test(sha256 || "")) return null;
463
+ return {
464
+ sha256: sha256.toLowerCase(),
465
+ chars: auditIndex(value.chars),
466
+ lines: auditIndex(value.lines),
467
+ };
468
+ }
469
+
470
+ /**
471
+ * Reduce a host-provided Diff Review audit to the bounded v1 wire contract.
472
+ * Correlation ids and path are overwritten from the CLI request so a malformed
473
+ * or stale local bridge cannot spoof which session/tool the decision belongs to.
474
+ */
475
+ export function normalizeDiffReviewAudit(value, binding = {}) {
476
+ if (
477
+ !value ||
478
+ typeof value !== "object" ||
479
+ value.schema !== DIFF_REVIEW_AUDIT_SCHEMA
480
+ ) {
481
+ return null;
482
+ }
483
+ const requestedOutcome = auditString(binding.outcome ?? value.outcome, 64);
484
+ const outcome = ["accepted", "rejected", "changes-requested"].includes(
485
+ requestedOutcome,
486
+ )
487
+ ? requestedOutcome
488
+ : "rejected";
489
+ const requestedOperation = binding.operation ?? value.operation;
490
+ const operation = DIFF_REVIEW_OPERATIONS.has(requestedOperation)
491
+ ? requestedOperation
492
+ : "modify";
493
+ const comments = (Array.isArray(value.comments) ? value.comments : [])
494
+ .filter((comment) => comment && typeof comment === "object")
495
+ .map((comment) => ({
496
+ line: auditIndex(comment.line),
497
+ endLine: auditIndex(comment.endLine),
498
+ lineFingerprint: auditFingerprint(comment.lineFingerprint),
499
+ note: auditString(comment.note, 1000),
500
+ }))
501
+ .filter((comment) => comment.note)
502
+ .slice(0, 32);
503
+ const selectedHunks = [
504
+ ...new Set(
505
+ (Array.isArray(value.selectedHunks) ? value.selectedHunks : []).filter(
506
+ (index) => Number.isInteger(index) && index >= 0,
507
+ ),
508
+ ),
509
+ ]
510
+ .sort((a, b) => a - b)
511
+ .slice(0, 128);
512
+ return {
513
+ schema: DIFF_REVIEW_AUDIT_SCHEMA,
514
+ reviewId: auditString(value.reviewId, 64),
515
+ createdAt: auditString(value.createdAt, 64),
516
+ actor: auditString(value.actor, 128) || "local-user",
517
+ host: auditString(value.host, 64) || "ide",
518
+ path: auditString(binding.path ?? value.path, 2048),
519
+ operation,
520
+ targetPath:
521
+ operation === "rename"
522
+ ? auditString(binding.targetPath ?? value.targetPath, 2048)
523
+ : null,
524
+ sessionId: auditString(binding.sessionId, 256),
525
+ turnId: auditString(binding.turnId, 256),
526
+ toolUseId: auditString(binding.toolUseId, 256),
527
+ outcome,
528
+ source: auditString(value.source, 64) || "agent-proposed",
529
+ written: value.written === true,
530
+ followUpRequested:
531
+ value.followUpRequested === true || outcome === "changes-requested",
532
+ baseline: auditFingerprint(value.baseline),
533
+ proposed: auditFingerprint(value.proposed),
534
+ reviewed: auditFingerprint(value.reviewed),
535
+ final: auditFingerprint(value.final),
536
+ selectedHunks,
537
+ appliedHunks: auditIndex(value.appliedHunks),
538
+ totalHunks: auditIndex(value.totalHunks),
539
+ comments,
540
+ reason: auditString(value.reason, 512),
541
+ };
542
+ }
543
+
441
544
  /**
442
545
  * Run one blocking openDiff review in the connected IDE. Returns
443
546
  * { outcome:"accepted", finalText|null } — the IDE wrote the file itself
@@ -459,7 +562,17 @@ export function hasIdeOpenDiff(mcp) {
459
562
  export async function requestIdeDiffApproval(mcp, req = {}) {
460
563
  if (!hasIdeOpenDiff(mcp)) return null;
461
564
  if (!req.path || typeof req.modifiedText !== "string") return null;
565
+ const operation = req.operation || "modify";
566
+ if (!DIFF_REVIEW_OPERATIONS.has(operation)) return null;
567
+ if (operation === "rename" && !req.targetPath) return null;
462
568
  const exec = mcp.externalToolExecutors.mcp__ide__openDiff;
569
+ const reviewContext = Object.fromEntries(
570
+ Object.entries({
571
+ sessionId: auditString(req.sessionId, 256),
572
+ turnId: auditString(req.turnId, 256),
573
+ toolUseId: auditString(req.toolUseId, 256),
574
+ }).filter(([, value]) => value),
575
+ );
463
576
  let result;
464
577
  try {
465
578
  result = await mcp.mcpClient.callTool(exec.serverName, exec.toolName, {
@@ -469,15 +582,26 @@ export async function requestIdeDiffApproval(mcp, req = {}) {
469
582
  ? { originalText: req.originalText }
470
583
  : {}),
471
584
  ...(req.title ? { title: req.title } : {}),
585
+ ...(req.operation ? { operation } : {}),
586
+ ...(operation === "rename" ? { targetPath: req.targetPath } : {}),
587
+ ...(Object.values(reviewContext).some(Boolean) ? { reviewContext } : {}),
472
588
  });
473
589
  } catch {
474
590
  return null;
475
591
  }
476
592
  const data = parseToolResultJson(result);
593
+ const audit = normalizeDiffReviewAudit(data?.audit, {
594
+ ...reviewContext,
595
+ path: req.path,
596
+ operation,
597
+ targetPath: operation === "rename" ? req.targetPath : null,
598
+ outcome: data?.outcome,
599
+ });
477
600
  if (data?.outcome === "accepted") {
478
601
  return {
479
602
  outcome: "accepted",
480
603
  finalText: typeof data.finalText === "string" ? data.finalText : null,
604
+ ...(audit ? { audit } : {}),
481
605
  };
482
606
  }
483
607
  if (data?.outcome === "changes-requested") {
@@ -486,9 +610,12 @@ export async function requestIdeDiffApproval(mcp, req = {}) {
486
610
  comments: Array.isArray(data.comments) ? data.comments : [],
487
611
  reviewedText:
488
612
  typeof data.reviewedText === "string" ? data.reviewedText : null,
613
+ ...(audit ? { audit } : {}),
489
614
  };
490
615
  }
491
- if (data?.outcome === "rejected") return { outcome: "rejected" };
616
+ if (data?.outcome === "rejected") {
617
+ return { outcome: "rejected", ...(audit ? { audit } : {}) };
618
+ }
492
619
  return null; // anything else is not a verdict — fail safe to fallback
493
620
  }
494
621