chainlesschain 0.162.188 → 0.162.193

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 (337) hide show
  1. package/README.md +61 -11
  2. package/bin/chainlesschain.js +7 -52
  3. package/completions/_cc +209 -0
  4. package/completions/cc.bash +18 -0
  5. package/completions/cc.fish +13 -0
  6. package/completions/cc.ps1 +226 -0
  7. package/package.json +10 -2
  8. package/src/assets/web-panel/assets/{AIOps-Brr1LVcE.js → AIOps-DBLkaTje.js} +1 -1
  9. package/src/assets/web-panel/assets/{ActionButton-DQU74DKG.js → ActionButton-BAy-Qebo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Analytics-CYp9178y.js → Analytics-Dfb1Mlau.js} +3 -3
  11. package/src/assets/web-panel/assets/{AppLayout-DW4SCYsW.js → AppLayout-BbFkN8m0.js} +5 -5
  12. package/src/assets/web-panel/assets/{Artifacts-CYlD_ed1.js → Artifacts-kM4-cEEH.js} +1 -1
  13. package/src/assets/web-panel/assets/{Audit-CWl1rZOi.js → Audit-BSQfYWf3.js} +1 -1
  14. package/src/assets/web-panel/assets/{BackgroundAgents-BOR-LPsa.js → BackgroundAgents-CWDbI_fG.js} +1 -1
  15. package/src/assets/web-panel/assets/{Backup-DLpG7j1X.js → Backup-BxLPbq_Q.js} +1 -1
  16. package/src/assets/web-panel/assets/{BaseInput-B35K9wdr.js → BaseInput-DuIbdrp6.js} +1 -1
  17. package/src/assets/web-panel/assets/{Chat-CwUJb9gB.js → Chat-NEmjGahU.js} +5 -5
  18. package/src/assets/web-panel/assets/{ChatBubbleRenderer-1v6aMS1m.js → ChatBubbleRenderer-DfJEo-5_.js} +1 -1
  19. package/src/assets/web-panel/assets/{Checkbox-pi3-tPNW.js → Checkbox-CaoeG3Ns.js} +1 -1
  20. package/src/assets/web-panel/assets/{Codegen-FyNF35eL.js → Codegen-BFf_g3xY.js} +1 -1
  21. package/src/assets/web-panel/assets/{Col-tGt_JDEr.js → Col-CNOd8mdQ.js} +1 -1
  22. package/src/assets/web-panel/assets/{Community-CC7LonQX.js → Community-BhpDqz-i.js} +1 -1
  23. package/src/assets/web-panel/assets/{Compact-BGXrHHjE.js → Compact-CQ42T7Z6.js} +1 -1
  24. package/src/assets/web-panel/assets/{Compliance-DSW0TBZ8.js → Compliance-DI5PcLMN.js} +1 -1
  25. package/src/assets/web-panel/assets/{Cowork-Bhk7rbvE.js → Cowork-wYYZe0wR.js} +3 -3
  26. package/src/assets/web-panel/assets/{Cron-DxyiQ2NZ.js → Cron-Dlq03DD_.js} +2 -2
  27. package/src/assets/web-panel/assets/{Crosschain-B2ZkxHok.js → Crosschain-BzqS8PP3.js} +1 -1
  28. package/src/assets/web-panel/assets/{DID-yOJV99eJ.js → DID-It55Yem7.js} +2 -2
  29. package/src/assets/web-panel/assets/{Dashboard-CKsttz7D.js → Dashboard-9HkH6oxn.js} +2 -2
  30. package/src/assets/web-panel/assets/{Dropdown-CVFldXSL.js → Dropdown-00e2YWRB.js} +1 -1
  31. package/src/assets/web-panel/assets/{EmailListRenderer-Bufv638J.js → EmailListRenderer-By-ugRDL.js} +1 -1
  32. package/src/assets/web-panel/assets/{FamilyGuardDashboard-4ncjoIjL.js → FamilyGuardDashboard-C396yu5m.js} +1 -1
  33. package/src/assets/web-panel/assets/{Federation-DsknEDoX.js → Federation-BME5sbZY.js} +1 -1
  34. package/src/assets/web-panel/assets/{FormItemContext-Cqe5jWXA.js → FormItemContext-B4TEZCr-.js} +1 -1
  35. package/src/assets/web-panel/assets/{GenericCardRenderer-NAJaFKxc.js → GenericCardRenderer-_9CX9ieY.js} +1 -1
  36. package/src/assets/web-panel/assets/{Git-CszKQpnl.js → Git-BrS6WVSr.js} +2 -2
  37. package/src/assets/web-panel/assets/{Governance-BXGodXi6.js → Governance-BMdCWnKF.js} +1 -1
  38. package/src/assets/web-panel/assets/{Inference-CkoYuG2c.js → Inference-Bcp3vzcA.js} +1 -1
  39. package/src/assets/web-panel/assets/{KnowledgeGraph-DFlEr_T0.js → KnowledgeGraph-DlLuqGY5.js} +1 -1
  40. package/src/assets/web-panel/assets/{Logs-CVaENddA.js → Logs-D-W_6x09.js} +2 -2
  41. package/src/assets/web-panel/assets/MarkdownRenderer-DElGPxCZ.js +1 -0
  42. package/src/assets/web-panel/assets/{Marketplace-CDlLT0fw.js → Marketplace-Dzn2guvI.js} +1 -1
  43. package/src/assets/web-panel/assets/{McpTools-DdwOyszN.js → McpTools-uPict-KL.js} +6 -6
  44. package/src/assets/web-panel/assets/{Memory-DKQnkKuG.js → Memory-BCw43kOb.js} +2 -2
  45. package/src/assets/web-panel/assets/{MobileBridge-DGseqlzJ.js → MobileBridge-DmV8Wv7F.js} +1 -1
  46. package/src/assets/web-panel/assets/{MobileProjects-COBbEOlj.js → MobileProjects-C-HaCmSM.js} +1 -1
  47. package/src/assets/web-panel/assets/{Mtc-O61Vwyli.js → Mtc-C6jxJ34Y.js} +5 -5
  48. package/src/assets/web-panel/assets/{MtcAudit-Dw2SyasS.js → MtcAudit-Za8ExwhQ.js} +5 -5
  49. package/src/assets/web-panel/assets/{Multisig-hSu_l8kf.js → Multisig-KKDbuEgb.js} +3 -3
  50. package/src/assets/web-panel/assets/{NLProgramming-CX1Epurr.js → NLProgramming-Dj97zbCk.js} +1 -1
  51. package/src/assets/web-panel/assets/{Notes-R9xX8o8_.js → Notes-DBXvMraU.js} +4 -4
  52. package/src/assets/web-panel/assets/{NotificationSettings-jtSNLCuK.js → NotificationSettings-DOxITLYl.js} +1 -1
  53. package/src/assets/web-panel/assets/OrderTableRenderer-7DVjZwMM.js +1 -0
  54. package/src/assets/web-panel/assets/{Organization-Pu2WO-U3.js → Organization-D1i73mjb.js} +4 -4
  55. package/src/assets/web-panel/assets/{Overflow-BjnqUyFp.js → Overflow-kW6Q3rvg.js} +1 -1
  56. package/src/assets/web-panel/assets/{P2P-jjkvz44c.js → P2P-C-v_8p2v.js} +2 -2
  57. package/src/assets/web-panel/assets/PdhVaultBrowser-tUbbY64W.js +7 -0
  58. package/src/assets/web-panel/assets/{Permissions-D4yDpivd.js → Permissions-DkHxEZ58.js} +4 -4
  59. package/src/assets/web-panel/assets/{PersonalDataHub-0qsL6iH1.js → PersonalDataHub-DWuMPGrK.js} +5 -5
  60. package/src/assets/web-panel/assets/{Pipeline-Cx7Ybrk2.js → Pipeline-30IYXWWm.js} +1 -1
  61. package/src/assets/web-panel/assets/{Privacy-PbfR_M_V.js → Privacy-DZNQ4RrH.js} +1 -1
  62. package/src/assets/web-panel/assets/{ProjectInit-CyV6Gsub.js → ProjectInit-De2MCElf.js} +2 -2
  63. package/src/assets/web-panel/assets/{ProjectSettings-C7KZ2Wdk.js → ProjectSettings-5uHk9wsC.js} +2 -2
  64. package/src/assets/web-panel/assets/{Projects-DQDjO-yK.js → Projects-XjDfrFLb.js} +1 -1
  65. package/src/assets/web-panel/assets/{Providers-DyFVBBMX.js → Providers-Bgwj6gcE.js} +1 -1
  66. package/src/assets/web-panel/assets/{QrScannerModal-CzB1BC9_.js → QrScannerModal-gKql9umv.js} +1 -1
  67. package/src/assets/web-panel/assets/{QuickAsk-Bk636mC1.js → QuickAsk-BWvmwkh7.js} +1 -1
  68. package/src/assets/web-panel/assets/{Recommend-DoWxHIT3.js → Recommend-Uok4hZPd.js} +1 -1
  69. package/src/assets/web-panel/assets/{RemoteSession-oOVIv9wq.js → RemoteSession-DLJzTk9a.js} +3 -3
  70. package/src/assets/web-panel/assets/{Reputation-BucoReGG.js → Reputation-ZVwIPMSO.js} +1 -1
  71. package/src/assets/web-panel/assets/{Row-DzmOdJU7.js → Row-CN04HxWR.js} +1 -1
  72. package/src/assets/web-panel/assets/{RssFeed-C1tK7KGU.js → RssFeed-BdSrEG4g.js} +3 -3
  73. package/src/assets/web-panel/assets/{Search-CSnInOqk.js → Search-5PwVd0IR.js} +1 -1
  74. package/src/assets/web-panel/assets/{Security-dlejr15l.js → Security-DdBo4zjN.js} +3 -3
  75. package/src/assets/web-panel/assets/{Services-BioPZuNh.js → Services-D3letU7M.js} +2 -2
  76. package/src/assets/web-panel/assets/{Skeleton-DWMibwpC.js → Skeleton--Jb83f1v.js} +1 -1
  77. package/src/assets/web-panel/assets/{Skills-BAAnx1B2.js → Skills-Bg-CulHX.js} +1 -1
  78. package/src/assets/web-panel/assets/{Sla-jWNp4hNO.js → Sla-7QOa7S-X.js} +1 -1
  79. package/src/assets/web-panel/assets/{SpeechSettings-y5kqKha-.js → SpeechSettings-DQwppjRw.js} +1 -1
  80. package/src/assets/web-panel/assets/{SyncSettings-B9GNsc3e.js → SyncSettings-dNPQGL-s.js} +2 -2
  81. package/src/assets/web-panel/assets/{Tasks-BDBYKRen.js → Tasks-Ggs-Z48q.js} +1 -1
  82. package/src/assets/web-panel/assets/{Templates-DRiE5eaN.js → Templates-78TYHgRO.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tenant-BGlAvExF.js → Tenant-xHwwv9vO.js} +1 -1
  84. package/src/assets/web-panel/assets/{Terminal-B8uzrbNY.js → Terminal-BJXSJfm4.js} +2 -2
  85. package/src/assets/web-panel/assets/{TimelineRenderer-Df48iveY.js → TimelineRenderer-fLbjRhJw.js} +1 -1
  86. package/src/assets/web-panel/assets/{Tokens-CcmHndN6.js → Tokens-oMSBSBmB.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trigger-DPkWxmQ2.js → Trigger-CfnY_wX_.js} +1 -1
  88. package/src/assets/web-panel/assets/{Trust-DTb5a5AV.js → Trust-AdyTgYKO.js} +1 -1
  89. package/src/assets/web-panel/assets/{UkeySign-CBmg5vch.js → UkeySign-C5K_81dS.js} +1 -1
  90. package/src/assets/web-panel/assets/{VideoEditing-B0mZrz4O.js → VideoEditing-vcGVDqki.js} +1 -1
  91. package/src/assets/web-panel/assets/{Wallet-Bxs7_mpd.js → Wallet-hhOc3hlY.js} +4 -4
  92. package/src/assets/web-panel/assets/{WebAuthn-C8x3cMxU.js → WebAuthn-CVloC11s.js} +3 -3
  93. package/src/assets/web-panel/assets/{WorkflowEditor-DPrNznrP.js → WorkflowEditor-CYeE32R5.js} +1 -1
  94. package/src/assets/web-panel/assets/{chat-D3bYWu7S.js → chat-CNROR5bN.js} +1 -1
  95. package/src/assets/web-panel/assets/{colors-DY-PwMu4.js → colors-Cjx-cnwU.js} +1 -1
  96. package/src/assets/web-panel/assets/{compact-item-LDk10Kw6.js → compact-item-DOIfelvD.js} +1 -1
  97. package/src/assets/web-panel/assets/{createContext-C-2MZnFq.js → createContext-DfA7UZ8u.js} +1 -1
  98. package/src/assets/web-panel/assets/devWarning-ChcCBGs7.js +1 -0
  99. package/src/assets/web-panel/assets/{hasIn-BQIBjcnB.js → hasIn-BMSCzcfM.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CQVb2dWp.js → index-5-HXgOX5.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BdXnYMCZ.js → index-AWg-0M1S.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cx6D_dx2.js → index-B4iYzpkL.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-_HRO_cIu.js → index-B5Udeb_6.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DlRYqt3S.js → index-B7gf77CJ.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BrnRO9yE.js → index-BEMwBBHk.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-VCh5zNJo.js → index-BM1y_9hM.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BRI3ngNg.js → index-BUonmKSE.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C3GNvExG.js → index-BbQ2eQ8H.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DSvo_bp0.js → index-BemJ2u_E.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-L6qixyLc.js → index-BolaOQxx.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BI4KgcYC.js → index-BxOk9vkG.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CY4KnaO9.js → index-By61ojUx.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-L3smcoQX.js → index-C2K9SNVX.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BX2b9Orc.js → index-C3L5gdiD.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Cz4b6Z_7.js → index-C7xn0Nub.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-COG61sRv.js → index-CAnvhwg6.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C7FC8cP2.js → index-CEKMcOyU.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BN-xdSWZ.js → index-CNC5onm4.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DY2FIrmz.js → index-CVL27kXC.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CiTvBAr-.js → index-CVm1_i3t.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DhRt9cYJ.js → index-CdYBye8B.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-B5pgtZnY.js → index-ClNMrqEY.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-7xKu7Fns.js → index-Cs6l7uRu.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D4K1weKc.js → index-CshQbilz.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-k7C_oDCO.js → index-Cyweh0Hy.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D3Oq-DLL.js → index-DBpWXFed.js} +3 -3
  127. package/src/assets/web-panel/assets/{index-DYyLJPlF.js → index-DHtpHZAQ.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Dh-tkpKQ.js → index-DLmn0BoK.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-8JC9BJa1.js → index-DPAWBrMf.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Dd2Km97U.js → index-DjEsxO5h.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-KFZO_lcx.js → index-FBc_CJBd.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DTIZpPtG.js → index-Icdoqmzt.js} +1 -1
  133. package/src/assets/web-panel/assets/index-Q2IajL54.js +1 -0
  134. package/src/assets/web-panel/assets/index-bRkHgOMc.js +1 -0
  135. package/src/assets/web-panel/assets/{index-lmm9p-jm.js → index-dCd8cSUq.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-HasPt4-h.js → index-m2vG9gG_.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-CaslYch6.js → index-mTpHoEzr.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-CbR6ROOa.js → index-ti_lnTWl.js} +1 -1
  139. package/src/assets/web-panel/assets/{initDefaultProps-zQPSHf2C.js → initDefaultProps-Bu8k7H1Y.js} +1 -1
  140. package/src/assets/web-panel/assets/{motion-CKCStGVk.js → motion-s3iVK41k.js} +1 -1
  141. package/src/assets/web-panel/assets/{move-BufVDGYF.js → move-B6B-E5Jz.js} +1 -1
  142. package/src/assets/web-panel/assets/{mtc-parser-DcaFxy5D.js → mtc-parser-BiYgTidA.js} +1 -1
  143. package/src/assets/web-panel/assets/{omit-EScpkGdo.js → omit-pU1RdUDA.js} +1 -1
  144. package/src/assets/web-panel/assets/{pickAttrs-72hG_qfT.js → pickAttrs-Cdoq_SeM.js} +1 -1
  145. package/src/assets/web-panel/assets/{placementArrow-CMFWiH20.js → placementArrow-DIuvAn2K.js} +1 -1
  146. package/src/assets/web-panel/assets/{responsiveObserve-DKQHS41p.js → responsiveObserve-8w16YR2D.js} +1 -1
  147. package/src/assets/web-panel/assets/{slide-QVAFHTIQ.js → slide-VZ01cZe3.js} +1 -1
  148. package/src/assets/web-panel/assets/{statusUtils-DIz38e2G.js → statusUtils-lh8YMN8Z.js} +1 -1
  149. package/src/assets/web-panel/assets/{styleChecker-zK5cyLby.js → styleChecker-CmDyreec.js} +1 -1
  150. package/src/assets/web-panel/assets/{useFlexGapSupport-DhZngk62.js → useFlexGapSupport-hiJWMU5y.js} +1 -1
  151. package/src/assets/web-panel/assets/{useFs-BvV2cvkg.js → useFs-Thnu-Iaj.js} +1 -1
  152. package/src/assets/web-panel/assets/{usePersonalDataHub-CRmxb9l3.js → usePersonalDataHub-LBdOxjwY.js} +1 -1
  153. package/src/assets/web-panel/assets/{vnode-CgQIbobP.js → vnode-Cg6lFY_X.js} +1 -1
  154. package/src/assets/web-panel/assets/{zoom-D4XrrO0R.js → zoom-DVfsR1YO.js} +1 -1
  155. package/src/assets/web-panel/index.html +1 -1
  156. package/src/cli-help.js +181 -0
  157. package/src/command-help-index.json +181 -0
  158. package/src/command-manifest.json +1107 -175
  159. package/src/command-surface-policy.js +197 -0
  160. package/src/commands/agent.js +98 -33
  161. package/src/commands/artifacts.js +400 -2
  162. package/src/commands/background-session.js +41 -3
  163. package/src/commands/checkpoint-managed.js +1059 -0
  164. package/src/commands/checkpoint-restore-recovery.js +1476 -0
  165. package/src/commands/checkpoint.js +950 -22
  166. package/src/commands/compact.js +101 -25
  167. package/src/commands/config.js +506 -20
  168. package/src/commands/doctor.js +4 -1
  169. package/src/commands/hub.js +1 -1
  170. package/src/commands/mcp.js +688 -24
  171. package/src/commands/pack.js +16 -2
  172. package/src/commands/plugin.js +20 -12
  173. package/src/commands/session-mcp-recovery.js +218 -0
  174. package/src/commands/session.js +470 -110
  175. package/src/commands/setup.js +36 -10
  176. package/src/commands/skill.js +181 -110
  177. package/src/commands/status.js +21 -5
  178. package/src/commands/team-distributed.js +3324 -0
  179. package/src/commands/team.js +1130 -74
  180. package/src/commands/update.js +68 -6
  181. package/src/constants.js +11 -0
  182. package/src/data/changelog.json +26 -0
  183. package/src/gateways/ws/action-protocol.js +10 -0
  184. package/src/gateways/ws/session-protocol.js +555 -27
  185. package/src/gateways/ws/ws-agent-handler.js +541 -14
  186. package/src/gateways/ws/ws-session-gateway.js +129 -22
  187. package/src/gateways/ws/ws-session-state.js +431 -0
  188. package/src/harness/background-task-manager.js +233 -36
  189. package/src/harness/jsonl-session-store.js +2551 -167
  190. package/src/harness/mcp-client.js +802 -61
  191. package/src/harness/prompt-compressor.js +227 -27
  192. package/src/harness/session-index.js +89 -38
  193. package/src/harness/session-list-index.js +254 -0
  194. package/src/harness/structured-handoff.js +410 -0
  195. package/src/lazy-dispatch.js +747 -84
  196. package/src/lib/__tests__/logger.test.js +50 -2
  197. package/src/lib/advisor-runtime.js +1047 -0
  198. package/src/lib/agent-core.js +2 -0
  199. package/src/lib/agent-sandbox.js +120 -26
  200. package/src/lib/agent-session-export.js +20 -0
  201. package/src/lib/agent-team/task-lease.js +271 -3
  202. package/src/lib/agent-team/team-adjudication.js +1501 -0
  203. package/src/lib/agent-team/team-budget.js +4 -1
  204. package/src/lib/agent-team/team-control-store.js +582 -0
  205. package/src/lib/agent-team/team-distributed-queue.js +5246 -0
  206. package/src/lib/agent-team/team-process-checkpoint.js +211 -0
  207. package/src/lib/agent-team/team-runner.js +543 -24
  208. package/src/lib/agent-team/team-worktree.js +1403 -95
  209. package/src/lib/artifact-store.js +131 -8
  210. package/src/lib/background-agent-supervisor.js +185 -13
  211. package/src/lib/background-interaction-journal.js +37 -9
  212. package/src/lib/background-launch-profile.js +1058 -0
  213. package/src/lib/checkpoint-restore-already-completed-controller.js +902 -0
  214. package/src/lib/checkpoint-restore-orchestrator.js +987 -0
  215. package/src/lib/checkpoint-restore-partial-rollback-controller.js +1953 -0
  216. package/src/lib/checkpoint-restore-recovery-controller.js +689 -0
  217. package/src/lib/checkpoint-restore-recovery.js +884 -0
  218. package/src/lib/checkpoint-restore-retention.js +126 -0
  219. package/src/lib/checkpoint-restore-saga.js +5079 -0
  220. package/src/lib/checkpoint-restore-session-recovery.js +1178 -0
  221. package/src/lib/checkpoint-restore-workspace-target-verifier.js +270 -0
  222. package/src/lib/checkpoint-store.js +1688 -97
  223. package/src/lib/checkpoint-timeline-authority.js +522 -0
  224. package/src/lib/checkpoint-timeline.js +642 -0
  225. package/src/lib/config-keys.js +18 -119
  226. package/src/lib/config-manager.js +446 -27
  227. package/src/lib/config-redaction.js +57 -0
  228. package/src/lib/config-schema.js +853 -0
  229. package/src/lib/cowork-mcp-tools.js +5 -0
  230. package/src/lib/cowork-task-runner.js +458 -63
  231. package/src/lib/delivery-coordinator.js +1234 -0
  232. package/src/lib/delivery-evidence.js +450 -0
  233. package/src/lib/doctor-checkup.js +199 -14
  234. package/src/lib/executable-path.js +34 -0
  235. package/src/lib/fatal-handler.js +16 -0
  236. package/src/lib/file-checkpoint.js +4909 -186
  237. package/src/lib/file-lines.js +125 -0
  238. package/src/lib/headless-config-command.js +16 -5
  239. package/src/lib/hook-runner.cjs +139 -38
  240. package/src/lib/hooks-v2-workspace-context.js +10 -0
  241. package/src/lib/impacted-gate-selector.js +424 -0
  242. package/src/lib/interaction-adapter.js +62 -0
  243. package/src/lib/jsonl-session-store.js +1 -35
  244. package/src/lib/logger.js +66 -14
  245. package/src/lib/managed-checkpoint-render.js +60 -0
  246. package/src/lib/managed-tool-checkpoint.js +194 -0
  247. package/src/lib/mcp-call-ledger-store.js +1069 -0
  248. package/src/lib/mcp-call-ledger.js +747 -0
  249. package/src/lib/mcp-client.js +5 -0
  250. package/src/lib/mcp-conflict-scheduler.js +468 -0
  251. package/src/lib/mcp-effect-contract.js +102 -0
  252. package/src/lib/mcp-headers-helper-trust.js +145 -0
  253. package/src/lib/mcp-headers-helper.js +616 -0
  254. package/src/lib/mcp-host-recovery-runtime.js +131 -0
  255. package/src/lib/mcp-ledger-recovery-admission.js +1065 -0
  256. package/src/lib/mcp-recovery-adjudication.js +443 -0
  257. package/src/lib/output-context.js +86 -0
  258. package/src/lib/packer/file-identity.js +170 -0
  259. package/src/lib/packer/index.js +3 -0
  260. package/src/lib/packer/native-update-state.js +277 -0
  261. package/src/lib/packer/pack-update-applier.js +1983 -136
  262. package/src/lib/packer/pack-update-checker.js +34 -0
  263. package/src/lib/packer/pack-update-downloader.js +875 -86
  264. package/src/lib/packer/pack-update-signature.js +86 -0
  265. package/src/lib/packer/pkg-config-generator.js +6 -0
  266. package/src/lib/paths.js +65 -10
  267. package/src/lib/plan-mode.js +831 -14
  268. package/src/lib/plan-persistence.js +540 -0
  269. package/src/lib/plugin-runtime/hooks.js +227 -69
  270. package/src/lib/plugin-runtime/plugin-options.js +189 -44
  271. package/src/lib/pr-automation-policy.js +146 -8
  272. package/src/lib/process-execution-broker/credential-agent.js +7 -0
  273. package/src/lib/process-execution-broker/index.js +491 -13
  274. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +28 -1
  275. package/src/lib/process-execution-broker/linux-generic-bwrap.js +28 -4
  276. package/src/lib/process-execution-broker/platform-sandbox.js +92 -70
  277. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  278. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  279. package/src/lib/process-execution-broker/windows-sandbox.cs +284 -19
  280. package/src/lib/process-execution-broker/workspace-transaction.js +4459 -0
  281. package/src/lib/project-instructions.js +165 -29
  282. package/src/lib/project-mcp-trust.js +67 -0
  283. package/src/lib/public-ide-capability-manifest.js +272 -0
  284. package/src/lib/public-ide-capability-validation.js +351 -0
  285. package/src/lib/secret-store.js +267 -43
  286. package/src/lib/secure-file-identity.js +433 -0
  287. package/src/lib/secure-fs.js +1089 -0
  288. package/src/lib/security-audit.js +58 -0
  289. package/src/lib/service-manager.js +34 -13
  290. package/src/lib/session-budget-runtime.js +1452 -0
  291. package/src/lib/session-host-snapshot.js +388 -0
  292. package/src/lib/session-message-provenance.js +429 -0
  293. package/src/lib/session-projection.js +804 -0
  294. package/src/lib/session-resource-budget.js +1495 -0
  295. package/src/lib/settings-hooks.cjs +138 -22
  296. package/src/lib/settings-loader.cjs +25 -2
  297. package/src/lib/side-effect-ledger-store.js +45 -23
  298. package/src/lib/skill-execution-identity.js +217 -0
  299. package/src/lib/skill-loader.js +299 -18
  300. package/src/lib/sub-agent-context.js +236 -28
  301. package/src/lib/sub-agent-registry.js +5 -0
  302. package/src/lib/subagent-contract.js +94 -0
  303. package/src/lib/todo-manager.js +185 -18
  304. package/src/lib/todo-persistence.js +417 -0
  305. package/src/lib/turn-binding-store.js +41 -23
  306. package/src/lib/turn-binding.js +160 -2
  307. package/src/lib/with-file-lock.js +165 -24
  308. package/src/lib/ws-chat-handler.js +21 -0
  309. package/src/program-base.js +18 -0
  310. package/src/repl/advisor-command.js +103 -0
  311. package/src/repl/agent-repl.js +2175 -146
  312. package/src/repl/btw-command.js +93 -10
  313. package/src/repl/clipboard-image.js +119 -0
  314. package/src/repl/config-summary.js +64 -108
  315. package/src/repl/prompt-editor.js +233 -0
  316. package/src/repl/prompt-interactions.js +344 -0
  317. package/src/repl/prompt-stash.js +354 -0
  318. package/src/repl/prompt-suggestions.js +312 -0
  319. package/src/repl/repl-keybindings.js +227 -0
  320. package/src/repl/session-recap.js +217 -0
  321. package/src/repl/slash-command-registry.js +22 -0
  322. package/src/repl/terminal-layout.js +88 -0
  323. package/src/runtime/agent-core.js +1630 -447
  324. package/src/runtime/coding-agent-contract-shared.cjs +13 -1
  325. package/src/runtime/coding-agent-managed-tool-policy.cjs +7 -2
  326. package/src/runtime/diagnostics.js +32 -13
  327. package/src/runtime/headless-runner.js +310 -118
  328. package/src/runtime/headless-stream.js +356 -95
  329. package/src/runtime/mcp-config.js +148 -14
  330. package/src/runtime/policies/agent-policy.js +14 -0
  331. package/src/runtime/status-diagnostics-lite.js +137 -0
  332. package/src/assets/web-panel/assets/MarkdownRenderer-7iWGwZ-r.js +0 -1
  333. package/src/assets/web-panel/assets/OrderTableRenderer-BU2Yqq5H.js +0 -1
  334. package/src/assets/web-panel/assets/PdhVaultBrowser-69ca_WeR.js +0 -7
  335. package/src/assets/web-panel/assets/devWarning-B4dXIJqD.js +0 -1
  336. package/src/assets/web-panel/assets/index-C-C7DaG6.js +0 -1
  337. package/src/assets/web-panel/assets/index-DkfWzWtd.js +0 -1
