chainlesschain 0.162.176 → 0.162.178

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 (260) hide show
  1. package/README.md +10 -0
  2. package/package.json +1 -1
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-BDLu5Elz.js → AIOps-DRftcSue.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-DH5us-CK.js → ActionButton-BFvUaMKR.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-BZ0u8IFG.js → Analytics-C0-Rru4P.js} +3 -3
  7. package/src/assets/web-panel/assets/AppLayout-bx-BCljj.js +9 -0
  8. package/src/assets/web-panel/assets/{Artifacts-Br2YBbh_.js → Artifacts-DAJ8B3Un.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-C3C6a482.js → Audit-hOk4L1lr.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-CzHvebcj.js → BackgroundAgents-3pbDpM9z.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-DZNHYDFd.js → Backup-BtziGDn9.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-VRiC4fIx.js → BaseInput-kmshphJ3.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-Cm08WWAD.js → Chat-d7tGSosA.js} +5 -5
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CGHYrugQ.js → ChatBubbleRenderer-p-_PBpX_.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-DtByk7d7.js → Checkbox-C4Eh4Tz5.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-CphXXOfD.js → Codegen-r7gmhZyA.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-Hz86TnLR.js → Col-U7mDaGlL.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-HP03ltpD.js → Community-Bpu8aH1T.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-B_N1mqQz.js → Compact-CHb2XBJe.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-CVztRpi8.js → Compliance-Cn_r4dey.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-wUVOyZih.js → Cowork-CdMWfDcz.js} +4 -4
  22. package/src/assets/web-panel/assets/{Cron-DW5TLJKw.js → Cron-BtnREHWy.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-CrAFGhWH.js → Crosschain-BKI9TSzr.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-pA-oD8ke.js → DID-pkNubzzJ.js} +2 -2
  25. package/src/assets/web-panel/assets/Dashboard-1rrz1snN.js +3 -0
  26. package/src/assets/web-panel/assets/{Dropdown-EweJcsek.js → Dropdown-DLyFVxDc.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-C9xVLPG4.js → EmailListRenderer-CtUWfYVq.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-CDcEEqlu.js → FamilyGuardDashboard-B8eX2Qe4.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-DtZda9A_.js → Federation-D8lsDGus.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-CiYdcVz3.js → FormItemContext-CRYt_aIw.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-DA13uwA0.js → GenericCardRenderer-ClKzY8_N.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-DzRhZD1O.js → Git-BXj5Dney.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-D5RMgOSb.js → Governance-Cm-I8RMz.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-BgrPfSNk.js → Inference-CPvbhvgt.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-DzjnD571.js → KnowledgeGraph-sYNDZaoi.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-BhWzVDtN.js → Logs-BZY_3CRZ.js} +2 -2
  37. package/src/assets/web-panel/assets/{MarkdownRenderer-BDape9cx.js → MarkdownRenderer-up0BW6pv.js} +1 -1
  38. package/src/assets/web-panel/assets/{Marketplace-DJtL5GV7.js → Marketplace-C5MEJ2Qe.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-CZcQygI7.js → McpTools-ihdrn43I.js} +5 -5
  40. package/src/assets/web-panel/assets/{Memory-DUWSDUUu.js → Memory-Br8bPMlh.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-BTwq2WKY.js → MobileBridge-BNntgrYW.js} +1 -1
  42. package/src/assets/web-panel/assets/MobileProjects-BdV915mw.js +1 -0
  43. package/src/assets/web-panel/assets/{Mtc-BiGugEQm.js → Mtc-A3wDmlqL.js} +5 -5
  44. package/src/assets/web-panel/assets/{MtcAudit-DY7a6gUe.js → MtcAudit-CF-mBLWM.js} +2 -2
  45. package/src/assets/web-panel/assets/{Multisig-BQbDu_w7.js → Multisig-Iy2k_MSo.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-CM2wXTLv.js → NLProgramming-kk0W7HUb.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-DI6gGs1v.js → Notes-B5u5t_4S.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-BsZOLWAB.js → NotificationSettings-BN0POf6_.js} +1 -1
  49. package/src/assets/web-panel/assets/OrderTableRenderer-CHkSUrXB.js +1 -0
  50. package/src/assets/web-panel/assets/{Organization-Cds0_tXr.js → Organization-DwWQESuN.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-WunYMD87.js → Overflow-DG6klrcC.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-Bo6j4DDv.js → P2P-BwJcKkgZ.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-Bh2XPD5f.js → PdhVaultBrowser-BwOHG0in.js} +5 -5
  54. package/src/assets/web-panel/assets/{Permissions-EMvMMC8N.js → Permissions-CGMXe4TX.js} +4 -4
  55. package/src/assets/web-panel/assets/PersonalDataHub-ziYqg7-A.js +8 -0
  56. package/src/assets/web-panel/assets/{Pipeline-BOx8HOgL.js → Pipeline-BzJfeoGt.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-tBeTVQVM.js → Privacy-DLh3Bblx.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-CVYg1W4M.js → ProjectInit-USVWW36c.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-Dvt5I7y1.js → ProjectSettings-CiiOn62h.js} +2 -2
  60. package/src/assets/web-panel/assets/Projects-6V-PNmcA.js +1 -0
  61. package/src/assets/web-panel/assets/{Providers-Ct8xqY-E.js → Providers-CBPWWzpu.js} +1 -1
  62. package/src/assets/web-panel/assets/{QrScannerModal-Cni8Ooja.js → QrScannerModal-QVwoRUq3.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-BJVLKdxr.js → QuickAsk-CXnR-2Vn.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-DPG8Rbbm.js → Recommend-ClaNzjmF.js} +1 -1
  65. package/src/assets/web-panel/assets/{RemoteSession-DsdR7dCt.js → RemoteSession-C3rGw8vJ.js} +2 -2
  66. package/src/assets/web-panel/assets/{Reputation-Csg1YM-b.js → Reputation-Ci-OWAoP.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-D9DoFoEf.js → Row-DRhAwXOS.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-BsvKrXMS.js → RssFeed-BQLJQ2_y.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-DFUStfgQ.js → Search-QQUpkfFd.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-ILg1zxdK.js → Security-DdXKzuKT.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-Dd41PCaY.js → Services-x2Zh62Qd.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-Bzo1cN80.js → Skeleton-GdY4KwRz.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-BDHh17P0.js → Skills-Bv4tY1Fd.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-jl7UTiRY.js → Sla-C3QnM-11.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-BePa-RF6.js → SpeechSettings-Bl3ytvmI.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-DiqqDKGZ.js → SyncSettings-Wp9IwTsP.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-DYQ_6lxj.js → Tasks-CF3rIrDe.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-JiDeI06L.js → Templates-CGfvVVM9.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-hhgI6zwS.js → Tenant-CVXmwQ3U.js} +1 -1
  80. package/src/assets/web-panel/assets/Terminal-bvwrt03E.js +3 -0
  81. package/src/assets/web-panel/assets/{TimelineRenderer-B8uB5Llk.js → TimelineRenderer-D0g74KhH.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-C3b_6r2z.js → Tokens-BH4IwzlT.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-tIP7HKVe.js → Trigger-DJOpM533.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-vjoc11vJ.js → Trust-B43EPRLr.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-DUPBnGuH.js → UkeySign-BmBFG-em.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-CBvhUY5T.js → VideoEditing-n9oJwB8k.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-DUaQ0uA5.js → Wallet-D5QeivHp.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-DllSivjE.js → WebAuthn-DcNy7igO.js} +5 -5
  89. package/src/assets/web-panel/assets/{WorkflowEditor-xc8D3uO6.js → WorkflowEditor-BVjc7-5-.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-BVicU7oA.js → chat-Dy5Tfj3m.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-DJzLmhLm.js → colors-C4c2CNZU.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-BvYRfThE.js → compact-item-DPa3O5vN.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-DGXxCBKR.js → createContext-TLcfNA6_.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-BAwdDA_5.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-SBDJB1y4.js → hasIn-D41LVFkp.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-D7HimK0M.js → index-0oevYjfT.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DCdRAgjy.js → index-388pLGJ1.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BO1itZaY.js → index-B8nLBZbv.js} +3 -3
  99. package/src/assets/web-panel/assets/{index-DvUTDYXX.js → index-BPTGAjee.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-hxTODbM1.js → index-BPtrOBmW.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-wcCL-miV.js → index-BQiIxHBy.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CKyEivf8.js → index-BSM1cHVK.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BJZf9DhV.js → index-BYPr9fkz.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DHVLJ8q0.js → index-BsQ7Ev6i.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-Cs2rmLFt.js → index-Btk9qLL2.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-z1ZylsLq.js → index-BvmziZSG.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Cf-O_g_8.js → index-BvopLC_T.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DMarmfrv.js → index-C7xhTVyP.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CoJAO1Lm.js → index-CNk_ZooP.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-9gdI7uUW.js → index-CQrEHoOG.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Bf-ctERC.js → index-CSxex23J.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-MjC4G09d.js → index-CVjgm992.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-e4fXH_WO.js → index-CWK4zOPe.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-xfluRkCT.js → index-CX0VsoP4.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DRfiXB_p.js → index-CXl0YPNG.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-d5BVd-cL.js → index-Cip7LWml.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Dm_77jgR.js → index-Cq_hlWNt.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-YJkzy8ZF.js → index-CzZ49YZL.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CtwqO5qo.js → index-D2Nkivlm.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BYqz4Wrr.js → index-DBUgRs4D.js} +1 -1
  121. package/src/assets/web-panel/assets/index-DEjVkdzq.js +1 -0
  122. package/src/assets/web-panel/assets/{index-CdGY9P8a.js → index-DNsBj2Ob.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DonCnfMr.js → index-Di4X8cfI.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-1SdDS6lR.js → index-DljFsVGI.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DnjPdvR6.js → index-Korc3QIe.js} +1 -1
  126. package/src/assets/web-panel/assets/index-LMOc5xrS.js +1 -0
  127. package/src/assets/web-panel/assets/{index-VMfwIH5G.js → index-MKZDje0H.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DKrvvWm4.js → index-OHAfRu_3.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-FxZzRyE1.js → index-WEJr8PL5.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Crk5NTb0.js → index-WinCp6du.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DCqRS6da.js → index-Yjr6cqSK.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-BTrBGBJs.js → index-iQ6gtFih.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-lpaGoTH3.js → index-pt3s7yvV.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-CloCgBUR.js → index-tQ3igERQ.js} +1 -1
  135. package/src/assets/web-panel/assets/{initDefaultProps-C1zO1KnY.js → initDefaultProps-BFZu87WZ.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-CWLtEGmC.js → motion-DJIo7qvt.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-DzD_C3Vm.js → move-Cfr5qknL.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-D880PYJl.js → mtc-parser-Bgc-OadH.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-CFR_z2ov.js → omit-X3WI-TNp.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-srIhgrSC.js → pickAttrs-pJhU9IxK.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-C1rXpibP.js → placementArrow-BNg_Vj3T.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-C30gRcSS.js → responsiveObserve-TeSEGQ5-.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-CvtKiMfV.js → slide-D_t_P0bv.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-DNHO7ITG.js → statusUtils-DrrIMwAT.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-Dt_Sl-g4.js → styleChecker-BjZCuFRm.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-Cjev42Gh.js → useFlexGapSupport-rTFdlqdQ.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-Baxglj2V.js → useFs-BidCpfLX.js} +1 -1
  148. package/src/assets/web-panel/assets/usePersonalDataHub-C5mHttA9.js +1 -0
  149. package/src/assets/web-panel/assets/{vnode-mIRkdT7o.js → vnode-BrbcRiHZ.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-HzI5DlH_.js → zoom-PISX7AkR.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/commands/__tests__/hub-wechat.test.js +45 -0
  153. package/src/commands/agenda.js +22 -6
  154. package/src/commands/agent.js +3 -3
  155. package/src/commands/background-session.js +16 -6
  156. package/src/commands/batch.js +79 -27
  157. package/src/commands/changelog.js +15 -4
  158. package/src/commands/context.js +33 -1
  159. package/src/commands/eval.js +21 -6
  160. package/src/commands/hook.js +2 -2
  161. package/src/commands/hub.js +473 -39
  162. package/src/commands/init.js +212 -110
  163. package/src/commands/llm.js +22 -6
  164. package/src/commands/loop.js +9 -2
  165. package/src/commands/skill.js +13 -1
  166. package/src/commands/statusline.js +3 -3
  167. package/src/data/changelog.json +53 -5
  168. package/src/gateways/ws/personal-data-hub-protocol.js +22 -2
  169. package/src/harness/background-task-manager.js +18 -6
  170. package/src/harness/background-task-worker.js +11 -18
  171. package/src/harness/golden-transcript.js +3 -0
  172. package/src/harness/mcp-client.js +9 -15
  173. package/src/harness/worktree-isolator.js +18 -21
  174. package/src/index.js +18 -7
  175. package/src/lib/agent-core.js +5 -0
  176. package/src/lib/agent-ipc-bus.js +12 -3
  177. package/src/lib/agent-team/team-worktree.js +28 -6
  178. package/src/lib/agent-worktree.js +20 -19
  179. package/src/lib/approval-authority-store.js +891 -0
  180. package/src/lib/async-hook-supervisor.cjs +134 -24
  181. package/src/lib/async-hook-supervisor.js +47 -0
  182. package/src/lib/background-agent-supervisor.js +35 -12
  183. package/src/lib/background-interaction-resolver.js +399 -54
  184. package/src/lib/background-session-transport.js +3 -1
  185. package/src/lib/background-task-manager.js +5 -1
  186. package/src/lib/changelog.js +57 -0
  187. package/src/lib/chrome-connector.js +6 -2
  188. package/src/lib/claude-code-bridge.js +24 -8
  189. package/src/lib/cli-anything-bridge.js +82 -25
  190. package/src/lib/context-breakdown.js +82 -3
  191. package/src/lib/doctor-checkup.js +18 -6
  192. package/src/lib/eval/tasks.js +25 -31
  193. package/src/lib/event-runtime-host.js +225 -0
  194. package/src/lib/event-runtime-store.js +102 -21
  195. package/src/lib/event-runtime-worker.js +70 -2
  196. package/src/lib/hook-runner.cjs +71 -36
  197. package/src/lib/hook-runner.js +55 -0
  198. package/src/lib/hooks-v2-producers.js +33 -8
  199. package/src/lib/hooks-v2-runtime.js +360 -40
  200. package/src/lib/host-adb-bridge.js +18 -3
  201. package/src/lib/interaction-adapter.js +66 -0
  202. package/src/lib/lsp/__tests__/benchmark.test.js +61 -0
  203. package/src/lib/lsp/__tests__/lsp-client.test.js +6 -1
  204. package/src/lib/lsp/benchmark.js +20 -4
  205. package/src/lib/lsp/lsp-client.js +6 -4
  206. package/src/lib/lsp/lsp-server-registry.js +0 -2
  207. package/src/lib/operation-fingerprint.js +107 -2
  208. package/src/lib/orchestrator.js +8 -2
  209. package/src/lib/packer/pack-update-applier.js +14 -2
  210. package/src/lib/packer/smoke-runner.js +18 -5
  211. package/src/lib/paths.js +1 -1
  212. package/src/lib/pdh-dedicated-batch-collectors.js +124 -0
  213. package/src/lib/personal-data-hub-wiring.js +327 -52
  214. package/src/lib/plugin-monitor-supervisor.js +20 -13
  215. package/src/lib/plugin-runtime/install.js +10 -3
  216. package/src/lib/process-execution-broker/credential-agent.js +954 -111
  217. package/src/lib/process-execution-broker/index.js +369 -85
  218. package/src/lib/process-execution-broker/platform-sandbox.js +320 -140
  219. package/src/lib/provider-http-error.js +94 -0
  220. package/src/lib/remote-approval-bridge.js +222 -26
  221. package/src/lib/repl-bang-memorize.js +10 -2
  222. package/src/lib/repl-goal.js +19 -2
  223. package/src/lib/settings-hook-events.cjs +13 -8
  224. package/src/lib/settings-hook-events.js +20 -0
  225. package/src/lib/side-effect-ledger-store.js +65 -14
  226. package/src/lib/skill-loader.js +215 -12
  227. package/src/lib/skill-packs/generator.js +18 -9
  228. package/src/lib/skill-process-broker.js +85 -0
  229. package/src/lib/slash-commands.js +10 -2
  230. package/src/lib/status-line.cjs +28 -7
  231. package/src/lib/status-line.js +33 -0
  232. package/src/lib/sub-agent-context.js +42 -0
  233. package/src/lib/turn-binding-store.js +64 -15
  234. package/src/lib/turn-binding.js +85 -16
  235. package/src/repl/agent-repl.js +88 -49
  236. package/src/repl/remote-approval.js +13 -13
  237. package/src/repl/repl-turn-binding.js +46 -16
  238. package/src/runtime/agent-core.js +419 -84
  239. package/src/runtime/coding-agent-contract-shared.cjs +16 -0
  240. package/src/runtime/headless-runner.js +172 -44
  241. package/src/runtime/headless-stream.js +221 -11
  242. package/src/runtime/session-slash-commands.js +506 -0
  243. package/src/skills/video-editing/extractors/audio-extractor.js +13 -5
  244. package/src/skills/video-editing/extractors/video-extractor.js +13 -3
  245. package/src/skills/video-editing/media-process.js +20 -0
  246. package/src/skills/video-editing/render/audio-mix.js +13 -3
  247. package/src/skills/video-editing/render/ffmpeg-concat.js +7 -2
  248. package/src/skills/video-editing/render/ffmpeg-extract.js +7 -2
  249. package/src/workers/background-agent-worker.js +76 -40
  250. package/src/assets/web-panel/assets/AppLayout-Duu8xR14.js +0 -9
  251. package/src/assets/web-panel/assets/Dashboard-CXrd5gAw.js +0 -3
  252. package/src/assets/web-panel/assets/MobileProjects-NZvvfDME.js +0 -1
  253. package/src/assets/web-panel/assets/OrderTableRenderer-C48mu09U.js +0 -1
  254. package/src/assets/web-panel/assets/PersonalDataHub-AX3ypUDV.js +0 -9
  255. package/src/assets/web-panel/assets/Projects-Cc7FC9-e.js +0 -1
  256. package/src/assets/web-panel/assets/Terminal-CjTZPa37.js +0 -3
  257. package/src/assets/web-panel/assets/devWarning-BT46Y_QI.js +0 -1
  258. package/src/assets/web-panel/assets/index-B7nuIywP.js +0 -1
  259. package/src/assets/web-panel/assets/index-ycwAfC-i.js +0 -1
  260. package/src/assets/web-panel/assets/usePersonalDataHub-B4NkcLaP.js +0 -1
@@ -561,6 +561,7 @@ parameters:
561
561
  description: 输出文件路径(.mp3 或 .wav)
562
562
  default: "output.mp3"
563
563
  execution-mode: direct
564
+ capabilities: [shell-exec]
564
565
  ---
565
566
 
566
567
  # AI 音频生成
@@ -608,24 +609,38 @@ chainlesschain cli-anything register <tool-name>
608
609
  * Auto-detects which backend is available and uses the best one.
609
610
  */
610
611
 
611
- const { execSync, spawn, spawnSync } = require("child_process");
612
612
  const fs = require("fs");
613
613
  const path = require("path");
614
614
  const https = require("https");
615
615
 
616
- function commandExists(cmd) {
616
+ function requireProcessBroker(context) {
617
+ const broker = context && context.processBroker;
618
+ if (!broker || typeof broker.run !== "function" ||
619
+ typeof broker.runSync !== "function" || typeof broker.runFileSync !== "function") {
620
+ throw new Error("Process Broker unavailable for audio-gen skill");
621
+ }
622
+ return broker;
623
+ }
624
+
625
+ function commandExists(processBroker, cmd) {
617
626
  try {
618
- execSync(\`\${cmd} --version\`, { stdio: "ignore", encoding: "utf-8" });
627
+ processBroker.runFileSync(cmd, ["--version"], {
628
+ stdio: "ignore",
629
+ encoding: "utf-8",
630
+ timeout: 5000,
631
+ });
619
632
  return true;
620
633
  } catch {
621
634
  return false;
622
635
  }
623
636
  }
624
637
 
625
- function runEdgeTTS(text, voice, outputPath) {
638
+ function runEdgeTTS(processBroker, text, voice, outputPath) {
626
639
  return new Promise((resolve, reject) => {
627
640
  const args = ["edge-tts", "--voice", voice || "zh-CN-XiaoxiaoNeural", "--text", text, "--write-media", outputPath];
628
- const proc = spawn("python", ["-m", ...args], { stdio: ["ignore", "pipe", "pipe"] });
641
+ const proc = processBroker.run("python", ["-m", ...args], {
642
+ stdio: ["ignore", "pipe", "pipe"],
643
+ });
629
644
  let stderr = "";
630
645
  proc.stderr.on("data", (d) => (stderr += d.toString("utf8")));
631
646
  proc.on("close", (code) => {
@@ -699,7 +714,7 @@ function callOpenAITTS(text, voice, outputPath, apiKey) {
699
714
  });
700
715
  }
701
716
 
702
- async function audioGenHandler(params) {
717
+ async function audioGenHandler(params, processBroker) {
703
718
  const { text, voice, type, output } = params;
704
719
 
705
720
  if (!text) {
@@ -717,9 +732,9 @@ async function audioGenHandler(params) {
717
732
  const openaiKey = process.env.OPENAI_API_KEY;
718
733
 
719
734
  // 1. edge-tts (free, no API key needed)
720
- if (commandExists("edge-tts") || await checkPythonModule("edge_tts")) {
735
+ if (commandExists(processBroker, "edge-tts") || await checkPythonModule(processBroker, "edge_tts")) {
721
736
  try {
722
- await runEdgeTTS(text, voice, outputPath);
737
+ await runEdgeTTS(processBroker, text, voice, outputPath);
723
738
  return {
724
739
  success: true,
725
740
  backend: "edge-tts",
@@ -732,11 +747,11 @@ async function audioGenHandler(params) {
732
747
  }
733
748
 
734
749
  // 2. piper-tts (offline, free)
735
- if (commandExists("piper")) {
750
+ if (commandExists(processBroker, "piper")) {
736
751
  try {
737
752
  // Pass the text via stdin with NO shell — an echo-pipe only escaped
738
753
  // double-quotes, so backticks / \$(...) in \`text\` would still execute.
739
- const r = spawnSync("piper", ["--output_file", outputPath], {
754
+ const r = processBroker.runSync("piper", ["--output_file", outputPath], {
740
755
  input: text,
741
756
  encoding: "utf-8",
742
757
  });
@@ -796,21 +811,26 @@ async function audioGenHandler(params) {
796
811
  };
797
812
  };
798
813
 
799
- async function checkPythonModule(moduleName) {
814
+ async function checkPythonModule(processBroker, moduleName) {
800
815
  try {
801
- execSync(\`python -c "import \${moduleName}"\`, { stdio: "ignore", encoding: "utf-8" });
816
+ processBroker.runFileSync("python", ["-c", \`import \${moduleName}\`], {
817
+ stdio: "ignore",
818
+ encoding: "utf-8",
819
+ timeout: 10000,
820
+ });
802
821
  return true;
803
822
  } catch {
804
823
  return false;
805
824
  }
806
825
  }
807
826
 
808
- audioGenHandler.execute = async (task, _ctx, _skill) => {
827
+ audioGenHandler.execute = async (task, context, _skill) => {
828
+ const processBroker = requireProcessBroker(context);
809
829
  const input = typeof task === "string" ? task : (task.input || task.params?.input || "");
810
830
  let p = {};
811
831
  try { p = input.trim().startsWith("{") ? JSON.parse(input) : { text: input }; }
812
832
  catch { p = { text: input }; }
813
- return audioGenHandler(p);
833
+ return audioGenHandler(p, processBroker);
814
834
  };
815
835
  module.exports = audioGenHandler;
816
836
  `,
@@ -899,6 +919,7 @@ parameters:
899
919
  required: false
900
920
  description: 输出文件名(不含扩展名,默认为主题名)
901
921
  execution-mode: direct
922
+ capabilities: [shell-exec]
902
923
  ---
903
924
 
904
925
  # AI 文档生成
@@ -969,27 +990,39 @@ chainlesschain skill run cli-anything-soffice "convert report.md to pdf"
969
990
  * - pdf: LibreOffice soffice --headless
970
991
  */
971
992
 
972
- const { spawnSync, execSync } = require("child_process");
973
993
  const fs = require("fs");
974
994
  const path = require("path");
975
995
 
976
996
  // ─── Tool detection ───────────────────────────────────────────────
977
997
 
978
- function commandExists(cmd) {
998
+ function requireProcessBroker(context) {
999
+ const broker = context && context.processBroker;
1000
+ if (!broker || typeof broker.runSync !== "function" ||
1001
+ typeof broker.runFileSync !== "function") {
1002
+ throw new Error("Process Broker unavailable for doc-generate skill");
1003
+ }
1004
+ return broker;
1005
+ }
1006
+
1007
+ function commandExists(processBroker, cmd) {
979
1008
  try {
980
- execSync(\`\${cmd} --version\`, { stdio: "ignore", encoding: "utf-8" });
1009
+ processBroker.runFileSync(cmd, ["--version"], {
1010
+ stdio: "ignore",
1011
+ encoding: "utf-8",
1012
+ timeout: 5000,
1013
+ });
981
1014
  return true;
982
1015
  } catch {
983
1016
  return false;
984
1017
  }
985
1018
  }
986
1019
 
987
- function detectSoffice() {
988
- if (commandExists("soffice")) return "soffice";
989
- if (commandExists("libreoffice")) return "libreoffice";
1020
+ function detectSoffice(processBroker) {
1021
+ if (commandExists(processBroker, "soffice")) return "soffice";
1022
+ if (commandExists(processBroker, "libreoffice")) return "libreoffice";
990
1023
  // Windows default install path
991
1024
  const winPath = "C:\\\\Program Files\\\\LibreOffice\\\\program\\\\soffice.exe";
992
- if (process.platform === "win32" && fs.existsSync(winPath)) return \`"\${winPath}"\`;
1025
+ if (process.platform === "win32" && fs.existsSync(winPath)) return winPath;
993
1026
  return null;
994
1027
  }
995
1028
 
@@ -1042,11 +1075,11 @@ function mdToHtml(md, title) {
1042
1075
 
1043
1076
  // ─── Conversion helpers ───────────────────────────────────────────
1044
1077
 
1045
- function convertWithPandoc(mdFile, outputFile, format) {
1046
- const result = spawnSync(
1078
+ function convertWithPandoc(processBroker, mdFile, outputFile, format) {
1079
+ const result = processBroker.runSync(
1047
1080
  "pandoc",
1048
1081
  [mdFile, "-o", outputFile, "--standalone"],
1049
- { encoding: "utf-8", timeout: 60000 },
1082
+ { encoding: "utf-8", timeout: 60000, shell: false },
1050
1083
  );
1051
1084
  if (result.status !== 0) {
1052
1085
  throw new Error(\`pandoc failed: \${result.stderr || result.error?.message}\`);
@@ -1054,11 +1087,11 @@ function convertWithPandoc(mdFile, outputFile, format) {
1054
1087
  return outputFile;
1055
1088
  }
1056
1089
 
1057
- function convertWithSoffice(sofficeCmd, inputFile, format, outDir) {
1058
- const result = spawnSync(
1090
+ function convertWithSoffice(processBroker, sofficeCmd, inputFile, format, outDir) {
1091
+ const result = processBroker.runSync(
1059
1092
  sofficeCmd,
1060
1093
  ["--headless", "--convert-to", format, inputFile, "--outdir", outDir],
1061
- { encoding: "utf-8", timeout: 120000, shell: process.platform === "win32" },
1094
+ { encoding: "utf-8", timeout: 120000, shell: false },
1062
1095
  );
1063
1096
  if (result.status !== 0) {
1064
1097
  throw new Error(\`soffice failed: \${result.stderr || result.error?.message}\`);
@@ -1070,7 +1103,7 @@ function convertWithSoffice(sofficeCmd, inputFile, format, outDir) {
1070
1103
 
1071
1104
  // ─── LLM content generation ───────────────────────────────────────
1072
1105
 
1073
- function generateContent(topic, style, outline) {
1106
+ function generateContent(processBroker, topic, style, outline) {
1074
1107
  const styleDesc = STYLE_PROMPTS[style] || STYLE_PROMPTS.report;
1075
1108
  const outlineSection = outline
1076
1109
  ? \`\\n\\n大纲要求(请按以下结构组织内容):\\n\${outline}\`
@@ -1080,7 +1113,7 @@ function generateContent(topic, style, outline) {
1080
1113
  \`请为以下主题生成\${styleDesc}。\\n\\n主题:\${topic}\${outlineSection}\\n\\n要求:\\n- 使用标准 Markdown 格式(H1/H2/H3 标题、列表、表格等)\\n- 内容详实具体,不少于 800 字\\n- 使用中文撰写\\n- 直接输出 Markdown 内容,不需要额外说明\`;
1081
1114
 
1082
1115
  // Try chainlesschain ask first
1083
- const askResult = spawnSync(
1116
+ const askResult = processBroker.runSync(
1084
1117
  process.execPath,
1085
1118
  [process.argv[1], "ask", prompt],
1086
1119
  {
@@ -1088,6 +1121,7 @@ function generateContent(topic, style, outline) {
1088
1121
  timeout: 120000,
1089
1122
  cwd: process.cwd(),
1090
1123
  env: process.env,
1124
+ shell: false,
1091
1125
  },
1092
1126
  );
1093
1127
 
@@ -1130,7 +1164,7 @@ function generateContent(topic, style, outline) {
1130
1164
 
1131
1165
  // ─── Main handler ─────────────────────────────────────────────────
1132
1166
 
1133
- async function docGenerateHandler(params) {
1167
+ async function docGenerateHandler(params, processBroker) {
1134
1168
  const { topic, format, outline, style, output } = params;
1135
1169
 
1136
1170
  if (!topic) {
@@ -1144,7 +1178,7 @@ async function docGenerateHandler(params) {
1144
1178
 
1145
1179
  // Generate content via LLM
1146
1180
  console.log(\`[doc-generate] Generating \${docStyle} document for: \${topic}\`);
1147
- const mdContent = generateContent(topic, docStyle, outline);
1181
+ const mdContent = generateContent(processBroker, topic, docStyle, outline);
1148
1182
 
1149
1183
  // Always write markdown first
1150
1184
  const mdFile = path.join(outputDir, \`\${safeTitle}.md\`);
@@ -1174,13 +1208,13 @@ async function docGenerateHandler(params) {
1174
1208
  }
1175
1209
 
1176
1210
  // DOCX / PDF: try pandoc then soffice
1177
- const sofficeCmd = detectSoffice();
1211
+ const sofficeCmd = detectSoffice(processBroker);
1178
1212
 
1179
1213
  if (fmt === "docx") {
1180
- if (commandExists("pandoc")) {
1214
+ if (commandExists(processBroker, "pandoc")) {
1181
1215
  try {
1182
1216
  const docxFile = path.join(outputDir, \`\${safeTitle}.docx\`);
1183
- convertWithPandoc(mdFile, docxFile, "docx");
1217
+ convertWithPandoc(processBroker, mdFile, docxFile, "docx");
1184
1218
  return { success: true, format: "docx", output: docxFile, mdOutput: mdFile, message: \`DOCX saved to: \${docxFile} (via pandoc)\` };
1185
1219
  } catch (err) {
1186
1220
  console.warn("[doc-generate] pandoc failed:", err.message);
@@ -1191,7 +1225,7 @@ async function docGenerateHandler(params) {
1191
1225
  // soffice needs HTML or ODT as input for md→docx (md not natively supported)
1192
1226
  const htmlFile = path.join(outputDir, \`\${safeTitle}.html\`);
1193
1227
  fs.writeFileSync(htmlFile, mdToHtml(mdContent, topic), "utf-8");
1194
- const docxFile = convertWithSoffice(sofficeCmd, htmlFile, "docx", outputDir);
1228
+ const docxFile = convertWithSoffice(processBroker, sofficeCmd, htmlFile, "docx", outputDir);
1195
1229
  // Clean up temp HTML
1196
1230
  try { fs.unlinkSync(htmlFile); } catch { /* ignore */ }
1197
1231
  return { success: true, format: "docx", output: docxFile, mdOutput: mdFile, message: \`DOCX saved to: \${docxFile} (via LibreOffice)\` };
@@ -1213,17 +1247,17 @@ async function docGenerateHandler(params) {
1213
1247
  try {
1214
1248
  const htmlFile = path.join(outputDir, \`\${safeTitle}.html\`);
1215
1249
  fs.writeFileSync(htmlFile, mdToHtml(mdContent, topic), "utf-8");
1216
- const pdfFile = convertWithSoffice(sofficeCmd, htmlFile, "pdf", outputDir);
1250
+ const pdfFile = convertWithSoffice(processBroker, sofficeCmd, htmlFile, "pdf", outputDir);
1217
1251
  try { fs.unlinkSync(htmlFile); } catch { /* ignore */ }
1218
1252
  return { success: true, format: "pdf", output: pdfFile, mdOutput: mdFile, message: \`PDF saved to: \${pdfFile} (via LibreOffice)\` };
1219
1253
  } catch (err) {
1220
1254
  console.warn("[doc-generate] soffice pdf failed:", err.message);
1221
1255
  }
1222
1256
  }
1223
- if (commandExists("pandoc") && commandExists("wkhtmltopdf")) {
1257
+ if (commandExists(processBroker, "pandoc") && commandExists(processBroker, "wkhtmltopdf")) {
1224
1258
  try {
1225
1259
  const pdfFile = path.join(outputDir, \`\${safeTitle}.pdf\`);
1226
- convertWithPandoc(mdFile, pdfFile, "pdf");
1260
+ convertWithPandoc(processBroker, mdFile, pdfFile, "pdf");
1227
1261
  return { success: true, format: "pdf", output: pdfFile, mdOutput: mdFile, message: \`PDF saved to: \${pdfFile} (via pandoc+wkhtmltopdf)\` };
1228
1262
  } catch (err) {
1229
1263
  console.warn("[doc-generate] pandoc pdf failed:", err.message);
@@ -1241,12 +1275,13 @@ async function docGenerateHandler(params) {
1241
1275
  return { error: \`Unsupported format: \${fmt}\`, hint: "Supported formats: md, html, docx, pdf" };
1242
1276
  }
1243
1277
 
1244
- docGenerateHandler.execute = async (task, _ctx, _skill) => {
1278
+ docGenerateHandler.execute = async (task, context, _skill) => {
1279
+ const processBroker = requireProcessBroker(context);
1245
1280
  const input = typeof task === "string" ? task : (task.input || task.params?.input || "");
1246
1281
  let p = {};
1247
1282
  try { p = input.trim().startsWith("{") ? JSON.parse(input) : { topic: input }; }
1248
1283
  catch { p = { topic: input }; }
1249
- return docGenerateHandler(p);
1284
+ return docGenerateHandler(p, processBroker);
1250
1285
  };
1251
1286
  module.exports = docGenerateHandler;
1252
1287
  `,
@@ -1275,6 +1310,7 @@ parameters:
1275
1310
  required: false
1276
1311
  description: 输出目录(默认与源文件相同目录)
1277
1312
  execution-mode: direct
1313
+ capabilities: [shell-exec]
1278
1314
  ---
1279
1315
 
1280
1316
  # LibreOffice 文档格式转换
@@ -1352,17 +1388,29 @@ soffice --version
1352
1388
  * chainlesschain cli-anything register soffice
1353
1389
  */
1354
1390
 
1355
- const { spawnSync, execSync } = require("child_process");
1356
1391
  const fs = require("fs");
1357
1392
  const path = require("path");
1358
1393
 
1359
1394
  const SUPPORTED_FORMATS = new Set(["pdf", "docx", "html", "odt", "pptx", "xlsx", "csv", "txt", "png"]);
1360
1395
 
1361
- function findSoffice() {
1396
+ function requireProcessBroker(context) {
1397
+ const broker = context && context.processBroker;
1398
+ if (!broker || typeof broker.runSync !== "function" ||
1399
+ typeof broker.runFileSync !== "function") {
1400
+ throw new Error("Process Broker unavailable for libre-convert skill");
1401
+ }
1402
+ return broker;
1403
+ }
1404
+
1405
+ function findSoffice(processBroker) {
1362
1406
  const candidates = ["soffice", "libreoffice"];
1363
1407
  for (const cmd of candidates) {
1364
1408
  try {
1365
- execSync(\`\${cmd} --version\`, { stdio: "ignore", encoding: "utf-8" });
1409
+ processBroker.runFileSync(cmd, ["--version"], {
1410
+ stdio: "ignore",
1411
+ encoding: "utf-8",
1412
+ timeout: 5000,
1413
+ });
1366
1414
  return cmd;
1367
1415
  } catch { /* try next */ }
1368
1416
  }
@@ -1373,13 +1421,13 @@ function findSoffice() {
1373
1421
  "C:\\\\Program Files (x86)\\\\LibreOffice\\\\program\\\\soffice.exe",
1374
1422
  ];
1375
1423
  for (const p of paths) {
1376
- if (fs.existsSync(p)) return \`"\${p}"\`;
1424
+ if (fs.existsSync(p)) return p;
1377
1425
  }
1378
1426
  }
1379
1427
  return null;
1380
1428
  }
1381
1429
 
1382
- async function libreConvertHandler(params) {
1430
+ async function libreConvertHandler(params, processBroker) {
1383
1431
  const { input_file, format, outdir } = params;
1384
1432
 
1385
1433
  if (!input_file) {
@@ -1404,7 +1452,7 @@ async function libreConvertHandler(params) {
1404
1452
  }
1405
1453
 
1406
1454
  // Find LibreOffice
1407
- const sofficeCmd = findSoffice();
1455
+ const sofficeCmd = findSoffice(processBroker);
1408
1456
  if (!sofficeCmd) {
1409
1457
  return {
1410
1458
  error: "LibreOffice not found",
@@ -1432,13 +1480,13 @@ async function libreConvertHandler(params) {
1432
1480
  console.log(\`[libre-convert] Converting \${path.basename(inputPath)} → \${targetFormat}\`);
1433
1481
 
1434
1482
  // Run soffice
1435
- const result = spawnSync(
1483
+ const result = processBroker.runSync(
1436
1484
  sofficeCmd,
1437
1485
  ["--headless", "--convert-to", targetFormat, inputPath, "--outdir", outputDir],
1438
1486
  {
1439
1487
  encoding: "utf-8",
1440
1488
  timeout: 120000,
1441
- shell: process.platform === "win32",
1489
+ shell: false,
1442
1490
  },
1443
1491
  );
1444
1492
 
@@ -1486,12 +1534,13 @@ async function libreConvertHandler(params) {
1486
1534
  };
1487
1535
  }
1488
1536
 
1489
- libreConvertHandler.execute = async (task, _ctx, _skill) => {
1537
+ libreConvertHandler.execute = async (task, context, _skill) => {
1538
+ const processBroker = requireProcessBroker(context);
1490
1539
  const input = typeof task === "string" ? task : (task.input || task.params?.input || "");
1491
1540
  let p = {};
1492
1541
  try { p = input.trim().startsWith("{") ? JSON.parse(input) : { input_file: input }; }
1493
1542
  catch { p = { input_file: input }; }
1494
- return libreConvertHandler(p);
1543
+ return libreConvertHandler(p, processBroker);
1495
1544
  };
1496
1545
  module.exports = libreConvertHandler;
1497
1546
  `,
@@ -1530,6 +1579,7 @@ input_schema:
1530
1579
  description: 输出目录(默认与输入文件同目录)
1531
1580
  required: [input_file, instruction]
1532
1581
  execution-mode: direct
1582
+ capabilities: [shell-exec]
1533
1583
  ---
1534
1584
 
1535
1585
  # AI 文档修改 (doc-edit)
@@ -1601,23 +1651,38 @@ chainlesschain cli-anything register soffice
1601
1651
  const fs = require("fs");
1602
1652
  const path = require("path");
1603
1653
  const os = require("os");
1604
- const { execSync, spawnSync } = require("child_process");
1654
+
1655
+ function requireProcessBroker(context) {
1656
+ const broker = context && context.processBroker;
1657
+ if (!broker || typeof broker.runSync !== "function" ||
1658
+ typeof broker.runFileSync !== "function") {
1659
+ throw new Error("Process Broker unavailable for doc-edit skill");
1660
+ }
1661
+ return broker;
1662
+ }
1605
1663
 
1606
1664
  // ── Python detection (mirrors cli-anything-bridge pattern) ───────────────────
1607
- function detectPython() {
1665
+ function detectPython(processBroker) {
1608
1666
  const candidates = ["python", "python3", "py"];
1609
1667
  for (const cmd of candidates) {
1610
1668
  try {
1611
- const r = spawnSync(cmd, ["--version"], { encoding: "utf-8", timeout: 5000 });
1669
+ const r = processBroker.runSync(cmd, ["--version"], {
1670
+ encoding: "utf-8",
1671
+ timeout: 5000,
1672
+ shell: false,
1673
+ });
1612
1674
  if (r.status === 0) return { found: true, command: cmd };
1613
1675
  } catch (_e) { /* try next */ }
1614
1676
  }
1615
1677
  return { found: false, command: null };
1616
1678
  }
1617
1679
 
1618
- function checkPythonModule(pyCmd, moduleName) {
1680
+ function checkPythonModule(processBroker, pyCmd, moduleName) {
1619
1681
  try {
1620
- execSync(\`\${pyCmd} -c "import \${moduleName}"\`, { stdio: "ignore", timeout: 10000 });
1682
+ processBroker.runFileSync(pyCmd, ["-c", \`import \${moduleName}\`], {
1683
+ stdio: "ignore",
1684
+ timeout: 10000,
1685
+ });
1621
1686
  return true;
1622
1687
  } catch {
1623
1688
  return false;
@@ -1625,11 +1690,11 @@ function checkPythonModule(pyCmd, moduleName) {
1625
1690
  }
1626
1691
 
1627
1692
  // ── LLM call via CLI sub-process ─────────────────────────────────────────────
1628
- function callLLM(prompt) {
1629
- const r = spawnSync(
1693
+ function callLLM(processBroker, prompt) {
1694
+ const r = processBroker.runSync(
1630
1695
  process.execPath,
1631
1696
  [process.argv[1], "ask", prompt],
1632
- { encoding: "utf-8", timeout: 120000, cwd: process.cwd(), env: process.env },
1697
+ { encoding: "utf-8", timeout: 120000, cwd: process.cwd(), env: process.env, shell: false },
1633
1698
  );
1634
1699
  if (r.status === 0 && r.stdout && r.stdout.trim().length > 10) return r.stdout.trim();
1635
1700
  return null;
@@ -1706,10 +1771,10 @@ function buildTextPrompt(content, instruction, action, section) {
1706
1771
  }
1707
1772
 
1708
1773
  // ── md / txt / html handler ───────────────────────────────────────────────────
1709
- function editText(inputFile, instruction, action, section, outputDir) {
1774
+ function editText(processBroker, inputFile, instruction, action, section, outputDir) {
1710
1775
  const content = fs.readFileSync(inputFile, "utf-8");
1711
1776
  const prompt = buildTextPrompt(content, instruction, action, section);
1712
- const llmResult = callLLM(prompt);
1777
+ const llmResult = callLLM(processBroker, prompt);
1713
1778
 
1714
1779
  let newContent;
1715
1780
  if (llmResult) {
@@ -1745,22 +1810,34 @@ function editText(inputFile, instruction, action, section, outputDir) {
1745
1810
  }
1746
1811
 
1747
1812
  // ── docx handler ──────────────────────────────────────────────────────────────
1748
- function editDocx(inputFile, instruction, action, section, outputDir) {
1813
+ function editDocx(processBroker, inputFile, instruction, action, section, outputDir) {
1749
1814
  // Try pandoc: docx → markdown → LLM → markdown → docx
1750
1815
  try {
1751
- const r = spawnSync("pandoc", ["--version"], { encoding: "utf-8", timeout: 5000 });
1816
+ const r = processBroker.runSync("pandoc", ["--version"], {
1817
+ encoding: "utf-8",
1818
+ timeout: 5000,
1819
+ shell: false,
1820
+ });
1752
1821
  if (r.status === 0) {
1753
1822
  const tmpMd = path.join(os.tmpdir(), \`doc_edit_\${Date.now()}.md\`);
1754
- spawnSync("pandoc", [inputFile, "-o", tmpMd], { encoding: "utf-8", timeout: 60000 });
1823
+ processBroker.runSync("pandoc", [inputFile, "-o", tmpMd], {
1824
+ encoding: "utf-8",
1825
+ timeout: 60000,
1826
+ shell: false,
1827
+ });
1755
1828
  if (fs.existsSync(tmpMd)) {
1756
1829
  const content = fs.readFileSync(tmpMd, "utf-8");
1757
1830
  const prompt = buildTextPrompt(content, instruction, action, section);
1758
- const llmResult = callLLM(prompt);
1831
+ const llmResult = callLLM(processBroker, prompt);
1759
1832
  if (llmResult) {
1760
1833
  let newContent = action === "append" ? content + "\\n\\n" + llmResult : llmResult;
1761
1834
  fs.writeFileSync(tmpMd, newContent, "utf-8");
1762
1835
  const outputFile = buildOutputPath(inputFile, outputDir);
1763
- spawnSync("pandoc", [tmpMd, "-o", outputFile], { encoding: "utf-8", timeout: 60000 });
1836
+ processBroker.runSync("pandoc", [tmpMd, "-o", outputFile], {
1837
+ encoding: "utf-8",
1838
+ timeout: 60000,
1839
+ shell: false,
1840
+ });
1764
1841
  try { fs.unlinkSync(tmpMd); } catch (_e) { /* ignore */ }
1765
1842
  if (fs.existsSync(outputFile)) {
1766
1843
  return { success: true, input: inputFile, output: outputFile, action, message: \`DOCX edited via pandoc: \${outputFile}\` };
@@ -1784,23 +1861,27 @@ function editDocx(inputFile, instruction, action, section, outputDir) {
1784
1861
  }
1785
1862
  for (const soffice of sofficeCandidates) {
1786
1863
  try {
1787
- const rv = spawnSync(soffice, ["--version"], { encoding: "utf-8", timeout: 5000, shell: process.platform === "win32" });
1864
+ const rv = processBroker.runSync(soffice, ["--version"], {
1865
+ encoding: "utf-8",
1866
+ timeout: 5000,
1867
+ shell: false,
1868
+ });
1788
1869
  if (rv.status === 0) {
1789
1870
  const tmpDir2 = os.tmpdir();
1790
- spawnSync(soffice, ["--headless", "--convert-to", "html", inputFile, "--outdir", tmpDir2], {
1791
- encoding: "utf-8", timeout: 60000, shell: process.platform === "win32",
1871
+ processBroker.runSync(soffice, ["--headless", "--convert-to", "html", inputFile, "--outdir", tmpDir2], {
1872
+ encoding: "utf-8", timeout: 60000, shell: false,
1792
1873
  });
1793
1874
  const baseName = path.basename(inputFile, ".docx");
1794
1875
  const htmlFile = path.join(tmpDir2, \`\${baseName}.html\`);
1795
1876
  if (fs.existsSync(htmlFile)) {
1796
1877
  const content = fs.readFileSync(htmlFile, "utf-8");
1797
1878
  const prompt = buildTextPrompt(content, instruction, action, section);
1798
- const llmResult = callLLM(prompt);
1879
+ const llmResult = callLLM(processBroker, prompt);
1799
1880
  if (llmResult) {
1800
1881
  fs.writeFileSync(htmlFile, llmResult, "utf-8");
1801
1882
  const outputFile = buildOutputPath(inputFile, outputDir);
1802
- spawnSync(soffice, ["--headless", "--convert-to", "docx", htmlFile, "--outdir", path.dirname(outputFile)], {
1803
- encoding: "utf-8", timeout: 60000, shell: process.platform === "win32",
1883
+ processBroker.runSync(soffice, ["--headless", "--convert-to", "docx", htmlFile, "--outdir", path.dirname(outputFile)], {
1884
+ encoding: "utf-8", timeout: 60000, shell: false,
1804
1885
  });
1805
1886
  try { fs.unlinkSync(htmlFile); } catch (_e) { /* ignore */ }
1806
1887
  if (fs.existsSync(outputFile)) {
@@ -1822,12 +1903,12 @@ function editDocx(inputFile, instruction, action, section, outputDir) {
1822
1903
  }
1823
1904
 
1824
1905
  // ── xlsx handler (Python + openpyxl) ─────────────────────────────────────────
1825
- function editXlsx(inputFile, instruction, action, outputDir) {
1826
- const py = detectPython();
1906
+ function editXlsx(processBroker, inputFile, instruction, action, outputDir) {
1907
+ const py = detectPython(processBroker);
1827
1908
  if (!py.found) {
1828
1909
  return { success: false, error: "未找到 Python,请安装 Python 3.x", hint: "https://python.org" };
1829
1910
  }
1830
- if (!checkPythonModule(py.command, "openpyxl")) {
1911
+ if (!checkPythonModule(processBroker, py.command, "openpyxl")) {
1831
1912
  return {
1832
1913
  success: false,
1833
1914
  error: "需要安装 openpyxl 才能修改 XLSX 文件",
@@ -1842,19 +1923,24 @@ function editXlsx(inputFile, instruction, action, outputDir) {
1842
1923
  try {
1843
1924
  // Step 1: extract text cells (non-formula string cells)
1844
1925
  const extractScript = \`
1845
- import json, openpyxl
1846
- wb = openpyxl.load_workbook(r"""\${inputFile}""", data_only=False)
1926
+ import json, openpyxl, sys
1927
+ input_file, output_json = sys.argv[1], sys.argv[2]
1928
+ wb = openpyxl.load_workbook(input_file, data_only=False)
1847
1929
  cells = []
1848
1930
  for ws in wb.worksheets:
1849
1931
  for row in ws.iter_rows():
1850
1932
  for cell in row:
1851
1933
  if cell.data_type == 's' and cell.value is not None:
1852
1934
  cells.append({"sheet": ws.title, "row": cell.row, "col": cell.column, "value": cell.value})
1853
- with open(r"""\${tmpJson}""", "w", encoding="utf-8") as f:
1935
+ with open(output_json, "w", encoding="utf-8") as f:
1854
1936
  json.dump(cells, f, ensure_ascii=False)
1855
1937
  \`;
1856
1938
  fs.writeFileSync(tmpExtract, extractScript, "utf-8");
1857
- const er = spawnSync(py.command, [tmpExtract], { encoding: "utf-8", timeout: 30000 });
1939
+ const er = processBroker.runSync(py.command, [tmpExtract, inputFile, tmpJson], {
1940
+ encoding: "utf-8",
1941
+ timeout: 30000,
1942
+ shell: false,
1943
+ });
1858
1944
  if (er.status !== 0) throw new Error(er.stderr || "extract failed");
1859
1945
 
1860
1946
  const cells = JSON.parse(fs.readFileSync(tmpJson, "utf-8"));
@@ -1873,7 +1959,7 @@ with open(r"""\${tmpJson}""", "w", encoding="utf-8") as f:
1873
1959
  \${textList}
1874
1960
 
1875
1961
  直接返回 JSON 数组,不要其他说明。\`;
1876
- const llmResult = callLLM(prompt);
1962
+ const llmResult = callLLM(processBroker, prompt);
1877
1963
  if (!llmResult) {
1878
1964
  return { success: false, error: "LLM 调用失败", hint: "运行 chainlesschain llm test 检查连接" };
1879
1965
  }
@@ -1890,21 +1976,26 @@ with open(r"""\${tmpJson}""", "w", encoding="utf-8") as f:
1890
1976
  // Step 3: apply changes
1891
1977
  const outputFile = buildOutputPath(inputFile, outputDir);
1892
1978
  const applyScript = \`
1893
- import json, openpyxl, shutil
1894
- shutil.copy2(r"""\${inputFile}""", r"""\${outputFile}""")
1895
- wb = openpyxl.load_workbook(r"""\${outputFile}""", data_only=False)
1896
- updated = json.loads('''
1897
- \${JSON.stringify(updatedCells).replace(/'/g, "\\\\'")}
1898
- ''')
1979
+ import json, openpyxl, shutil, sys
1980
+ input_file, output_file, updated_json = sys.argv[1], sys.argv[2], sys.argv[3]
1981
+ shutil.copy2(input_file, output_file)
1982
+ wb = openpyxl.load_workbook(output_file, data_only=False)
1983
+ with open(updated_json, "r", encoding="utf-8") as f:
1984
+ updated = json.load(f)
1899
1985
  for item in updated:
1900
1986
  ws = wb[item["sheet"]]
1901
1987
  cell = ws.cell(row=item["row"], column=item["col"])
1902
1988
  if cell.data_type == 's':
1903
1989
  cell.value = item["value"]
1904
- wb.save(r"""\${outputFile}""")
1990
+ wb.save(output_file)
1905
1991
  \`;
1906
1992
  fs.writeFileSync(tmpApply, applyScript, "utf-8");
1907
- const ar = spawnSync(py.command, [tmpApply], { encoding: "utf-8", timeout: 30000 });
1993
+ fs.writeFileSync(tmpJson, JSON.stringify(updatedCells), "utf-8");
1994
+ const ar = processBroker.runSync(py.command, [tmpApply, inputFile, outputFile, tmpJson], {
1995
+ encoding: "utf-8",
1996
+ timeout: 30000,
1997
+ shell: false,
1998
+ });
1908
1999
  if (ar.status !== 0) throw new Error(ar.stderr || "apply failed");
1909
2000
 
1910
2001
  return {
@@ -1925,12 +2016,12 @@ wb.save(r"""\${outputFile}""")
1925
2016
  }
1926
2017
 
1927
2018
  // ── pptx handler (Python + python-pptx) ──────────────────────────────────────
1928
- function editPptx(inputFile, instruction, action, outputDir) {
1929
- const py = detectPython();
2019
+ function editPptx(processBroker, inputFile, instruction, action, outputDir) {
2020
+ const py = detectPython(processBroker);
1930
2021
  if (!py.found) {
1931
2022
  return { success: false, error: "未找到 Python,请安装 Python 3.x", hint: "https://python.org" };
1932
2023
  }
1933
- if (!checkPythonModule(py.command, "pptx")) {
2024
+ if (!checkPythonModule(processBroker, py.command, "pptx")) {
1934
2025
  return {
1935
2026
  success: false,
1936
2027
  error: "需要安装 python-pptx 才能修改 PPTX 文件",
@@ -1945,9 +2036,10 @@ function editPptx(inputFile, instruction, action, outputDir) {
1945
2036
  try {
1946
2037
  // Step 1: extract text runs (skip chart shapes)
1947
2038
  const extractScript = \`
1948
- import json
2039
+ import json, sys
1949
2040
  from pptx import Presentation
1950
- prs = Presentation(r"""\${inputFile}""")
2041
+ input_file, output_json = sys.argv[1], sys.argv[2]
2042
+ prs = Presentation(input_file)
1951
2043
  runs = []
1952
2044
  for si, slide in enumerate(prs.slides):
1953
2045
  for shi, shape in enumerate(slide.shapes):
@@ -1957,11 +2049,15 @@ for si, slide in enumerate(prs.slides):
1957
2049
  for ri, run in enumerate(para.runs):
1958
2050
  if run.text.strip():
1959
2051
  runs.append({"slide": si, "shape": shi, "para": pi, "run": ri, "text": run.text})
1960
- with open(r"""\${tmpJson}""", "w", encoding="utf-8") as f:
2052
+ with open(output_json, "w", encoding="utf-8") as f:
1961
2053
  json.dump(runs, f, ensure_ascii=False)
1962
2054
  \`;
1963
2055
  fs.writeFileSync(tmpExtract, extractScript, "utf-8");
1964
- const er = spawnSync(py.command, [tmpExtract], { encoding: "utf-8", timeout: 30000 });
2056
+ const er = processBroker.runSync(py.command, [tmpExtract, inputFile, tmpJson], {
2057
+ encoding: "utf-8",
2058
+ timeout: 30000,
2059
+ shell: false,
2060
+ });
1965
2061
  if (er.status !== 0) throw new Error(er.stderr || "extract failed");
1966
2062
 
1967
2063
  const runs = JSON.parse(fs.readFileSync(tmpJson, "utf-8"));
@@ -1980,7 +2076,7 @@ with open(r"""\${tmpJson}""", "w", encoding="utf-8") as f:
1980
2076
  \${textList}
1981
2077
 
1982
2078
  直接返回 JSON 数组,不要其他说明。\`;
1983
- const llmResult = callLLM(prompt);
2079
+ const llmResult = callLLM(processBroker, prompt);
1984
2080
  if (!llmResult) {
1985
2081
  return { success: false, error: "LLM 调用失败", hint: "运行 chainlesschain llm test 检查连接" };
1986
2082
  }
@@ -1996,23 +2092,28 @@ with open(r"""\${tmpJson}""", "w", encoding="utf-8") as f:
1996
2092
  // Step 3: apply changes (only .text, preserve all font/style)
1997
2093
  const outputFile = buildOutputPath(inputFile, outputDir);
1998
2094
  const applyScript = \`
1999
- import json, shutil
2095
+ import json, shutil, sys
2000
2096
  from pptx import Presentation
2001
- shutil.copy2(r"""\${inputFile}""", r"""\${outputFile}""")
2002
- prs = Presentation(r"""\${outputFile}""")
2003
- updated = json.loads('''
2004
- \${JSON.stringify(updatedRuns).replace(/'/g, "\\\\'")}
2005
- ''')
2097
+ input_file, output_file, updated_json = sys.argv[1], sys.argv[2], sys.argv[3]
2098
+ shutil.copy2(input_file, output_file)
2099
+ prs = Presentation(output_file)
2100
+ with open(updated_json, "r", encoding="utf-8") as f:
2101
+ updated = json.load(f)
2006
2102
  for item in updated:
2007
2103
  slide = prs.slides[item["slide"]]
2008
2104
  shape = slide.shapes[item["shape"]]
2009
2105
  if shape.has_text_frame:
2010
2106
  run = shape.text_frame.paragraphs[item["para"]].runs[item["run"]]
2011
2107
  run.text = item["text"]
2012
- prs.save(r"""\${outputFile}""")
2108
+ prs.save(output_file)
2013
2109
  \`;
2014
2110
  fs.writeFileSync(tmpApply, applyScript, "utf-8");
2015
- const ar = spawnSync(py.command, [tmpApply], { encoding: "utf-8", timeout: 30000 });
2111
+ fs.writeFileSync(tmpJson, JSON.stringify(updatedRuns), "utf-8");
2112
+ const ar = processBroker.runSync(py.command, [tmpApply, inputFile, outputFile, tmpJson], {
2113
+ encoding: "utf-8",
2114
+ timeout: 30000,
2115
+ shell: false,
2116
+ });
2016
2117
  if (ar.status !== 0) throw new Error(ar.stderr || "apply failed");
2017
2118
 
2018
2119
  return {
@@ -2033,7 +2134,7 @@ prs.save(r"""\${outputFile}""")
2033
2134
  }
2034
2135
 
2035
2136
  // ── Main export ───────────────────────────────────────────────────────────────
2036
- async function docEdit(params) {
2137
+ async function docEdit(params, processBroker) {
2037
2138
  const { input_file, instruction, action = "edit", section, output_dir } = params || {};
2038
2139
 
2039
2140
  if (!input_file) {
@@ -2054,16 +2155,16 @@ async function docEdit(params) {
2054
2155
  const ext = path.extname(input_file).toLowerCase();
2055
2156
 
2056
2157
  if ([".md", ".txt", ".html", ".htm"].includes(ext)) {
2057
- return editText(input_file, instruction, action, section, output_dir);
2158
+ return editText(processBroker, input_file, instruction, action, section, output_dir);
2058
2159
  }
2059
2160
  if (ext === ".docx") {
2060
- return editDocx(input_file, instruction, action, section, output_dir);
2161
+ return editDocx(processBroker, input_file, instruction, action, section, output_dir);
2061
2162
  }
2062
2163
  if (ext === ".xlsx") {
2063
- return editXlsx(input_file, instruction, action, output_dir);
2164
+ return editXlsx(processBroker, input_file, instruction, action, output_dir);
2064
2165
  }
2065
2166
  if (ext === ".pptx") {
2066
- return editPptx(input_file, instruction, action, output_dir);
2167
+ return editPptx(processBroker, input_file, instruction, action, output_dir);
2067
2168
  }
2068
2169
 
2069
2170
  return {
@@ -2073,12 +2174,13 @@ async function docEdit(params) {
2073
2174
  };
2074
2175
  }
2075
2176
 
2076
- docEdit.execute = async (task, _ctx, _skill) => {
2177
+ docEdit.execute = async (task, context, _skill) => {
2178
+ const processBroker = requireProcessBroker(context);
2077
2179
  const input = typeof task === "string" ? task : (task.input || task.params?.input || "");
2078
2180
  let p = {};
2079
2181
  try { p = input.trim().startsWith("{") ? JSON.parse(input) : { input_file: input }; }
2080
2182
  catch { p = { input_file: input }; }
2081
- return docEdit(p);
2183
+ return docEdit(p, processBroker);
2082
2184
  };
2083
2185
  module.exports = docEdit;
2084
2186
  `,