@phnx-labs/agents-cli 1.22.83 → 1.22.85

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 (291) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +80 -53
  3. package/dist/bootstrap.d.ts +7 -6
  4. package/dist/bootstrap.js +20 -27
  5. package/dist/cli/command-registry.js +5 -1
  6. package/dist/commands/accounts.d.ts +6 -13
  7. package/dist/commands/accounts.js +330 -143
  8. package/dist/commands/apply.js +1 -1
  9. package/dist/commands/auth-mint.d.ts +7 -3
  10. package/dist/commands/auth-mint.js +21 -9
  11. package/dist/commands/auth.js +2 -3
  12. package/dist/commands/browser.js +10 -10
  13. package/dist/commands/daemon.d.ts +7 -3
  14. package/dist/commands/daemon.js +40 -25
  15. package/dist/commands/doctor.js +28 -2
  16. package/dist/commands/exec.js +87 -39
  17. package/dist/commands/fleet-capture.js +21 -2
  18. package/dist/commands/harness-wizard.js +2 -2
  19. package/dist/commands/lease.js +7 -12
  20. package/dist/commands/profiles.d.ts +2 -2
  21. package/dist/commands/profiles.js +20 -13
  22. package/dist/commands/repo.js +3 -3
  23. package/dist/commands/run-account-picker.d.ts +3 -3
  24. package/dist/commands/run-account-picker.js +29 -30
  25. package/dist/commands/secrets-passthrough.d.ts +20 -0
  26. package/dist/commands/secrets-passthrough.js +43 -0
  27. package/dist/commands/sessions-trace.d.ts +11 -0
  28. package/dist/commands/sessions-trace.js +71 -0
  29. package/dist/commands/setup-accounts.d.ts +3 -2
  30. package/dist/commands/setup-accounts.js +4 -4
  31. package/dist/commands/setup-secrets.d.ts +16 -21
  32. package/dist/commands/setup-secrets.js +43 -224
  33. package/dist/commands/ssh.js +2 -2
  34. package/dist/commands/sync.js +1 -1
  35. package/dist/commands/update.d.ts +10 -0
  36. package/dist/commands/update.js +43 -40
  37. package/dist/commands/versions.d.ts +11 -11
  38. package/dist/commands/versions.js +131 -83
  39. package/dist/commands/view.d.ts +1 -9
  40. package/dist/commands/view.js +41 -55
  41. package/dist/commands/webhook.js +5 -5
  42. package/dist/commands/workflows.js +2 -1
  43. package/dist/index.d.ts +12 -12
  44. package/dist/index.js +13 -42
  45. package/dist/lib/account-capabilities.d.ts +1 -1
  46. package/dist/lib/account-capabilities.js +1 -1
  47. package/dist/lib/account-catalog.d.ts +121 -6
  48. package/dist/lib/account-catalog.js +421 -7
  49. package/dist/lib/account-registry.d.ts +8 -30
  50. package/dist/lib/account-registry.js +36 -79
  51. package/dist/lib/account-schema.d.ts +1 -1
  52. package/dist/lib/account-schema.js +1 -1
  53. package/dist/lib/accounting/account-pool-collect.js +16 -4
  54. package/dist/lib/accounting/rotate.d.ts +20 -7
  55. package/dist/lib/accounting/rotate.js +89 -13
  56. package/dist/lib/accounting/usage.js +11 -16
  57. package/dist/lib/accounts/add.d.ts +138 -0
  58. package/dist/lib/accounts/add.js +651 -0
  59. package/dist/lib/accounts/migrate.d.ts +117 -0
  60. package/dist/lib/accounts/migrate.js +536 -0
  61. package/dist/lib/accounts/slots.d.ts +13 -0
  62. package/dist/lib/accounts/slots.js +100 -0
  63. package/dist/lib/agent-spec/agents.d.ts +16 -0
  64. package/dist/lib/agent-spec/agents.js +32 -4
  65. package/dist/lib/app-bundle-install.js +5 -4
  66. package/dist/lib/auth-health.d.ts +3 -0
  67. package/dist/lib/auth-health.js +11 -0
  68. package/dist/lib/auth-mint.d.ts +52 -16
  69. package/dist/lib/auth-mint.js +117 -39
  70. package/dist/lib/browser/chrome.d.ts +1 -1
  71. package/dist/lib/browser/chrome.js +5 -5
  72. package/dist/lib/byok-usage.js +3 -3
  73. package/dist/lib/claude-account-token.d.ts +47 -3
  74. package/dist/lib/claude-account-token.js +172 -50
  75. package/dist/lib/cloud/antigravity.js +4 -4
  76. package/dist/lib/cloud/cursor.js +4 -4
  77. package/dist/lib/crabbox/cli.d.ts +1 -1
  78. package/dist/lib/crabbox/cli.js +6 -6
  79. package/dist/lib/crabbox/runtimes.d.ts +3 -3
  80. package/dist/lib/crabbox/runtimes.js +5 -5
  81. package/dist/lib/daemon/account-state-daemon-service.d.ts +37 -1
  82. package/dist/lib/daemon/account-state-daemon-service.js +199 -3
  83. package/dist/lib/daemon/auth-sync-service.js +28 -1
  84. package/dist/lib/daemon/daemon.d.ts +6 -16
  85. package/dist/lib/daemon/daemon.js +52 -97
  86. package/dist/lib/daemon/daemon.test-fixture.d.ts +7 -9
  87. package/dist/lib/daemon/daemon.test-fixture.js +22 -40
  88. package/dist/lib/daemon/harness-update-service.d.ts +1 -1
  89. package/dist/lib/daemon/harness-update-service.js +1 -1
  90. package/dist/lib/daemon/runner.d.ts +15 -3
  91. package/dist/lib/daemon/runner.js +49 -24
  92. package/dist/lib/daemon-health.d.ts +1 -2
  93. package/dist/lib/daemon-health.js +7 -6
  94. package/dist/lib/daemon-services.d.ts +1 -1
  95. package/dist/lib/daemon-services.js +1 -11
  96. package/dist/lib/daemon-ticks.js +23 -2
  97. package/dist/lib/daemon-webhooks.d.ts +8 -7
  98. package/dist/lib/daemon-webhooks.js +10 -9
  99. package/dist/lib/device-config.js +1 -1
  100. package/dist/lib/devices/doctor-findings.d.ts +1 -1
  101. package/dist/lib/devices/harness-inventory.d.ts +39 -0
  102. package/dist/lib/devices/harness-inventory.js +126 -4
  103. package/dist/lib/doctor-diff.js +2 -1
  104. package/dist/lib/exec-account-home.d.ts +38 -0
  105. package/dist/lib/exec-account-home.js +164 -0
  106. package/dist/lib/exec.d.ts +30 -0
  107. package/dist/lib/exec.js +101 -31
  108. package/dist/lib/feed/activity-stream.d.ts +60 -0
  109. package/dist/lib/feed/activity-stream.js +271 -0
  110. package/dist/lib/feed/activity.d.ts +7 -0
  111. package/dist/lib/feed/activity.js +10 -4
  112. package/dist/lib/feed/watch.d.ts +9 -3
  113. package/dist/lib/feed/watch.js +72 -36
  114. package/dist/lib/fleet/apply.d.ts +2 -2
  115. package/dist/lib/fleet/apply.js +4 -4
  116. package/dist/lib/fleet/auth-sync.js +4 -3
  117. package/dist/lib/fleet-shared-repo-sync.js +6 -9
  118. package/dist/lib/fleet-shared-state.d.ts +6 -0
  119. package/dist/lib/harness/adapter.d.ts +7 -7
  120. package/dist/lib/harness/adapter.js +10 -6
  121. package/dist/lib/harness/adapters/grok.js +8 -3
  122. package/dist/lib/harness/adapters/muse.js +1 -1
  123. package/dist/lib/harness/adapters/opencode.js +12 -3
  124. package/dist/lib/harness-auth-capabilities.d.ts +61 -0
  125. package/dist/lib/harness-auth-capabilities.js +52 -0
  126. package/dist/lib/helper-versions.d.ts +6 -4
  127. package/dist/lib/helper-versions.js +5 -4
  128. package/dist/lib/hosts/credential-transport.d.ts +10 -0
  129. package/dist/lib/hosts/credential-transport.js +37 -0
  130. package/dist/lib/hosts/dispatch.d.ts +7 -0
  131. package/dist/lib/hosts/dispatch.js +13 -6
  132. package/dist/lib/identity/client.d.ts +3 -3
  133. package/dist/lib/identity/client.js +3 -3
  134. package/dist/lib/installations/index.d.ts +1 -1
  135. package/dist/lib/installations/index.js +1 -1
  136. package/dist/lib/installations/migrate.js +9 -0
  137. package/dist/lib/installations/resolve.js +1 -1
  138. package/dist/lib/installations/shims.d.ts +15 -0
  139. package/dist/lib/installations/shims.js +69 -0
  140. package/dist/lib/installations/store.d.ts +43 -0
  141. package/dist/lib/installations/store.js +75 -7
  142. package/dist/lib/installations/versions.js +1 -1
  143. package/dist/lib/menubar/install-menubar.d.ts +3 -3
  144. package/dist/lib/menubar/install-menubar.js +3 -3
  145. package/dist/lib/native-accounts.d.ts +35 -0
  146. package/dist/lib/native-accounts.js +41 -0
  147. package/dist/lib/net-close.d.ts +11 -0
  148. package/dist/lib/net-close.js +25 -0
  149. package/dist/lib/openclaw-keychain.js +27 -1
  150. package/dist/lib/profiles.js +22 -9
  151. package/dist/lib/project-resources.js +1 -1
  152. package/dist/lib/reserved-stores.d.ts +53 -0
  153. package/dist/lib/reserved-stores.js +120 -0
  154. package/dist/lib/secrets-client.d.ts +191 -0
  155. package/dist/lib/secrets-client.js +710 -0
  156. package/dist/lib/secrets-policy.d.ts +222 -0
  157. package/dist/lib/secrets-policy.js +483 -0
  158. package/dist/lib/secrets-types.d.ts +188 -0
  159. package/dist/lib/secrets-types.js +24 -0
  160. package/dist/lib/service-manifest.js +3 -4
  161. package/dist/lib/session/active.d.ts +38 -4
  162. package/dist/lib/session/active.js +36 -4
  163. package/dist/lib/session/bash-command.js +10 -0
  164. package/dist/lib/session/db.d.ts +65 -2
  165. package/dist/lib/session/db.js +178 -18
  166. package/dist/lib/session/mirror.d.ts +5 -0
  167. package/dist/lib/session/mirror.js +166 -0
  168. package/dist/lib/session/parse.d.ts +49 -0
  169. package/dist/lib/session/parse.js +324 -30
  170. package/dist/lib/session/prompt.d.ts +93 -2
  171. package/dist/lib/session/prompt.js +266 -15
  172. package/dist/lib/session/remote/peer-stream.d.ts +47 -0
  173. package/dist/lib/session/remote/peer-stream.js +142 -0
  174. package/dist/lib/session/remote/watch.d.ts +1 -1
  175. package/dist/lib/session/remote/watch.js +41 -42
  176. package/dist/lib/session/session-cache.d.ts +9 -0
  177. package/dist/lib/session/session-cache.js +40 -2
  178. package/dist/lib/session/sync/config.js +2 -2
  179. package/dist/lib/session/timeline-pass.d.ts +129 -0
  180. package/dist/lib/session/timeline-pass.js +323 -0
  181. package/dist/lib/session/timeline.d.ts +182 -0
  182. package/dist/lib/session/timeline.js +636 -0
  183. package/dist/lib/session/types.d.ts +155 -1
  184. package/dist/lib/sha256-asset.d.ts +11 -16
  185. package/dist/lib/sha256-asset.js +11 -16
  186. package/dist/lib/share/config.js +14 -5
  187. package/dist/lib/signin-badge.d.ts +26 -0
  188. package/dist/lib/signin-badge.js +42 -0
  189. package/dist/lib/staleness/detectors/workflows.js +3 -105
  190. package/dist/lib/staleness/writers/workflows.js +2 -1
  191. package/dist/lib/state.d.ts +7 -4
  192. package/dist/lib/state.js +18 -7
  193. package/dist/lib/summarizer/pass.d.ts +2 -0
  194. package/dist/lib/summarizer/pass.js +14 -1
  195. package/dist/lib/summarizer/summarize.d.ts +7 -0
  196. package/dist/lib/summarizer/summarize.js +3 -0
  197. package/dist/lib/sync-umbrella.js +2 -2
  198. package/dist/lib/teams/agents.js +1 -1
  199. package/dist/lib/types.d.ts +74 -33
  200. package/dist/lib/view-types.d.ts +6 -3
  201. package/dist/lib/workflows-registry.d.ts +71 -0
  202. package/dist/lib/workflows-registry.js +280 -0
  203. package/dist/lib/workflows.d.ts +21 -21
  204. package/dist/lib/workflows.js +12 -327
  205. package/package.json +2 -3
  206. package/scripts/postinstall.js +4 -29
  207. package/dist/commands/secrets-import.d.ts +0 -18
  208. package/dist/commands/secrets-import.js +0 -74
  209. package/dist/commands/secrets-migrate.d.ts +0 -25
  210. package/dist/commands/secrets-migrate.js +0 -334
  211. package/dist/commands/secrets-rotate-passphrase.d.ts +0 -17
  212. package/dist/commands/secrets-rotate-passphrase.js +0 -96
  213. package/dist/commands/secrets-sync.d.ts +0 -11
  214. package/dist/commands/secrets-sync.js +0 -153
  215. package/dist/commands/secrets-vault.d.ts +0 -10
  216. package/dist/commands/secrets-vault.js +0 -130
  217. package/dist/commands/secrets.d.ts +0 -212
  218. package/dist/commands/secrets.js +0 -3030
  219. package/dist/lib/accounts/connect.d.ts +0 -170
  220. package/dist/lib/accounts/connect.js +0 -383
  221. package/dist/lib/daemon/keychain-reap-service.d.ts +0 -17
  222. package/dist/lib/daemon/keychain-reap-service.js +0 -32
  223. package/dist/lib/daemon/secrets-broker-service.d.ts +0 -21
  224. package/dist/lib/daemon/secrets-broker-service.js +0 -51
  225. package/dist/lib/secrets/agent.d.ts +0 -358
  226. package/dist/lib/secrets/agent.js +0 -1291
  227. package/dist/lib/secrets/audit.d.ts +0 -46
  228. package/dist/lib/secrets/audit.js +0 -101
  229. package/dist/lib/secrets/bundles.d.ts +0 -290
  230. package/dist/lib/secrets/bundles.js +0 -1547
  231. package/dist/lib/secrets/download-keychain.d.ts +0 -47
  232. package/dist/lib/secrets/download-keychain.js +0 -70
  233. package/dist/lib/secrets/drivers/rush.d.ts +0 -14
  234. package/dist/lib/secrets/drivers/rush.js +0 -90
  235. package/dist/lib/secrets/fallback.d.ts +0 -48
  236. package/dist/lib/secrets/fallback.js +0 -48
  237. package/dist/lib/secrets/filestore.d.ts +0 -222
  238. package/dist/lib/secrets/filestore.js +0 -1099
  239. package/dist/lib/secrets/headless.d.ts +0 -43
  240. package/dist/lib/secrets/headless.js +0 -56
  241. package/dist/lib/secrets/icloud-import.d.ts +0 -79
  242. package/dist/lib/secrets/icloud-import.js +0 -206
  243. package/dist/lib/secrets/index.d.ts +0 -451
  244. package/dist/lib/secrets/index.js +0 -1568
  245. package/dist/lib/secrets/install-helper.d.ts +0 -72
  246. package/dist/lib/secrets/install-helper.js +0 -245
  247. package/dist/lib/secrets/lease.d.ts +0 -25
  248. package/dist/lib/secrets/lease.js +0 -44
  249. package/dist/lib/secrets/linux.d.ts +0 -77
  250. package/dist/lib/secrets/linux.js +0 -393
  251. package/dist/lib/secrets/list-filter.d.ts +0 -109
  252. package/dist/lib/secrets/list-filter.js +0 -261
  253. package/dist/lib/secrets/mcp.d.ts +0 -93
  254. package/dist/lib/secrets/mcp.js +0 -211
  255. package/dist/lib/secrets/profiles.d.ts +0 -10
  256. package/dist/lib/secrets/profiles.js +0 -13
  257. package/dist/lib/secrets/push.d.ts +0 -133
  258. package/dist/lib/secrets/push.js +0 -273
  259. package/dist/lib/secrets/rc-hygiene.d.ts +0 -63
  260. package/dist/lib/secrets/rc-hygiene.js +0 -143
  261. package/dist/lib/secrets/read-backoff.d.ts +0 -27
  262. package/dist/lib/secrets/read-backoff.js +0 -64
  263. package/dist/lib/secrets/reaper.d.ts +0 -90
  264. package/dist/lib/secrets/reaper.js +0 -243
  265. package/dist/lib/secrets/remote.d.ts +0 -152
  266. package/dist/lib/secrets/remote.js +0 -344
  267. package/dist/lib/secrets/reserved-sync.d.ts +0 -66
  268. package/dist/lib/secrets/reserved-sync.js +0 -147
  269. package/dist/lib/secrets/scope.d.ts +0 -26
  270. package/dist/lib/secrets/scope.js +0 -29
  271. package/dist/lib/secrets/session-store.d.ts +0 -107
  272. package/dist/lib/secrets/session-store.js +0 -342
  273. package/dist/lib/secrets/sync-backend.d.ts +0 -48
  274. package/dist/lib/secrets/sync-backend.js +0 -13
  275. package/dist/lib/secrets/sync-commands.d.ts +0 -21
  276. package/dist/lib/secrets/sync-commands.js +0 -21
  277. package/dist/lib/secrets/sync.d.ts +0 -48
  278. package/dist/lib/secrets/sync.js +0 -237
  279. package/dist/lib/secrets/unlock-hints.d.ts +0 -27
  280. package/dist/lib/secrets/unlock-hints.js +0 -36
  281. package/dist/lib/secrets/usage-db.d.ts +0 -46
  282. package/dist/lib/secrets/usage-db.js +0 -96
  283. package/dist/lib/secrets/vault-age-helper.d.ts +0 -1
  284. package/dist/lib/secrets/vault-age-helper.js +0 -34
  285. package/dist/lib/secrets/vault.d.ts +0 -49
  286. package/dist/lib/secrets/vault.js +0 -399
  287. package/dist/lib/secrets/windows.d.ts +0 -81
  288. package/dist/lib/secrets/windows.js +0 -556
  289. package/scripts/install-helper.js +0 -97
  290. /package/dist/lib/{secrets/sync-passphrase.d.ts → sync-passphrase.d.ts} +0 -0
  291. /package/dist/lib/{secrets/sync-passphrase.js → sync-passphrase.js} +0 -0