@@ -44,6 +44,7 @@ export class SubAgentContext {
44
44
  * @param {string[]} [options.allowedTools] - Tool whitelist (null = all tools)
45
45
  * @param {number} [options.maxIterations] - Iteration limit (fallback if no budget)
46
46
  * @param {import('./iteration-budget.js').IterationBudget} [options.iterationBudget] - Shared iteration budget (takes priority over maxIterations)
47
+ * @param {import('./session-resource-budget.js').SessionResourceBudget} [options.sessionBudget] - Shared session-wide resource authority
47
48
  * @param {number} [options.tokenBudget] - Optional token budget
48
49
  * @param {object} [options.db] - Database instance (memory recall source)
49
50
  * @param {object} [options.permanentMemory] - Permanent memory instance
@@ -72,9 +73,10 @@ export class SubAgentContext {
72
73
  this._profile?.maxIterations ||
73
74
  DEFAULT_MAX_ITERATIONS;
74
75
  this.iterationBudget = options.iterationBudget || null; // shared budget from parent
76
+ this.sessionBudget = options.sessionBudget || null;
75
77
  this.tokenBudget = options.tokenBudget || null;
76
78
  this.inheritedContext = options.inheritedContext || null;
77
- this.allowedTools = options.allowedTools || null; // null = all
79
+ this.allowedTools = options.allowedTools ?? null; // null = all; [] = none
78
80
  this.depth = options.depth || 1; // nesting level (parent main loop = 0)
79
81
  // Shared run-wide TOTAL-sub-agent counter (one object across the whole tree)
80
82
  // so this sub-agent's own spawns draw from the same breadth pool.
@@ -163,7 +165,12 @@ export class SubAgentContext {
163
165
  // registry's `cancel(id)`), independent of any external signal.
164
166
  this._signal = options.signal || null;
165
167
  this._abortController = new AbortController();
168
+ this._runAbortController = null;
169
+ this._abortLinkCleanup = [];
166
170
  this._cancelReason = null;
171
+ this._sessionBudgetLease = null;
172
+ this._unregisterSessionAbortable = null;
173
+ this._running = false;
167
174
 
168
175
  // Optional MCP / external tool plumbing. These are forwarded into the
169
176
  // agentLoop options so MCP-backed tools (e.g. from a cowork template's
@@ -183,6 +190,8 @@ export class SubAgentContext {
183
190
  ? options.externalToolExecutors
184
191
  : {};
185
192
  this._mcpClient = options.mcpClient || null;
193
+ this._mcpCallLedger = options.mcpCallLedger || null;
194
+ this._mcpConflictScheduler = options.mcpConflictScheduler || null;
186
195
 
187
196
  // Inherited settings hooks (Pre/PostToolUse) for this child loop. null =
188
197
  // no hooks (the spawn default). The spawn path passes the parent's hooks
@@ -200,6 +209,22 @@ export class SubAgentContext {
200
209
  // gated headlessly (CONFIRM→no-confirmer→DENY).
201
210
  this._approvalGate = options.approvalGate || null;
202
211
 
212
+ // Parent execution authority. These values are applied AFTER any internal
213
+ // loop options so a child/worktree path can tighten but never replace the
214
+ // parent's policy, Plan lock, workspace sandbox, or unattended boundary.
215
+ this._parentAuthority = Object.freeze({
216
+ permissionRules: options.permissionRules || null,
217
+ hostManagedToolPolicy: options.hostManagedToolPolicy || null,
218
+ planManager: options.planManager || null,
219
+ sandbox: options.sandbox || null,
220
+ additionalDirectories: Array.isArray(options.additionalDirectories)
221
+ ? Object.freeze([...options.additionalDirectories])
222
+ : null,
223
+ shellPolicyOverrides: options.shellPolicyOverrides || null,
224
+ classifyAllShell: options.classifyAllShell === true,
225
+ unattendedActionPolicy: options.unattendedActionPolicy || null,
226
+ });
227
+
203
228
  // Build isolated system prompt
204
229
  const basePrompt = buildSystemPrompt(this.cwd);
205
230
  const profilePrompt = this._profile?.systemPrompt
@@ -231,28 +256,139 @@ export class SubAgentContext {
231
256
  );
232
257
  }
233
258
 
234
- // If worktree isolation is enabled, wrap execution in isolated worktree.
235
- if (this._useWorktree) {
236
- if (isGitRepo(this._repoDir)) {
237
- return this._runInWorktree(userPrompt, loopOptions);
238
- }
239
- // FAIL CLOSED: isolation was explicitly requested but this is not a git
240
- // repo. Never silently fall back to the parent checkout — refuse.
259
+ const admission = this._acquireSessionBudget();
260
+ if (!admission.ok) {
241
261
  this.status = "failed";
242
262
  this.completedAt = new Date().toISOString();
243
263
  this.result = {
244
- summary:
245
- "Worktree isolation was requested but the working directory is not a git repository — refusing to run in the parent checkout.",
264
+ summary: `Sub-agent blocked by session budget: ${admission.reason}`,
246
265
  artifacts: [],
247
266
  tokenCount: this._tokenCount,
248
267
  toolsUsed: [...new Set(this._toolsUsed)],
249
268
  iterationCount: this._iterationCount,
250
- isolationError: true,
269
+ budgetReason: admission.reason,
251
270
  };
252
271
  return this.result;
253
272
  }
254
273
 
255
- return this._runCore(userPrompt, loopOptions);
274
+ this._running = true;
275
+ try {
276
+ this._activateAbortLinks(loopOptions.signal || null);
277
+
278
+ // If worktree isolation is enabled, wrap execution in isolated worktree.
279
+ if (this._useWorktree) {
280
+ if (isGitRepo(this._repoDir)) {
281
+ return await this._runInWorktree(userPrompt, loopOptions);
282
+ }
283
+ // FAIL CLOSED: isolation was explicitly requested but this is not a git
284
+ // repo. Never silently fall back to the parent checkout — refuse.
285
+ this.status = "failed";
286
+ this.completedAt = new Date().toISOString();
287
+ this.result = {
288
+ summary:
289
+ "Worktree isolation was requested but the working directory is not a git repository — refusing to run in the parent checkout.",
290
+ artifacts: [],
291
+ tokenCount: this._tokenCount,
292
+ toolsUsed: [...new Set(this._toolsUsed)],
293
+ iterationCount: this._iterationCount,
294
+ isolationError: true,
295
+ };
296
+ return this.result;
297
+ }
298
+
299
+ return await this._runCore(userPrompt, loopOptions);
300
+ } finally {
301
+ this._running = false;
302
+ this._deactivateAbortLinks();
303
+ this._releaseSessionBudget();
304
+ }
305
+ }
306
+
307
+ _acquireSessionBudget() {
308
+ if (!this.sessionBudget?.acquireWork) return { ok: true };
309
+ const lease = this.sessionBudget.acquireWork({
310
+ id: this.id,
311
+ kind: "sub-agent",
312
+ depth: this.depth,
313
+ });
314
+ if (!lease.ok) return lease;
315
+ this._sessionBudgetLease = lease;
316
+ try {
317
+ this._unregisterSessionAbortable =
318
+ this.sessionBudget.registerAbortable?.(
319
+ `sub-agent:${this.id}`,
320
+ (reason) =>
321
+ this.abort(
322
+ reason?.budgetReason || reason?.message || "session-budget",
323
+ ),
324
+ ) || null;
325
+ } catch (error) {
326
+ lease.release();
327
+ this._sessionBudgetLease = null;
328
+ throw error;
329
+ }
330
+ return lease;
331
+ }
332
+
333
+ _releaseSessionBudget() {
334
+ try {
335
+ this._unregisterSessionAbortable?.();
336
+ } catch {
337
+ // Session cancellation remains authoritative if observer cleanup fails.
338
+ }
339
+ this._unregisterSessionAbortable = null;
340
+ try {
341
+ this._sessionBudgetLease?.release?.();
342
+ } catch {
343
+ // A released/aborted budget lease is idempotent.
344
+ }
345
+ this._sessionBudgetLease = null;
346
+ }
347
+
348
+ _activateAbortLinks(extraSignal = null) {
349
+ this._deactivateAbortLinks();
350
+ this._runAbortController = new AbortController();
351
+ const signals = [
352
+ this._signal,
353
+ this._abortController.signal,
354
+ this.sessionBudget?.signal || null,
355
+ extraSignal,
356
+ ].filter(Boolean);
357
+ for (const source of signals) {
358
+ const propagate = () => {
359
+ if (!this._cancelReason) {
360
+ this._cancelReason =
361
+ source.reason?.budgetReason ||
362
+ source.reason?.message ||
363
+ "cancelled";
364
+ }
365
+ if (!this._runAbortController.signal.aborted) {
366
+ try {
367
+ this._runAbortController.abort(source.reason);
368
+ } catch {
369
+ this._runAbortController.abort();
370
+ }
371
+ }
372
+ };
373
+ if (source.aborted) propagate();
374
+ else {
375
+ source.addEventListener?.("abort", propagate, { once: true });
376
+ this._abortLinkCleanup.push(() =>
377
+ source.removeEventListener?.("abort", propagate),
378
+ );
379
+ }
380
+ }
381
+ }
382
+
383
+ _deactivateAbortLinks() {
384
+ for (const cleanup of this._abortLinkCleanup.splice(0)) {
385
+ try {
386
+ cleanup();
387
+ } catch {
388
+ // Abort-listener removal is best-effort cleanup only.
389
+ }
390
+ }
391
+ this._runAbortController = null;
256
392
  }
257
393
 
258
394
  /**
@@ -332,7 +468,7 @@ export class SubAgentContext {
332
468
  // computed via _getFilteredTools() but never handed to agentLoop, so a
333
469
  // sub-agent's `tools`/frontmatter allowlist was silently ignored at the
334
470
  // LLM surface. agentLoop consumes NAMES via enabledToolNames.
335
- ...(Array.isArray(this.allowedTools) && this.allowedTools.length > 0
471
+ ...(Array.isArray(this.allowedTools)
336
472
  ? { enabledToolNames: this.allowedTools }
337
473
  : {}),
338
474
  contextEngine: this.contextEngine,
@@ -342,6 +478,7 @@ export class SubAgentContext {
342
478
  // Shared total-sub-agent counter so a nested spawn_sub_agent draws from
343
479
  // (and is bounded by) the run's single breadth pool.
344
480
  subAgentBudget: this.subAgentBudget,
481
+ sessionBudget: this.sessionBudget,
345
482
  // This context's effective contract = the ceiling for its nested spawns.
346
483
  subAgentContract: this.subAgentContract,
347
484
  toolAdmission: this.toolAdmission,
@@ -353,6 +490,39 @@ export class SubAgentContext {
353
490
  : {}),
354
491
  ...loopOptions,
355
492
  };
493
+ // Re-apply tighten-only capability fields after loopOptions. In particular,
494
+ // [] must survive as deny-all and cannot be replaced by a worktree/direct
495
+ // runner override.
496
+ if (Array.isArray(this.allowedTools)) {
497
+ options.enabledToolNames = [...this.allowedTools];
498
+ options.exactToolNames = true;
499
+ }
500
+ options.subAgentContract = this.subAgentContract;
501
+ options.sessionBudget = this.sessionBudget;
502
+ if (this._runAbortController) {
503
+ options.signal = this._runAbortController.signal;
504
+ }
505
+ options.toolAdmission = this.toolAdmission;
506
+ options.skillAllowlist = this.skillAllowlist;
507
+ const authority = this._parentAuthority;
508
+ if (authority.permissionRules) {
509
+ options.permissionRules = authority.permissionRules;
510
+ }
511
+ if (authority.hostManagedToolPolicy) {
512
+ options.hostManagedToolPolicy = authority.hostManagedToolPolicy;
513
+ }
514
+ if (authority.planManager) options.planManager = authority.planManager;
515
+ if (authority.sandbox) options.sandbox = authority.sandbox;
516
+ if (authority.additionalDirectories) {
517
+ options.additionalDirectories = [...authority.additionalDirectories];
518
+ }
519
+ if (authority.shellPolicyOverrides) {
520
+ options.shellPolicyOverrides = authority.shellPolicyOverrides;
521
+ }
522
+ if (authority.classifyAllShell) options.classifyAllShell = true;
523
+ if (authority.unattendedActionPolicy) {
524
+ options.unattendedActionPolicy = authority.unattendedActionPolicy;
525
+ }
356
526
  if (this.iterationBudget) {
357
527
  options.iterationBudget = this.iterationBudget;
358
528
  }
@@ -379,6 +549,12 @@ export class SubAgentContext {
379
549
  if (this._mcpClient) {
380
550
  options.mcpClient = this._mcpClient;
381
551
  }
552
+ if (this._mcpCallLedger) {
553
+ options.mcpCallLedger = this._mcpCallLedger;
554
+ }
555
+ if (this._mcpConflictScheduler) {
556
+ options.mcpConflictScheduler = this._mcpConflictScheduler;
557
+ }
382
558
  // Inherited Pre/PostToolUse hooks (spawn passes the parent's, filtered by
383
559
  // the contract's `hooks` allow-list). Only set when non-null so a plain
384
560
  // sub-agent keeps its no-hooks default.
@@ -420,18 +596,31 @@ export class SubAgentContext {
420
596
  }
421
597
  }
422
598
 
423
- if (event.type === "token-usage" && this._onUsage) {
424
- // Forward real usage to the spawner. A nested child's event already
425
- // carries its own attribution frame — preserve it (deepest wins).
426
- try {
427
- this._onUsage({
599
+ if (event.type === "token-usage") {
600
+ // Attributed usage was already charged by the nested child sharing
601
+ // this same authority. Only direct usage is folded here, otherwise a
602
+ // child-of-child would be counted once at every ancestor level.
603
+ if (!event.attribution && this.sessionBudget?.recordUsage) {
604
+ this.sessionBudget.recordUsage({
428
605
  provider: event.provider || null,
429
606
  model: event.model || null,
430
607
  usage: event.usage || null,
431
- attribution: event.attribution || null,
432
608
  });
433
- } catch (_e) {
434
- // Usage forwarding is best-effort — never break the child loop
609
+ }
610
+ if (this._onUsage) {
611
+ // Forward real usage to the spawner. A nested child's event already
612
+ // carries its own attribution frame — preserve it (deepest wins).
613
+ try {
614
+ this._onUsage({
615
+ provider: event.provider || null,
616
+ model: event.model || null,
617
+ usage: event.usage || null,
618
+ ...(event.source ? { source: event.source } : {}),
619
+ attribution: event.attribution || null,
620
+ });
621
+ } catch (_e) {
622
+ // Usage forwarding is best-effort — never break the child loop
623
+ }
435
624
  }
436
625
  }
437
626
 
@@ -499,6 +688,13 @@ export class SubAgentContext {
499
688
  }
500
689
  }
501
690
  } catch (err) {
691
+ if (this.isAborted()) {
692
+ this.forceComplete(this._cancelReason || "cancelled", {
693
+ partialContent: lastContent,
694
+ artifacts,
695
+ });
696
+ return this.result;
697
+ }
502
698
  this.status = "failed";
503
699
  this.completedAt = new Date().toISOString();
504
700
  // Return partial work to the parent instead of discarding it: the
@@ -527,6 +723,13 @@ export class SubAgentContext {
527
723
  if (this.status !== "active") {
528
724
  return this.result;
529
725
  }
726
+ if (this.isAborted()) {
727
+ this.forceComplete(this._cancelReason || "cancelled", {
728
+ partialContent: lastContent,
729
+ artifacts,
730
+ });
731
+ return this.result;
732
+ }
530
733
 
531
734
  // Summarize the result
532
735
  const summary = this.summarize(lastContent);
@@ -590,7 +793,7 @@ export class SubAgentContext {
590
793
  * @returns {Array} Filtered AGENT_TOOLS
591
794
  */
592
795
  _getFilteredTools() {
593
- if (!this.allowedTools || this.allowedTools.length === 0) {
796
+ if (this.allowedTools === null) {
594
797
  return AGENT_TOOLS;
595
798
  }
596
799
  return AGENT_TOOLS.filter((t) =>
@@ -638,10 +841,8 @@ export class SubAgentContext {
638
841
  parentTraceId: this._hookParentTraceId || null,
639
842
  checkpointIds: [...this._checkpointIds],
640
843
  toolUseIds: [...this._toolUseIds],
641
- worktreeId:
642
- worktree?.branch || this._worktreeBranch || null,
643
- worktreePath:
644
- worktree?.path || this._worktreePath || null,
844
+ worktreeId: worktree?.branch || this._worktreeBranch || null,
845
+ worktreePath: worktree?.path || this._worktreePath || null,
645
846
  };
646
847
  }
647
848
 
@@ -653,7 +854,10 @@ export class SubAgentContext {
653
854
  */
654
855
  isAborted() {
655
856
  return Boolean(
656
- this._signal?.aborted || this._abortController.signal.aborted,
857
+ this._signal?.aborted ||
858
+ this._abortController.signal.aborted ||
859
+ this._runAbortController?.signal.aborted ||
860
+ this.sessionBudget?.signal?.aborted,
657
861
  );
658
862
  }
659
863
 
@@ -668,7 +872,11 @@ export class SubAgentContext {
668
872
  return false;
669
873
  }
670
874
  this._cancelReason = reason;
671
- this._abortController.abort();
875
+ try {
876
+ this._abortController.abort(reason);
877
+ } catch {
878
+ this._abortController.abort();
879
+ }
672
880
  return true;
673
881
  }
674
882
 
@@ -182,6 +182,10 @@ export class SubAgentRegistry {
182
182
  forceCompleteAll(sessionId) {
183
183
  for (const [id, subCtx] of this._active) {
184
184
  if (!sessionId || subCtx.parentId === sessionId) {
185
+ // Trip the live loop's AbortSignal before recording a terminal result.
186
+ // forceComplete() alone only changed bookkeeping, so a provider/tool
187
+ // call could continue after the session had supposedly closed.
188
+ subCtx.abort?.("session-closed");
185
189
  subCtx.forceComplete("session-closed");
186
190
  this.complete(id, subCtx.result);
187
191
  }
@@ -215,6 +219,7 @@ export class SubAgentRegistry {
215
219
  const cutoff = Date.now() - maxAgeMs;
216
220
  for (const [id, subCtx] of this._active) {
217
221
  if (new Date(subCtx.createdAt).getTime() < cutoff) {
222
+ subCtx.abort?.("timeout");
218
223
  subCtx.forceComplete("timeout");
219
224
  this.complete(id, subCtx.result);
220
225
  }
@@ -72,6 +72,100 @@ export const SUBAGENT_EFFORT_LEVELS = Object.freeze([
72
72
  ]);
73
73
  const EFFORT_SYNONYMS = Object.freeze({ med: "medium", max: "xhigh" });
74
74
 
75
+ function contractValidationError(field, message) {
76
+ const error = new Error(
77
+ `invalid subagent contract field "${field}": ${message}`,
78
+ );
79
+ error.code = "CC_SUBAGENT_CONTRACT_INVALID";
80
+ return error;
81
+ }
82
+
83
+ /**
84
+ * Strict validation for authority-bearing declarations at the spawn boundary.
85
+ * The legacy normalizer remains permissive for read/display callers, but a
86
+ * malformed explicit field must never silently become "unspecified" and widen
87
+ * a live child session.
88
+ */
89
+ export function assertValidSubagentContract(raw = {}) {
90
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
91
+ throw contractValidationError("contract", "expected an object");
92
+ }
93
+ if (
94
+ raw.permissionMode != null &&
95
+ !SUBAGENT_PERMISSION_MODES.includes(raw.permissionMode)
96
+ ) {
97
+ throw contractValidationError(
98
+ "permissionMode",
99
+ `expected one of ${SUBAGENT_PERMISSION_MODES.join(", ")}`,
100
+ );
101
+ }
102
+ if (raw.context != null && !SUBAGENT_CONTEXT_MODES.includes(raw.context)) {
103
+ throw contractValidationError(
104
+ "context",
105
+ `expected one of ${SUBAGENT_CONTEXT_MODES.join(", ")}`,
106
+ );
107
+ }
108
+ for (const field of ["skills", "mcpServers", "hooks"]) {
109
+ const value = raw[field];
110
+ if (value == null) continue;
111
+ if (
112
+ typeof value !== "string" &&
113
+ !(
114
+ Array.isArray(value) &&
115
+ value.every((entry) => typeof entry === "string")
116
+ )
117
+ ) {
118
+ throw contractValidationError(field, "expected a string or string array");
119
+ }
120
+ }
121
+ for (const field of ["tools", "disallowedTools"]) {
122
+ const value = raw[field];
123
+ if (
124
+ value != null &&
125
+ !(
126
+ Array.isArray(value) &&
127
+ value.every((entry) => typeof entry === "string")
128
+ )
129
+ ) {
130
+ throw contractValidationError(field, "expected a string array");
131
+ }
132
+ }
133
+ for (const field of ["memory", "background"]) {
134
+ if (raw[field] != null && toBool(raw[field]) == null) {
135
+ throw contractValidationError(field, "expected a boolean value");
136
+ }
137
+ }
138
+ if (raw.effort != null) {
139
+ const effort = String(raw.effort).trim().toLowerCase();
140
+ const canonical = EFFORT_SYNONYMS[effort] || effort;
141
+ if (!SUBAGENT_EFFORT_LEVELS.includes(canonical)) {
142
+ throw contractValidationError(
143
+ "effort",
144
+ `expected one of ${SUBAGENT_EFFORT_LEVELS.join(", ")}`,
145
+ );
146
+ }
147
+ }
148
+ for (const field of ["maxDepth", "maxChildren"]) {
149
+ if (raw[field] != null && toPosInt(raw[field]) == null) {
150
+ throw contractValidationError(field, "expected a positive integer");
151
+ }
152
+ }
153
+ if (raw.budget != null) {
154
+ if (typeof raw.budget !== "object" || Array.isArray(raw.budget)) {
155
+ throw contractValidationError("budget", "expected an object");
156
+ }
157
+ for (const field of ["tokens", "cost", "costUsd", "time", "timeMs"]) {
158
+ if (raw.budget[field] != null && toPosNum(raw.budget[field]) == null) {
159
+ throw contractValidationError(
160
+ `budget.${field}`,
161
+ "expected a positive number",
162
+ );
163
+ }
164
+ }
165
+ }
166
+ return raw;
167
+ }
168
+
75
169
  // ─── small pure helpers ─────────────────────────────────────────────────────
76
170
 
77
171
  function toBool(v) {