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
@@ -26,41 +26,82 @@ export const _deps = {
26
26
  readEvents: storeReadEvents,
27
27
  };
28
28
 
29
+ export class SideEffectLedgerPersistenceError extends Error {
30
+ constructor(operation, sessionId, cause) {
31
+ const detail = cause?.message || String(cause || "unknown persistence error");
32
+ super(`Side-effect ledger ${operation} failed for ${sessionId}: ${detail}`, {
33
+ cause,
34
+ });
35
+ this.name = "SideEffectLedgerPersistenceError";
36
+ this.code =
37
+ operation === "read"
38
+ ? "SIDE_EFFECT_LEDGER_READ_FAILED"
39
+ : "SIDE_EFFECT_LEDGER_PERSIST_FAILED";
40
+ this.operation = operation;
41
+ this.sessionId = sessionId;
42
+ }
43
+ }
44
+
45
+ function persistenceFailure(operation, sessionId, cause, failIfUnavailable) {
46
+ if (!failIfUnavailable) return false;
47
+ throw new SideEffectLedgerPersistenceError(operation, sessionId, cause);
48
+ }
49
+
29
50
  /**
30
- * Append the current ledger as a chained event. Best-effort a persistence
31
- * failure must not crash the operation it is guarding.
51
+ * Append the current ledger as a chained event. This is Critical state:
52
+ * persistence failures reject by default so the guarded operation cannot run.
53
+ * Diagnostic callers may explicitly request advisory best-effort behavior.
32
54
  *
33
55
  * @param {string} sessionId
34
56
  * @param {SideEffectLedger|object} ledger
57
+ * @param {{failIfUnavailable?:boolean}} [opts]
35
58
  * @returns {boolean}
36
59
  */
