@wrongstack/core 0.313.1 → 0.316.2

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 (290) hide show
  1. package/dist/chronicle/index.js +31 -31
  2. package/dist/chronicle/legacy-journal-import.d.ts +0 -6
  3. package/dist/chronicle/metrics-ingest.d.ts +14 -0
  4. package/dist/chronicle/metrics-schema.d.ts +10 -1
  5. package/dist/chronicle/metrics-store.d.ts +20 -2
  6. package/dist/chronicle/project-server.js +39 -31
  7. package/dist/chronicle/sink.d.ts +13 -0
  8. package/dist/chronicle/sqlite-journal.d.ts +20 -2
  9. package/dist/{chunk-WOEZV3Q4.js → chunk-25LSLC3G.js} +2 -1
  10. package/dist/{chunk-AI4LLQ2U.js → chunk-27QIURLN.js} +229 -12
  11. package/dist/{chunk-I45KAW2N.js → chunk-3AGWVSS7.js} +38 -450
  12. package/dist/chunk-3BDV7RL3.js +211 -0
  13. package/dist/{chunk-NFAYHPRH.js → chunk-3ECENVHL.js} +10 -8
  14. package/dist/{chunk-FW5LDDMJ.js → chunk-45WI72ZB.js} +1576 -1156
  15. package/dist/{chunk-AT4V4XGI.js → chunk-4BMVPOHO.js} +539 -313
  16. package/dist/{chunk-YBUJCZ57.js → chunk-4I7HGVVA.js} +17 -5
  17. package/dist/{chunk-JVGPR3TS.js → chunk-4LCZVJVF.js} +7 -55
  18. package/dist/{chunk-4ZHTKJHM.js → chunk-4SJNS7OB.js} +36 -2
  19. package/dist/{chunk-AD7ZFZCS.js → chunk-5BMIE7QG.js} +3 -3
  20. package/dist/{chunk-IQ35HMQL.js → chunk-5YPSXQXM.js} +71 -24
  21. package/dist/chunk-6FHWXLPT.js +10 -0
  22. package/dist/{chunk-FIV4IJL7.js → chunk-6H5GEOET.js} +163 -20
  23. package/dist/{chunk-VB3H5WWB.js → chunk-6NWEVFEL.js} +2 -2
  24. package/dist/{chunk-E6I5RXVK.js → chunk-AYW5YINX.js} +2 -2
  25. package/dist/{chunk-DEIQMBD2.js → chunk-B7F4WVP4.js} +2 -2
  26. package/dist/{chunk-XQ2XGIBF.js → chunk-BPBKKBUK.js} +6 -7
  27. package/dist/{chunk-K4YUNKU7.js → chunk-BYD345OX.js} +2 -2
  28. package/dist/{chunk-LZDDLNCZ.js → chunk-C27KDLOX.js} +4 -4
  29. package/dist/{chunk-6AKOTGLM.js → chunk-CU546ESW.js} +7 -7
  30. package/dist/{chunk-ZZ4V3WIZ.js → chunk-DLHHXUAM.js} +10 -1
  31. package/dist/{chunk-BAKVJLEV.js → chunk-DOTHQSJ2.js} +28 -16
  32. package/dist/{chunk-KBZGE6LN.js → chunk-DYLPMV4Q.js} +4 -3
  33. package/dist/{chunk-52RTVH4M.js → chunk-F3JWNST7.js} +2 -2
  34. package/dist/{chunk-WEBMSQP2.js → chunk-FC2ZGRF3.js} +21 -4
  35. package/dist/{chunk-FHAMQS7Q.js → chunk-FCBTO76Z.js} +76 -146
  36. package/dist/{chunk-4LJJYBAU.js → chunk-FHZVFYSL.js} +9 -1
  37. package/dist/{chunk-W4A6QA3D.js → chunk-FWNLEZYG.js} +4 -3
  38. package/dist/{chunk-OJZEX73F.js → chunk-GDQ7CZRQ.js} +5 -1
  39. package/dist/{chunk-QVOVMXJR.js → chunk-GJJGJB2R.js} +32 -9
  40. package/dist/{chunk-4XV6IR37.js → chunk-HI3JGZR2.js} +7 -6
  41. package/dist/{chunk-FSWCWSTS.js → chunk-HMLIGAU7.js} +26 -26
  42. package/dist/{chunk-PFXFQQRT.js → chunk-HXKZ7OBQ.js} +7 -43
  43. package/dist/{chunk-2FQL4PDC.js → chunk-I7DALG7J.js} +5 -5
  44. package/dist/{chunk-GM54GJBU.js → chunk-IRUTEHCE.js} +3 -3
  45. package/dist/{chunk-TYW2GI5I.js → chunk-J2WRWR37.js} +40 -13
  46. package/dist/{chunk-ZEHUCJHY.js → chunk-JFPJ6LLQ.js} +2 -2
  47. package/dist/chunk-JMULFFLN.js +9 -0
  48. package/dist/{chunk-RD6DEE36.js → chunk-JO4MGB6Z.js} +94 -8
  49. package/dist/{chunk-5DSMEVA4.js → chunk-K6BXGITA.js} +7 -7
  50. package/dist/{chunk-O74MJHXU.js → chunk-KZMSZV32.js} +2 -2
  51. package/dist/{chunk-GFJOMSHG.js → chunk-LA7CLDRW.js} +6 -2
  52. package/dist/{chunk-M2WF6AXG.js → chunk-LSMMOS2Z.js} +7 -3
  53. package/dist/{chunk-ASX6AW36.js → chunk-LXWCMQNJ.js} +3 -3
  54. package/dist/{chunk-WZO23AWO.js → chunk-M27LIEKV.js} +72 -22
  55. package/dist/{chunk-JTHKOYWU.js → chunk-MJPHJRAL.js} +15 -15
  56. package/dist/{chunk-G5AAKEEZ.js → chunk-MTL4O5YR.js} +5 -5
  57. package/dist/chunk-NHJ75HXY.js +1 -0
  58. package/dist/{chunk-ZYU2YOJ6.js → chunk-NIOAGFPB.js} +29 -15
  59. package/dist/{chunk-Y2GE5TSI.js → chunk-NS52ISWS.js} +2 -2
  60. package/dist/{chunk-UIWONWVG.js → chunk-NSOFPKGT.js} +541 -148
  61. package/dist/{chunk-RCQYT2I4.js → chunk-NVIZG63R.js} +2 -2
  62. package/dist/{chunk-EPC3GZD4.js → chunk-OOYZPOXM.js} +2 -2
  63. package/dist/{chunk-7ZHZE5EO.js → chunk-OSGLYW5J.js} +2 -2
  64. package/dist/{chunk-CE4ZOCOI.js → chunk-PFCMSSUF.js} +9 -9
  65. package/dist/{chunk-GFXZTHNI.js → chunk-PGRVXIMY.js} +5 -5
  66. package/dist/{chunk-JJPMWPB6.js → chunk-PISBFBJN.js} +6 -6
  67. package/dist/chunk-POOOIWE5.js +9 -0
  68. package/dist/{chunk-5RP3QTRL.js → chunk-PQNS3U7Z.js} +20 -3
  69. package/dist/{chunk-3E244UDA.js → chunk-QSTSJOCK.js} +52 -6
  70. package/dist/{chunk-YUPMXOGP.js → chunk-RFQMOKWK.js} +3 -3
  71. package/dist/chunk-RTOTNK3P.js +484 -0
  72. package/dist/{chunk-SN2DQRL6.js → chunk-RXKSDUAU.js} +7 -7
  73. package/dist/{chunk-T3KGZBU5.js → chunk-S45JPKQN.js} +189 -43
  74. package/dist/{chunk-YNCVSFGF.js → chunk-SAFHACFA.js} +4 -1
  75. package/dist/{chunk-KI4L2DUL.js → chunk-TCCHINEF.js} +114 -19
  76. package/dist/{chunk-AWNQ6ED6.js → chunk-THEGTRAG.js} +7 -2
  77. package/dist/{chunk-2KKODIQU.js → chunk-TR4LQE7L.js} +15 -15
  78. package/dist/{chunk-GPQ3NJPR.js → chunk-TWJMGXCI.js} +3 -3
  79. package/dist/{chunk-H72H4XDU.js → chunk-U45AXT5D.js} +9 -9
  80. package/dist/{chunk-62V2AFVG.js → chunk-U4FWBSO3.js} +160 -73
  81. package/dist/{chunk-A455ATZB.js → chunk-UBGDX6FI.js} +8 -1
  82. package/dist/chunk-UJILKYES.js +75 -0
  83. package/dist/{chunk-KSJ5UTP7.js → chunk-ULMAQV3T.js} +84 -4
  84. package/dist/{chunk-CB2HFKTP.js → chunk-VVBP6KGT.js} +1 -1
  85. package/dist/{chunk-RPOA7IAE.js → chunk-W5VITDM2.js} +43 -25
  86. package/dist/{chunk-QRTG4XTI.js → chunk-WAHQVNWT.js} +7 -1
  87. package/dist/{chunk-SQP64RCS.js → chunk-WGGYRBXH.js} +3019 -2976
  88. package/dist/{chunk-K3G6JBUC.js → chunk-WLYKU45P.js} +679 -141
  89. package/dist/chunk-WP7BVANJ.js +53 -0
  90. package/dist/{chunk-GAZEWQEZ.js → chunk-XF4VUMKW.js} +2 -2
  91. package/dist/{chunk-PAAWLLZX.js → chunk-Y5YXDM7D.js} +2 -2
  92. package/dist/{chunk-65RDIOR2.js → chunk-YOPAUVU4.js} +162 -44
  93. package/dist/{chunk-FFSX2QDQ.js → chunk-YPT4A46F.js} +3 -3
  94. package/dist/chunk-YWXT3JNM.js +425 -0
  95. package/dist/{chunk-EFEHDQGY.js → chunk-ZHZ2Y2DH.js} +64 -10
  96. package/dist/{chunk-CQQL4ZOQ.js → chunk-ZT7JNIGX.js} +4 -3
  97. package/dist/coordination/agent-monitor.d.ts +9 -1
  98. package/dist/coordination/agent-subagent-runner.d.ts +1 -1
  99. package/dist/coordination/agents/agent-prompts.d.ts +8 -0
  100. package/dist/coordination/agents/index.d.ts +33 -1
  101. package/dist/coordination/agents/index.js +52 -22
  102. package/dist/coordination/agents/phase3-wave1-platform.d.ts +1 -3
  103. package/dist/coordination/agents/phase3-wave2-meta.d.ts +1 -3
  104. package/dist/coordination/agents/phase8-wave3-products.d.ts +1 -3
  105. package/dist/coordination/agents/phase9-wave4-platform-meta.d.ts +1 -3
  106. package/dist/coordination/agents/project-agent-identity.d.ts +11 -11
  107. package/dist/coordination/agents/types.d.ts +13 -2
  108. package/dist/coordination/brain-monitor.d.ts +30 -7
  109. package/dist/coordination/collab-debug.d.ts +1 -1
  110. package/dist/coordination/collab-pause.d.ts +1 -1
  111. package/dist/coordination/delegate-tool.d.ts +7 -5
  112. package/dist/coordination/director-kanban-queue-helpers.d.ts +1 -0
  113. package/dist/coordination/director-options.d.ts +7 -0
  114. package/dist/coordination/director-spawn-model.d.ts +17 -0
  115. package/dist/coordination/director-tools.d.ts +2 -2
  116. package/dist/coordination/director.d.ts +12 -0
  117. package/dist/coordination/dispatcher.d.ts +8 -0
  118. package/dist/coordination/fleet-bus.d.ts +35 -4
  119. package/dist/coordination/fleet-supervisor.d.ts +10 -2
  120. package/dist/coordination/fleet.d.ts +16 -7
  121. package/dist/coordination/index.d.ts +4 -0
  122. package/dist/coordination/index.js +86 -49
  123. package/dist/coordination/kanban-dispatch-port.d.ts +2 -2
  124. package/dist/coordination/mailbox-http-router.d.ts +4 -3
  125. package/dist/coordination/mailbox-http-validation.d.ts +1 -1
  126. package/dist/coordination/mailbox-project-server.js +15 -15
  127. package/dist/coordination/mailbox-types.d.ts +24 -6
  128. package/dist/coordination/model-tier-leader.d.ts +122 -0
  129. package/dist/coordination/model-tier.d.ts +122 -0
  130. package/dist/coordination/multi-agent-coordinator.d.ts +24 -0
  131. package/dist/coordination/origin-session.d.ts +16 -0
  132. package/dist/coordination/provider-status-tracker.d.ts +37 -5
  133. package/dist/coordination/session-note-hub.d.ts +44 -0
  134. package/dist/coordination/session-note-tool.d.ts +10 -0
  135. package/dist/core/agent.d.ts +1 -1
  136. package/dist/core/context.d.ts +22 -3
  137. package/dist/core/index.d.ts +2 -0
  138. package/dist/core/index.js +130 -38
  139. package/dist/core/request-conversation-binding.d.ts +37 -0
  140. package/dist/core/session-notes.d.ts +25 -0
  141. package/dist/core/system-prompt-builder.d.ts +11 -2
  142. package/dist/core/system-prompt-variants.d.ts +78 -0
  143. package/dist/design/index.js +3 -3
  144. package/dist/execution/auto-compaction-middleware.d.ts +11 -0
  145. package/dist/execution/autonomy-brain.d.ts +2 -1
  146. package/dist/execution/autonomy-prompt-contributor.d.ts +7 -2
  147. package/dist/execution/compaction-core.d.ts +4 -4
  148. package/dist/execution/eternal-autonomy.d.ts +1 -1
  149. package/dist/execution/index.js +138 -129
  150. package/dist/execution/model-runtime.d.ts +0 -7
  151. package/dist/execution/parallel-eternal-engine.d.ts +7 -7
  152. package/dist/extension/index.js +3 -3
  153. package/dist/goal/index.js +6 -6
  154. package/dist/hooks/index.js +3 -3
  155. package/dist/hq/index.js +14 -12
  156. package/dist/hq/persistence/event-log.d.ts +0 -1
  157. package/dist/hq/persistence.d.ts +4 -4
  158. package/dist/hq/publisher.d.ts +2 -0
  159. package/dist/index.d.ts +14 -11
  160. package/dist/index.js +728 -635
  161. package/dist/infrastructure/index.d.ts +4 -4
  162. package/dist/infrastructure/index.js +281 -260
  163. package/dist/infrastructure/token-counter.d.ts +9 -0
  164. package/dist/kernel/events/agent-events.d.ts +77 -3
  165. package/dist/kernel/events/brain-events.d.ts +12 -0
  166. package/dist/kernel/events/provider-events.d.ts +7 -1
  167. package/dist/kernel/events/session-events.d.ts +14 -0
  168. package/dist/kernel/events/tool-events.d.ts +13 -0
  169. package/dist/kernel/index.js +4 -4
  170. package/dist/mailbox-attach.d.ts +1 -1
  171. package/dist/models/index.js +10 -9
  172. package/dist/observability/event-bridge.d.ts +25 -5
  173. package/dist/observability/index.d.ts +9 -8
  174. package/dist/observability/index.js +459 -351
  175. package/dist/observability/tool-usage-source.d.ts +65 -0
  176. package/dist/plugin/index.d.ts +5 -0
  177. package/dist/plugin/index.js +66 -50
  178. package/dist/plugins/auto-review-plugin.d.ts +3 -2
  179. package/dist/plugins/review-finding-commands.d.ts +0 -8
  180. package/dist/{review-finding-store-DKAV3AS6.js → plugins/review-finding-store.js} +7 -6
  181. package/dist/plugins/review-finding-types.js +19 -0
  182. package/dist/plugins/review-report-integration.js +21 -0
  183. package/dist/{review-report-store-OWY3EC3N.js → plugins/review-report-store.js} +7 -6
  184. package/dist/plugins/review-report-types.js +13 -0
  185. package/dist/prompts/index.js +5 -5
  186. package/dist/registry/index.js +3 -3
  187. package/dist/registry/tool-registry.d.ts +59 -9
  188. package/dist/{registry-R23UBE7H.js → registry-7N4O3E7W.js} +5 -5
  189. package/dist/security/capabilities.d.ts +6 -0
  190. package/dist/security/file-permissions.d.ts +1 -1
  191. package/dist/security/index.js +47 -33
  192. package/dist/security/permission-policy.d.ts +12 -1
  193. package/dist/security/secret-scrubber.d.ts +15 -0
  194. package/dist/session-catalog/index.d.ts +1 -0
  195. package/dist/session-catalog/index.js +19 -14
  196. package/dist/session-catalog/project-server.js +30 -13
  197. package/dist/session-catalog/protocol.d.ts +32 -1
  198. package/dist/session-catalog/registry.d.ts +17 -1
  199. package/dist/session-catalog/session-agents.d.ts +56 -0
  200. package/dist/session-catalog/store-rebuild.d.ts +14 -0
  201. package/dist/session-catalog/store-schema.d.ts +26 -0
  202. package/dist/session-catalog/store.d.ts +27 -1
  203. package/dist/session-note-attach.d.ts +9 -0
  204. package/dist/skills/index.js +5 -5
  205. package/dist/statusline/index.d.ts +43 -0
  206. package/dist/statusline/index.js +102 -0
  207. package/dist/storage/board-store-port.d.ts +2 -2
  208. package/dist/storage/config-loader/in-project-policy.d.ts +29 -0
  209. package/dist/storage/config-loader.d.ts +3 -2
  210. package/dist/storage/file-session-writer.d.ts +4 -2
  211. package/dist/storage/goal-coordination.d.ts +6 -1
  212. package/dist/storage/goal-kanban.d.ts +4 -1
  213. package/dist/storage/index.d.ts +12 -4
  214. package/dist/storage/index.js +76 -61
  215. package/dist/storage/input-history-store.d.ts +2 -4
  216. package/dist/storage/memory-curator.d.ts +133 -0
  217. package/dist/storage/session-agent-attribution.d.ts +39 -0
  218. package/dist/storage/session-doctor.d.ts +109 -0
  219. package/dist/storage/session-event-bridge.d.ts +5 -7
  220. package/dist/storage/session-outcome.d.ts +42 -0
  221. package/dist/storage/session-recovery.d.ts +55 -0
  222. package/dist/storage/session-store/load-session-data.d.ts +11 -0
  223. package/dist/storage/session-store/prune-helpers.d.ts +1 -1
  224. package/dist/storage/session-store/resume-session.d.ts +0 -2
  225. package/dist/storage/session-store/types.d.ts +8 -0
  226. package/dist/storage/session-store.d.ts +3 -3
  227. package/dist/storage/session-summary-tracker.d.ts +8 -1
  228. package/dist/storage/session-write-buffer.d.ts +18 -0
  229. package/dist/storage/session-writer-truncate.d.ts +2 -0
  230. package/dist/tasking/index.js +2 -2
  231. package/dist/tools/fallback-manage-tools.d.ts +6 -4
  232. package/dist/tools/index.js +21 -21
  233. package/dist/tools/model-tier-set-tool.d.ts +66 -0
  234. package/dist/types/agent-bridge.d.ts +2 -1
  235. package/dist/types/config/mcp-features.d.ts +7 -0
  236. package/dist/types/config/model-tiers.d.ts +148 -0
  237. package/dist/types/config/root.d.ts +9 -0
  238. package/dist/types/config/tools.d.ts +73 -0
  239. package/dist/types/config.d.ts +1 -0
  240. package/dist/types/context.d.ts +2 -0
  241. package/dist/types/default-config.d.ts +6 -0
  242. package/dist/types/errors.d.ts +2 -1
  243. package/dist/types/index.d.ts +11 -9
  244. package/dist/types/index.js +25 -15
  245. package/dist/types/multi-agent.d.ts +43 -0
  246. package/dist/types/plugin.d.ts +1 -1
  247. package/dist/types/provider.d.ts +15 -0
  248. package/dist/types/runtime-capability-manifest.d.ts +1 -1
  249. package/dist/types/secret-scrubber.d.ts +15 -0
  250. package/dist/types/session-markers.d.ts +37 -10
  251. package/dist/types/session-markers.js +1 -1
  252. package/dist/types/session-timeline.d.ts +197 -0
  253. package/dist/types/session-timeline.js +12 -0
  254. package/dist/types/session.d.ts +172 -11
  255. package/dist/types/system-prompt.d.ts +27 -0
  256. package/dist/utils/config-backup.d.ts +9 -1
  257. package/dist/utils/heap-watchdog.js +2 -2
  258. package/dist/utils/index.js +50 -48
  259. package/dist/utils/message-invariants.d.ts +4 -1
  260. package/dist/utils/regex-guard.d.ts +1 -1
  261. package/dist/utils/socket-path.d.ts +1 -1
  262. package/dist/utils/token-estimate.d.ts +6 -2
  263. package/dist/utils/wstack-paths.d.ts +2 -0
  264. package/dist/wiring/proxy-rewrite.d.ts +28 -0
  265. package/dist/wiring/proxy-rewrite.js +7 -1
  266. package/dist/worktree/index.js +2 -2
  267. package/instructions/agents/explore-companion.md +45 -18
  268. package/instructions/agents/memory-curator.md +34 -22
  269. package/instructions/coordination/director-preamble.md +12 -7
  270. package/instructions/coordination/subagent-baseline.md +26 -5
  271. package/instructions/leader-after-task.md +4 -1
  272. package/instructions/llm/chimera-review.md +30 -9
  273. package/instructions/llm/memory-curator.md +31 -0
  274. package/instructions/sections/tool/delegation-compact.md +2 -0
  275. package/instructions/sections/tool/delegation-full.md +5 -1
  276. package/instructions/sections/tool/mailbox-compact.md +5 -1
  277. package/instructions/sections/tool/mailbox-full.md +3 -0
  278. package/instructions/sections/tool/session-note-compact.md +3 -0
  279. package/instructions/sections/tool/session-note-full.md +15 -0
  280. package/instructions/system-lite.md +9 -4
  281. package/instructions/system-pro.md +66 -143
  282. package/instructions/system.md +73 -175
  283. package/package.json +33 -5
  284. package/dist/chunk-2BUUIMQB.js +0 -225
  285. package/dist/chunk-FAYRX2AD.js +0 -13
  286. package/dist/chunk-H5E77KUJ.js +0 -15
  287. package/dist/chunk-M7BS2K6U.js +0 -1
  288. package/dist/coordination/agents.d.ts +0 -8
  289. package/dist/coordination/transport.d.ts +0 -2
  290. package/dist/storage/session-writer/session-writer-summary-tracker.d.ts +0 -28
