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
@@ -50,9 +50,11 @@ export {
50
50
  _anthropicThinkingParams,
51
51
  _normalizeAnthropicResponse,
52
52
  _resetFileFreshness,
53
+ _withPostEditDiagnostics,
53
54
  _getSharedCodeIntel,
54
55
  disposeSharedCodeIntel,
55
56
  emitToolHookLifecycle,
56
57
  emitToolBatchHookLifecycle,
58
+ buildSubAgentHandoffContext,
57
59
  _resetSubtreeInstructionLoaders,
58
60
  } from "../runtime/agent-core.js";
@@ -5,6 +5,11 @@ import { proxyEnv } from "./sandbox-egress-proxy.js";
5
5
  import executionBroker from "./process-execution-broker/index.js";
6
6
 
7
7
  export const DEFAULT_SANDBOX_IMAGE = "node:22-bookworm-slim";
8
+ export const AGENT_SANDBOX_MODES = Object.freeze([
9
+ "off",
10
+ "workspace-write",
11
+ "strict",
12
+ ]);
8
13
  export const _deps = {
9
14
  spawnSync: (...args) => executionBroker.spawnSync(...args),
10
15
  };
@@ -82,8 +87,7 @@ function pathIsWithin(candidate, root) {
82
87
  }
83
88
 
84
89
  function normalizeWorkspaceRoots(entries, cwd) {
85
- const roots =
86
- Array.isArray(entries) && entries.length > 0 ? entries : [cwd];
90
+ const roots = Array.isArray(entries) && entries.length > 0 ? entries : [cwd];
87
91
  return stringList(roots).map((entry) => path.resolve(cwd, entry));
88
92
  }
89
93
 