@@ -30,6 +30,43 @@ export const SESSION_MIRROR_MAX_ROWS = 200;
30
30
  export const SESSION_MIRROR_SNIPPET_MAX = 280;
31
31
  /** Mirror rows older than this since their last sync are pruned (staleness/size ceiling). */
32
32
  export const SESSION_MIRROR_MAX_AGE_MS = 14 * 24 * 60 * 60_000;
33
+ /** Caps for the timeline block on a published mirror row. */
34
+ export const SESSION_MIRROR_MAX_STEPS = 8;
35
+ export const SESSION_MIRROR_STEP_TEXT_MAX = 160;
36
+ export const SESSION_MIRROR_REQUEST_MAX = 2_000;
37
+ export const SESSION_MIRROR_MAX_FILES = 8;
38
+ function cap(value, max) {
39
+ return value.length > max ? value.slice(0, max) : value;
40
+ }
41
+ /** Bound the tidied request: prose capped, chips capped, never re-derived. */
42
+ function boundedRequest(request) {
43
+ return {
44
+ ...request,
45
+ text: cap(request.text, SESSION_MIRROR_REQUEST_MAX),
46
+ headline: cap(request.headline, SESSION_MIRROR_STEP_TEXT_MAX),
47
+ ...(request.command ? { command: cap(request.command, 120) } : {}),
48
+ attachments: request.attachments.slice(0, SESSION_MIRROR_MAX_FILES)
49
+ .map((a) => ({ kind: a.kind, name: cap(a.name, 120) })),
50
+ };
51
+ }
52
+ /** Bound the step list. Counters are kept exact — only text is truncated. */
53
+ function boundedTimeline(timeline) {
54
+ const steps = timeline.steps.slice(-SESSION_MIRROR_MAX_STEPS).map((step) => ({
55
+ ...step,
56
+ text: cap(step.text, SESSION_MIRROR_STEP_TEXT_MAX),
57
+ ...(step.now ? { now: cap(step.now, SESSION_MIRROR_STEP_TEXT_MAX) } : {}),
58
+ ...(step.marks ? { marks: step.marks.slice(0, 4).map((mark) => cap(mark, 40)) } : {}),
59
+ }));
60
+ return { ...timeline, steps, ...(timeline.reason ? { reason: cap(timeline.reason, 200) } : {}) };
61
+ }
62
+ /** Bound the file rows; `total` still reports the real count. */
63
+ function boundedFiles(files) {
64
+ return {
65
+ ...files,
66
+ changes: files.changes.slice(0, SESSION_MIRROR_MAX_FILES)
67
+ .map((change) => ({ ...change, path: cap(change.path, 400) })),
68
+ };
69
+ }
33
70
  function snippet(value, max = SESSION_MIRROR_SNIPPET_MAX) {
34
71
  if (!value)
35
72
  return undefined;
@@ -83,6 +120,12 @@ export async function publishSessionMirrorToSharedStore(options = {}) {
83
120
  }
84
121
  : {}),
