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
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  import { existsSync, mkdirSync, appendFileSync, readFileSync } from "node:fs";
12
- import { join } from "node:path";
12
+ import { join, resolve } from "node:path";
13
13
  import { createHash } from "node:crypto";
14
14
  import { EventEmitter } from "node:events";
15
15
  import { getHomeDir } from "../lib/paths.js";
@@ -42,9 +42,55 @@ const RECOVERABLE_TASK_STATUSES = new Set([
42
42
  TaskStatus.RUNNING,
43
43
  ]);
44
44
 
45
+ function validatePinnedSandboxPolicy(policy) {
46
+ if (policy == null) return null;
47
+ if (
48
+ typeof policy !== "object" ||
49
+ Array.isArray(policy) ||
50
+ typeof policy.then === "function" ||
51
+ !Array.isArray(policy.requiredBoundaries) ||
52
+ policy.requiredBoundaries.length === 0 ||
53
+ policy.requiredBoundaries.some(
54
+ (boundary) => typeof boundary !== "string" || boundary.length === 0,
55
+ ) ||
56
+ !Object.isFrozen(policy) ||
57
+ !Object.isFrozen(policy.requiredBoundaries)
58
+ ) {
59
+ const error = new TypeError("invalid_background_task_sandbox_policy");
60
+ error.code = "ERR_BACKGROUND_TASK_SANDBOX_POLICY_INVALID";
61
+ error.sandboxReason = "invalid_background_task_sandbox_policy";
62
+ error.sandboxFailClosed = true;
63
+ throw error;
64
+ }
65
+ return policy;
66
+ }
67
+
68
+ function createUnsupportedSandboxError(sandboxPolicy) {
69
+ const requiredBoundaries = [...sandboxPolicy.requiredBoundaries];
70
+ const error = new Error(
71
+ `Background tasks cannot run without their required sandbox boundaries: ${requiredBoundaries.join(", ")}`,
72
+ );
73
+ error.code = "ERR_BACKGROUND_TASK_SANDBOX_UNSUPPORTED";
74
+ error.sandboxReason = "background_execution_unsupported";
75
+ error.sandboxFailClosed = true;
76
+ error.requiredBoundaries = requiredBoundaries;
77
+ error.actualGuarantees = [];
78
+ error.missingBoundaries = [...requiredBoundaries];
79
+ error.sandboxBackend = null;
80
+ error.sandboxCandidateBackend = null;
81
+ return error;
82
+ }
83
+
45
84
  export class BackgroundTaskManager extends EventEmitter {
46
85
  constructor(options = {}) {
47
86
  super();
87
+ const resolveSandboxPolicy = options.resolveSandboxPolicy ?? null;
88
+ if (
89
+ resolveSandboxPolicy !== null &&
90
+ typeof resolveSandboxPolicy !== "function"
91
+ ) {
92
+ throw new TypeError("resolveSandboxPolicy must be a function or null");
93
+ }
48
94
  this.maxConcurrent = options.maxConcurrent || 3;
49
95
  this.heartbeatTimeout = options.heartbeatTimeout || 60000;
50
96
  this.historyLimit = options.historyLimit || 50;
@@ -54,6 +100,10 @@ export class BackgroundTaskManager extends EventEmitter {
54
100
  `${process.pid}@${process.platform}`;
55
101
  this.recoveryPolicy = options.recoveryPolicy || "claim-stale";
56
102
  this.staleNodeTimeout = options.staleNodeTimeout || 5 * 60 * 1000;
103
+ this._policyCwd = resolveSandboxPolicy
104
+ ? resolve(options.policyCwd || process.cwd())
105
+ : null;
106
+ this._resolveSandboxPolicy = resolveSandboxPolicy;
57
107
  this.tasks = new Map();
58
108
  this.processes = new Map();
59
109
  this._checkInterval = null;
@@ -72,12 +122,15 @@ export class BackgroundTaskManager extends EventEmitter {
72
122
  );
73
123
  }
74
124
 
125
+ const cwd = spec.cwd || process.cwd();
126
+ this._assertSandboxSupported(cwd);
127
+
75
128
  const id = `task-${Date.now()}-${createHash("sha256").update(Math.random().toString()).digest("hex").slice(0, 6)}`;
76
129
  const task = {
77
130
  id,
78
131
  type: spec.type || "shell",
79
132
  command: spec.command,
80
- cwd: spec.cwd || process.cwd(),
133
+ cwd,
81
134
  description: spec.description || spec.command,
82
135
  status: TaskStatus.PENDING,
83
136
  createdAt: Date.now(),
@@ -111,6 +164,8 @@ export class BackgroundTaskManager extends EventEmitter {
111
164
  throw new Error(`Task ${taskId} is not pending (status: ${task.status})`);
112
165
  }
113
166
 
167
+ this._assertSandboxSupported(task.cwd);
168
+
114
169
  task.status = TaskStatus.RUNNING;
115
170
  task.startedAt = Date.now();
116
171
  task.lastHeartbeat = Date.now();
@@ -185,6 +240,19 @@ export class BackgroundTaskManager extends EventEmitter {
185
240
  return task;
186
241
  }
187
242
 
243
+ _assertSandboxSupported(executionCwd) {
244
+ if (!this._resolveSandboxPolicy) return;
245
+ const sandboxPolicy = validatePinnedSandboxPolicy(
246
+ this._resolveSandboxPolicy({
247
+ workspaceCwd: this._policyCwd,
248
+ executionCwd,
249
+ }),
250
+ );
251
+ if (sandboxPolicy) {
252
+ throw createUnsupportedSandboxError(sandboxPolicy);
253
+ }
254
+ }
255
+
188
256
  get(taskId) {
189
257
  return this.tasks.get(taskId) || null;
190
258
  }
@@ -164,20 +164,22 @@ export function appendToolCall(sessionId, toolName, args) {
164
164
 
165
165
  /**
166
166
  * Compact tool-call record for usage attribution (用量归因): tool name +
167
- * error flag (+ an optional skill hint for `run_skill`) — deliberately NOT
167
+ * error flag (+ optional skill and plugin/version hints) — deliberately NOT
168
168
  * the args, which can carry whole file bodies (write_file content) and would
169
169
  * bloat the transcript. Written at tool-result time by the agent drivers so
170
- * `cc session usage --by tool|mcp` and `cc insights` can aggregate tool use
171
- * for any persisted session.
170
+ * `cc session usage --by tool|mcp|plugin` and `cc insights` can aggregate tool
171
+ * use for any persisted session.
172
172
  */
173
173
  export function appendToolCallCompact(
174
174
  sessionId,
175
- { tool, isError, skill } = {},
175
+ { tool, isError, skill, plugin, pluginVersion } = {},
176
176
  ) {
177
177
  appendEvent(sessionId, "tool_call", {
178
178
  tool: tool || "?",
179
179
  is_error: Boolean(isError),
180
180
  ...(skill ? { skill: String(skill) } : {}),
181
+ ...(plugin ? { plugin: String(plugin) } : {}),
182
+ ...(pluginVersion ? { plugin_version: String(pluginVersion) } : {}),
181
183
  });
182
184
  }
183
185
 
@@ -456,7 +456,11 @@ export function previewWorktreeMerge(repoDir, branchName, options = {}) {
456
456
 
457
457
  let mergeStarted = false;
458
458
  try {
459
- gitExec(`merge ${baseBranch} --no-commit --no-ff`, worktree.path);
459
+ // Use argv form here rather than routing through a shell. Besides avoiding
460
+ // another quoting surface, this is important on Windows where a conflicted
461
+ // `git merge` followed immediately by another shell-wrapped git process can
462
+ // race the hosted runner's process/job cleanup and hide the unmerged index.
463
+ gitExecArgs(["merge", baseBranch, "--no-commit", "--no-ff"], worktree.path);
460
464
  mergeStarted = true;
461
465
 
462
466
  return {
@@ -713,7 +717,14 @@ function _hasBranchCommits(repoDir, branchName) {
713
717
 
714
718
  function _collectConflictFiles(repoDir) {
715
719
  try {
716
- const output = gitExec("diff --name-only --diff-filter=U", repoDir);
720
+ // A conflict is expected to make the preceding merge exit non-zero. Query
721
+ // the index with a direct git argv invocation so Windows shell/process
722
+ // teardown cannot turn the authoritative conflict probe into an empty
723
+ // best-effort result.
724
+ const output = gitExecArgs(
725
+ ["diff", "--name-only", "--diff-filter=U"],
726
+ repoDir,
727
+ );
717
728
  return output
718
729
  .split("\n")
719
730
  .map((line) => line.trim())
@@ -988,7 +999,7 @@ function _resolveAutomationCandidate(type, filePath, branchName, candidateId) {
988
999
 
989
1000
  function _abortMergeIfPresent(repoDir) {
990
1001
  try {
991
- gitExec("merge --abort", repoDir);
1002
+ gitExecArgs(["merge", "--abort"], repoDir);
992
1003
  } catch (_e) {
993
1004
  // Ignore if there is no in-progress merge.
994
1005
  }
@@ -12,6 +12,7 @@ export {
12
12
  getAgentToolDefinitions,
13
13
  getAgentToolDescriptors,
14
14
  getCachedPython,
15
+ _resetCachedPythonForTests,
15
16
  getEnvironmentInfo,
16
17
  _environmentProcessDeps,
17
18
  _agentToolProcessDeps,
@@ -48,6 +48,14 @@ function normalizeJitterMs(v) {
48
48
  return Number.isFinite(n) && n > 0 ? n : 0;
49
49
  }
50
50
 
51
+ function normalizeMonitorWorkspaceCwd(value) {
52
+ if (value == null) return null;
53
+ if (typeof value !== "string" || value.length === 0) {
54
+ throw new Error("monitor workspaceCwd must be a non-empty string");
55
+ }
56
+ return path.resolve(value);
57
+ }
58
+
51
59
  /**
52
60
  * A per-task execution policy for wakeup/cron entries — how the spawned
53
61
  * `cc agent` run should behave when this entry fires. Each field maps to a real
@@ -388,6 +396,7 @@ export class AgentScheduleStore {
388
396
 
389
397
  createMonitor({
390
398
  command,
399
+ workspaceCwd = null,
391
400
  watchFile = null,
392
401
  watchUrl = null,
393
402
  watchChange = false,
@@ -443,16 +452,22 @@ export class AgentScheduleStore {
443
452
  if (stopWhen != null) {
444
453
  // Validate the regex up-front so a bad pattern errors at creation, not
445
454
  // silently at the first check.
446
- // eslint-disable-next-line no-new
455
+
447
456
  new RegExp(stopWhen);
448
457
  }
449
458
  const now = this._now();
450
459
  const source = hasFile ? "file" : hasUrl ? "http" : "command";
460
+ const normalizedWorkspaceCwd = hasCommand
461
+ ? normalizeMonitorWorkspaceCwd(workspaceCwd)
462
+ : null;
451
463
  const entry = {
452
464
  id: randomUUID(),
453
465
  kind: "monitor",
454
466
  source,
455
467
  command: hasCommand ? command : null,
468
+ ...(normalizedWorkspaceCwd
469
+ ? { workspaceCwd: normalizedWorkspaceCwd }
470
+ : {}),
456
471
  watchFile: hasFile ? watchFile : null,
457
472
  watchUrl: hasUrl ? watchUrl : null,
458
473
  watchChange: hasFile ? Boolean(watchChange) : false,
@@ -513,28 +528,36 @@ export class AgentScheduleStore {
513
528
  const now = atMs != null ? Number(atMs) : this._now();
514
529
  const ttl = Math.max(1000, Number(leaseMs) || 120000);
515
530
  this._ensureDir();
516
- return withFileLock(path.join(this.dir, ".agenda-claims"), () => {
517
- const claimed = [];
518
- for (const kind of SCHEDULE_KINDS) {
519
- const entries = this._readAll(kind);
520
- let changed = false;
521
- for (const entry of entries) {
522
- if (!isSchedulableStatus(entry) || isEntryExpired(entry, now)) continue;
523
- if (hasLiveExecutionLease(entry, now)) continue;
524
- const fireAt = effectiveFireAt(entry);
525
- if (fireAt == null || fireAt > now) continue;
526
- entry.executionLease = {
527
- owner: `${process.pid}:${randomUUID()}`,
528
- claimedAt: now,
529
- expiresAt: now + ttl,
530
- };
531
- claimed.push({ ...entry, executionLease: { ...entry.executionLease } });
532
- changed = true;
531
+ return withFileLock(
532
+ path.join(this.dir, ".agenda-claims"),
533
+ () => {
534
+ const claimed = [];
535
+ for (const kind of SCHEDULE_KINDS) {
536
+ const entries = this._readAll(kind);
537
+ let changed = false;
538
+ for (const entry of entries) {
539
+ if (!isSchedulableStatus(entry) || isEntryExpired(entry, now))
540
+ continue;
541
+ if (hasLiveExecutionLease(entry, now)) continue;
542
+ const fireAt = effectiveFireAt(entry);
543
+ if (fireAt == null || fireAt > now) continue;
544
+ entry.executionLease = {
545
+ owner: `${process.pid}:${randomUUID()}`,
546
+ claimedAt: now,
547
+ expiresAt: now + ttl,
548
+ };
549
+ claimed.push({
550
+ ...entry,
551
+ executionLease: { ...entry.executionLease },
552
+ });
553
+ changed = true;
554
+ }
555
+ if (changed) this._writeAll(kind, entries);
533
556
  }
534
- if (changed) this._writeAll(kind, entries);
535
- }
536
- return claimed;
537
- }, { failIfUnavailable: true });
557
+ return claimed;
558
+ },
559
+ { failIfUnavailable: true },
560
+ );
538
561
  }
539
562
 
540
563
  /** Release a failed/aborted claim so a later runner can retry it. */
@@ -51,6 +51,10 @@ export class TeamRunner {
51
51
  this._executions = 0;
52
52
  this._inFlight = 0;
53
53
  this._maxInFlight = 0;
54
+ // Keys executing in this runner process. An event-loop stall may let a
55
+ // short lease expire before its heartbeat callback runs; peer loops in the
56
+ // same process must not steal and double-run that still-active task.
57
+ this._activeKeys = new Set();
54
58
  this._members = new Map(); // holder → lifecycle record
55
59
  this._budgetStopped = false;
56
60
  }
@@ -208,6 +212,7 @@ export class TeamRunner {
208
212
  let best = null;
209
213
  let bestScore = Infinity;
210
214
  for (const key of claimable) {
215
+ if (this._activeKeys.has(key)) continue;
211
216
  const t = this.registry.getTask(key);
212
217
  const score = rank[t?.priority] ?? 1;
213
218
  if (score < bestScore) {
@@ -222,10 +227,22 @@ export class TeamRunner {
222
227
  const task = this.registry.getTask(key);
223
228
  this._executions++;
224
229
  this._inFlight++;
230
+ this._activeKeys.add(key);
225
231
  this._maxInFlight = Math.max(this._maxInFlight, this._inFlight);
226
232
  this._setState(holder, "running", { key });
227
233
  this._emit("task:claimed", { key, holder, attempts: task.attempts });
228
- const renew = () => this.registry.renew(key, { holder, ttlMs: this.ttlMs });
234
+ const renew = () => {
235
+ const result = this.registry.renew(key, {
236
+ holder,
237
+ ttlMs: this.ttlMs,
238
+ });
239
+ // A delayed timer may wake just after expiry. Reacquire is safe and
240
+ // optimistic: it succeeds only if no external runner has taken the
241
+ // lease; a real takeover remains authoritative and stops the heartbeat.
242
+ return !result?.ok && result?.reason === "not_holder_or_expired"
243
+ ? this.registry.acquire(key, { holder, ttlMs: this.ttlMs })
244
+ : result;
245
+ };
229
246
  // Heartbeat: the built-in executors (shell / agent / worktree) never call
230
247
  // `renew` themselves, so before this ANY task outliving the lease TTL was
231
248
  // indistinguishable from a crash — a peer could steal it and the SAME task
@@ -338,6 +355,7 @@ export class TeamRunner {
338
355
  });
339
356
  } finally {
340
357
  clearInterval(heartbeat);
358
+ this._activeKeys.delete(key);
341
359
  this._inFlight--;
342
360
  }
343
361
  }
@@ -762,6 +762,47 @@ export function normalizeBackgroundWorktree(worktree, cwd) {
762
762
  return normalized;
763
763
  }
764
764
 
765
+ /**
766
+ * Persist only the bounded, secret-free governance envelope needed by IDE task
767
+ * rows. The supervisor owns `owner`; callers cannot forge it. Prompt text,
768
+ * argv, credentials and tool arguments are deliberately excluded.
769
+ */
770
+ export function normalizeBackgroundGovernance(
771
+ governance,
772
+ { id, sessionId } = {},
773
+ ) {
774
+ const source = governance && typeof governance === "object" ? governance : {};
775
+ const budget =
776
+ source.resourceBudget && typeof source.resourceBudget === "object"
777
+ ? source.resourceBudget
778
+ : {};
779
+ const positive = (value) => {
780
+ const n = Number(value);
781
+ return Number.isFinite(n) && n > 0 ? n : null;
782
+ };
783
+ const permissionMode = new Set([
784
+ "manual",
785
+ "auto",
786
+ "dontAsk",
787
+ "default",
788
+ "plan",
789
+ "acceptEdits",
790
+ "bypassPermissions",
791
+ ]).has(source.permissionMode)
792
+ ? source.permissionMode
793
+ : "default";
794
+ return {
795
+ version: 1,
796
+ owner: `background:${String(id || "").slice(0, 160)}`,
797
+ sessionId: sessionId ? String(sessionId).slice(0, 256) : null,
798
+ permissionMode,
799
+ resourceBudget: {
800
+ maxTurns: positive(budget.maxTurns),
801
+ maxCostUsd: positive(budget.maxCostUsd),
802
+ },
803
+ };
804
+ }
805
+
765
806
  function persistedWorktree(state) {
766
807
  if (!state?.worktreePath) return null;
767
808
  return {
@@ -817,6 +858,7 @@ export function resumeBackgroundAgent(id, prompt, options = {}) {
817
858
  cliEntry: options.cliEntry,
818
859
  followUpArgv: ["agent", "--session", state.sessionId],
819
860
  worktree,
861
+ governance: state.governance,
820
862
  });
821
863
  }
822
864
 
@@ -855,10 +897,15 @@ export function launchBackgroundAgent({
855
897
  cliEntry,
856
898
  followUpArgv,
857
899
  worktree,
900
+ governance,
858
901
  }) {
859
902
  assertUsableCwd(cwd);
860
903
  const worktreeState = normalizeBackgroundWorktree(worktree, cwd);
861
904
  const id = createBackgroundAgentId();
905
+ const governanceState = normalizeBackgroundGovernance(governance, {
906
+ id,
907
+ sessionId,
908
+ });
862
909
  const dir = backgroundAgentsDir();
863
910
  const jobFile = join(dir, `${id}.job.${process.pid}.json`);
864
911
  const worker = fileURLToPath(
@@ -873,6 +920,7 @@ export function launchBackgroundAgent({
873
920
  cliEntry: cliEntry || process.argv[1],
874
921
  logFile: logPath(id),
875
922
  ...(worktreeState || {}),
923
+ governance: governanceState,
876
924
  // Present = interactive attach can start follow-up turns; absent = the
877
925
  // transport rejects prompts (log-only session).
878
926
  ...(Array.isArray(followUpArgv) ? { followUpArgv } : {}),
@@ -897,6 +945,7 @@ export function launchBackgroundAgent({
897
945
  exitCode: null,
898
946
  logFile: job.logFile,
899
947
  ...(worktreeState || {}),
948
+ governance: governanceState,
900
949
  };
901
950
  writeBackgroundAgentState(state);
902
951
  let child;
@@ -35,8 +35,12 @@ function runHookProcessSync(file, argsOrOptions, maybeOptions) {
35
35
  });
36
36
  }
37
37
 
38
- runner._deps.run = runHookProcess;
39
- runner._deps.runSync = runHookProcessSync;
38
+ export function _restoreProcessRunners() {
39
+ runner._deps.run = runHookProcess;
40
+ runner._deps.runSync = runHookProcessSync;
41
+ }
42
+
43
+ _restoreProcessRunners();
40
44
 
41
45
  export const {
42
46
  runCommandHook,
@@ -385,7 +385,9 @@ export function generatePkgConfig(ctx) {
385
385
  const assets = [
386
386
  `${posixify(distDir)}/**/*`,
387
387
  `${posixify(templatesDir)}/**/*`,
388
- `${posixify(cliRoot)}/src/lib/process-execution-broker/*.ps1`,
388
+ `${posixify(cliRoot)}/src/lib/process-execution-broker/windows-sandbox-helper.dll`,
389
+ `${posixify(cliRoot)}/src/lib/process-execution-broker/windows-sandbox-helper.exe`,
390
+ `${posixify(cliRoot)}/src/lib/process-execution-broker/windows-sandbox.cs`,
389
391
  ];
390
392
  if (prebuildsDir) assets.push(`${posixify(prebuildsDir)}/**/*`);
391
393
  // Project mode: bundle the collected .chainlesschain/ snapshot as an asset.