@@ -142,9 +146,7 @@ export function resolveSandboxPolicyPath(
142
146
  ? normalizedPolicy.allowWrite
143
147
  : normalizedPolicy.allowRead;
144
148
  const policyDenies =
145
- access === "write"
146
- ? normalizedPolicy.denyWrite
147
- : normalizedPolicy.denyRead;
149
+ access === "write" ? normalizedPolicy.denyWrite : normalizedPolicy.denyRead;
148
150
  const allowedInputs = [
149
151
  ...normalizeWorkspaceRoots(workspaceRoots, resolvedCwd),
150
152
  ...resolvePolicyPaths(policyAllows, resolvedCwd),
@@ -208,18 +210,112 @@ export function normalizeSandboxPolicy(settings = {}, cwd = process.cwd()) {
208
210
 
209
211
  export function normalizeAgentSandbox(value, options = {}) {
210
212
  const settings = options.settings || {};
211
- if (!value && settings.enabled !== true) return null;
212
- if (value === false || settings.enabled === false) return null;
213
+ const policyRequiresSandbox =
214
+ settings.requireSandbox === true ||
215
+ settings.allowUnsandboxedCommands === false;
216
+ if (!value && settings.enabled !== true && !policyRequiresSandbox)
217
+ return null;
218
+ if (value === false || settings.enabled === false) {
219
+ if (policyRequiresSandbox) {
220
+ const error = new Error(
221
+ "Sandbox disablement is prohibited by effective sandbox policy",
222
+ );
223
+ error.code = "CONFIG_SANDBOX_OFF_PROHIBITED";
224
+ throw error;
225
+ }
226
+ return null;
227
+ }
228
+ const effectiveSettings = policyRequiresSandbox
229
+ ? {
230
+ ...settings,
231
+ enabled: true,
232
+ failIfUnavailable: true,
233
+ allowUnsandboxedCommands: false,
234
+ }
235
+ : settings;
236
+ const managedNetworkDisabled = options.managedSettings?.network === false;
213
237
  const image =
214
238
  typeof value === "string" && value.trim() && value !== "true"
215
239
  ? value.trim()
216
240
  : DEFAULT_SANDBOX_IMAGE;
217
241
  return {
218
- engine: settings.engine || "docker",
219
- image: settings.image || image,
242
+ engine: effectiveSettings.engine || "docker",
243
+ image: effectiveSettings.image || image,
220
244
  cwd: path.resolve(options.cwd || process.cwd()),
221
- network: options.network === true || settings.network === true,
222
- policy: normalizeSandboxPolicy(settings, options.cwd || process.cwd()),
245
+ network: managedNetworkDisabled
246
+ ? false
247
+ : options.network === true || effectiveSettings.network === true,
248
+ policy: normalizeSandboxPolicy(
249
+ effectiveSettings,
250
+ options.cwd || process.cwd(),
251
+ ),
252
+ };
253
+ }
254
+
255
+ /**
256
+ * Resolve the explicit public sandbox posture. Both isolation modes fail
257
+ * closed when the selected engine is unavailable; `strict` additionally
258
+ * forbids per-command unsandboxed escape hatches and network access.
259
+ */
260
+ export function normalizeAgentSandboxMode(mode, value, options = {}) {
261
+ if (mode == null || mode === "") {
262
+ return normalizeAgentSandbox(value, options);
263
+ }
264
+ if (!AGENT_SANDBOX_MODES.includes(mode)) {
265
+ const error = new Error(
266
+ `Invalid sandbox mode "${mode}"; expected off, workspace-write, or strict`,
267
+ );
268
+ error.code = "CONFIG_SANDBOX_MODE_INVALID";
269
+ throw error;
270
+ }
271
+ const settings = { ...(options.settings || {}) };
272
+ if (mode === "off") {
273
+ const managedSettings = options.managedSettings || {};
274
+ if (
275
+ managedSettings.enabled === true ||
276
+ managedSettings.requireSandbox === true ||
277
+ managedSettings.allowUnsandboxedCommands === false ||
278
+ settings.requireSandbox === true ||
279
+ settings.allowUnsandboxedCommands === false
280
+ ) {
281
+ const error = new Error(
282
+ "Sandbox mode off is prohibited by managed/effective sandbox policy",
283
+ );
284
+ error.code = "CONFIG_SANDBOX_OFF_PROHIBITED";
285
+ throw error;
286
+ }
287
+ return null;
288
+ }
289
+ settings.enabled = true;
290
+ settings.failIfUnavailable = true;
291
+ settings.allowUnsandboxedCommands = false;
292
+ if (mode === "strict") {
293
+ settings.network = false;
294
+ }
295
+ const sandbox = normalizeAgentSandbox(value || true, {
296
+ ...options,
297
+ network: mode === "strict" ? false : options.network,
298
+ settings,
299
+ });
300
+ sandbox.mode = mode;
301
+ return sandbox;
302
+ }
303
+
304
+ /**
305
+ * Clamp an already-enabled sandbox to fail closed for safety-oriented run
306
+ * modes. This never turns isolation on implicitly; it only prevents a selected
307
+ * sandbox from degrading to bare host execution when its engine is missing.
308
+ */
309
+ export function enforceSandboxFailClosed(sandbox, reason = "safe") {
310
+ if (!sandbox) return null;
311
+ return {
312
+ ...sandbox,
313
+ failClosedReason: reason,
314
+ policy: {
315
+ ...(sandbox.policy || {}),
316
+ allowUnsandboxedCommands: false,
317
+ failIfUnavailable: true,
318
+ },
223
319
  };
224
320
  }
225
321
 
@@ -229,21 +325,19 @@ export function executeSandboxedShell(command, sandbox, options = {}) {
229
325
  }
230
326
  const hostCwd = path.resolve(options.cwd || sandbox.cwd);
231
327
  const policy = sandbox.policy || normalizeSandboxPolicy({}, hostCwd);
232
- // An egress proxy (see sandbox-egress-proxy.js) ENFORCES the domain allow/deny
233
- // policy: the caller starts it and passes `{ env }` here, and the sandboxed
234
- // process routes its HTTP(S) traffic through it. Without a proxy, a
235
- // domain-restricted network request has no enforcement point, so we refuse
236
- // rather than grant unrestricted access.
328
+ // Proxy environment variables are advisory: a child can clear them or open a
329
+ // raw socket. Until a backend can enforce egress below the process layer,
330
+ // domain-restricted networking must fail closed instead of granting the
331
+ // sandbox an unrestricted network namespace.
237
332
  const egress = options.egressProxy || null;
238
333
  if (
239
334
  (policy.allowedDomains.length || policy.deniedDomains.length) &&
240
- sandbox.network &&
241
- !egress
335
+ sandbox.network
242
336
  ) {
243
337
  return {
244
338
  stdout: "",
245
339
  stderr:
246
- "Domain-restricted sandbox networking requires a configured sandbox proxy; refusing unrestricted network access",
340
+ "Domain-restricted sandbox networking has no non-bypassable backend enforcement; refusing unrestricted network access",
247
341
  exitCode: 1,
248
342
  failedToStart: true,
249
343
  };
@@ -272,10 +366,8 @@ export function executeSandboxedShell(command, sandbox, options = {}) {
272
366
  if (process.platform !== "win32" && process.getuid && process.getgid) {
273
367
  args.push("--user", `${process.getuid()}:${process.getgid()}`);
274
368
  }
275
- // Route egress through the host proxy so the domain policy is enforced. The
276
- // container reaches the host proxy via host.docker.internal (mapped to the
277
- // gateway on Linux via host-gateway); the caller builds `egress.env` with that
278
- // hostname (proxyEnv(port, "host.docker.internal")).
369
+ // Proxy variables remain useful for unrestricted networking, but are not a
370
+ // security boundary. Domain-restricted requests have already failed closed.
279
371
  if (egress && egress.port && sandbox.network) {
280
372
  args.push("--add-host", "host.docker.internal:host-gateway");
281
373
  const penv = proxyEnv(egress.port, "host.docker.internal");
@@ -348,8 +440,8 @@ function executeBubblewrapShell(command, sandbox, options, hostCwd, policy) {
348
440
  for (const target of policy.denyWrite) args.push("--ro-bind", target, target);
349
441
  for (const target of policy.denyRead) args.push("--tmpfs", target);
350
442
  args.push("--", "sh", "-lc", String(command || ""));
351
- // bwrap `--share-net` shares the host network namespace, so the egress proxy
352
- // is reachable at 127.0.0.1 directly — merge its env into the child's.
443
+ // bwrap `--share-net` shares the host network namespace. Proxy variables are
444
+ // convenience only; domain-restricted requests have already failed closed.
353
445
  const egress = options.egressProxy || null;
354
446
  const bwrapEnv =
355
447
  egress && egress.port && sandbox.network
@@ -459,7 +551,7 @@ export function assertSandboxAvailable(sandbox, deps = _deps) {
459
551
 
460
552
  export function sandboxSummary(sandbox) {
461
553
  if (!sandbox) return null;
462
- return {
554
+ const summary = {
463
555
  engine: sandbox.engine,
464
556
  image: sandbox.image,
465
557
  isolationLevel: isolationLevel(sandbox),
@@ -474,4 +566,6 @@ export function sandboxSummary(sandbox) {
474
566
  failIfUnavailable: sandbox.policy?.failIfUnavailable === true,
475
567
  },
476
568
  };
569
+ if (sandbox.mode) summary.mode = sandbox.mode;
570
+ return summary;
477
571
  }
@@ -7,6 +7,7 @@
7
7
  * Pure function over the event list (see jsonl-session-store.js appendEvent):
8
8
  * { type, timestamp, data }
9
9
  * types: session_start{title,provider,model} · user_message · assistant_message
10
+ * · ws_turn{requestId,user,assistant,outcome}
10
11
  * · system · tool_call{tool,args} · tool_result{tool,result}
11
12
  * · compact(stats) · token_usage{...}
12
13
  */
@@ -76,6 +77,25 @@ export function renderAgentSessionMarkdown(sessionId, events, opts = {}) {
76
77
  L.push(asText(ev.data?.content));
77
78
  L.push("");
78
79
  break;
80
+ case "ws_turn":
81
+ if (
82
+ ev.data?.schemaVersion === 1 &&
83
+ ev.data?.outcome === "completed" &&
84
+ ev.data?.user?.role === "user" &&
85
+ ev.data?.assistant?.role === "assistant"
86
+ ) {
87
+ users += 1;
88
+ assistants += 1;
89
+ L.push("## 👤 User");
90
+ L.push("");
91
+ L.push(asText(ev.data.user.content));
92
+ L.push("");
93
+ L.push("## 🤖 Assistant");
94
+ L.push("");
95
+ L.push(asText(ev.data.assistant.content));
96
+ L.push("");
97
+ }
98
+ break;
79
99
  case "system":
80
100
  L.push("## ⚙ System");
81
101
  L.push("");
@@ -28,6 +28,11 @@ import { randomUUID } from "node:crypto";
28
28
 
29
29
  export const DEFAULT_LEASE_TTL_MS = 60000;
30
30
  export const DEFAULT_MAX_ATTEMPTS = 3;
31
+ export const ADJUDICATION_DECISIONS = Object.freeze({
32
+ RETRY: "retry",
33
+ ACCEPT: "accept",
34
+ CANCEL: "cancel",
35
+ });
31
36
 
32
37
  export class TaskLeaseRegistry {
33
38
  constructor({
@@ -423,7 +428,14 @@ export class TaskLeaseRegistry {
423
428
  */
424
429
  fail(
425
430
  key,
426
- { holder, leaseId, error = null, retryable = true, now = this._now() } = {},
431
+ {
432
+ holder,
433
+ leaseId,
434
+ error = null,
435
+ retryable = true,
436
+ adjudication = null,
437
+ now = this._now(),
438
+ } = {},
427
439
  ) {
428
440
  const id = this._byKey.get(key);
429
441
  const task = id ? this._tasks.get(id) : null;
@@ -434,6 +446,23 @@ export class TaskLeaseRegistry {
434
446
  }
435
447
  const attempts = (task.metadata?.attempts || 0) + 1;
436
448
  const willRetry = retryable !== false && attempts < this.maxAttempts;
449
+ const adjudicationRequest =
450
+ !willRetry && adjudication && typeof adjudication === "object"
451
+ ? {
452
+ required: true,
453
+ code:
454
+ adjudication.code ||
455
+ "TEAM_TASK_SIDE_EFFECT_ADJUDICATION_REQUIRED",
456
+ reason:
457
+ adjudication.reason ||
458
+ (error ? String(error) : "task outcome requires adjudication"),
459
+ evidenceDigest: adjudication.evidenceDigest || null,
460
+ requestedAt: Number.isFinite(adjudication.requestedAt)
461
+ ? adjudication.requestedAt
462
+ : now,
463
+ decision: null,
464
+ }
465
+ : task.metadata?.adjudication || null;
437
466
  const ok = this._write(task, {
438
467
  status: willRetry ? TASK_STATUS.PENDING : TASK_STATUS.CANCELLED,
439
468
  assignee: null,
@@ -442,6 +471,7 @@ export class TaskLeaseRegistry {
442
471
  lease: null,
443
472
  attempts,
444
473
  lastError: error ? String(error) : null,
474
+ ...(adjudicationRequest ? { adjudication: adjudicationRequest } : {}),
445
475
  },
446
476
  });
447
477
  if (!ok) return { ok: false, reason: "concurrent" };
@@ -529,6 +559,14 @@ export class TaskLeaseRegistry {
529
559
  if (!candidate.retry) {
530
560
  metadata.attempts = (fresh.metadata?.attempts || 0) + 1;
531
561
  metadata.lastError = String(error);
562
+ metadata.adjudication = {
563
+ required: true,
564
+ code: "TEAM_TASK_ABANDONED_ADJUDICATION_REQUIRED",
565
+ reason: String(error),
566
+ evidenceDigest: null,
567
+ requestedAt: this._now(),
568
+ decision: null,
569
+ };
532
570
  }
533
571
  if (
534
572
  this._write(fresh, {
@@ -550,6 +588,234 @@ export class TaskLeaseRegistry {
550
588
  return { reclaimed, adjudicationRequired };
551
589
  }
552
590
 
591
+ /**
592
+ * Resolve a fail-closed task after a durable human decision has been
593
+ * authenticated by the adjudication log.
594
+ *
595
+ * This is deliberately the only TaskLeaseRegistry operation allowed to move
596
+ * a CANCELLED task out of a terminal state. The generic SharedTaskList keeps
597
+ * its terminal-state invariant; this method performs a compare-by-revision
598
+ * replacement and records the exceptional transition in task history.
599
+ */
600
+ resolveAdjudication(
601
+ key,
602
+ {
603
+ decision,
604
+ decisionId,
605
+ actor = "human",
606
+ reason = null,
607
+ evidenceDigest = null,
608
+ result = null,
609
+ now = this._now(),
610
+ } = {},
611
+ ) {
612
+ const allowed = new Set(Object.values(ADJUDICATION_DECISIONS));
613
+ if (!allowed.has(decision)) {
614
+ return { ok: false, reason: "invalid_decision" };
615
+ }
616
+ if (!decisionId || typeof decisionId !== "string") {
617
+ return { ok: false, reason: "decision_id_required" };
618
+ }
619
+ const id = this._byKey.get(key);
620
+ const task = id ? this._tasks.get(id) : null;
621
+ if (!task) return { ok: false, reason: "not_found" };
622
+ const pending = task.metadata?.adjudication || null;
623
+ if (pending?.required !== true) {
624
+ const prior = pending?.decision || null;
625
+ if (prior?.id === decisionId && prior?.action === decision) {
626
+ return {
627
+ ok: true,
628
+ idempotent: true,
629
+ decision,
630
+ status: task.status,
631
+ };
632
+ }
633
+ return { ok: false, reason: "adjudication_not_required" };
634
+ }
635
+ if (task.status !== TASK_STATUS.CANCELLED) {
636
+ return { ok: false, reason: "invalid_task_state" };
637
+ }
638
+ if (pending.evidenceDigest && pending.evidenceDigest !== evidenceDigest) {
639
+ return { ok: false, reason: "evidence_mismatch" };
640
+ }
641
+
642
+ const status =
643
+ decision === ADJUDICATION_DECISIONS.RETRY
644
+ ? TASK_STATUS.PENDING
645
+ : decision === ADJUDICATION_DECISIONS.ACCEPT
646
+ ? TASK_STATUS.COMPLETED
647
+ : TASK_STATUS.CANCELLED;
648
+ const decidedAt = Number.isFinite(now) ? now : this._now();
649
+ const decisionRecord = {
650
+ id: decisionId,
651
+ action: decision,
652
+ actor: actor ? String(actor) : "human",
653
+ reason: reason == null ? null : String(reason),
654
+ evidenceDigest: evidenceDigest || pending.evidenceDigest || null,
655
+ decidedAt,
656
+ };
657
+ const snapshot = this._tasks.snapshot();
658
+ const stored = snapshot.tasks.find((candidate) => candidate.id === task.id);
659
+ if (!stored || stored.rev !== task.rev) {
660
+ return { ok: false, reason: "concurrent" };
661
+ }
662
+ stored.status = status;
663
+ stored.assignee = null;
664
+ stored.updatedAt = decidedAt;
665
+ stored.rev += 1;
666
+ stored.metadata = {
667
+ ...stored.metadata,
668
+ lease: null,
669
+ ...(decision === ADJUDICATION_DECISIONS.ACCEPT
670
+ ? {
671
+ result: result ?? {
672
+ adjudicated: true,
673
+ decisionId,
674
+ },
675
+ }
676
+ : {}),
677
+ adjudication: {
678
+ ...pending,
679
+ required: false,
680
+ decision: decisionRecord,
681
+ },
682
+ };
683
+ stored.history = [
684
+ ...(stored.history || []),
685
+ {
686
+ ts: decidedAt,
687
+ actor: decisionRecord.actor,
688
+ action: "adjudicated",
689
+ changes: ["status", "assignee", "metadata"],
690
+ decision: decisionRecord.action,
691
+ decisionId,
692
+ },
693
+ ];
694
+ this._tasks = SharedTaskList.restore(snapshot, { now: this._now });
695
+ this._rebuildIndexes();
696
+ if (status === TASK_STATUS.PENDING) {
697
+ this._enqueueIfReady(key, decidedAt);
698
+ } else if (status === TASK_STATUS.COMPLETED) {
699
+ for (const dependent of this._dependentsByKey.get(key) || []) {
700
+ this._enqueueIfReady(dependent, decidedAt);
701
+ }
702
+ }
703
+ return { ok: true, decision, status };
704
+ }
705
+
706
+ /**
707
+ * Force any recovery-ambiguous task into the fail-closed adjudication state.
708
+ * This exceptional transition is used only when durable collaboration
709
+ * evidence contradicts or weakens the registry snapshot.
710
+ */
711
+ requireAdjudication(
712
+ key,
713
+ {
714
+ code = "TEAM_TASK_SIDE_EFFECT_ADJUDICATION_REQUIRED",
715
+ reason = "task outcome requires adjudication",
716
+ evidenceDigest = null,
717
+ now = this._now(),
718
+ } = {},
719
+ ) {
720
+ const id = this._byKey.get(key);
721
+ const task = id ? this._tasks.get(id) : null;
722
+ if (!task) return { ok: false, reason: "not_found" };
723
+ if (task.metadata?.adjudication?.required === true) {
724
+ return { ok: true, idempotent: true };
725
+ }
726
+ const snapshot = this._tasks.snapshot();
727
+ const stored = snapshot.tasks.find((candidate) => candidate.id === task.id);
728
+ if (!stored || stored.rev !== task.rev) {
729
+ return { ok: false, reason: "concurrent" };
730
+ }
731
+ const requestedAt = Number.isFinite(now) ? now : this._now();
732
+ const priorStatus = stored.status;
733
+ stored.status = TASK_STATUS.CANCELLED;
734
+ stored.assignee = null;
735
+ stored.updatedAt = requestedAt;
736
+ stored.rev += 1;
737
+ stored.metadata = {
738
+ ...stored.metadata,
739
+ lease: null,
740
+ lastError: String(reason),
741
+ adjudication: {
742
+ required: true,
743
+ code: String(code),
744
+ reason: String(reason),
745
+ evidenceDigest: evidenceDigest || null,
746
+ requestedAt,
747
+ priorStatus,
748
+ decision: null,
749
+ },
750
+ };
751
+ stored.history = [
752
+ ...(stored.history || []),
753
+ {
754
+ ts: requestedAt,
755
+ actor: "recovery",
756
+ action: "adjudication-required",
757
+ changes: ["status", "assignee", "metadata"],
758
+ },
759
+ ];
760
+ this._tasks = SharedTaskList.restore(snapshot, { now: this._now });
761
+ this._rebuildIndexes();
762
+ return { ok: true, priorStatus };
763
+ }
764
+
765
+ /** Bind a pending adjudication to its immutable durable case evidence. */
766
+ bindAdjudicationCase(key, { caseId, registryDigest, sideEffectDigest } = {}) {
767
+ const id = this._byKey.get(key);
768
+ const task = id ? this._tasks.get(id) : null;
769
+ if (!task) return { ok: false, reason: "not_found" };
770
+ const adjudication = task.metadata?.adjudication || null;
771
+ if (adjudication?.required !== true) {
772
+ return { ok: false, reason: "adjudication_not_required" };
773
+ }
774
+ for (const [name, value] of Object.entries({
775
+ caseId,
776
+ registryDigest,
777
+ sideEffectDigest,
778
+ })) {
779
+ if (typeof value !== "string" || value.length === 0) {
780
+ return { ok: false, reason: `${name}_required` };
781
+ }
782
+ }
783
+ const current = adjudication.case || null;
784
+ if (current) {
785
+ if (
786
+ current.caseId === caseId &&
787
+ current.registryDigest === registryDigest &&
788
+ current.sideEffectDigest === sideEffectDigest
789
+ ) {
790
+ return { ok: true, idempotent: true, case: { ...current } };
791
+ }
792
+ return { ok: false, reason: "case_binding_conflict" };
793
+ }
794
+ const binding = { caseId, registryDigest, sideEffectDigest };
795
+ const ok = this._write(task, {
796
+ metadata: {
797
+ ...task.metadata,
798
+ adjudication: {
799
+ ...adjudication,
800
+ case: binding,
801
+ },
802
+ },
803
+ });
804
+ return ok
805
+ ? { ok: true, case: { ...binding } }
806
+ : { ok: false, reason: "concurrent" };
807
+ }
808
+
809
+ pendingAdjudications() {
810
+ return this.list()
811
+ .filter((task) => task.metadata?.adjudication?.required === true)
812
+ .map((task) => ({
813
+ key: task.key,
814
+ status: task.status,
815
+ ...task.metadata.adjudication,
816
+ }));
817
+ }
818
+
553
819
  stats({ now = this._now() } = {}) {
554
820
  const base = this._tasks.stats();
555
821
  let leased = 0;
@@ -566,6 +832,7 @@ export class TaskLeaseRegistry {
566
832
  leased,
567
833
  expiredLeases: expired,
568
834
  claimable: this.claimable({ now }).length,
835
+ adjudicationRequired: this.pendingAdjudications().length,
569
836
  };
570
837
  }
571
838
 
@@ -575,8 +842,9 @@ export class TaskLeaseRegistry {
575
842
  .list()
576
843
  .every(
577
844
  (t) =>
578
- t.status === TASK_STATUS.COMPLETED ||
579
- t.status === TASK_STATUS.CANCELLED,
845
+ (t.status === TASK_STATUS.COMPLETED ||
846
+ t.status === TASK_STATUS.CANCELLED) &&
847
+ t.metadata?.adjudication?.required !== true,
580
848
  );
581
849
  }
582
850