85
122
  ...(s.summary?.summaryState ? { summaryState: s.summary.summaryState } : {}),
123
+ // Same bound-on-publish discipline as the summary above: the fleet state file
124
+ // is git-synced, so the request text, the step list, and the file rows are
125
+ // capped here rather than shipped raw (PHNX-3939).
126
+ ...(s.timeline?.request ? { request: boundedRequest(s.timeline.request) } : {}),
127
+ ...(s.timeline?.timeline ? { timeline: boundedTimeline(s.timeline.timeline) } : {}),
128
+ ...(s.timeline?.files ? { files: boundedFiles(s.timeline.files) } : {}),
86
129
  capturedAt,
87
130
  }));
88
131
  try {
@@ -133,8 +176,131 @@ function toUpsert(raw) {
133
176
  ticketId: cap(r.ticketId, 64),
134
177
  prUrl: cap(r.prUrl, 512),
135
178
  summary: toMirrorSummary(r),
179
+ timeline: toMirrorTimeline(r),
136
180
  };
137
181
  }
182
+ /**
183
+ * Validate an untrusted peer's published request/timeline/files into the bounded
184
+ * projection the local cache stores (PHNX-3939). Bounds mirror the publish side,
185
+ * so a hostile or oversized peer cannot bloat this box's cache. Only a row that
186
+ * carries a well-formed timeline is kept; a malformed one is dropped whole
187
+ * rather than partially trusted.
188
+ */
189
+ function toMirrorTimeline(r) {
190
+ const timeline = toMirrorTimelineBlock(r.timeline);
191
+ if (!timeline)
192
+ return undefined;
193
+ return {
194
+ timeline,
195
+ ...(toMirrorRequest(r.request) ? { request: toMirrorRequest(r.request) } : {}),
196
+ ...(toMirrorFiles(r.files) ? { files: toMirrorFiles(r.files) } : {}),
197
+ };
198
+ }
199
+ function isRecord(v) {
200
+ return Boolean(v) && typeof v === 'object' && !Array.isArray(v);
201
+ }
202
+ function count(v) {
203
+ return typeof v === 'number' && Number.isFinite(v) && v >= 0 ? Math.floor(v) : 0;
204
+ }
205
+ /** The verb keys a peer's `mix` may carry — anything else is dropped, not trusted. */
206
+ const MIRROR_VERB_CLASSES = [
207
+ 'read', 'edit', 'run', 'git', 'test', 'browser', 'agent', 'other',
208
+ ];
209
+ /** A peer's per-verb breakdown, whitelisted by key and clamped by value. */
210
+ function toMirrorMix(raw) {
211
+ if (!isRecord(raw))
212
+ return undefined;
213
+ const mix = {};
214
+ for (const verb of MIRROR_VERB_CLASSES) {
215
+ const n = count(raw[verb]);
216
+ if (n > 0)
217
+ mix[verb] = n;
218
+ }
219
+ return Object.keys(mix).length ? mix : undefined;
220
+ }
221
+ function toMirrorTimelineBlock(raw) {
222
+ if (!isRecord(raw))
223
+ return undefined;
224
+ const state = raw.state;
225
+ if (state !== 'ready' && state !== 'partial' && state !== 'unavailable')
226
+ return undefined;
227
+ const steps = (Array.isArray(raw.steps) ? raw.steps : [])
228
+ .filter(isRecord)
229
+ .filter((step) => isString(step.text) && isString(step.at))
230
+ .slice(0, SESSION_MIRROR_MAX_STEPS)
231
+ .map((step) => ({
232
+ text: String(step.text).slice(0, SESSION_MIRROR_STEP_TEXT_MAX),
233
+ at: String(step.at).slice(0, 40),
234
+ ...(isString(step.endedAt) ? { endedAt: step.endedAt.slice(0, 40) } : {}),
235
+ source: (step.source === 'thinking' || step.source === 'derived' || step.source === 'user'
236
+ ? step.source : 'narration'),
237
+ tools: count(step.tools),
238
+ failed: count(step.failed),
239
+ blocked: count(step.blocked),
240
+ ...(isString(step.now) ? { now: step.now.slice(0, SESSION_MIRROR_STEP_TEXT_MAX) } : {}),
241
+ // `mix` and `live` are what the sidebar renders a step WITH ("6 run ·
242
+ // 2 blocked", the amber now-line). Dropping them here made a remote row
243
+ // disagree with the local one about what a live step even is, while `now`
244
+ // survived — so they ride through, whitelisted like every other field.
245
+ ...(step.live === true ? { live: true } : {}),
246
+ ...(() => {
247
+ const mix = toMirrorMix(step.mix);
248
+ return mix ? { mix } : {};
249
+ })(),
250
+ ...(Array.isArray(step.marks)
251
+ ? { marks: step.marks.filter(isString).slice(0, 4).map((mark) => mark.slice(0, 40)) }
252
+ : {}),
253
+ }));
254
+ const earlier = isRecord(raw.earlier) ? raw.earlier : {};
255
+ return {
256
+ steps,
257
+ earlier: { steps: count(earlier.steps), tools: count(earlier.tools), failed: count(earlier.failed) },
258
+ tools: count(raw.tools),
259
+ failed: count(raw.failed),
260
+ blocked: count(raw.blocked),
261
+ spanMs: count(raw.spanMs),
262
+ state,
263
+ ...(isString(raw.reason) ? { reason: raw.reason.slice(0, 200) } : {}),
264
+ };
265
+ }
266
+ function toMirrorRequest(raw) {
267
+ if (!isRecord(raw) || !isString(raw.headline))
268
+ return undefined;
269
+ const kind = raw.kind;
270
+ return {
271
+ text: isString(raw.text) ? raw.text.slice(0, SESSION_MIRROR_REQUEST_MAX) : '',
272
+ headline: raw.headline.slice(0, SESSION_MIRROR_STEP_TEXT_MAX),
273
+ kind: kind === 'image' || kind === 'command' || kind === 'skill' ? kind : 'text',
274
+ ...(isString(raw.command) ? { command: raw.command.slice(0, 120) } : {}),
275
+ attachments: (Array.isArray(raw.attachments) ? raw.attachments : [])
276
+ .filter(isRecord)
277
+ .filter((a) => isString(a.name))
278
+ .slice(0, SESSION_MIRROR_MAX_FILES)
279
+ .map((a) => ({
280
+ kind: a.kind === 'image' || a.kind === 'dir' ? a.kind : 'file',
281
+ name: String(a.name).slice(0, 120),
282
+ })),
283
+ pastedLines: count(raw.pastedLines),
284
+ ...(typeof raw.turns === 'number' ? { turns: count(raw.turns) } : {}),
285
+ };
286
+ }
287
+ function toMirrorFiles(raw) {
288
+ if (!isRecord(raw))
289
+ return undefined;
290
+ const changes = (Array.isArray(raw.changes) ? raw.changes : [])
291
+ .filter(isRecord)
292
+ .filter((change) => isString(change.path))
293
+ .slice(0, SESSION_MIRROR_MAX_FILES)
294
+ .map((change) => ({
295
+ path: String(change.path).slice(0, 400),
296
+ op: (change.op === 'created' || change.op === 'deleted' ? change.op : 'modified'),
297
+ edits: count(change.edits),
298
+ at: isString(change.at) ? change.at.slice(0, 40) : '',
299
+ }));
300
+ if (!changes.length)
301
+ return undefined;
302
+ return { changes, total: count(raw.total) || changes.length, source: raw.source === 'harness' ? 'harness' : 'tools' };
303
+ }
138
304
  /** One published summary state, validated back into the union or undefined. */
