chainlesschain 0.162.181 → 0.162.183

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 (195) hide show
  1. package/package.json +2 -1
  2. package/scripts/build-windows-sandbox-helper.ps1 +163 -0
  3. package/src/assets/web-panel/assets/{AIOps-cq0dwbnf.js → AIOps-BapS7lz4.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-CvcgGl3w.js → ActionButton-CXYdXEUI.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-hM2-jFqg.js → Analytics-CKR5Lexn.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-B9_Gsd_g.js → AppLayout-DATVUOXB.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-B7bu52Og.js → Artifacts-vb_0ZlV1.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-DThfDgqB.js → Audit-BI1l9GWt.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-DjlFiD4v.js → BackgroundAgents-BFXbaUEf.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-CK9xJKnG.js → Backup-DEYBJJ6H.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-DEiSU8K8.js → BaseInput-COdzeO0M.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-CpT96czj.js → Chat-oSN6sfM5.js} +6 -6
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-CI_jT0ru.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-C1GfDnO0.js → Checkbox-BezEa4tm.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-3DAKgiLx.js → Codegen-CNEL0Ife.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-74cOwZU1.js → Col-Bf2Y2Bn1.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-tn9Kkz9j.js → Community-BfUlu4Hc.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-BcoXH7m4.js → Compact-BN4xWP9e.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-DIPGUBgi.js → Compliance-Bt6BKmEP.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-doD5_91c.js → Cowork-DKLp8YxO.js} +2 -2
  21. package/src/assets/web-panel/assets/{Cron-C-IDvubz.js → Cron-o7Hhw6ky.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-CdcCoBdj.js → Crosschain-DaNXWJIw.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-DdH5aMMA.js → DID-B-Qa2mha.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-DHLA4mm0.js → Dashboard-CMX0Qnxw.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-dEeCt7Md.js → Dropdown-BLuLyRu_.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-BMaecFv9.js → EmailListRenderer-CFBAeMij.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DUaUukTN.js → FamilyGuardDashboard-DWzXQ67V.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-CMBE0_rp.js → Federation-DB1QSLgr.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-PG-JDbXq.js → FormItemContext-C-OKCToP.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-Bcb0p88m.js → GenericCardRenderer-DMJFtFZf.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-Bgv15myB.js → Git-DsGSujOV.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-DB8YTArI.js → Governance-B0iS9NEW.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-BQMwCWaS.js → Inference-CH004H7c.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-B1_ZziiB.js → KnowledgeGraph-Q9MTQ83c.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-DovEEnt_.js → Logs-B_fyjZK9.js} +2 -2
  36. package/src/assets/web-panel/assets/{MarkdownRenderer-D201OL4T.js → MarkdownRenderer-C0o4FtpD.js} +1 -1
  37. package/src/assets/web-panel/assets/{Marketplace-BlCXSpyB.js → Marketplace-BIStF9d1.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-CsCR09Wj.js → McpTools-pGfal768.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-CBVRLKno.js → Memory-xbNqpIqB.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-C9OIafgA.js → MobileBridge-B5EQGrIK.js} +1 -1
  41. package/src/assets/web-panel/assets/MobileProjects-VTc3gT1y.js +1 -0
  42. package/src/assets/web-panel/assets/{Mtc-vE-HdvLj.js → Mtc-a_rmfxJH.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-CPLaekCd.js → MtcAudit-BmKuofUr.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-C_UP9C2o.js → Multisig-BQbJ-CAN.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-2nODJcU1.js → NLProgramming-JtPJKX25.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-BhE-SJGu.js → Notes-ZFKznTSG.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-D21q7BNU.js → NotificationSettings-B6aHRBBR.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-0b62GYOD.js → OrderTableRenderer-DdcsOqEz.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-CEqmw_sb.js → Organization-BFDTAUgS.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-MW-gMDO_.js → Overflow-0FoTfbWH.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-CY0hjI_G.js → P2P-CWd90etw.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-BbWh7Man.js → PdhVaultBrowser-DtCGC-W-.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-ChqEA_4Q.js → Permissions-CvQ7nr7T.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-B3YrbYfD.js → PersonalDataHub-rdNPcR-Z.js} +5 -5
  55. package/src/assets/web-panel/assets/{Pipeline-B8WBhhlW.js → Pipeline-CmrfiNOs.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-Cmb0PXNx.js → Privacy-D7ep1h_t.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-hF6zW3Nz.js → ProjectInit-C0xKINHS.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-BFSVfpW0.js → ProjectSettings-AOmZFp-F.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-BWHSkXZP.js +1 -0
  60. package/src/assets/web-panel/assets/{Providers-B8yux8Dx.js → Providers-Cb7JCTPL.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-N76cQluO.js → QrScannerModal-BDMehcXC.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-ClvZ0KYR.js → QuickAsk-BF6_1nvx.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-B-GfgBpT.js → Recommend-BHfT-A28.js} +1 -1
  64. package/src/assets/web-panel/assets/RemoteSession-B6EEf8hh.js +5 -0
  65. package/src/assets/web-panel/assets/{Reputation-DJIZzQeG.js → Reputation-CsWHLEcj.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-COzxu_bb.js → Row-D6srnWhm.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-CoYsJQuE.js → RssFeed-Xhr-KyVd.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-DC77Mq9S.js → Search-vIbIJvwL.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-Loy2EdMO.js → Security-Bzi5Aiko.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-GUD07Eu0.js → Services-BHtVX52P.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-DWzkptYU.js → Skeleton-C0R8B2jf.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-CEDn1r-Z.js → Skills-DtT6rWOX.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-ub_k4pXh.js → Sla-0B37mxVU.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-D7HLX9CA.js → SpeechSettings-0V2jE1Bs.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-DbwOvl6m.js → SyncSettings-CYedRzaj.js} +2 -2
  76. package/src/assets/web-panel/assets/Tasks-D-R1x8vm.js +1 -0
  77. package/src/assets/web-panel/assets/{Templates-BNVeIhud.js → Templates-BKoHztGT.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-PS9AzhXU.js → Tenant--17nwVNZ.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-Cgb4eLB_.js → Terminal-Dnkos7vW.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-CrmXMOkg.js → TimelineRenderer-C5jx4AE3.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-DD-VDHw1.js → Tokens-DYJKYa9t.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-BsoN_n-n.js → Trigger-DChpWiQ9.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-n8LmN4ZV.js → Trust-DfWG52EA.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-C9_7MImA.js → UkeySign-CMugYcyA.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-DyBteNgn.js → VideoEditing-BOSmrHAd.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-BS5ixeXI.js → Wallet-D5g3k3Sa.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-spc4UImU.js → WebAuthn-D-7u4Mkc.js} +3 -3
  88. package/src/assets/web-panel/assets/{WorkflowEditor-D7iVvaBO.js → WorkflowEditor-CFzZMSUJ.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-6CmBkHrL.js → chat-VbR6l6mc.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-BGoCLkxI.js → colors-BSZn8EDS.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-fYZBetMO.js → compact-item-y74obMEq.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-BeM-1UVj.js → createContext-C326bjex.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-D3Bho_6u.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-CE7ZuEnV.js → hasIn-D_INJQT_.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-ukg99D1V.js → index-4PIeTM--.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-B2U-ObMq.js → index-4eyH-eC2.js} +1 -1
  97. package/src/assets/web-panel/assets/index-5iAFwYx1.js +1 -0
  98. package/src/assets/web-panel/assets/{index-CRLjEP1H.js → index-9PIVuXqo.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BfPL-m46.js → index-B7SrC-On.js} +1 -1
  100. package/src/assets/web-panel/assets/{index--lap6cf7.js → index-BJi3UqBt.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-B3CDgvNW.js → index-BY8-nCgs.js} +1 -1
  102. package/src/assets/web-panel/assets/index-BfnB7LPx.js +1 -0
  103. package/src/assets/web-panel/assets/{index-De0quFDw.js → index-Bfw2hf2s.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BunaQCa0.js → index-BjcWKg1S.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BsMfoaeo.js → index-BnSfnSMP.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-C0v6YKKO.js → index-Bnua8IX3.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-C4SJVjs4.js → index-C-ZCaUJc.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BNZDILcO.js → index-C2NyllnW.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-YjcumOZ4.js → index-C327pLbw.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CRnUE8Cb.js → index-CMHqs3Jb.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CIpVrf5P.js → index-CfLJ42kv.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BEVm0lCS.js → index-Cr3uuz0C.js} +3 -3
  113. package/src/assets/web-panel/assets/{index-Dw1PyYPm.js → index-CsovTpx9.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-lJBjB1QX.js → index-CzE53HiB.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CpIGIB85.js → index-DBkzrpiL.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DoXk5KJ8.js → index-DNMxIsDg.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DsvfrESp.js → index-DUU2606o.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Cip8emOQ.js → index-DdyjrCAu.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-ATcSr_2O.js → index-DkH1JvEt.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BV551878.js → index-Dlxh9D8D.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BU_2qiDk.js → index-DuIkfnTF.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-zb7rVOhV.js → index-DwHSZLXg.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-MtOuq2i6.js → index-E_v1ZCTP.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-B8BsdNV_.js → index-FQBsuExX.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-WUrJ6S1j.js → index-GA80ir_u.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-RMZ8a7Yt.js → index-IZAWt0H8.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-D1r9tT3J.js → index-Iw0FfqUz.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BowH1eLQ.js → index-KF9Zmqln.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-Puq6Luf1.js → index-abmn_8Yz.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-QIpnpZgz.js → index-gINyI1rh.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-C9Y3k0HI.js → index-jYaogFE8.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-B4wiTEOM.js → index-nSn2-C4N.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DT3zPSVX.js → index-qMA4GYdQ.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-CYHMs1ag.js → initDefaultProps-DI0Zaf8-.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-DDB2Ffk5.js → motion-BZDKSy3Z.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-Bg3cD-dX.js → move-DsIW01Vp.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-B5nedjTS.js → mtc-parser-CohkDhsf.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-BHyuUILu.js → omit-DpiN5rzg.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-C9YQnEN9.js → pickAttrs-qbuqni3y.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-DBUFYUe7.js → placementArrow-mBky6714.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-nBs2Obnk.js → responsiveObserve-Bas3eQ2K.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-DkCEaXNU.js → slide-CBx_SKoK.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-aqE1Wi6U.js → statusUtils-BlYguJSV.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-CN5bhfHB.js → styleChecker-BCYQmRGv.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-B_oX_kvJ.js → useFlexGapSupport-Dp5dybLM.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-rCuXHeme.js → useFs-DHAMBgA2.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-DZR9Abyd.js → usePersonalDataHub-W6jsSw76.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-ConCYQlX.js → vnode-BkI6aayc.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-CUdDxG5M.js → zoom-C_IMGueq.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/commands/agenda.js +115 -3
  152. package/src/commands/agent.js +15 -0
  153. package/src/commands/background-session.js +49 -0
  154. package/src/commands/plugin.js +235 -23
  155. package/src/commands/session.js +13 -0
  156. package/src/data/changelog.json +26 -0
  157. package/src/gateways/terminal/PtyManager.js +45 -4
  158. package/src/gateways/ws/ws-server.js +10 -1
  159. package/src/harness/background-task-manager.js +70 -2
  160. package/src/harness/jsonl-session-store.js +6 -4
  161. package/src/harness/worktree-isolator.js +14 -3
  162. package/src/lib/agent-core.js +1 -0
  163. package/src/lib/agent-schedule-store.js +45 -22
  164. package/src/lib/agent-team/team-runner.js +19 -1
  165. package/src/lib/background-agent-supervisor.js +49 -0
  166. package/src/lib/hook-runner.js +6 -2
  167. package/src/lib/packer/pkg-config-generator.js +3 -1
  168. package/src/lib/plugin-runtime/bin.js +1148 -70
  169. package/src/lib/plugin-runtime/install.js +226 -7
  170. package/src/lib/plugin-runtime/manifest.js +68 -12
  171. package/src/lib/plugin-runtime/scopes.js +33 -12
  172. package/src/lib/plugin-usage-attribution.js +44 -0
  173. package/src/lib/process-execution-broker/index.js +626 -48
  174. package/src/lib/process-execution-broker/platform-sandbox.js +4971 -266
  175. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  176. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  177. package/src/lib/process-execution-broker/windows-sandbox.cs +3856 -0
  178. package/src/lib/repl-bang-memorize.js +67 -10
  179. package/src/lib/session-usage.js +77 -0
  180. package/src/lib/slash-commands.js +27 -4
  181. package/src/repl/agent-repl.js +10 -9
  182. package/src/runtime/agent-core.js +376 -52
  183. package/src/runtime/agent-runtime.js +13 -1
  184. package/src/runtime/headless-runner.js +13 -4
  185. package/src/runtime/headless-stream.js +20 -1
  186. package/src/runtime/mcp-config.js +15 -5
  187. package/src/assets/web-panel/assets/ChatBubbleRenderer-BKPPNmZI.js +0 -1
  188. package/src/assets/web-panel/assets/MobileProjects-D_zoJ8Xs.js +0 -1
  189. package/src/assets/web-panel/assets/Projects-DAWkVFkc.js +0 -1
  190. package/src/assets/web-panel/assets/RemoteSession-mlglCdQi.js +0 -5
  191. package/src/assets/web-panel/assets/Tasks-CBQzoAu5.js +0 -1
  192. package/src/assets/web-panel/assets/devWarning-BzPwHnw8.js +0 -1
  193. package/src/assets/web-panel/assets/index-DacrAdc-.js +0 -1
  194. package/src/assets/web-panel/assets/index-EHzNJozo.js +0 -1
  195. package/src/lib/process-execution-broker/windows-sandbox.ps1 +0 -999
@@ -21,6 +21,7 @@ import fsDefault from "fs";
21
21
  import pathDefault from "path";
22
22
  import { findProjectRoot } from "./project-instructions.js";
23
23
  import executionBroker from "./process-execution-broker/index.js";
24
+ import { collectPluginBinSandboxPolicy as collectDefaultPluginBinSandboxPolicy } from "./plugin-runtime/bin.js";
24
25
 
25
26
  export const BANG_TIMEOUT_MS = 120_000;
26
27
  export const BANG_MAX_BUFFER = 10 * 1024 * 1024;
@@ -33,6 +34,8 @@ export const MEMO_NOTE_MAX = 4_000;
33
34
 
34
35
  export const _deps = {
35
36
  spawnSync: (...args) => executionBroker.spawnSync(...args),
37
+ collectPluginBinSandboxPolicy: (opts) =>
38
+ collectDefaultPluginBinSandboxPolicy(opts),
36
39
  fs: fsDefault,
37
40
  path: pathDefault,
38
41
  };
@@ -44,6 +47,46 @@ function cap(s) {
44
47
  : str;
45
48
  }
46
49
 
50
+ function resolveWindowsCommandShell(opts = {}) {
51
+ const path = opts.deps?.path || _deps.path;
52
+ const env = opts.env || process.env;
53
+ const normalizeLocalPath = (candidate) => {
54
+ const value =
55
+ typeof candidate === "string"
56
+ ? candidate.trim()
57
+ : String(candidate || "");
58
+ // `path.win32.isAbsolute("\\foo")` is true even though the result still
59
+ // depends on the process's current drive. Require a drive-qualified local
60
+ // path so the helper receives one deterministic executable identity.
61
+ if (!/^[a-z]:[\\/]/i.test(value)) return null;
62
+ return path.win32.normalize(value);
63
+ };
64
+
65
+ for (const candidate of [opts.comSpec, env.ComSpec, env.COMSPEC]) {
66
+ const value = normalizeLocalPath(candidate);
67
+ if (value && path.win32.basename(value).toLowerCase() === "cmd.exe") {
68
+ return value;
69
+ }
70
+ }
71
+
72
+ for (const candidate of [
73
+ opts.systemRoot,
74
+ env.SystemRoot,
75
+ env.SYSTEMROOT,
76
+ env.WINDIR,
77
+ "C:\\Windows",
78
+ ]) {
79
+ const value = normalizeLocalPath(candidate);
80
+ if (value) {
81
+ return path.win32.join(value, "System32", "cmd.exe");
82
+ }
83
+ }
84
+
85
+ // The literal fallback above is absolute, so this is unreachable with Node's
86
+ // path.win32 implementation. Keep a fail-closed guard for injected path seams.
87
+ throw new Error("No absolute Windows command shell is available");
88
+ }
89
+
47
90
  /** True when the REPL line is a `!` bash passthrough. */
48
91
  export function isBangCommand(trimmed) {
49
92
  return (
@@ -70,24 +113,37 @@ export function isMemorizeLine(trimmed) {
70
113
  */
71
114
  export function runBangCommand(line, opts = {}) {
72
115
  const spawnSync = opts.deps?.spawnSync || _deps.spawnSync;
116
+ const collectPluginBinSandboxPolicy =
117
+ opts.deps?.collectPluginBinSandboxPolicy ||
118
+ _deps.collectPluginBinSandboxPolicy;
73
119
  const cwd = opts.cwd || process.cwd();
74
120
  const isWin =
75
121
  opts.platform != null
76
122
  ? opts.platform === "win32"
77
123
  : process.platform === "win32";
78
124
  const cmd = String(line).replace(/^!/, "").trim();
125
+ // A bang command is another arbitrary workspace process surface. Collect the
126
+ // tighten-only Plugin bin boundary union before the shell starts so it cannot
127
+ // bypass a policy that run_shell already pins for the same workspace.
128
+ const sandboxPolicy = collectPluginBinSandboxPolicy({ cwd });
129
+ const sandboxOptions = sandboxPolicy ? { sandboxPolicy } : {};
79
130
 
80
131
  const res = isWin
81
- ? spawnSync("cmd.exe", ["/d", "/s", "/c", `chcp 65001 >nul && ${cmd}`], {
82
- encoding: "utf-8",
83
- timeout: BANG_TIMEOUT_MS,
84
- maxBuffer: BANG_MAX_BUFFER,
85
- cwd,
86
- origin: "repl:bang-command",
87
- policy: "allow",
88
- scope: "repl",
89
- shell: false,
90
- })
132
+ ? spawnSync(
133
+ resolveWindowsCommandShell(opts),
134
+ ["/d", "/s", "/c", `chcp 65001 >nul && ${cmd}`],
135
+ {
136
+ encoding: "utf-8",
137
+ timeout: BANG_TIMEOUT_MS,
138
+ maxBuffer: BANG_MAX_BUFFER,
139
+ cwd,
140
+ origin: "repl:bang-command",
141
+ policy: "allow",
142
+ scope: "repl",
143
+ shell: false,
144
+ ...sandboxOptions,
145
+ },
146
+ )
91
147
  : spawnSync("/bin/sh", ["-c", cmd], {
92
148
  encoding: "utf-8",
93
149
  timeout: BANG_TIMEOUT_MS,
@@ -97,6 +153,7 @@ export function runBangCommand(line, opts = {}) {
97
153
  policy: "allow",
98
154
  scope: "repl",
99
155
  shell: false,
156
+ ...sandboxOptions,
100
157
  });
101
158
 
102
159
  const exitCode = res.status == null ? (res.error ? -1 : 0) : res.status;
@@ -12,6 +12,7 @@ import {
12
12
  readEvents,
13
13
  listJsonlSessions,
14
14
  } from "../harness/jsonl-session-store.js";
15
+ import { extractPluginUsageAttribution } from "./plugin-usage-attribution.js";
15
16
 
16
17
  // Injectable disk seams (tests override). readEvents skips malformed JSON lines
17
18
  // but does NOT guard readFileSync, so an unreadable session file (EACCES /
@@ -228,6 +229,7 @@ function _isToolResultError(event) {
228
229
  export function aggregateToolCalls(events) {
229
230
  const byTool = new Map();
230
231
  const byServer = new Map();
232
+ const byPlugin = new Map();
231
233
  let totalCalls = 0;
232
234
  let totalErrors = 0;
233
235
 
@@ -253,19 +255,42 @@ export function aggregateToolCalls(events) {
253
255
  }
254
256
  return s;
255
257
  };
258
+ const bumpPlugin = (plugin, version = null) => {
259
+ const key = `${plugin}@${version || "?"}`;
260
+ let row = byPlugin.get(key);
261
+ if (!row) {
262
+ row = {
263
+ plugin,
264
+ version: version || null,
265
+ calls: 0,
266
+ errors: 0,
267
+ turnTokens: 0,
268
+ };
269
+ byPlugin.set(key, row);
270
+ }
271
+ return row;
272
+ };
256
273
 
257
274
  let turnTools = new Set();
258
275
  let turnServers = new Set();
276
+ let turnPlugins = new Set();
259
277
  let turnTokens = 0;
278
+ let pendingPlugin = null;
260
279
  const flushTurn = () => {
261
280
  if (turnTokens > 0) {
262
281
  for (const name of turnTools) bumpTool(name).turnTokens += turnTokens;
263
282
  for (const server of turnServers)
264
283
  bumpServer(server).turnTokens += turnTokens;
284
+ for (const key of turnPlugins) {
285
+ const row = byPlugin.get(key);
286
+ if (row) row.turnTokens += turnTokens;
287
+ }
265
288
  }
266
289
  turnTools = new Set();
267
290
  turnServers = new Set();
291
+ turnPlugins = new Set();
268
292
  turnTokens = 0;
293
+ pendingPlugin = null;
269
294
  };
270
295
 
271
296
  for (const evt of events || []) {
@@ -292,6 +317,21 @@ export function aggregateToolCalls(events) {
292
317
  if (isErr) s.errors++;
293
318
  turnServers.add(server);
294
319
  }
320
+ const plugin =
321
+ typeof evt.data?.plugin === "string" && evt.data.plugin
322
+ ? evt.data.plugin
323
+ : null;
324
+ const pluginVersion =
325
+ typeof evt.data?.plugin_version === "string"
326
+ ? evt.data.plugin_version
327
+ : null;
328
+ pendingPlugin = { tool: name, plugin, version: pluginVersion };
329
+ if (plugin) {
330
+ const p = bumpPlugin(plugin, pluginVersion);
331
+ p.calls++;
332
+ if (isErr) p.errors++;
333
+ turnPlugins.add(`${plugin}@${pluginVersion || "?"}`);
334
+ }
295
335
  continue;
296
336
  }
297
337
  if (evt.type === "tool_result") {
@@ -304,6 +344,26 @@ export function aggregateToolCalls(events) {
304
344
  bumpTool(name).errors++;
305
345
  if (server) bumpServer(server).errors++;
306
346
  }
347
+ const extracted = extractPluginUsageAttribution(evt.data?.result);
348
+ const plugin =
349
+ typeof evt.data?.plugin === "string" && evt.data.plugin
350
+ ? evt.data.plugin
351
+ : extracted.plugin || null;
352
+ const pluginVersion =
353
+ typeof evt.data?.plugin_version === "string"
354
+ ? evt.data.plugin_version
355
+ : extracted.pluginVersion || null;
356
+ if (plugin) {
357
+ const p = bumpPlugin(plugin, pluginVersion);
358
+ const countedByCall =
359
+ pendingPlugin?.tool === name &&
360
+ pendingPlugin?.plugin === plugin &&
361
+ (pendingPlugin?.version || null) === (pluginVersion || null);
362
+ if (!countedByCall) p.calls++;
363
+ if (_isToolResultError(evt) && !countedByCall) p.errors++;
364
+ turnPlugins.add(`${plugin}@${pluginVersion || "?"}`);
365
+ }
366
+ pendingPlugin = null;
307
367
  continue;
308
368
  }
309
369
  const u = extractUsage(evt);
@@ -317,6 +377,7 @@ export function aggregateToolCalls(events) {
317
377
  totalErrors,
318
378
  byTool: Array.from(byTool.values()).sort(byCallsDesc),
319
379
  byMcpServer: Array.from(byServer.values()).sort(byCallsDesc),
380
+ byPlugin: Array.from(byPlugin.values()).sort(byCallsDesc),
320
381
  };
321
382
  }
322
383
 
@@ -457,6 +518,7 @@ export function allSessionsUsage({ limit = 1000 } = {}) {
457
518
  const gSubagent = new Map();
458
519
  const gTool = new Map();
459
520
  const gServer = new Map();
521
+ const gPlugin = new Map();
460
522
  let gToolCalls = 0;
461
523
  let gToolErrors = 0;
462
524
  const mergeRow = (map, key, row, seed) => {
@@ -508,6 +570,20 @@ export function allSessionsUsage({ limit = 1000 } = {}) {
508
570
  entry.turnTokens += row.turnTokens || 0;
509
571
  gServer.set(row.server, entry);
510
572
  }
573
+ for (const row of tools.byPlugin || []) {
574
+ const key = `${row.plugin}@${row.version || "?"}`;
575
+ const entry = gPlugin.get(key) || {
576
+ plugin: row.plugin,
577
+ version: row.version || null,
578
+ calls: 0,
579
+ errors: 0,
580
+ turnTokens: 0,
581
+ };
582
+ entry.calls += row.calls || 0;
583
+ entry.errors += row.errors || 0;
584
+ entry.turnTokens += row.turnTokens || 0;
585
+ gPlugin.set(key, entry);
586
+ }
511
587
  }
512
588
  const byCallsDesc = (a, b) => b.calls - a.calls;
513
589
 
@@ -527,6 +603,7 @@ export function allSessionsUsage({ limit = 1000 } = {}) {
527
603
  totalErrors: gToolErrors,
528
604
  byTool: Array.from(gTool.values()).sort(byCallsDesc),
529
605
  byMcpServer: Array.from(gServer.values()).sort(byCallsDesc),
606
+ byPlugin: Array.from(gPlugin.values()).sort(byCallsDesc),
530
607
  },
531
608
  },
532
609
  };
@@ -24,11 +24,14 @@ import { homedir } from "node:os";
24
24
  import { expandFileRefs } from "../runtime/file-ref-expander.js";
25
25
  import { projectRootBase } from "./project-root.cjs";
26
26
  import executionBroker from "./process-execution-broker/index.js";
27
+ import { collectPluginBinSandboxPolicy as collectDefaultPluginBinSandboxPolicy } from "./plugin-runtime/bin.js";
27
28
 
28
29
  const _deps = {
29
30
  fs: fsDefault,
30
31
  path: pathDefault,
31
32
  execSync: (...args) => executionBroker.execSync(...args),
33
+ collectPluginBinSandboxPolicy: (opts) =>
34
+ collectDefaultPluginBinSandboxPolicy(opts),
32
35
  };
33
36
 
34
37
  /**
@@ -186,8 +189,16 @@ export function substituteArgs(text, args = []) {
186
189
  return out;
187
190
  }
188
191
 
192
+ function isSandboxFailClosedError(error) {
193
+ return (
194
+ error?.sandboxFailClosed === true ||
195
+ (typeof error?.code === "string" &&
196
+ error.code.startsWith("ERR_PROCESS_SANDBOX"))
197
+ );
198
+ }
199
+
189
200
  /** Run every `!`cmd`` and replace it with the command's stdout (best-effort). */
190
- function runBangs(text, { cwd, execSync }) {
201
+ function runBangs(text, { cwd, execSync, sandboxPolicy }) {
191
202
  return text.replace(/!`([^`]+)`/g, (_, cmd) => {
192
203
  try {
193
204
  const out = execSync(cmd, {
@@ -199,9 +210,13 @@ function runBangs(text, { cwd, execSync }) {
199
210
  policy: "allow",
200
211
  scope: "slash-command",
201
212
  shell: true,
213
+ ...(sandboxPolicy ? { sandboxPolicy } : {}),
202
214
  });
203
215
  return String(out).trim();
204
216
  } catch (err) {
217
+ // Broker boundary failures are security decisions, not ordinary command
218
+ // failures. Preserve the exact structured error for the caller.
219
+ if (isSandboxFailClosedError(err)) throw err;
205
220
  return `[command failed: ${cmd} — ${err.message?.split("\n")[0] || err}]`;
206
221
  }
207
222
  });
@@ -215,18 +230,26 @@ function runBangs(text, { cwd, execSync }) {
215
230
  *
216
231
  * @param {object} command output of getCommand/parseCommandFile (needs .body)
217
232
  * @param {string[]} args
218
- * @param {object} [opts] { cwd, allowBang, deps:{ execSync } }
233
+ * @param {object} [opts] { cwd, allowBang,
234
+ * deps:{ execSync, collectPluginBinSandboxPolicy } }
219
235
  * @returns {{ prompt:string, warnings:string[] }}
220
236
  */
221
237
  export function expandCommand(command, args = [], opts = {}) {
222
238
  const cwd = opts.cwd || process.cwd();
223
239
  const execSync = opts.deps?.execSync || _deps.execSync;
240
+ const collectPluginBinSandboxPolicy =
241
+ opts.deps?.collectPluginBinSandboxPolicy ||
242
+ _deps.collectPluginBinSandboxPolicy;
224
243
  const warnings = [];
225
244
 
226
245
  let text = substituteArgs(command.body || "", args);
227
246
 
228
- if (opts.allowBang !== false) {
229
- text = runBangs(text, { cwd, execSync });
247
+ if (opts.allowBang !== false && /!`[^`]+`/.test(text)) {
248
+ // Resolve and pin once before the first bang. Every expansion in this macro
249
+ // receives the same immutable policy object, so no earlier command can run
250
+ // before a later discovery failure or observe a weaker boundary set.
251
+ const sandboxPolicy = collectPluginBinSandboxPolicy({ cwd });
252
+ text = runBangs(text, { cwd, execSync, sandboxPolicy });
230
253
  }
231
254
 
232
255
  // @file expansion appends a <referenced-files> block when anything resolves.
@@ -108,6 +108,7 @@ import {
108
108
  import { resolveSlashMacro } from "./slash-macro.js";
109
109
  import { expandMcpPrompt, renderMcpSurface } from "./mcp-prompt.js";
110
110
  import { newCostStore, addUsage } from "./session-cost.js";
111
+ import { extractPluginUsageAttribution } from "../lib/plugin-usage-attribution.js";
111
112
  import { parseThinkCommand, parseEffortCommand } from "./think-command.js";
112
113
  import { parseBtwCommand, buildAsideBlock, applyAside } from "./btw-command.js";
113
114
  import { shouldStreamLive } from "./stream-decision.js";
@@ -360,9 +361,9 @@ export async function agentLoop(messages, options) {
360
361
  );
361
362
  } else if (event.type === "tool-result") {
362
363
  // 用量归因: persist a compact tool_call record (name + error flag +
363
- // skill hint — never args, which can carry whole file bodies) so
364
- // `cc session usage --by tool|mcp` and `cc insights` can aggregate
365
- // tool use for REPL sessions. Best-effort; opt out with
364
+ // skill/plugin hints — never args, which can carry whole file bodies)
365
+ // so `cc session usage --by tool|mcp|plugin` and `cc insights` can
366
+ // aggregate tool use for REPL sessions. Best-effort; opt out with
366
367
  // options.persistToolCalls === false.
367
368
  if (options.sessionId && options.persistToolCalls !== false) {
368
369
  try {
@@ -373,6 +374,7 @@ export async function agentLoop(messages, options) {
373
374
  event.tool === "run_skill" && _lastExec?.tool === "run_skill"
374
375
  ? _lastExec.args?.skill_name
375
376
  : undefined,
377
+ ...extractPluginUsageAttribution(event.result),
376
378
  });
377
379
  } catch (_e) {
378
380
  // persistence is best-effort — never break the turn
@@ -915,8 +917,9 @@ export async function startAgentRepl(options = {}) {
915
917
  _pluginMonitors = null;
916
918
  }
917
919
 
918
- // Put trusted plugins' bin/ executables on PATH for the session (Phase 3.3n),
919
- // restored at SessionEnd. Trust-gated inside collectPluginBinDirs.
920
+ // Preserve PATH compatibility for trusted legacy bin components without a
921
+ // sandboxPolicy, restored at SessionEnd. Policy-bearing bins stay off PATH
922
+ // and use agent-core's exact direct Broker route.
920
923
  try {
921
924
  const { applyPluginBinPath } = await import("../lib/plugin-runtime/bin.js");
922
925
  const res = applyPluginBinPath({ cwd: process.cwd() });
@@ -1843,9 +1846,7 @@ export async function startAgentRepl(options = {}) {
1843
1846
  " Open this secure page? [y/N] ",
1844
1847
  ),
1845
1848
  async (answer) => {
1846
- const approved = /^(y|yes)$/i.test(
1847
- String(answer || "").trim(),
1848
- );
1849
+ const approved = /^(y|yes)$/i.test(String(answer || "").trim());
1849
1850
  if (!approved) {
1850
1851
  resolve({ action: "decline" });
1851
1852
  rl.prompt();
@@ -3876,7 +3877,7 @@ export async function startAgentRepl(options = {}) {
3876
3877
  /* monitor restart is best-effort */
3877
3878
  }
3878
3879
 
3879
- // Re-apply plugin bin PATH (a newly-trusted plugin's executables).
3880
+ // Re-apply legacy plugin bin PATH; strict bins remain direct-only.
3880
3881
  try {
3881
3882
  const { applyPluginBinPath } =
3882
3883
  await import("../lib/plugin-runtime/bin.js");