@@ -82,6 +82,24 @@ export interface SubagentConfig {
82
82
  * caller input so a model cannot forge a shallower depth or larger budget.
83
83
  */
84
84
  spawnLineage?: SubagentSpawnLineage | undefined;
85
+ /**
86
+ * The conversation that ASKED for this spawn.
87
+ *
88
+ * The coordinator otherwise stamps a new worker with "which session is the
89
+ * host on right now", read from the host's own writer. In a single-session
90
+ * CLI those are the same answer. With four WebUI tabs sharing one process
91
+ * they are not: the host writer stays pinned to the boot tab, so every
92
+ * worker spawned from tabs 2-4 was filed under tab 1 — its lifecycle,
93
+ * budget and context events surfaced in the wrong roster, its spend was
94
+ * charged to the wrong conversation, and `stopSession` could not find it
95
+ * because nothing recorded who it belonged to.
96
+ *
97
+ * Set by the tools that spawn on an agent's behalf, from the run-pinned
98
+ * session of the caller. Absent (a host spawning for itself) the
99
+ * coordinator's live reading stands, which is what single-session hosts
100
+ * have always used.
101
+ */
102
+ originSessionId?: string | undefined;
85
103
  /**
86
104
  * Working directory for this subagent's tools. Defaults to the factory's
87
105
  * cwd. Goal sets this to a per-phase git worktree so parallel phases
@@ -116,6 +134,21 @@ export interface SubagentConfig {
116
134
  * → the factory's own default fallback behavior (usually the leader's config).
117
135
  */
118
136
  fallbackModels?: string[] | undefined;
137
+ /**
138
+ * Deterministic model tier for this subagent ('budget' | 'standard' |
139
+ * 'premium', or any user-defined level). Resolved at spawn time into a
140
+ * fallback profile, a budget, and runtime overrides. A tier only FILLS IN
141
+ * fields left unset — an explicit provider/model always wins over it.
142
+ */
143
+ tier?: string | undefined;
144
+ /**
145
+ * Budget field names the CALLER pinned explicitly (e.g. `delegate({ maxCostUsd })`).
146
+ * The tier layer never touches a pinned field: a number the user typed is a
147
+ * decision, while a roster default is just a default. Without this marker the
148
+ * two are indistinguishable at spawn time, because `applyRosterBudget` has
149
+ * already populated every budget field by then.
150
+ */
151
+ budgetPins?: readonly string[] | undefined;
119
152
  /**
120
153
  * Named live fallback profile for this subagent. Unlike `fallbackModels`, the
121
154
  * factory re-resolves this profile from ConfigStore on every provider attempt,
@@ -493,6 +526,16 @@ export interface SubagentRunContext {
493
526
  config: SubagentConfig;
494
527
  budget: SubagentBudget;
495
528
  signal: AbortSignal;
529
+ /**
530
+ * The session that spawned this subagent, fixed at spawn time.
531
+ *
532
+ * A worker belongs to one session for its whole life. Runners must stamp
533
+ * their events with THIS rather than re-reading the host's current session:
534
+ * with four tabs live, the host's session moves whenever the user switches
535
+ * tabs, and a late-firing event would then be filed under whichever tab
536
+ * happened to be in front.
537
+ */
538
+ sessionId?: string | undefined;
496
539
  /** Null until `setSubagentBridge` is called for this subagent. */
497
540
  bridge: AgentBridge | null;
498
541
  /** Publish a bounded in-memory snapshot that survives timeout races. */
@@ -1,7 +1,7 @@
1
1
  import type { Mailbox } from '../coordination/mailbox-types.js';
2
2
  import type { Notifier } from '../notifications/notifier.js';
3
3
  export type { Notifier };
4
- import type { ToolCallPipelinePayload } from '../core/agent.js';
4
+ import type { ToolCallPipelinePayload } from '../core/agent-types.js';
5
5
  import type { AgentContext } from './context.js';
6
6
  import type { ExtensionRegistry } from '../extension/registry.js';
7
7
  import type { Container } from '../kernel/container.js';
@@ -103,6 +103,21 @@ export interface Usage {
103
103
  export declare function effectiveInputTokens(usage: Usage): number;
104
104
  /** Prompt tokens that were not served by a cache read. */
105
105
  export declare function freshInputTokens(usage: Usage): number;
106
+ /**
107
+ * Every token this request moved — the complete prompt the model loaded plus
108
+ * what it generated.
109
+ *
110
+ * The single definition of `SessionSummary.tokenTotal`. Three call sites
111
+ * compute that field (the live writer's tracker, the disk-rebuild summary
112
+ * builder, and the SQLite catalog's transcript summarizer) and they had
113
+ * drifted: two summed only `input + output` while the third also counted the
114
+ * cache buckets. With prompt caching on, `cacheRead` is the bulk of a real
115
+ * prompt, so the narrow reading under-reported long sessions by more than an
116
+ * order of magnitude — one measured session listed 118,719 tokens against an
117
+ * actual 2,466,978. Route every tokenTotal through here so the three cannot
118
+ * disagree again.
119
+ */
120
+ export declare function totalUsageTokens(usage: Usage): number;
106
121
  /**
107
122
  * Cache-read share of the complete prompt context, normalized to [0, 1].
108
123
  *
@@ -69,7 +69,7 @@ export declare const RUNTIME_CAPABILITY_MANIFEST: readonly [{
69
69
  readonly id: 'coordination.mailbox';
70
70
  readonly pack: 'fleet';
71
71
  readonly exposure: 'direct';
72
- readonly tools: readonly ["mailbox", "mail_send", "mail_inbox", "fleet_status"];
72
+ readonly tools: readonly ["mailbox", "mail_send", "mail_inbox", "fleet_status", "session_note"];
73
73
  }, {
74
74
  readonly id: 'fleet.delegate';
75
75
  readonly pack: 'fleet';
@@ -1,5 +1,20 @@
1
1
  export interface SecretScrubber {
2
2
  scrub(text: string): string;
3
3
  scrubObject<T>(obj: T): T;
4
+ /**
5
+ * Same redaction as {@link scrubObject}, but the result MAY SHARE structure
6
+ * with the input: any subtree that needed no redaction is returned by
7
+ * reference instead of being rebuilt.
8
+ *
9
+ * Only call this on a graph you exclusively own and will not mutate — a
10
+ * freshly `JSON.parse`d journal line, say. On anything still referenced
11
+ * elsewhere (a live conversation message queued for an async write), the
12
+ * shared subtrees would alias state that can still change underneath the
13
+ * consumer; use {@link scrubObject} there.
14
+ *
15
+ * Optional so existing implementations (and the object literals tests hand
16
+ * in) stay valid; callers fall back to {@link scrubObject}.
17
+ */
18
+ scrubObjectShared?<T>(obj: T): T;
4
19
  }
5
20
  //# sourceMappingURL=secret-scrubber.d.ts.map
@@ -31,9 +31,40 @@ export interface SessionMarker {
31
31
  source: SessionEvent['type'];
32
32
  level: SessionMarkerLevel;
33
33
  text: string;
34
- /** Set only for the `agent_*` sources. */
34
+ /** Set only for the `agent_*` and `delegate_*` sources. */
35
35
  agentId?: string | undefined;
36
+ /**
37
+ * The source event's own fields, for the sources a surface renders as
38
+ * something richer than a line of text.
39
+ *
40
+ * `text` stays the fallback every surface can always use. But the TUI draws
41
+ * a delegation as a labelled subagent row with its own icon, colour and
42
+ * compact stat line, and the WebUI as a two-line assistant message — both
43
+ * built from the structured payload, live. Handing replay only the rendered
44
+ * sentence would have forced those surfaces to show something they never
45
+ * showed while running, which is the exact divergence this module exists to
46
+ * prevent. Kept to the few sources that need it, and JSON-serializable so it
47
+ * survives the wire alongside the rest of the marker.
48
+ */
49
+ detail?: SessionMarkerDetail | undefined;
36
50
  }
51
+ /** Structured payload for the marker sources whose surfaces render richly. */
52
+ export type SessionMarkerDetail = {
53
+ kind: 'delegate_started';
54
+ target: string;
55
+ task: string;
56
+ } | {
57
+ kind: 'delegate_completed';
58
+ target: string;
59
+ task: string;
60
+ ok: boolean;
61
+ status?: string | undefined;
62
+ summary: string;
63
+ durationMs: number;
64
+ iterations: number;
65
+ toolCalls: number;
66
+ costUsd?: number | undefined;
67
+ };
37
68
  /**
38
69
  * Every event type that projects to a marker. Conversation-bearing events
39
70
  * (`user_input`, `llm_response`, `tool_*`) are deliberately excluded — those
@@ -41,15 +72,6 @@ export interface SessionMarker {
41
72
  * `message_appended` journal replay identically.
42
73
  */
43
74
  export declare const SESSION_MARKER_EVENT_TYPES: ReadonlySet<SessionEvent['type']>;
44
- /**
45
- * The subset chat-shaped surfaces (WebUI, SimpleUI, HQ Live Console) render.
46
- *
47
- * `checkpoint` is excluded: one is written per user prompt
48
- * (`agent-loop.ts` → `writeCheckpoint`), so in a chat transcript it would be a
49
- * line restating the user message immediately next to it. Dense timeline
50
- * surfaces like the TUI use {@link SESSION_MARKER_EVENT_TYPES} instead, where
51
- * the checkpoint marker doubles as a `/rewind` target hint.
52
- */
53
75
  export declare const CHAT_MARKER_SOURCES: ReadonlySet<SessionEvent['type']>;
54
76
  /**
55
77
  * Project one session event to a marker, or `null` when the event carries no
@@ -69,6 +91,11 @@ export declare function projectSessionMarkers(events: readonly SessionEvent[], s
69
91
  * as `user`/`system`-role messages by the agent loop at runtime (mailbox,
70
92
  * fleet pulse, loop detector, resume validation notices) but should NOT appear
71
93
  * in the human-facing chat history on session resume/replay.
94
+ *
95
+ * Also covers routing-noise error bubbles that the WebUI client has already
96
+ * swallowed live (`handleError` drops them) but that earlier turns may have
97
+ * persisted to the on-disk transcript — replay must not resurrect them into
98
+ * the human-visible chat.
72
99
  */
73
100
  export declare const SYSTEM_INJECTION_PREFIXES: readonly string[];
74
101
  /**
@@ -5,7 +5,7 @@ import {
5
5
  isSystemInjectedMessage,
6
6
  projectSessionMarkers,
7
7
  sessionEventToMarker
8
- } from "../chunk-KSJ5UTP7.js";
8
+ } from "../chunk-ULMAQV3T.js";
9
9
  export {
10
10
  CHAT_MARKER_SOURCES,
11
11
  SESSION_MARKER_EVENT_TYPES,
@@ -0,0 +1,197 @@
1
+ import type { Message } from './messages.js';
2
+ import { type SessionMarker, type SessionMarkerDetail } from './session-markers.js';
3
+ import type { SessionEvent } from './session.js';
4
+ /** An image the user attached to a prompt, as it survives in the journal. */
5
+ export interface SessionTimelineImage {
6
+ mediaType?: string | undefined;
7
+ /** Base64 payload, when the block carried one. */
8
+ data?: string | undefined;
9
+ /** Remote URL, when the block referenced one instead. */
10
+ url?: string | undefined;
11
+ }
12
+ /**
13
+ * Tool-call metadata that lives in `tool_call_end` events rather than in the
14
+ * conversation.
15
+ *
16
+ * The message journal records WHICH tool ran with WHICH arguments and WHAT it
17
+ * returned; how long it took and how much it produced is audit detail, in a
18
+ * separate event keyed by the same `tool_use` id. The TUI reads both because
19
+ * it holds the raw event array; the browser surfaces are handed a projection
20
+ * over the wire, so this is the shape that projection carries.
21
+ */
22
+ export interface SessionToolMeta {
23
+ /** The `tool_use` id this describes. */
24
+ id: string;
25
+ name?: string | undefined;
26
+ durationMs?: number | undefined;
27
+ outputBytes?: number | undefined;
28
+ outputTokens?: number | undefined;
29
+ outputLines?: number | undefined;
30
+ ok?: boolean | undefined;
31
+ /** Subagent that ran the tool; absent = the session's leader. */
32
+ agentId?: string | undefined;
33
+ }
34
+ interface TimelineEntryBase {
35
+ ts: string;
36
+ }
37
+ export interface SessionTimelineUserEntry extends TimelineEntryBase {
38
+ kind: 'user';
39
+ text: string;
40
+ /** Present only when the prompt carried image blocks. */
41
+ images?: SessionTimelineImage[] | undefined;
42
+ }
43
+ export interface SessionTimelineAssistantEntry extends TimelineEntryBase {
44
+ kind: 'assistant';
45
+ text: string;
46
+ /**
47
+ * True when this prose ended its turn. A message carrying a `tool_use` block
48
+ * stopped for a tool call, so its text is mid-turn — the surfaces use this to
49
+ * decide whether a `<nextsteps>` panel may appear.
50
+ */
51
+ final: boolean;
52
+ }
53
+ /** A conversation message with `role: 'system'` — resume notices and the like. */
54
+ export interface SessionTimelineSystemEntry extends TimelineEntryBase {
55
+ kind: 'system';
56
+ text: string;
57
+ }
58
+ export interface SessionTimelineThinkingEntry extends TimelineEntryBase {
59
+ kind: 'thinking';
60
+ text: string;
61
+ /** 1-based ordinal across the whole timeline; surfaces label iterations with it. */
62
+ index: number;
63
+ }
64
+ export interface SessionTimelineToolEntry extends TimelineEntryBase {
65
+ kind: 'tool';
66
+ /** The provider's `tool_use` id, or the `tool_result`'s id for an orphan result. */
67
+ toolUseId: string;
68
+ name: string;
69
+ input?: unknown;
70
+ /** Untruncated result body. Surfaces decide their own preview length. */
71
+ output?: string | undefined;
72
+ /**
73
+ * `undefined` while a call has no result in the journal — the run was still
74
+ * executing it when the process stopped. A surface renders that as "running"
75
+ * or "interrupted"; it is NOT a failure, and reporting it as one is what the
76
+ * SimpleUI replay used to do.
77
+ */
78
+ ok?: boolean | undefined;
79
+ durationMs?: number | undefined;
80
+ outputBytes?: number | undefined;
81
+ outputTokens?: number | undefined;
82
+ outputLines?: number | undefined;
83
+ agentId?: string | undefined;
84
+ }
85
+ export interface SessionTimelineMarkerEntry extends TimelineEntryBase {
86
+ kind: 'marker';
87
+ source: SessionEvent['type'];
88
+ level: SessionMarker['level'];
89
+ text: string;
90
+ agentId?: string | undefined;
91
+ /** See {@link SessionMarker.detail} — structured fields for rich sources. */
92
+ detail?: SessionMarkerDetail | undefined;
93
+ }
94
+ export type SessionTimelineEntry = SessionTimelineUserEntry | SessionTimelineAssistantEntry | SessionTimelineSystemEntry | SessionTimelineThinkingEntry | SessionTimelineToolEntry | SessionTimelineMarkerEntry;
95
+ /**
96
+ * Where a message's thinking blocks land relative to its prose.
97
+ *
98
+ * Not a style choice — it is what the surface did LIVE, and resume has to
99
+ * match the surface it is resuming into:
100
+ *
101
+ * - `'inline'` — one entry per thinking block, before the prose, in provider
102
+ * block order. The TUI and SimpleUI stream thinking as it arrives and leave
103
+ * it where it fell.
104
+ * - `'merged-after'` — one entry per message, carrying every thinking block
105
+ * joined, emitted after that message's prose and tool calls. The WebUI keeps
106
+ * a transient thinking bubble during a run and only commits the archived log
107
+ * when the iteration completes, which is after the prose is on screen.
108
+ */
109
+ export type ThinkingPlacement = 'inline' | 'merged-after';
110
+ /**
111
+ * How a message's text blocks relate to the tool calls between them.
112
+ *
113
+ * Again a record of what the surface did LIVE, not a preference:
114
+ *
115
+ * - `'split'` — a text run becomes its own entry wherever a tool interrupts
116
+ * it, so prose that followed a tool stays after that tool. The TUI and the
117
+ * WebUI render a fresh bubble per run.
118
+ * - `'join'` — every text block of a message becomes ONE entry, emitted before
119
+ * the message's tool entries. The SimpleUI streams a whole iteration into a
120
+ * single bubble and lists tool calls beside it, so splitting would invent
121
+ * bubbles that were never on screen.
122
+ */
123
+ export type TextBlockMode = 'split' | 'join';
124
+ export interface ProjectSessionTimelineInput {
125
+ /** The reconstructed conversation, as `SessionStore.load()` rebuilds it. */
126
+ messages: readonly Message[];
127
+ /**
128
+ * Raw journal events. Callers holding the JSONL (the TUI, the servers) pass
129
+ * this and markers/toolMeta are projected from it.
130
+ */
131
+ events?: readonly SessionEvent[] | undefined;
132
+ /** Pre-projected markers, for callers that received them over the wire. */
133
+ markers?: readonly SessionMarker[] | undefined;
134
+ /** Pre-projected tool metadata, for callers that received it over the wire. */
135
+ toolMeta?: readonly SessionToolMeta[] | undefined;
136
+ /**
137
+ * Which event types project to markers. Defaults to the dense
138
+ * {@link SESSION_MARKER_EVENT_TYPES}; chat-shaped surfaces pass
139
+ * `CHAT_MARKER_SOURCES`. Ignored when `markers` is supplied — the sender
140
+ * already applied its own set.
141
+ */
142
+ markerSources?: ReadonlySet<SessionEvent['type']> | undefined;
143
+ /** See {@link ThinkingPlacement}. Defaults to `'inline'`. */
144
+ thinkingPlacement?: ThinkingPlacement | undefined;
145
+ /** See {@link TextBlockMode}. Defaults to `'split'`. */
146
+ textBlocks?: TextBlockMode | undefined;
147
+ /**
148
+ * Glue between adjacent text blocks of one run. Defaults to `''` — the
149
+ * provider already streamed them as one continuous body, and inserting a
150
+ * separator would put a break where the live render had none.
151
+ */
152
+ textSeparator?: string | undefined;
153
+ /**
154
+ * Drop conversation messages the agent loop injected for the model's benefit
155
+ * (mailbox, fleet pulse, loop detector, resume notices). Defaults to true —
156
+ * every surface hides them, and a surface that wants the raw journal should
157
+ * read the events instead.
158
+ */
159
+ hideSystemInjections?: boolean | undefined;
160
+ }
161
+ /** Project the `tool_call_end` records of an event stream, keyed by tool id. */
162
+ export declare function projectSessionToolMeta(events: Iterable<SessionEvent>): SessionToolMeta[];
163
+ /**
164
+ * Size of the LAST prompt this session sent, from its journal.
165
+ *
166
+ * This is the number the context-fill bar means: how full the window was when
167
+ * the conversation last went to the model. Live, `ctx.lastRequestTokens` holds
168
+ * exactly that (the pre-flight total). Every resume path instead reached for
169
+ * `SessionData.usage.input`, which is the SUM of every request the session has
170
+ * ever made — so a long session came back claiming a nine-million-token
171
+ * context on a one-million-token model. Cumulative totals belong in the cost
172
+ * and usage readouts; they are never a fill source.
173
+ *
174
+ * The last `llm_response` carries that request's own usage, and its prompt is
175
+ * everything the provider counted on the way in: fresh input plus whatever it
176
+ * served or wrote through the cache — `effectiveInputTokens` in `provider.ts`,
177
+ * inlined here because this module must stay importable from a browser bundle
178
+ * and that one pulls a value chain behind it. Scanned from the end, so a 100k-
179
+ * event journal costs one step. Returns `undefined` when the session never reached
180
+ * the model — the caller must then leave the estimate unset rather than
181
+ * publish a zero, which reads as "0% full" instead of "not known yet".
182
+ */
183
+ export declare function projectLastRequestTokens(events: readonly SessionEvent[] | undefined): number | undefined;
184
+ /**
185
+ * Merge a session's conversation and audit streams into one ordered timeline.
186
+ *
187
+ * Ordering is a two-pointer merge of two sequences that are each already
188
+ * chronological — the message backbone by construction, the markers by journal
189
+ * order — so the conversation is never reordered: markers are only inserted
190
+ * between existing turns, and a tie keeps the backbone entry first. That is
191
+ * deliberately NOT a sort over the union: message timestamps repeat (every
192
+ * block of one message shares its `ts`), and sorting a repeated key moves tool
193
+ * calls away from the prose they belong to.
194
+ */
195
+ export declare function projectSessionTimeline(input: ProjectSessionTimelineInput): SessionTimelineEntry[];
196
+ export {};
197
+ //# sourceMappingURL=session-timeline.d.ts.map
@@ -0,0 +1,12 @@
1
+ import {
2
+ projectLastRequestTokens,
3
+ projectSessionTimeline,
4
+ projectSessionToolMeta
5
+ } from "../chunk-3BDV7RL3.js";
6
+ import "../chunk-ULMAQV3T.js";
7
+ export {
8
+ projectLastRequestTokens,
9
+ projectSessionTimeline,
10
+ projectSessionToolMeta
11
+ };
12
+ //# sourceMappingURL=session-timeline.js.map
@@ -65,7 +65,28 @@ export interface SessionMetadata {
65
65
  * The only files that live inside the project tree are the committed
66
66
  * `.wrongstack/AGENTS.md` and `.wrongstack/skills/`.
67
67
  */
68
- export type SessionEvent = {
68
+ export type SessionEvent = SessionEventVariant & SessionEventAttribution;
69
+ /**
70
+ * Attribution stamped onto a journal event by the WRITER, never by the
71
+ * producer that built it.
72
+ *
73
+ * A leader's JSONL can carry events produced by its subagents: the
74
+ * parent-interleaved writer (`createParentSubagentSessionWriter`) forwards a
75
+ * subagent's appends into the leader's journal because that subagent has no
76
+ * journal of its own. Without a stamp those appends are indistinguishable
77
+ * from the leader's, so a transcript reader cannot say which agent ran which
78
+ * tool. `withAgentAttribution` sets this at the writer boundary — the one
79
+ * place that knows whose writer it is — so no emit site has to remember.
80
+ *
81
+ * Absent means "the session's own leader". Old journals have no stamp at all,
82
+ * which reads the same way and is correct: they predate subagent interleaving
83
+ * being attributable.
84
+ */
85
+ export interface SessionEventAttribution {
86
+ /** Subagent that produced this event; absent = the session's leader. */
87
+ agentId?: string | undefined;
88
+ }
89
+ type SessionEventVariant = {
69
90
  type: 'session_start';
70
91
  ts: string;
71
92
  id: string;
@@ -105,6 +126,21 @@ export type SessionEvent = {
105
126
  content: ContentBlock[];
106
127
  stopReason: string;
107
128
  usage: Usage;
129
+ /**
130
+ * Model that produced this response and billed this `usage`.
131
+ *
132
+ * Optional because logs written before this field existed omit it —
133
+ * never because a live writer may skip it. `usage` is the only place
134
+ * token counts are journaled, so without these two fields the journal
135
+ * cannot answer "which model burned these tokens": `session_start`
136
+ * records only the model the session OPENED with (a mid-session switch
137
+ * or a fallback rotation leaves it stale), and `llm_request` carries
138
+ * `model` but no provider. Readers must still tolerate `undefined` and
139
+ * fall back to the nearest preceding `llm_request` / `session_start`.
140
+ */
141
+ model?: string | undefined;
142
+ /** Provider id that served this response. See {@link model}. */
143
+ provider?: string | undefined;
108
144
  } | {
109
145
  type: 'tool_use';
110
146
  ts: string;
@@ -250,26 +286,121 @@ export type SessionEvent = {
250
286
  ts: string;
251
287
  agentId: string;
252
288
  role: string;
289
+ } | {
290
+ /**
291
+ * Binds a spawned agent to the transcript it writes into.
292
+ *
293
+ * Separate from `agent_spawned` because the two facts are learned in
294
+ * different places: the fleet layer emits `agent_spawned` once the
295
+ * coordinator hands back an id, while the writer is built one layer
296
+ * down in the subagent factory, which has no channel back to that emit
297
+ * site. Threading one would have changed five signatures for a fact
298
+ * that is naturally its own record — and would still be optional on
299
+ * `agent_spawned`, since an agent running on the parent-interleaved
300
+ * writer never gets a transcript of its own and emits no link at all.
301
+ *
302
+ * Readers join on `agentId` within the session.
303
+ */
304
+ type: 'agent_session_linked';
305
+ ts: string;
306
+ agentId: string;
307
+ /** The subagent journal's own session id. */
308
+ agentSessionId: string;
309
+ /**
310
+ * Absolute path of the subagent's JSONL at the time it was opened.
311
+ * Absent for in-memory writers (tests, ephemeral runs), which have a
312
+ * session id but no file.
313
+ */
314
+ transcriptPath?: string | undefined;
315
+ provider?: string | undefined;
316
+ model?: string | undefined;
317
+ /** Set when this agent was spawned by another agent, not the leader. */
318
+ parentAgentId?: string | undefined;
253
319
  } | {
254
320
  type: 'agent_stopped';
255
321
  ts: string;
256
322
  agentId: string;
323
+ /** Why the agent ended. Absent in journals written before this field. */
324
+ reason?: 'completed' | 'aborted' | 'failed' | 'evicted' | undefined;
325
+ /** This agent's own cumulative spend, when the stopper knows it. */
326
+ usage?: Usage | undefined;
257
327
  } | {
258
328
  type: 'agent_error';
259
329
  ts: string;
260
330
  agentId: string;
261
331
  error: string;
262
332
  } | {
263
- type: 'spec_parsed';
333
+ /**
334
+ * A `delegate` tool call handing work to a subagent.
335
+ *
336
+ * Distinct from `agent_spawned`, which records that an agent exists.
337
+ * This records that the LEADER stopped and waited on it, which is the
338
+ * thing the transcript shows: every surface renders a delegation line
339
+ * live (the TUI even suppresses the generic tool card in its favour),
340
+ * and none of it reached disk — so a resumed session showed a gap where
341
+ * minutes of delegated work had happened.
342
+ */
343
+ type: 'delegate_started';
344
+ ts: string;
345
+ /** Resolved roster role or free-form subagent name. */
346
+ target: string;
347
+ /** The instruction handed to the subagent. */
348
+ task: string;
349
+ subagentId?: string | undefined;
350
+ } | {
351
+ type: 'delegate_completed';
352
+ ts: string;
353
+ target: string;
354
+ task: string;
355
+ ok: boolean;
356
+ /** `success` | `timeout` | `host_timeout` | `stopped` | … */
357
+ status?: string | undefined;
358
+ /** One-line human summary, as the live surfaces render it. */
359
+ summary: string;
360
+ durationMs: number;
361
+ iterations: number;
362
+ toolCalls: number;
363
+ costUsd?: number | undefined;
364
+ subagentId?: string | undefined;
365
+ } | {
366
+ /**
367
+ * The loop detector acted on a repeating run.
368
+ *
369
+ * Only `action: 'cut'` is worth a record: a `steer` is an in-band nudge
370
+ * the model absorbs, while a cut ENDS the turn — and without this the
371
+ * run came back as a bare `max_iterations` with nothing saying why.
372
+ */
373
+ type: 'loop_detected';
264
374
  ts: string;
265
- specId: string;
266
- title: string;
267
- completeness: number;
375
+ /** Comma-separated tool names, or empty for a pure message loop. */
376
+ tools: string;
377
+ repeatCount: number;
378
+ iteration: number;
379
+ kind?: 'tool' | 'message' | 'mixed' | undefined;
380
+ action?: 'steer' | 'cut' | undefined;
268
381
  } | {
269
- type: 'spec_analyzed';
382
+ /**
383
+ * The active provider/model changed mid-session.
384
+ *
385
+ * `reason: 'fallback'` is the automatic switch after a provider failure;
386
+ * `'user'` is an explicit `/model` or UI change. Either way the rest of
387
+ * the transcript was produced by a different model than the one
388
+ * `session_start` names, and a reader with no record of the switch
389
+ * attributes it all to the first one.
390
+ */
391
+ type: 'model_switched';
270
392
  ts: string;
271
- specId: string;
272
- gaps: string[];
393
+ from?: {
394
+ providerId: string;
395
+ model: string;
396
+ } | undefined;
397
+ to: {
398
+ providerId: string;
399
+ model: string;
400
+ };
401
+ reason: 'fallback' | 'user';
402
+ /** HTTP status that triggered an automatic fallback, when there was one. */
403
+ status?: number | undefined;
273
404
  } | {
274
405
  type: 'skill_activated';
275
406
  ts: string;
@@ -530,7 +661,11 @@ export interface SessionData {
530
661
  * in flight (crash/interrupt). Computed during replay BEFORE adjacency
531
662
  * repair strips them. `resume()` surfaces this as an informational notice so
532
663
  * the user/model know work was interrupted; the tools are NOT re-executed.
533
- * Undefined for events-only loads (no message reconstruction).
664
+ *
665
+ * Only present when at least one call was left open: **absent means none**,
666
+ * never zero (see `load-session-data.ts`). It is also absent for
667
+ * events-only loads, which reconstruct no messages to count. Read it as
668
+ * `data.pendingToolUseCount ?? 0` rather than testing for `undefined`.
534
669
  */
535
670
  pendingToolUseCount?: number | undefined;
536
671
  /**
@@ -561,9 +696,28 @@ export interface ForkedSession {
561
696
  /** Available for checkpoint forks captured by workspace-CAS-aware writers. */
562
697
  workspaceCheckpoint?: WorkspaceCheckpointRef | undefined;
563
698
  }
699
+ /**
700
+ * Byte-level progress for a session JSONL load. `loadedBytes` counts raw
701
+ * source bytes consumed so far (newline-inclusive approximation) and
702
+ * `totalBytes` is the source file size at load start.
703
+ */
704
+ export interface SessionLoadProgress {
705
+ loadedBytes: number;
706
+ totalBytes: number;
707
+ }
564
708
  export interface SessionStore {
565
709
  create(meta: Omit<SessionMetadata, 'startedAt'>): Promise<SessionWriter>;
566
- load(id: string): Promise<SessionData>;
710
+ /**
711
+ * Read a session without claiming it for writing.
712
+ *
713
+ * `onLoadProgress` mirrors {@link SessionStore.resume} — the implementation
714
+ * has always accepted it, but the interface did not declare it, so the only
715
+ * caller that can stream progress for a read-only view (a resume falling
716
+ * back to showing the transcript it could not attach to) had to drop it and
717
+ * leave the user staring at a frozen screen for the length of a 131 MB
718
+ * parse. Implementations may ignore it.
719
+ */
720
+ load(id: string, onLoadProgress?: (progress: SessionLoadProgress) => void): Promise<SessionData>;
567
721
  /**
568
722
  * Open an existing session for append, returning both a writer that
569
723
  * continues writing to the same JSONL file and the replayed state
@@ -571,8 +725,12 @@ export interface SessionStore {
571
725
  * `session_resumed` marker is appended for audit. New writers may also
572
726
  * persist the exact conversation journal (`message_*` events); legacy logs
573
727
  * containing only user/assistant/tool events remain replayable.
728
+ *
729
+ * Optional `onLoadProgress` streams byte-level parse progress for large
730
+ * journals so callers can surface a live indicator; implementations may
731
+ * ignore it, and a warm load cache reports a single completed event.
574
732
  */
575
- resume(id: string): Promise<ResumedSession>;
733
+ resume(id: string, onLoadProgress?: (progress: SessionLoadProgress) => void): Promise<ResumedSession>;
576
734
  /**
577
735
  * Create a non-destructive child journal from a persisted parent boundary.
578
736
  * Parent file snapshots are intentionally not inherited as rewind authority;
@@ -654,6 +812,8 @@ export interface SessionStore {
654
812
  }
655
813
  export interface SessionWriter {
656
814
  readonly id: string;
815
+ /** Original session start timestamp, used by resumed surfaces to keep uptime stable. */
816
+ readonly startedAt?: string | undefined;
657
817
  /**
658
818
  * Session-level trace ID for correlating storage events with agent
659
819
  * iterations in observability pipelines. Generated once at Context
@@ -823,4 +983,5 @@ export interface SessionWriter {
823
983
  */
824
984
  clearInFlightMarker(reason: 'clean' | 'aborted' | 'recovered'): Promise<void>;
825
985
  }
986
+ export {};
826
987
  //# sourceMappingURL=session.d.ts.map