chainlesschain 0.163.2 → 0.163.3

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 (185) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-DnGsmsqJ.js → AIOps-DIY6KxV-.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-CrO6fcQ7.js → ActionButton-BXH0muPt.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-DsBdOaP2.js → Analytics-D39w8vmg.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-DmQslKUB.js → AppLayout-CUU1zvLs.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-BvyrT_QQ.js → Artifacts-D8azHO3T.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-prndoLiC.js → Audit-D0tAwXTg.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-DOTFyA55.js → BackgroundAgents-C29mhJll.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-9zOnPp_8.js → Backup-D6Aa1Gro.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-C4PC6sAG.js → BaseInput-B1uoHbPQ.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-BBAF-W9v.js → Chat-Bs4DLOR5.js} +6 -6
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CWhvvloO.js → ChatBubbleRenderer-DUYIBSle.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-BI9iculd.js → Checkbox-CNcBPEa4.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-3DP9BCKb.js → Codegen-CIY89763.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-df-2TnJX.js → Col-CsPYFmgo.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-CHs8gG_A.js → Community-BBocEge4.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-CDfF6q7V.js → Compact-TQ8Ux0Lf.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-CthrDnO7.js → Compliance-DfBsZTft.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-HjIqsWJw.js → Cowork-Cg-I6FVH.js} +2 -2
  20. package/src/assets/web-panel/assets/{Cron-BKc196fb.js → Cron-DTQzfRTp.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-CJnjdc8W.js → Crosschain-DGxEKGpR.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-BHUy-8Q2.js → DID-DLZ1RDSr.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-QDB7sKeY.js → Dashboard-XneICKNI.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-DStcVK11.js → Dropdown-BRU00J1-.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-BwSUskMJ.js → EmailListRenderer-BzCbJuAy.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DgF_kurT.js → FamilyGuardDashboard-D7BRyNBG.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-k8wvv-wN.js → Federation-D9DeFIhW.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-C11qoq2r.js → FormItemContext-6rAtA9Ko.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-BIIpr9kg.js → GenericCardRenderer-8Hqy80pU.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-BlA1exTe.js → Git-Cmvkj1rt.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-CYa1ZYM4.js → Governance-BRiQUjjw.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-6_kKVIt6.js → Inference-CKN_EzVf.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-CB4AwxYy.js → KnowledgeGraph-BCDHwpwQ.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-xf7nHFAe.js → Logs-DK9ovhaB.js} +2 -2
  35. package/src/assets/web-panel/assets/MarkdownRenderer-D53pHiHy.js +1 -0
  36. package/src/assets/web-panel/assets/{Marketplace-aPg8e4Jt.js → Marketplace-BILPGakp.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-C-TNlVUf.js → McpTools-DTVCOr9-.js} +5 -5
  38. package/src/assets/web-panel/assets/{Memory-DMTPIpGa.js → Memory-Hzc1iow4.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-BxyvveRq.js → MobileBridge-GXfgnGYV.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-DyPCrAyQ.js → MobileProjects-B-3TJWsS.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-BdhqNXp6.js → Mtc-DwSJMWtK.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-Cz-HFxzW.js → MtcAudit-D2uxf-DA.js} +5 -5
  43. package/src/assets/web-panel/assets/{Multisig-CIUaFNsx.js → Multisig-DG6kbKK0.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-CWe6-J17.js → NLProgramming-f5p49EDU.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-vYAKeviU.js → Notes-FUgHyzSD.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-DQL9-2d7.js → NotificationSettings-DCHGee7e.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-DnXj1jBn.js → OrderTableRenderer-Dm6LlIoa.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-B3spU8AN.js → Organization-BawA7qAg.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-DgEwo7vm.js → Overflow-D6a5wZU1.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-hujMRH8X.js → P2P-K8WavwnA.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-C_qhdg9h.js → PdhVaultBrowser-4JAJYaqx.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-vp7LMcSf.js → Permissions-BDWvi8PD.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-Dxr5Hgnq.js → PersonalDataHub-DF_K4E9i.js} +3 -3
  54. package/src/assets/web-panel/assets/{Pipeline-DEPZqqH4.js → Pipeline-BYeZlesI.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-DTpDiKPe.js → Privacy-BIHlgnIc.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-jDJsRWmF.js → ProjectInit-Cvf-6B5P.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-Dhor5RWH.js → ProjectSettings-CnwfJrRz.js} +2 -2
  58. package/src/assets/web-panel/assets/Projects-b-jPXzF4.js +1 -0
  59. package/src/assets/web-panel/assets/{Providers-BGs47s1a.js → Providers-CxC7JuYv.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-CjIw-wIb.js → QrScannerModal-VLf3gAfL.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-DX6jcqoi.js → QuickAsk-B5vGjRiF.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-DopXkhar.js → Recommend--UW4iYs-.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-BLvqJE9c.js → RemoteSession-DMSPcfKR.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-DhRj2Me7.js → Reputation-kQXlEHmj.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-DQ53vuPq.js → Row-CxGu3pit.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-BslvwiBD.js → RssFeed-Bi5lo8MZ.js} +2 -2
  67. package/src/assets/web-panel/assets/{Search-DJKBDNKZ.js → Search-Cq_H5RTh.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-COhpxHER.js → Security-YFbmkaQS.js} +3 -3
  69. package/src/assets/web-panel/assets/{Services-dbulD6cI.js → Services-DLOGdaLm.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-ciIVNfhC.js → Skeleton-CteIxb3D.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-AiRTkTCk.js → Skills-CccopaIZ.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-DDMcWYBc.js → Sla-AzfEQKX1.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-BPxWbpXO.js → SpeechSettings-ekGo5l77.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-BoEOXCyg.js → SyncSettings-BmZmAgYH.js} +2 -2
  75. package/src/assets/web-panel/assets/Tasks-D7q3Z4uL.js +1 -0
  76. package/src/assets/web-panel/assets/{Templates-UowY8Ixe.js → Templates-CX1Tgeka.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-DauSLQXN.js → Tenant-Zc59jF4i.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-DBj7Jneq.js → Terminal-CXOD7y83.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-UMrPwoZC.js → TimelineRenderer-B1aBHPBo.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-4ea96-bn.js → Tokens-zALlOq_U.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger--ISCqt4b.js → Trigger-CQfJMXaq.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-D4GVimRJ.js → Trust-BU0RcM-w.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-Ci-nXRQc.js → UkeySign-IFZ3HsbH.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-Cjk7mKPw.js → VideoEditing-BzslgW0v.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-BgOLOO3Z.js → Wallet-BZAcQNS6.js} +2 -2
  86. package/src/assets/web-panel/assets/{WebAuthn-CCX0K29i.js → WebAuthn-CBK1DMi0.js} +4 -4
  87. package/src/assets/web-panel/assets/{WorkflowEditor-Ch3zgIsE.js → WorkflowEditor-BlMTPzO-.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-DKOU_2Vb.js → chat-B51-8QVn.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-6OVo4u3C.js → colors-504RTByU.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-BH78Hlsq.js → compact-item-C-GP6IQM.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-CFRpSbbC.js → createContext-DOkIj7ID.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-kB0nCNwN.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-DNQhgcVi.js → hasIn-DN7V-_FW.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-dDkoL4Pe.js → index--n-ZciV3.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-CaYqY35Z.js → index-7jIqHbzw.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BYrnm5Ob.js → index-B2-x9bS8.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-sm7W8AXy.js → index-BFIFJ5Dr.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-DKN2noIF.js → index-B_vGU-Js.js} +1 -1
  99. package/src/assets/web-panel/assets/{index--rq90rL9.js → index-Bkxhaeta.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CFPJ8yzF.js → index-By6u5IV1.js} +1 -1
  101. package/src/assets/web-panel/assets/index-Bya64sZE.js +1 -0
  102. package/src/assets/web-panel/assets/{index-caye7AOE.js → index-C0k_Nqg9.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BxRy5LPR.js → index-C3TSohzc.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BepBTpa8.js → index-C4DV_5uA.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-D84id2Y4.js → index-C8UltbXK.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Y9MJv28e.js → index-C9_48OzU.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Bb6kDrUx.js → index-CKTfZyfU.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CrcLHN2F.js → index-CP2A226L.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CkNEMANR.js → index-CUhQpiYv.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Cu3L4r5l.js → index-CX78k-qf.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DaDgdJYj.js → index-CYopNjcJ.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Du0rnksC.js → index-Cao5DZy7.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BaVE6E8y.js → index-CfiEM64n.js} +3 -3
  114. package/src/assets/web-panel/assets/{index-BujsOZfc.js → index-ConjaJro.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-hPY0fFrd.js → index-CqcLo5WV.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BDSR7ecX.js → index-CySTJKeq.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BHa4WyTZ.js → index-D1phyca8.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-nbfHl1oV.js → index-D9LyiN-L.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CkqHgG-b.js → index-DA2f1UV3.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Eag8e_mA.js → index-DAOpQvl_.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-cdf7fd7d.js → index-DE-hmI2l.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-bKm3TUDp.js → index-DEMPUVa3.js} +1 -1
  123. package/src/assets/web-panel/assets/index-D_FWpDZM.js +1 -0
  124. package/src/assets/web-panel/assets/{index-7TC3S8SN.js → index-DaA__-q1.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DvHGtNnF.js → index-FcV8J_Qz.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-B_Z-YoxX.js → index-P2mfY27Z.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-AuBhLqOm.js → index-et5JIPHO.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-D3RtTT4K.js → index-f4Bo4KXm.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-CNuCHHQT.js → index-kAqQXfP6.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BkN3iTTp.js → index-kt_5rfcZ.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BnnXQot_.js → index-so8eIIxF.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-HNGGVF6o.js → index-yYTQZypF.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-BZ9w6jPL.js → initDefaultProps-CPYEIdpV.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-BnwUiOho.js → motion-Cjim9pxs.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-ByUKJnNm.js → move-DuU-cgz3.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-V7yK1KEl.js → mtc-parser-DJHNAkta.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-BEXBBt4j.js → omit-DSQBgdBj.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-qDm_46Gi.js → pickAttrs-CTmT_j5m.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-BIbhEo_0.js → placementArrow-Lfm6v-r4.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-NbPbDgA_.js → responsiveObserve-CgrcPcDi.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-BnUWglZ0.js → slide-CuE3110i.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-BX8_wZI5.js → statusUtils-DiK5nbpf.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-BV4OycQX.js → styleChecker-DPEJdQaZ.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-Od_H5llY.js → useFlexGapSupport-CnnodGmp.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-BWI-PyiX.js → useFs-DWF84Yav.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-BqMuhG3g.js → usePersonalDataHub-a5b5Dw2f.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-DNd23z6f.js → vnode-DAluzXOq.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-Cjaxnm7l.js → zoom-Dokg7uAZ.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-help-index.json +1 -1
  151. package/src/commands/agenda.js +6 -5
  152. package/src/commands/agent.js +237 -75
  153. package/src/commands/agents.js +6 -0
  154. package/src/commands/background-session.js +11 -1
  155. package/src/commands/mcp.js +217 -30
  156. package/src/data/changelog.json +14 -1
  157. package/src/harness/mcp-client.js +242 -42
  158. package/src/harness/worktree-isolator.js +26 -3
  159. package/src/lib/agent-worktree.js +41 -2
  160. package/src/lib/background-agent-supervisor.js +790 -186
  161. package/src/lib/background-command-argv.js +318 -0
  162. package/src/lib/background-launch-profile.js +1 -0
  163. package/src/lib/background-phase-reporter.js +22 -2
  164. package/src/lib/background-worktree-policy.js +109 -0
  165. package/src/lib/cowork-mcp-tools.js +51 -6
  166. package/src/lib/cowork-task-runner.js +1 -0
  167. package/src/lib/mcp-headers-helper.js +76 -8
  168. package/src/lib/mcp-sandbox-policy.js +155 -0
  169. package/src/lib/mcp-stdio-execution-authority.js +163 -0
  170. package/src/lib/mcp-stdio-workspace-authority.js +252 -0
  171. package/src/lib/plugin-runtime/sandbox-policy.js +42 -2
  172. package/src/lib/process-execution-broker/index.js +179 -104
  173. package/src/lib/process-execution-broker/platform-sandbox.js +942 -168
  174. package/src/lib/process-tree-termination.js +17 -1
  175. package/src/lib/skill-mcp.js +65 -4
  176. package/src/lib/web-fetch.js +4 -4
  177. package/src/runtime/agent-runtime.js +61 -8
  178. package/src/runtime/mcp-config.js +235 -28
  179. package/src/workers/background-agent-worker.js +492 -71
  180. package/src/assets/web-panel/assets/MarkdownRenderer-Bf3DEqP6.js +0 -1
  181. package/src/assets/web-panel/assets/Projects-08xUDZGt.js +0 -1
  182. package/src/assets/web-panel/assets/Tasks-CEYFJwmr.js +0 -1
  183. package/src/assets/web-panel/assets/devWarning-DEMblAIm.js +0 -1
  184. package/src/assets/web-panel/assets/index-BTvq-36D.js +0 -1
  185. package/src/assets/web-panel/assets/index-hUpvk6Jl.js +0 -1
@@ -22,24 +22,89 @@ import {
22
22
  enforceSandboxFailClosed,
23
23
  } from "../lib/agent-sandbox.js";
24
24
  import { appendSecurityAuditEvent } from "../lib/security-audit.js";
25
+ import {
26
+ agentPrintArgument,
27
+ canonicalizeBackgroundSessionArgv,
28
+ captureCommandArgvGrammar,
29
+ transformBackgroundLaunchArgv,
30
+ } from "../lib/background-command-argv.js";
25
31
 
26
32
  /**
27
33
  * Resolve + validate `--add-dir` values into absolute, existing, de-duped
28
- * directories. Invalid entries are skipped with a stderr warning rather than
29
- * aborting the run. Relative paths resolve against the process cwd.
34
+ * directories. Relative paths resolve against the invocation cwd. When the
35
+ * session owns a worktree, paths inside the original repository are remapped
36
+ * to the same repo-relative location in that worktree; explicit external roots
37
+ * remain shared and can be surfaced with a warning.
30
38
  *
31
39
  * @param {string[]} [rawDirs]
40
+ * @param {{cwd?:string, worktree?:object|null, warnOnExternalShare?:boolean}} [options]
32
41
  * @returns {string[]} absolute directory paths
33
42
  */
34
- export function resolveAddDirs(rawDirs) {
43
+ export function resolveAddDirs(rawDirs, options = {}) {
44
+ const cwd = options.cwd || process.cwd();
45
+ const worktree = options.worktree || null;
46
+ const realpath = fs.realpathSync.native || fs.realpathSync;
47
+ const within = (root, candidate) => {
48
+ const relative = path.relative(root, candidate);
49
+ return (
50
+ relative === "" ||
51
+ (relative !== ".." &&
52
+ !relative.startsWith(`..${path.sep}`) &&
53
+ !path.isAbsolute(relative))
54
+ );
55
+ };
56
+ let worktreeScope = null;
57
+ if (worktree) {
58
+ try {
59
+ worktreeScope = {
60
+ repoRoot: realpath(worktree.repoRoot),
61
+ path: realpath(worktree.path),
62
+ };
63
+ } catch (error) {
64
+ throw new Error(
65
+ `--add-dir: background worktree identity is unavailable (${error.message})`,
66
+ );
67
+ }
68
+ }
35
69
  const out = [];
70
+ const seen = new Set();
36
71
  for (const d of rawDirs || []) {
37
- const abs = path.resolve(process.cwd(), d);
72
+ const abs = path.resolve(cwd, d);
38
73
  try {
39
- if (fs.existsSync(abs) && fs.statSync(abs).isDirectory()) {
40
- if (!out.includes(abs)) out.push(abs);
41
- } else {
74
+ if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) {
42
75
  process.stderr.write(`--add-dir: skipping non-directory "${d}"\n`);
76
+ continue;
77
+ }
78
+ let target = realpath(abs);
79
+ let sharedExternal = false;
80
+ if (worktreeScope) {
81
+ const sourceReal = target;
82
+ if (within(worktreeScope.repoRoot, sourceReal)) {
83
+ const relative = path.relative(worktreeScope.repoRoot, sourceReal);
84
+ const mapped = path.resolve(worktree.path, relative);
85
+ if (!fs.existsSync(mapped) || !fs.statSync(mapped).isDirectory()) {
86
+ process.stderr.write(
87
+ `--add-dir: skipping "${d}" because its isolated worktree path does not exist\n`,
88
+ );
89
+ continue;
90
+ }
91
+ const mappedReal = realpath(mapped);
92
+ target = mappedReal;
93
+ sharedExternal = !within(worktreeScope.path, mappedReal);
94
+ } else {
95
+ sharedExternal = true;
96
+ }
97
+ }
98
+ if (sharedExternal && options.warnOnExternalShare) {
99
+ process.stderr.write(
100
+ `warning: --add-dir "${d}" remains a shared external root outside the background worktree.\n`,
101
+ );
102
+ }
103
+ const identity =
104
+ process.platform === "win32" ? target.toLowerCase() : target;
105
+ if (!seen.has(identity)) {
106
+ seen.add(identity);
107
+ out.push(target);
43
108
  }
44
109
  } catch {
45
110
  process.stderr.write(`--add-dir: skipping unreadable "${d}"\n`);
@@ -220,6 +285,10 @@ export function registerAgentCommand(program) {
220
285
  "--worktree",
221
286
  "Run this session in a fresh git worktree (isolated branch; auto-removed when the session changes nothing)",
222
287
  )
288
+ .option(
289
+ "--no-worktree",
290
+ "Background Git task: explicitly share the current work tree (intended for read-only tasks; writable runs are not isolated)",
291
+ )
223
292
  .option(
224
293
  "--unattended",
225
294
  "Enable fail-closed shell action policy for scheduled/event-driven runs",
@@ -554,6 +623,43 @@ export function registerAgentCommand(program) {
554
623
  if (options.projectMcp === true) {
555
624
  process.env.CC_PROJECT_MCP = "1";
556
625
  }
626
+ const backgroundRequested =
627
+ options.background === true || options.bg === true;
628
+ const invocationCwd = process.cwd();
629
+ let worktreeDecision = {
630
+ enabled: false,
631
+ source: "foreground-default",
632
+ reason: "worktree not requested",
633
+ repoRoot: null,
634
+ };
635
+ if (options.worktree !== undefined || backgroundRequested) {
636
+ try {
637
+ const { resolveBackgroundWorktreePolicy } =
638
+ await import("../lib/background-worktree-policy.js");
639
+ worktreeDecision = resolveBackgroundWorktreePolicy({
640
+ background: backgroundRequested,
641
+ worktree: options.worktree,
642
+ inputFormat: options.inputFormat,
643
+ permissionMode: options.permissionMode,
644
+ cwd: invocationCwd,
645
+ });
646
+ } catch (error) {
647
+ process.stderr.write(
648
+ `background worktree policy failed: ${error.message}\n`,
649
+ );
650
+ process.exit(1);
651
+ return;
652
+ }
653
+ }
654
+ if (
655
+ backgroundRequested &&
656
+ worktreeDecision.source === "explicit-disable" &&
657
+ String(options.inputFormat || "text").toLowerCase() !== "stream-json"
658
+ ) {
659
+ process.stderr.write(
660
+ "warning: --no-worktree shares the current work tree with a background agent; worktree isolation is disabled.\n",
661
+ );
662
+ }
557
663
  // --worktree (Claude-Code 2.1.171 parity): run THIS session in a fresh
558
664
  // git worktree — edits land on an isolated branch, the main working
559
665
  // tree (and parallel sessions) stay untouched. chdir BEFORE everything
@@ -567,19 +673,39 @@ export function registerAgentCommand(program) {
567
673
  // _finishWorktree(). Null unless --worktree is active + hooks loaded.
568
674
  let _worktreeSettingsHooks = null;
569
675
  let _worktreeAsyncSupervisor = null;
570
- if (options.worktree) {
676
+ const _finishWorktreeSync = () => {
677
+ if (!_worktree || _worktreeFinished || _worktreeTransferred) {
678
+ return null;
679
+ }
680
+ _worktreeFinished = true;
681
+ try {
682
+ process.chdir(_worktree.repoRoot); // release the dir before removal
683
+ return _finishAgentWorktreeFn(_worktree);
684
+ } catch {
685
+ return null; // keep silently — never block exit/error reporting
686
+ }
687
+ };
688
+ if (worktreeDecision.enabled) {
571
689
  try {
572
690
  const { setupAgentWorktree, finishAgentWorktree } =
573
691
  await import("../lib/agent-worktree.js");
574
692
  _finishAgentWorktreeFn = finishAgentWorktree;
693
+ const detectedRepoRoot = worktreeDecision.repoRoot || invocationCwd;
575
694
  const worktreeCwd =
576
695
  process.platform === "darwin"
577
- ? process.cwd().replace(/^\/private\//, "/")
578
- : process.cwd();
579
- _worktree = setupAgentWorktree({ cwd: worktreeCwd });
696
+ ? detectedRepoRoot.replace(/^\/private\//, "/")
697
+ : detectedRepoRoot;
698
+ _worktree = setupAgentWorktree({
699
+ cwd: worktreeCwd,
700
+ ...(backgroundRequested ? { requireCleanSource: true } : {}),
701
+ });
702
+ // Register cleanup immediately after creation. In particular,
703
+ // process.chdir() can fail on Windows when the new path is raced,
704
+ // locked, or denied; that must not leak the worktree + branch.
705
+ process.on("exit", _finishWorktreeSync);
580
706
  process.chdir(_worktree.path);
581
707
  process.stderr.write(
582
- `worktree: ${_worktree.path} (branch ${_worktree.branch})\n`,
708
+ `${worktreeDecision.source === "background-git-default" ? "worktree (background default)" : "worktree"}: ${_worktree.path} (branch ${_worktree.branch})\n`,
583
709
  );
584
710
  // WorktreeCreate lifecycle hook (observe-only, best-effort): a fresh
585
711
  // isolated worktree just appeared — let automation react (register it
@@ -618,37 +744,28 @@ export function registerAgentCommand(program) {
618
744
  } catch {
619
745
  /* worktree lifecycle hooks are best-effort — never block */
620
746
  }
621
- // The worktree is created BEFORE flag validation, and several
622
- // `process.exit(1)` guards below (plus any future ones) would skip the
623
- // normal cleanup and orphan an empty worktree + branch on disk. A sync
624
- // exit handler guarantees the auto-removable worktree is cleaned up on
625
- // EVERY exit path (finishAgentWorktree is synchronous). Deduped with
626
- // the normal async _finishWorktree() via _worktreeFinished.
627
- process.on("exit", () => {
628
- if (!_worktree || _worktreeFinished || _worktreeTransferred) {
629
- return;
630
- }
631
- _worktreeFinished = true;
632
- try {
633
- process.chdir(_worktree.repoRoot);
634
- _finishAgentWorktreeFn(_worktree);
635
- } catch {
636
- /* never block exit */
637
- }
638
- });
639
747
  } catch (err) {
748
+ const fin = _finishWorktreeSync();
640
749
  process.stderr.write(`--worktree failed: ${err.message}\n`);
750
+ if (err.retainedWorktree?.path) {
751
+ process.stderr.write(
752
+ `worktree recovery required: retained ${err.retainedWorktree.path} ` +
753
+ `(branch ${err.retainedWorktree.branch || "unknown"}); ` +
754
+ `cleanup failed: ${err.worktreeCleanupError?.message || "unknown error"}. ` +
755
+ `Inspect it with git -C "${err.retainedWorktree.repoRoot}" worktree list before manual cleanup.\n`,
756
+ );
757
+ }
758
+ if (fin?.removed) {
759
+ process.stderr.write(`worktree removed (${fin.reason}).\n`);
760
+ }
641
761
  process.exit(1);
762
+ return;
642
763
  }
643
764
  }
644
765
  const _finishWorktree = async () => {
645
- if (!_worktree || _worktreeFinished || _worktreeTransferred) {
646
- return;
647
- }
648
- _worktreeFinished = true;
766
+ const fin = _finishWorktreeSync();
767
+ if (!fin) return;
649
768
  try {
650
- process.chdir(_worktree.repoRoot); // release the dir before removal
651
- const fin = _finishAgentWorktreeFn(_worktree);
652
769
  process.stderr.write(
653
770
  fin.removed
654
771
  ? `worktree removed (${fin.reason}).\n`
@@ -738,6 +855,7 @@ export function registerAgentCommand(program) {
738
855
  process.stderr.write(
739
856
  "No previous session to continue. Start one with `cc agent`.\n",
740
857
  );
858
+ await _finishWorktree();
741
859
  process.exit(1);
742
860
  }
743
861
  }
@@ -784,6 +902,7 @@ export function registerAgentCommand(program) {
784
902
  process.stderr.write(
785
903
  "--include-partial-messages requires --output-format stream-json.\n",
786
904
  );
905
+ await _finishWorktree();
787
906
  process.exit(1);
788
907
  }
789
908
 
@@ -885,8 +1004,22 @@ export function registerAgentCommand(program) {
885
1004
  process.exit(6);
886
1005
  }
887
1006
 
888
- // Extra workspace roots (--add-dir) 鈥?shared by headless + interactive.
889
- const additionalDirectories = resolveAddDirs(options.addDir);
1007
+ // Extra workspace roots (--add-dir) — shared by headless + interactive.
1008
+ // Resolve against the invocation cwd (before chdir), then remap any path
1009
+ // inside the original repository to the isolated worktree counterpart.
1010
+ let additionalDirectories;
1011
+ try {
1012
+ additionalDirectories = resolveAddDirs(options.addDir, {
1013
+ cwd: invocationCwd,
1014
+ worktree: _worktree,
1015
+ warnOnExternalShare: backgroundRequested && Boolean(_worktree),
1016
+ });
1017
+ } catch (error) {
1018
+ process.stderr.write(`Error: ${error.message}\n`);
1019
+ await _finishWorktree();
1020
+ process.exit(1);
1021
+ return;
1022
+ }
890
1023
 
891
1024
  // --image <path> (repeatable): read into {mediaType, base64} for the
892
1025
  // headless prompt's vision input. A bad extension fails loudly here
@@ -897,6 +1030,7 @@ export function registerAgentCommand(program) {
897
1030
  images = resolveImages(options.image);
898
1031
  } catch (err) {
899
1032
  process.stderr.write(`Error: ${err.message}\n`);
1033
+ await _finishWorktree();
900
1034
  process.exit(1);
901
1035
  }
902
1036
  }
@@ -1137,6 +1271,7 @@ export function registerAgentCommand(program) {
1137
1271
  process.stderr.write(
1138
1272
  `Invalid --input-format "${options.inputFormat}". Expected: text | stream-json.\n`,
1139
1273
  );
1274
+ await _finishWorktree();
1140
1275
  process.exit(1);
1141
1276
  }
1142
1277
 
@@ -1164,39 +1299,39 @@ export function registerAgentCommand(program) {
1164
1299
  // Commander canonicalizes the dual long-option declaration
1165
1300
  // `--bg, --background` to `options.background`; retain `options.bg` for
1166
1301
  // callers/tests that invoke the action with a pre-normalized object.
1167
- const background = options.background === true || options.bg === true;
1302
+ const background = backgroundRequested;
1168
1303
  if (background && !prompt) {
1169
1304
  process.stderr.write(
1170
1305
  "--bg requires a task via positional text, -p, or piped stdin.\n",
1171
1306
  );
1307
+ await _finishWorktree();
1172
1308
  process.exitCode = 1;
1173
1309
  return;
1174
1310
  }
1175
1311
 
1176
1312
  if (prompt) {
1177
1313
  if (background) {
1178
- const { launchBackgroundAgent, buildFollowUpArgv } =
1179
- await import("../lib/background-agent-supervisor.js");
1180
- const childArgv = process.argv.slice(2).filter(
1181
- (arg) =>
1182
- arg !== "--bg" &&
1183
- arg !== "--background" &&
1184
- // The parent already created the isolated checkout. Keeping
1185
- // this flag would make the worker child create a nested second
1186
- // worktree and later clean up the wrong owner.
1187
- arg !== "--worktree",
1188
- );
1189
- const hasSessionArg = childArgv.some(
1190
- (arg) =>
1191
- arg === "--session" ||
1192
- arg === "--resume" ||
1193
- arg === "--continue" ||
1194
- arg === "-c",
1195
- );
1314
+ const {
1315
+ launchBackgroundAgent,
1316
+ buildFollowUpArgv,
1317
+ insertArgumentsBeforeOptionTerminator,
1318
+ isBackgroundWorkerStartedError,
1319
+ } = await import("../lib/background-agent-supervisor.js");
1320
+ const { optionSpecs, commandNames } =
1321
+ captureCommandArgvGrammar(command);
1322
+ let childArgv = transformBackgroundLaunchArgv(process.argv.slice(2), {
1323
+ directories: additionalDirectories,
1324
+ optionSpecs,
1325
+ commandNames,
1326
+ });
1196
1327
  const sessionId =
1197
1328
  options.session ||
1198
1329
  `session-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`;
1199
- if (!hasSessionArg) childArgv.push("--session", sessionId);
1330
+ childArgv = canonicalizeBackgroundSessionArgv(childArgv, {
1331
+ sessionId,
1332
+ optionSpecs,
1333
+ commandNames,
1334
+ });
1200
1335
  // Follow-up template for interactive attach: same flags/session,
1201
1336
  // minus the first turn's prompt tokens (built BEFORE any piped
1202
1337
  // prompt is appended below). The worker appends -p <text> per turn.
@@ -1204,28 +1339,55 @@ export function registerAgentCommand(program) {
1204
1339
  positionalTokens: Array.isArray(task) ? task : [],
1205
1340
  printValue:
1206
1341
  typeof options.print === "string" ? options.print : null,
1342
+ optionSpecs,
1343
+ commandNames,
1207
1344
  });
1208
1345
  const promptWasPiped =
1209
1346
  positional.length === 0 &&
1210
1347
  !(typeof options.print === "string" && options.print.trim());
1211
- if (promptWasPiped) childArgv.push(prompt);
1212
- const state = launchBackgroundAgent({
1213
- argv: childArgv,
1214
- cwd: _worktree ? _worktree.path : process.cwd(),
1215
- sessionId,
1216
- title: prompt.slice(0, 100),
1217
- followUpArgv,
1218
- worktree: _worktree,
1219
- governance: {
1220
- permissionMode: options.permissionMode || "default",
1221
- resourceBudget: {
1222
- maxTurns: options.maxTurns
1223
- ? parseInt(options.maxTurns, 10)
1224
- : null,
1225
- maxCostUsd,
1348
+ if (promptWasPiped) {
1349
+ // A piped prompt beginning with `-` must remain data, never become
1350
+ // a second-pass Commander option in the detached child.
1351
+ childArgv = insertArgumentsBeforeOptionTerminator(followUpArgv, [
1352
+ agentPrintArgument(prompt),
1353
+ ]);
1354
+ }
1355
+ let state;
1356
+ try {
1357
+ state = launchBackgroundAgent({
1358
+ argv: childArgv,
1359
+ cwd: _worktree ? _worktree.path : process.cwd(),
1360
+ sessionId,
1361
+ title: prompt.slice(0, 100),
1362
+ followUpArgv,
1363
+ worktree: _worktree,
1364
+ governance: {
1365
+ permissionMode: options.permissionMode || "default",
1366
+ resourceBudget: {
1367
+ maxTurns: options.maxTurns
1368
+ ? parseInt(options.maxTurns, 10)
1369
+ : null,
1370
+ maxCostUsd,
1371
+ },
1226
1372
  },
1227
- },
1228
- });
1373
+ });
1374
+ } catch (error) {
1375
+ if (_worktree && isBackgroundWorkerStartedError(error)) {
1376
+ // Spawn succeeded: the worker may already have this path as cwd.
1377
+ // Transfer ownership and retain it even though the launcher's
1378
+ // final state write/listener setup failed.
1379
+ _worktreeTransferred = true;
1380
+ _worktreeFinished = true;
1381
+ try {
1382
+ process.chdir(_worktree.repoRoot);
1383
+ } catch {
1384
+ /* ownership is transferred; never race-delete a live cwd */
1385
+ }
1386
+ } else {
1387
+ await _finishWorktree();
1388
+ }
1389
+ throw error;
1390
+ }
1229
1391
  if (_worktree) {
1230
1392
  // Ownership moves to the persisted background session only after
1231
1393
  // the detached worker launched successfully. The parent exit hook
@@ -118,6 +118,12 @@ export function registerAgentsCommand(program) {
118
118
  if (options.json) console.log(JSON.stringify(state, null, 2));
119
119
  else if (state.stopped)
120
120
  logger.log(chalk.green(`Stopped background agent ${id}`));
121
+ else if (state.stopPending)
122
+ logger.log(
123
+ chalk.yellow(
124
+ `Stop pending for background agent ${id} (${state.stopPendingReason})`,
125
+ ),
126
+ );
121
127
  else logger.log(chalk.gray(`${id} is already ${state.status}`));
122
128
  } catch (error) {
123
129
  logger.error(chalk.red(error.message));
@@ -10,6 +10,10 @@ import {
10
10
  import { readSessionHostResumeState } from "../lib/session-host-snapshot.js";
11
11
  import executionBroker from "../lib/process-execution-broker/index.js";
12
12
 
13
+ export function buildBackgroundDispatchArgs(prompt) {
14
+ return ["agent", "--bg", `--print=${prompt}`];
15
+ }
16
+
13
17
  function formatAge(ms) {
14
18
  const n = Math.max(0, Math.round(Number(ms || 0) / 1000));
15
19
  if (n < 60) return `${n}s`;
@@ -746,7 +750,7 @@ async function runDashboardView(options = {}) {
746
750
  dispatchAgent: async (text) => {
747
751
  const child = executionBroker.spawn(
748
752
  process.execPath,
749
- [BIN_PATH, "agent", "--bg", "-p", text],
753
+ [BIN_PATH, ...buildBackgroundDispatchArgs(text)],
750
754
  {
751
755
  detached: true,
752
756
  stdio: "ignore",
@@ -1038,6 +1042,12 @@ export function registerBackgroundSessionCommands(program) {
1038
1042
  for (const result of results) {
1039
1043
  if (result.stopped) {
1040
1044
  logger.log(chalk.green(`Stopped background agent ${result.id}`));
1045
+ } else if (result.stopPending) {
1046
+ logger.log(
1047
+ chalk.yellow(
1048
+ `Stop pending for background agent ${result.id} (${result.stopPendingReason})`,
1049
+ ),
1050
+ );
1041
1051
  } else {
1042
1052
  logger.log(chalk.gray(`${result.id} is already ${result.status}`));
1043
1053
  }