chainlesschain 0.162.186 → 0.162.188

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 (177) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-DTXiO-TB.js → AIOps-Brr1LVcE.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-BbmDW-Pz.js → ActionButton-DQU74DKG.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-CSfgXJuD.js → Analytics-CYp9178y.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-BS0FFLb7.js → AppLayout-DW4SCYsW.js} +4 -4
  6. package/src/assets/web-panel/assets/{Artifacts-B19WFPK2.js → Artifacts-CYlD_ed1.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-CQhZBi7n.js → Audit-CWl1rZOi.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-BOLZCpGH.js → BackgroundAgents-BOR-LPsa.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-Dz3R_ePD.js → Backup-DLpG7j1X.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-CYfgMpax.js → BaseInput-B35K9wdr.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-5CymMr1j.js → Chat-CwUJb9gB.js} +5 -5
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-B2A_TJtl.js → ChatBubbleRenderer-1v6aMS1m.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-CDXHVYcu.js → Checkbox-pi3-tPNW.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-uq9Z9oiS.js → Codegen-FyNF35eL.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-BuW1K_65.js → Col-tGt_JDEr.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-Bbg-PvRY.js → Community-CC7LonQX.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-co0pPPTw.js → Compact-BGXrHHjE.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-B-pFAv7z.js → Compliance-DSW0TBZ8.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-54ZQS4gC.js → Cowork-Bhk7rbvE.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-B1BF2Seq.js → Cron-DxyiQ2NZ.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-Dey6qQTj.js → Crosschain-B2ZkxHok.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-ltERvfAj.js → DID-yOJV99eJ.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-DuWxOcqN.js → Dashboard-CKsttz7D.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-CrZ8ekTo.js → Dropdown-CVFldXSL.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-fIyHXhUS.js → EmailListRenderer-Bufv638J.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BtRyrRPm.js → FamilyGuardDashboard-4ncjoIjL.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-EUC6Wydj.js → Federation-DsknEDoX.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-BOpka2G-.js → FormItemContext-Cqe5jWXA.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-BXtrrYHn.js → GenericCardRenderer-NAJaFKxc.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-8WMb7PiR.js → Git-CszKQpnl.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-DNWOeDTV.js → Governance-BXGodXi6.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-Bne9b_Lb.js → Inference-CkoYuG2c.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-Cp-6Us9b.js → KnowledgeGraph-DFlEr_T0.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-Ck-uSPAx.js → Logs-CVaENddA.js} +2 -2
  35. package/src/assets/web-panel/assets/MarkdownRenderer-7iWGwZ-r.js +1 -0
  36. package/src/assets/web-panel/assets/{Marketplace-Vdq7brrJ.js → Marketplace-CDlLT0fw.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-ggLnw4hY.js → McpTools-DdwOyszN.js} +5 -5
  38. package/src/assets/web-panel/assets/{Memory-BKIjNVCU.js → Memory-DKQnkKuG.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-BElCY25a.js → MobileBridge-DGseqlzJ.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-DpLgovdH.js → MobileProjects-COBbEOlj.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-bNdrF_Zh.js → Mtc-O61Vwyli.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-Dw8w1Cqk.js → MtcAudit-Dw2SyasS.js} +2 -2
  43. package/src/assets/web-panel/assets/{Multisig-CfGKvlqc.js → Multisig-hSu_l8kf.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-D6OJf7YN.js → NLProgramming-CX1Epurr.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-B3n_LzIS.js → Notes-R9xX8o8_.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-Uu1V_ICM.js → NotificationSettings-jtSNLCuK.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-aGyWwWcp.js → OrderTableRenderer-BU2Yqq5H.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-qjFFmuwK.js → Organization-Pu2WO-U3.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-J4ZgnwZz.js → Overflow-BjnqUyFp.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-YEZF-uVH.js → P2P-jjkvz44c.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-yqx7fwqk.js → PdhVaultBrowser-69ca_WeR.js} +4 -4
  52. package/src/assets/web-panel/assets/{Permissions-DdEjlZ02.js → Permissions-D4yDpivd.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-DbAPYvns.js → PersonalDataHub-0qsL6iH1.js} +5 -5
  54. package/src/assets/web-panel/assets/{Pipeline-Bxlk_ZJU.js → Pipeline-Cx7Ybrk2.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-CpE-05tz.js → Privacy-PbfR_M_V.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-DWlhcGHT.js → ProjectInit-CyV6Gsub.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-BnH6BiTQ.js → ProjectSettings-C7KZ2Wdk.js} +2 -2
  58. package/src/assets/web-panel/assets/Projects-DQDjO-yK.js +1 -0
  59. package/src/assets/web-panel/assets/{Providers-Bdz_sTyb.js → Providers-DyFVBBMX.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-BHh2b3pH.js → QrScannerModal-CzB1BC9_.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-D84M09pe.js → QuickAsk-Bk636mC1.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-Czc30K6M.js → Recommend-DoWxHIT3.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-q_TU5qxt.js → RemoteSession-oOVIv9wq.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-CnTce4WM.js → Reputation-BucoReGG.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-C60UFLay.js → Row-DzmOdJU7.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-BOUFEu9_.js → RssFeed-C1tK7KGU.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-D4__blE-.js → Search-CSnInOqk.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-BoOm7_JK.js → Security-dlejr15l.js} +3 -3
  69. package/src/assets/web-panel/assets/{Services-AvzrW6HA.js → Services-BioPZuNh.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-BZlrHozi.js → Skeleton-DWMibwpC.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-CKaMLuk0.js → Skills-BAAnx1B2.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-DYCNJF8h.js → Sla-jWNp4hNO.js} +1 -1
  73. package/src/assets/web-panel/assets/SpeechSettings-y5kqKha-.js +1 -0
  74. package/src/assets/web-panel/assets/{SyncSettings-B6tW8dVO.js → SyncSettings-B9GNsc3e.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-oNC_2NVz.js → Tasks-BDBYKRen.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-DvLPvvjL.js → Templates-DRiE5eaN.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-BDt9UBn_.js → Tenant-BGlAvExF.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-ddCUnH-X.js → Terminal-B8uzrbNY.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-CA4sDL47.js → TimelineRenderer-Df48iveY.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-By03hnVs.js → Tokens-CcmHndN6.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-Dz2mH-ZU.js → Trigger-DPkWxmQ2.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-DShSWHeJ.js → Trust-DTb5a5AV.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-JN8lP3gt.js → UkeySign-CBmg5vch.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-BgPy4gV3.js → VideoEditing-B0mZrz4O.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-CQGEsXw_.js → Wallet-Bxs7_mpd.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-D8xR-ds_.js → WebAuthn-C8x3cMxU.js} +4 -4
  87. package/src/assets/web-panel/assets/{WorkflowEditor-Df61_p1p.js → WorkflowEditor-DPrNznrP.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-fdPby427.js → chat-D3bYWu7S.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-Dimqhufo.js → colors-DY-PwMu4.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-DHayKcqZ.js → compact-item-LDk10Kw6.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-hZUhypRH.js → createContext-C-2MZnFq.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-B4dXIJqD.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-Dw7zC_dV.js → hasIn-BQIBjcnB.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-y5LHQ5Ck.js → index-7xKu7Fns.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-CBQK-LEF.js → index-8JC9BJa1.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BuMSdwno.js → index-B5pgtZnY.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BM5BNqp9.js → index-BI4KgcYC.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BwnUluxu.js → index-BN-xdSWZ.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-D7jQEwB6.js → index-BRI3ngNg.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BIxxvaGN.js → index-BX2b9Orc.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-C1yMYKi-.js → index-BdXnYMCZ.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CuaVa8tX.js → index-BrnRO9yE.js} +1 -1
  103. package/src/assets/web-panel/assets/index-C-C7DaG6.js +1 -0
  104. package/src/assets/web-panel/assets/{index-CIOE8tt6.js → index-C3GNvExG.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-C8XXPz2n.js → index-C7FC8cP2.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-cEnkyHtX.js → index-COG61sRv.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DJP7TjWm.js → index-CQVb2dWp.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CvKHpaao.js → index-CY4KnaO9.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DxoPzPHy.js → index-CaslYch6.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DSlda4-6.js → index-CbR6ROOa.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CPZ3U5iH.js → index-CiTvBAr-.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-j0pxzOu7.js → index-Cx6D_dx2.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DzJXkoZs.js → index-Cz4b6Z_7.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BVHdkz8F.js → index-D3Oq-DLL.js} +17 -17
  115. package/src/assets/web-panel/assets/{index-ulvBurtw.js → index-D4K1weKc.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DyEhrvpm.js → index-DSvo_bp0.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DC2R4zvM.js → index-DTIZpPtG.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CsCo_A0I.js → index-DY2FIrmz.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CTiVrnpR.js → index-DYyLJPlF.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BHJUptSx.js → index-Dd2Km97U.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CcpDboUd.js → index-Dh-tkpKQ.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DnwDYBnG.js → index-DhRt9cYJ.js} +1 -1
  123. package/src/assets/web-panel/assets/index-DkfWzWtd.js +1 -0
  124. package/src/assets/web-panel/assets/{index--DVpUpz3.js → index-DlRYqt3S.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DVM_KgzF.js → index-HasPt4-h.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DX1DwDFI.js → index-KFZO_lcx.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-lPjBQJCy.js → index-L3smcoQX.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Urt2R5aE.js → index-L6qixyLc.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BYdNwhkv.js → index-VCh5zNJo.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Bhmpp3cm.js → index-_HRO_cIu.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DAjvkQ4K.js → index-k7C_oDCO.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-JE6Udz2r.js → index-lmm9p-jm.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-B4pR3px5.js → initDefaultProps-zQPSHf2C.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-CE7dWPPs.js → motion-CKCStGVk.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-Hw8cUObc.js → move-BufVDGYF.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-CvRjE4Fa.js → mtc-parser-DcaFxy5D.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-CkFeLVre.js → omit-EScpkGdo.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-5ZMqmbbb.js → pickAttrs-72hG_qfT.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-BZ4oeZ0q.js → placementArrow-CMFWiH20.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-lwoiX_Us.js → responsiveObserve-DKQHS41p.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-D_as37l8.js → slide-QVAFHTIQ.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-BsA-4Bs7.js → statusUtils-DIz38e2G.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-BVar4sLQ.js → styleChecker-zK5cyLby.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-j1IwVpGd.js → useFlexGapSupport-DhZngk62.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-7Q9bEnUp.js → useFs-BvV2cvkg.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-BBwTIRMd.js → usePersonalDataHub-CRmxb9l3.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-C7Dk-M8w.js → vnode-CgQIbobP.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-D3UHaTFB.js → zoom-D4XrrO0R.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/commands/auto-mode.js +47 -0
  151. package/src/commands/team.js +1805 -473
  152. package/src/data/auto-mode-safety-eval-v1.json +3294 -0
  153. package/src/data/changelog.json +26 -0
  154. package/src/harness/worktree-isolator.js +671 -79
  155. package/src/lib/agent-team/task-lease.js +378 -78
  156. package/src/lib/agent-team/team-agent-stream.js +488 -0
  157. package/src/lib/agent-team/team-budget.js +216 -20
  158. package/src/lib/agent-team/team-mailbox.js +389 -15
  159. package/src/lib/agent-team/team-run-state-lock.js +209 -0
  160. package/src/lib/agent-team/team-runner.js +547 -63
  161. package/src/lib/agent-team/team-scope-lock.js +409 -0
  162. package/src/lib/agent-team/team-task-contract.js +277 -0
  163. package/src/lib/agent-team/team-worktree.js +1171 -62
  164. package/src/lib/agent-worktree.js +19 -20
  165. package/src/lib/auto-mode-safety-classifier.js +2034 -0
  166. package/src/lib/auto-mode-safety-eval.js +1022 -0
  167. package/src/lib/collaboration-run-store.js +983 -68
  168. package/src/lib/with-file-lock.js +190 -24
  169. package/src/lib/worktree-isolator.js +3 -0
  170. package/src/lib/worktree-sparse.js +23 -0
  171. package/src/runtime/headless-stream.js +6 -1
  172. package/src/assets/web-panel/assets/MarkdownRenderer-DxjsdAXw.js +0 -1
  173. package/src/assets/web-panel/assets/Projects-CHw2fXDB.js +0 -1
  174. package/src/assets/web-panel/assets/SpeechSettings-BvCSU6d2.js +0 -1
  175. package/src/assets/web-panel/assets/devWarning-ePxoBp92.js +0 -1
  176. package/src/assets/web-panel/assets/index-BTBDdCoo.js +0 -1
  177. package/src/assets/web-panel/assets/index-CfOGx8Ns.js +0 -1
@@ -0,0 +1,488 @@
1
+ /**
2
+ * Incremental parser for a real teammate's `cc agent --output-format
3
+ * stream-json` stdout.
4
+ *
5
+ * The parser deliberately retains only billing metadata. Prompt, assistant and
6
+ * terminal result bodies are parsed only as part of the current NDJSON line and
7
+ * are never copied into parser state or returned to callers.
8
+ */
9
+
10
+ import { TextDecoder } from "node:util";
11
+
12
+ export const DEFAULT_TEAM_AGENT_MAX_LINE_BYTES = 1024 * 1024;
13
+ export const DEFAULT_TEAM_AGENT_MAX_TOTAL_BYTES = 32 * 1024 * 1024;
14
+
15
+ const USAGE_KEYS = Object.freeze([
16
+ "input_tokens",
17
+ "output_tokens",
18
+ "cache_read_input_tokens",
19
+ "cache_creation_input_tokens",
20
+ ]);
21
+
22
+ function emptyUsage() {
23
+ return {
24
+ input_tokens: 0,
25
+ output_tokens: 0,
26
+ cache_read_input_tokens: 0,
27
+ cache_creation_input_tokens: 0,
28
+ };
29
+ }
30
+
31
+ function cloneUsage(usage) {
32
+ return usage ? { ...usage } : null;
33
+ }
34
+
35
+ function cloneUsageRecords(records) {
36
+ return Array.isArray(records)
37
+ ? records.map((record) => ({
38
+ provider: record.provider,
39
+ model: record.model,
40
+ usage: cloneUsage(record.usage),
41
+ }))
42
+ : [];
43
+ }
44
+
45
+ function positiveInteger(value, name) {
46
+ if (!Number.isSafeInteger(value) || value <= 0) {
47
+ throw new TypeError(`${name} must be a positive safe integer`);
48
+ }
49
+ return value;
50
+ }
51
+
52
+ function asBuffer(chunk) {
53
+ if (typeof chunk === "string") return Buffer.from(chunk, "utf8");
54
+ if (Buffer.isBuffer(chunk)) return chunk;
55
+ if (chunk instanceof Uint8Array) {
56
+ return Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength);
57
+ }
58
+ throw new TypeError(
59
+ "TeamAgentStreamParser.push expects a string or Uint8Array",
60
+ );
61
+ }
62
+
63
+ export class TeamAgentStreamError extends Error {
64
+ constructor(code, message, details = {}) {
65
+ super(message);
66
+ this.name = "TeamAgentStreamError";
67
+ this.code = code;
68
+ for (const [key, value] of Object.entries(details)) {
69
+ if (value != null) this[key] = value;
70
+ }
71
+ }
72
+ }
73
+
74
+ /**
75
+ * @typedef {object} TeamAgentStreamSummary
76
+ * @property {string|null} provider
77
+ * @property {string|null} model
78
+ * @property {object|null} usage
79
+ * @property {Array<object>} usageRecords
80
+ * @property {boolean} terminalResult
81
+ */
82
+
83
+ export class TeamAgentStreamParser {
84
+ #maxLineBytes;
85
+ #maxTotalBytes;
86
+ #totalBytes = 0;
87
+ #lineBytes = 0;
88
+ #lineChunks = [];
89
+ #lineNumber = 0;
90
+ #provider = null;
91
+ #model = null;
92
+ #usage = emptyUsage();
93
+ #lastResultUsage = null;
94
+ #lastResultProvider = null;
95
+ #lastResultModel = null;
96
+ #tokenUsageEvents = 0;
97
+ #usageByIdentity = new Map();
98
+ #sawTerminalResult = false;
99
+ #finished = false;
100
+ #failed = null;
101
+ #finalSummary = null;
102
+
103
+ constructor({
104
+ maxLineBytes = DEFAULT_TEAM_AGENT_MAX_LINE_BYTES,
105
+ maxTotalBytes = DEFAULT_TEAM_AGENT_MAX_TOTAL_BYTES,
106
+ } = {}) {
107
+ this.#maxLineBytes = positiveInteger(maxLineBytes, "maxLineBytes");
108
+ this.#maxTotalBytes = positiveInteger(maxTotalBytes, "maxTotalBytes");
109
+ }
110
+
111
+ /**
112
+ * Consume one stdout chunk. Chunks may end anywhere, including in the middle
113
+ * of an NDJSON line or a multi-byte UTF-8 character.
114
+ *
115
+ * @returns {this}
116
+ */
117
+ push(chunk) {
118
+ this.#assertWritable();
119
+ const bytes = asBuffer(chunk);
120
+ if (bytes.length === 0) return this;
121
+
122
+ const nextTotal = this.#totalBytes + bytes.length;
123
+ if (!Number.isSafeInteger(nextTotal) || nextTotal > this.#maxTotalBytes) {
124
+ this.#fail(
125
+ new TeamAgentStreamError(
126
+ "TEAM_AGENT_STREAM_TOTAL_LIMIT",
127
+ `Teammate stream exceeded the ${this.#maxTotalBytes}-byte total limit`,
128
+ {
129
+ limit: this.#maxTotalBytes,
130
+ actual: nextTotal,
131
+ },
132
+ ),
133
+ );
134
+ }
135
+ this.#totalBytes = nextTotal;
136
+
137
+ let start = 0;
138
+ for (let i = 0; i < bytes.length; i += 1) {
139
+ if (bytes[i] !== 0x0a) continue;
140
+ this.#appendLineBytes(bytes.subarray(start, i));
141
+ this.#consumePendingLine();
142
+ start = i + 1;
143
+ }
144
+ this.#appendLineBytes(bytes.subarray(start));
145
+ return this;
146
+ }
147
+
148
+ /**
149
+ * Finish the stream, consuming a final line even when it has no trailing LF.
150
+ * Repeated calls are idempotent.
151
+ *
152
+ * `token_usage` events win over the terminal result aggregate to prevent
153
+ * double counting. The last `result.usage` is used only when no token-usage
154
+ * event was observed.
155
+ *
156
+ * @returns {TeamAgentStreamSummary}
157
+ */
158
+ finish(chunk) {
159
+ if (chunk !== undefined) this.push(chunk);
160
+ if (this.#failed) throw this.#failed;
161
+ if (this.#finished) return this.#copySummary();
162
+
163
+ if (this.#lineBytes > 0) this.#consumePendingLine();
164
+ this.#finished = true;
165
+ this.#finalSummary = Object.freeze({
166
+ provider: this.#provider,
167
+ model: this.#model,
168
+ usage: Object.freeze(
169
+ cloneUsage(
170
+ this.#tokenUsageEvents > 0 ? this.#usage : this.#lastResultUsage,
171
+ ),
172
+ ),
173
+ usageRecords: Object.freeze(
174
+ this.#usageRecords().map((record) =>
175
+ Object.freeze({
176
+ ...record,
177
+ usage: Object.freeze(record.usage),
178
+ }),
179
+ ),
180
+ ),
181
+ terminalResult: this.#sawTerminalResult,
182
+ });
183
+ return this.#copySummary();
184
+ }
185
+
186
+ /**
187
+ * Return the billing metadata observed so far without finishing the stream.
188
+ * This is intentionally limited to provider/model/usage so callers can
189
+ * enforce a live per-agent token ceiling without retaining assistant text.
190
+ */
191
+ status() {
192
+ if (this.#failed) throw this.#failed;
193
+ if (this.#finished) return this.#copySummary();
194
+ return this.#copyLiveSummary();
195
+ }
196
+
197
+ /**
198
+ * Return already-observed billing data even after a later malformed line
199
+ * poisoned the protocol parser. This never exposes prompt/result content and
200
+ * lets callers bill work consumed before a stream failure.
201
+ */
202
+ partialStatus() {
203
+ if (this.#finished) return this.#copySummary();
204
+ return this.#copyLiveSummary();
205
+ }
206
+
207
+ #copyLiveSummary() {
208
+ return {
209
+ provider: this.#provider,
210
+ model: this.#model,
211
+ usage:
212
+ this.#tokenUsageEvents > 0
213
+ ? cloneUsage(this.#usage)
214
+ : cloneUsage(this.#lastResultUsage),
215
+ usageRecords: this.#usageRecords(),
216
+ terminalResult: this.#sawTerminalResult,
217
+ };
218
+ }
219
+
220
+ #assertWritable() {
221
+ if (this.#failed) throw this.#failed;
222
+ if (this.#finished) {
223
+ throw new TeamAgentStreamError(
224
+ "TEAM_AGENT_STREAM_FINISHED",
225
+ "Cannot push data after the teammate stream has finished",
226
+ );
227
+ }
228
+ }
229
+
230
+ #appendLineBytes(bytes) {
231
+ if (bytes.length === 0) return;
232
+ const nextLineBytes = this.#lineBytes + bytes.length;
233
+ if (
234
+ !Number.isSafeInteger(nextLineBytes) ||
235
+ nextLineBytes > this.#maxLineBytes
236
+ ) {
237
+ this.#fail(
238
+ new TeamAgentStreamError(
239
+ "TEAM_AGENT_STREAM_LINE_LIMIT",
240
+ `Teammate stream line exceeded the ${this.#maxLineBytes}-byte limit`,
241
+ {
242
+ line: this.#lineNumber + 1,
243
+ limit: this.#maxLineBytes,
244
+ actual: nextLineBytes,
245
+ },
246
+ ),
247
+ );
248
+ }
249
+
250
+ // Copy partial input: stdout buffers are caller-owned and may be reused.
251
+ this.#lineChunks.push(Buffer.from(bytes));
252
+ this.#lineBytes = nextLineBytes;
253
+
254
+ // Bound array/object overhead as well as payload bytes when a producer
255
+ // supplies a very large number of tiny chunks for one line.
256
+ if (this.#lineChunks.length >= 64) {
257
+ this.#lineChunks = [Buffer.concat(this.#lineChunks, this.#lineBytes)];
258
+ }
259
+ }
260
+
261
+ #consumePendingLine() {
262
+ this.#lineNumber += 1;
263
+ let raw =
264
+ this.#lineChunks.length === 0
265
+ ? Buffer.alloc(0)
266
+ : Buffer.concat(this.#lineChunks, this.#lineBytes);
267
+ this.#lineChunks = [];
268
+ this.#lineBytes = 0;
269
+
270
+ if (raw.length > 0 && raw[raw.length - 1] === 0x0d) {
271
+ raw = raw.subarray(0, raw.length - 1);
272
+ }
273
+ if (raw.length === 0) return;
274
+
275
+ let line;
276
+ try {
277
+ line = new TextDecoder("utf-8", { fatal: true }).decode(raw);
278
+ } catch {
279
+ this.#fail(
280
+ new TeamAgentStreamError(
281
+ "TEAM_AGENT_STREAM_INVALID_UTF8",
282
+ `Invalid UTF-8 in teammate stream at line ${this.#lineNumber}`,
283
+ { line: this.#lineNumber },
284
+ ),
285
+ );
286
+ }
287
+ raw = null;
288
+
289
+ if (this.#lineNumber === 1 && line.charCodeAt(0) === 0xfeff) {
290
+ line = line.slice(1);
291
+ }
292
+ if (line.trim() === "") return;
293
+
294
+ let event;
295
+ try {
296
+ event = JSON.parse(line);
297
+ } catch {
298
+ // Never include JSON.parse's engine-specific message: recent runtimes
299
+ // may quote the source text, which can contain a prompt or result body.
300
+ this.#fail(
301
+ new TeamAgentStreamError(
302
+ "TEAM_AGENT_STREAM_INVALID_JSON",
303
+ `Invalid JSON in teammate stream at line ${this.#lineNumber}`,
304
+ { line: this.#lineNumber },
305
+ ),
306
+ );
307
+ } finally {
308
+ line = null;
309
+ }
310
+
311
+ if (!event || typeof event !== "object" || Array.isArray(event)) return;
312
+
313
+ if (event.type === "system" && event.subtype === "init") {
314
+ if (this.#provider == null && typeof event.provider === "string") {
315
+ this.#provider = event.provider;
316
+ }
317
+ if (this.#model == null && typeof event.model === "string") {
318
+ this.#model = event.model;
319
+ }
320
+ return;
321
+ }
322
+
323
+ if (event.type === "token_usage") {
324
+ const usage = this.#normalizeUsage(event.usage);
325
+ const provider =
326
+ typeof event.provider === "string" ? event.provider : this.#provider;
327
+ const model = typeof event.model === "string" ? event.model : this.#model;
328
+ for (const key of USAGE_KEYS) {
329
+ const next = this.#usage[key] + usage[key];
330
+ if (!Number.isSafeInteger(next)) {
331
+ this.#fail(
332
+ new TeamAgentStreamError(
333
+ "TEAM_AGENT_STREAM_INVALID_USAGE",
334
+ `Unsafe ${key} total in teammate stream at line ${this.#lineNumber}`,
335
+ { line: this.#lineNumber, field: key },
336
+ ),
337
+ );
338
+ }
339
+ this.#usage[key] = next;
340
+ }
341
+ this.#recordUsage(provider, model, usage);
342
+ this.#tokenUsageEvents += 1;
343
+ return;
344
+ }
345
+
346
+ if (event.type === "result") {
347
+ this.#sawTerminalResult = true;
348
+ this.#lastResultProvider =
349
+ typeof event.provider === "string" ? event.provider : this.#provider;
350
+ this.#lastResultModel =
351
+ typeof event.model === "string" ? event.model : this.#model;
352
+ this.#lastResultUsage =
353
+ event.usage == null ? null : this.#normalizeUsage(event.usage);
354
+ }
355
+ }
356
+
357
+ #recordUsage(provider, model, usage) {
358
+ const normalizedProvider =
359
+ typeof provider === "string" && provider ? provider : null;
360
+ const normalizedModel = typeof model === "string" && model ? model : null;
361
+ const identity = `${normalizedProvider || ""}\0${normalizedModel || ""}`;
362
+ let record = this.#usageByIdentity.get(identity);
363
+ if (!record) {
364
+ if (this.#usageByIdentity.size >= 64) {
365
+ this.#fail(
366
+ new TeamAgentStreamError(
367
+ "TEAM_AGENT_STREAM_USAGE_IDENTITY_LIMIT",
368
+ "Teammate stream exceeded the 64-model billing identity limit",
369
+ { limit: 64 },
370
+ ),
371
+ );
372
+ }
373
+ record = {
374
+ provider: normalizedProvider,
375
+ model: normalizedModel,
376
+ usage: emptyUsage(),
377
+ };
378
+ this.#usageByIdentity.set(identity, record);
379
+ }
380
+ for (const key of USAGE_KEYS) {
381
+ const next = record.usage[key] + usage[key];
382
+ if (!Number.isSafeInteger(next)) {
383
+ this.#fail(
384
+ new TeamAgentStreamError(
385
+ "TEAM_AGENT_STREAM_INVALID_USAGE",
386
+ `Unsafe ${key} identity total in teammate stream`,
387
+ { field: key },
388
+ ),
389
+ );
390
+ }
391
+ record.usage[key] = next;
392
+ }
393
+ }
394
+
395
+ #usageRecords() {
396
+ if (this.#tokenUsageEvents > 0) {
397
+ return [...this.#usageByIdentity.values()].map((record) => ({
398
+ provider: record.provider,
399
+ model: record.model,
400
+ usage: cloneUsage(record.usage),
401
+ }));
402
+ }
403
+ if (!this.#lastResultUsage) return [];
404
+ return [
405
+ {
406
+ provider: this.#lastResultProvider ?? this.#provider,
407
+ model: this.#lastResultModel ?? this.#model,
408
+ usage: cloneUsage(this.#lastResultUsage),
409
+ },
410
+ ];
411
+ }
412
+
413
+ #normalizeUsage(raw) {
414
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
415
+ this.#fail(
416
+ new TeamAgentStreamError(
417
+ "TEAM_AGENT_STREAM_INVALID_USAGE",
418
+ `Invalid usage object in teammate stream at line ${this.#lineNumber}`,
419
+ { line: this.#lineNumber },
420
+ ),
421
+ );
422
+ }
423
+
424
+ const usage = emptyUsage();
425
+ for (const key of USAGE_KEYS) {
426
+ const rawValue = raw[key];
427
+ if (rawValue == null) continue;
428
+ if (
429
+ (typeof rawValue !== "number" && typeof rawValue !== "string") ||
430
+ rawValue === ""
431
+ ) {
432
+ this.#invalidUsageField(key);
433
+ }
434
+ const value = Number(rawValue);
435
+ if (!Number.isSafeInteger(value) || value < 0) {
436
+ this.#invalidUsageField(key);
437
+ }
438
+ usage[key] = value;
439
+ }
440
+ return usage;
441
+ }
442
+
443
+ #invalidUsageField(field) {
444
+ this.#fail(
445
+ new TeamAgentStreamError(
446
+ "TEAM_AGENT_STREAM_INVALID_USAGE",
447
+ `Invalid ${field} in teammate stream at line ${this.#lineNumber}`,
448
+ { line: this.#lineNumber, field },
449
+ ),
450
+ );
451
+ }
452
+
453
+ #copySummary() {
454
+ return {
455
+ provider: this.#finalSummary.provider,
456
+ model: this.#finalSummary.model,
457
+ usage: cloneUsage(this.#finalSummary.usage),
458
+ usageRecords: cloneUsageRecords(this.#finalSummary.usageRecords),
459
+ terminalResult: this.#finalSummary.terminalResult,
460
+ };
461
+ }
462
+
463
+ #fail(error) {
464
+ this.#lineChunks = [];
465
+ this.#lineBytes = 0;
466
+ this.#failed = error;
467
+ throw error;
468
+ }
469
+ }
470
+
471
+ /**
472
+ * Parse a complete string/buffer or a synchronous iterable of chunks.
473
+ *
474
+ * @returns {TeamAgentStreamSummary}
475
+ */
476
+ export function parseTeamAgentStream(input, options = {}) {
477
+ const parser = new TeamAgentStreamParser(options);
478
+ if (
479
+ typeof input === "string" ||
480
+ Buffer.isBuffer(input) ||
481
+ input instanceof Uint8Array
482
+ ) {
483
+ parser.push(input);
484
+ } else if (input != null) {
485
+ for (const chunk of input) parser.push(chunk);
486
+ }
487
+ return parser.finish();
488
+ }