chainlesschain 0.166.7 → 0.166.10

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 (191) hide show
  1. package/README.md +21 -0
  2. package/package.json +4 -1
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-BlrmQxa2.js → AIOps-CLYBDAGv.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-zyRyLITg.js → ActionButton-CpeSttcu.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-DwGz7OGN.js → Analytics-Ba1TNLG0.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-Dc-nj7Zd.js → AppLayout-xBy8EOeg.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-7Hu3O73p.js → Artifacts-CJ_3TFb8.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-Bnoe3-fR.js → Audit-DUATFCG3.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-BqYFrDKZ.js → BackgroundAgents-BRXYPIGp.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-B3hwW1nz.js → Backup-D8auLx7y.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-XFVxLA4w.js → BaseInput-CBgdslQ3.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-CWRDNw7e.js → Chat-B32LvAiE.js} +5 -5
  14. package/src/assets/web-panel/assets/ChatBubbleRenderer-CVfvAy-n.js +1 -0
  15. package/src/assets/web-panel/assets/{Checkbox-kFeeBgac.js → Checkbox-BwzBxOpC.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-CCxp8xoI.js → Codegen-0U5vrg1H.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-BLKZalle.js → Col-dZ2i4aAj.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-DD0eWCez.js → Community-UVvpLr8c.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-CHqHWdy0.js → Compact-BDNEb1Bd.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-Bw54uPiK.js → Compliance-BrzQPxyS.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-DZ13zKNJ.js → Cowork-BbgGsu-9.js} +3 -3
  22. package/src/assets/web-panel/assets/{Cron-Dlj5Jevg.js → Cron-G321XPhp.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-Nvz0aR0j.js → Crosschain-CgLNUyMn.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-Ct89eUyY.js → DID-BAfRj18q.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-BHUH5IAe.js → Dashboard-BNIxA4TK.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-BhZG-PO7.js → Dropdown-BLAUmCAN.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-ae4RVwwJ.js → EmailListRenderer-CsnhTW22.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-AOcxLfLr.js → FamilyGuardDashboard-zcQ7Ip1n.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-BK2PJQOF.js → Federation-KFwxodNU.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-C2n3xO2_.js → FormItemContext-3CYRLEHG.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-DcyUVFZq.js → GenericCardRenderer-D3d9D8L9.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-tBae9Lt8.js → Git-BJ202nJY.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-DmNR3AP4.js → Governance-ClnnXVQ-.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-CoseEigi.js → Inference-DNU-PTkc.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-Bdjd1sxr.js → KnowledgeGraph-DJuinbuY.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-CtlkKIcn.js → Logs-D4No-46s.js} +2 -2
  37. package/src/assets/web-panel/assets/MarkdownRenderer-Dt8hH_qA.js +1 -0
  38. package/src/assets/web-panel/assets/{Marketplace-BTYb7nEx.js → Marketplace-Ba-KqRN3.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-D0iUdW3P.js → McpTools-DVoxnPgE.js} +2 -2
  40. package/src/assets/web-panel/assets/{Memory--gwI7w4Y.js → Memory-D_C8gzAZ.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-JmFBi24T.js → MobileBridge-DnzTPcDH.js} +1 -1
  42. package/src/assets/web-panel/assets/MobileProjects-Jg2dVUc-.js +1 -0
  43. package/src/assets/web-panel/assets/{Mtc-u7avzyoO.js → Mtc-CvEHmHId.js} +5 -5
  44. package/src/assets/web-panel/assets/{MtcAudit-gT3z5fo_.js → MtcAudit-VNJmWqmv.js} +2 -2
  45. package/src/assets/web-panel/assets/{Multisig-BIqZTz5n.js → Multisig-BO0x_Vsa.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-DdhVfXYq.js → NLProgramming-CM2gI1UY.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-CBlyUmY3.js → Notes-CMc1HsML.js} +4 -4
  48. package/src/assets/web-panel/assets/{NotificationSettings-DSyI26N3.js → NotificationSettings-DGNmSKGM.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-B7IEuNz4.js → OrderTableRenderer-Du-Kct3p.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-ozhi4kGS.js → Organization-DRtRZjas.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-CBy57RVM.js → Overflow-Dp4OeWsn.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-CA-ZRv77.js → P2P-DXMJVls8.js} +2 -2
  53. package/src/assets/web-panel/assets/PdhVaultBrowser-0jYeVmyY.js +7 -0
  54. package/src/assets/web-panel/assets/{Permissions-DiP632GP.js → Permissions-D1Hbb51o.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-AnU8O-SS.js → PersonalDataHub-BridiDhr.js} +5 -5
  56. package/src/assets/web-panel/assets/{Pipeline-DDibOUaP.js → Pipeline-B4bUNCm1.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-D421t36T.js → Privacy-BTu_HEqK.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-DR879ZPJ.js → ProjectInit-SVtL2hnt.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-Ded8o6aY.js → ProjectSettings-B2Sh7JZ2.js} +2 -2
  60. package/src/assets/web-panel/assets/{Projects-BHPxiucB.js → Projects-BwU1xalW.js} +1 -1
  61. package/src/assets/web-panel/assets/{Providers-Boivuu-E.js → Providers-BWdWQSDw.js} +1 -1
  62. package/src/assets/web-panel/assets/{QrScannerModal-xKD_ntKp.js → QrScannerModal-Brzc-Sxb.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-D3y_A6FV.js → QuickAsk-DIBz7FCe.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-BjKM-YC2.js → Recommend-CZ8RriIJ.js} +1 -1
  65. package/src/assets/web-panel/assets/RemoteSession-CM0KJQ3t.js +5 -0
  66. package/src/assets/web-panel/assets/{Reputation-Ci2GjH5p.js → Reputation-D_wo8H0O.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-B0-T2BSh.js → Row-D1G1fD7N.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-Bet-ur-r.js → RssFeed-dKCVtA0K.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-DWtRAS2R.js → Search-Be1D61xo.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-BDfu2Qn6.js → Security-IbNiR6OC.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-CvJmvSMM.js → Services-nuHK8y8p.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-CEbrKpdC.js → Skeleton-DnM5jdnC.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-CjVeiETf.js → Skills-DCTdoq_q.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-Dibypxum.js → Sla-DlWun-Ui.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-XflYXp7a.js → SpeechSettings-C19kv2sd.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-ro1Ivx1E.js → SyncSettings-CkQIR_Hu.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-CHq1qFbo.js → Tasks-DdbqOEbs.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-CRnUZxtZ.js → Templates-B7GpIXeo.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-jUX72JCA.js → Tenant-ByEstFhY.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-BBhAs7pt.js → Terminal-BKRVID1a.js} +2 -2
  81. package/src/assets/web-panel/assets/{TimelineRenderer-CD5M3RGp.js → TimelineRenderer-CNS3dHNv.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-sah3v0gu.js → Tokens-BykqylCL.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-BNT3Uz3s.js → Trigger-ByNxq51W.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-BytMGPMo.js → Trust-BlrFsdaS.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-BkYVMRQs.js → UkeySign-Dg26A-sd.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-psvb5Q7Y.js → VideoEditing-C1wUxNn0.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-PFQTW0MH.js → Wallet-OphEUzI4.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-DgO-OwRT.js → WebAuthn-_8lL08hF.js} +5 -5
  89. package/src/assets/web-panel/assets/{WorkflowEditor-DL2l9VNl.js → WorkflowEditor-BnTuIvnP.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-C84akEzN.js → chat-3N3VLQYr.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-DzTWuQKP.js → colors-Bo_G96gg.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-CR9LJQFv.js → compact-item-DjubfjI_.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-CTTov5Kn.js → createContext-Cx_HSLCk.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-BX944k9E.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-DALj523o.js → hasIn-D5OjAOlA.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-D9ScRFxz.js → index-3_CEBEEf.js} +3 -3
  97. package/src/assets/web-panel/assets/{index-BKNIzw0U.js → index-B905-Mcs.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-eJcFleIV.js → index-BScGr1BY.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CXaCRXN4.js → index-BgPb37tI.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-B6QOJbSn.js → index-Bj7S5IJw.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CNmTDXmf.js → index-BvYo09C0.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-7ux_XohH.js → index-BxgIE4PD.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-D_Bg0LdK.js → index-C-4sfa0l.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DZER6Lj3.js → index-C-_Cy0k_.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CmELknPe.js → index-C4MAnkl5.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CXTEpfGe.js → index-C5IwN9q3.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-W9axN_Ce.js → index-C8dPFFhy.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-B2qpjU-D.js → index-CC7RnaPP.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-D0MqUnKO.js → index-CCjq3g32.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DtW6Zr_i.js → index-CNmsP0Xf.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CqUgXYIQ.js → index-CRKk1JPX.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-_8vetPbU.js → index-CVPDhmVH.js} +1 -1
  113. package/src/assets/web-panel/assets/index-C_9Jt_SR.js +1 -0
  114. package/src/assets/web-panel/assets/{index-Cef0n4k_.js → index-Ce8EWU6r.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CnxjXIsK.js → index-CmLwI-Y8.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CunGDV0g.js → index-CqZq3zWr.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DjE_ew7U.js → index-Cz5tQ5PY.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-QW0EXx14.js → index-DBvZhdCb.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Dah8M4l2.js → index-DD1zSPZH.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DBIPnoTj.js → index-DE4XtzMl.js} +1 -1
  121. package/src/assets/web-panel/assets/index-DL2EFx7m.js +1 -0
  122. package/src/assets/web-panel/assets/{index-3-XJoYgX.js → index-DXJqa1-I.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-Be6Os5S8.js → index-DaU60K3A.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-AXnERsyV.js → index-Dbdr8tVi.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-hzzTITR9.js → index-DlcbE0sX.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-s4CFyn-n.js → index-DrVjatPe.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CZhhFQi9.js → index-EZr3bvz2.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BDyt57zL.js → index-HioDjvUF.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DH6OG-ci.js → index-Q_vn0t8d.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BNaQt49r.js → index-UnpsQ6A0.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-C5eeMl_2.js → index-Y-H7j25u.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-CjkPDSX4.js → index-uAcJUJkx.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DxdzSljS.js → index-x7o-2T3S.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-BHRXKiU1.js → index-ydnEPOzZ.js} +1 -1
  135. package/src/assets/web-panel/assets/{initDefaultProps-JuW8mFj7.js → initDefaultProps-DurpENJY.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-Cwb0HBve.js → motion-CIh-z-gR.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-DHokzMgu.js → move-Uc_yI2NA.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-DX31y6QS.js → mtc-parser-DUevj5wz.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-BCIUYDA6.js → omit-85eMYyur.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-DMCj4EoZ.js → pickAttrs-AuxDD20F.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-Dy5K-u1s.js → placementArrow-DOWn8dd1.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-DkGeZu54.js → responsiveObserve-CPxTWodH.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-Dc5dyJdg.js → slide-BqvbGPjx.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-DIUBjOaC.js → statusUtils-BzXKkV8d.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-DmyEOxm5.js → styleChecker-B2O7yRk3.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-FRhakk1e.js → useFlexGapSupport-DRWp7px1.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-clXyV1WQ.js → useFs-Dp0V7sjM.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-UF6DG41z.js → usePersonalDataHub-CyCrG3ql.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-CoCt95G7.js → vnode-CXhoFpFo.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-yVWt-ENm.js → zoom-0z3mtwEg.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/command-help-index.json +1 -1
  153. package/src/commands/orchestrate.js +61 -9
  154. package/src/data/changelog.json +47 -1
  155. package/src/gateways/ws/message-dispatcher.js +4 -0
  156. package/src/gateways/ws/session-protocol.js +89 -11
  157. package/src/gateways/ws/ws-agent-handler.js +65 -9
  158. package/src/gateways/ws/ws-approval-gate.js +181 -16
  159. package/src/gateways/ws/ws-server.js +16 -6
  160. package/src/generated/cc-agent-protocol.schema.json +148 -2
  161. package/src/lib/agent-team/task-lease.js +172 -3
  162. package/src/lib/agent-team/team-runner.js +60 -1
  163. package/src/lib/app-server/graph-runtime.js +326 -2
  164. package/src/lib/app-server/server.js +60 -0
  165. package/src/lib/approval-grant-ledger.js +69 -0
  166. package/src/lib/codex-app-server-adapter.js +11 -20
  167. package/src/lib/graph-kernel/compiler.js +66 -13
  168. package/src/lib/graph-kernel/cutover-authority-resolver.js +26 -0
  169. package/src/lib/graph-kernel/cutover-ledger.js +53 -11
  170. package/src/lib/graph-kernel/index.js +2 -0
  171. package/src/lib/graph-kernel/production-cutover-evidence.js +969 -0
  172. package/src/lib/graph-kernel/retirement-evidence.js +575 -0
  173. package/src/lib/graph-kernel/runtime.js +76 -14
  174. package/src/lib/interaction-adapter.js +61 -9
  175. package/src/lib/policy-decision-event.js +149 -0
  176. package/src/lib/process-execution-broker/platform-sandbox.js +15 -1
  177. package/src/lib/record-replay/index.js +1 -0
  178. package/src/lib/record-replay/playwright-ui-driver.js +327 -0
  179. package/src/lib/webhook-security.js +484 -36
  180. package/src/runtime/coding-agent-events.cjs +13 -11
  181. package/src/runtime/headless-runner.js +17 -1
  182. package/src/runtime/headless-stream.js +66 -3
  183. package/src/runtime/session-slash-commands.js +57 -6
  184. package/src/assets/web-panel/assets/ChatBubbleRenderer-Bf30VM8G.js +0 -1
  185. package/src/assets/web-panel/assets/MarkdownRenderer-CZsTBEQE.js +0 -1
  186. package/src/assets/web-panel/assets/MobileProjects-BK01cQRx.js +0 -1
  187. package/src/assets/web-panel/assets/PdhVaultBrowser-DOHc9zm8.js +0 -7
  188. package/src/assets/web-panel/assets/RemoteSession-CgqKMXG4.js +0 -5
  189. package/src/assets/web-panel/assets/devWarning-BOhvmlpc.js +0 -1
  190. package/src/assets/web-panel/assets/index-DDyMJexx.js +0 -1
  191. package/src/assets/web-panel/assets/index-btiojFYn.js +0 -1
@@ -6,6 +6,11 @@ import {
6
6
  import { createGraphAuthorityBinding } from "../graph-kernel/authority.js";
7
7
  import { GraphEventStore } from "../graph-kernel/event-store.js";
8
8
  import { GraphKernel } from "../graph-kernel/runtime.js";
9
+ import {
10
+ diffGraphTrace,
11
+ locateBlockedRoot,
12
+ reduceGraphTrace,
13
+ } from "../graph-kernel/trace-reducer.js";
9
14
 
10
15
  const TERMINAL = new Set([
11
16
  "succeeded",
@@ -19,6 +24,10 @@ const TERMINAL = new Set([
19
24
  "compensation_failed",
20
25
  ]);
21
26
  const DIGEST = /^sha256:[a-f0-9]{64}$/u;
27
+ const DEFAULT_HISTORY_EVENT_LIMIT = 1_000;
28
+ const MAX_HISTORY_EVENT_LIMIT = 2_000;
29
+ const DEFAULT_HISTORY_SNAPSHOT_LIMIT = 200;
30
+ const MAX_HISTORY_SNAPSHOT_LIMIT = 200;
22
31
 
23
32
  function runtimeError(code, message, details = {}) {
24
33
  const error = new Error(message);
@@ -73,6 +82,51 @@ function nodeInput(inputs, nodeId) {
73
82
  return { prompt: "" };
74
83
  }
75
84
 
85
+ function boundedInteger(value, fallback, { min = 0, max } = {}) {
86
+ if (value === undefined || value === null) return fallback;
87
+ const number = Number(value);
88
+ if (!Number.isSafeInteger(number) || number < min || number > max) {
89
+ throw runtimeError(
90
+ "CC_GRAPH_HISTORY_RANGE_INVALID",
91
+ `Graph history range must be an integer between ${min} and ${max}`,
92
+ );
93
+ }
94
+ return number;
95
+ }
96
+
97
+ function debuggerProjection(projection) {
98
+ return Object.freeze({
99
+ ...projection,
100
+ timeline: Object.freeze(
101
+ (projection.timeline || []).map((event) =>
102
+ Object.freeze({
103
+ seq: event.seq,
104
+ timestamp: event.timestamp,
105
+ type: event.type,
106
+ hash: event.hash,
107
+ }),
108
+ ),
109
+ ),
110
+ effects: Object.freeze(
111
+ (projection.effects || []).map((effect) =>
112
+ Object.freeze({
113
+ id: effect.id,
114
+ nodeId: effect.nodeId ?? null,
115
+ attemptId: effect.attemptId ?? null,
116
+ status: effect.status,
117
+ iterationPath: Object.freeze([...(effect.iterationPath || [])]),
118
+ receiptDigest: DIGEST.test(
119
+ String(effect.receipt?.receiptDigest || ""),
120
+ )
121
+ ? effect.receipt.receiptDigest
122
+ : null,
123
+ compensationEffectId: effect.compensationEffectId ?? null,
124
+ }),
125
+ ),
126
+ ),
127
+ });
128
+ }
129
+
76
130
  /**
77
131
  * Host-owned Graph executor used by fixed App Server capabilities. GraphKernel
78
132
  * owns ready/attempt/effect/terminal state; the injected executor owns only a
@@ -85,6 +139,7 @@ export class AppServerGraphRuntime {
85
139
  ? new GraphEventStore({ rolloutStore })
86
140
  : new GraphEventStore(),
87
141
  executeNode,
142
+ requestHumanTask = null,
88
143
  now = Date.now,
89
144
  createId = randomUUID,
90
145
  onEvent = null,
@@ -96,6 +151,8 @@ export class AppServerGraphRuntime {
96
151
  this.eventStore = eventStore;
97
152
  this.rolloutStore = eventStore.rolloutStore;
98
153
  this.executeNode = executeNode;
154
+ this.requestHumanTask =
155
+ typeof requestHumanTask === "function" ? requestHumanTask : null;
99
156
  this.now = now;
100
157
  this.createId = createId;
101
158
  this.onEvent = typeof onEvent === "function" ? onEvent : null;
@@ -161,6 +218,9 @@ export class AppServerGraphRuntime {
161
218
  persistence: "durable",
162
219
  isolated: true,
163
220
  terminalEvidence: true,
221
+ durableHumanTasks: true,
222
+ humanTaskQuorum: true,
223
+ humanTaskSeparationOfDuties: true,
164
224
  authorityModes: Object.freeze(["shadow", "canonical"]),
165
225
  featureGated: true,
166
226
  });
@@ -206,7 +266,8 @@ export class AppServerGraphRuntime {
206
266
  const compiled = compileGraphDefinition(definition);
207
267
  const id = String(runId);
208
268
  const request = {
209
- definition: compiled.definition,
269
+ definition:
270
+ compiled.definitionMigration?.backupDefinition || compiled.definition,
210
271
  inputs: { ...inputs },
211
272
  originSurface,
212
273
  agentCapacity: Math.max(1, Number(agentCapacity) || 1),
@@ -323,11 +384,23 @@ export class AppServerGraphRuntime {
323
384
  this._emit(runId, "graph/run-settled", { projection: status });
324
385
  return status;
325
386
  }
387
+ const pendingHumanTask = kernel
388
+ .humanTasks(runId)
389
+ .find((task) => ["open", "claimed"].includes(task.status));
390
+ if (pendingHumanTask) {
391
+ if (!this.requestHumanTask) return status;
392
+ await this._requestHumanTaskDecision(entry, pendingHumanTask);
393
+ continue;
394
+ }
326
395
  const next = kernel
327
396
  .readyNodes(runId)
328
397
  .find((candidate) => candidate.dispatch !== "subgraph");
329
398
  if (!next) return status;
330
- await this._executeAttempt(entry, next.nodeId);
399
+ if (entry.compiled.nodes[next.nodeId]?.kind === "human") {
400
+ await this._executeHumanTask(entry, next.nodeId);
401
+ } else {
402
+ await this._executeAttempt(entry, next.nodeId);
403
+ }
331
404
  }
332
405
  throw runtimeError(
333
406
  "CC_GRAPH_DRIVE_LIMIT",
@@ -335,6 +408,157 @@ export class AppServerGraphRuntime {
335
408
  );
336
409
  }
337
410
 
411
+ async _executeHumanTask(entry, nodeId) {
412
+ const { kernel } = entry;
413
+ const runId = entry.runId;
414
+ const node = entry.compiled.nodes[nodeId];
415
+ if (node.effectClass !== "none") {
416
+ throw runtimeError(
417
+ "CC_GRAPH_HUMAN_TASK_EFFECT_UNSUPPORTED",
418
+ "HumanTask nodes must use effectClass=none; approved effects belong to a dependent task node",
419
+ );
420
+ }
421
+ const attempt = kernel.assignNode(runId, nodeId, "app-server-agent", {
422
+ ttlMs: this.writerLeaseTtlMs,
423
+ leaseId: `app-server-human-attempt:${this.createId()}`,
424
+ grant: { executor: "durable_human_task", originSurface: "desktop" },
425
+ });
426
+ const quorum =
427
+ node.join === "quorum" ? Math.max(1, Number(node.quorum) || 1) : 1;
428
+ const task = kernel.createHumanTask(runId, {
429
+ humanTaskId: `app-server-human-task:${this.createId()}`,
430
+ attemptId: attempt.id,
431
+ leaseId: attempt.leaseId,
432
+ fence: attempt.fence,
433
+ operation: nodeInput(entry.inputs, nodeId),
434
+ nonce: `app-server-human-nonce:${this.createId()}`,
435
+ ttlMs: this.writerLeaseTtlMs,
436
+ quorum,
437
+ // Product quorum is intentionally fail-closed: one identity can never
438
+ // contribute more than one vote to a multi-review HumanTask.
439
+ separationOfDuties: quorum > 1,
440
+ });
441
+ this._emit(runId, "graph/human-task-requested", {
442
+ nodeId,
443
+ humanTaskId: task.id,
444
+ quorum: task.quorum,
445
+ separationOfDuties: task.separationOfDuties,
446
+ });
447
+ if (!this.requestHumanTask) {
448
+ return kernel.getRun(runId);
449
+ }
450
+ return this._requestHumanTaskDecision(entry, task);
451
+ }
452
+
453
+ async _requestHumanTaskDecision(entry, task) {
454
+ const { kernel, runId } = entry;
455
+ const response = await this.requestHumanTask({ task });
456
+ if (!response || typeof response !== "object" || Array.isArray(response)) {
457
+ throw runtimeError(
458
+ "CC_GRAPH_HUMAN_DECISION_INVALID",
459
+ "HumanTask client returned no structured decision",
460
+ );
461
+ }
462
+ for (const [field, expected] of [
463
+ ["humanTaskId", task.id],
464
+ ["runId", runId],
465
+ ["revisionDigest", task.revisionDigest],
466
+ ["operationDigest", task.operationDigest],
467
+ ["nonce", task.nonce],
468
+ ]) {
469
+ if (response[field] !== expected) {
470
+ throw runtimeError(
471
+ "CC_GRAPH_HUMAN_TASK_BINDING_MISMATCH",
472
+ `HumanTask client response does not match ${field}`,
473
+ );
474
+ }
475
+ }
476
+ const actorId = String(response.actorId || "").trim();
477
+ if (!actorId) {
478
+ throw runtimeError(
479
+ "CC_GRAPH_HUMAN_DECISION_INVALID",
480
+ "HumanTask client response requires an authenticated actorId",
481
+ );
482
+ }
483
+ if (
484
+ task.separationOfDuties === true &&
485
+ task.decisions.some((entry) => entry.actorId === actorId)
486
+ ) {
487
+ throw runtimeError(
488
+ "CC_GRAPH_HUMAN_SEPARATION_OF_DUTIES",
489
+ "HumanTask requires a different authenticated actor",
490
+ );
491
+ }
492
+ const claim = kernel.claimHumanTask(runId, task.id, actorId, {
493
+ claimLeaseId: `app-server-human-claim:${this.createId()}`,
494
+ ttlMs: Math.min(this.writerLeaseTtlMs, 5 * 60 * 1000),
495
+ });
496
+ const decided = kernel.decideHumanTask(runId, task.id, {
497
+ actorId,
498
+ claimLeaseId: claim.claimLeaseId,
499
+ revisionDigest: response.revisionDigest,
500
+ operationDigest: response.operationDigest,
501
+ nonce: response.nonce,
502
+ decision: response.decision,
503
+ });
504
+ this._emit(runId, "graph/human-task-decided", {
505
+ nodeId: decided.nodeId,
506
+ humanTaskId: decided.id,
507
+ actorId,
508
+ status: decided.status,
509
+ acceptedDecisions: decided.decisions.filter((entry) =>
510
+ ["acceptOnce", "acceptForTurn", "acceptForSession"].includes(
511
+ entry.decision.kind,
512
+ ),
513
+ ).length,
514
+ quorum: decided.quorum,
515
+ });
516
+ if (
517
+ decided.status !== "decided" ||
518
+ ["decline", "cancel"].includes(decided.decision?.kind)
519
+ ) {
520
+ return kernel.getRun(runId);
521
+ }
522
+ const settlement = kernel.assignNode(
523
+ runId,
524
+ decided.nodeId,
525
+ "app-server-agent",
526
+ {
527
+ ttlMs: this.writerLeaseTtlMs,
528
+ leaseId: `app-server-human-settlement:${this.createId()}`,
529
+ grant: {
530
+ executor: "durable_human_task_decision",
531
+ humanTaskId: decided.id,
532
+ },
533
+ },
534
+ );
535
+ const settled = kernel.settleAttempt(runId, {
536
+ attemptId: settlement.id,
537
+ leaseId: settlement.leaseId,
538
+ fence: settlement.fence,
539
+ outcome: "succeeded",
540
+ evidence: {
541
+ outputDigest: graphDigest(
542
+ {
543
+ humanTaskId: decided.id,
544
+ revisionDigest: decided.revisionDigest,
545
+ operationDigest: decided.operationDigest,
546
+ decisions: decided.decisions,
547
+ },
548
+ "cc.app-server.human-task-settlement/v1",
549
+ ),
550
+ },
551
+ usage: { turns: 0, tokens: 0, costUsd: 0, wallMs: 0 },
552
+ });
553
+ this._emit(runId, "graph/node-settled", {
554
+ nodeId: decided.nodeId,
555
+ attemptId: settlement.id,
556
+ outcome: "succeeded",
557
+ humanTaskId: decided.id,
558
+ });
559
+ return settled;
560
+ }
561
+
338
562
  async _executeAttempt(entry, nodeId) {
339
563
  const { kernel } = entry;
340
564
  const runId = entry.runId;
@@ -451,6 +675,106 @@ export class AppServerGraphRuntime {
451
675
  return entry.kernel.getRun(id);
452
676
  }
453
677
 
678
+ humanTasks(runId) {
679
+ const id = String(runId);
680
+ const entry = this.runs.get(id) || this._recover(id);
681
+ return entry.kernel.humanTasks(id);
682
+ }
683
+
684
+ history(
685
+ runId,
686
+ {
687
+ afterSeq = 0,
688
+ limit = DEFAULT_HISTORY_EVENT_LIMIT,
689
+ snapshotLimit = DEFAULT_HISTORY_SNAPSHOT_LIMIT,
690
+ } = {},
691
+ ) {
692
+ const id = String(runId);
693
+ const cursor = boundedInteger(afterSeq, 0, {
694
+ min: 0,
695
+ max: Number.MAX_SAFE_INTEGER,
696
+ });
697
+ const eventLimit = boundedInteger(limit, DEFAULT_HISTORY_EVENT_LIMIT, {
698
+ min: 1,
699
+ max: MAX_HISTORY_EVENT_LIMIT,
700
+ });
701
+ const projectionLimit = boundedInteger(
702
+ snapshotLimit,
703
+ DEFAULT_HISTORY_SNAPSHOT_LIMIT,
704
+ { min: 1, max: MAX_HISTORY_SNAPSHOT_LIMIT },
705
+ );
706
+ const head = this.eventStore.head(id);
707
+ const effectiveCursor =
708
+ cursor === 0 && head.seq > eventLimit ? head.seq - eventLimit : cursor;
709
+ const selected = this.eventStore.read(id, {
710
+ afterSeq: effectiveCursor,
711
+ limit: eventLimit + 1,
712
+ });
713
+ const hasMore = selected.length > eventLimit;
714
+ const events = selected.slice(0, eventLimit);
715
+ const stateEvents = events.filter(
716
+ (event) => event.payload?.state?.version === 1,
717
+ );
718
+ if (stateEvents.length === 0) {
719
+ throw runtimeError(
720
+ "CC_GRAPH_TRACE_STATE_MISSING",
721
+ `Graph history has no runtime snapshot after sequence ${effectiveCursor}: ${id}`,
722
+ );
723
+ }
724
+ const snapshotEvents = stateEvents.slice(-projectionLimit);
725
+ const snapshots = snapshotEvents.map((event) => {
726
+ const through = events.filter((candidate) => candidate.seq <= event.seq);
727
+ return Object.freeze({
728
+ seq: event.seq,
729
+ timestamp: event.timestamp,
730
+ type: event.type,
731
+ hash: event.hash,
732
+ projection: debuggerProjection(reduceGraphTrace(through)),
733
+ });
734
+ });
735
+ const diffs = snapshots
736
+ .slice(1)
737
+ .map((snapshot, index) =>
738
+ diffGraphTrace(snapshots[index].projection, snapshot.projection),
739
+ );
740
+ const current = snapshots.at(-1).projection;
741
+ const blockedRoots = Object.freeze(
742
+ current.taskGraph.nodes
743
+ .filter((node) => node.blockedRoot)
744
+ .map((node) =>
745
+ Object.freeze({
746
+ nodeId: node.id,
747
+ ...locateBlockedRoot(current, node.id),
748
+ }),
749
+ ),
750
+ );
751
+ return Object.freeze({
752
+ schema: "chainlesschain.graph-debug-history/v1",
753
+ runId: id,
754
+ requestedAfterSeq: cursor,
755
+ afterSeq: effectiveCursor,
756
+ nextAfterSeq: events.at(-1)?.seq || effectiveCursor,
757
+ hasMore,
758
+ truncatedBefore: effectiveCursor > cursor,
759
+ truncatedSnapshots: stateEvents.length > projectionLimit,
760
+ eventCount: events.length,
761
+ events: Object.freeze(
762
+ events.map((event) =>
763
+ Object.freeze({
764
+ seq: event.seq,
765
+ timestamp: event.timestamp,
766
+ type: event.type,
767
+ hash: event.hash,
768
+ }),
769
+ ),
770
+ ),
771
+ snapshots: Object.freeze(snapshots),
772
+ diffs: Object.freeze(diffs),
773
+ blockedRoots,
774
+ current,
775
+ });
776
+ }
777
+
454
778
  _recover(runId) {
455
779
  let events;
456
780
  try {
@@ -132,6 +132,7 @@ export class CcAppServer {
132
132
  now,
133
133
  createId,
134
134
  executeNode: (context) => this._executeGraphNode(context),
135
+ requestHumanTask: (context) => this._requestHumanTask(context),
135
136
  onEvent: (event) => {
136
137
  void this._notify("graph/event", event).catch(() => {});
137
138
  },
@@ -295,6 +296,7 @@ export class CcAppServer {
295
296
  "graph/compile": () => this._graphCompile(message.params),
296
297
  "graph/run": () => this._graphRun(message.params),
297
298
  "graph/status": () => this._graphStatus(message.params),
299
+ "graph/history": () => this._graphHistory(message.params),
298
300
  "graph/cancel": () => this._graphCancel(message.params),
299
301
  "graph/reconcile": () => this._graphReconcile(message.params),
300
302
  };
@@ -360,6 +362,17 @@ export class CcAppServer {
360
362
  definitionId: compiled.definitionId,
361
363
  revision: compiled.revision,
362
364
  revisionDigest: compiled.revisionDigest,
365
+ migratedFrom: compiled.migratedFrom,
366
+ definitionMigration: compiled.definitionMigration
367
+ ? {
368
+ schema: compiled.definitionMigration.schema,
369
+ fromVersion: compiled.definitionMigration.fromVersion,
370
+ toVersion: compiled.definitionMigration.toVersion,
371
+ revisionDigest: compiled.definitionMigration.revisionDigest,
372
+ rollbackDigest: compiled.definitionMigration.rollbackDigest,
373
+ backupAvailable: true,
374
+ }
375
+ : null,
363
376
  topologicalOrder: [...compiled.topologicalOrder],
364
377
  };
365
378
  }
@@ -387,6 +400,15 @@ export class CcAppServer {
387
400
  return this.graphRuntime.status(requiredString(params.runId, "runId"));
388
401
  }
389
402
 
403
+ _graphHistory(rawParams) {
404
+ const params = requireObject(rawParams);
405
+ return this.graphRuntime.history(requiredString(params.runId, "runId"), {
406
+ afterSeq: params.afterSeq,
407
+ limit: params.limit,
408
+ snapshotLimit: params.snapshotLimit,
409
+ });
410
+ }
411
+
390
412
  _graphCancel(rawParams) {
391
413
  const params = requireObject(rawParams);
392
414
  return this.graphRuntime.cancel(
@@ -909,6 +931,44 @@ export class CcAppServer {
909
931
  return result;
910
932
  }
911
933
 
934
+ async _requestHumanTask({ task }) {
935
+ const result = await this._requestClient("humanTask/decide", { task });
936
+ const response = requireObject(result, "humanTask decision");
937
+ const validation = validateApprovalDecision(response.decision);
938
+ const bindings = [
939
+ ["humanTaskId", task.id],
940
+ ["runId", task.runId],
941
+ ["revisionDigest", task.revisionDigest],
942
+ ["operationDigest", task.operationDigest],
943
+ ["nonce", task.nonce],
944
+ ];
945
+ if (
946
+ !validation.ok ||
947
+ typeof response.actorId !== "string" ||
948
+ !/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,159}$/u.test(response.actorId) ||
949
+ Object.keys(response).some(
950
+ (field) =>
951
+ ![
952
+ "humanTaskId",
953
+ "runId",
954
+ "revisionDigest",
955
+ "operationDigest",
956
+ "nonce",
957
+ "actorId",
958
+ "decision",
959
+ ].includes(field),
960
+ ) ||
961
+ bindings.some(([field, expected]) => response[field] !== expected)
962
+ ) {
963
+ throw new JsonRpcError(
964
+ JSON_RPC_ERROR.INVALID_PARAMS,
965
+ "client returned an invalid or stale HumanTask decision",
966
+ { errors: validation.errors },
967
+ );
968
+ }
969
+ return response;
970
+ }
971
+
912
972
  async _completeTurn(turn, status, result) {
913
973
  if (TERMINAL_TURN_STATUSES.has(turn.status)) return;
914
974
  if (turn.assistantStarted) {
@@ -46,6 +46,14 @@ function permissionKey(permission) {
46
46
  return `${permission.capability}\0${permission.scope}`;
47
47
  }
48
48
 
49
+ function grantId(sessionId, lifetime, permission) {
50
+ return `grant_${createHash("sha256")
51
+ .update(
52
+ `${String(sessionId)}\0${String(lifetime)}\0${permissionKey(permission)}`,
53
+ )
54
+ .digest("hex")}`;
55
+ }
56
+
49
57
  function livePermission(permission, now) {
50
58
  const validation = validateAppServerDefinition("PermissionGrant", permission);
51
59
  if (!validation.ok) return false;
@@ -102,6 +110,67 @@ export class ApprovalGrantLedger {
102
110
  return false;
103
111
  }
104
112
 
113
+ listGrants() {
114
+ const now = this.now();
115
+ const grants = [];
116
+ for (const [lifetime, entries] of [
117
+ ["turn", this.turnGrants],
118
+ ["session", this.sessionGrants],
119
+ ]) {
120
+ for (const [key, entry] of entries) {
121
+ if (!livePermission(entry.permission, now)) {
122
+ entries.delete(key);
123
+ continue;
124
+ }
125
+ grants.push(
126
+ Object.freeze({
127
+ grantId: grantId(this.sessionId, lifetime, entry.permission),
128
+ lifetime,
129
+ permission: Object.freeze({ ...entry.permission }),
130
+ binding: entry.binding,
131
+ grantedAt: entry.grantedAt,
132
+ ...(lifetime === "turn" ? { turnId: this.turnId } : {}),
133
+ }),
134
+ );
135
+ }
136
+ }
137
+ return Object.freeze(grants);
138
+ }
139
+
140
+ revoke(grantIdValue) {
141
+ const requestedId = String(grantIdValue || "");
142
+ for (const [lifetime, entries] of [
143
+ ["turn", this.turnGrants],
144
+ ["session", this.sessionGrants],
145
+ ]) {
146
+ for (const [key, entry] of entries) {
147
+ if (
148
+ grantId(this.sessionId, lifetime, entry.permission) !== requestedId
149
+ ) {
150
+ continue;
151
+ }
152
+ entries.delete(key);
153
+ if (lifetime === "session") this.revision += 1;
154
+ return Object.freeze({
155
+ revoked: true,
156
+ persistedScope: lifetime === "session",
157
+ grant: Object.freeze({
158
+ grantId: requestedId,
159
+ lifetime,
160
+ permission: Object.freeze({ ...entry.permission }),
161
+ binding: entry.binding,
162
+ grantedAt: entry.grantedAt,
163
+ }),
164
+ });
165
+ }
166
+ }
167
+ return Object.freeze({
168
+ revoked: false,
169
+ persistedScope: false,
170
+ grant: null,
171
+ });
172
+ }
173
+
105
174
  applyDecision(decision, requiredPermission, binding) {
106
175
  if (
107
176
  decision?.kind !== "acceptForTurn" &&
@@ -2,6 +2,11 @@ import { EventEmitter } from "node:events";
2
2
 
3
3
  export const CODEX_APP_SERVER_PROTOCOL = "codex-app-server-experimental-v1";
4
4
  export const CODEX_APP_SERVER_FEATURE_FLAG = "CC_EXPERIMENTAL_CODEX_APP_SERVER";
5
+ export const CODEX_APP_SERVER_COMPATIBILITY_MATRIX = Object.freeze([
6
+ Object.freeze({ version: "0.149.0" }),
7
+ Object.freeze({ version: "0.150.0" }),
8
+ Object.freeze({ version: "0.150.1" }),
9
+ ]);
5
10
 
6
11
  function adapterError(code, message, details = {}) {
7
12
  const error = new Error(message);
@@ -12,30 +17,16 @@ function adapterError(code, message, details = {}) {
12
17
  }
13
18
 
14
19
  function parseVersion(value) {
15
- const match = String(value || "").match(/(\d+)\.(\d+)\.(\d+)/u);
16
- return match ? match.slice(1).map(Number) : null;
17
- }
18
-
19
- function compareVersion(left, right) {
20
- for (let index = 0; index < 3; index += 1) {
21
- if (left[index] !== right[index]) return left[index] - right[index];
22
- }
23
- return 0;
20
+ const match = String(value || "")
21
+ .trim()
22
+ .match(/^(?:codex(?:-cli)?\s+)?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u);
23
+ return match ? match.slice(1).map(Number).join(".") : null;
24
24
  }
25
25
 
26
26
  export function isCodexAppServerVersionCompatible(version, matrix = []) {
27
27
  const parsed = parseVersion(version);
28
28
  if (!parsed || !Array.isArray(matrix) || matrix.length === 0) return false;
29
- return matrix.some((range) => {
30
- const minimum = parseVersion(range.min);
31
- const maximum = parseVersion(range.maxExclusive);
32
- return (
33
- minimum &&
34
- maximum &&
35
- compareVersion(parsed, minimum) >= 0 &&
36
- compareVersion(parsed, maximum) < 0
37
- );
38
- });
29
+ return matrix.some((entry) => parseVersion(entry?.version) === parsed);
39
30
  }
40
31
 
41
32
  function projectNotification(notification) {
@@ -103,7 +94,7 @@ export class CodexAppServerAdapter extends EventEmitter {
103
94
  client,
104
95
  fallback,
105
96
  upstreamVersion,
106
- compatibilityMatrix = [],
97
+ compatibilityMatrix = CODEX_APP_SERVER_COMPATIBILITY_MATRIX,
107
98
  enabled = process.env[CODEX_APP_SERVER_FEATURE_FLAG] === "1",
108
99
  timeoutMs = 120_000,
109
100
  } = {}) {