139
305
  function toSummaryState(v) {
140
306
  return v === 'pending' || v === 'ready' || v === 'skipped' ? v : undefined;
@@ -33,6 +33,14 @@ export interface ParseSessionOptions {
33
33
  maxToolOutputChars?: number;
34
34
  /** Opt-in because interrupts are not user messages and would change the published event stream. */
35
35
  includeInterrupts?: boolean;
36
+ /**
37
+ * Opt-in `file_change` events from the harness's own file ledger (Claude
38
+ * `file-history-delta`). Opt-in for the same reason as
39
+ * {@link includeInterrupts}: they are not tool calls, and emitting them by
40
+ * default would change every published event stream (message counts, digests,
41
+ * trajectories) for a signal only the timeline fold consumes.
42
+ */
43
+ includeFileHistory?: boolean;
36
44
  }
37
45
  export declare function parseSession(filePath: string, agent?: SessionAgentId, opts?: ParseSessionOptions): SessionEvent[];
38
46
  /** Infer the agent type from a session file path using known directory conventions. */
@@ -75,6 +83,28 @@ export declare function applyPatchTargets(input: string): Array<{
75
83
  op: 'Add' | 'Update' | 'Delete';
76
84
  }>;
77
85
  export declare function applyPatchTargetPaths(input: string): string[];
86
+ /**
87
+ * Codex writes its turn TWICE in one rollout: the raw `response_item` records
88
+ * the model exchanged, and a parallel `event_msg` / `item_completed` stream of
89
+ * typed, already-classified items. The two overlap — on a 6,244-line rollout on
90
+ * zion (2026-09-06) the same turn appears as 648 `custom_tool_call` +
91
+ * 60 `function_call` records AND as 1,038 `CommandExecution` items — so the two
92
+ * MUST NOT be merged into one event list: every consumer that counts tool calls
93
+ * (digest, trajectory, insights, the tool index) would double-count.
94
+ *
95
+ * {@link parseCodexContent} therefore keeps reading `response_item` and this is
96
+ * a SEPARATE reader over the item stream, for consumers that want the harness's
97
+ * own classification instead of re-deriving it: the command as Codex parsed it
98
+ * (`parsed_cmd.type`), its `exit_code`/`status`, the per-path `FileChange`
99
+ * ledger, `AgentMessage.phase` (`commentary` is the narration between calls),
100
+ * web searches, sub-agent activity and compactions. The timeline fold is the
101
+ * consumer; `parseSession` is untouched.
102
+ *
103
+ * Version-tolerant by construction: an item type this does not know folds to a
104
+ * generic `other` tool_use rather than throwing, so a Codex release that adds an
105
+ * item type degrades to a counted step instead of an empty timeline.
106
+ */
107
+ export declare function parseCodexItemsContent(content: string): SessionEvent[];
78
108
  /**
79
109
  * Parse Codex JSONL *content* (already read into a string) into normalized
80
110
  * events. Split from `parseCodex` so the tail reader can parse just the last
@@ -142,6 +172,25 @@ export declare function sessionFilePathContainer(filePath: string): string;
142
172
  * timestamps aren't stored, so every event carries the session's `created_at`
143
173
  * (from summary.json), falling back to the transcript's mtime.
144
174
  */
175
+ /**
176
+ * Counters Grok writes beside its transcript in `signals.json` — the only place
177
+ * a Grok session records milestones and failures, since `chat_history.jsonl`
178
+ * carries no timestamps and no exit codes. Read by the timeline fold to mark a
179
+ * session that committed / opened / merged a PR and to report a tool-failure
180
+ * count the event stream cannot supply.
181
+ */
182
+ export interface GrokSessionSignals {
183
+ gitCommitCount: number;
184
+ prCreatedCount: number;
185
+ prMergedCount: number;
186
+ toolFailureCount: number;
187
+ }
188
+ /**
189
+ * Read `signals.json` next to a Grok transcript. Returns `undefined` when the
190
+ * file is absent or unreadable — a Grok session simply has no signals then, and
191
+ * the fold reports what it does have rather than inventing zeros.
192
+ */
193
+ export declare function readGrokSignals(filePath: string): GrokSessionSignals | undefined;
145
194
  export declare function parseGrok(filePath: string): SessionEvent[];
146
195
  /**
147
196
  * The transcript query {@link parseOpenCode} runs, exported so a test can assert