37
- export function persistSideEffectLedger(sessionId, ledger) {
38
- if (!sessionId || !ledger) return false;
39
- const snapshot =
40
- ledger instanceof SideEffectLedger ? ledger.toJSON() : ledger;
41
- if (!snapshot || !Array.isArray(snapshot.ops)) return false;
60
+ export function persistSideEffectLedger(sessionId, ledger, opts = {}) {
61
+ const failIfUnavailable = opts.failIfUnavailable !== false;
62
+ if (!sessionId || !ledger) {
63
+ return persistenceFailure(
64
+ "write",
65
+ sessionId || "<missing-session>",
66
+ new TypeError("sessionId and ledger are required"),
67
+ failIfUnavailable,
68
+ );
69
+ }
70
+
42
71
  try {
72
+ const snapshot =
73
+ ledger instanceof SideEffectLedger ? ledger.toJSON() : ledger;
74
+ if (!snapshot || !Array.isArray(snapshot.ops)) {
75
+ throw new TypeError("ledger snapshot must contain an ops array");
76
+ }
43
77
  _deps.appendEvent(sessionId, SIDE_EFFECT_LEDGER_EVENT, snapshot);
44
78
  return true;
45
- } catch {
46
- return false;
79
+ } catch (error) {
80
+ return persistenceFailure("write", sessionId, error, failIfUnavailable);
47
81
  }
48
82
  }
49
83
 
50
84
  /**
51
85
  * Rebuild the ledger from the LATEST persisted snapshot, or an empty ledger when
52
- * the session never persisted one (or on read error).
86
+ * the session never persisted one. Read/corruption errors reject by default.
53
87
  *
54
88
  * @param {string} sessionId
55
- * @param {{clock?:Function}} [opts]
89
+ * @param {{clock?:Function,failIfUnavailable?:boolean}} [opts]
56
90
  * @returns {SideEffectLedger}
57
91
  */
58
92
  export function loadSideEffectLedger(sessionId, opts = {}) {
93
+ const failIfUnavailable = opts.failIfUnavailable !== false;
59
94
  let events = [];
60
95
  try {
61
96
  events = _deps.readEvents(sessionId) || [];
62
- } catch {
63
- return new SideEffectLedger(opts);
97
+ } catch (error) {
98
+ const fallback = persistenceFailure(
99
+ "read",
100
+ sessionId || "<missing-session>",
101
+ error,
102
+ failIfUnavailable,
103
+ );
104
+ if (fallback === false) return new SideEffectLedger(opts);
64
105
  }
65
106
  for (let i = events.length - 1; i >= 0; i--) {
66
107
  const e = events[i];
@@ -70,7 +111,17 @@ export function loadSideEffectLedger(sessionId, opts = {}) {
70
111
  e.data &&
71
112
  Array.isArray(e.data.ops)
72
113
  ) {
73
- return SideEffectLedger.fromJSON(e.data, opts);
114
+ try {
115
+ return SideEffectLedger.fromJSON(e.data, opts);
116
+ } catch (error) {
117
+ const fallback = persistenceFailure(
118
+ "read",
119
+ sessionId || "<missing-session>",
120
+ error,
121
+ failIfUnavailable,
122
+ );
123
+ if (fallback === false) return new SideEffectLedger(opts);
124
+ }
74
125
  }
75
126
  }
76
127
  return new SideEffectLedger(opts);
@@ -31,6 +31,7 @@ import { parseSkillMcpServers } from "./skill-mcp.js";
31
31
  import { normalizeSkillPaths } from "./skill-path-scope.js";
32
32
  import { discoverPluginSkillLayers } from "./plugin-runtime/skills.js";
33
33
  import settingsLoader from "./settings-loader.cjs";
34
+ import contextSourceLedger from "./context-source-ledger.js";
34
35
 
35
36
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
36
37
 
@@ -218,6 +219,40 @@ export function parseSkillMd(content) {
218
219
  return { data, body };
219
220
  }
220
221
 
222
+ /**
223
+ * Read only enough of SKILL.md to parse its YAML frontmatter. The markdown
224
+ * body is deliberately not retained during discovery; it is materialized by
225
+ * CLISkillLoader.materializeSkill() only when a persona or run_skill needs it.
226
+ */
227
+ function readSkillFrontmatter(skillMd, maxBytes = 256 * 1024) {
228
+ const fd = fs.openSync(skillMd, "r");
229
+ const chunks = [];
230
+ let total = 0;
231
+ try {
232
+ while (total < maxBytes) {
233
+ const chunk = Buffer.allocUnsafe(Math.min(8192, maxBytes - total));
234
+ const read = fs.readSync(fd, chunk, 0, chunk.length, total);
235
+ if (read <= 0) break;
236
+ chunks.push(chunk.subarray(0, read));
237
+ total += read;
238
+ const prefix = Buffer.concat(chunks).toString("utf-8").replace(/^\uFEFF/, "");
239
+ const firstLineEnd = prefix.search(/\r?\n/);
240
+ if (firstLineEnd >= 0 && prefix.slice(0, firstLineEnd).trim() !== "---") {
241
+ return {};
242
+ }
243
+ const match = prefix.match(/^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/);
244
+ if (match) return parseSkillMd(match[0]).data;
245
+ }
246
+ return {};
247
+ } finally {
248
+ fs.closeSync(fd);
249
+ }
250
+ }
251
+
252
+ function estimateSkillTokens(text) {
253
+ return Math.ceil(String(text || "").length / 4);
254
+ }
255
+
221
256
  /**
222
257
  * Substitute $ARGUMENTS / $1 / $2 / ... placeholders in a skill body.
223
258
  * Inspired by open-agents substituteArguments.
@@ -290,8 +325,17 @@ export function prepareSkillBody(skill, args) {
290
325
  * Multi-layer CLI skill loader
291
326
  */
292
327
  export class CLISkillLoader {
293
- constructor() {
328
+ constructor({ contextLedger = contextSourceLedger } = {}) {
294
329
  this._cache = null;
330
+ this._bodyCache = new Map();
331
+ this._contextLedger = contextLedger;
332
+ this._cacheStats = {
333
+ descriptorScans: 0,
334
+ descriptorCacheHits: 0,
335
+ bodyCacheHits: 0,
336
+ bodyCacheMisses: 0,
337
+ bodyLoads: new Map(),
338
+ };
295
339
  }
296
340
 
297
341
  /**
@@ -449,8 +493,8 @@ export class CLISkillLoader {
449
493
  continue;
450
494
  }
451
495
  try {
452
- const content = fs.readFileSync(skillMd, "utf-8");
453
- const { data, body } = parseSkillMd(content);
496
+ const data = readSkillFrontmatter(skillMd);
497
+ const stat = fs.statSync(skillMd);
454
498
 
455
499
  out.push({
456
500
  id: data.name || entry.name,
@@ -474,12 +518,17 @@ export class CLISkillLoader {
474
518
  paths: normalizeSkillPaths(data),
475
519
  dirName: entry.name,
476
520
  hasHandler: fs.existsSync(path.join(skillDir, "handler.js")),
477
- body,
478
- // Skill-Embedded MCP: inline server declarations in a
479
- // ```mcp-servers fenced code block. Empty array if absent.
480
- mcpServers: parseSkillMcpServers(body),
521
+ isolation: data.isolation === true,
522
+ // Two-tier loading: discovery retains only the descriptor. The body
523
+ // and embedded MCP declarations are populated on first use.
524
+ body: null,
525
+ bodyLoaded: false,
526
+ mcpServers: [],
481
527
  source: layer,
482
528
  skillDir,
529
+ skillMdPath: skillMd,
530
+ skillFileBytes: stat.size,
531
+ skillFileMtimeMs: stat.mtimeMs,
483
532
  });
484
533
  } catch {
485
534
  // Skip malformed skill files
@@ -487,12 +536,149 @@ export class CLISkillLoader {
487
536
  }
488
537
  }
489
538
 
539
+ /**
540
+ * Materialize a descriptor's markdown body and embedded MCP declarations.
541
+ * Cache entries are invalidated by file size/mtime and never include content
542
+ * in provenance records.
543
+ */
544
+ materializeSkill(skill, context = {}) {
545
+ if (!skill || !skill.skillMdPath) {
546
+ throw new TypeError("A discovered skill descriptor is required");
547
+ }
548
+ const stat = fs.statSync(skill.skillMdPath);
549
+ const signature = `${stat.size}:${stat.mtimeMs}`;
550
+ let cached = this._bodyCache.get(skill.skillMdPath);
551
+ let cacheRead = false;
552
+ if (cached?.signature === signature) {
553
+ this._cacheStats.bodyCacheHits += 1;
554
+ cacheRead = true;
555
+ } else {
556
+ const content = fs.readFileSync(skill.skillMdPath, "utf-8");
557
+ const { body } = parseSkillMd(content);
558
+ cached = {
559
+ signature,
560
+ body,
561
+ mcpServers: parseSkillMcpServers(body),
562
+ rawChars: body.length,
563
+ estimatedTokens: estimateSkillTokens(body),
564
+ };
565
+ this._bodyCache.set(skill.skillMdPath, cached);
566
+ this._cacheStats.bodyCacheMisses += 1;
567
+ }
568
+
569
+ skill.body = cached.body;
570
+ skill.mcpServers = cached.mcpServers;
571
+ skill.bodyLoaded = true;
572
+ skill.skillFileBytes = stat.size;
573
+ skill.skillFileMtimeMs = stat.mtimeMs;
574
+
575
+ const prior = this._cacheStats.bodyLoads.get(skill.skillMdPath) || {
576
+ id: skill.id,
577
+ source: skill.source,
578
+ rawChars: cached.rawChars,
579
+ estimatedTokens: cached.estimatedTokens,
580
+ loads: 0,
581
+ cacheHits: 0,
582
+ loadedBecause: [],
583
+ };
584
+ prior.loads += 1;
585
+ if (cacheRead) prior.cacheHits += 1;
586
+ const reason = context.loadedBecause || "explicit";
587
+ if (!prior.loadedBecause.includes(reason)) prior.loadedBecause.push(reason);
588
+ this._cacheStats.bodyLoads.set(skill.skillMdPath, prior);
589
+
590
+ try {
591
+ this._contextLedger?.recordRead?.({
592
+ sessionId: context.sessionId || "unknown",
593
+ turnId: context.turnId || "unknown",
594
+ sourceType: "skill",
595
+ sourceId: skill.id,
596
+ permissionMode: context.permissionMode || "agent",
597
+ tokenCount: cached.estimatedTokens,
598
+ metadata: {
599
+ source: skill.source,
600
+ loadedBecause: reason,
601
+ cacheRead,
602
+ bodyIncluded: context.bodyIncluded === true,
603
+ },
604
+ });
605
+ } catch {
606
+ // Context observability must never make a valid skill unloadable.
607
+ }
608
+ return skill;
609
+ }
610
+
611
+ /** Record descriptor text that was actually returned to a model/tool caller. */
612
+ recordDescriptorUse(skills, context = {}) {
613
+ for (const skill of Array.isArray(skills) ? skills : []) {
614
+ const descriptorText = `${skill.id}\n${skill.description || ""}\n${skill.category || ""}`;
615
+ try {
616
+ this._contextLedger?.recordRead?.({
617
+ sessionId: context.sessionId || "unknown",
618
+ turnId: context.turnId || "unknown",
619
+ sourceType: "skill_descriptor",
620
+ sourceId: skill.id,
621
+ permissionMode: context.permissionMode || "agent",
622
+ tokenCount: estimateSkillTokens(descriptorText),
623
+ metadata: {
624
+ source: skill.source,
625
+ loadedBecause: context.loadedBecause || "list_skills",
626
+ bodyLoaded: skill.bodyLoaded === true,
627
+ },
628
+ });
629
+ } catch {
630
+ // Observability only.
631
+ }
632
+ }
633
+ }
634
+
635
+ /** Content-free cache/cost snapshot for `cc context --sources`. */
636
+ getCacheLedger() {
637
+ const descriptors = Array.isArray(this._cache) ? this._cache : [];
638
+ const descriptorChars = descriptors.reduce(
639
+ (sum, skill) =>
640
+ sum +
641
+ `${skill.id}\n${skill.displayName}\n${skill.description}\n${skill.category}`.length,
642
+ 0,
643
+ );
644
+ const residentPaths = new Set(this._bodyCache.keys());
645
+ const lazyFileBytes = descriptors.reduce(
646
+ (sum, skill) =>
647
+ sum +
648
+ (residentPaths.has(skill.skillMdPath) ? 0 : skill.skillFileBytes || 0),
649
+ 0,
650
+ );
651
+ const bodyLoads = Array.from(this._cacheStats.bodyLoads.values()).map(
652
+ (entry) => ({ ...entry, loadedBecause: [...entry.loadedBecause] }),
653
+ );
654
+ return {
655
+ descriptors: {
656
+ resident: descriptors.length,
657
+ scans: this._cacheStats.descriptorScans,
658
+ cacheHits: this._cacheStats.descriptorCacheHits,
659
+ rawChars: descriptorChars,
660
+ estimatedTokens: estimateSkillTokens(descriptorChars),
661
+ },
662
+ bodies: {
663
+ resident: this._bodyCache.size,
664
+ cacheHits: this._cacheStats.bodyCacheHits,
665
+ cacheMisses: this._cacheStats.bodyCacheMisses,
666
+ entries: bodyLoads,
667
+ },
668
+ savings: {
669
+ lazyFileBytes,
670
+ estimatedTokensAvoided: estimateSkillTokens(lazyFileBytes),
671
+ },
672
+ };
673
+ }
674
+
490
675
  /**
491
676
  * Load all skills from all layers, applying priority override
492
677
  * Higher-priority layers override same-name skills from lower layers.
493
678
  * @returns {object[]} Resolved skill list
494
679
  */
495
680
  loadAll(options = {}) {
681
+ this._cacheStats.descriptorScans += 1;
496
682
  // `cc agent --bare` (CC_SKILLS=0): no skill layer loads at all — cache the
497
683
  // empty result so getResolvedSkills stays cheap on every call.
498
684
  if (allSkillsDisabled(options)) {
@@ -552,7 +738,10 @@ export class CLISkillLoader {
552
738
  * @returns {object[]}
553
739
  */
554
740
  getResolvedSkills() {
555
- if (this._cache) return this._cache;
741
+ if (this._cache) {
742
+ this._cacheStats.descriptorCacheHits += 1;
743
+ return this._cache;
744
+ }
556
745
  return this.loadAll();
557
746
  }
558
747
 
@@ -560,10 +749,16 @@ export class CLISkillLoader {
560
749
  * Get auto-activated persona skills
561
750
  * @returns {object[]} skills with category "persona" and activation "auto"
562
751
  */
563
- getAutoActivatedPersonas() {
564
- return this.getResolvedSkills().filter(
565
- (s) => s.category === "persona" && s.activation === "auto",
566
- );
752
+ getAutoActivatedPersonas(context = {}) {
753
+ return this.getResolvedSkills()
754
+ .filter((s) => s.category === "persona" && s.activation === "auto")
755
+ .map((skill) =>
756
+ this.materializeSkill(skill, {
757
+ ...context,
758
+ loadedBecause: context.loadedBecause || "persona_auto",
759
+ bodyIncluded: true,
760
+ }),
761
+ );
567
762
  }
568
763
 
569
764
  /**
@@ -571,6 +766,14 @@ export class CLISkillLoader {
571
766
  */
572
767
  clearCache() {
573
768
  this._cache = null;
769
+ this._bodyCache.clear();
770
+ this._cacheStats = {
771
+ descriptorScans: 0,
772
+ descriptorCacheHits: 0,
773
+ bodyCacheHits: 0,
774
+ bodyCacheMisses: 0,
775
+ bodyLoads: new Map(),
776
+ };
574
777
  }
575
778
  }
576
779
 
@@ -115,6 +115,7 @@ cli-version-hash: "${hash}"
115
115
  tags: [${allTags}]
116
116
  user-invocable: true
117
117
  handler: handler.js
118
+ capabilities: [shell-exec]
118
119
  ---
119
120
 
120
121
  # ${domainDef.displayName}
@@ -176,7 +177,6 @@ export function generateDirectHandler(domainKey, domainDef) {
176
177
  * 自动生成 — 请勿手动修改,运行 \`chainlesschain skill sync-cli\` 重新生成
177
178
  */
178
179
 
179
- const { spawnSync } = require("child_process");
180
180
 
181
181
  /** 解析输入字符串为指令+参数数组 */
182
182
  function parseInput(input) {
@@ -241,7 +241,7 @@ ${commandGuide}
241
241
  const useJson = JSON_SUPPORTED_COMMANDS.has(command) && !cliArgs.includes("--json");
242
242
  if (useJson) cliArgs.push("--json");
243
243
 
244
- // Security: spawnSync uses shell:true (needed to run the chainlesschain.cmd
244
+ // Security: Broker execution uses shell:true (needed to run the chainlesschain.cmd
245
245
  // shim on Windows), which joins cliArgs into a shell command. Reject shell
246
246
  // metacharacters so a crafted skill input can't inject commands.
247
247
  const unsafeArg = cliArgs.find((a) => /[;&|\`$<>()\\n\\r]/.test(a));
@@ -252,11 +252,16 @@ ${commandGuide}
252
252
  };
253
253
  }
254
254
 
255
- // Execute via child process
256
- const result = spawnSync("chainlesschain", cliArgs, {
255
+ const processBroker = context?.processBroker;
256
+ if (!processBroker || typeof processBroker.runSync !== "function") {
257
+ return { success: false, error: "Process Broker unavailable for skill execution." };
258
+ }
259
+
260
+ // Execute via the host-scoped Process Broker facade.
261
+ const result = processBroker.runSync("chainlesschain", cliArgs, {
257
262
  encoding: "utf-8",
258
263
  shell: true,
259
- cwd: context.projectRoot || process.cwd(),
264
+ cwd: context?.projectRoot || process.cwd(),
260
265
  timeout: 30000,
261
266
  env: { ...process.env },
262
267
  });
@@ -407,7 +412,6 @@ export function generateHybridHandler(domainKey, domainDef) {
407
412
  * 自动生成 — 请勿手动修改,运行 \`chainlesschain skill sync-cli\` 重新生成
408
413
  */
409
414
 
410
- const { spawnSync } = require("child_process");
411
415
 
412
416
  const AGENT_ONLY_COMMANDS = new Set([${agentCmds}]);
413
417
  const VALID_COMMANDS = new Set(["${commandList}"]);
@@ -470,7 +474,7 @@ const handler = {
470
474
  // Direct execution for other commands
471
475
  const cliArgs = [...args, "--quiet"];
472
476
 
473
- // Security: spawnSync uses shell:true (needed to run the chainlesschain.cmd
477
+ // Security: Broker execution uses shell:true (needed to run the chainlesschain.cmd
474
478
  // shim on Windows), which joins cliArgs into a shell command. Reject shell
475
479
  // metacharacters so a crafted skill input can't inject commands.
476
480
  const unsafeArg = cliArgs.find((a) => /[;&|\`$<>()\\n\\r]/.test(a));
@@ -481,10 +485,15 @@ const handler = {
481
485
  };
482
486
  }
483
487
 
484
- const result = spawnSync("chainlesschain", cliArgs, {
488
+ const processBroker = context?.processBroker;
489
+ if (!processBroker || typeof processBroker.runSync !== "function") {
490
+ return { success: false, error: "Process Broker unavailable for skill execution." };
491
+ }
492
+
493
+ const result = processBroker.runSync("chainlesschain", cliArgs, {
485
494
  encoding: "utf-8",
486
495
  shell: true,
487
- cwd: context.projectRoot || process.cwd(),
496
+ cwd: context?.projectRoot || process.cwd(),
488
497
  timeout: 30000,
489
498
  env: { ...process.env },
490
499
  });
@@ -0,0 +1,85 @@
1
+ import executionBroker from "./process-execution-broker/index.js";
2
+
3
+ const defaultRunSync = executionBroker.spawnSync.bind(executionBroker);
4
+ const defaultRunFileSync = executionBroker.execFileSync.bind(executionBroker);
5
+ const defaultRun = executionBroker.spawn.bind(executionBroker);
6
+
7
+ function skillIdentity(skill = {}) {
8
+ const identity = String(
9
+ skill.id || skill.name || skill.skillName || "unknown",
10
+ )
11
+ .trim()
12
+ .replace(/[^a-zA-Z0-9._:-]+/g, "-")
13
+ .slice(0, 96);
14
+ return identity || "unknown";
15
+ }
16
+
17
+ function declaresShellExecution(skill = {}) {
18
+ return (
19
+ Array.isArray(skill.capabilities) &&
20
+ skill.capabilities.some(
21
+ (capability) => String(capability).toLowerCase() === "shell-exec",
22
+ )
23
+ );
24
+ }
25
+
26
+ /**
27
+ * Create the narrow process facade exposed to a skill handler.
28
+ *
29
+ * The host, not the handler, owns provenance and permission metadata. Generated
30
+ * handlers can choose argv and ordinary process options, but cannot relabel the
31
+ * execution or bypass the Broker boundary.
32
+ */
33
+ export function createSkillProcessBroker(
34
+ skill,
35
+ {
36
+ run = defaultRun,
37
+ runSync = defaultRunSync,
38
+ runFileSync = defaultRunFileSync,
39
+ } = {},
40
+ ) {
41
+ if (!declaresShellExecution(skill)) return null;
42
+
43
+ const identity = skillIdentity(skill);
44
+ const metadata = Object.freeze({
45
+ origin: `skill:${identity}`,
46
+ policy: "allow",
47
+ scope: "skill",
48
+ pluginId: skill?.pluginId || skill?.plugin?.id || null,
49
+ pluginVersion: skill?.pluginVersion || skill?.plugin?.version || null,
50
+ pluginSource: skill?.pluginSource || skill?.plugin?.source || null,
51
+ });
52
+
53
+ return Object.freeze({
54
+ run(file, args = [], options = {}) {
55
+ return run(file, args, {
56
+ ...options,
57
+ ...metadata,
58
+ shell: false,
59
+ });
60
+ },
61
+
62
+ runSync(file, args = [], options = {}) {
63
+ return runSync(file, args, {
64
+ ...options,
65
+ ...metadata,
66
+ });
67
+ },
68
+
69
+ runFileSync(file, args = [], options = {}) {
70
+ return runFileSync(file, args, {
71
+ ...options,
72
+ ...metadata,
73
+ shell: false,
74
+ });
75
+ },
76
+ });
77
+ }
78
+
79
+ export const _skillProcessDefaults = {
80
+ run: defaultRun,
81
+ runSync: defaultRunSync,
82
+ runFileSync: defaultRunFileSync,
83
+ };
84
+
85
+ export { declaresShellExecution as skillDeclaresShellExecution };
@@ -21,11 +21,15 @@
21
21
  import fsDefault from "node:fs";
22
22
  import pathDefault from "node:path";
23
23
  import { homedir } from "node:os";
24
- import { execSync as execSyncDefault } from "node:child_process";
25
24
  import { expandFileRefs } from "../runtime/file-ref-expander.js";
26
25
  import { projectRootBase } from "./project-root.cjs";
26
+ import executionBroker from "./process-execution-broker/index.js";
27
27
 
28
- const _deps = { fs: fsDefault, path: pathDefault, execSync: execSyncDefault };
28
+ const _deps = {
29
+ fs: fsDefault,
30
+ path: pathDefault,
31
+ execSync: (...args) => executionBroker.execSync(...args),
32
+ };
29
33
 
30
34
  /**
31
35
  * Split `--- ... ---` frontmatter from the body and camelCase the keys (so
@@ -191,6 +195,10 @@ function runBangs(text, { cwd, execSync }) {
191
195
  encoding: "utf-8",
192
196
  timeout: BANG_TIMEOUT_MS,
193
197
  stdio: ["ignore", "pipe", "pipe"],
198
+ origin: "slash-command:bang",
199
+ policy: "allow",
200
+ scope: "slash-command",
201
+ shell: true,
194
202
  });
195
203
  return String(out).trim();
196
204
  } catch (err) {
@@ -13,15 +13,14 @@
13
13
  *
14
14
  * Best-effort throughout: a missing config, a broken command, or a timeout just
15
15
  * yields no status line — it never blocks or breaks the REPL. `_deps` injection
16
- * (spawnSync / settings reader) for tests.
16
+ * (process runner / settings reader) for tests.
17
17
  */
18
18
 
19
- const cpDefault = require("node:child_process");
20
19
  const path = require("node:path");
21
20
  const { settingsPaths, readSettingsFile } = require("./settings-loader.cjs");
22
21
 
23
22
  const _deps = {
24
- spawnSync: cpDefault.spawnSync,
23
+ runProcess: null,
25
24
  // injectable so tests don't touch real settings files
26
25
  readSettings: (cwd, settingsFile) => {
27
26
  const out = [];
@@ -181,7 +180,7 @@ function isStatusLineDisabled({ cwd = process.cwd(), settingsFile } = {}) {
181
180
  function renderStatusLine(
182
181
  config,
183
182
  context = {},
184
- { cwd, timeout = 5000, columns, rows } = {},
183
+ { cwd, timeout = 5000, columns, rows, runProcess } = {},
185
184
  ) {
186
185
  if (!config || !config.command) return null;
187
186
  // Claude-Code parity (2.1.153): hand the command the terminal width/height so
@@ -194,7 +193,9 @@ function renderStatusLine(
194
193
  if (rws != null) env.LINES = String(rws);
195
194
  let res;
196
195
  try {
197
- res = _deps.spawnSync(config.command, {
196
+ const runner = runProcess || _deps.runProcess;
197
+ if (typeof runner !== "function") return null;
198
+ res = runner(config.command, [], {
198
199
  input: JSON.stringify(context),
199
200
  cwd: cwd || process.cwd(),
200
201
  env,
@@ -202,6 +203,9 @@ function renderStatusLine(
202
203
  timeout,
203
204
  shell: true,
204
205
  maxBuffer: 1024 * 1024,
206
+ origin: "status-line:command",
207
+ policy: "allow",
208
+ scope: "status-line",
205
209
  });
206
210
  } catch {
207
211
  return null; // spawn failure → no status line
@@ -216,11 +220,28 @@ function renderStatusLine(
216
220
  }
217
221
 
218
222
  /** Convenience: load + render in one call (used by the REPL each turn). */
219
- function getStatusLine({ cwd, settingsFile, sessionId, model, provider, projectDir, timeout, columns, rows } = {}) {
223
+ function getStatusLine({
224
+ cwd,
225
+ settingsFile,
226
+ sessionId,
227
+ model,
228
+ provider,
229
+ projectDir,
230
+ timeout,
231
+ columns,
232
+ rows,
233
+ runProcess,
234
+ } = {}) {
220
235
  const config = loadStatusLineConfig({ cwd, settingsFile });
221
236
  if (!config) return null;
222
237
  const context = buildContext({ sessionId, model, provider, cwd, projectDir });
223
- return renderStatusLine(config, context, { cwd, timeout, columns, rows });
238
+ return renderStatusLine(config, context, {
239
+ cwd,
240
+ timeout,
241
+ columns,
242
+ rows,
243
+ runProcess,
244
+ });
224
245
  }
225
246
 
226
247
  module.exports = {