@phnx-labs/agents-cli 1.22.120 → 1.22.121

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 (1603) hide show
  1. package/CHANGELOG.md +227 -0
  2. package/README.md +19 -2
  3. package/dist/bootstrap.d.ts +0 -15
  4. package/dist/bootstrap.js +10 -409
  5. package/dist/cli/command-registry.d.ts +0 -58
  6. package/dist/cli/command-registry.js +2 -74
  7. package/dist/commands/accounts.d.ts +0 -17
  8. package/dist/commands/accounts.js +1 -52
  9. package/dist/commands/alias.d.ts +0 -12
  10. package/dist/commands/alias.js +0 -6
  11. package/dist/commands/apply.d.ts +0 -15
  12. package/dist/commands/apply.js +0 -63
  13. package/dist/commands/audit.d.ts +0 -12
  14. package/dist/commands/audit.js +0 -13
  15. package/dist/commands/auth.js +4 -12
  16. package/dist/commands/beta.d.ts +0 -6
  17. package/dist/commands/beta.js +2 -6
  18. package/dist/commands/browser-sessions-picker.d.ts +0 -8
  19. package/dist/commands/browser-sessions-picker.js +0 -26
  20. package/dist/commands/browser.d.ts +0 -57
  21. package/dist/commands/browser.js +0 -80
  22. package/dist/commands/budget.d.ts +0 -13
  23. package/dist/commands/budget.js +0 -2
  24. package/dist/commands/cli.d.ts +0 -12
  25. package/dist/commands/cli.js +0 -4
  26. package/dist/commands/cloud.d.ts +0 -9
  27. package/dist/commands/cloud.js +0 -43
  28. package/dist/commands/commands.d.ts +0 -9
  29. package/dist/commands/commands.js +0 -18
  30. package/dist/commands/computer-sessions-picker.d.ts +0 -11
  31. package/dist/commands/computer-sessions-picker.js +0 -29
  32. package/dist/commands/computer.d.ts +0 -62
  33. package/dist/commands/computer.js +3 -114
  34. package/dist/commands/config.d.ts +0 -14
  35. package/dist/commands/config.js +21 -60
  36. package/dist/commands/cost.d.ts +0 -11
  37. package/dist/commands/cost.js +1 -17
  38. package/dist/commands/daemon-test-harness.d.ts +0 -32
  39. package/dist/commands/daemon-test-harness.js +1 -36
  40. package/dist/commands/daemon.d.ts +0 -46
  41. package/dist/commands/daemon.js +8 -255
  42. package/dist/commands/detach-core.d.ts +0 -28
  43. package/dist/commands/detach-core.js +0 -30
  44. package/dist/commands/detach.d.ts +1 -12
  45. package/dist/commands/detach.js +16 -52
  46. package/dist/commands/device-config-test-harness.js +0 -12
  47. package/dist/commands/doctor.d.ts +0 -103
  48. package/dist/commands/doctor.js +3 -279
  49. package/dist/commands/events.d.ts +0 -29
  50. package/dist/commands/events.js +1 -55
  51. package/dist/commands/exec.d.ts +0 -163
  52. package/dist/commands/exec.js +15 -964
  53. package/dist/commands/factory.d.ts +0 -6
  54. package/dist/commands/factory.js +0 -2
  55. package/dist/commands/feed-watch.js +0 -20
  56. package/dist/commands/feed.d.ts +0 -38
  57. package/dist/commands/feed.js +1 -151
  58. package/dist/commands/feedback.d.ts +0 -5
  59. package/dist/commands/feedback.js +0 -5
  60. package/dist/commands/fleet-capture.d.ts +0 -12
  61. package/dist/commands/fleet-capture.js +1 -39
  62. package/dist/commands/focus.d.ts +6 -94
  63. package/dist/commands/focus.js +13 -183
  64. package/dist/commands/fork.d.ts +0 -21
  65. package/dist/commands/fork.js +0 -45
  66. package/dist/commands/funnel.d.ts +0 -3
  67. package/dist/commands/go.d.ts +2 -71
  68. package/dist/commands/go.js +5 -99
  69. package/dist/commands/harness-hooks.d.ts +0 -41
  70. package/dist/commands/harness-hooks.js +0 -48
  71. package/dist/commands/harness-wizard.d.ts +0 -137
  72. package/dist/commands/harness-wizard.js +0 -109
  73. package/dist/commands/harness.d.ts +0 -63
  74. package/dist/commands/harness.js +0 -103
  75. package/dist/commands/hooks.d.ts +0 -9
  76. package/dist/commands/hooks.js +0 -26
  77. package/dist/commands/humans.d.ts +0 -8
  78. package/dist/commands/humans.js +0 -8
  79. package/dist/commands/import.d.ts +0 -22
  80. package/dist/commands/import.js +0 -79
  81. package/dist/commands/insights.d.ts +0 -37
  82. package/dist/commands/insights.js +3 -115
  83. package/dist/commands/inspect.d.ts +0 -117
  84. package/dist/commands/inspect.js +2 -448
  85. package/dist/commands/lease.d.ts +0 -28
  86. package/dist/commands/lease.js +0 -43
  87. package/dist/commands/logs.d.ts +0 -23
  88. package/dist/commands/logs.js +0 -30
  89. package/dist/commands/mailboxes.d.ts +0 -18
  90. package/dist/commands/mailboxes.js +0 -29
  91. package/dist/commands/mcp.d.ts +0 -9
  92. package/dist/commands/mcp.js +0 -53
  93. package/dist/commands/memory.d.ts +0 -7
  94. package/dist/commands/memory.js +0 -7
  95. package/dist/commands/menubar.d.ts +0 -8
  96. package/dist/commands/menubar.js +0 -24
  97. package/dist/commands/message.d.ts +0 -23
  98. package/dist/commands/message.js +0 -50
  99. package/dist/commands/mine.d.ts +0 -22
  100. package/dist/commands/mine.js +0 -21
  101. package/dist/commands/models.d.ts +0 -8
  102. package/dist/commands/models.js +0 -33
  103. package/dist/commands/modes.d.ts +0 -10
  104. package/dist/commands/modes.js +0 -13
  105. package/dist/commands/monitors.d.ts +0 -9
  106. package/dist/commands/monitors.js +3 -160
  107. package/dist/commands/open.d.ts +0 -26
  108. package/dist/commands/open.js +0 -10
  109. package/dist/commands/output.d.ts +0 -18
  110. package/dist/commands/output.js +1 -34
  111. package/dist/commands/packages-materialize.d.ts +0 -11
  112. package/dist/commands/packages-materialize.js +0 -3
  113. package/dist/commands/packages.d.ts +0 -10
  114. package/dist/commands/packages.js +0 -50
  115. package/dist/commands/perf.d.ts +0 -41
  116. package/dist/commands/perf.js +0 -55
  117. package/dist/commands/permissions.d.ts +0 -9
  118. package/dist/commands/permissions.js +0 -43
  119. package/dist/commands/plugins.d.ts +0 -14
  120. package/dist/commands/plugins.js +2 -55
  121. package/dist/commands/profiles.d.ts +0 -25
  122. package/dist/commands/profiles.js +0 -27
  123. package/dist/commands/projects-todo.d.ts +2 -0
  124. package/dist/commands/projects-todo.js +132 -0
  125. package/dist/commands/projects.d.ts +0 -85
  126. package/dist/commands/projects.js +344 -291
  127. package/dist/commands/prune.js +0 -30
  128. package/dist/commands/ps-roster.d.ts +92 -0
  129. package/dist/commands/ps-roster.js +744 -0
  130. package/dist/commands/ps.d.ts +6 -0
  131. package/dist/commands/ps.js +98 -0
  132. package/dist/commands/refresh-rules.d.ts +0 -13
  133. package/dist/commands/refresh-rules.js +0 -14
  134. package/dist/commands/reminders.d.ts +0 -7
  135. package/dist/commands/repo.d.ts +0 -89
  136. package/dist/commands/repo.js +7 -205
  137. package/dist/commands/resource-view.d.ts +0 -33
  138. package/dist/commands/resource-view.js +0 -49
  139. package/dist/commands/resume.d.ts +1 -19
  140. package/dist/commands/resume.js +0 -50
  141. package/dist/commands/route.d.ts +0 -10
  142. package/dist/commands/route.js +0 -19
  143. package/dist/commands/routines.d.ts +0 -42
  144. package/dist/commands/routines.js +5 -290
  145. package/dist/commands/routines.test-fixture.d.ts +0 -34
  146. package/dist/commands/routines.test-fixture.js +4 -100
  147. package/dist/commands/rules.d.ts +0 -9
  148. package/dist/commands/rules.js +1 -6
  149. package/dist/commands/run-account-picker.d.ts +0 -59
  150. package/dist/commands/run-account-picker.js +0 -71
  151. package/dist/commands/run-broadcast.d.ts +0 -9
  152. package/dist/commands/run-broadcast.js +0 -7
  153. package/dist/commands/run-cloud.d.ts +0 -15
  154. package/dist/commands/run-cloud.js +0 -37
  155. package/dist/commands/run-device-picker.d.ts +0 -25
  156. package/dist/commands/run-device-picker.js +1 -53
  157. package/dist/commands/secrets-passthrough.d.ts +0 -31
  158. package/dist/commands/secrets-passthrough.js +0 -10
  159. package/dist/commands/send.d.ts +0 -20
  160. package/dist/commands/send.js +14 -18
  161. package/dist/commands/sessions-backfill.d.ts +0 -7
  162. package/dist/commands/sessions-backfill.js +1 -16
  163. package/dist/commands/sessions-backup-setup.js +0 -11
  164. package/dist/commands/sessions-bookmark.d.ts +0 -8
  165. package/dist/commands/sessions-bookmark.js +0 -28
  166. package/dist/commands/sessions-browser.d.ts +2 -117
  167. package/dist/commands/sessions-browser.js +5 -243
  168. package/dist/commands/sessions-export.d.ts +1 -26
  169. package/dist/commands/sessions-export.js +3 -81
  170. package/dist/commands/sessions-import.d.ts +0 -14
  171. package/dist/commands/sessions-import.js +0 -59
  172. package/dist/commands/sessions-inject.d.ts +0 -60
  173. package/dist/commands/sessions-inject.js +3 -96
  174. package/dist/commands/sessions-migrate.d.ts +2 -37
  175. package/dist/commands/sessions-migrate.js +7 -159
  176. package/dist/commands/sessions-optimize.d.ts +0 -12
  177. package/dist/commands/sessions-picker-factory.d.ts +0 -7
  178. package/dist/commands/sessions-picker-factory.js +0 -8
  179. package/dist/commands/sessions-picker.d.ts +4 -103
  180. package/dist/commands/sessions-picker.js +13 -352
  181. package/dist/commands/sessions-render.d.ts +1 -2
  182. package/dist/commands/sessions-render.js +3 -7
  183. package/dist/commands/sessions-resume.d.ts +1 -24
  184. package/dist/commands/sessions-resume.js +2 -65
  185. package/dist/commands/sessions-share.d.ts +1 -9
  186. package/dist/commands/sessions-share.js +1 -45
  187. package/dist/commands/sessions-stats.d.ts +0 -24
  188. package/dist/commands/sessions-stats.js +0 -49
  189. package/dist/commands/sessions-stop.d.ts +1 -20
  190. package/dist/commands/sessions-stop.js +4 -9
  191. package/dist/commands/sessions-tail.d.ts +1 -19
  192. package/dist/commands/sessions-tail.js +3 -36
  193. package/dist/commands/sessions-trace.d.ts +5 -36
  194. package/dist/commands/sessions-trace.js +7 -82
  195. package/dist/commands/sessions.d.ts +1 -666
  196. package/dist/commands/sessions.js +30 -2279
  197. package/dist/commands/sessions.test-fixture.d.ts +0 -9
  198. package/dist/commands/sessions.test-fixture.js +8 -23
  199. package/dist/commands/setup-accounts.d.ts +0 -6
  200. package/dist/commands/setup-browser.d.ts +0 -23
  201. package/dist/commands/setup-browser.js +0 -28
  202. package/dist/commands/setup-computer.d.ts +0 -16
  203. package/dist/commands/setup-computer.js +0 -28
  204. package/dist/commands/setup-fleet.d.ts +0 -8
  205. package/dist/commands/setup-fleet.js +0 -11
  206. package/dist/commands/setup-mine.d.ts +0 -14
  207. package/dist/commands/setup-mine.js +0 -25
  208. package/dist/commands/setup-preferences.d.ts +0 -47
  209. package/dist/commands/setup-preferences.js +0 -53
  210. package/dist/commands/setup-secrets.d.ts +2 -24
  211. package/dist/commands/setup-secrets.js +0 -24
  212. package/dist/commands/setup-term.d.ts +0 -21
  213. package/dist/commands/setup-term.js +0 -21
  214. package/dist/commands/setup-terminal.d.ts +0 -1
  215. package/dist/commands/setup-terminal.js +0 -1
  216. package/dist/commands/setup-tools.d.ts +2 -0
  217. package/dist/commands/setup-tools.js +73 -0
  218. package/dist/commands/setup.d.ts +0 -20
  219. package/dist/commands/setup.js +4 -57
  220. package/dist/commands/skills.d.ts +0 -9
  221. package/dist/commands/skills.js +1 -22
  222. package/dist/commands/snapshot.d.ts +0 -9
  223. package/dist/commands/snapshot.js +0 -10
  224. package/dist/commands/ssh.d.ts +0 -64
  225. package/dist/commands/ssh.js +9 -420
  226. package/dist/commands/status.d.ts +0 -12
  227. package/dist/commands/status.js +0 -26
  228. package/dist/commands/subagents.d.ts +0 -8
  229. package/dist/commands/subagents.js +0 -31
  230. package/dist/commands/sync.d.ts +0 -37
  231. package/dist/commands/sync.js +0 -256
  232. package/dist/commands/teams-picker.d.ts +0 -3
  233. package/dist/commands/teams-picker.js +0 -34
  234. package/dist/commands/teams.d.ts +1 -76
  235. package/dist/commands/teams.js +9 -477
  236. package/dist/commands/tmux.d.ts +0 -25
  237. package/dist/commands/tmux.js +0 -46
  238. package/dist/commands/traces.js +0 -19
  239. package/dist/commands/trash.d.ts +0 -17
  240. package/dist/commands/trash.js +1 -11
  241. package/dist/commands/uninstall.d.ts +0 -9
  242. package/dist/commands/uninstall.js +0 -6
  243. package/dist/commands/update.d.ts +0 -22
  244. package/dist/commands/update.js +0 -44
  245. package/dist/commands/upgrade.d.ts +0 -1
  246. package/dist/commands/upgrade.js +0 -1
  247. package/dist/commands/utils.d.ts +0 -85
  248. package/dist/commands/utils.js +1 -95
  249. package/dist/commands/versions.d.ts +0 -16
  250. package/dist/commands/versions.js +0 -134
  251. package/dist/commands/view.d.ts +0 -90
  252. package/dist/commands/view.js +4 -343
  253. package/dist/commands/watchdog.d.ts +0 -19
  254. package/dist/commands/watchdog.js +3 -43
  255. package/dist/commands/webhook.d.ts +0 -8
  256. package/dist/commands/webhook.js +0 -14
  257. package/dist/commands/workflows.d.ts +0 -8
  258. package/dist/commands/workflows.js +0 -6
  259. package/dist/index.d.ts +0 -25
  260. package/dist/index.js +5 -119
  261. package/dist/lib/account-capabilities.d.ts +0 -34
  262. package/dist/lib/account-capabilities.js +0 -32
  263. package/dist/lib/account-catalog.d.ts +0 -128
  264. package/dist/lib/account-catalog.js +8 -154
  265. package/dist/lib/account-provider-registry.d.ts +0 -14
  266. package/dist/lib/account-provider-registry.js +0 -8
  267. package/dist/lib/account-registry.d.ts +0 -74
  268. package/dist/lib/account-registry.js +14 -189
  269. package/dist/lib/account-schema.d.ts +0 -19
  270. package/dist/lib/account-schema.js +0 -43
  271. package/dist/lib/accounting/account-launch.d.ts +0 -15
  272. package/dist/lib/accounting/account-launch.js +1 -3
  273. package/dist/lib/accounting/account-pool-collect.d.ts +0 -26
  274. package/dist/lib/accounting/account-pool-collect.js +0 -42
  275. package/dist/lib/accounting/account-pool.d.ts +0 -41
  276. package/dist/lib/accounting/account-pool.js +0 -17
  277. package/dist/lib/accounting/capacity.d.ts +0 -32
  278. package/dist/lib/accounting/capacity.js +0 -32
  279. package/dist/lib/accounting/rotate.d.ts +0 -518
  280. package/dist/lib/accounting/rotate.js +4 -598
  281. package/dist/lib/accounting/usage-ingest.d.ts +0 -1
  282. package/dist/lib/accounting/usage-ingest.js +0 -44
  283. package/dist/lib/accounting/usage-sync.d.ts +0 -60
  284. package/dist/lib/accounting/usage-sync.js +4 -51
  285. package/dist/lib/accounting/usage.d.ts +0 -632
  286. package/dist/lib/accounting/usage.js +14 -1055
  287. package/dist/lib/accounts/add.d.ts +0 -60
  288. package/dist/lib/accounts/add.js +0 -127
  289. package/dist/lib/accounts/auth-operation-lock.d.ts +0 -1
  290. package/dist/lib/accounts/auth-operation-lock.js +0 -4
  291. package/dist/lib/accounts/migrate.d.ts +0 -9
  292. package/dist/lib/accounts/migrate.js +3 -42
  293. package/dist/lib/accounts/slots.d.ts +0 -25
  294. package/dist/lib/accounts/slots.js +1 -49
  295. package/dist/lib/acp/client.d.ts +0 -16
  296. package/dist/lib/acp/client.js +0 -29
  297. package/dist/lib/acp/harnesses.d.ts +0 -15
  298. package/dist/lib/acp/harnesses.js +0 -16
  299. package/dist/lib/acp/run.d.ts +0 -8
  300. package/dist/lib/acp/run.js +0 -8
  301. package/dist/lib/actor.d.ts +1 -71
  302. package/dist/lib/actor.js +1 -99
  303. package/dist/lib/add-dir.d.ts +0 -46
  304. package/dist/lib/add-dir.js +1 -70
  305. package/dist/lib/address.d.ts +0 -17
  306. package/dist/lib/address.js +0 -15
  307. package/dist/lib/agent-cli-commands.d.ts +0 -10
  308. package/dist/lib/agent-cli-commands.js +0 -10
  309. package/dist/lib/agent-modes.d.ts +0 -29
  310. package/dist/lib/agent-modes.js +0 -31
  311. package/dist/lib/agent-spec/agents.d.ts +0 -426
  312. package/dist/lib/agent-spec/agents.js +37 -924
  313. package/dist/lib/agent-spec/index.d.ts +0 -5
  314. package/dist/lib/agent-spec/index.js +0 -14
  315. package/dist/lib/agent-spec/materialize.d.ts +0 -10
  316. package/dist/lib/agent-spec/materialize.js +2 -139
  317. package/dist/lib/agent-spec/package-resolve.d.ts +0 -8
  318. package/dist/lib/agent-spec/package-resolve.js +1 -44
  319. package/dist/lib/agent-spec/package-schema.d.ts +0 -2
  320. package/dist/lib/agent-spec/package-schema.js +0 -11
  321. package/dist/lib/agent-spec/package-types.d.ts +0 -27
  322. package/dist/lib/agent-spec/package-types.js +0 -1
  323. package/dist/lib/agent-spec/primitives.d.ts +0 -18
  324. package/dist/lib/agent-spec/primitives.js +0 -27
  325. package/dist/lib/agent-spec/provider.js +0 -2
  326. package/dist/lib/agent-spec/resolve.d.ts +0 -23
  327. package/dist/lib/agent-spec/resolve.js +0 -41
  328. package/dist/lib/agent-spec/types.d.ts +0 -34
  329. package/dist/lib/agent-spec/types.js +0 -6
  330. package/dist/lib/agents.d.ts +0 -1
  331. package/dist/lib/agents.js +0 -1
  332. package/dist/lib/analytics/mix-commands.d.ts +0 -23
  333. package/dist/lib/analytics/mix-commands.js +0 -26
  334. package/dist/lib/analytics/recipes.d.ts +0 -1
  335. package/dist/lib/analytics/recipes.js +5 -10
  336. package/dist/lib/analytics/usage-db.js +4 -6
  337. package/dist/lib/answer-router.d.ts +0 -61
  338. package/dist/lib/answer-router.js +0 -57
  339. package/dist/lib/app-bundle-install.d.ts +0 -13
  340. package/dist/lib/app-bundle-install.js +0 -50
  341. package/dist/lib/artifact-actions.d.ts +0 -15
  342. package/dist/lib/artifact-actions.js +0 -18
  343. package/dist/lib/artifacts-client.d.ts +0 -10
  344. package/dist/lib/artifacts-client.js +0 -17
  345. package/dist/lib/ask-classifier.d.ts +0 -38
  346. package/dist/lib/ask-classifier.js +0 -27
  347. package/dist/lib/audit/log.d.ts +0 -47
  348. package/dist/lib/audit/log.js +1 -59
  349. package/dist/lib/auth-health.d.ts +0 -213
  350. package/dist/lib/auth-health.js +16 -266
  351. package/dist/lib/auth-mint.d.ts +0 -83
  352. package/dist/lib/auth-mint.js +8 -85
  353. package/dist/lib/auto-pull-worker.d.ts +0 -10
  354. package/dist/lib/auto-pull-worker.js +3 -48
  355. package/dist/lib/auto-pull.d.ts +0 -64
  356. package/dist/lib/auto-pull.js +0 -79
  357. package/dist/lib/beta.d.ts +0 -9
  358. package/dist/lib/beta.js +0 -9
  359. package/dist/lib/binary-shadow.d.ts +0 -22
  360. package/dist/lib/binary-shadow.js +4 -34
  361. package/dist/lib/boot-profile.d.ts +0 -10
  362. package/dist/lib/boot-profile.js +1 -31
  363. package/dist/lib/brand.d.ts +0 -20
  364. package/dist/lib/brand.js +0 -50
  365. package/dist/lib/browser/context.d.ts +0 -54
  366. package/dist/lib/browser/context.js +0 -49
  367. package/dist/lib/browser/paths.d.ts +0 -21
  368. package/dist/lib/browser/paths.js +0 -26
  369. package/dist/lib/browser/record.d.ts +0 -34
  370. package/dist/lib/browser/record.js +0 -38
  371. package/dist/lib/browser/sessions-list.d.ts +1 -79
  372. package/dist/lib/browser/sessions-list.js +2 -98
  373. package/dist/lib/browser-client.d.ts +0 -112
  374. package/dist/lib/browser-client.js +1 -90
  375. package/dist/lib/budget/config.d.ts +0 -6
  376. package/dist/lib/budget/config.js +0 -29
  377. package/dist/lib/budget/enforce.d.ts +0 -50
  378. package/dist/lib/budget/enforce.js +0 -27
  379. package/dist/lib/budget/ledger.d.ts +0 -23
  380. package/dist/lib/budget/ledger.js +0 -28
  381. package/dist/lib/budget/live-cloud.d.ts +0 -26
  382. package/dist/lib/budget/live-cloud.js +0 -12
  383. package/dist/lib/budget/live-team.d.ts +0 -17
  384. package/dist/lib/budget/live-team.js +1 -35
  385. package/dist/lib/budget/preflight.d.ts +0 -51
  386. package/dist/lib/budget/preflight.js +0 -36
  387. package/dist/lib/byok-usage.d.ts +0 -20
  388. package/dist/lib/byok-usage.js +1 -24
  389. package/dist/lib/capabilities.d.ts +0 -24
  390. package/dist/lib/capabilities.js +0 -29
  391. package/dist/lib/catchup.d.ts +0 -87
  392. package/dist/lib/catchup.js +1 -81
  393. package/dist/lib/channels/owner-forward.d.ts +0 -70
  394. package/dist/lib/channels/owner-forward.js +1 -43
  395. package/dist/lib/channels/owner-sink.js +0 -21
  396. package/dist/lib/channels/providers/desktop.d.ts +0 -37
  397. package/dist/lib/channels/providers/desktop.js +0 -72
  398. package/dist/lib/channels/providers/index.d.ts +0 -1
  399. package/dist/lib/channels/providers/index.js +2 -6
  400. package/dist/lib/channels/providers/mailbox.js +0 -7
  401. package/dist/lib/channels/providers/openclaw-telegram.js +0 -8
  402. package/dist/lib/channels/providers/rush.d.ts +0 -2
  403. package/dist/lib/channels/providers/rush.js +0 -26
  404. package/dist/lib/channels/providers/session.d.ts +2 -0
  405. package/dist/lib/channels/providers/session.js +26 -0
  406. package/dist/lib/channels/registry.d.ts +0 -27
  407. package/dist/lib/channels/registry.js +0 -10
  408. package/dist/lib/channels/resolve.d.ts +0 -19
  409. package/dist/lib/channels/resolve.js +0 -2
  410. package/dist/lib/channels/send.d.ts +0 -50
  411. package/dist/lib/channels/send.js +0 -25
  412. package/dist/lib/checkpoint.d.ts +0 -36
  413. package/dist/lib/checkpoint.js +0 -28
  414. package/dist/lib/claude-account-token.d.ts +0 -98
  415. package/dist/lib/claude-account-token.js +7 -169
  416. package/dist/lib/claude-statusline.d.ts +0 -41
  417. package/dist/lib/claude-statusline.js +0 -68
  418. package/dist/lib/cli-entry.d.ts +0 -26
  419. package/dist/lib/cli-entry.js +1 -61
  420. package/dist/lib/cli-resources.d.ts +31 -89
  421. package/dist/lib/cli-resources.js +116 -152
  422. package/dist/lib/cloud/antigravity.d.ts +0 -29
  423. package/dist/lib/cloud/antigravity.js +0 -36
  424. package/dist/lib/cloud/codex.d.ts +0 -8
  425. package/dist/lib/cloud/codex.js +0 -41
  426. package/dist/lib/cloud/cursor.d.ts +0 -5
  427. package/dist/lib/cloud/cursor.js +2 -7
  428. package/dist/lib/cloud/dispatch.d.ts +0 -13
  429. package/dist/lib/cloud/dispatch.js +1 -48
  430. package/dist/lib/cloud/factory.d.ts +0 -52
  431. package/dist/lib/cloud/factory.js +3 -67
  432. package/dist/lib/cloud/host.d.ts +0 -39
  433. package/dist/lib/cloud/host.js +5 -48
  434. package/dist/lib/cloud/registry.d.ts +0 -25
  435. package/dist/lib/cloud/registry.js +0 -29
  436. package/dist/lib/cloud/rush.d.ts +0 -47
  437. package/dist/lib/cloud/rush.js +1 -82
  438. package/dist/lib/cloud/session-index.d.ts +0 -27
  439. package/dist/lib/cloud/session-index.js +1 -32
  440. package/dist/lib/cloud/store.d.ts +0 -18
  441. package/dist/lib/cloud/store.js +0 -28
  442. package/dist/lib/cloud/stream.d.ts +0 -14
  443. package/dist/lib/cloud/stream.js +0 -25
  444. package/dist/lib/cloud/types.d.ts +0 -168
  445. package/dist/lib/cloud/types.js +0 -46
  446. package/dist/lib/cloudflare/creds.d.ts +0 -2
  447. package/dist/lib/cloudflare/creds.js +0 -14
  448. package/dist/lib/cloudflare/provision.d.ts +0 -8
  449. package/dist/lib/cloudflare/provision.js +1 -19
  450. package/dist/lib/codex-home.d.ts +0 -60
  451. package/dist/lib/codex-home.js +2 -72
  452. package/dist/lib/codex-policy.d.ts +0 -10
  453. package/dist/lib/codex-policy.js +0 -13
  454. package/dist/lib/command-skills.d.ts +0 -10
  455. package/dist/lib/command-skills.js +0 -10
  456. package/dist/lib/commands.d.ts +0 -74
  457. package/dist/lib/commands.js +0 -112
  458. package/dist/lib/comms-render.d.ts +0 -5
  459. package/dist/lib/comms-render.js +0 -5
  460. package/dist/lib/computer/context.d.ts +0 -23
  461. package/dist/lib/computer/context.js +0 -14
  462. package/dist/lib/computer/policy.d.ts +0 -20
  463. package/dist/lib/computer/policy.js +0 -53
  464. package/dist/lib/computer/record.d.ts +0 -33
  465. package/dist/lib/computer/record.js +1 -48
  466. package/dist/lib/computer/sessions-list.d.ts +1 -128
  467. package/dist/lib/computer/sessions-list.js +6 -165
  468. package/dist/lib/computer-client.d.ts +0 -106
  469. package/dist/lib/computer-client.js +5 -86
  470. package/dist/lib/concurrency.d.ts +0 -14
  471. package/dist/lib/concurrency.js +0 -3
  472. package/dist/lib/config-drift.d.ts +0 -31
  473. package/dist/lib/config-drift.js +0 -32
  474. package/dist/lib/config-keys.d.ts +1 -65
  475. package/dist/lib/config-keys.js +6 -52
  476. package/dist/lib/config-transfer.d.ts +0 -14
  477. package/dist/lib/config-transfer.js +0 -26
  478. package/dist/lib/convert.d.ts +0 -17
  479. package/dist/lib/convert.js +0 -18
  480. package/dist/lib/crabbox/cli.d.ts +0 -156
  481. package/dist/lib/crabbox/cli.js +1 -188
  482. package/dist/lib/crabbox/config.d.ts +0 -18
  483. package/dist/lib/crabbox/config.js +1 -19
  484. package/dist/lib/crabbox/lease.d.ts +0 -93
  485. package/dist/lib/crabbox/lease.js +4 -148
  486. package/dist/lib/crabbox/progress.d.ts +0 -56
  487. package/dist/lib/crabbox/progress.js +2 -49
  488. package/dist/lib/crabbox/runtimes.d.ts +0 -94
  489. package/dist/lib/crabbox/runtimes.js +1 -111
  490. package/dist/lib/crabbox/setup-copy.d.ts +0 -64
  491. package/dist/lib/crabbox/setup-copy.js +1 -53
  492. package/dist/lib/daemon/account-state-daemon-service.d.ts +0 -48
  493. package/dist/lib/daemon/account-state-daemon-service.js +2 -63
  494. package/dist/lib/daemon/attention-notify-service.d.ts +0 -12
  495. package/dist/lib/daemon/attention-notify-service.js +1 -24
  496. package/dist/lib/daemon/auth-sync-service.d.ts +0 -28
  497. package/dist/lib/daemon/auth-sync-service.js +0 -56
  498. package/dist/lib/daemon/catchup-service.d.ts +0 -34
  499. package/dist/lib/daemon/catchup-service.js +0 -30
  500. package/dist/lib/daemon/daemon.d.ts +0 -374
  501. package/dist/lib/daemon/daemon.js +44 -1049
  502. package/dist/lib/daemon/daemon.test-fixture.d.ts +0 -19
  503. package/dist/lib/daemon/daemon.test-fixture.js +1 -24
  504. package/dist/lib/daemon/device-probe-service.d.ts +0 -16
  505. package/dist/lib/daemon/device-probe-service.js +0 -20
  506. package/dist/lib/daemon/feed-stream-service.d.ts +0 -15
  507. package/dist/lib/daemon/feed-stream-service.js +0 -20
  508. package/dist/lib/daemon/harness-update-service.d.ts +2 -61
  509. package/dist/lib/daemon/harness-update-service.js +6 -86
  510. package/dist/lib/daemon/heartbeat-service.d.ts +0 -1
  511. package/dist/lib/daemon/heartbeat-service.js +0 -1
  512. package/dist/lib/daemon/leaked-daemons.d.ts +0 -46
  513. package/dist/lib/daemon/leaked-daemons.js +2 -78
  514. package/dist/lib/daemon/monitor-engine-service.d.ts +0 -13
  515. package/dist/lib/daemon/monitor-engine-service.js +3 -15
  516. package/dist/lib/daemon/runner.d.ts +0 -194
  517. package/dist/lib/daemon/runner.js +39 -760
  518. package/dist/lib/daemon/self-heal-service.d.ts +18 -17
  519. package/dist/lib/daemon/self-heal-service.js +83 -37
  520. package/dist/lib/daemon/self-update-service.d.ts +1 -131
  521. package/dist/lib/daemon/self-update-service.js +26 -189
  522. package/dist/lib/daemon/service.d.ts +0 -73
  523. package/dist/lib/daemon/service.js +0 -34
  524. package/dist/lib/daemon/session-index-service.d.ts +0 -12
  525. package/dist/lib/daemon/session-index-service.js +0 -23
  526. package/dist/lib/daemon/session-state-service.d.ts +0 -8
  527. package/dist/lib/daemon/session-state-service.js +0 -8
  528. package/dist/lib/daemon/session-summarizer-service.d.ts +0 -14
  529. package/dist/lib/daemon/session-summarizer-service.js +1 -19
  530. package/dist/lib/daemon/session-title-service.d.ts +0 -25
  531. package/dist/lib/daemon/session-title-service.js +0 -32
  532. package/dist/lib/daemon/state-dir-check-service.d.ts +0 -24
  533. package/dist/lib/daemon/state-dir-check-service.js +0 -29
  534. package/dist/lib/daemon/supervisor.d.ts +0 -112
  535. package/dist/lib/daemon/supervisor.js +4 -147
  536. package/dist/lib/daemon/testdata/process-view-daemon.js +0 -2
  537. package/dist/lib/daemon/testdata/process-view-start.js +0 -5
  538. package/dist/lib/daemon/tmux-reap-service.d.ts +0 -1
  539. package/dist/lib/daemon/tmux-reap-service.js +0 -1
  540. package/dist/lib/daemon/usage-sync-service.d.ts +0 -23
  541. package/dist/lib/daemon/usage-sync-service.js +0 -26
  542. package/dist/lib/daemon/watchdog-service.d.ts +0 -9
  543. package/dist/lib/daemon/watchdog-service.js +0 -13
  544. package/dist/lib/daemon/webhook-receiver-service.d.ts +0 -1
  545. package/dist/lib/daemon/webhook-receiver-service.js +0 -1
  546. package/dist/lib/daemon-health.d.ts +0 -55
  547. package/dist/lib/daemon-health.js +4 -77
  548. package/dist/lib/daemon-services.d.ts +0 -36
  549. package/dist/lib/daemon-services.js +0 -45
  550. package/dist/lib/daemon-ticks.d.ts +0 -126
  551. package/dist/lib/daemon-ticks.js +1 -156
  552. package/dist/lib/daemon-webhooks.d.ts +0 -57
  553. package/dist/lib/daemon-webhooks.js +2 -54
  554. package/dist/lib/deeplink/register.d.ts +0 -15
  555. package/dist/lib/deeplink/register.js +0 -60
  556. package/dist/lib/deeplink/url.d.ts +0 -24
  557. package/dist/lib/deeplink/url.js +1 -33
  558. package/dist/lib/device-config.d.ts +1 -192
  559. package/dist/lib/device-config.js +86 -240
  560. package/dist/lib/devices/config-migration.d.ts +0 -43
  561. package/dist/lib/devices/config-migration.js +7 -127
  562. package/dist/lib/devices/connect.d.ts +0 -168
  563. package/dist/lib/devices/connect.js +6 -254
  564. package/dist/lib/devices/device-docs.d.ts +0 -24
  565. package/dist/lib/devices/device-docs.js +0 -46
  566. package/dist/lib/devices/discovery-policy.d.ts +0 -30
  567. package/dist/lib/devices/discovery-policy.js +3 -34
  568. package/dist/lib/devices/doctor-findings.d.ts +0 -109
  569. package/dist/lib/devices/doctor-findings.js +30 -326
  570. package/dist/lib/devices/doctor-overview-cache.d.ts +0 -33
  571. package/dist/lib/devices/doctor-overview-cache.js +0 -81
  572. package/dist/lib/devices/fleet-divergence.d.ts +0 -89
  573. package/dist/lib/devices/fleet-divergence.js +1 -60
  574. package/dist/lib/devices/fleet-inventory.d.ts +0 -27
  575. package/dist/lib/devices/fleet-inventory.js +0 -38
  576. package/dist/lib/devices/fleet.d.ts +0 -95
  577. package/dist/lib/devices/fleet.js +0 -79
  578. package/dist/lib/devices/harness-inventory.d.ts +0 -75
  579. package/dist/lib/devices/harness-inventory.js +0 -101
  580. package/dist/lib/devices/health-report.d.ts +0 -37
  581. package/dist/lib/devices/health-report.js +0 -73
  582. package/dist/lib/devices/health.d.ts +0 -71
  583. package/dist/lib/devices/health.js +2 -82
  584. package/dist/lib/devices/interactive-host.d.ts +0 -10
  585. package/dist/lib/devices/interactive-host.js +0 -34
  586. package/dist/lib/devices/known-hosts.d.ts +0 -45
  587. package/dist/lib/devices/known-hosts.js +0 -77
  588. package/dist/lib/devices/pending.d.ts +0 -31
  589. package/dist/lib/devices/pending.js +7 -67
  590. package/dist/lib/devices/pool.d.ts +0 -36
  591. package/dist/lib/devices/pool.js +0 -30
  592. package/dist/lib/devices/reachability.d.ts +0 -25
  593. package/dist/lib/devices/reachability.js +0 -14
  594. package/dist/lib/devices/registry.d.ts +0 -141
  595. package/dist/lib/devices/registry.js +4 -151
  596. package/dist/lib/devices/resolve-profile.d.ts +0 -18
  597. package/dist/lib/devices/resolve-profile.js +0 -18
  598. package/dist/lib/devices/resolve-target.d.ts +0 -20
  599. package/dist/lib/devices/resolve-target.js +1 -51
  600. package/dist/lib/devices/rollout-verify.d.ts +1 -81
  601. package/dist/lib/devices/rollout-verify.js +0 -77
  602. package/dist/lib/devices/self-host.d.ts +0 -7
  603. package/dist/lib/devices/self-host.js +1 -29
  604. package/dist/lib/devices/ssh-config.d.ts +0 -18
  605. package/dist/lib/devices/ssh-config.js +0 -9
  606. package/dist/lib/devices/stats-cache.d.ts +0 -48
  607. package/dist/lib/devices/stats-cache.js +0 -80
  608. package/dist/lib/devices/sync.d.ts +0 -97
  609. package/dist/lib/devices/sync.js +0 -88
  610. package/dist/lib/devices/tailscale.d.ts +0 -18
  611. package/dist/lib/devices/tailscale.js +1 -38
  612. package/dist/lib/devices/terminfo.d.ts +0 -27
  613. package/dist/lib/devices/terminfo.js +2 -64
  614. package/dist/lib/devices/worker-pick.d.ts +0 -15
  615. package/dist/lib/devices/worker-pick.js +0 -48
  616. package/dist/lib/diff-text.d.ts +0 -18
  617. package/dist/lib/diff-text.js +0 -15
  618. package/dist/lib/doctor-diff.d.ts +0 -79
  619. package/dist/lib/doctor-diff.js +2 -181
  620. package/dist/lib/drift-sync.d.ts +0 -29
  621. package/dist/lib/drift-sync.js +0 -40
  622. package/dist/lib/drift.d.ts +0 -43
  623. package/dist/lib/drift.js +0 -31
  624. package/dist/lib/event-families.d.ts +0 -17
  625. package/dist/lib/event-families.js +0 -33
  626. package/dist/lib/event-provenance.d.ts +0 -4
  627. package/dist/lib/event-provenance.js +0 -5
  628. package/dist/lib/event-stream.d.ts +0 -29
  629. package/dist/lib/event-stream.js +0 -36
  630. package/dist/lib/events-ingest.d.ts +0 -27
  631. package/dist/lib/events-ingest.js +0 -54
  632. package/dist/lib/exec-account-home.d.ts +0 -24
  633. package/dist/lib/exec-account-home.js +0 -41
  634. package/dist/lib/exec-bounded.d.ts +1 -37
  635. package/dist/lib/exec-bounded.js +10 -46
  636. package/dist/lib/exec.d.ts +3 -583
  637. package/dist/lib/exec.js +18 -1025
  638. package/dist/lib/factory/snapshot.js +1 -15
  639. package/dist/lib/feed/activity-stream.d.ts +0 -27
  640. package/dist/lib/feed/activity-stream.js +4 -80
  641. package/dist/lib/feed/activity.d.ts +1 -243
  642. package/dist/lib/feed/activity.js +8 -273
  643. package/dist/lib/feed/answer.d.ts +0 -103
  644. package/dist/lib/feed/answer.js +0 -267
  645. package/dist/lib/feed/attention.d.ts +0 -56
  646. package/dist/lib/feed/attention.js +0 -161
  647. package/dist/lib/feed/envelope.d.ts +2 -17
  648. package/dist/lib/feed/envelope.js +0 -14
  649. package/dist/lib/feed/events.d.ts +0 -118
  650. package/dist/lib/feed/events.js +13 -213
  651. package/dist/lib/feed/feed.d.ts +1 -250
  652. package/dist/lib/feed/feed.js +24 -334
  653. package/dist/lib/feed/hub-server.d.ts +0 -100
  654. package/dist/lib/feed/hub-server.js +1 -191
  655. package/dist/lib/feed/hub.d.ts +0 -53
  656. package/dist/lib/feed/hub.js +0 -89
  657. package/dist/lib/feed/pr-status.d.ts +1 -19
  658. package/dist/lib/feed/pr-status.js +0 -18
  659. package/dist/lib/feed/tool-activity.d.ts +0 -59
  660. package/dist/lib/feed/tool-activity.js +1 -119
  661. package/dist/lib/feed/tools.d.ts +0 -100
  662. package/dist/lib/feed/tools.js +0 -89
  663. package/dist/lib/feed/watch.d.ts +0 -33
  664. package/dist/lib/feed/watch.js +2 -94
  665. package/dist/lib/feed-broadcast.d.ts +0 -148
  666. package/dist/lib/feed-broadcast.js +1 -283
  667. package/dist/lib/feed-outcome.d.ts +0 -50
  668. package/dist/lib/feed-outcome.js +1 -67
  669. package/dist/lib/feed-policy.d.ts +0 -6
  670. package/dist/lib/feed-policy.js +1 -27
  671. package/dist/lib/feed-post.d.ts +0 -61
  672. package/dist/lib/feed-post.js +4 -61
  673. package/dist/lib/feed-ranking.d.ts +1 -1
  674. package/dist/lib/fleet/apply.d.ts +0 -64
  675. package/dist/lib/fleet/apply.js +0 -125
  676. package/dist/lib/fleet/auth-sync.d.ts +0 -48
  677. package/dist/lib/fleet/auth-sync.js +4 -49
  678. package/dist/lib/fleet/capture.d.ts +0 -26
  679. package/dist/lib/fleet/capture.js +1 -36
  680. package/dist/lib/fleet/manifest.d.ts +0 -38
  681. package/dist/lib/fleet/manifest.js +0 -40
  682. package/dist/lib/fleet/types.d.ts +1 -138
  683. package/dist/lib/fleet/types.js +0 -12
  684. package/dist/lib/fleet-cache.d.ts +0 -12
  685. package/dist/lib/fleet-cache.js +0 -24
  686. package/dist/lib/fleet-shared-state.d.ts +6 -59
  687. package/dist/lib/fleet-shared-state.js +5 -51
  688. package/dist/lib/fleet-status.d.ts +0 -27
  689. package/dist/lib/fleet-status.js +0 -48
  690. package/dist/lib/format.d.ts +0 -74
  691. package/dist/lib/format.js +3 -77
  692. package/dist/lib/friction-heuristics.d.ts +0 -20
  693. package/dist/lib/friction-heuristics.js +0 -8
  694. package/dist/lib/fs-atomic.d.ts +0 -51
  695. package/dist/lib/fs-atomic.js +8 -66
  696. package/dist/lib/fs-walk.d.ts +0 -13
  697. package/dist/lib/fs-walk.js +0 -22
  698. package/dist/lib/fuzzy.d.ts +0 -29
  699. package/dist/lib/fuzzy.js +0 -31
  700. package/dist/lib/gemini-settings.js +0 -12
  701. package/dist/lib/git.d.ts +0 -366
  702. package/dist/lib/git.js +7 -574
  703. package/dist/lib/github/ci-failure.d.ts +30 -0
  704. package/dist/lib/github/ci-failure.js +95 -0
  705. package/dist/lib/github/gh-overload.d.ts +0 -38
  706. package/dist/lib/github/gh-overload.js +3 -55
  707. package/dist/lib/github/pr-mergeable.d.ts +3 -34
  708. package/dist/lib/github/pr-mergeable.js +2 -42
  709. package/dist/lib/github/pr-verdict.d.ts +0 -44
  710. package/dist/lib/github/pr-verdict.js +0 -36
  711. package/dist/lib/github/project-prs.d.ts +135 -105
  712. package/dist/lib/github/project-prs.js +530 -170
  713. package/dist/lib/github/release-drift.d.ts +45 -0
  714. package/dist/lib/github/release-drift.js +91 -0
  715. package/dist/lib/github/rest.d.ts +0 -50
  716. package/dist/lib/github/rest.js +0 -49
  717. package/dist/lib/github/viewer.d.ts +27 -0
  718. package/dist/lib/github/viewer.js +101 -0
  719. package/dist/lib/goose-commands.d.ts +0 -29
  720. package/dist/lib/goose-commands.js +3 -48
  721. package/dist/lib/harness/adapter.d.ts +0 -151
  722. package/dist/lib/harness/adapter.js +0 -41
  723. package/dist/lib/harness/adapters/claude.d.ts +0 -8
  724. package/dist/lib/harness/adapters/claude.js +0 -89
  725. package/dist/lib/harness/adapters/codex.js +0 -18
  726. package/dist/lib/harness/adapters/copilot.js +0 -3
  727. package/dist/lib/harness/adapters/cursor.js +0 -16
  728. package/dist/lib/harness/adapters/droid.js +0 -3
  729. package/dist/lib/harness/adapters/kimi.js +0 -19
  730. package/dist/lib/harness/adapters/muse.js +0 -9
  731. package/dist/lib/harness/adapters/opencode.js +0 -2
  732. package/dist/lib/harness/exec-config-version.d.ts +0 -2
  733. package/dist/lib/harness/exec-config-version.js +0 -13
  734. package/dist/lib/harness/index.js +0 -10
  735. package/dist/lib/harness-auth-capabilities.d.ts +0 -26
  736. package/dist/lib/harness-auth-capabilities.js +0 -18
  737. package/dist/lib/harness-connection-test.d.ts +0 -27
  738. package/dist/lib/harness-connection-test.js +2 -20
  739. package/dist/lib/heal.d.ts +0 -45
  740. package/dist/lib/heal.js +2 -82
  741. package/dist/lib/help.d.ts +0 -32
  742. package/dist/lib/help.js +0 -41
  743. package/dist/lib/helper-download.d.ts +0 -85
  744. package/dist/lib/helper-download.js +0 -95
  745. package/dist/lib/helper-versions.d.ts +0 -51
  746. package/dist/lib/helper-versions.js +1 -45
  747. package/dist/lib/hooks/cache.d.ts +0 -40
  748. package/dist/lib/hooks/cache.js +8 -122
  749. package/dist/lib/hooks/install.d.ts +0 -253
  750. package/dist/lib/hooks/install.js +49 -822
  751. package/dist/lib/hooks/match.d.ts +0 -24
  752. package/dist/lib/hooks/match.js +0 -31
  753. package/dist/lib/hooks/profile.d.ts +0 -21
  754. package/dist/lib/hooks/profile.js +0 -28
  755. package/dist/lib/hosts/credential-transport.d.ts +0 -6
  756. package/dist/lib/hosts/credential-transport.js +0 -17
  757. package/dist/lib/hosts/credentials.d.ts +0 -35
  758. package/dist/lib/hosts/credentials.js +0 -38
  759. package/dist/lib/hosts/dispatch.d.ts +0 -140
  760. package/dist/lib/hosts/dispatch.js +0 -176
  761. package/dist/lib/hosts/logs.d.ts +0 -25
  762. package/dist/lib/hosts/logs.js +1 -51
  763. package/dist/lib/hosts/option.d.ts +0 -12
  764. package/dist/lib/hosts/option.js +0 -12
  765. package/dist/lib/hosts/passthrough.d.ts +0 -129
  766. package/dist/lib/hosts/passthrough.js +12 -249
  767. package/dist/lib/hosts/progress.d.ts +0 -90
  768. package/dist/lib/hosts/progress.js +5 -115
  769. package/dist/lib/hosts/providers/devices.d.ts +0 -19
  770. package/dist/lib/hosts/providers/devices.js +1 -34
  771. package/dist/lib/hosts/providers/local.d.ts +0 -14
  772. package/dist/lib/hosts/providers/local.js +0 -22
  773. package/dist/lib/hosts/ready.d.ts +0 -99
  774. package/dist/lib/hosts/ready.js +0 -101
  775. package/dist/lib/hosts/reconcile.d.ts +0 -38
  776. package/dist/lib/hosts/reconcile.js +1 -50
  777. package/dist/lib/hosts/reconnect.d.ts +0 -75
  778. package/dist/lib/hosts/reconnect.js +0 -98
  779. package/dist/lib/hosts/registry.d.ts +0 -74
  780. package/dist/lib/hosts/registry.js +0 -110
  781. package/dist/lib/hosts/remote-cmd.d.ts +1 -228
  782. package/dist/lib/hosts/remote-cmd.js +19 -294
  783. package/dist/lib/hosts/remote-cmd.test-fixture.d.ts +0 -1
  784. package/dist/lib/hosts/remote-cmd.test-fixture.js +0 -12
  785. package/dist/lib/hosts/remote-os.d.ts +0 -19
  786. package/dist/lib/hosts/remote-os.js +0 -22
  787. package/dist/lib/hosts/remote-session-id.d.ts +0 -22
  788. package/dist/lib/hosts/remote-session-id.js +0 -24
  789. package/dist/lib/hosts/routing-flag.d.ts +0 -21
  790. package/dist/lib/hosts/routing-flag.js +0 -21
  791. package/dist/lib/hosts/run-target.d.ts +0 -53
  792. package/dist/lib/hosts/run-target.js +0 -56
  793. package/dist/lib/hosts/session-index.d.ts +1 -53
  794. package/dist/lib/hosts/session-index.js +2 -59
  795. package/dist/lib/hosts/session-marker.d.ts +0 -31
  796. package/dist/lib/hosts/session-marker.js +0 -32
  797. package/dist/lib/hosts/ssh-config.d.ts +0 -25
  798. package/dist/lib/hosts/ssh-config.js +1 -32
  799. package/dist/lib/hosts/tasks.d.ts +0 -54
  800. package/dist/lib/hosts/tasks.js +0 -35
  801. package/dist/lib/hosts/types.d.ts +0 -39
  802. package/dist/lib/hosts/types.js +0 -22
  803. package/dist/lib/humans.d.ts +0 -21
  804. package/dist/lib/humans.js +0 -30
  805. package/dist/lib/identity/client.d.ts +1 -35
  806. package/dist/lib/identity/client.js +3 -29
  807. package/dist/lib/identity/index.d.ts +3 -27
  808. package/dist/lib/identity/index.js +8 -24
  809. package/dist/lib/import.d.ts +0 -104
  810. package/dist/lib/import.js +1 -137
  811. package/dist/lib/installations/active-check.d.ts +0 -53
  812. package/dist/lib/installations/active-check.js +0 -49
  813. package/dist/lib/installations/index.d.ts +0 -9
  814. package/dist/lib/installations/index.js +0 -9
  815. package/dist/lib/installations/installation-lock.js +0 -8
  816. package/dist/lib/installations/launch-gate.d.ts +0 -56
  817. package/dist/lib/installations/launch-gate.js +0 -83
  818. package/dist/lib/installations/migrate.d.ts +0 -100
  819. package/dist/lib/installations/migrate.js +105 -572
  820. package/dist/lib/installations/native-command.d.ts +0 -1
  821. package/dist/lib/installations/native-command.js +0 -6
  822. package/dist/lib/installations/resolve.d.ts +0 -24
  823. package/dist/lib/installations/resolve.js +0 -24
  824. package/dist/lib/installations/shims.d.ts +0 -395
  825. package/dist/lib/installations/shims.js +30 -957
  826. package/dist/lib/installations/store.d.ts +0 -199
  827. package/dist/lib/installations/store.js +1 -297
  828. package/dist/lib/installations/strategies.d.ts +0 -44
  829. package/dist/lib/installations/strategies.js +0 -87
  830. package/dist/lib/installations/types.d.ts +1 -67
  831. package/dist/lib/installations/types.js +0 -6
  832. package/dist/lib/installations/update-cancellation.d.ts +0 -74
  833. package/dist/lib/installations/update-cancellation.js +0 -74
  834. package/dist/lib/installations/update-policy.d.ts +0 -57
  835. package/dist/lib/installations/update-policy.js +0 -62
  836. package/dist/lib/installations/update-runtime.d.ts +0 -88
  837. package/dist/lib/installations/update-runtime.js +1 -127
  838. package/dist/lib/installations/update.d.ts +0 -53
  839. package/dist/lib/installations/update.js +0 -95
  840. package/dist/lib/installations/versions.d.ts +0 -310
  841. package/dist/lib/installations/versions.js +14 -837
  842. package/dist/lib/isolation-boundary-report.d.ts +0 -7
  843. package/dist/lib/isolation-boundary-report.js +0 -7
  844. package/dist/lib/launch-identity.d.ts +0 -8
  845. package/dist/lib/launch-identity.js +0 -8
  846. package/dist/lib/linear-autoclose.d.ts +0 -25
  847. package/dist/lib/linear-autoclose.js +0 -19
  848. package/dist/lib/linear-cache.d.ts +0 -57
  849. package/dist/lib/linear-cache.js +1 -81
  850. package/dist/lib/linear-project-counts.d.ts +0 -83
  851. package/dist/lib/linear-project-counts.js +2 -64
  852. package/dist/lib/linear-projects.d.ts +0 -62
  853. package/dist/lib/linear-projects.js +0 -85
  854. package/dist/lib/linear-rate-limit.d.ts +0 -21
  855. package/dist/lib/linear-rate-limit.js +1 -93
  856. package/dist/lib/linux-userns.d.ts +1 -42
  857. package/dist/lib/linux-userns.js +0 -47
  858. package/dist/lib/lock-compromise.d.ts +0 -7
  859. package/dist/lib/lock-compromise.js +0 -7
  860. package/dist/lib/log-follow.d.ts +0 -2
  861. package/dist/lib/log-follow.js +5 -15
  862. package/dist/lib/loop.d.ts +0 -106
  863. package/dist/lib/loop.js +0 -135
  864. package/dist/lib/machine-id.d.ts +0 -19
  865. package/dist/lib/machine-id.js +0 -19
  866. package/dist/lib/mailbox-gc.d.ts +0 -7
  867. package/dist/lib/mailbox-gc.js +0 -25
  868. package/dist/lib/mailbox-target.d.ts +0 -31
  869. package/dist/lib/mailbox-target.js +0 -27
  870. package/dist/lib/mailbox.d.ts +0 -77
  871. package/dist/lib/mailbox.js +5 -105
  872. package/dist/lib/manifest.d.ts +0 -4
  873. package/dist/lib/manifest.js +0 -36
  874. package/dist/lib/markdown.d.ts +0 -3
  875. package/dist/lib/markdown.js +0 -9
  876. package/dist/lib/mcp-registry.d.ts +1 -50
  877. package/dist/lib/mcp-registry.js +0 -64
  878. package/dist/lib/mcp.d.ts +0 -115
  879. package/dist/lib/mcp.js +3 -199
  880. package/dist/lib/memory-cache.d.ts +0 -11
  881. package/dist/lib/memory-cache.js +0 -9
  882. package/dist/lib/memory.d.ts +0 -52
  883. package/dist/lib/memory.js +12 -74
  884. package/dist/lib/menubar/download-menubar.d.ts +0 -35
  885. package/dist/lib/menubar/download-menubar.js +0 -38
  886. package/dist/lib/menubar/install-menubar.d.ts +0 -405
  887. package/dist/lib/menubar/install-menubar.js +25 -667
  888. package/dist/lib/menubar/migrate-prefs.d.ts +0 -47
  889. package/dist/lib/menubar/migrate-prefs.js +1 -70
  890. package/dist/lib/menubar/notify-desktop.d.ts +0 -82
  891. package/dist/lib/menubar/notify-desktop.js +0 -68
  892. package/dist/lib/menubar/resolve-version.d.ts +0 -41
  893. package/dist/lib/menubar/resolve-version.js +2 -44
  894. package/dist/lib/menubar/snapshot.d.ts +13 -66
  895. package/dist/lib/menubar/snapshot.js +45 -39
  896. package/dist/lib/merged-resources.d.ts +0 -10
  897. package/dist/lib/merged-resources.js +0 -10
  898. package/dist/lib/migrate-fold.d.ts +0 -31
  899. package/dist/lib/migrate-fold.js +6 -38
  900. package/dist/lib/model-tier-overrides.d.ts +0 -30
  901. package/dist/lib/model-tier-overrides.js +0 -14
  902. package/dist/lib/model-tiers.d.ts +0 -43
  903. package/dist/lib/model-tiers.js +5 -78
  904. package/dist/lib/models.d.ts +0 -145
  905. package/dist/lib/models.js +3 -333
  906. package/dist/lib/monitors/config.d.ts +0 -187
  907. package/dist/lib/monitors/config.js +4 -101
  908. package/dist/lib/monitors/dispatch.d.ts +0 -22
  909. package/dist/lib/monitors/dispatch.js +0 -35
  910. package/dist/lib/monitors/engine.d.ts +1 -53
  911. package/dist/lib/monitors/engine.js +17 -106
  912. package/dist/lib/monitors/fingerprint.d.ts +0 -43
  913. package/dist/lib/monitors/fingerprint.js +0 -57
  914. package/dist/lib/monitors/pid-watch.d.ts +0 -31
  915. package/dist/lib/monitors/pid-watch.js +0 -31
  916. package/dist/lib/monitors/remote.d.ts +0 -52
  917. package/dist/lib/monitors/remote.js +0 -42
  918. package/dist/lib/monitors/sources/command.d.ts +2 -9
  919. package/dist/lib/monitors/sources/command.js +13 -34
  920. package/dist/lib/monitors/sources/device.d.ts +0 -10
  921. package/dist/lib/monitors/sources/device.js +0 -14
  922. package/dist/lib/monitors/sources/failure.d.ts +0 -27
  923. package/dist/lib/monitors/sources/failure.js +0 -27
  924. package/dist/lib/monitors/sources/file.d.ts +0 -10
  925. package/dist/lib/monitors/sources/file.js +0 -11
  926. package/dist/lib/monitors/sources/http.d.ts +0 -7
  927. package/dist/lib/monitors/sources/http.js +0 -9
  928. package/dist/lib/monitors/sources/index.d.ts +0 -9
  929. package/dist/lib/monitors/sources/index.js +0 -9
  930. package/dist/lib/monitors/sources/poll.d.ts +0 -8
  931. package/dist/lib/monitors/sources/poll.js +0 -8
  932. package/dist/lib/monitors/sources/types.d.ts +0 -18
  933. package/dist/lib/monitors/sources/types.js +0 -8
  934. package/dist/lib/monitors/sources/webhook.d.ts +0 -7
  935. package/dist/lib/monitors/sources/webhook.js +0 -7
  936. package/dist/lib/monitors/sources/ws.d.ts +0 -10
  937. package/dist/lib/monitors/sources/ws.js +3 -13
  938. package/dist/lib/monitors/state.d.ts +0 -132
  939. package/dist/lib/monitors/state.js +2 -86
  940. package/dist/lib/native-accounts.d.ts +0 -32
  941. package/dist/lib/native-accounts.js +0 -17
  942. package/dist/lib/net-close.d.ts +0 -9
  943. package/dist/lib/net-close.js +0 -5
  944. package/dist/lib/notify.d.ts +0 -47
  945. package/dist/lib/notify.js +0 -30
  946. package/dist/lib/onepassword.d.ts +0 -14
  947. package/dist/lib/onepassword.js +0 -12
  948. package/dist/lib/open-url.d.ts +0 -38
  949. package/dist/lib/open-url.js +1 -69
  950. package/dist/lib/openclaw-keychain.js +2 -7
  951. package/dist/lib/operator.d.ts +0 -9
  952. package/dist/lib/operator.js +0 -34
  953. package/dist/lib/origin-machine.d.ts +0 -16
  954. package/dist/lib/origin-machine.js +0 -16
  955. package/dist/lib/output/git-output.d.ts +0 -31
  956. package/dist/lib/output/git-output.js +4 -43
  957. package/dist/lib/overdue.d.ts +0 -35
  958. package/dist/lib/overdue.js +0 -60
  959. package/dist/lib/owner-message.d.ts +0 -20
  960. package/dist/lib/owner-message.js +1 -40
  961. package/dist/lib/packages/output-home.d.ts +0 -28
  962. package/dist/lib/packages/output-home.js +0 -114
  963. package/dist/lib/paths.d.ts +0 -26
  964. package/dist/lib/paths.js +1 -27
  965. package/dist/lib/percentile.d.ts +0 -11
  966. package/dist/lib/percentile.js +0 -11
  967. package/dist/lib/perf/db.d.ts +0 -16
  968. package/dist/lib/perf/db.js +3 -32
  969. package/dist/lib/perf/spool.d.ts +0 -12
  970. package/dist/lib/perf/spool.js +0 -13
  971. package/dist/lib/perf/types.d.ts +0 -26
  972. package/dist/lib/perf/types.js +0 -1
  973. package/dist/lib/permissions-registry.d.ts +0 -48
  974. package/dist/lib/permissions-registry.js +0 -108
  975. package/dist/lib/permissions.d.ts +0 -215
  976. package/dist/lib/permissions.js +4 -407
  977. package/dist/lib/picker.d.ts +0 -124
  978. package/dist/lib/picker.js +0 -140
  979. package/dist/lib/placement.d.ts +0 -57
  980. package/dist/lib/placement.js +0 -47
  981. package/dist/lib/platform/exec.d.ts +0 -73
  982. package/dist/lib/platform/exec.js +0 -80
  983. package/dist/lib/platform/index.d.ts +0 -14
  984. package/dist/lib/platform/index.js +0 -14
  985. package/dist/lib/platform/ipc.d.ts +0 -10
  986. package/dist/lib/platform/ipc.js +0 -13
  987. package/dist/lib/platform/links.d.ts +0 -14
  988. package/dist/lib/platform/links.js +0 -25
  989. package/dist/lib/platform/paths.d.ts +0 -48
  990. package/dist/lib/platform/paths.js +0 -52
  991. package/dist/lib/platform/posixpath.d.ts +0 -18
  992. package/dist/lib/platform/posixpath.js +0 -62
  993. package/dist/lib/platform/process.d.ts +0 -67
  994. package/dist/lib/platform/process.js +5 -99
  995. package/dist/lib/platform/winpath.d.ts +0 -50
  996. package/dist/lib/platform/winpath.js +0 -81
  997. package/dist/lib/plugins/plugin-marketplace.d.ts +0 -165
  998. package/dist/lib/plugins/plugin-marketplace.js +10 -238
  999. package/dist/lib/plugins/plugins.d.ts +0 -238
  1000. package/dist/lib/plugins/plugins.js +20 -454
  1001. package/dist/lib/plugins/skills.d.ts +0 -86
  1002. package/dist/lib/plugins/skills.js +1 -139
  1003. package/dist/lib/pr-land-detach.d.ts +0 -17
  1004. package/dist/lib/pr-land-detach.js +0 -30
  1005. package/dist/lib/pricing/cost.d.ts +0 -29
  1006. package/dist/lib/pricing/cost.js +0 -38
  1007. package/dist/lib/pricing/index.d.ts +0 -6
  1008. package/dist/lib/pricing/index.js +0 -6
  1009. package/dist/lib/pricing/table.d.ts +0 -8
  1010. package/dist/lib/pricing/table.js +3 -56
  1011. package/dist/lib/probe.d.ts +0 -5
  1012. package/dist/lib/probe.js +0 -40
  1013. package/dist/lib/profiles-presets.d.ts +0 -20
  1014. package/dist/lib/profiles-presets.js +1 -36
  1015. package/dist/lib/profiles.d.ts +0 -185
  1016. package/dist/lib/profiles.js +1 -158
  1017. package/dist/lib/project-doctor.d.ts +0 -29
  1018. package/dist/lib/project-doctor.js +0 -26
  1019. package/dist/lib/project-focus.d.ts +0 -41
  1020. package/dist/lib/project-focus.js +0 -49
  1021. package/dist/lib/project-import.d.ts +0 -41
  1022. package/dist/lib/project-import.js +0 -36
  1023. package/dist/lib/project-key.d.ts +0 -65
  1024. package/dist/lib/project-key.js +0 -70
  1025. package/dist/lib/project-launch.d.ts +0 -49
  1026. package/dist/lib/project-launch.js +2 -91
  1027. package/dist/lib/project-probe.d.ts +0 -86
  1028. package/dist/lib/project-probe.js +1 -88
  1029. package/dist/lib/project-pull.d.ts +0 -96
  1030. package/dist/lib/project-pull.js +0 -122
  1031. package/dist/lib/project-resources.d.ts +0 -44
  1032. package/dist/lib/project-resources.js +7 -171
  1033. package/dist/lib/project-root.d.ts +0 -95
  1034. package/dist/lib/project-root.js +0 -101
  1035. package/dist/lib/project-schedule.d.ts +0 -43
  1036. package/dist/lib/project-schedule.js +0 -52
  1037. package/dist/lib/project-status.d.ts +0 -108
  1038. package/dist/lib/project-status.js +0 -117
  1039. package/dist/lib/projects.d.ts +0 -197
  1040. package/dist/lib/projects.js +1 -213
  1041. package/dist/lib/pwsh.d.ts +0 -41
  1042. package/dist/lib/pwsh.js +0 -51
  1043. package/dist/lib/quick-todo.d.ts +84 -0
  1044. package/dist/lib/quick-todo.js +243 -0
  1045. package/dist/lib/reconcile-and-repair.d.ts +0 -78
  1046. package/dist/lib/reconcile-and-repair.js +3 -66
  1047. package/dist/lib/redact.d.ts +0 -29
  1048. package/dist/lib/redact.js +0 -54
  1049. package/dist/lib/refresh-coordinator.d.ts +0 -15
  1050. package/dist/lib/refresh-coordinator.js +0 -10
  1051. package/dist/lib/refresh.d.ts +0 -39
  1052. package/dist/lib/refresh.js +0 -45
  1053. package/dist/lib/registry.d.ts +0 -65
  1054. package/dist/lib/registry.js +0 -127
  1055. package/dist/lib/reminders.d.ts +0 -21
  1056. package/dist/lib/reminders.js +0 -30
  1057. package/dist/lib/remote-agents-json.d.ts +0 -44
  1058. package/dist/lib/remote-agents-json.js +1 -44
  1059. package/dist/lib/reserved-stores.d.ts +0 -28
  1060. package/dist/lib/reserved-stores.js +2 -28
  1061. package/dist/lib/resource-aliases.d.ts +0 -12
  1062. package/dist/lib/resource-aliases.js +0 -12
  1063. package/dist/lib/resource-content-diff.d.ts +0 -28
  1064. package/dist/lib/resource-content-diff.js +7 -34
  1065. package/dist/lib/resource-inventory.d.ts +0 -51
  1066. package/dist/lib/resource-inventory.js +0 -45
  1067. package/dist/lib/resource-patterns.d.ts +0 -32
  1068. package/dist/lib/resource-patterns.js +0 -34
  1069. package/dist/lib/resource-profiles.d.ts +0 -7
  1070. package/dist/lib/resource-profiles.js +0 -11
  1071. package/dist/lib/resources/types.d.ts +0 -50
  1072. package/dist/lib/resources/types.js +0 -7
  1073. package/dist/lib/resources/workflows.d.ts +0 -7
  1074. package/dist/lib/resources/workflows.js +0 -13
  1075. package/dist/lib/resources.d.ts +0 -65
  1076. package/dist/lib/resources.js +0 -78
  1077. package/dist/lib/routers.d.ts +0 -67
  1078. package/dist/lib/routers.js +0 -60
  1079. package/dist/lib/routine-activation.d.ts +0 -23
  1080. package/dist/lib/routine-activation.js +0 -24
  1081. package/dist/lib/routine-context.d.ts +1 -91
  1082. package/dist/lib/routine-context.js +0 -107
  1083. package/dist/lib/routine-notify-owner.d.ts +0 -79
  1084. package/dist/lib/routine-notify-owner.js +1 -103
  1085. package/dist/lib/routine-notify.d.ts +0 -70
  1086. package/dist/lib/routine-notify.js +1 -75
  1087. package/dist/lib/routine-process-cleanup.d.ts +0 -1
  1088. package/dist/lib/routine-process-cleanup.js +1 -4
  1089. package/dist/lib/routine-readiness.d.ts +0 -63
  1090. package/dist/lib/routine-readiness.js +4 -86
  1091. package/dist/lib/routines-format.d.ts +0 -40
  1092. package/dist/lib/routines-format.js +0 -67
  1093. package/dist/lib/routines-placement.d.ts +0 -33
  1094. package/dist/lib/routines-placement.js +0 -40
  1095. package/dist/lib/routines-project.d.ts +0 -57
  1096. package/dist/lib/routines-project.js +6 -80
  1097. package/dist/lib/rules/compile.d.ts +0 -66
  1098. package/dist/lib/rules/compile.js +6 -118
  1099. package/dist/lib/rules/compose.d.ts +0 -56
  1100. package/dist/lib/rules/compose.js +2 -83
  1101. package/dist/lib/rules/rules.d.ts +0 -23
  1102. package/dist/lib/rules/rules.js +0 -35
  1103. package/dist/lib/rules/run-sync.d.ts +0 -16
  1104. package/dist/lib/rules/run-sync.js +1 -44
  1105. package/dist/lib/run-config.d.ts +0 -7
  1106. package/dist/lib/run-config.js +0 -8
  1107. package/dist/lib/run-defaults.d.ts +0 -14
  1108. package/dist/lib/run-defaults.js +0 -14
  1109. package/dist/lib/run-notify.d.ts +0 -18
  1110. package/dist/lib/run-notify.js +0 -36
  1111. package/dist/lib/run-trace-sync.d.ts +0 -21
  1112. package/dist/lib/run-trace-sync.js +2 -66
  1113. package/dist/lib/rush-session.d.ts +0 -26
  1114. package/dist/lib/rush-session.js +0 -28
  1115. package/dist/lib/sandbox.d.ts +0 -45
  1116. package/dist/lib/sandbox.js +5 -93
  1117. package/dist/lib/scheduler.d.ts +0 -28
  1118. package/dist/lib/scheduler.js +0 -45
  1119. package/dist/lib/scheduling/routines.d.ts +0 -652
  1120. package/dist/lib/scheduling/routines.js +8 -475
  1121. package/dist/lib/secrets-cli.d.ts +3 -8
  1122. package/dist/lib/secrets-cli.js +1 -19
  1123. package/dist/lib/secrets-client.d.ts +0 -117
  1124. package/dist/lib/secrets-client.js +4 -275
  1125. package/dist/lib/secrets-policy.d.ts +0 -142
  1126. package/dist/lib/secrets-policy.js +4 -237
  1127. package/dist/lib/secrets-types.d.ts +0 -87
  1128. package/dist/lib/secrets-types.js +0 -13
  1129. package/dist/lib/self-heal/checks/hook-manifest.js +0 -25
  1130. package/dist/lib/self-heal/checks/hook-runtime.js +0 -5
  1131. package/dist/lib/self-heal/checks/install-staging.d.ts +0 -1
  1132. package/dist/lib/self-heal/checks/install-staging.js +1 -28
  1133. package/dist/lib/self-heal/checks/menubar-helper.js +0 -5
  1134. package/dist/lib/self-heal/checks/path.js +0 -9
  1135. package/dist/lib/self-heal/checks/resources.js +0 -5
  1136. package/dist/lib/self-heal/checks/shadowing.js +2 -16
  1137. package/dist/lib/self-heal/checks/shims.js +0 -14
  1138. package/dist/lib/self-heal/child.d.ts +12 -0
  1139. package/dist/lib/self-heal/child.js +23 -0
  1140. package/dist/lib/self-heal/registry.d.ts +0 -9
  1141. package/dist/lib/self-heal/registry.js +0 -16
  1142. package/dist/lib/self-heal/types.d.ts +0 -12
  1143. package/dist/lib/self-heal/types.js +0 -15
  1144. package/dist/lib/self-update.d.ts +0 -312
  1145. package/dist/lib/self-update.js +9 -360
  1146. package/dist/lib/service-manifest.d.ts +0 -39
  1147. package/dist/lib/service-manifest.js +0 -72
  1148. package/dist/lib/session/active.d.ts +13 -869
  1149. package/dist/lib/session/active.js +17 -976
  1150. package/dist/lib/session/actor-sidecar.d.ts +1 -32
  1151. package/dist/lib/session/actor-sidecar.js +1 -41
  1152. package/dist/lib/session/bookmarks.d.ts +0 -33
  1153. package/dist/lib/session/bookmarks.js +0 -37
  1154. package/dist/lib/session/bundle.d.ts +0 -86
  1155. package/dist/lib/session/bundle.js +0 -54
  1156. package/dist/lib/session/claude-accounts.d.ts +0 -40
  1157. package/dist/lib/session/claude-accounts.js +0 -49
  1158. package/dist/lib/session/cloud.d.ts +1 -23
  1159. package/dist/lib/session/cloud.js +0 -26
  1160. package/dist/lib/session/db.d.ts +5 -658
  1161. package/dist/lib/session/db.js +22 -1443
  1162. package/dist/lib/session/detached.d.ts +0 -21
  1163. package/dist/lib/session/detached.js +0 -29
  1164. package/dist/lib/session/discover.d.ts +3 -420
  1165. package/dist/lib/session/discover.js +30 -1123
  1166. package/dist/lib/session/fork.d.ts +1 -41
  1167. package/dist/lib/session/fork.js +0 -19
  1168. package/dist/lib/session/ghostty-tabs.d.ts +0 -24
  1169. package/dist/lib/session/ghostty-tabs.js +0 -37
  1170. package/dist/lib/session/glance-files.d.ts +19 -0
  1171. package/dist/lib/session/glance-files.js +258 -0
  1172. package/dist/lib/session/hook-sessions.d.ts +0 -33
  1173. package/dist/lib/session/hook-sessions.js +4 -99
  1174. package/dist/lib/session/host-link.d.ts +1 -94
  1175. package/dist/lib/session/host-link.js +1 -81
  1176. package/dist/lib/session/inject-target.d.ts +8 -0
  1177. package/dist/lib/session/inject-target.js +32 -0
  1178. package/dist/lib/session/inject.d.ts +0 -15
  1179. package/dist/lib/session/inject.js +0 -15
  1180. package/dist/lib/session/live-metadata.d.ts +1 -34
  1181. package/dist/lib/session/live-metadata.js +1 -73
  1182. package/dist/lib/session/local-tmux-attach.d.ts +0 -37
  1183. package/dist/lib/session/local-tmux-attach.js +1 -76
  1184. package/dist/lib/session/migrate-targets.d.ts +0 -46
  1185. package/dist/lib/session/migrate-targets.js +0 -24
  1186. package/dist/lib/session/migrations.d.ts +0 -12
  1187. package/dist/lib/session/migrations.js +1 -20
  1188. package/dist/lib/session/mirror.d.ts +0 -32
  1189. package/dist/lib/session/mirror.js +0 -77
  1190. package/dist/lib/session/origin-machine.js +0 -3
  1191. package/dist/lib/session/pid-registry.d.ts +0 -80
  1192. package/dist/lib/session/pid-registry.js +2 -81
  1193. package/dist/lib/session/presence.d.ts +0 -39
  1194. package/dist/lib/session/presence.js +2 -52
  1195. package/dist/lib/session/process-view.d.ts +0 -11
  1196. package/dist/lib/session/process-view.js +0 -25
  1197. package/dist/lib/session/projection.d.ts +0 -3
  1198. package/dist/lib/session/projection.js +0 -10
  1199. package/dist/lib/session/provenance.d.ts +1 -37
  1200. package/dist/lib/session/provenance.js +0 -69
  1201. package/dist/lib/session/recovery.d.ts +1 -40
  1202. package/dist/lib/session/recovery.js +2 -80
  1203. package/dist/lib/session/relative-time.js +0 -3
  1204. package/dist/lib/session/remote/peer-stream.d.ts +0 -42
  1205. package/dist/lib/session/remote/peer-stream.js +0 -64
  1206. package/dist/lib/session/remote/remote-bundle.d.ts +0 -6
  1207. package/dist/lib/session/remote/remote-bundle.js +0 -21
  1208. package/dist/lib/session/remote/remote-list.d.ts +1 -110
  1209. package/dist/lib/session/remote/remote-list.js +5 -139
  1210. package/dist/lib/session/remote/remote.d.ts +0 -98
  1211. package/dist/lib/session/remote/remote.js +3 -119
  1212. package/dist/lib/session/remote/watch.d.ts +1 -34
  1213. package/dist/lib/session/remote/watch.js +12 -72
  1214. package/dist/lib/session/remote-active.d.ts +0 -35
  1215. package/dist/lib/session/remote-active.js +0 -48
  1216. package/dist/lib/session/remote-bundle.js +0 -2
  1217. package/dist/lib/session/remote-list.js +0 -2
  1218. package/dist/lib/session/remote-preview-cache.d.ts +0 -7
  1219. package/dist/lib/session/remote-preview-cache.js +1 -76
  1220. package/dist/lib/session/remote.js +0 -2
  1221. package/dist/lib/session/resume-command.d.ts +0 -6
  1222. package/dist/lib/session/resume-command.js +0 -6
  1223. package/dist/lib/session/resume-owner.d.ts +1 -52
  1224. package/dist/lib/session/resume-owner.js +0 -56
  1225. package/dist/lib/session/run-names.d.ts +0 -24
  1226. package/dist/lib/session/run-names.js +0 -26
  1227. package/dist/lib/session/session-cache.d.ts +2 -146
  1228. package/dist/lib/session/session-cache.js +26 -203
  1229. package/dist/lib/session/short-id.js +0 -3
  1230. package/dist/lib/session/sync/agents.d.ts +0 -68
  1231. package/dist/lib/session/sync/agents.js +0 -0
  1232. package/dist/lib/session/sync/backend.d.ts +0 -39
  1233. package/dist/lib/session/sync/backend.js +0 -45
  1234. package/dist/lib/session/sync/config.d.ts +0 -27
  1235. package/dist/lib/session/sync/config.js +0 -56
  1236. package/dist/lib/session/sync/managed-config.d.ts +0 -17
  1237. package/dist/lib/session/sync/managed-config.js +0 -17
  1238. package/dist/lib/session/sync/managed-key.d.ts +0 -38
  1239. package/dist/lib/session/sync/managed-key.js +1 -42
  1240. package/dist/lib/session/sync/net-client.d.ts +0 -36
  1241. package/dist/lib/session/sync/net-client.js +0 -30
  1242. package/dist/lib/session/sync/provision.d.ts +0 -2
  1243. package/dist/lib/session/sync/provision.js +0 -13
  1244. package/dist/lib/session/sync/r2.d.ts +0 -20
  1245. package/dist/lib/session/sync/r2.js +0 -20
  1246. package/dist/lib/session/sync/transcript-crypto.d.ts +0 -37
  1247. package/dist/lib/session/sync/transcript-crypto.js +5 -37
  1248. package/dist/lib/session/sync/worker-template.d.ts +0 -5
  1249. package/dist/lib/session/sync/worker-template.js +0 -40
  1250. package/dist/lib/session/testdata/pid-registry-namespace.js +0 -2
  1251. package/dist/lib/session/testdata/process-view-private.js +0 -1
  1252. package/dist/lib/session/throughput.d.ts +0 -24
  1253. package/dist/lib/session/throughput.js +1 -25
  1254. package/dist/lib/session/timeline-pass.d.ts +1 -63
  1255. package/dist/lib/session/timeline-pass.js +161 -148
  1256. package/dist/lib/session/title.d.ts +0 -182
  1257. package/dist/lib/session/title.js +0 -139
  1258. package/dist/lib/session/tool-index.d.ts +2 -21
  1259. package/dist/lib/session/tool-index.js +3 -75
  1260. package/dist/lib/session/tool-store.d.ts +2 -48
  1261. package/dist/lib/session/tool-store.js +1 -33
  1262. package/dist/lib/session/viewing-in.d.ts +0 -67
  1263. package/dist/lib/session/viewing-in.js +1 -71
  1264. package/dist/lib/session/watch.js +0 -2
  1265. package/dist/lib/session/width.js +0 -3
  1266. package/dist/lib/sessions-client.d.ts +0 -46
  1267. package/dist/lib/sessions-client.js +36 -113
  1268. package/dist/lib/settings-manifest.d.ts +1 -17
  1269. package/dist/lib/settings-manifest.js +4 -57
  1270. package/dist/lib/setup-tool-install.d.ts +0 -1
  1271. package/dist/lib/setup-tool-install.js +2 -7
  1272. package/dist/lib/setup-tool-status.d.ts +0 -3
  1273. package/dist/lib/setup-tool-status.js +4 -14
  1274. package/dist/lib/sha256-asset.d.ts +0 -20
  1275. package/dist/lib/sha256-asset.js +0 -20
  1276. package/dist/lib/share-runtime.d.ts +0 -10
  1277. package/dist/lib/share-runtime.js +1 -27
  1278. package/dist/lib/shim-heal.d.ts +0 -15
  1279. package/dist/lib/shim-heal.js +3 -29
  1280. package/dist/lib/signin-badge.d.ts +0 -72
  1281. package/dist/lib/signin-badge.js +0 -86
  1282. package/dist/lib/sink-format.d.ts +0 -32
  1283. package/dist/lib/sink-format.js +0 -14
  1284. package/dist/lib/smart-launch.d.ts +0 -75
  1285. package/dist/lib/smart-launch.js +1 -83
  1286. package/dist/lib/snapshot.d.ts +0 -46
  1287. package/dist/lib/snapshot.js +5 -31
  1288. package/dist/lib/spinner.d.ts +0 -37
  1289. package/dist/lib/spinner.js +0 -37
  1290. package/dist/lib/sqlite.d.ts +0 -13
  1291. package/dist/lib/sqlite.js +3 -71
  1292. package/dist/lib/ssh-exec.d.ts +0 -209
  1293. package/dist/lib/ssh-exec.js +11 -248
  1294. package/dist/lib/ssh-tunnel.d.ts +0 -43
  1295. package/dist/lib/ssh-tunnel.js +2 -48
  1296. package/dist/lib/staleness/checkers/commands.d.ts +0 -4
  1297. package/dist/lib/staleness/checkers/commands.js +0 -4
  1298. package/dist/lib/staleness/checkers/hooks.d.ts +0 -10
  1299. package/dist/lib/staleness/checkers/hooks.js +0 -15
  1300. package/dist/lib/staleness/checkers/mcp.d.ts +0 -9
  1301. package/dist/lib/staleness/checkers/mcp.js +0 -9
  1302. package/dist/lib/staleness/checkers/permissions.d.ts +0 -12
  1303. package/dist/lib/staleness/checkers/permissions.js +0 -13
  1304. package/dist/lib/staleness/checkers/plugins.d.ts +0 -8
  1305. package/dist/lib/staleness/checkers/plugins.js +0 -8
  1306. package/dist/lib/staleness/checkers/rules.d.ts +0 -15
  1307. package/dist/lib/staleness/checkers/rules.js +0 -26
  1308. package/dist/lib/staleness/checkers/skills.d.ts +0 -4
  1309. package/dist/lib/staleness/checkers/skills.js +0 -4
  1310. package/dist/lib/staleness/checkers/subagents.d.ts +0 -9
  1311. package/dist/lib/staleness/checkers/subagents.js +0 -9
  1312. package/dist/lib/staleness/checkers/types.d.ts +0 -34
  1313. package/dist/lib/staleness/checkers/types.js +0 -19
  1314. package/dist/lib/staleness/checkers/workflows.d.ts +0 -7
  1315. package/dist/lib/staleness/checkers/workflows.js +0 -7
  1316. package/dist/lib/staleness/detectors/commands.js +0 -17
  1317. package/dist/lib/staleness/detectors/hooks.js +1 -6
  1318. package/dist/lib/staleness/detectors/mcp.js +0 -4
  1319. package/dist/lib/staleness/detectors/permissions.js +10 -23
  1320. package/dist/lib/staleness/detectors/rules.js +0 -6
  1321. package/dist/lib/staleness/detectors/skills.d.ts +0 -1
  1322. package/dist/lib/staleness/detectors/skills.js +1 -12
  1323. package/dist/lib/staleness/detectors/types.d.ts +0 -10
  1324. package/dist/lib/staleness/fingerprint.d.ts +0 -19
  1325. package/dist/lib/staleness/fingerprint.js +0 -35
  1326. package/dist/lib/staleness/index.d.ts +0 -28
  1327. package/dist/lib/staleness/index.js +1 -45
  1328. package/dist/lib/staleness/layers.d.ts +0 -23
  1329. package/dist/lib/staleness/layers.js +0 -34
  1330. package/dist/lib/staleness/prune.d.ts +0 -71
  1331. package/dist/lib/staleness/prune.js +2 -27
  1332. package/dist/lib/staleness/registry.d.ts +0 -10
  1333. package/dist/lib/staleness/registry.js +3 -33
  1334. package/dist/lib/staleness/types.d.ts +0 -36
  1335. package/dist/lib/staleness/types.js +0 -5
  1336. package/dist/lib/staleness/writers/commands.js +1 -48
  1337. package/dist/lib/staleness/writers/hooks.js +1 -18
  1338. package/dist/lib/staleness/writers/kinds.d.ts +0 -12
  1339. package/dist/lib/staleness/writers/kinds.js +0 -1
  1340. package/dist/lib/staleness/writers/lazy-map.d.ts +0 -11
  1341. package/dist/lib/staleness/writers/mcp.js +0 -13
  1342. package/dist/lib/staleness/writers/plugins.js +0 -4
  1343. package/dist/lib/staleness/writers/rules.d.ts +0 -1
  1344. package/dist/lib/staleness/writers/rules.js +1 -19
  1345. package/dist/lib/staleness/writers/skills.js +3 -14
  1346. package/dist/lib/staleness/writers/sources.d.ts +0 -11
  1347. package/dist/lib/staleness/writers/sources.js +0 -32
  1348. package/dist/lib/staleness/writers/subagents.js +0 -16
  1349. package/dist/lib/staleness/writers/types.d.ts +0 -58
  1350. package/dist/lib/staleness/writers/workflows.js +1 -1
  1351. package/dist/lib/standalone-tools.d.ts +24 -0
  1352. package/dist/lib/standalone-tools.js +58 -0
  1353. package/dist/lib/star-nudge.d.ts +0 -32
  1354. package/dist/lib/star-nudge.js +2 -36
  1355. package/dist/lib/startup/command-registry.d.ts +0 -45
  1356. package/dist/lib/startup/command-registry.js +1 -46
  1357. package/dist/lib/startup/dev-build.d.ts +0 -9
  1358. package/dist/lib/startup/dev-build.js +1 -42
  1359. package/dist/lib/startup/root-command.d.ts +0 -19
  1360. package/dist/lib/startup/root-command.js +0 -19
  1361. package/dist/lib/startup/spellcheck.d.ts +0 -13
  1362. package/dist/lib/startup/spellcheck.js +0 -13
  1363. package/dist/lib/state.d.ts +0 -376
  1364. package/dist/lib/state.js +19 -737
  1365. package/dist/lib/storage/selection.d.ts +0 -40
  1366. package/dist/lib/storage/selection.js +0 -29
  1367. package/dist/lib/subagents-registry.d.ts +0 -56
  1368. package/dist/lib/subagents-registry.js +0 -99
  1369. package/dist/lib/subagents.d.ts +0 -128
  1370. package/dist/lib/subagents.js +1 -158
  1371. package/dist/lib/summarizer/config.d.ts +0 -37
  1372. package/dist/lib/summarizer/config.js +0 -37
  1373. package/dist/lib/summarizer/pass.d.ts +0 -20
  1374. package/dist/lib/summarizer/pass.js +1 -34
  1375. package/dist/lib/summarizer/summarize.d.ts +1 -49
  1376. package/dist/lib/summarizer/summarize.js +0 -35
  1377. package/dist/lib/sync-passphrase.d.ts +0 -16
  1378. package/dist/lib/sync-passphrase.js +1 -18
  1379. package/dist/lib/sync-status.d.ts +0 -72
  1380. package/dist/lib/sync-status.js +0 -55
  1381. package/dist/lib/sync-umbrella.d.ts +0 -54
  1382. package/dist/lib/sync-umbrella.js +0 -48
  1383. package/dist/lib/system-run-sync.d.ts +0 -5
  1384. package/dist/lib/system-run-sync.js +1 -31
  1385. package/dist/lib/teams/agents.d.ts +1 -444
  1386. package/dist/lib/teams/agents.js +11 -871
  1387. package/dist/lib/teams/api.d.ts +2 -52
  1388. package/dist/lib/teams/api.js +4 -63
  1389. package/dist/lib/teams/debug.d.ts +0 -6
  1390. package/dist/lib/teams/debug.js +0 -6
  1391. package/dist/lib/teams/delivery.d.ts +0 -41
  1392. package/dist/lib/teams/delivery.js +0 -32
  1393. package/dist/lib/teams/file_ops.d.ts +0 -11
  1394. package/dist/lib/teams/file_ops.js +0 -11
  1395. package/dist/lib/teams/forEach.d.ts +0 -76
  1396. package/dist/lib/teams/forEach.js +1 -77
  1397. package/dist/lib/teams/index.d.ts +1 -7
  1398. package/dist/lib/teams/index.js +1 -7
  1399. package/dist/lib/teams/parsers.d.ts +0 -4
  1400. package/dist/lib/teams/parsers.js +0 -81
  1401. package/dist/lib/teams/persistence.d.ts +0 -2
  1402. package/dist/lib/teams/persistence.js +0 -12
  1403. package/dist/lib/teams/placement-probe.d.ts +0 -12
  1404. package/dist/lib/teams/placement-probe.js +1 -51
  1405. package/dist/lib/teams/pr-watch.d.ts +0 -107
  1406. package/dist/lib/teams/pr-watch.js +1 -107
  1407. package/dist/lib/teams/registry.d.ts +0 -36
  1408. package/dist/lib/teams/registry.js +0 -47
  1409. package/dist/lib/teams/remoteWorktree.d.ts +0 -50
  1410. package/dist/lib/teams/remoteWorktree.js +1 -96
  1411. package/dist/lib/teams/scheduler.d.ts +0 -111
  1412. package/dist/lib/teams/scheduler.js +2 -125
  1413. package/dist/lib/teams/summarizer.d.ts +0 -22
  1414. package/dist/lib/teams/summarizer.js +6 -50
  1415. package/dist/lib/teams/supervisor.d.ts +0 -38
  1416. package/dist/lib/teams/supervisor.js +0 -21
  1417. package/dist/lib/teams/worktree.d.ts +0 -95
  1418. package/dist/lib/teams/worktree.js +3 -110
  1419. package/dist/lib/template.d.ts +0 -21
  1420. package/dist/lib/template.js +0 -23
  1421. package/dist/lib/term-client.d.ts +0 -26
  1422. package/dist/lib/term-client.js +0 -48
  1423. package/dist/lib/term-driver.d.ts +0 -5
  1424. package/dist/lib/term-driver.js +0 -8
  1425. package/dist/lib/terminal/backends/ghostty.d.ts +0 -2
  1426. package/dist/lib/terminal/backends/ghostty.js +0 -12
  1427. package/dist/lib/terminal/backends/index.d.ts +0 -17
  1428. package/dist/lib/terminal/backends/index.js +0 -15
  1429. package/dist/lib/terminal/backends/iterm.d.ts +0 -2
  1430. package/dist/lib/terminal/backends/iterm.js +0 -10
  1431. package/dist/lib/terminal/backends/terminal-app.d.ts +0 -10
  1432. package/dist/lib/terminal/backends/terminal-app.js +0 -30
  1433. package/dist/lib/terminal/backends/tmux.d.ts +0 -10
  1434. package/dist/lib/terminal/backends/tmux.js +0 -2
  1435. package/dist/lib/terminal/backends/vscodium-agent.d.ts +0 -25
  1436. package/dist/lib/terminal/backends/vscodium-agent.js +0 -36
  1437. package/dist/lib/terminal/engine.d.ts +0 -17
  1438. package/dist/lib/terminal/engine.js +0 -10
  1439. package/dist/lib/terminal/index.d.ts +0 -8
  1440. package/dist/lib/terminal/inject.d.ts +1 -173
  1441. package/dist/lib/terminal/inject.js +0 -146
  1442. package/dist/lib/terminal/policy.d.ts +0 -8
  1443. package/dist/lib/terminal/policy.js +0 -1
  1444. package/dist/lib/terminal/preferred.d.ts +0 -66
  1445. package/dist/lib/terminal/preferred.js +0 -30
  1446. package/dist/lib/terminal/quote.d.ts +0 -8
  1447. package/dist/lib/terminal/quote.js +0 -8
  1448. package/dist/lib/terminal/resolve.d.ts +0 -46
  1449. package/dist/lib/terminal/resolve.js +0 -30
  1450. package/dist/lib/terminal/run-surface.d.ts +0 -56
  1451. package/dist/lib/terminal/run-surface.js +0 -46
  1452. package/dist/lib/terminal/shell.d.ts +0 -3
  1453. package/dist/lib/terminal/shell.js +0 -13
  1454. package/dist/lib/terminal/transport.d.ts +0 -14
  1455. package/dist/lib/terminal/transport.js +1 -30
  1456. package/dist/lib/terminal/types.d.ts +0 -40
  1457. package/dist/lib/terminal/types.js +0 -10
  1458. package/dist/lib/text/relative-time.d.ts +0 -36
  1459. package/dist/lib/text/relative-time.js +0 -43
  1460. package/dist/lib/text/short-id.d.ts +0 -16
  1461. package/dist/lib/text/short-id.js +0 -16
  1462. package/dist/lib/text/width.d.ts +0 -24
  1463. package/dist/lib/text/width.js +10 -52
  1464. package/dist/lib/tmux/binary.d.ts +0 -36
  1465. package/dist/lib/tmux/binary.js +0 -28
  1466. package/dist/lib/tmux/index.d.ts +0 -5
  1467. package/dist/lib/tmux/index.js +0 -5
  1468. package/dist/lib/tmux/orphan-reap.d.ts +0 -253
  1469. package/dist/lib/tmux/orphan-reap.js +3 -299
  1470. package/dist/lib/tmux/paths.d.ts +0 -14
  1471. package/dist/lib/tmux/paths.js +0 -14
  1472. package/dist/lib/tmux/session.d.ts +0 -263
  1473. package/dist/lib/tmux/session.js +6 -344
  1474. package/dist/lib/traces/backend.d.ts +0 -20
  1475. package/dist/lib/traces/backend.js +0 -23
  1476. package/dist/lib/traces/classify.d.ts +0 -20
  1477. package/dist/lib/traces/classify.js +0 -7
  1478. package/dist/lib/traces/insights.d.ts +1 -84
  1479. package/dist/lib/traces/insights.js +0 -126
  1480. package/dist/lib/traces/phenotype.d.ts +0 -69
  1481. package/dist/lib/traces/phenotype.js +0 -150
  1482. package/dist/lib/traces/provision.d.ts +0 -1
  1483. package/dist/lib/traces/provision.js +0 -5
  1484. package/dist/lib/traces/schema2-build.d.ts +3 -60
  1485. package/dist/lib/traces/schema2-build.js +8 -149
  1486. package/dist/lib/traces/schema2-danger.d.ts +0 -30
  1487. package/dist/lib/traces/schema2-danger.js +1 -63
  1488. package/dist/lib/traces/schema2.d.ts +0 -11
  1489. package/dist/lib/traces/segments.d.ts +0 -44
  1490. package/dist/lib/traces/segments.js +0 -65
  1491. package/dist/lib/traces/sync.d.ts +2 -239
  1492. package/dist/lib/traces/sync.js +15 -237
  1493. package/dist/lib/traces/worker-template.d.ts +0 -3
  1494. package/dist/lib/traces/worker-template.js +0 -29
  1495. package/dist/lib/triggers/handlers.d.ts +0 -82
  1496. package/dist/lib/triggers/handlers.js +0 -75
  1497. package/dist/lib/triggers/webhook.d.ts +0 -158
  1498. package/dist/lib/triggers/webhook.js +0 -143
  1499. package/dist/lib/types.d.ts +0 -736
  1500. package/dist/lib/types.js +0 -50
  1501. package/dist/lib/uninstall.d.ts +0 -17
  1502. package/dist/lib/uninstall.js +0 -75
  1503. package/dist/lib/usage-backoff.d.ts +0 -20
  1504. package/dist/lib/usage-backoff.js +3 -60
  1505. package/dist/lib/usage-refresh.d.ts +0 -154
  1506. package/dist/lib/usage-refresh.js +8 -212
  1507. package/dist/lib/verbs.d.ts +0 -12
  1508. package/dist/lib/verbs.js +0 -12
  1509. package/dist/lib/version-duplicates.d.ts +0 -6
  1510. package/dist/lib/version-duplicates.js +0 -6
  1511. package/dist/lib/version.d.ts +0 -55
  1512. package/dist/lib/version.js +1 -58
  1513. package/dist/lib/view-types.d.ts +0 -48
  1514. package/dist/lib/warn-unpushed.d.ts +0 -27
  1515. package/dist/lib/warn-unpushed.js +1 -45
  1516. package/dist/lib/watchdog/history.d.ts +0 -1
  1517. package/dist/lib/watchdog/history.js +0 -3
  1518. package/dist/lib/watchdog/index.js +0 -2
  1519. package/dist/lib/watchdog/log.d.ts +0 -19
  1520. package/dist/lib/watchdog/log.js +0 -34
  1521. package/dist/lib/watchdog/read.d.ts +0 -27
  1522. package/dist/lib/watchdog/read.js +3 -58
  1523. package/dist/lib/watchdog/rotate.d.ts +0 -139
  1524. package/dist/lib/watchdog/rotate.js +2 -151
  1525. package/dist/lib/watchdog/runner.d.ts +0 -125
  1526. package/dist/lib/watchdog/runner.js +3 -223
  1527. package/dist/lib/watchdog/service.d.ts +0 -1
  1528. package/dist/lib/watchdog/service.js +0 -2
  1529. package/dist/lib/watchdog/watchdog-agent.d.ts +0 -31
  1530. package/dist/lib/watchdog/watchdog-agent.js +0 -27
  1531. package/dist/lib/watchdog/watchdog.d.ts +0 -7
  1532. package/dist/lib/watchdog/watchdog.js +0 -10
  1533. package/dist/lib/watchdog/watchdogTail.js +0 -7
  1534. package/dist/lib/whats-new.d.ts +0 -10
  1535. package/dist/lib/whats-new.js +0 -21
  1536. package/dist/lib/workflows-registry.d.ts +0 -45
  1537. package/dist/lib/workflows-registry.js +0 -60
  1538. package/dist/lib/workflows.d.ts +0 -282
  1539. package/dist/lib/workflows.js +3 -213
  1540. package/dist/lib/worktree/held.d.ts +0 -89
  1541. package/dist/lib/worktree/held.js +1 -103
  1542. package/dist/lib/wrap.d.ts +0 -32
  1543. package/dist/lib/wrap.js +0 -32
  1544. package/dist/lib/yaml-io.d.ts +0 -45
  1545. package/dist/lib/yaml-io.js +0 -47
  1546. package/dist/session-tracker/dist/adapters/claude.js +0 -2
  1547. package/dist/session-tracker/dist/hook.sh +4 -37
  1548. package/dist/session-tracker/dist/index.d.ts +0 -7
  1549. package/dist/session-tracker/dist/index.js +0 -5
  1550. package/dist/session-tracker/dist/install-hook.d.ts +0 -5
  1551. package/dist/session-tracker/dist/install-hook.js +1 -15
  1552. package/dist/session-tracker/dist/prune-state.js +0 -4
  1553. package/dist/session-tracker/dist/reader.js +0 -4
  1554. package/dist/session-tracker/dist/state-file.d.ts +0 -3
  1555. package/dist/session-tracker/dist/state-file.js +3 -8
  1556. package/package.json +3 -4
  1557. package/scripts/postinstall.js +8 -116
  1558. package/dist/lib/session/artifacts.d.ts +0 -14
  1559. package/dist/lib/session/artifacts.js +0 -101
  1560. package/dist/lib/session/bash-command.d.ts +0 -63
  1561. package/dist/lib/session/bash-command.js +0 -490
  1562. package/dist/lib/session/digest.d.ts +0 -66
  1563. package/dist/lib/session/digest.js +0 -328
  1564. package/dist/lib/session/highlights.d.ts +0 -151
  1565. package/dist/lib/session/highlights.js +0 -391
  1566. package/dist/lib/session/insights.d.ts +0 -165
  1567. package/dist/lib/session/insights.js +0 -563
  1568. package/dist/lib/session/linear.d.ts +0 -19
  1569. package/dist/lib/session/linear.js +0 -99
  1570. package/dist/lib/session/parse.d.ts +0 -224
  1571. package/dist/lib/session/parse.js +0 -2408
  1572. package/dist/lib/session/prompt.d.ts +0 -213
  1573. package/dist/lib/session/prompt.js +0 -601
  1574. package/dist/lib/session/render.d.ts +0 -133
  1575. package/dist/lib/session/render.js +0 -1047
  1576. package/dist/lib/session/share-html.d.ts +0 -35
  1577. package/dist/lib/session/share-html.js +0 -319
  1578. package/dist/lib/session/shell-programs.d.ts +0 -33
  1579. package/dist/lib/session/shell-programs.js +0 -380
  1580. package/dist/lib/session/state.d.ts +0 -269
  1581. package/dist/lib/session/state.js +0 -777
  1582. package/dist/lib/session/stream-render.d.ts +0 -4
  1583. package/dist/lib/session/stream-render.js +0 -131
  1584. package/dist/lib/session/tail.d.ts +0 -88
  1585. package/dist/lib/session/tail.js +0 -294
  1586. package/dist/lib/session/team-filter.d.ts +0 -129
  1587. package/dist/lib/session/team-filter.js +0 -269
  1588. package/dist/lib/session/timeline.d.ts +0 -172
  1589. package/dist/lib/session/timeline.js +0 -636
  1590. package/dist/lib/session/tool-calls.d.ts +0 -132
  1591. package/dist/lib/session/tool-calls.js +0 -674
  1592. package/dist/lib/session/trajectory-compare.d.ts +0 -48
  1593. package/dist/lib/session/trajectory-compare.js +0 -116
  1594. package/dist/lib/session/trajectory-html.d.ts +0 -19
  1595. package/dist/lib/session/trajectory-html.js +0 -771
  1596. package/dist/lib/session/trajectory-lineage.d.ts +0 -93
  1597. package/dist/lib/session/trajectory-lineage.js +0 -195
  1598. package/dist/lib/session/trajectory-text.d.ts +0 -38
  1599. package/dist/lib/session/trajectory-text.js +0 -284
  1600. package/dist/lib/session/trajectory.d.ts +0 -145
  1601. package/dist/lib/session/trajectory.js +0 -394
  1602. package/dist/lib/session/types.d.ts +0 -627
  1603. package/dist/lib/session/types.js +0 -43
@@ -1,11 +1,3 @@
1
- /**
2
- * Session discovery across Claude, Codex, Gemini, OpenCode, and OpenClaw.
3
- *
4
- * Performs incremental scans: each agent's session files are stat'd and compared
5
- * to a scan-stamp ledger in SQLite. Only files whose mtime or size changed since
6
- * the last run are re-parsed. All metadata is upserted into the sessions DB so
7
- * subsequent queries are served entirely from the cache.
8
- */
9
1
  import * as fs from 'fs';
10
2
  import * as path from 'path';
11
3
  import * as os from 'os';
@@ -22,13 +14,14 @@ import { walkForFilesWithStat } from '../fs-walk.js';
22
14
  import { hasCommand } from '../cli-resources.js';
23
15
  import { execFileShellSpec } from '../platform/exec.js';
24
16
  import { getConfigSymlinkVersion } from '../installations/shims.js';
25
- import { SESSION_AGENTS } from './types.js';
17
+ import { SESSION_AGENTS } from '@phnx-labs/sessions-cli/reader';
26
18
  import { deriveShortId } from './short-id.js';
27
19
  import { buildClaudeAccountIndex, resolveClaudeAccount } from './claude-accounts.js';
28
- import { cleanFirstUserMessage, extractSessionTopic, extractSlashCommandName, extractSlashCommandFromToolInput, cleanGeneratedSessionLabel } from './prompt.js';
29
- import { isBackgroundShellStart, isSkillInvocation, extractSkills, extractSlashCommands, isSubAgentTool } from './highlights.js';
30
- import { parseAntigravity, parseCursor, splitSessionFilePath } from './parse.js';
31
- import { extractPrUrl, detectWorktree, detectTicket, isPrCreateCommand, detectSpawnedTeam, isTicketCreateTool, extractCreatedTicket, extractRecentDirectoriesTouched, extractTodoProgressFromEvents } from './state.js';
20
+ import { cleanFirstUserMessage, extractSessionTopic, extractSlashCommandName, extractSlashCommandFromToolInput, cleanGeneratedSessionLabel } from '@phnx-labs/sessions-cli/reader';
21
+ import { isBackgroundShellStart, isSkillInvocation, extractSkills, extractSlashCommands, isSubAgentTool } from '@phnx-labs/sessions-cli/reader';
22
+ import { claudeSubagentFiles, resolvedSubAgentCount } from './glance-files.js';
23
+ import { parseAntigravity, parseCursor, splitSessionFilePath } from '@phnx-labs/sessions-cli/reader';
24
+ import { extractPrUrl, detectWorktree, detectTicket, isPrCreateCommand, detectSpawnedTeam, isTicketCreateTool, extractCreatedTicket, extractRecentDirectoriesTouched, extractTodoProgressFromEvents } from '@phnx-labs/sessions-cli/reader';
32
25
  import { costOfUsage, costOfUsageNoCache } from '../pricing/index.js';
33
26
  import { isSelfHost } from '../devices/self-host.js';
34
27
  import { readSessionActorRecord } from './actor-sidecar.js';
@@ -38,31 +31,16 @@ import { mapBounded } from '../concurrency.js';
38
31
  import { getDB, getScanStampByPath, getScanStampsForPaths, getParserStatesForPaths, getDirLedgerForPaths, recordDirScans, recordScans, syncLabels, seedLabelsFromNames, syncTopics, upsertSessionsBatch, querySessions, countSessions, ftsSearch, getSessionById, tryClaimScan, releaseScan, scanInProgressByLivePid, cacheLinearProject, CONTENT_INDEX_VERSION, } from './db.js';
39
32
  import { buildRunNameMap } from './run-names.js';
40
33
  import { resolveLinearApiKey } from '../linear-cache.js';
41
- import { ToolCallCollector, collectClaudeToolCalls, collectCodexToolCalls, } from './tool-calls.js';
34
+ import { ToolCallCollector, collectClaudeToolCalls, collectCodexToolCalls, } from '@phnx-labs/sessions-cli/reader';
42
35
  import { purgeMissingToolCallsInDirectory } from './tool-store.js';
43
36
  const HOME = os.homedir();
44
- // Versions can live under either repo: the user repo (current canonical
45
- // location, ~/.agents/.history/versions/) or the system repo (legacy / npm-shipped,
46
- // ~/.agents-system/versions/). Both must be scanned — sessions written by
47
- // any installed version end up in that version's projects/ dir, and the user
48
- // can be running one repo's version while another repo holds older versions
49
- // whose JSONLs the user still wants to search.
50
37
  const VERSIONS_ROOTS = [getHistoryDir(), getAgentsDir()];
51
38
  const RUSH_SESSIONS_DIR = path.join(HOME, '.rush', 'sessions');
52
39
  const HERMES_SESSIONS_DIR = path.join(HOME, '.hermes', 'sessions');
53
- /** Muse Code sessions: ~/.local/share/muse/sessions/YYYY/MM/DD/<uuid>/session.jsonl */
54
40
  const MUSE_SESSIONS_DIR = path.join(HOME, '.local', 'share', 'muse', 'sessions');
55
- /** How long OpenClaw channel/cron snapshots stay valid before we re-shell-out. */
56
41
  const OPENCLAW_TTL_MS = 60_000;
57
42
  const ACTIVE_APPEND_RESCAN_DEBOUNCE_MS = 5_000;
58
- /** One JSONL record may not force an unbounded string allocation. */
59
43
  const SESSION_JSONL_LINE_MAX_BYTES = 1024 * 1024;
60
- /**
61
- * Stream one appended JSONL range, applying only newline-terminated records.
62
- * Memory is bounded to one record. An ordinary unterminated tail remains for the
63
- * next scan. Once a record exceeds the cap, its consumed offset and a one-bit
64
- * dropping state advance together so later scans never reread the growing tail.
65
- */
66
44
  async function applyJsonlAppend(filePath, fromOffset, wasDroppingOversizedLine, apply) {
67
45
  let pending = Buffer.alloc(0);
68
46
  let droppingOversizedLine = wasDroppingOversizedLine;
@@ -101,7 +79,6 @@ async function applyJsonlAppend(filePath, fromOffset, wasDroppingOversizedLine,
101
79
  apply(JSON.parse(line));
102
80
  }
103
81
  catch {
104
- // One malformed line never aborts the session scan.
105
82
  }
106
83
  }
107
84
  }
@@ -122,56 +99,30 @@ async function applyJsonlAppend(filePath, fromOffset, wasDroppingOversizedLine,
122
99
  }
123
100
  return { consumedBytes, droppingOversizedLine, skippedOversizedLine };
124
101
  }
125
- /**
126
- * How recently a file must have been scanned to be treated as "hot" — a
127
- * candidate for an in-place append even when its parent dir's mtime hasn't
128
- * moved. A dir-ledger match lets us skip the per-file stat of everything in a
129
- * leaf dir EXCEPT its hot set; a file is hot if it lives under the agent's live
130
- * `~/.<agent>` root (the only tree an agent appends to live) or was scanned
131
- * within this window. 10 minutes comfortably covers a session that paused
132
- * between `agents sessions` calls but is still being written to.
133
- */
134
102
  const HOT_FILE_WINDOW_MS = 600_000;
135
- /** Emergency kill-switch for the directory-ledger optimization. */
136
103
  function dirLedgerDisabled() {
137
104
  const v = process.env.AGENTS_SESSIONS_NO_DIR_LEDGER;
138
105
  return v === '1' || v === 'true';
139
106
  }
140
107
  let cachedOpenClawWorkspaces = null;
141
- /** Max time a `waitForScan` repair waits for a concurrent scan to settle. */
142
108
  const WAIT_FOR_SCAN_TIMEOUT_MS = 2_000;
143
109
  const WAIT_FOR_SCAN_POLL_MS = 100;
144
110
  function sleep(ms) {
145
111
  return new Promise(resolve => setTimeout(resolve, ms));
146
112
  }
147
113
  const cachedAgentVersions = new Map();
148
- /**
149
- * Discover sessions. Scans only files whose (mtime, size) have changed since
150
- * the last run; everything else is served from the SQLite cache.
151
- *
152
- * Only one process runs the incremental scan at a time. When many agents boot
153
- * simultaneously (e.g. after a restart), the first to claim the scan slot does
154
- * the work; the rest skip parsing entirely and serve from the DB. The claim is
155
- * stored in the `meta` table — crash-safe via dead-PID detection and a 2-min
156
- * TTL, no external lock files needed.
157
- */
158
114
  export async function discoverSessions(options) {
159
115
  const { claimed } = await scanSessionsIncremental({
160
116
  agent: options?.agent,
161
117
  onProgress: options?.onProgress,
162
118
  });
163
119
  if (!claimed && options?.waitForScan) {
164
- // Lost the single-flight claim to another live process (a foreground
165
- // `agents sessions*` or the daemon's index warm). Rather than return the
166
- // pre-scan snapshot that just missed, wait (bounded) for that scan to finish
167
- // so the read below reflects what it wrote (RUSH-2682 cold-miss repair).
168
120
  await waitForScanToSettle();
169
121
  }
170
122
  return queryIndexedSessions(options, {
171
123
  skipExistenceCheck: options?.skipExistenceCheck ?? false,
172
124
  });
173
125
  }
174
- /** Read only matching Claude/Codex transcripts on a cold ID lookup; indexing stays with the daemon. */
175
126
  export async function findLocalSessionTranscripts(selector, agent) {
176
127
  const matches = new Map();
177
128
  const seen = new Set();
@@ -209,7 +160,6 @@ export async function findLocalSessionTranscripts(selector, agent) {
209
160
  }
210
161
  return [...matches.values()];
211
162
  }
212
- /** Repair local metadata before deciding that a conversation has no context. */
213
163
  export async function hydrateSessionTranscript(session) {
214
164
  const accountId = session.accountId ?? readSessionActorRecord(session.id)?.accountId;
215
165
  if (accountId && !session.accountId)
@@ -219,7 +169,7 @@ export async function hydrateSessionTranscript(session) {
219
169
  if (file && fs.statSync(file).isFile() && fs.statSync(file).size > 0)
220
170
  return session;
221
171
  }
222
- catch { /* A moved account home needs a canonical rescan. */ }
172
+ catch { }
223
173
  if (session.machine && !isSelfHost(session.machine))
224
174
  return session;
225
175
  if (session.agent === 'claude' || session.agent === 'codex') {
@@ -237,33 +187,20 @@ export async function hydrateSessionTranscript(session) {
237
187
  const indexed = getSessionById(session.id);
238
188
  return indexed ? { ...session, ...indexed, accountId: session.accountId ?? indexed.accountId } : session;
239
189
  }
240
- /** Separate write half so daemon warming does not pay for listing or external enrichment. */
241
190
  export async function scanSessionsIncremental(options) {
242
- // Touch the DB so the schema is ready and connection is cached for this run.
243
191
  getDB();
244
192
  const agents = options?.agent ? [options.agent] : SESSION_AGENTS;
245
193
  const onProgress = options?.onProgress;
246
194
  if (!tryClaimScan(process.pid))
247
195
  return { claimed: false, scanned: 0 };
248
- // `parsed` climbs monotonically within one scanner run, so the last value per
249
- // (phase, agent) is that scanner's total. Phase-keyed because the dotfile scan
250
- // and the routine-archive scan both report under the same agent id.
251
196
  const parsedByPhaseAgent = new Map();
252
197
  const track = (phase) => (p) => {
253
198
  parsedByPhaseAgent.set(`${phase}\0${p.agent}`, p.parsed);
254
199
  onProgress?.(p);
255
200
  };
256
201
  try {
257
- // Bounded + staggered instead of a single Promise.all: scanning every
258
- // agent's dotfile dir (~/.claude, ~/.codex, ~/.gemini, …) simultaneously
259
- // reads to behavioral EDR (CrowdStrike Falcon) as a ransomware-style bulk
260
- // file-enumeration sweep. Same dirs, same results — just not all at once.
261
202
  await scanAgentsBounded(agents, agent => dispatchAgentScan(agent, track('dotfiles')));
262
203
  await scanAgentsBounded(agents, agent => scanRoutineArchivesIncremental(agent, track('routines')));
263
- // Seed labels from `agents run --name` handles onto the freshly-scanned
264
- // rows by id. Runs AFTER the per-agent scans (which applied agent-generated
265
- // titles via syncLabels), so a real title always wins and the seed only
266
- // backfills sessions that would otherwise be unnamed.
267
204
  seedLabelsFromNames(buildRunNameMap());
268
205
  }
269
206
  finally {
@@ -274,7 +211,6 @@ export async function scanSessionsIncremental(options) {
274
211
  scanned += n;
275
212
  return { claimed: true, scanned };
276
213
  }
277
- /** Bounded wait so a wedged scan cannot hang a foreground cold-miss repair. */
278
214
  export async function waitForScanToSettle(timeoutMs = WAIT_FOR_SCAN_TIMEOUT_MS, pollMs = WAIT_FOR_SCAN_POLL_MS) {
279
215
  const deadline = Date.now() + timeoutMs;
280
216
  while (scanInProgressByLivePid()) {
@@ -284,7 +220,6 @@ export async function waitForScanToSettle(timeoutMs = WAIT_FOR_SCAN_TIMEOUT_MS,
284
220
  }
285
221
  return true;
286
222
  }
287
- /** Read the current SQLite snapshot without scanning or parsing transcript files. */
288
223
  export async function queryIndexedSessions(options, indexedOptions = {}) {
289
224
  getDB();
290
225
  const agents = options?.agent ? [options.agent] : SESSION_AGENTS;
@@ -292,24 +227,11 @@ export async function queryIndexedSessions(options, indexedOptions = {}) {
292
227
  if (indexedOptions.resolveLinear !== false)
293
228
  await resolveLinearProjects(sessions);
294
229
  for (const s of sessions) {
295
- // A non-empty transcript path is authoritative for origin (a live-home file
296
- // is this box; `backups/<agent>/<machine>/…` names that peer), so derive
297
- // there. An EMPTY file_path carries no such signal — `machineForSessionFile`
298
- // falls back to THIS box — so keep the machine the row was recorded with
299
- // instead: a host dispatch stamps the EXECUTION host on its empty-file index
300
- // row (`registerHostSession`), and re-deriving re-attributed the dispatcher's
301
- // own pool row to itself, splitting it from the executing peer's fan-out row
302
- // and making resume-by-id read as "ambiguous (2 sessions)" (RUSH-2486 /
303
- // RUSH-2479 criterion 2). A recorded-less empty-file row still falls back.
304
230
  if (s.filePath || !s.machine?.trim())
305
231
  s.machine = machineForSessionFile(s.filePath, s.agent);
306
232
  }
307
233
  return scopeToManaged(sessions, agents, options);
308
234
  }
309
- /**
310
- * Resolve locally without scanning or fleet I/O, keeping concurrent crash recovery lock-light.
311
- * The existence check preserves archived content while rejecting transcriptless phantoms.
312
- */
313
235
  export async function resolveIndexedSessionById(idQuery) {
314
236
  const q = idQuery.trim();
315
237
  if (!q)
@@ -357,16 +279,6 @@ async function resolveLinearProjects(sessions) {
357
279
  cacheLinearProject(session.id, project.name, project.url);
358
280
  }));
359
281
  }
360
- /**
361
- * Drop unmanaged rows for agents that HAVE managed versions.
362
- *
363
- * Scoping happens here, at query time, rather than by narrowing the scan: the index
364
- * stays complete, so `--unmanaged` needs no re-scan and every other consumer of the
365
- * DB (watchdog, the Factory watcher, `--roots`) is unaffected.
366
- *
367
- * An agent with no managed versions is left alone entirely — someone who has never
368
- * run `agents add` sees exactly what they saw before.
369
- */
370
282
  export function scopeToManaged(sessions, agents, options) {
371
283
  if (options?.includeUnmanaged)
372
284
  return sessions;
@@ -378,12 +290,6 @@ export function scopeToManaged(sessions, agents, options) {
378
290
  options?.onHiddenUnmanaged?.(hidden);
379
291
  return kept;
380
292
  }
381
- /**
382
- * True once agents-cli manages ANY agent version. Until then it manages nothing, so
383
- * scoping to "managed only" would leave the listing empty for a user who has never
384
- * run `agents add` — the browser is most of the tool's value before you install
385
- * anything through it.
386
- */
387
293
  function anyManagedVersions() {
388
294
  for (const root of VERSIONS_ROOTS) {
389
295
  const base = path.join(root, 'versions');
@@ -401,26 +307,19 @@ function anyManagedVersions() {
401
307
  if (fs.readdirSync(path.join(base, a.name), { withFileTypes: true }).some((e) => e.isDirectory()))
402
308
  return true;
403
309
  }
404
- catch { /* unreadable */ }
310
+ catch { }
405
311
  }
406
312
  }
407
313
  return false;
408
314
  }
409
- /**
410
- * How many agents' dotfile dirs we scan at once, and the minimum spacing between
411
- * successive scan starts. A small bound + stagger turns a simultaneous bulk
412
- * multi-dotfile sweep (a behavioral-EDR file-enumeration trigger) into a trickle.
413
- */
414
315
  export const DOTFILE_SCAN_CONCURRENCY = 2;
415
316
  const DOTFILE_SCAN_STAGGER_MS = 15;
416
- /** Run each agent's incremental scan, bounded + staggered. Order is irrelevant (each scan writes its own rows). */
417
317
  export function scanAgentsBounded(items, run) {
418
318
  return mapBounded(items, run, {
419
319
  concurrency: DOTFILE_SCAN_CONCURRENCY,
420
320
  staggerMs: DOTFILE_SCAN_STAGGER_MS,
421
321
  });
422
322
  }
423
- /** Dispatch a single agent's incremental dotfile scan. */
424
323
  function dispatchAgentScan(agent, onProgress) {
425
324
  switch (agent) {
426
325
  case 'claude': return scanClaudeIncremental(onProgress);
@@ -438,61 +337,18 @@ function dispatchAgentScan(agent, onProgress) {
438
337
  default: return Promise.resolve();
439
338
  }
440
339
  }
441
- /**
442
- * The machine a discovered session originated on. Cross-machine sync mirrors a
443
- * remote transcript to backups/<agent>/<machine>/<subdir>/… (see mirrorPath in
444
- * sync/agents.ts); every other transcript is a live-home file on this box. So:
445
- * when the path sits under the agent's backups root, the first segment below it
446
- * is the origin machine id; otherwise it's the local machine.
447
- */
448
- /**
449
- * True when this transcript belongs to a version agents-cli manages — i.e. it lives
450
- * under a version home (or a backup mirror of one) rather than in the user's own
451
- * `~/.<agent>`.
452
- *
453
- * `agents sessions` scans both, which is right for indexing: the DB stays a complete
454
- * picture and `--unmanaged` can surface everything without a re-scan. But listing
455
- * *by default* is a different question. Once you have managed versions, an unmanaged
456
- * install's history is not really agents-cli's to show — most visibly after
457
- * `agents add --isolated`, where the whole point was to keep the two apart.
458
- */
459
340
  export function isManagedSessionFile(filePath) {
460
- // Synthetic rows (OpenClaw workspace sessions, cloud/remote entries) have no local
461
- // transcript to classify. They are produced BY agents-cli rather than read out of
462
- // someone's dotfile dir, so scoping must not silently swallow them.
463
341
  if (!filePath || !path.isAbsolute(filePath))
464
342
  return true;
465
- // A composite file_path (`<container>#<id>`) names a row inside a single shared
466
- // DB the scanner reads from one fixed location (OpenCode's `opencode.db`) — that
467
- // store is never a per-install dotfile under a version home, so the managed-vs-
468
- // unmanaged split does not apply: there is exactly one store, not a "your own"
469
- // copy to hide. Classifying it as unmanaged hid every OpenCode row from default
470
- // listings once any agent was managed (RUSH-2357). Keyed off the composite FORM,
471
- // so any future single-DB harness inherits this.
472
343
  if (splitSessionFilePath(filePath).fragment !== undefined)
473
344
  return true;
474
345
  const roots = [
475
346
  ...VERSIONS_ROOTS.map((root) => path.join(root, 'versions')),
476
347
  path.join(getHistoryDir(), 'backups'),
477
- // Codex's managed home is not always under versions/. On macOS the versioned path
478
- // overflows SUN_LEN for codex's control socket, so the shim relocates it to
479
- // `<agentsUserDir>/.codex-homes/<key>/` (lib/codex-home.ts) — keyed by version OR
480
- // by account short key (`a-<accountId prefix>`, lib/codex-home.ts `codexShortKey`).
481
348
  path.join(getUserAgentsDir(), '.codex-homes'),
482
- // Account slots (PHNX-3940): a named account's HOME-shaped dir under
483
- // `<historyDir>/accounts/<agent>/<accountId>/` (lib/accounts/slots.ts
484
- // `slotDir`), sharing the one managed install rather than owning a version
485
- // home of its own. Without this root, every account-slot transcript read as
486
- // unmanaged the moment any version was managed, hiding a fully registered,
487
- // runnable account's entire history from the default listing.
488
349
  path.join(getHistoryDir(), 'accounts'),
489
- // Routine archives are agents-cli's OWN run output — managed by definition.
490
350
  getRunsDir(),
491
351
  ];
492
- // Compare realpaths as well as the literal roots. A transcript's stored path is
493
- // resolved, so on macOS (`/var` -> `/private/var`) a temp-dir HOME yields
494
- // `/private/var/...` for the file and `/var/...` for the root, and a plain prefix
495
- // test silently classifies every managed session as the user's own.
496
352
  const real = safeRealpathSync(filePath) || filePath;
497
353
  return roots.some((root) => {
498
354
  if (filePath.startsWith(root + path.sep))
@@ -501,16 +357,10 @@ export function isManagedSessionFile(filePath) {
501
357
  return !!realRoot && real.startsWith(realRoot + path.sep);
502
358
  });
503
359
  }
504
- /**
505
- * Count sessions in scope without running an incremental scan. Assumes the DB
506
- * is already fresh (typically true because `discoverSessions` ran first this
507
- * turn). Uses the exact same filter shape as the discover query.
508
- */
509
360
  export function countSessionsInScope(options) {
510
361
  const agents = options.agent ? [options.agent] : SESSION_AGENTS;
511
362
  return countSessions(buildQueryOptions(options, agents, { includeLimit: false }));
512
363
  }
513
- /** Translate DiscoverOptions into the QueryOptions shape expected by the DB layer. */
514
364
  function buildQueryOptions(options, agents, opts) {
515
365
  const projectQuery = options?.project?.trim();
516
366
  const sinceMs = options?.since ? parseTimeFilter(options.since) : undefined;
@@ -521,8 +371,6 @@ function buildQueryOptions(options, agents, opts) {
521
371
  cwdPrefixFilter = normalizeCwd(options.cwdPrefix);
522
372
  }
523
373
  else if (!options?.all && !projectQuery && options?.agent !== 'rush' && options?.agent !== 'hermes') {
524
- // Rush and Hermes sessions are cloud/gateway-bound and have no cwd — skip
525
- // cwd filtering when the user explicitly asked for them.
526
374
  cwdFilter = normalizeCwd(options?.cwd || process.cwd());
527
375
  }
528
376
  return {
@@ -546,109 +394,36 @@ function buildQueryOptions(options, agents, opts) {
546
394
  idPrefix: options?.idPrefix,
547
395
  };
548
396
  }
549
- /**
550
- * Canonicalize a working directory path (follows symlinks when it is local).
551
- *
552
- * Most callers pass a cwd RECORDED in a transcript, which may name a directory
553
- * on another machine — a POSIX path read on a Windows host, say. `path.resolve()`
554
- * rebases such a path onto the current drive (`/Users/me` -> `D:\Users\me`),
555
- * inventing a location that never existed. So an absolute path is normalized but
556
- * never rebased; only a genuinely relative one resolves against the process cwd.
557
- *
558
- * `path.normalize()` still runs on every branch: it collapses `.`, `..`, and
559
- * duplicate separators, and folds separators on Windows. Both sides of the cwd
560
- * filter in `db.ts` (`cwd = ?` and `cwd LIKE ? || path.sep || '%'`) come through
561
- * here, so dropping that would leave a trailing slash or a `..` segment in one
562
- * side and match nothing.
563
- *
564
- * Realpath is attempted only for a path that is absolute in THIS platform's
565
- * terms. A POSIX-rooted path on Windows is drive-relative to `fs.realpathSync`,
566
- * which would resolve `/Users/me` against the current drive and reintroduce the
567
- * graft for any path that happens to exist locally.
568
- */
569
397
  export function _normalizeCwdForTest(cwd) {
570
398
  return normalizeCwd(cwd);
571
399
  }
572
400
  function normalizeCwd(cwd) {
573
401
  if (!cwd)
574
402
  return '';
575
- // A POSIX-rooted path on Windows belongs to another machine. Normalize it with
576
- // POSIX rules so its separators survive — path.win32.normalize would fold them
577
- // to backslashes, mangling the very path we are trying to preserve — and never
578
- // realpath it, since fs.realpathSync would resolve it against the current drive.
579
403
  if (process.platform === 'win32' && /^\//.test(cwd) && !/^[a-zA-Z]:/.test(cwd)) {
580
404
  return stripTrailingSep(path.posix.normalize(cwd));
581
405
  }
582
- // The mirror case (RUSH-2358): a Windows-rooted path (`C:\...`, `C:/...`, or a
583
- // UNC `\\server\share\...`) read on POSIX belongs to another machine too, but
584
- // `path.isAbsolute()` here uses POSIX rules and doesn't recognize a drive
585
- // letter — without this branch such a cwd falls into the `path.resolve()` arm
586
- // below and gets silently prefixed with THIS process's own cwd, corrupting the
587
- // path (and, via WORKTREE_RE, can misattribute the worktree slug to whatever
588
- // worktree the reading process happens to be running in). Normalize with
589
- // win32 rules so separators survive; never realpath it, for the same
590
- // cross-drive reason as the mirror branch above.
591
406
  if (process.platform !== 'win32' && /^([a-zA-Z]:[\\/]|\\\\)/.test(cwd)) {
592
407
  return stripTrailingSep(path.win32.normalize(cwd));
593
408
  }
594
409
  const normalized = path.isAbsolute(cwd) ? stripTrailingSep(path.normalize(cwd)) : path.resolve(cwd);
595
410
  return safeRealpathSync(normalized) || normalized;
596
411
  }
597
- /** Drop a trailing separator so `cwd = ?` and the `cwd LIKE ? + sep` subdir
598
- * wildcard agree; a root path (`/`, `C:\`) keeps its separator. */
599
412
  function stripTrailingSep(p) {
600
413
  const stripped = p.replace(/[\\/]+$/, '');
601
414
  return stripped.length > 0 && !/^[a-zA-Z]:$/.test(stripped) ? stripped : p;
602
415
  }
603
- /** Canonical 8-4-4-4-12 hex UUID (covers both v4 and the v7 ids newer harnesses mint). */
604
416
  const UUID_36 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
605
- /** kimi and rush mint `session_` + a UUID. */
606
417
  const SESSION_UUID_PREFIX = /^session_/;
607
- /** opencode mints `ses_` + a 26-char ULID — NOT a UUID, so it needs its own shape. */
608
418
  const SES_ULID = /^ses_[0-9a-z]{26}$/;
609
- /**
610
- * Whether a query is a session id in full, rather than an id prefix or a search
611
- * phrase.
612
- *
613
- * Callers use this to decide that an id lookup is the ONLY admissible
614
- * interpretation: a complete id is unique, so when it misses there is nothing
615
- * left to widen to. Without the check, `sessions <uuid>` fell through to the
616
- * FTS content search, which tokenizes the UUID and matches every transcript that
617
- * merely mentions it — surfacing unrelated sessions as if they were id matches.
618
- *
619
- * The accepted shapes are the ones the index actually holds, measured over a
620
- * 12,507-row index: a bare UUID (11,116 rows), `session_` + UUID (1,360 — kimi
621
- * and rush), and `ses_` + ULID (15 — opencode). Deliberately NOT covered, so a
622
- * miss keeps today's search behavior rather than gaining a wrong error: routine
623
- * run ids (ISO timestamps, matched via `routineRunId` below) and cloud execution
624
- * ids, whose charset is too permissive to distinguish from a search phrase.
625
- */
626
419
  export function isCompleteSessionId(query) {
627
420
  const q = query.trim().toLowerCase();
628
421
  return UUID_36.test(q.replace(SESSION_UUID_PREFIX, '')) || SES_ULID.test(q);
629
422
  }
630
- /**
631
- * Whether a query should be treated as a session id rather than a search phrase
632
- * — the one canonical id-shaped test, shared by every session-id resolver.
633
- *
634
- * True for a complete id (`isCompleteSessionId`) AND for a bare hex short-id or
635
- * prefix (`d3470b57`), which the complete-id check rejects. Any id-shaped query
636
- * resolves by id ONLY (exact -> prefix -> `findSessionsById` index) and must
637
- * never fall back to fuzzy content search: a short id like `d3470b57` otherwise
638
- * surfaces every transcript that merely MENTIONS the string (a resume prompt
639
- * echoes the parent id into the body of many later sessions). The hex test
640
- * catches the bare short-id/prefix; `isCompleteSessionId` additionally catches
641
- * the prefixed whole ids (`session_…`, `ses_…`) that the hex test rejects.
642
- */
643
423
  export function looksLikeSessionId(query) {
644
424
  const trimmed = query.trim();
645
425
  return /^[0-9a-f-]{6,}$/i.test(trimmed) || isCompleteSessionId(trimmed);
646
426
  }
647
- /**
648
- * Resolve a session by full or short ID. Accepts a pre-loaded session list
649
- * (fast path from discoverSessions) and falls back to a DB lookup for the
650
- * "I only know the id" case.
651
- */
652
427
  export function resolveSessionById(sessions, idQuery) {
653
428
  const query = idQuery.toLowerCase();
654
429
  const exact = sessions.filter(s => s.id.toLowerCase() === query ||
@@ -660,20 +435,6 @@ export function resolveSessionById(sessions, idQuery) {
660
435
  s.shortId.toLowerCase().startsWith(query) ||
661
436
  s.routineRunId?.toLowerCase().startsWith(query));
662
437
  }
663
- // ---------------------------------------------------------------------------
664
- // Content-index search (FTS5-backed)
665
- // ---------------------------------------------------------------------------
666
- /**
667
- * Run an FTS5 search over the DB and union hits with the given session list.
668
- *
669
- * The listing pool is a minority of the index — cwd-scoped, default-capped at
670
- * 50, and skipping whole classes of indexed transcript — so intersecting FTS
671
- * hits with it dropped grep-visible sessions that the index already found
672
- * (PHNX-2767: `agents sessions "tmux pane"` returned 0 while the project
673
- * transcripts matched). Hits already in the pool keep the caller's SessionMeta;
674
- * hits the pool missed are hydrated from the index so a content query returns
675
- * the transcript FTS matched.
676
- */
677
438
  export function searchContentIndex(sessions, query) {
678
439
  if (!query.trim())
679
440
  return new Map();
@@ -695,18 +456,6 @@ export function searchContentIndex(sessions, query) {
695
456
  }
696
457
  return result;
697
458
  }
698
- // ---------------------------------------------------------------------------
699
- // Incremental scan orchestration
700
- // ---------------------------------------------------------------------------
701
- /**
702
- * For a list of files, stat each, compare to the DB ledger, and return only
703
- * the ones that need rescanning. One bulk DB query for the whole list.
704
- *
705
- * Actively running agents append to their JSONL every few seconds. Without a
706
- * small debounce, repeated `agents sessions` invocations stream-parse the same
707
- * growing transcript over and over. The cached row is good enough for a few
708
- * seconds; once writes settle or the debounce expires, the file is parsed once.
709
- */
710
459
  export function filterChangedFiles(filePaths) {
711
460
  const entries = [];
712
461
  for (const filePath of filePaths) {
@@ -717,19 +466,6 @@ export function filterChangedFiles(filePaths) {
717
466
  }
718
467
  return filterChangedEntries(entries);
719
468
  }
720
- /**
721
- * Ledger-compare pre-stat'd entries (from the walk's own stat) without a second
722
- * stat. Same debounce and change-detection as filterChangedFiles; the raw
723
- * mtime is floored here so warm files match the ledger exactly as the stat path
724
- * does (Math.floor(stat.mtimeMs)).
725
- *
726
- * A file is also treated as "changed" — independent of (mtime, size) — when
727
- * its ledger row's `extractor_version` is behind {@link CONTENT_INDEX_VERSION}.
728
- * This is the lever that backfills a content-extractor improvement (e.g.
729
- * indexing assistant answers, not just user prompts) into every already-scanned
730
- * session on its next pass, without a `DELETE FROM scan_ledger` that would also
731
- * discard the Claude/Codex resumable parser_state.
732
- */
733
469
  export function filterChangedEntries(entries) {
734
470
  const ledger = getScanStampsForPaths(entries.map(e => e.filePath));
735
471
  const out = [];
@@ -760,31 +496,10 @@ export function shouldDeferRecentAppend(prev, current, nowMs, debounceMs = ACTIV
760
496
  return false;
761
497
  return nowMs - prev.scannedAt < debounceMs;
762
498
  }
763
- /**
764
- * Walk a set of leaf transcript directories and return the files that changed,
765
- * skipping the per-file `stat` of directories whose (mtime, entry_count) matches
766
- * the dir_ledger.
767
- *
768
- * Per leaf dir:
769
- * - `stat` the dir once and `readdir` it (one cheap syscall) to get the entry
770
- * count and the file list.
771
- * - If the dir matches the dir_ledger (floored mtime AND entry_count), no file
772
- * was created / deleted / renamed since we last walked it. We then stat ONLY
773
- * the hot files (live-root files, or files scanned within HOT_FILE_WINDOW_MS)
774
- * and run just those through the ledger compare — so an in-place append to a
775
- * still-live session is still caught, while immutable backup/version dirs
776
- * collapse to a single dir stat and zero per-file stats.
777
- * - Else (changed dir, or no ledger row) we stat every file (today's full
778
- * walk) and record the fresh dir stamp so the next run can short-circuit.
779
- *
780
- * The kill-switch (`AGENTS_SESSIONS_NO_DIR_LEDGER=1`) forces the full-walk branch
781
- * for every dir and never consults or records the dir_ledger.
782
- */
783
499
  function collectChangedFilesInLeafDirs(leafDirs, ext) {
784
500
  const disabled = dirLedgerDisabled();
785
501
  const dirStamps = disabled ? new Map() : getDirLedgerForPaths(leafDirs.map(d => d.dirPath));
786
502
  const now = Date.now();
787
- // Files whose per-file stat we still need to ledger-compare this run.
788
503
  const toCompare = [];
789
504
  const allFiles = [];
790
505
  const dirScansToRecord = [];
@@ -807,16 +522,6 @@ function collectChangedFilesInLeafDirs(leafDirs, ext) {
807
522
  const prevDir = dirStamps.get(dirPath);
808
523
  const dirUnchanged = !disabled && prevDir !== undefined && prevDir.dirMtimeMs === dirMtimeMs && prevDir.entryCount === entryCount;
809
524
  if (dirUnchanged) {
810
- // Contents did not change (no create/delete/rename). Stat only the hot
811
- // files; the rest are served from the DB with no stat. An immutable backup
812
- // dir (not a live root, nothing recently scanned) does zero per-file stats.
813
- //
814
- // A live-root dir treats every file as hot — that is the tree an agent
815
- // appends to live, and an append does NOT bump the parent-dir mtime, so
816
- // without this a growing session would be silently skipped. A non-live
817
- // file is hot only if it was scanned within HOT_FILE_WINDOW_MS (bulk ledger
818
- // lookup), covering a session under a version/backup path that is somehow
819
- // still being written.
820
525
  const stamps = isLiveRoot ? null : getScanStampsForPaths(files);
821
526
  for (const filePath of files) {
822
527
  let hot = isLiveRoot;
@@ -832,10 +537,8 @@ function collectChangedFilesInLeafDirs(leafDirs, ext) {
832
537
  continue;
833
538
  toCompare.push({ filePath, fileMtimeMs: stat.mtimeMs, fileSize: stat.size });
834
539
  }
835
- // No dir stamp to record — nothing about the dir changed.
836
540
  }
837
541
  else {
838
- // Changed dir (or cold ledger): full per-file stat, exactly as today.
839
542
  for (const filePath of files) {
840
543
  const stat = safeStatSync(filePath);
841
544
  if (!stat)
@@ -852,13 +555,6 @@ function collectChangedFilesInLeafDirs(leafDirs, ext) {
852
555
  recordDirScans(dirScansToRecord);
853
556
  return { changed, allFiles };
854
557
  }
855
- // ---------------------------------------------------------------------------
856
- // Multi-version directory scanning
857
- // ---------------------------------------------------------------------------
858
- /**
859
- * Collect all directories to scan for an agent's sessions. Deduplicates by
860
- * realpath to avoid double-counting symlinked version homes.
861
- */
862
558
  export function getAgentSessionDirs(agent, subdir) {
863
559
  const resolved = new Set();
864
560
  const dirs = [];
@@ -872,9 +568,6 @@ export function getAgentSessionDirs(agent, subdir) {
872
568
  resolved.add(key);
873
569
  dirs.push(dir);
874
570
  }
875
- // Config-dir name relative to home — handles nested layouts (antigravity →
876
- // .gemini/antigravity-cli) and ~/.config agents (amp, goose) as well as kimi
877
- // (.kimi-code). Falls back to `.${agent}` for ids not in the registry.
878
571
  const configDirName = agent in AGENTS ? agentConfigDirName(agent) : `.${agent}`;
879
572
  addDir(path.join(HOME, configDirName, subdir));
880
573
  for (const root of VERSIONS_ROOTS) {
@@ -886,19 +579,8 @@ export function getAgentSessionDirs(agent, subdir) {
886
579
  addDir(path.join(versionsBase, version, 'home', configDirName, subdir));
887
580
  }
888
581
  }
889
- catch { /* dir unreadable */ }
890
- }
891
- // Codex's managed home is not always where the version layout says. On macOS
892
- // the versioned path overflows SUN_LEN (104 bytes) for codex's control socket,
893
- // so the shim relocates the home to `<agentsUserDir>/.codex-homes/<key>/.codex`
894
- // (lib/codex-home.ts) — `<key>` is the version for a version home, or
895
- // `a-<accountId prefix>` (`codexShortKey`) for an account slot under
896
- // `<historyDir>/accounts/codex/`. Walking `.codex-homes/` directly — rather
897
- // than deriving keys from the installed-version list — is what catches BOTH:
898
- // an account short key is not a vendor version and never appears in
899
- // `versions/codex/`, so iterating only installed versions silently dropped
900
- // every transcript a codex account slot wrote. addDir skips what does not
901
- // exist, so this is inert on Linux and for homes that never needed relocating.
582
+ catch { }
583
+ }
902
584
  if (agent === 'codex') {
903
585
  const codexHomesBase = path.join(getUserAgentsDir(), '.codex-homes');
904
586
  try {
@@ -906,25 +588,15 @@ export function getAgentSessionDirs(agent, subdir) {
906
588
  addDir(path.join(codexHomesBase, key, '.codex', subdir));
907
589
  }
908
590
  }
909
- catch { /* dir absent or unreadable */ }
910
- }
911
- // Account slots (PHNX-3940): a named account gets its own HOME-shaped dir
912
- // under `<historyDir>/accounts/<agent>/<accountId>/`, sharing the one managed
913
- // binary install rather than owning a version home of its own
914
- // (lib/accounts/slots.ts `slotDir`). A slot-launched transcript lives ONLY
915
- // there — never under `versions/` — so without this root it is fully
916
- // discoverable by the account machinery (the account is registered and
917
- // runnable) yet invisible to `agents sessions`, reading as if the history had
918
- // vanished. `addDir` follows the realpath, so a codex slot whose `.codex` is a
919
- // symlink onto its `.codex-homes/<key>` short home (SUN_LEN relocation, above)
920
- // is deduplicated against that same target rather than double-counted.
591
+ catch { }
592
+ }
921
593
  const accountsBase = path.join(getHistoryDir(), 'accounts', agent);
922
594
  try {
923
595
  for (const accountId of fs.readdirSync(accountsBase)) {
924
596
  addDir(path.join(accountsBase, accountId, configDirName, subdir));
925
597
  }
926
598
  }
927
- catch { /* dir absent or unreadable */ }
599
+ catch { }
928
600
  const backupsBase = path.join(getHistoryDir(), 'backups', agent);
929
601
  if (fs.existsSync(backupsBase)) {
930
602
  try {
@@ -932,18 +604,10 @@ export function getAgentSessionDirs(agent, subdir) {
932
604
  addDir(path.join(backupsBase, ts, subdir));
933
605
  }
934
606
  }
935
- catch { /* dir unreadable */ }
607
+ catch { }
936
608
  }
937
609
  return dirs;
938
610
  }
939
- /**
940
- * The (agent, subdir) pairs `discoverSessions` walks for JSONL transcripts —
941
- * the single source of truth for which directories hold live session files.
942
- * `getSessionRoots` expands each pair to its concrete directories so a consumer
943
- * (AGI EXT's fs.watch, see issue #741) can configure its watcher
944
- * from the CLI instead of hardcoding `~/.claude|.codex|.gemini`. Adding a new
945
- * on-disk agent here makes every consumer watch it automatically.
946
- */
947
611
  const SESSION_ROOT_SPECS = [
948
612
  { agent: 'claude', subdir: 'projects' },
949
613
  { agent: 'codex', subdir: 'sessions' },
@@ -956,12 +620,6 @@ const SESSION_ROOT_SPECS = [
956
620
  function sessionRootSubdir(agent) {
957
621
  return SESSION_ROOT_SPECS.find((spec) => spec.agent === agent)?.subdir ?? null;
958
622
  }
959
- /**
960
- * The directories `agents sessions` scans for each on-disk session agent,
961
- * resolved to what exists on this machine. Emitted by `agents sessions --roots
962
- * --json` so external watchers stay in lockstep with the CLI's discovery paths.
963
- * Agents with no directories present are omitted.
964
- */
965
623
  export function getSessionRoots() {
966
624
  const out = [];
967
625
  for (const { agent, subdir } of SESSION_ROOT_SPECS) {
@@ -1030,9 +688,6 @@ async function readRoutineArchiveMeta(agent, filePath) {
1030
688
  return null;
1031
689
  if (agent === 'claude') {
1032
690
  const sessionId = path.basename(filePath).replace(/\.jsonl$/, '');
1033
- // Routine archives are finalized, immutable transcripts — no live append, so
1034
- // no continuation to resume. A FULL parse (undefined prior) is correct here;
1035
- // the returned continuation is unused by this archive path.
1036
691
  const stat = safeStatSync(filePath);
1037
692
  if (!stat)
1038
693
  return null;
@@ -1045,8 +700,6 @@ async function readRoutineArchiveMeta(agent, filePath) {
1045
700
  return result ? { ...result, meta: decorateRoutineSession(result.meta, info) } : null;
1046
701
  }
1047
702
  if (agent === 'cursor') {
1048
- // PR #1723 archives Cursor routine transcripts; preserve version resolution
1049
- // when this reader consumes those archives.
1050
703
  const currentVersion = await getCurrentAgentVersion('cursor');
1051
704
  const result = readCursorMeta(filePath, currentVersion);
1052
705
  return result ? { ...result, meta: decorateRoutineSession(result.meta, info) } : null;
@@ -1096,34 +749,12 @@ async function scanRoutineArchivesIncremental(agent, onProgress) {
1096
749
  upsertSessionsBatch(entries);
1097
750
  recordScans(touched);
1098
751
  }
1099
- // ---------------------------------------------------------------------------
1100
- // Claude account info
1101
- // ---------------------------------------------------------------------------
1102
752
  let cachedClaudeAccountIndex;
1103
- /**
1104
- * The account-attribution index, built at most once per scan pass.
1105
- *
1106
- * Rebuilt when `refresh` is set — `scanClaudeIncremental` does that at the start of
1107
- * each pass so a long-lived process (the daemon) picks up an `agents use` switch or a
1108
- * fresh login instead of attributing later sessions to a stale set of homes. Per-file
1109
- * resolution then reads the cached index, because rebuilding it per transcript would
1110
- * re-read every home's `.claude.json` thousands of times.
1111
- */
1112
753
  function claudeAccountIndex(refresh = false) {
1113
754
  if (refresh || !cachedClaudeAccountIndex)
1114
755
  cachedClaudeAccountIndex = buildClaudeAccountIndex();
1115
756
  return cachedClaudeAccountIndex;
1116
757
  }
1117
- // ---------------------------------------------------------------------------
1118
- // Claude
1119
- // ---------------------------------------------------------------------------
1120
- /**
1121
- * Build a map of Claude sessionId -> user-given label from ~/.claude/sessions/*.json.
1122
- * Each JSON has shape { pid, sessionId, cwd, startedAt, name?, ... }. The
1123
- * `name` field only exists if the user ran /rename in that session.
1124
- * For sessionId collisions (re-resume of the same session), prefer the most
1125
- * recent startedAt.
1126
- */
1127
758
  export function buildClaudeLabelMap() {
1128
759
  const map = new Map();
1129
760
  const dir = path.join(HOME, '.claude', 'sessions');
@@ -1148,23 +779,16 @@ export function buildClaudeLabelMap() {
1148
779
  map.set(data.sessionId, { label: name, startedAt });
1149
780
  }
1150
781
  }
1151
- catch { /* unreadable session metadata file */ }
782
+ catch { }
1152
783
  }
1153
784
  const out = new Map();
1154
785
  for (const [sid, { label }] of map)
1155
786
  out.set(sid, label);
1156
787
  return out;
1157
788
  }
1158
- /** Incrementally re-scan changed Claude session files and upsert into the DB. */
1159
789
  async function scanClaudeIncremental(onProgress) {
1160
- // Rebuild once per pass; readClaudeMeta resolves each transcript against it.
1161
790
  claudeAccountIndex(true);
1162
791
  const labelMap = buildClaudeLabelMap();
1163
- // Enumerate every leaf project dir across all Claude roots. The FIRST root
1164
- // returned by getAgentSessionDirs is the agent's live `~/.claude/projects` —
1165
- // the only tree Claude appends to in place, so its project dirs are live roots
1166
- // (every file hot). Version-home + backup roots are immutable: their dirs
1167
- // short-circuit to a single dir stat when unchanged.
1168
792
  const roots = getAgentSessionDirs('claude', 'projects');
1169
793
  const leafDirs = [];
1170
794
  const seenLeaf = new Set();
@@ -1187,17 +811,6 @@ async function scanClaudeIncremental(onProgress) {
1187
811
  }
1188
812
  });
1189
813
  const { changed: changedAll, allFiles } = collectChangedFilesInLeafDirs(leafDirs, '.jsonl');
1190
- // Restore the pre-A-2 cross-root precedence: a session id present in multiple
1191
- // roots is ALWAYS served from its live path, never a frozen backup/version
1192
- // copy. Pre-A-2, dedup happened at enumeration time via a live-first `seen`
1193
- // set, so a non-live copy was never even stat'd when a live copy existed. This
1194
- // PR must not regress that to "whichever copy changed this run wins" — a cold
1195
- // (unchanged) live copy paired with a freshly-written backup snapshot would
1196
- // otherwise flip the row's file_path to the backup path.
1197
- //
1198
- // allFiles is every transcript file across all roots in live-first order, so
1199
- // the FIRST occurrence of each session id is its live (or highest-precedence)
1200
- // path — the durable winner, independent of which copy was flagged changed.
1201
814
  const sessionIdOf = (fp) => path.basename(fp).replace('.jsonl', '');
1202
815
  const winnerBySession = new Map();
1203
816
  for (const { filePath } of allFiles) {
@@ -1205,18 +818,9 @@ async function scanClaudeIncremental(onProgress) {
1205
818
  if (!winnerBySession.has(id))
1206
819
  winnerBySession.set(id, filePath);
1207
820
  }
1208
- // Keep a changed entry only if it is its session's winner. A changed non-live
1209
- // copy is dropped whenever a live copy exists anywhere; the winning path is
1210
- // parsed only when it itself changed (a cold winner needs no re-parse — its DB
1211
- // row already points at the live path).
1212
821
  const changed = changedAll.filter(e => winnerBySession.get(sessionIdOf(e.filePath)) === e.filePath);
1213
822
  if (changed.length > 0) {
1214
823
  onProgress?.({ agent: 'claude', parsed: 0, total: changed.length });
1215
- // Bulk-fetch each changed file's prior resumable continuation. A file with a
1216
- // usable prior state + growth goes incremental (re-parse only the appended
1217
- // bytes); everything else does a FULL from-offset-0 parse. The decision + the
1218
- // parse both live in scanClaudeSessionResumable so full and incremental share
1219
- // one reducer and produce identical rows.
1220
824
  const priorStates = getParserStatesForPaths(changed.map(c => c.filePath));
1221
825
  const entries = [];
1222
826
  const touched = [];
@@ -1252,24 +856,10 @@ async function scanClaudeIncremental(onProgress) {
1252
856
  upsertSessionsBatch(entries);
1253
857
  recordScans(touched);
1254
858
  }
1255
- // Pick up /rename changes on sessions whose JSONL didn't change.
1256
- // Only bother for sessions we actually have a Claude row for.
1257
859
  if (labelMap.size > 0)
1258
860
  syncLabels(labelMap);
1259
861
  }
1260
- /**
1261
- * Stream-parse a single Claude JSONL file to extract session metadata, resuming
1262
- * from the persisted continuation when the file merely grew (see
1263
- * {@link scanClaudeSessionResumable}). Returns the row's meta + FTS content plus
1264
- * the serialized continuation (parser_state + content_text) to persist for the
1265
- * next scan.
1266
- */
1267
862
  async function readClaudeMeta(filePath, sessionId, scanStamp, priorRow, label) {
1268
- // A prior continuation extracted at an older CONTENT_INDEX_VERSION is missing
1269
- // whatever the current extractor adds (e.g. assistant-answer text) — resuming
1270
- // from it would fold only the NEWLY appended lines into that gap, never
1271
- // backfilling the file's earlier assistant text. Treat it as absent so the
1272
- // file gets one full from-offset-0 reparse instead.
1273
863
  const prior = priorRow?.extractorVersion === CONTENT_INDEX_VERSION ? parsePriorClaudeState(priorRow) : null;
1274
864
  const { scan, newState, toolCalls, mode } = await scanClaudeSessionResumable(filePath, prior, scanStamp.fileMtimeMs, scanStamp.fileSize, priorRow?.fileMtimeMs);
1275
865
  if (mode === 'incremental')
@@ -1277,9 +867,6 @@ async function readClaudeMeta(filePath, sessionId, scanStamp, priorRow, label) {
1277
867
  else
1278
868
  claudeFullScanCount++;
1279
869
  const isTeamOrigin = scan.entrypoint === 'sdk-cli';
1280
- // Which account produced this transcript. Resolved from the path plus the version
1281
- // recorded inside the file, so rows under the mutable ~/.claude symlink are
1282
- // attributed to the version that actually wrote them. See claude-accounts.ts.
1283
870
  const acct = resolveClaudeAccount(claudeAccountIndex(), filePath, scan.version, readSessionActorRecord(sessionId)?.accountId);
1284
871
  let meta;
1285
872
  if (scan.timestamp) {
@@ -1301,8 +888,6 @@ async function readClaudeMeta(filePath, sessionId, scanStamp, priorRow, label) {
1301
888
  accountOrg: acct.orgName ?? undefined,
1302
889
  topic: scan.topic,
1303
890
  firstUserMessage: scan.firstUserMessage,
1304
- // The live sessions metadata file contains only user `/rename` values;
1305
- // prefer it when present, then fall back to the title parsed from JSONL.
1306
891
  label: label || scan.label,
1307
892
  messageCount: scan.messageCount,
1308
893
  toolCallCount: scan.toolCallCount,
@@ -1343,8 +928,6 @@ async function readClaudeMeta(filePath, sessionId, scanStamp, priorRow, label) {
1343
928
  accountKey: acct.key,
1344
929
  accountOrg: acct.orgName ?? undefined,
1345
930
  model: scan.model,
1346
- // Keep parsed ai-title/custom-title values even when the transcript has
1347
- // no timestamp and therefore takes this stat-backed fallback path.
1348
931
  label: label || scan.label,
1349
932
  messageCount: scan.messageCount,
1350
933
  toolCallCount: scan.toolCallCount,
@@ -1378,26 +961,14 @@ async function readClaudeMeta(filePath, sessionId, scanStamp, priorRow, label) {
1378
961
  meta,
1379
962
  content: scan.contentText || '',
1380
963
  assistantContent: scan.assistantText || '',
1381
- // Persist the continuation so the next scan of this file can resume from the
1382
- // offset instead of a full reparse. content_text is the same accumulated user
1383
- // doc, cached so the resume can hydrate userTexts without re-reading the file.
1384
964
  parserState: JSON.stringify(newState),
1385
965
  contentText: newState.contentText,
1386
966
  toolCalls,
1387
967
  toolIndexMode: mode === 'full' ? 'replace' : 'append',
1388
968
  };
1389
969
  }
1390
- // ---------------------------------------------------------------------------
1391
- // Codex account info
1392
- // ---------------------------------------------------------------------------
1393
970
  let cachedCodexAccount;
1394
- /** Number of times the auth.json JWT was actually base64-decoded. Test seam for the lazy-decode contract. */
1395
971
  let codexAccountResolveCount = 0;
1396
- /**
1397
- * Base64url-decode a JWT and return its `email` claim, if present. Split out so
1398
- * the decode is a single, testable step — and so it only runs when someone
1399
- * actually reads the Codex account (see the lazy resolution below).
1400
- */
1401
972
  export function decodeJwtEmail(idToken) {
1402
973
  const parts = idToken.split('.');
1403
974
  if (parts.length < 2)
@@ -1407,17 +978,9 @@ export function decodeJwtEmail(idToken) {
1407
978
  return typeof payload.email === 'string' ? payload.email : undefined;
1408
979
  }
1409
980
  catch {
1410
- return undefined; // malformed JWT
981
+ return undefined;
1411
982
  }
1412
983
  }
1413
- /**
1414
- * Extract the Codex account email from the JWT id_token in auth.json.
1415
- *
1416
- * Memoized and resolved LAZILY: the credential-harvesting-shaped JWT decode
1417
- * (base64-decoding ~/.codex/auth.json) only runs when the account is actually
1418
- * needed to build a session's metadata — never eagerly during the bulk scan.
1419
- * A scan with no changed Codex files never touches the auth file.
1420
- */
1421
984
  function getCodexAccount() {
1422
985
  if (cachedCodexAccount !== undefined)
1423
986
  return cachedCodexAccount || undefined;
@@ -1432,7 +995,7 @@ function getCodexAccount() {
1432
995
  candidates.push(path.join(versionsBase, version, 'home', '.codex', 'auth.json'));
1433
996
  }
1434
997
  }
1435
- catch { /* versions dir unreadable */ }
998
+ catch { }
1436
999
  }
1437
1000
  for (const candidate of candidates) {
1438
1001
  try {
@@ -1448,59 +1011,37 @@ function getCodexAccount() {
1448
1011
  }
1449
1012
  }
1450
1013
  }
1451
- catch { /* auth file malformed */ }
1014
+ catch { }
1452
1015
  }
1453
1016
  cachedCodexAccount = '';
1454
1017
  return undefined;
1455
1018
  }
1456
- /** Test seam: how many times getCodexAccount has actually resolved (decoded) since the last reset. */
1457
1019
  export function __codexAccountResolveCountForTest() {
1458
1020
  return codexAccountResolveCount;
1459
1021
  }
1460
- /** Test seam: clear the memoized account + resolve counter so laziness can be observed from a clean slate. */
1461
1022
  export function __resetCodexAccountCacheForTest() {
1462
1023
  cachedCodexAccount = undefined;
1463
1024
  codexAccountResolveCount = 0;
1464
1025
  }
1465
- // ---------------------------------------------------------------------------
1466
- // Codex
1467
- // ---------------------------------------------------------------------------
1468
- /** Incrementally re-scan changed Codex session files and upsert into the DB. */
1469
1026
  async function scanCodexIncremental(onProgress) {
1470
- // Lazy: getCodexAccount (the auth.json JWT decode) is only resolved by
1471
- // readCodexMeta when a changed session actually needs it — never eagerly here,
1472
- // so a no-op scan (changed.length === 0) never touches the credential file.
1473
1027
  const currentVersion = await getCurrentAgentVersion('codex');
1474
1028
  const prestat = [];
1475
1029
  for (const sessionsDir of getAgentSessionDirs('codex', 'sessions')) {
1476
- // High limit: the walk stats each file once here; parsing is gated by the
1477
- // ledger match below, which reuses that stat instead of re-stat'ing.
1478
1030
  for (const f of walkForFilesWithStat(sessionsDir, '.jsonl', 100_000)) {
1479
1031
  prestat.push({ filePath: f.path, fileMtimeMs: f.mtimeMs, fileSize: f.size });
1480
1032
  }
1481
1033
  }
1482
1034
  const changed = filterChangedEntries(prestat);
1483
- // Codex keeps human-readable titles (`thread_name`) in `session_index.jsonl`,
1484
- // which updates independently of the rollout files. Stat each index against the
1485
- // ledger *without reading it*; only read + re-apply titles when the index (or a
1486
- // rollout) actually changed. On a fully unchanged scan this collapses to a
1487
- // couple of stat() calls instead of a full read + a `syncTopics` DB pass.
1488
1035
  const titleIndex = diffCodexTitleIndexes();
1489
1036
  if (changed.length === 0 && !titleIndex.changed)
1490
1037
  return;
1491
1038
  const titles = readCodexThreadNames();
1492
1039
  if (changed.length === 0) {
1493
- // No rollouts changed, but the title index did — apply the new titles.
1494
1040
  syncTopics(titles);
1495
1041
  recordScans(titleIndex.stamps);
1496
1042
  return;
1497
1043
  }
1498
1044
  onProgress?.({ agent: 'codex', parsed: 0, total: changed.length });
1499
- // Bulk-fetch each changed rollout's prior resumable continuation. A file with
1500
- // a usable prior state + growth goes incremental (re-parse only the appended
1501
- // bytes); everything else does a FULL from-offset-0 parse. The decision + the
1502
- // parse both live in scanCodexSessionResumable so full and incremental share
1503
- // one reducer and produce identical rows.
1504
1045
  const priorStates = getParserStatesForPaths(changed.map(c => c.filePath));
1505
1046
  const entries = [];
1506
1047
  const touched = [];
@@ -1512,7 +1053,6 @@ async function scanCodexIncremental(onProgress) {
1512
1053
  const result = await readCodexMeta(filePath, getCodexAccount, currentVersion, scan, priorRow);
1513
1054
  if (result && !seen.has(result.meta.id)) {
1514
1055
  seen.add(result.meta.id);
1515
- // Prefer the Codex-generated title over the first-prompt fallback.
1516
1056
  const title = titles.get(result.meta.id);
1517
1057
  if (title)
1518
1058
  result.meta.topic = title;
@@ -1539,14 +1079,10 @@ async function scanCodexIncremental(onProgress) {
1539
1079
  }
1540
1080
  upsertSessionsBatch(entries);
1541
1081
  recordScans(touched);
1542
- // Only when the title index changed can an *unchanged* rollout have gained a
1543
- // title since the last scan; the inline titles applied above already cover
1544
- // every changed session, so skip the extra sync when the index is untouched.
1545
1082
  if (titleIndex.changed)
1546
1083
  syncTopics(titles);
1547
1084
  recordScans(titleIndex.stamps);
1548
1085
  }
1549
- /** Parse the lines of a Codex `session_index.jsonl` into a session id -> title map. */
1550
1086
  export function parseCodexThreadNameIndex(raw) {
1551
1087
  const titles = new Map();
1552
1088
  for (const line of raw.split('\n')) {
@@ -1560,20 +1096,10 @@ export function parseCodexThreadNameIndex(raw) {
1560
1096
  titles.set(id, name);
1561
1097
  }
1562
1098
  catch {
1563
- // skip malformed line
1564
1099
  }
1565
1100
  }
1566
1101
  return titles;
1567
1102
  }
1568
- /**
1569
- * Stat every Codex `session_index.jsonl` and diff it against the scan ledger
1570
- * *without reading it*. Returns the fresh stamps (persisted only after a
1571
- * successful title sync) and whether any index changed since the last scan — the
1572
- * signal that lets a no-op scan skip the file read + `syncTopics` entirely.
1573
- *
1574
- * The index path is a sibling of `sessions/` (never inside it), so it is never
1575
- * walked as a rollout and its ledger row can't collide with a transcript's.
1576
- */
1577
1103
  function diffCodexTitleIndexes() {
1578
1104
  const stamps = [];
1579
1105
  let changed = false;
@@ -1581,7 +1107,7 @@ function diffCodexTitleIndexes() {
1581
1107
  const indexPath = path.join(path.dirname(sessionsDir), 'session_index.jsonl');
1582
1108
  const stat = safeStatSync(indexPath);
1583
1109
  if (!stat)
1584
- continue; // no index in this home
1110
+ continue;
1585
1111
  const scan = { fileMtimeMs: Math.floor(stat.mtimeMs), fileSize: stat.size };
1586
1112
  const prev = getScanStampByPath(indexPath);
1587
1113
  if (!prev || prev.fileMtimeMs !== scan.fileMtimeMs || prev.fileSize !== scan.fileSize) {
@@ -1591,10 +1117,6 @@ function diffCodexTitleIndexes() {
1591
1117
  }
1592
1118
  return { stamps, changed };
1593
1119
  }
1594
- /**
1595
- * Read Codex session titles across every Codex home (live + versioned). The
1596
- * `session_index.jsonl` file sits beside each `sessions/` rollout tree.
1597
- */
1598
1120
  function readCodexThreadNames() {
1599
1121
  const titles = new Map();
1600
1122
  for (const sessionsDir of getAgentSessionDirs('codex', 'sessions')) {
@@ -1604,35 +1126,20 @@ function readCodexThreadNames() {
1604
1126
  raw = fs.readFileSync(indexPath, 'utf-8');
1605
1127
  }
1606
1128
  catch {
1607
- continue; // no index in this home
1129
+ continue;
1608
1130
  }
1609
1131
  for (const [id, name] of parseCodexThreadNameIndex(raw))
1610
1132
  titles.set(id, name);
1611
1133
  }
1612
1134
  return titles;
1613
1135
  }
1614
- /**
1615
- * Stream-parse a single Codex JSONL file to extract session metadata.
1616
- *
1617
- * `resolveAccount` is a lazy thunk (not a resolved string): the JWT decode it
1618
- * performs is deferred until we know this file is a real session worth building
1619
- * metadata for, and only then — never during the file walk / stat phase.
1620
- */
1621
1136
  export async function readCodexMeta(filePath, resolveAccount, currentVersion, scanStamp, priorRow) {
1622
- // Resume from the persisted continuation when the file merely grew; otherwise
1623
- // full-parse from byte 0. Both branches share one reducer, so an append yields
1624
- // a row identical to a from-scratch reparse. When no stamp is supplied (a
1625
- // caller outside the live scan path), fall back to a plain full parse with no
1626
- // continuation to persist.
1627
1137
  let scan;
1628
1138
  let newState;
1629
1139
  let newOffset = 0;
1630
1140
  let toolCalls;
1631
1141
  let toolIndexMode = 'replace';
1632
1142
  if (scanStamp) {
1633
- // See readClaudeMeta: a prior continuation from an older content extractor
1634
- // is missing what the current extractor adds, so it must not be resumed
1635
- // from — treat it as absent and force one full reparse.
1636
1143
  const prior = priorRow?.extractorVersion === CONTENT_INDEX_VERSION ? parsePriorCodexState(priorRow) : null;
1637
1144
  const result = await scanCodexSessionResumable(filePath, prior, scanStamp.fileMtimeMs, scanStamp.fileSize, priorRow?.fileMtimeMs);
1638
1145
  if (result.mode === 'incremental')
@@ -1656,8 +1163,6 @@ export async function readCodexMeta(filePath, resolveAccount, currentVersion, sc
1656
1163
  id: sessionId,
1657
1164
  shortId: deriveShortId(sessionId),
1658
1165
  agent: 'codex',
1659
- // Codex `session_meta` only carries the start time; use file mtime when
1660
- // it's newer so long-running sessions register as recently active.
1661
1166
  timestamp: pickLatestCodexTimestamp(scan.timestamp, filePath),
1662
1167
  lastActivity: scan.lastActivity,
1663
1168
  project: cwd ? path.basename(cwd) : undefined,
@@ -1691,21 +1196,12 @@ export async function readCodexMeta(filePath, resolveAccount, currentVersion, sc
1691
1196
  meta,
1692
1197
  content: scan.contentText || '',
1693
1198
  assistantContent: scan.assistantText || '',
1694
- // Persist the continuation so the next scan of this rollout resumes from the
1695
- // offset instead of a full reparse; content_text caches the accumulated user
1696
- // doc for the resume's hydrate. Absent when no stamp was supplied.
1697
1199
  parserState: newState ? JSON.stringify(newState) : undefined,
1698
1200
  contentText: newState?.contentText,
1699
1201
  toolCalls,
1700
1202
  toolIndexMode,
1701
1203
  };
1702
1204
  }
1703
- /**
1704
- * Codex writes `session_meta` (with the start timestamp) on the first line of a
1705
- * rollout and never updates it. For long-running sessions that's stale by
1706
- * hours — `--since 2h` would drop a session still being actively written.
1707
- * Compare against the file's mtime and use whichever is newer.
1708
- */
1709
1205
  function pickLatestCodexTimestamp(metaTimestamp, filePath) {
1710
1206
  const fallback = new Date().toISOString();
1711
1207
  let mtimeIso = null;
@@ -1713,24 +1209,12 @@ function pickLatestCodexTimestamp(metaTimestamp, filePath) {
1713
1209
  mtimeIso = fs.statSync(filePath).mtime.toISOString();
1714
1210
  }
1715
1211
  catch {
1716
- /* file vanished between scan and stat */
1717
1212
  }
1718
1213
  const candidates = [metaTimestamp, mtimeIso].filter((v) => !!v);
1719
1214
  if (candidates.length === 0)
1720
1215
  return fallback;
1721
1216
  return candidates.reduce((best, cur) => (cur > best ? cur : best));
1722
1217
  }
1723
- // ---------------------------------------------------------------------------
1724
- // Antigravity
1725
- //
1726
- // Antigravity stores one SQLite DB per conversation at
1727
- // ~/.gemini/antigravity-cli/conversations/<trajectory-uuid>.db. The filename
1728
- // (minus .db) is the canonical session id. Each DB is stat'd against the ledger;
1729
- // only changed DBs are re-parsed (via parseAntigravity, which shells out to
1730
- // sqlite3). Tool count doubles as the message count; the toolSummary of the
1731
- // first tool call becomes the topic, and any run_command's Cwd fills in cwd.
1732
- // ---------------------------------------------------------------------------
1733
- /** Incrementally re-scan changed Antigravity conversation DBs and upsert into the DB. */
1734
1218
  async function scanAntigravityIncremental(onProgress) {
1735
1219
  const currentVersion = await getCurrentAgentVersion('antigravity');
1736
1220
  const filePaths = [];
@@ -1779,13 +1263,11 @@ async function scanAntigravityIncremental(onProgress) {
1779
1263
  upsertSessionsBatch(entries);
1780
1264
  recordScans(touched);
1781
1265
  }
1782
- /** Parse a single Antigravity conversation DB to extract session metadata. */
1783
1266
  function readAntigravityMeta(filePath, currentVersion) {
1784
1267
  const sessionId = path.basename(filePath).replace(/\.db$/, '');
1785
1268
  if (!sessionId)
1786
1269
  return null;
1787
1270
  const events = parseAntigravity(filePath);
1788
- // cwd: first run_command carries the working directory in its Cwd arg.
1789
1271
  let cwd;
1790
1272
  const contentParts = [];
1791
1273
  for (const e of events) {
@@ -1795,7 +1277,6 @@ function readAntigravityMeta(filePath, currentVersion) {
1795
1277
  contentParts.push(e.content);
1796
1278
  }
1797
1279
  const normalizedCwd = cwd ? normalizeCwd(cwd) : undefined;
1798
- // Topic: the first tool's human summary is a decent one-line label.
1799
1280
  const topic = events.find(e => e.content)?.content;
1800
1281
  const stat = safeStatSync(filePath);
1801
1282
  const meta = {
@@ -1812,73 +1293,15 @@ function readAntigravityMeta(filePath, currentVersion) {
1812
1293
  };
1813
1294
  return { meta, content: contentParts.join('\n'), events };
1814
1295
  }
1815
- // ---------------------------------------------------------------------------
1816
- // OpenCode
1817
- // ---------------------------------------------------------------------------
1818
1296
  const OPENCODE_DB = path.join(HOME, '.local', 'share', 'opencode', 'opencode.db');
1819
1297
  let cachedOpenCodeAccount;
1820
- /**
1821
- * The active OpenCode account: the provider ids with a valid credential in
1822
- * `auth.json`, joined (e.g. `"anthropic+muse-spark"`) — see
1823
- * `resolveOpenCodeAccountId` in `../agents.js`, the single source of truth
1824
- * `agents view`/`agents doctor` also read.
1825
- *
1826
- * OpenCode's `opencode.db` also carries `account`/`account_state`/
1827
- * `control_account` tables that look like the obvious source, but on a real,
1828
- * actively-used install (yosemite-s1, 1.16.0, 35 applied migrations) all
1829
- * three are permanently empty — no migration populates them and no session
1830
- * has ever written a row. Querying them (the pre-fix behavior here) always
1831
- * returned undefined, credential or not; `auth.json` is what OpenCode
1832
- * actually reads at runtime.
1833
- */
1834
1298
  function getOpenCodeAccount() {
1835
1299
  if (cachedOpenCodeAccount !== undefined)
1836
1300
  return cachedOpenCodeAccount || undefined;
1837
1301
  cachedOpenCodeAccount = resolveOpenCodeAccountId(HOME) ?? '';
1838
1302
  return cachedOpenCodeAccount || undefined;
1839
1303
  }
1840
- /**
1841
- * The per-session ledger stamp for an OpenCode row: the newest write time across
1842
- * the session's own row, its messages, and its parts, paired with the total byte
1843
- * length of that session's message + part payloads.
1844
- *
1845
- * OpenCode keeps every session in ONE shared SQLite file, so that file's
1846
- * mtime/size changes whenever *any* session is written. Stamping each session
1847
- * with the whole-DB stat therefore invalidated every indexed session on every
1848
- * scan: up to `LIMIT 1000` sessions were re-emitted into `upsertSessionsBatch`,
1849
- * and its enrichment step re-opened `opencode.db` once per re-emitted entry via
1850
- * `parseSession` (RUSH-2210).
1851
- *
1852
- * `s.time_updated` alone is NOT that session's change signal, which is the trap
1853
- * this shape exists to avoid. On a real database, parts land long after the
1854
- * session row was last touched — e.g. `ses_3955202dfffe…` carried
1855
- * `time_updated = 1771316403087` with its newest part at `1771331512162`, over
1856
- * four hours later. So the stamp maxes `time_updated` with the newest message
1857
- * and part times, and pairs it with a byte total that also moves when an
1858
- * existing part's `data` is rewritten in place (a streaming turn) without any
1859
- * new row or timestamp.
1860
- *
1861
- * The byte total is a REAL size, not a repurposed counter, because
1862
- * `sessions.file_size` is read back as bytes elsewhere: `ensureToolIndex` uses
1863
- * it as the tool-backfill byte budget and `toolCallsForBackfill` as the 16 MiB
1864
- * in-memory parser cap (`tool-index.ts`). A message/part byte total is the
1865
- * honest cost of parsing that session — strictly better than the whole-DB size
1866
- * this column used to hold for every OpenCode row.
1867
- *
1868
- * The size is `LENGTH(CAST(data AS BLOB))`, not `LENGTH(data)`: SQLite's
1869
- * `LENGTH()` on a TEXT column counts CHARACTERS, so a CJK/emoji-heavy transcript
1870
- * would under-report its real size by up to 4x — and this number is a byte
1871
- * budget downstream.
1872
- *
1873
- * A degenerate row — nothing but zeros/NaN for every time AND no payload at all
1874
- * — falls back to the whole-DB stat, keeping the pre-RUSH-2210 always-rescan
1875
- * behavior for exactly those rows rather than pinning them to a stamp that never
1876
- * changes.
1877
- */
1878
1304
  function openCodeSessionStamp(times, bytes, dbScan) {
1879
- // A positive time, not merely a finite one: the SQL COALESCEs the aggregates
1880
- // to 0, so `Number.isFinite` alone would accept a row that told us nothing and
1881
- // this branch could never fire.
1882
1305
  const known = [times.timeUpdated, times.lastMessageAt, times.lastPartAt, times.timeCreated]
1883
1306
  .filter(t => Number.isFinite(t) && t > 0);
1884
1307
  const size = (Number.isFinite(bytes.messageBytes) ? bytes.messageBytes : 0)
@@ -1887,24 +1310,18 @@ function openCodeSessionStamp(times, bytes, dbScan) {
1887
1310
  return dbScan;
1888
1311
  return { fileMtimeMs: known.length === 0 ? 0 : Math.floor(Math.max(...known)), fileSize: size };
1889
1312
  }
1890
- /** Scan OpenCode sessions from its SQLite database when the DB file has changed. */
1891
1313
  async function scanOpenCodeIncremental(onProgress) {
1892
1314
  if (!fs.existsSync(OPENCODE_DB))
1893
1315
  return;
1894
1316
  const stat = safeStatSync(OPENCODE_DB);
1895
1317
  if (!stat)
1896
1318
  return;
1897
- // OpenCode is one big DB. Its mtime/size is the cheap "did ANYTHING change"
1898
- // short-circuit for the whole harness — not the per-session stamp, which each
1899
- // row carries itself (see openCodeSessionStamp, RUSH-2210).
1900
1319
  const currentScan = {
1901
1320
  fileMtimeMs: Math.floor(stat.mtimeMs),
1902
1321
  fileSize: stat.size,
1903
1322
  };
1904
1323
  const prev = getScanStampByPath(OPENCODE_DB);
1905
1324
  const extractorUpgrade = prev != null && prev.extractorVersion !== CONTENT_INDEX_VERSION;
1906
- // OpenCode has a shared database rather than one transcript file per session,
1907
- // so this container-level gate must honor extractor-version invalidation too.
1908
1325
  if (prev &&
1909
1326
  prev.fileMtimeMs === currentScan.fileMtimeMs &&
1910
1327
  prev.fileSize === currentScan.fileSize &&
@@ -1912,24 +1329,13 @@ async function scanOpenCodeIncremental(onProgress) {
1912
1329
  return;
1913
1330
  }
1914
1331
  const currentVersion = await getCurrentAgentVersion('opencode');
1915
- // Read through the node/bun SQLite wrapper (not the `sqlite3` CLI) so this
1916
- // works on every OS — the CLI is absent on Windows.
1917
1332
  let db;
1918
1333
  try {
1919
1334
  db = new Database(OPENCODE_DB);
1920
- // OpenCode's `session` schema varies by version: `cost` and `model` are newer
1921
- // columns. Probe once and select NULL where absent, so an older opencode.db
1922
- // still scans instead of throwing "no such column" and dropping every session.
1923
1335
  const sessionCols = new Set(db.prepare('PRAGMA table_info(session);').all()
1924
1336
  .map(c => (typeof c.name === 'string' ? c.name : '')));
1925
1337
  const costExpr = sessionCols.has('cost') ? 's.cost' : 'NULL';
1926
1338
  const modelExpr = sessionCols.has('model') ? 's.model' : 'NULL';
1927
- // Every `json_extract` / `json_type` below is guarded by `json_valid`.
1928
- // SQLite raises "malformed JSON" on a non-JSON value, and that aborts the
1929
- // WHOLE query — so a single unparseable `part`/`message` row anywhere in the
1930
- // shared DB would drop EVERY OpenCode session from the index, silently in a
1931
- // non-TTY run (the handler below only prints when stderr is a TTY). A
1932
- // poisoned row must cost that row, not the harness.
1933
1339
  const query = `
1934
1340
  SELECT
1935
1341
  s.id AS id,
@@ -1989,10 +1395,6 @@ async function scanOpenCodeIncremental(onProgress) {
1989
1395
  `.replace(/\n/g, ' ');
1990
1396
  const account = getOpenCodeAccount();
1991
1397
  const rows = db.prepare(query).all();
1992
- // Two passes. First derive each row's identity + per-session stamp, then
1993
- // bulk-load the prior stamps in ONE query and keep only the rows that
1994
- // actually changed. Skipped rows never reach upsertSessionsBatch, so they
1995
- // never pay its per-entry `parseSession` re-open of this same DB.
1996
1398
  const asInt = (v) => typeof v === 'number' ? v : parseInt(String(v), 10);
1997
1399
  const candidates = rows.flatMap(row => {
1998
1400
  const id = typeof row.id === 'string' ? row.id : '';
@@ -2019,8 +1421,6 @@ async function scanOpenCodeIncremental(onProgress) {
2019
1421
  || prevStamp.fileSize !== c.scan.fileSize
2020
1422
  || prevStamp.extractorVersion !== CONTENT_INDEX_VERSION;
2021
1423
  });
2022
- // Role lives on the message row and the genuine user text lives on its
2023
- // ordered text parts. Poisoned JSON is ignored per row, never per database.
2024
1424
  const firstUserStmt = db.prepare(`
2025
1425
  SELECT json_extract(p.data, '$.text') AS text
2026
1426
  FROM part p
@@ -2054,18 +1454,11 @@ async function scanOpenCodeIncremental(onProgress) {
2054
1454
  const hasTokenData = asInt(row.has_token_data) === 1;
2055
1455
  const toolCallCount = asInt(row.tool_call_count);
2056
1456
  const timestamp = isNaN(timeCreated) ? new Date().toISOString() : new Date(timeCreated).toISOString();
2057
- // OpenCode is one shared DB, not one file per session — its row carries a
2058
- // per-session updated time. Set lastActivity explicitly (falling back to
2059
- // creation, never the whole-DB mtime the ScanStamp would otherwise supply).
2060
1457
  const lastActivity = Number.isNaN(timeUpdated) ? timestamp : new Date(timeUpdated).toISOString();
2061
1458
  const topic = title || undefined;
2062
- // Duration is the session-row span; a missing/degenerate pair yields no value
2063
- // rather than a negative or NaN.
2064
1459
  const durationMs = Number.isFinite(timeCreated) && Number.isFinite(timeUpdated) && timeUpdated > timeCreated
2065
1460
  ? timeUpdated - timeCreated
2066
1461
  : undefined;
2067
- // OpenCode stores the model as JSON (`{"id":"…","providerID":"…"}`); the
2068
- // index tracks the model id.
2069
1462
  let model;
2070
1463
  if (typeof row.model === 'string' && row.model.trim()) {
2071
1464
  try {
@@ -2073,13 +1466,9 @@ async function scanOpenCodeIncremental(onProgress) {
2073
1466
  if (typeof parsed?.id === 'string' && parsed.id.trim())
2074
1467
  model = parsed.id;
2075
1468
  }
2076
- catch { /* non-JSON model string — leave unset */ }
1469
+ catch { }
2077
1470
  }
2078
- // `cost` is a REAL rollup OpenCode maintains on the session row (0 for a
2079
- // zero-priced provider, which is a real value, not "unknown").
2080
1471
  const costUsd = typeof row.cost === 'number' ? row.cost : undefined;
2081
- // Worktree slug is a pure function of cwd (`.agents/worktrees/<slug>/`),
2082
- // so it derives for OpenCode exactly as it does for every other harness.
2083
1472
  const cwd = directory ? normalizeCwd(directory) : undefined;
2084
1473
  const worktreeSlug = detectWorktree(cwd)?.slug;
2085
1474
  const meta = {
@@ -2110,13 +1499,7 @@ async function scanOpenCodeIncremental(onProgress) {
2110
1499
  entries.push({ meta, content: topic || '', scan });
2111
1500
  }
2112
1501
  upsertSessionsBatch(entries);
2113
- // Report what this scan indexed. OpenCode is one SQLite DB rather than N
2114
- // transcript files, so the whole batch lands as a single progress emit —
2115
- // enough for the daemon's warm tick to count it (RUSH-2691); without it a
2116
- // tick whose only changed sessions were OpenCode's reported 0 and logged
2117
- // nothing, the same silent-success class this tick exists to remove.
2118
1502
  onProgress?.({ agent: 'opencode', parsed: entries.length, total: entries.length });
2119
- // Stamp the OpenCode DB itself so we can short-circuit on the next run.
2120
1503
  recordScans([{ filePath: OPENCODE_DB, scan: currentScan }]);
2121
1504
  }
2122
1505
  catch (err) {
@@ -2128,22 +1511,12 @@ async function scanOpenCodeIncremental(onProgress) {
2128
1511
  try {
2129
1512
  db?.close();
2130
1513
  }
2131
- catch { /* best-effort close */ }
1514
+ catch { }
2132
1515
  }
2133
1516
  }
2134
- // ---------------------------------------------------------------------------
2135
- // OpenClaw
2136
- // ---------------------------------------------------------------------------
2137
- /** Scan active OpenClaw channels and cron jobs via the openclaw CLI. */
2138
1517
  async function scanOpenClawIncremental(onProgress) {
2139
- // Check if openclaw is installed — silently skip if not. `which` is POSIX-only
2140
- // (Windows resolves PATH with `where`), so a bare `which` throws ENOENT on every
2141
- // Windows run and silently disabled the entire OpenClaw scan there — its sessions
2142
- // never reached the index (RUSH-2286). hasCommand() probes cross-platform.
2143
1518
  if (!hasCommand('openclaw'))
2144
1519
  return;
2145
- // TTL cache: skip subprocess calls if we scanned recently. Stored in the
2146
- // meta table so we skip even when no channels/cron exist to produce rows.
2147
1520
  const db = getDB();
2148
1521
  const row = db.prepare(`SELECT value FROM meta WHERE key = 'openclaw_last_scan_ms'`).get();
2149
1522
  const lastScanMs = row ? parseInt(row.value, 10) : 0;
@@ -2155,9 +1528,6 @@ async function scanOpenClawIncremental(onProgress) {
2155
1528
  const scan = { fileMtimeMs: now, fileSize: 0 };
2156
1529
  const entries = [];
2157
1530
  try {
2158
- // On Windows `openclaw` resolves to a .cmd/.ps1 shim that execFile can't launch
2159
- // directly; execFileShellSpec composes a shell-safe invocation there and is a
2160
- // no-op passthrough on POSIX (RUSH-2286).
2161
1531
  const channelsSpec = execFileShellSpec('openclaw', ['channels', 'status']);
2162
1532
  const { stdout: output } = await execFileAsync(channelsSpec.command, channelsSpec.args, {
2163
1533
  encoding: 'utf-8',
@@ -2187,7 +1557,6 @@ async function scanOpenClawIncremental(onProgress) {
2187
1557
  }
2188
1558
  }
2189
1559
  catch {
2190
- /* channels command failed */
2191
1560
  }
2192
1561
  try {
2193
1562
  const cronSpec = execFileShellSpec('openclaw', ['cron', 'list']);
@@ -2225,21 +1594,10 @@ async function scanOpenClawIncremental(onProgress) {
2225
1594
  }
2226
1595
  }
2227
1596
  catch {
2228
- /* cron command failed */
2229
1597
  }
2230
1598
  upsertSessionsBatch(entries);
2231
- // Deliberately NO onProgress emit, unlike every other scanner (RUSH-2691).
2232
- // This one cannot report a delta: its gate is a 60s TTL (not a store stamp),
2233
- // `scan` above stamps a fresh `now` on every entry every run, and `entries` is
2234
- // the CURRENT INVENTORY — running channels plus cron jobs — rebuilt from
2235
- // scratch each pass. Emitting entries.length would report "how many openclaw
2236
- // things exist", re-counted every 60s forever, which is a worse lie than
2237
- // silence: the warm tick's number means "transcripts parsed this scan". Giving
2238
- // OpenClaw a real per-entry stamp is tracked separately; until then it
2239
- // contributes 0 and the docblock on IncrementalScanResult says so.
2240
1599
  db.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES ('openclaw_last_scan_ms', ?)`).run(String(Date.now()));
2241
1600
  }
2242
- /** Incrementally re-scan changed Rush session files and upsert into the DB. */
2243
1601
  async function scanRushIncremental(onProgress) {
2244
1602
  if (!fs.existsSync(RUSH_SESSIONS_DIR))
2245
1603
  return;
@@ -2288,7 +1646,6 @@ async function scanRushIncremental(onProgress) {
2288
1646
  upsertSessionsBatch(entries);
2289
1647
  recordScans(touched);
2290
1648
  }
2291
- /** Stream-parse a single Rush messages.jsonl file to extract session metadata. */
2292
1649
  async function readRushMeta(filePath, sessionId) {
2293
1650
  const scan = await scanRushSession(filePath);
2294
1651
  const stat = safeStatSync(filePath);
@@ -2308,7 +1665,6 @@ async function readRushMeta(filePath, sessionId) {
2308
1665
  };
2309
1666
  return { meta, content: scan.contentText || '', assistantContent: scan.assistantText || '' };
2310
1667
  }
2311
- /** Stream a Rush messages.jsonl file and extract scan-level metadata. */
2312
1668
  async function scanRushSession(filePath) {
2313
1669
  const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
2314
1670
  const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
@@ -2376,17 +1732,6 @@ async function scanRushSession(filePath) {
2376
1732
  assistantText: assistantTexts.length > 0 ? assistantTexts.join('\n') : undefined,
2377
1733
  };
2378
1734
  }
2379
- // ---------------------------------------------------------------------------
2380
- // Hermes
2381
- //
2382
- // Hermes sessions live at ~/.hermes/sessions/session_<id>.json (one JSON
2383
- // file per session). Shape:
2384
- // { session_id, model, platform, session_start, last_updated,
2385
- // system_prompt, message_count, messages: [{role, content}, ...] }
2386
- // request_dump_*.json files in the same dir are per-turn debug dumps — skip.
2387
- // Hermes is a gateway/API agent, so cwd is left unset.
2388
- // ---------------------------------------------------------------------------
2389
- /** Incrementally re-scan changed Hermes session files and upsert into the DB. */
2390
1735
  async function scanHermesIncremental(onProgress) {
2391
1736
  if (!fs.existsSync(HERMES_SESSIONS_DIR))
2392
1737
  return;
@@ -2431,7 +1776,6 @@ async function scanHermesIncremental(onProgress) {
2431
1776
  upsertSessionsBatch(scanEntries);
2432
1777
  recordScans(touched);
2433
1778
  }
2434
- /** Parse a single Hermes session JSON file to extract session metadata. */
2435
1779
  function readHermesMeta(filePath) {
2436
1780
  let session;
2437
1781
  try {
@@ -2489,14 +1833,6 @@ function readHermesMeta(filePath) {
2489
1833
  };
2490
1834
  return { meta, content: userTexts.join('\n'), assistantContent: assistantTexts.join('\n') };
2491
1835
  }
2492
- /**
2493
- * Muse Code stores one session per directory under
2494
- * ~/.local/share/muse/sessions/YYYY/MM/DD/<uuid>/session.jsonl (event-sourced
2495
- * JSONL). Walk the tree for session.jsonl files and index each one.
2496
- *
2497
- * Also scan version homes (`versions/muse/<v>/home/.local/share/muse/sessions`)
2498
- * so managed/isolated runs that rewrite HOME still show up in `agents sessions`.
2499
- */
2500
1836
  function scanMuseIncremental(onProgress) {
2501
1837
  const roots = [];
2502
1838
  if (fs.existsSync(MUSE_SESSIONS_DIR))
@@ -2513,7 +1849,6 @@ function scanMuseIncremental(onProgress) {
2513
1849
  }
2514
1850
  }
2515
1851
  catch {
2516
- /* unreadable */
2517
1852
  }
2518
1853
  }
2519
1854
  if (roots.length === 0)
@@ -2530,7 +1865,6 @@ function scanMuseIncremental(onProgress) {
2530
1865
  for (const ent of entries) {
2531
1866
  const full = path.join(dir, ent.name);
2532
1867
  if (ent.isDirectory()) {
2533
- // Skip subagent child sessions — nested under subagent/<id>/
2534
1868
  if (ent.name === 'subagent')
2535
1869
  continue;
2536
1870
  walk(full);
@@ -2571,9 +1905,7 @@ function scanMuseIncremental(onProgress) {
2571
1905
  recordScans(touched);
2572
1906
  return Promise.resolve();
2573
1907
  }
2574
- /** Parse a Muse session.jsonl for session metadata + first user prompt text. */
2575
1908
  function readMuseMeta(filePath) {
2576
- // Path shape: .../sessions/YYYY/MM/DD/<uuid>/session.jsonl
2577
1909
  const sessionId = path.basename(path.dirname(filePath));
2578
1910
  if (!/^[0-9a-f-]{36}$/i.test(sessionId))
2579
1911
  return null;
@@ -2605,7 +1937,6 @@ function readMuseMeta(filePath) {
2605
1937
  }
2606
1938
  if (typeof raw.recorded_at === 'number') {
2607
1939
  const v = raw.recorded_at;
2608
- // Muse logs use microseconds; values < 1e14 are treated as milliseconds.
2609
1940
  const ms = v > 1e14 ? Math.floor(v / 1000) : v;
2610
1941
  const ts = new Date(ms).toISOString();
2611
1942
  if (!firstTs)
@@ -2662,7 +1993,6 @@ function readMuseMeta(filePath) {
2662
1993
  };
2663
1994
  return { meta, content: userTexts.join('\n'), assistantContent: assistantTexts.join('\n') };
2664
1995
  }
2665
- /** Extract plain text from a Hermes message content field (string or list of parts). */
2666
1996
  function extractHermesMessageText(content) {
2667
1997
  if (typeof content === 'string')
2668
1998
  return content.trim();
@@ -2679,18 +2009,10 @@ function extractHermesMessageText(content) {
2679
2009
  .join('\n')
2680
2010
  .trim();
2681
2011
  }
2682
- /**
2683
- * Incrementally re-scan changed Droid (Factory) session files and upsert into
2684
- * the DB. Droid writes one `<uuid>.jsonl` transcript plus a sibling
2685
- * `<uuid>.settings.json` (model + token usage) under
2686
- * `~/.factory/sessions/<encoded-cwd>/`.
2687
- */
2688
2012
  async function scanDroidIncremental(onProgress) {
2689
2013
  const currentVersion = await getCurrentAgentVersion('droid');
2690
2014
  const prestat = [];
2691
2015
  for (const sessionsDir of getAgentSessionDirs('droid', 'sessions')) {
2692
- // High limit: the walk stats each file once here; parsing is gated by the
2693
- // ledger match below, which reuses that stat instead of re-stat'ing.
2694
2016
  for (const f of walkForFilesWithStat(sessionsDir, '.jsonl', 100_000)) {
2695
2017
  prestat.push({ filePath: f.path, fileMtimeMs: f.mtimeMs, fileSize: f.size });
2696
2018
  }
@@ -2723,19 +2045,14 @@ async function scanDroidIncremental(onProgress) {
2723
2045
  upsertSessionsBatch(entries);
2724
2046
  recordScans(touched);
2725
2047
  }
2726
- /** Stream-parse a single Droid JSONL file (+ sibling settings) into session metadata. */
2727
2048
  async function readDroidMeta(filePath, currentVersion) {
2728
2049
  const scan = await scanDroidSession(filePath);
2729
- // The filename is the canonical session id; fall back to the session_start id.
2730
2050
  const sessionId = path.basename(filePath).replace(/\.jsonl$/, '') || scan.sessionId || '';
2731
2051
  if (!sessionId)
2732
2052
  return null;
2733
- // Token usage and cost live only in the sibling `<uuid>.settings.json`.
2734
2053
  const settings = readDroidSettings(filePath.replace(/\.jsonl$/, '.settings.json'));
2735
2054
  const model = settings.model || scan.model;
2736
2055
  const tokenCount = settings.tokenCount;
2737
- // Droid records a full split (input / cache-read / cache-write / output) in its
2738
- // settings sidecar, so both the actual and no-cache cost are derivable (RUSH-2287).
2739
2056
  const usageForCost = model && settings.usage
2740
2057
  ? {
2741
2058
  model,
@@ -2774,7 +2091,6 @@ async function readDroidMeta(filePath, currentVersion) {
2774
2091
  };
2775
2092
  return { meta, content: scan.contentText || '', assistantContent: scan.assistantText || '' };
2776
2093
  }
2777
- /** Read model + token usage from a Droid `<uuid>.settings.json` sidecar. */
2778
2094
  function readDroidSettings(settingsPath) {
2779
2095
  try {
2780
2096
  const data = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
@@ -2800,7 +2116,6 @@ function readDroidSettings(settingsPath) {
2800
2116
  return {};
2801
2117
  }
2802
2118
  }
2803
- /** Stream a Droid JSONL file and extract scan-level metadata (id, cwd, topic, model, duration). */
2804
2119
  async function scanDroidSession(filePath) {
2805
2120
  const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
2806
2121
  const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
@@ -2831,7 +2146,6 @@ async function scanDroidSession(filePath) {
2831
2146
  if (parsed.type === 'session_start') {
2832
2147
  sessionId = typeof parsed.id === 'string' ? parsed.id : sessionId;
2833
2148
  cwd = typeof parsed.cwd === 'string' ? parsed.cwd : cwd;
2834
- // Droid auto-generates `sessionTitle`; `title` is the raw first prompt.
2835
2149
  if (typeof parsed.sessionTitle === 'string' && parsed.sessionTitle.trim()) {
2836
2150
  sessionTitle = parsed.sessionTitle.trim();
2837
2151
  }
@@ -2842,7 +2156,6 @@ async function scanDroidSession(filePath) {
2842
2156
  }
2843
2157
  if (parsed.type !== 'message')
2844
2158
  continue;
2845
- // Track duration across every timestamped message.
2846
2159
  if (typeof parsed.timestamp === 'string') {
2847
2160
  const ms = new Date(parsed.timestamp).getTime();
2848
2161
  if (!Number.isNaN(ms)) {
@@ -2884,8 +2197,6 @@ async function scanDroidSession(filePath) {
2884
2197
  sessionId,
2885
2198
  timestamp,
2886
2199
  cwd,
2887
- // Prefer Droid's auto-title, then the raw first-prompt title, then the
2888
- // derived first-user-message topic.
2889
2200
  topic: sessionTitle || title || firstUserTopic,
2890
2201
  firstUserMessage,
2891
2202
  model,
@@ -2896,7 +2207,6 @@ async function scanDroidSession(filePath) {
2896
2207
  assistantText: assistantTexts.length > 0 ? assistantTexts.join('\n') : undefined,
2897
2208
  };
2898
2209
  }
2899
- /** Extract plain text from a Droid message content field (Anthropic-shaped blocks). */
2900
2210
  function extractDroidMessageText(content) {
2901
2211
  if (typeof content === 'string')
2902
2212
  return content.trim();
@@ -2904,13 +2214,10 @@ function extractDroidMessageText(content) {
2904
2214
  return '';
2905
2215
  return content
2906
2216
  .map((part) => (typeof part?.text === 'string' && part.type === 'text' ? part.text : ''))
2907
- // Droid front-loads injected context (date, skills list) as <system-reminder>
2908
- // text blocks on the first user turn — drop them so topic/content stay clean.
2909
2217
  .filter((text) => text.trim() && !text.trim().startsWith('<system-reminder>'))
2910
2218
  .join('\n')
2911
2219
  .trim();
2912
2220
  }
2913
- /** Zero-value accumulator for a fresh (from-byte-0) Claude parse. */
2914
2221
  export function initClaudeParseState() {
2915
2222
  return {
2916
2223
  subAgents: 0,
@@ -2960,13 +2267,8 @@ const DIRECTORY_TOOLS = new Set(['Edit', 'Write', 'edit_file', 'write_file', 'cr
2960
2267
  function foldDerivedToolState(state, event) {
2961
2268
  if (CHECKLIST_TOOLS.has(event.tool ?? ''))
2962
2269
  state.checklistEvents.push(event);
2963
- // #12: skill/slash-command usage, held here instead of re-parsed later — the
2964
- // same reason checklistEvents is folded incrementally rather than recomputed
2965
- // from a full re-parse (see session/db.ts's writeResourceUsage doc comment).
2966
2270
  if (isSkillInvocation(event))
2967
2271
  state.skillEvents.push(event);
2968
- // Fan-out tallies (RUSH-3091/3095): counted, not held — we need the number,
2969
- // and a heavy orchestrator session can spawn hundreds of each.
2970
2272
  if (state.subAgents !== undefined && isSubAgentTool(event.tool ?? '', event.command ?? '')) {
2971
2273
  state.subAgents += 1;
2972
2274
  }
@@ -2990,23 +2292,11 @@ function foldDerivedToolState(state, event) {
2990
2292
  if (state.recentDirectoriesTouched.length > 10)
2991
2293
  state.recentDirectoriesTouched.splice(0, state.recentDirectoriesTouched.length - 10);
2992
2294
  }
2993
- /**
2994
- * Fold one parsed transcript line into the accumulator. This is the exact loop
2995
- * body {@link scanClaudeSession} used to run inline — extracted verbatim,
2996
- * mutating `state.*` in place. `parsed` is the already-`JSON.parse`d line (the
2997
- * malformed-line skip happens in the caller, as before).
2998
- */
2999
2295
  export function applyClaudeLine(state, parsed) {
3000
2296
  collectClaudeToolCalls(state.toolCollector, parsed);
3001
- // entrypoint ships on the first envelope event (attachment/user/assistant)
3002
- // and is the clean structural signal for "was this a team spawn?"
3003
2297
  if (!state.entrypoint && typeof parsed.entrypoint === 'string') {
3004
2298
  state.entrypoint = parsed.entrypoint;
3005
2299
  }
3006
- // Produced-artifact signals, structurally (independent of the PR gate below):
3007
- // - a Bash `agents teams create/add` command → the team it spawned
3008
- // - a Linear create_issue / `gh issue create` tool_use → its result carries
3009
- // the new ticket ref, read from the matching tool_result.
3010
2300
  if (parsed.type === 'assistant' && Array.isArray(parsed.message?.content)) {
3011
2301
  for (const b of parsed.message.content) {
3012
2302
  if (b?.type !== 'tool_use')
@@ -3020,8 +2310,6 @@ export function applyClaudeLine(state, parsed) {
3020
2310
  if (typeof b?.id === 'string' && isTicketCreateTool(b?.name, b?.input?.command)) {
3021
2311
  state.pendingTicketTools.add(b.id);
3022
2312
  }
3023
- // ExitPlanMode plan markdown — last one wins so a re-planned session
3024
- // reports its most recent plan.
3025
2313
  if (b?.name === 'ExitPlanMode' && typeof b?.input?.plan === 'string') {
3026
2314
  const p = b.input.plan.trim();
3027
2315
  if (p)
@@ -3048,8 +2336,6 @@ export function applyClaudeLine(state, parsed) {
3048
2336
  state.createdTickets.add(t);
3049
2337
  }
3050
2338
  }
3051
- // PR signal, structurally: a Bash tool_use whose command is `gh pr create`
3052
- // marks intent; the pull URL is then read from a tool_result's output.
3053
2339
  if (!state.prUrl) {
3054
2340
  if (!state.sawPrCreate && parsed.type === 'assistant' && Array.isArray(parsed.message?.content)) {
3055
2341
  for (const b of parsed.message.content) {
@@ -3073,7 +2359,6 @@ export function applyClaudeLine(state, parsed) {
3073
2359
  }
3074
2360
  }
3075
2361
  }
3076
- // Track duration across every timestamped event, not just the first.
3077
2362
  if (typeof parsed.timestamp === 'string') {
3078
2363
  const ms = new Date(parsed.timestamp).getTime();
3079
2364
  if (!Number.isNaN(ms)) {
@@ -3110,9 +2395,6 @@ export function applyClaudeLine(state, parsed) {
3110
2395
  state.userTexts.push(text);
3111
2396
  if (!state.topic)
3112
2397
  state.topic = extractSessionTopic(text);
3113
- // #12: the USER typing a slash command — Claude injects a <command-name>
3114
- // wrapper as the message content (extractClaudeUserText returns it
3115
- // un-stripped; isLocalCommandMessage only filters bash-echo wrappers).
3116
2398
  const slashCommand = extractSlashCommandName(text);
3117
2399
  if (slashCommand) {
3118
2400
  state.slashCommandEvents.push({
@@ -3145,8 +2427,6 @@ export function applyClaudeLine(state, parsed) {
3145
2427
  }
3146
2428
  if (typeof usageObj?.output_tokens === 'number')
3147
2429
  state.outputTokens += usageObj.output_tokens;
3148
- // Burn split (RUSH-2287): accumulate the raw directional counts so `agents
3149
- // output` can report uncached-input / cache-read / cache-write separately.
3150
2430
  if (usageObj && typeof usageObj === 'object') {
3151
2431
  if (typeof usageObj.input_tokens === 'number')
3152
2432
  state.inputTokens += usageObj.input_tokens;
@@ -3155,8 +2435,6 @@ export function applyClaudeLine(state, parsed) {
3155
2435
  if (typeof usageObj.cache_creation_input_tokens === 'number')
3156
2436
  state.cacheWriteTokens += usageObj.cache_creation_input_tokens;
3157
2437
  }
3158
- // Per-assistant-message cost: each event carries its own model, so we
3159
- // multiply that event's raw token directions by that model's price.
3160
2438
  const model = parsed.message?.model;
3161
2439
  if (typeof model === 'string' && model)
3162
2440
  state.model = model;
@@ -3171,26 +2449,15 @@ export function applyClaudeLine(state, parsed) {
3171
2449
  const eventCost = costOfUsage(usageForCost);
3172
2450
  if (eventCost > 0) {
3173
2451
  state.costUsd += eventCost;
3174
- // No-cache scenario: reprice this same event's cache tokens at the input rate.
3175
2452
  state.costUsdNoCache += costOfUsageNoCache(usageForCost);
3176
2453
  state.sawCost = true;
3177
2454
  }
3178
2455
  }
3179
2456
  }
3180
- /**
3181
- * Build the {@link ClaudeSessionScan} return object from an accumulator. This is
3182
- * the exact return-building {@link scanClaudeSession} used to run inline.
3183
- */
3184
- export function finalizeClaudeScan(state) {
2457
+ export function finalizeClaudeScan(state, sessionFile) {
3185
2458
  const durationMs = state.firstTsMs !== undefined && state.lastTsMs !== undefined && state.lastTsMs > state.firstTsMs
3186
2459
  ? state.lastTsMs - state.firstTsMs
3187
2460
  : undefined;
3188
- // A topic is the first meaningful prompt. Harness-owned names travel in the
3189
- // separate label field so consumers can replace an early topic once Claude's
3190
- // generated title (or a later `/rename`) arrives.
3191
- // Generated titles (Claude `ai-title`, Cursor `chatMeta.title`) go through
3192
- // one shared cleaner so a skill-preamble echo collapses to `/<skill>`. A
3193
- // `/rename` (`custom-title`) is the user's own words and is never rewritten.
3194
2461
  const label = state.customTitle || cleanGeneratedSessionLabel(state.aiTitle);
3195
2462
  const worktree = detectWorktree(state.cwd, state.gitBranch);
3196
2463
  const ticket = detectTicket(state.userTexts.join('\n') || undefined, state.gitBranch);
@@ -3228,11 +2495,10 @@ export function finalizeClaudeScan(state) {
3228
2495
  recentDirectoriesTouched: state.recentDirectoriesTouched.length ? state.recentDirectoriesTouched : undefined,
3229
2496
  skillsUsed: state.skillEvents.length ? extractSkills(state.skillEvents) : undefined,
3230
2497
  slashCommandsUsed: state.slashCommandEvents.length ? extractSlashCommands(state.slashCommandEvents) : undefined,
3231
- subAgentCount: state.subAgents,
2498
+ subAgentCount: resolvedSubAgentCount(sessionFile ? claudeSubagentFiles(sessionFile) : undefined, state.subAgents),
3232
2499
  backgroundShellCount: state.backgroundShells,
3233
2500
  };
3234
2501
  }
3235
- /** Stream a Claude JSONL file and extract scan-level metadata (timestamp, cwd, topic, tokens). */
3236
2502
  export async function scanClaudeSession(filePath) {
3237
2503
  const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
3238
2504
  const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
@@ -3255,15 +2521,9 @@ export async function scanClaudeSession(filePath) {
3255
2521
  rl.close();
3256
2522
  stream.destroy();
3257
2523
  }
3258
- return finalizeClaudeScan(state);
2524
+ return finalizeClaudeScan(state, filePath);
3259
2525
  }
3260
- /** Cap on the FIFO window of recent assistant ids persisted in the continuation. */
3261
2526
  const SEEN_IDS_RECENT_CAP = 256;
3262
- /**
3263
- * Snapshot a live {@link ClaudeParseState} into its serializable form at
3264
- * `offset` bytes consumed. Round-trips through {@link hydrateClaudeParseState}
3265
- * so incremental replay equals a full parse.
3266
- */
3267
2527
  export function serializeClaudeParserState(state, offset, jsonlDroppingOversizedLine = false) {
3268
2528
  const allIds = [...state.seenAssistantIds];
3269
2529
  const seenIdsRecent = allIds.length > SEEN_IDS_RECENT_CAP
@@ -3308,10 +2568,6 @@ export function serializeClaudeParserState(state, offset, jsonlDroppingOversized
3308
2568
  pendingTicketTools: [...state.pendingTicketTools],
3309
2569
  createdTickets: [...state.createdTickets],
3310
2570
  spawnedTeam: state.spawnedTeam,
3311
- // ticketId is derived at finalize time; persist it (and content_text) so a
3312
- // consumer (B-2) can rebuild the row + FTS doc on append without re-reading
3313
- // the whole file. worktreeSlug is re-derived from cwd/gitBranch, so it need
3314
- // not be persisted.
3315
2571
  ticketId: ticket?.id,
3316
2572
  contentText: state.userTexts.length > 0 ? state.userTexts.join('\n') : undefined,
3317
2573
  assistantContentText: state.assistantTexts.length > 0 ? state.assistantTexts.join('\n') : undefined,
@@ -3322,26 +2578,8 @@ export function serializeClaudeParserState(state, offset, jsonlDroppingOversized
3322
2578
  slashCommandEvents: state.slashCommandEvents,
3323
2579
  };
3324
2580
  }
3325
- /**
3326
- * Rebuild a live {@link ClaudeParseState} from a persisted continuation so that
3327
- * applying the appended lines yields the same accumulator a full parse would.
3328
- *
3329
- * `seenAssistantIds` is rehydrated from the recent-id FIFO window, then padded
3330
- * with unique sentinel entries so its `.size` matches the true prior count
3331
- * (`seenIdsSize`) — the fallback id `${ts}:${size}` must line up with the full
3332
- * parse even when the window dropped older ids. Padding sentinels can never
3333
- * collide with a real logical id (real ids are message ids/uuids or
3334
- * `${ts}:${n}`; the sentinel prefix is not JSON-line-derived).
3335
- *
3336
- * `userTexts` is rehydrated as a single joined blob from `contentText`: only
3337
- * `userTexts.join('\n')` (detectTicket + contentText) and `userTexts.length > 0`
3338
- * are ever read downstream, and both are preserved by a one-element array
3339
- * holding the joined content.
3340
- */
3341
2581
  export function hydrateClaudeParseState(prior) {
3342
2582
  const seen = new Set(prior.seenIdsRecent);
3343
- // Pad to the true prior size so `seenAssistantIds.size` (which feeds the
3344
- // fallback logical id) is exact even when older ids fell out of the window.
3345
2583
  let pad = 0;
3346
2584
  while (seen.size < prior.seenIdsSize) {
3347
2585
  seen.add(`pad:${pad++}`);
@@ -3391,35 +2629,13 @@ export function hydrateClaudeParseState(prior) {
3391
2629
  slashCommandEvents: prior.slashCommandEvents ?? [],
3392
2630
  };
3393
2631
  }
3394
- /**
3395
- * Resume a Claude parse from `fromOffset` bytes into the file, folding only the
3396
- * newly-appended lines into `prior`. Returns the finalized scan, the next
3397
- * serialized continuation, and the byte offset to resume from next time —
3398
- * `newOffset` stops at the last `'\n'` seen so a half-written trailing record is
3399
- * re-read (not lost) on the next append.
3400
- *
3401
- * NOT wired into the live scan path yet (that is B-2); {@link scanClaudeSession}
3402
- * remains the only caller-facing entry point. This exists so the parity harness
3403
- * can prove full === hydrate(state@k) + apply(k+1..n).
3404
- */
3405
2632
  export async function scanClaudeSessionIncremental(filePath, fromOffset, prior) {
3406
2633
  const state = hydrateClaudeParseState(prior);
3407
- // Read the appended byte range and apply ONLY newline-terminated lines. The
3408
- // applied lines and `newOffset` MUST stay consistent: readline (like the full
3409
- // parse) would emit a trailing UNTERMINATED final line at EOF, but `newOffset`
3410
- // stops before it — so the next pass, after that record's '\n' is flushed,
3411
- // would re-read and re-apply the same line and double-count it (user events
3412
- // have no dedup, unlike assistant `seenAssistantIds`). A record written
3413
- // non-atomically — bytes first, then '\n' in a second write — is exactly this
3414
- // case. So we slice at the last '\n' ourselves: everything up to and including
3415
- // it is a run of complete lines we apply and commit. An ordinary tail after
3416
- // it is deferred until its '\n' lands; after a tail exceeds 1 MiB, its offset
3417
- // advances with a persisted discard-until-newline bit.
3418
2634
  const append = await applyJsonlAppend(filePath, fromOffset, prior.jsonlDroppingOversizedLine === true, (parsed) => applyClaudeLine(state, parsed));
3419
2635
  if (append.skippedOversizedLine)
3420
2636
  state.toolCollector.recordIndexLimit();
3421
2637
  const newOffset = fromOffset + append.consumedBytes;
3422
- const scan = finalizeClaudeScan(state);
2638
+ const scan = finalizeClaudeScan(state, filePath);
3423
2639
  const toolCalls = state.toolCollector.drainChanged();
3424
2640
  return {
3425
2641
  scan,
@@ -3428,39 +2644,10 @@ export async function scanClaudeSessionIncremental(filePath, fromOffset, prior)
3428
2644
  toolCalls,
3429
2645
  };
3430
2646
  }
3431
- /** Serialized zero-value continuation: a fresh accumulator at offset 0, used to drive a FULL parse from the start through the same resumable path. */
3432
2647
  function freshClaudeParserState() {
3433
2648
  return serializeClaudeParserState(initClaudeParseState(), 0);
3434
2649
  }
3435
- /**
3436
- * Decide full-vs-incremental for one Claude file and parse it uniformly, always
3437
- * returning a finalized scan plus the continuation to persist. Both branches run
3438
- * through the SAME reducer (via {@link scanClaudeSessionIncremental}), so the row
3439
- * an append produces is identical to a from-scratch full reparse by construction
3440
- * (the B-1 parity harness proves this at the function level).
3441
- *
3442
- * INCREMENTAL when a prior continuation exists AND the file grew past the
3443
- * persisted offset AND its mtime did not go backwards — an in-place append.
3444
- * FULL (from byte 0, fresh state) otherwise: cold start (no prior), truncation /
3445
- * rewrite (size shrank to at or below the offset), or a clock rewind / restore
3446
- * (mtime older than the last parse). A FULL parse still produces a continuation,
3447
- * so the file's very next append can go incremental.
3448
- *
3449
- * `mode` is returned so the caller (and tests) can confirm which branch ran.
3450
- */
3451
2650
  export async function scanClaudeSessionResumable(filePath, prior, currentFileMtimeMs, currentFileSize, priorFileMtimeMs) {
3452
- // File size + mtime cannot distinguish an APPEND from an in-place rewrite or a
3453
- // restore that dropped DIFFERENT, larger content at the same path: both grow
3454
- // the file and move mtime forward. Resuming from the stored offset across that
3455
- // boundary would fold the new file's bytes into an accumulator hydrated from
3456
- // the OLD session, so the persisted row silently diverges from a full reparse.
3457
- // So the metadata gate below only makes a file ELIGIBLE; before trusting the
3458
- // offset we re-read the transcript's first user/assistant timestamp and require
3459
- // it to still match the prior continuation's. An append keeps that identity
3460
- // byte-for-byte; a rewrite/restore of a different session changes it. A
3461
- // mismatch — or an identity we cannot derive — falls back to a FULL parse,
3462
- // which is always correct. (A shrink is already handled: currentFileSize is not
3463
- // > prior.offset, so it takes the FULL branch.)
3464
2651
  let canIncrement = false;
3465
2652
  if (prior !== null &&
3466
2653
  currentFileSize > prior.offset &&
@@ -3475,14 +2662,6 @@ export async function scanClaudeSessionResumable(filePath, prior, currentFileMti
3475
2662
  const result = await scanClaudeSessionIncremental(filePath, 0, freshClaudeParserState());
3476
2663
  return { ...result, mode: 'full' };
3477
2664
  }
3478
- /**
3479
- * Cheaply derive a Claude transcript's session identity — the first
3480
- * user/assistant event `timestamp` — by streaming only the START of the file
3481
- * (at most `maxBytes`) and stopping at the first such event. Used by
3482
- * {@link scanClaudeSessionResumable} to confirm a grown file is still the SAME
3483
- * session before resuming from a stored parse offset. Returns undefined when no
3484
- * user/assistant event appears within the budget, which forces a FULL parse.
3485
- */
3486
2665
  async function claudeSessionIdentityAt(filePath, maxBytes = 1_048_576) {
3487
2666
  const state = initClaudeParseState();
3488
2667
  const stream = fs.createReadStream(filePath, { start: 0, end: maxBytes - 1, encoding: 'utf-8' });
@@ -3509,12 +2688,6 @@ async function claudeSessionIdentityAt(filePath, maxBytes = 1_048_576) {
3509
2688
  }
3510
2689
  return state.timestamp;
3511
2690
  }
3512
- /**
3513
- * Parse the prior continuation blob for a changed file into a usable
3514
- * {@link ClaudeParserState}, or null when there is none / it is unusable. A blob
3515
- * from a different serialization version is treated as absent so the file falls
3516
- * back to a clean FULL parse rather than resuming against a stale shape.
3517
- */
3518
2691
  function parsePriorClaudeState(row) {
3519
2692
  if (!row?.parserState)
3520
2693
  return null;
@@ -3528,20 +2701,15 @@ function parsePriorClaudeState(row) {
3528
2701
  return null;
3529
2702
  }
3530
2703
  }
3531
- /** Test seam: how many times the incremental (append-resume) branch was taken since the last reset. */
3532
2704
  let claudeIncrementalScanCount = 0;
3533
- /** Test seam: how many times a full (from-offset-0) Claude parse ran since the last reset. */
3534
2705
  let claudeFullScanCount = 0;
3535
- /** Test seam: read the (incremental, full) Claude parse counters. */
3536
2706
  export function __claudeScanBranchCountsForTest() {
3537
2707
  return { incremental: claudeIncrementalScanCount, full: claudeFullScanCount };
3538
2708
  }
3539
- /** Test seam: reset the Claude parse-branch counters to observe a scan from a clean slate. */
3540
2709
  export function __resetClaudeScanBranchCountsForTest() {
3541
2710
  claudeIncrementalScanCount = 0;
3542
2711
  claudeFullScanCount = 0;
3543
2712
  }
3544
- /** Zero-value accumulator for a fresh (from-byte-0) Codex parse. */
3545
2713
  export function initCodexParseState() {
3546
2714
  return {
3547
2715
  sessionId: undefined,
@@ -3572,16 +2740,8 @@ export function initCodexParseState() {
3572
2740
  slashCommandEvents: [],
3573
2741
  };
3574
2742
  }
3575
- /**
3576
- * Fold one parsed Codex line into the accumulator — the exact loop body
3577
- * {@link scanCodexSession} used to run inline, extracted verbatim and mutating
3578
- * `state.*` in place. `parsed` is the already-`JSON.parse`d line (the
3579
- * malformed-line skip happens in the caller, as before).
3580
- */
3581
2743
  function applyCodexLine(state, parsed) {
3582
2744
  collectCodexToolCalls(state.toolCollector, parsed);
3583
- // PR signal, structurally: a Codex `function_call` whose command is
3584
- // `gh pr create`, then the pull URL from a `function_call_output`.
3585
2745
  if (parsed.type === 'response_item') {
3586
2746
  const p = parsed.payload || {};
3587
2747
  if (p.type === 'function_call') {
@@ -3591,7 +2751,7 @@ function applyCodexLine(state, parsed) {
3591
2751
  args = typeof p.arguments === 'string' ? JSON.parse(p.arguments) : (p.arguments || {});
3592
2752
  cmd = String(args.command || args.cmd || '');
3593
2753
  }
3594
- catch { /* non-JSON args */ }
2754
+ catch { }
3595
2755
  foldDerivedToolState(state, {
3596
2756
  type: 'tool_use', agent: 'codex', timestamp: parsed.timestamp || '', tool: p.name, args,
3597
2757
  path: args.file_path || args.path, command: cmd || undefined,
@@ -3623,7 +2783,6 @@ function applyCodexLine(state, parsed) {
3623
2783
  }
3624
2784
  }
3625
2785
  }
3626
- // Track duration across every timestamped event.
3627
2786
  if (typeof parsed.timestamp === 'string') {
3628
2787
  const ms = new Date(parsed.timestamp).getTime();
3629
2788
  if (!Number.isNaN(ms)) {
@@ -3635,8 +2794,6 @@ function applyCodexLine(state, parsed) {
3635
2794
  }
3636
2795
  if (parsed.type === 'session_meta') {
3637
2796
  const payload = parsed.payload || {};
3638
- // Native forks prepend child ownership before inherited parent metadata.
3639
- // The first valid identity owns this file in both full and resumed scans.
3640
2797
  if (state.sessionId || typeof payload.id !== 'string' || !payload.id.trim())
3641
2798
  return;
3642
2799
  state.sessionId = payload.id;
@@ -3647,10 +2804,6 @@ function applyCodexLine(state, parsed) {
3647
2804
  state.model = payload.model || state.model;
3648
2805
  return;
3649
2806
  }
3650
- // Codex rollouts put per-turn metadata (including the model) on
3651
- // `turn_context` events. Use them as a fallback when session_meta itself
3652
- // does not carry the field, otherwise `agents sessions` shows blank model
3653
- // info for Codex.
3654
2807
  if (parsed.type === 'turn_context') {
3655
2808
  const payload = parsed.payload || {};
3656
2809
  if (!state.model && typeof payload.model === 'string')
@@ -3673,9 +2826,6 @@ function applyCodexLine(state, parsed) {
3673
2826
  if (!genuine)
3674
2827
  return;
3675
2828
  state.userTexts.push(genuine);
3676
- // Codex records developer instructions as response_item messages too.
3677
- // They remain searchable for compatibility, but only an actual user role
3678
- // may become the session's first request.
3679
2829
  if (payloadRole === 'user' && !state.firstUserMessage)
3680
2830
  state.firstUserMessage = genuine;
3681
2831
  if (!state.topic)
@@ -3691,24 +2841,13 @@ function applyCodexLine(state, parsed) {
3691
2841
  const total = getCodexTokenCount(totalUsage);
3692
2842
  if (total !== null)
3693
2843
  state.tokenCount = total;
3694
- // token_count is cumulative — keep the latest snapshot and price it once
3695
- // after the stream, so we don't double-count across intermediate events.
3696
2844
  if (totalUsage && typeof totalUsage === 'object')
3697
2845
  state.lastTotalTokenUsage = totalUsage;
3698
- // Codex also stamps the model on the rate_limits/token_count payload on
3699
- // some versions; prefer session_meta but fall back to it.
3700
2846
  if (!state.model && typeof parsed.payload.info?.model === 'string')
3701
2847
  state.model = parsed.payload.info.model;
3702
2848
  }
3703
2849
  }
3704
- /**
3705
- * Build the {@link CodexSessionScan} return object from an accumulator — the
3706
- * exact return-building {@link scanCodexSession} used to run inline.
3707
- */
3708
2850
  function finalizeCodexScan(state) {
3709
- // Codex reports one cumulative snapshot: uncached input, cached (cache-read)
3710
- // input, and output+reasoning. It has no cache-write bucket. Derive the burn
3711
- // split and both costs (actual + no-cache) from that final snapshot (RUSH-2287).
3712
2851
  const snap = state.lastTotalTokenUsage;
3713
2852
  const outputTokens = snap
3714
2853
  ? (snap.output_tokens ?? 0) + (snap.reasoning_output_tokens ?? 0)
@@ -3721,7 +2860,6 @@ function finalizeCodexScan(state) {
3721
2860
  inputTokens = typeof snap.input_tokens === 'number' ? snap.input_tokens : undefined;
3722
2861
  cacheReadTokens = typeof snap.cached_input_tokens === 'number' ? snap.cached_input_tokens : undefined;
3723
2862
  }
3724
- // Price the final cumulative token snapshot once, against the session model.
3725
2863
  if (state.model && snap) {
3726
2864
  const usage = {
3727
2865
  model: state.model,
@@ -3771,7 +2909,6 @@ function finalizeCodexScan(state) {
3771
2909
  recentDirectoriesTouched: state.recentDirectoriesTouched.length ? state.recentDirectoriesTouched : undefined,
3772
2910
  };
3773
2911
  }
3774
- /** Stream a Codex JSONL file and extract scan-level metadata (session ID, cwd, topic, tokens). */
3775
2912
  async function scanCodexSession(filePath) {
3776
2913
  const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
3777
2914
  const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
@@ -3796,11 +2933,6 @@ async function scanCodexSession(filePath) {
3796
2933
  }
3797
2934
  return finalizeCodexScan(state);
3798
2935
  }
3799
- /**
3800
- * Snapshot a live {@link CodexParseState} into its serializable form at `offset`
3801
- * bytes consumed. Round-trips through {@link hydrateCodexParseState} so
3802
- * incremental replay equals a full parse.
3803
- */
3804
2936
  export function serializeCodexParserState(state, offset, jsonlDroppingOversizedLine = false) {
3805
2937
  const ticket = detectTicket(state.userTexts.join('\n') || undefined, state.gitBranch);
3806
2938
  return {
@@ -3826,10 +2958,6 @@ export function serializeCodexParserState(state, offset, jsonlDroppingOversizedL
3826
2958
  pendingTicketTools: [...state.pendingTicketTools],
3827
2959
  createdTickets: [...state.createdTickets],
3828
2960
  spawnedTeam: state.spawnedTeam,
3829
- // ticketId is derived at finalize time; persist it (and content_text) so a
3830
- // consumer can rebuild the row + FTS doc on append without re-reading the
3831
- // whole file. worktreeSlug is re-derived from cwd/gitBranch, so it need not
3832
- // be persisted.
3833
2961
  ticketId: ticket?.id,
3834
2962
  contentText: state.userTexts.length > 0 ? state.userTexts.join('\n') : undefined,
3835
2963
  assistantContentText: state.assistantTexts.length > 0 ? state.assistantTexts.join('\n') : undefined,
@@ -3838,16 +2966,6 @@ export function serializeCodexParserState(state, offset, jsonlDroppingOversizedL
3838
2966
  toolCalls: state.toolCollector.snapshot(),
3839
2967
  };
3840
2968
  }
3841
- /**
3842
- * Rebuild a live {@link CodexParseState} from a persisted continuation so that
3843
- * applying the appended lines yields the same accumulator a full parse would.
3844
- *
3845
- * `userTexts` is rehydrated as a single joined blob from `contentText`: only
3846
- * `userTexts.join('\n')` (detectTicket + contentText) and `userTexts.length > 0`
3847
- * are ever read downstream, and both are preserved by a one-element array
3848
- * holding the joined content. Topic is first-wins and already persisted, so a
3849
- * collapsed userTexts never changes it.
3850
- */
3851
2969
  function hydrateCodexParseState(prior) {
3852
2970
  return {
3853
2971
  sessionId: prior.sessionId,
@@ -3876,26 +2994,10 @@ function hydrateCodexParseState(prior) {
3876
2994
  checklistEvents: prior.checklistEvents ?? [],
3877
2995
  recentDirectoriesTouched: prior.recentDirectoriesTouched ?? [],
3878
2996
  toolCollector: new ToolCallCollector(prior.toolCalls),
3879
- // Not persisted in CodexParserState (always empty for Codex today — see
3880
- // CodexParseState.skillEvents) — a resume starts fresh rather than
3881
- // round-tripping an always-empty array through the continuation blob.
3882
2997
  skillEvents: [],
3883
2998
  slashCommandEvents: [],
3884
2999
  };
3885
3000
  }
3886
- /**
3887
- * Resume a Codex parse from `fromOffset` bytes into the file, folding only the
3888
- * newly-appended lines into `prior`. Returns the finalized scan, the next
3889
- * serialized continuation, and the byte offset to resume from next time.
3890
- *
3891
- * Same trailing-line discipline as {@link scanClaudeSessionIncremental}: apply
3892
- * ONLY the run of newline-terminated lines (slice at the last `'\n'`), and set
3893
- * `newOffset = fromOffset + consumedBytes`. An ordinary tail after the last
3894
- * `'\n'` is deferred; an oversized one advances under a persisted discard bit.
3895
- * Codex `messageCount` is additive with
3896
- * NO dedup, so re-reading a still-unterminated complete line would double-count
3897
- * it; deferring prevents that (the bug class prix-cloud caught for Claude).
3898
- */
3899
3001
  export async function scanCodexSessionIncremental(filePath, fromOffset, prior) {
3900
3002
  const state = hydrateCodexParseState(prior);
3901
3003
  const append = await applyJsonlAppend(filePath, fromOffset, prior.jsonlDroppingOversizedLine === true, (parsed) => applyCodexLine(state, parsed));
@@ -3911,20 +3013,9 @@ export async function scanCodexSessionIncremental(filePath, fromOffset, prior) {
3911
3013
  toolCalls,
3912
3014
  };
3913
3015
  }
3914
- /** Serialized zero-value continuation: a fresh accumulator at offset 0, used to drive a FULL parse from the start through the same resumable path. */
3915
3016
  function freshCodexParserState() {
3916
3017
  return serializeCodexParserState(initCodexParseState(), 0);
3917
3018
  }
3918
- /**
3919
- * Cheaply derive a Codex rollout's session identity — the `session_meta` id — by
3920
- * streaming only the START of the file (at most `maxBytes`) and stopping once the
3921
- * id is known. Mirrors {@link claudeSessionIdentityAt}: used by
3922
- * {@link scanCodexSessionResumable} to confirm a grown file is still the SAME
3923
- * session before resuming from a stored parse offset. Codex writes `session_meta`
3924
- * (carrying the durable session UUID) on the first line of every rollout, so the
3925
- * id is reached almost immediately. Returns undefined when no id appears within
3926
- * the budget, which forces a FULL parse.
3927
- */
3928
3019
  async function codexSessionIdentityAt(filePath, maxBytes = 1_048_576) {
3929
3020
  const state = initCodexParseState();
3930
3021
  const stream = fs.createReadStream(filePath, { start: 0, end: maxBytes - 1, encoding: 'utf-8' });
@@ -3951,27 +3042,7 @@ async function codexSessionIdentityAt(filePath, maxBytes = 1_048_576) {
3951
3042
  }
3952
3043
  return state.sessionId;
3953
3044
  }
3954
- /**
3955
- * Decide full-vs-incremental for one Codex rollout and parse it uniformly,
3956
- * always returning a finalized scan plus the continuation to persist. Both
3957
- * branches run through the SAME reducer (via {@link scanCodexSessionIncremental}),
3958
- * so an append produces a row identical to a from-scratch full reparse by
3959
- * construction. INCREMENTAL when a prior continuation exists AND the file grew
3960
- * past the persisted offset AND its mtime did not go backwards; FULL (from byte
3961
- * 0, fresh state) otherwise (cold start, truncation/rewrite, clock rewind).
3962
- */
3963
3045
  export async function scanCodexSessionResumable(filePath, prior, currentFileMtimeMs, currentFileSize, priorFileMtimeMs) {
3964
- // File size + mtime cannot distinguish an APPEND from an in-place rewrite or a
3965
- // restore that dropped a DIFFERENT, larger rollout at the same path: both grow
3966
- // the file and move mtime forward. Resuming from the stored offset across that
3967
- // boundary would fold the new session's bytes into an accumulator hydrated from
3968
- // the OLD session, so the persisted row silently diverges from a full reparse.
3969
- // So the metadata gate below only makes a file ELIGIBLE; before trusting the
3970
- // offset we re-read the rollout's `session_meta` id and require it to still
3971
- // match the prior continuation's. An append keeps that id; a rewrite/restore of
3972
- // a different session changes it. A mismatch — or an id we cannot derive —
3973
- // falls back to a FULL parse, which is always correct. (A shrink is already
3974
- // handled: currentFileSize is not > prior.offset, so it takes the FULL branch.)
3975
3046
  let canIncrement = false;
3976
3047
  if (prior !== null &&
3977
3048
  currentFileSize > prior.offset &&
@@ -3986,12 +3057,6 @@ export async function scanCodexSessionResumable(filePath, prior, currentFileMtim
3986
3057
  const result = await scanCodexSessionIncremental(filePath, 0, freshCodexParserState());
3987
3058
  return { ...result, mode: 'full' };
3988
3059
  }
3989
- /**
3990
- * Parse the prior continuation blob for a changed Codex file into a usable
3991
- * {@link CodexParserState}, or null when there is none / it is unusable. A blob
3992
- * from a different serialization version is treated as absent so the file falls
3993
- * back to a clean FULL parse rather than resuming against a stale shape.
3994
- */
3995
3060
  function parsePriorCodexState(row) {
3996
3061
  if (!row?.parserState)
3997
3062
  return null;
@@ -4005,20 +3070,15 @@ function parsePriorCodexState(row) {
4005
3070
  return null;
4006
3071
  }
4007
3072
  }
4008
- /** Test seam: how many times the incremental (append-resume) branch was taken since the last reset. */
4009
3073
  let codexIncrementalScanCount = 0;
4010
- /** Test seam: how many times a full (from-offset-0) Codex parse ran since the last reset. */
4011
3074
  let codexFullScanCount = 0;
4012
- /** Test seam: read the (incremental, full) Codex parse counters. */
4013
3075
  export function __codexScanBranchCountsForTest() {
4014
3076
  return { incremental: codexIncrementalScanCount, full: codexFullScanCount };
4015
3077
  }
4016
- /** Test seam: reset the Codex parse-branch counters to observe a scan from a clean slate. */
4017
3078
  export function __resetCodexScanBranchCountsForTest() {
4018
3079
  codexIncrementalScanCount = 0;
4019
3080
  codexFullScanCount = 0;
4020
3081
  }
4021
- /** Resolve the working directory for an OpenClaw agent from its workspace config. */
4022
3082
  function getOpenClawSessionCwd(agentId) {
4023
3083
  const workspace = agentId ? getOpenClawWorkspaceMap().get(agentId) : undefined;
4024
3084
  if (workspace)
@@ -4026,7 +3086,6 @@ function getOpenClawSessionCwd(agentId) {
4026
3086
  const configDir = AGENTS.openclaw.configDir;
4027
3087
  return safeRealpathSync(configDir) || configDir;
4028
3088
  }
4029
- /** Build a cached map of OpenClaw agent ID to workspace path from openclaw.json. */
4030
3089
  function getOpenClawWorkspaceMap() {
4031
3090
  if (cachedOpenClawWorkspaces)
4032
3091
  return cachedOpenClawWorkspaces;
@@ -4045,19 +3104,13 @@ function getOpenClawWorkspaceMap() {
4045
3104
  }
4046
3105
  }
4047
3106
  catch {
4048
- // Ignore invalid OpenClaw config and fall back to ~/.openclaw.
4049
3107
  }
4050
3108
  cachedOpenClawWorkspaces = workspaces;
4051
3109
  return workspaces;
4052
3110
  }
4053
- // ---------------------------------------------------------------------------
4054
- // Utilities
4055
- // ---------------------------------------------------------------------------
4056
- /** Compute the SHA-256 hex digest of a string. */
4057
3111
  function sha256(input) {
4058
3112
  return crypto.createHash('sha256').update(input).digest('hex');
4059
3113
  }
4060
- /** Stat a path, returning null on any error. */
4061
3114
  function safeStatSync(p) {
4062
3115
  try {
4063
3116
  return fs.statSync(p);
@@ -4066,7 +3119,6 @@ function safeStatSync(p) {
4066
3119
  return null;
4067
3120
  }
4068
3121
  }
4069
- /** Resolve a path to its real path, returning null on any error. */
4070
3122
  function safeRealpathSync(p) {
4071
3123
  try {
4072
3124
  return fs.realpathSync(p);
@@ -4075,7 +3127,6 @@ function safeRealpathSync(p) {
4075
3127
  return null;
4076
3128
  }
4077
3129
  }
4078
- /** Extract meaningful user text from a Claude JSONL user event, skipping meta and local-command messages. */
4079
3130
  function extractClaudeUserText(parsed) {
4080
3131
  if (parsed.isMeta === true)
4081
3132
  return undefined;
@@ -4094,18 +3145,9 @@ function extractClaudeUserText(parsed) {
4094
3145
  return undefined;
4095
3146
  return text;
4096
3147
  }
4097
- /** Check whether a message is a local-command wrapper rather than real user input. */
4098
3148
  function isLocalCommandMessage(text) {
4099
3149
  return /<local-command-caveat>|<bash-(input|stdout|stderr)>/i.test(text);
4100
3150
  }
4101
- /**
4102
- * Extract the assistant's own answer text from a Claude JSONL assistant event —
4103
- * the reply text blocks, skipping tool_use/tool_result blocks and an
4104
- * interrupted turn, mirroring {@link extractClaudeUserText}'s filters. Unlike
4105
- * the user side (which keeps only the first text block), a single assistant
4106
- * turn can legitimately carry multiple text blocks around tool calls, so every
4107
- * one is joined.
4108
- */
4109
3151
  function extractClaudeAssistantText(parsed) {
4110
3152
  const content = parsed.message?.content;
4111
3153
  if (typeof content === 'string') {
@@ -4121,7 +3163,6 @@ function extractClaudeAssistantText(parsed) {
4121
3163
  .join('\n');
4122
3164
  return text || undefined;
4123
3165
  }
4124
- /** Sum all token usage fields from a Claude assistant message's usage object. */
4125
3166
  function getClaudeUsageTotal(usage) {
4126
3167
  if (!usage || typeof usage !== 'object')
4127
3168
  return null;
@@ -4132,7 +3173,6 @@ function getClaudeUsageTotal(usage) {
4132
3173
  usage.cache_read_input_tokens,
4133
3174
  ]);
4134
3175
  }
4135
- /** Extract text from Codex message content blocks; the caller classifies user scaffolding. */
4136
3176
  function extractCodexMessageText(contentBlocks, role) {
4137
3177
  if (!Array.isArray(contentBlocks))
4138
3178
  return undefined;
@@ -4144,22 +3184,15 @@ function extractCodexMessageText(contentBlocks, role) {
4144
3184
  .find((value) => !!value);
4145
3185
  return text || undefined;
4146
3186
  }
4147
- /** Trim and normalize a version string, returning undefined for empty values. */
4148
3187
  function normalizeVersion(version) {
4149
3188
  const trimmed = version?.trim();
4150
3189
  return trimmed ? trimmed : undefined;
4151
3190
  }
4152
- /** Extract the version number from a managed versions/<agent>/<version>/... path under either repo. */
4153
3191
  export function extractVersionFromManagedPath(agent, sourcePath) {
4154
3192
  if (!sourcePath)
4155
3193
  return undefined;
4156
3194
  const candidates = [sourcePath, safeRealpathSync(sourcePath) || ''];
4157
3195
  const markers = [`/.agents/versions/${agent}/`, `/.agents-system/versions/${agent}/`];
4158
- // Codex is relocated by CODEX_HOME to `~/.agents/.codex-homes/<version>/`
4159
- // (shims.ts `codexHomeShimBash`), NOT the `versions/<agent>/<version>/home/…`
4160
- // layout every other isolated agent uses — so its rollout transcripts live
4161
- // under `.codex-homes/<version>/sessions/…` and the markers above never match,
4162
- // leaving `version` NULL and native resume degraded to `/continue` (PHNX-3626).
4163
3196
  if (agent === 'codex')
4164
3197
  markers.push('/.agents/.codex-homes/');
4165
3198
  for (const candidate of candidates) {
@@ -4177,7 +3210,6 @@ export function extractVersionFromManagedPath(agent, sourcePath) {
4177
3210
  }
4178
3211
  return undefined;
4179
3212
  }
4180
- /** Resolve the current version of an agent CLI (symlink version or live CLI output, cached). */
4181
3213
  async function getCurrentAgentVersion(agent) {
4182
3214
  const cached = cachedAgentVersions.get(agent);
4183
3215
  if (cached)
@@ -4191,13 +3223,11 @@ async function getCurrentAgentVersion(agent) {
4191
3223
  cachedAgentVersions.set(agent, promise);
4192
3224
  return promise;
4193
3225
  }
4194
- /** Resolve a session's version: embedded in file > extracted from managed path > current CLI version. */
4195
3226
  function resolveSessionVersion(agent, sourcePath, embeddedVersion, currentVersion) {
4196
3227
  return normalizeVersion(embeddedVersion)
4197
3228
  || extractVersionFromManagedPath(agent, sourcePath)
4198
3229
  || normalizeVersion(currentVersion);
4199
3230
  }
4200
- /** Sum all token usage fields from a Codex total_token_usage object. */
4201
3231
  function getCodexTokenCount(totalTokenUsage) {
4202
3232
  if (!totalTokenUsage || typeof totalTokenUsage !== 'object')
4203
3233
  return null;
@@ -4208,7 +3238,6 @@ function getCodexTokenCount(totalTokenUsage) {
4208
3238
  totalTokenUsage.reasoning_output_tokens,
4209
3239
  ]);
4210
3240
  }
4211
- /** Sum all numeric values in an array, returning null if none are valid numbers. */
4212
3241
  function sumKnownNumbers(values) {
4213
3242
  let total = 0;
4214
3243
  let found = false;
@@ -4220,20 +3249,6 @@ function sumKnownNumbers(values) {
4220
3249
  }
4221
3250
  return found ? total : null;
4222
3251
  }
4223
- // ---------------------------------------------------------------------------
4224
- // Time range parsing
4225
- // ---------------------------------------------------------------------------
4226
- // ---------------------------------------------------------------------------
4227
- // Cursor
4228
- // ---------------------------------------------------------------------------
4229
- // Cursor writes the conversation to
4230
- // projects/<encoded-cwd>/agent-transcripts/<uuid>/<uuid>.jsonl and metadata to
4231
- // chats/<workspace-hash>/<uuid>/meta.json. Discovery deliberately starts from
4232
- // transcripts, then joins metadata by UUID: chat directories with no transcript
4233
- // are empty or abandoned sessions and must not become broken zero-event rows.
4234
- // Routine archives may contain only the transcript; those remain browsable with
4235
- // file timestamps and without guessed cwd/title metadata.
4236
- /** Incrementally re-scan changed Cursor transcript files and upsert into the DB. */
4237
3252
  async function scanCursorIncremental(onProgress) {
4238
3253
  const currentVersion = await getCurrentAgentVersion('cursor');
4239
3254
  const prestat = [];
@@ -4303,12 +3318,10 @@ function readCursorChatMeta(filePath, sessionId) {
4303
3318
  return JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
4304
3319
  }
4305
3320
  catch {
4306
- // This workspace hash does not own the session, or its metadata is unreadable.
4307
3321
  }
4308
3322
  }
4309
3323
  return undefined;
4310
3324
  }
4311
- /** Parse one Cursor transcript and enrich it with the matching chat meta.json. */
4312
3325
  export function readCursorMeta(filePath, currentVersion) {
4313
3326
  const sessionId = path.basename(filePath).replace(/\.jsonl$/, '');
4314
3327
  if (!sessionId || path.basename(path.dirname(filePath)) !== sessionId)
@@ -4354,13 +3367,6 @@ export function readCursorMeta(filePath, currentVersion) {
4354
3367
  };
4355
3368
  return { meta, content: userTexts.join('\n'), assistantContent: assistantTexts.join('\n'), events };
4356
3369
  }
4357
- // ---------------------------------------------------------------------------
4358
- // Kimi
4359
- // ---------------------------------------------------------------------------
4360
- // Kimi stores sessions under ~/.kimi-code/sessions/<workdir_hash>/session_<uuid>/.
4361
- // Each session has state.json (metadata) and agents/main/wire.jsonl (conversation).
4362
- // A session_index.jsonl at ~/.kimi-code/ maps session IDs to directories.
4363
- /** Incrementally re-scan changed Kimi session state.json files and upsert into the DB. */
4364
3370
  async function scanKimiIncremental(onProgress) {
4365
3371
  const filePaths = [];
4366
3372
  for (const sessionsDir of getAgentSessionDirs('kimi', 'sessions')) {
@@ -4399,9 +3405,6 @@ async function scanKimiIncremental(onProgress) {
4399
3405
  if (changed.length === 0)
4400
3406
  return;
4401
3407
  onProgress?.({ agent: 'kimi', parsed: 0, total: changed.length });
4402
- // Bulk-fetch each changed session's prior wire-parse continuation (offset +
4403
- // counter bases). A session whose wire.jsonl grew resumes from the offset;
4404
- // everything else (cold start, truncation) full-parses from byte 0.
4405
3408
  const priorStates = getParserStatesForPaths(changed.map(c => c.filePath));
4406
3409
  const scanEntries = [];
4407
3410
  const touched = [];
@@ -4427,7 +3430,6 @@ async function scanKimiIncremental(onProgress) {
4427
3430
  upsertSessionsBatch(scanEntries);
4428
3431
  recordScans(touched);
4429
3432
  }
4430
- /** Parse a single Kimi session state.json file to extract session metadata. */
4431
3433
  export function readKimiMeta(filePath, priorRow) {
4432
3434
  let state;
4433
3435
  try {
@@ -4445,17 +3447,10 @@ export function readKimiMeta(filePath, priorRow) {
4445
3447
  const topic = title || lastPrompt || undefined;
4446
3448
  const createdAt = typeof state.createdAt === 'string' ? state.createdAt : undefined;
4447
3449
  const updatedAt = typeof state.updatedAt === 'string' ? state.updatedAt : undefined;
4448
- // Coerce to never-null, the same way every other parser does (Rush/Hermes/Droid/…):
4449
- // a real createdAt/updatedAt still wins; otherwise fall back to the state.json mtime.
4450
- // Kimi was the lone parser that could yield `undefined`, which binds NULL into
4451
- // `timestamp TEXT NOT NULL` and aborts the whole batch index. mtime also matches how
4452
- // the listing already ranks Kimi (last_activity resolves to the file mtime).
4453
3450
  const stat = safeStatSync(filePath);
4454
3451
  const timestamp = updatedAt || createdAt
4455
3452
  || (stat ? stat.mtime.toISOString() : new Date().toISOString());
4456
3453
  const shortId = deriveShortId(sessionId, /^session_/);
4457
- // Try to infer project from session directory path
4458
- // ~/.kimi-code/sessions/<workdir_hash>/session_<uuid>/
4459
3454
  const workDirName = path.basename(path.dirname(sessionDir));
4460
3455
  let project;
4461
3456
  if (workDirName.startsWith('wd_')) {
@@ -4464,9 +3459,6 @@ export function readKimiMeta(filePath, priorRow) {
4464
3459
  project = parts.slice(0, -1).join('/');
4465
3460
  }
4466
3461
  }
4467
- // Parse wire.jsonl incrementally: resume from the persisted offset + counter
4468
- // bases when the wire grew, else full-parse from byte 0. The continuation is
4469
- // persisted on this session's state.json ledger row.
4470
3462
  const prior = parsePriorKimiState(priorRow);
4471
3463
  const { messageCount, tokenCount, outputTokens, newState } = parseKimiWireMetricsIncremental(sessionDir, prior);
4472
3464
  const meta = {
@@ -4495,7 +3487,6 @@ function kimiWireUserText(event) {
4495
3487
  : '';
4496
3488
  return cleanFirstUserMessage(raw);
4497
3489
  }
4498
- /** Fold one parsed Kimi wire event into the additive counters, in place. */
4499
3490
  function applyKimiWireEvent(acc, event) {
4500
3491
  if (event.type === 'context.append_message') {
4501
3492
  acc.messageCount++;
@@ -4503,49 +3494,17 @@ function applyKimiWireEvent(acc, event) {
4503
3494
  acc.firstUserMessage = kimiWireUserText(event);
4504
3495
  }
4505
3496
  else if (event.type === 'usage.record' && event.usage) {
4506
- // Kimi usage structure: inputOther + output + inputCacheRead + inputCacheCreation
4507
3497
  const u = event.usage;
4508
3498
  acc.tokenCount += (u.inputOther || 0) + (u.output || 0) + (u.inputCacheRead || 0) + (u.inputCacheCreation || 0);
4509
3499
  acc.outputTokens += (u.output || 0);
4510
3500
  }
4511
3501
  }
4512
- /**
4513
- * Incrementally parse Kimi's wire.jsonl for message-count and token counters,
4514
- * resuming from a persisted continuation instead of re-reading from byte 0 every
4515
- * scan. Returns the finalized counters and the next {@link KimiParserState} to
4516
- * persist (offset + the three counter bases).
4517
- *
4518
- * Same trailing-line discipline as {@link scanClaudeSessionIncremental}: read
4519
- * only the appended byte range from `prior.offset`, apply ONLY the run of
4520
- * newline-terminated lines (slice at the last `'\n'`), and advance the offset to
4521
- * `prior.offset + consumedBytes`. A complete-but-not-yet-terminated last record
4522
- * is DEFERRED to the next pass; because these counters are additive with no
4523
- * dedup, re-reading such a line would double-count it. FULL parse from byte 0
4524
- * (fresh counters) when there is no prior OR the file shrank below the stored
4525
- * offset (truncation/rewrite).
4526
- */
4527
3502
  export function parseKimiWireMetricsIncremental(sessionDir, prior) {
4528
3503
  const wirePath = path.join(sessionDir, 'agents', 'main', 'wire.jsonl');
4529
3504
  const stat = safeStatSync(wirePath);
4530
3505
  if (!stat) {
4531
- // No wire.jsonl (yet): zero counters, offset 0 so a later append is a clean
4532
- // full parse.
4533
3506
  return { messageCount: 0, tokenCount: 0, outputTokens: 0, newState: { v: 2, offset: 0, messageCount: 0, tokenCount: 0, outputTokens: 0 } };
4534
3507
  }
4535
- // INCREMENTAL only when a usable prior exists AND the file grew past its
4536
- // offset; otherwise FULL from byte 0 with fresh counters (cold start OR the
4537
- // file shrank to/below the offset — a truncation/rewrite).
4538
- //
4539
- // No session-identity re-check is needed here (unlike Claude's
4540
- // claudeSessionIdentityAt / Codex's codexSessionIdentityAt, which guard against
4541
- // an in-place rewrite dropping a DIFFERENT session at the same path). A Kimi
4542
- // wire.jsonl is uniquely keyed by its session dir — `.../session_<uuid>/agents/
4543
- // main/wire.jsonl` (see readKimiMeta: sessionId is `session_<uuid>` and must
4544
- // start with `session_`) — and Kimi only ever APPENDS to that per-session log.
4545
- // The path therefore cannot host a different session's transcript, so a
4546
- // size-grew wire.jsonl is always the same session's append. (A truncation/
4547
- // rewrite — the only way its bytes could diverge — already shrinks it to/below
4548
- // the offset and takes the FULL branch above.)
4549
3508
  const canIncrement = prior !== null && stat.size > prior.offset;
4550
3509
  const fromOffset = canIncrement ? prior.offset : 0;
4551
3510
  const acc = canIncrement
@@ -4554,12 +3513,6 @@ export function parseKimiWireMetricsIncremental(sessionDir, prior) {
4554
3513
  let consumedBytes = 0;
4555
3514
  let fd;
4556
3515
  try {
4557
- // Read ONLY the appended byte range [fromOffset, stat.size) — not the whole
4558
- // file. readSync from an explicit position keeps this function synchronous
4559
- // (its callers are sync) while making the disk read + allocation scale with
4560
- // the appended delta, not total file size, matching scanCodexSessionIncremental
4561
- // / scanClaudeSessionIncremental. Bytes past the stat'd size are a concurrent
4562
- // append and are deferred to the next scan.
4563
3516
  const bytesToRead = Math.max(0, stat.size - fromOffset);
4564
3517
  const appended = Buffer.allocUnsafe(bytesToRead);
4565
3518
  if (bytesToRead > 0) {
@@ -4572,7 +3525,6 @@ export function parseKimiWireMetricsIncremental(sessionDir, prior) {
4572
3525
  read += n;
4573
3526
  }
4574
3527
  const chunk = read === bytesToRead ? appended : appended.subarray(0, read);
4575
- // Bytes up to AND INCLUDING the last '\n' are the committed, complete-line run.
4576
3528
  const lastNl = chunk.lastIndexOf(0x0a);
4577
3529
  consumedBytes = lastNl === -1 ? 0 : lastNl + 1;
4578
3530
  if (consumedBytes > 0) {
@@ -4583,22 +3535,19 @@ export function parseKimiWireMetricsIncremental(sessionDir, prior) {
4583
3535
  applyKimiWireEvent(acc, JSON.parse(line));
4584
3536
  }
4585
3537
  catch {
4586
- // Malformed line, skip
4587
3538
  }
4588
3539
  }
4589
3540
  }
4590
3541
  }
4591
3542
  }
4592
3543
  catch {
4593
- // If wire.jsonl can't be read, keep the accumulated counters (0s on a cold
4594
- // parse) — graceful degradation, matching the pre-incremental behavior.
4595
3544
  }
4596
3545
  finally {
4597
3546
  if (fd !== undefined) {
4598
3547
  try {
4599
3548
  fs.closeSync(fd);
4600
3549
  }
4601
- catch { /* already closed / gone */ }
3550
+ catch { }
4602
3551
  }
4603
3552
  }
4604
3553
  return {
@@ -4608,12 +3557,6 @@ export function parseKimiWireMetricsIncremental(sessionDir, prior) {
4608
3557
  newState: { v: 2, offset: fromOffset + consumedBytes, messageCount: acc.messageCount, tokenCount: acc.tokenCount, outputTokens: acc.outputTokens, firstUserMessage: acc.firstUserMessage },
4609
3558
  };
4610
3559
  }
4611
- /**
4612
- * Parse the prior continuation blob for a changed Kimi session into a usable
4613
- * {@link KimiParserState}, or null when there is none / it is unusable. A blob
4614
- * from a different serialization version is treated as absent so the wire parse
4615
- * falls back to a clean FULL parse rather than resuming against a stale shape.
4616
- */
4617
3560
  function parsePriorKimiState(row) {
4618
3561
  if (!row?.parserState)
4619
3562
  return null;
@@ -4627,14 +3570,6 @@ function parsePriorKimiState(row) {
4627
3570
  return null;
4628
3571
  }
4629
3572
  }
4630
- /**
4631
- * Scan Grok sessions. Grok stores one directory per session under
4632
- * ~/.grok/sessions/<url-encoded-cwd>/<uuid>/, each holding a summary.json with
4633
- * structured metadata (id, cwd, title, timestamps, message count). Same
4634
- * dir-per-session (L3) shape as Kimi, so it walks two levels and gates the
4635
- * summary.json read through the scan ledger. Before this, Grok had a type slot
4636
- * and a placeholder parser but no scanner, so `agents sessions` never indexed it.
4637
- */
4638
3573
  async function scanGrokIncremental(onProgress) {
4639
3574
  const currentVersion = await getCurrentAgentVersion('grok');
4640
3575
  const filePaths = [];
@@ -4696,18 +3631,6 @@ async function scanGrokIncremental(onProgress) {
4696
3631
  upsertSessionsBatch(scanEntries);
4697
3632
  recordScans(touched);
4698
3633
  }
4699
- /**
4700
- * Bounded read of a Grok `chat_history.jsonl` for the genuine full first user
4701
- * turn (PHNX-3621 leftover from #3359). Grok's cheap scan reads only
4702
- * `summary.json` (a LARGE-transcript harness whose full message log is
4703
- * deliberately not parsed on the hot tick), but the first turn is at the START
4704
- * of the log, so a bounded prefix read recovers it without paying the full-file
4705
- * cost. Production logs lead with a `type:system` record, then a huge
4706
- * `<user_info>` user dump (no `synthetic_reason`), then a `synthetic_reason`
4707
- * reminder, then the originating turn at `prompt_index: 0` wrapped in
4708
- * `<user_query>`. Skip that scaffolding and prefer `prompt_index` when present.
4709
- * Returns undefined when no genuine user turn appears within the budget.
4710
- */
4711
3634
  function readGrokFirstUserMessage(sessionDir, maxBytes = 262_144) {
4712
3635
  const historyPath = path.join(sessionDir, 'chat_history.jsonl');
4713
3636
  let fd;
@@ -4728,7 +3651,6 @@ function readGrokFirstUserMessage(sessionDir, maxBytes = 262_144) {
4728
3651
  read += n;
4729
3652
  }
4730
3653
  const chunk = buf.subarray(0, read).toString('utf-8');
4731
- // Drop a trailing partial line so we never parse half a JSON record.
4732
3654
  const lastNl = chunk.lastIndexOf('\n');
4733
3655
  const complete = lastNl === -1 ? chunk : chunk.slice(0, lastNl);
4734
3656
  let firstGenuine;
@@ -4770,11 +3692,10 @@ function readGrokFirstUserMessage(sessionDir, maxBytes = 262_144) {
4770
3692
  try {
4771
3693
  fs.closeSync(fd);
4772
3694
  }
4773
- catch { /* already closed / gone */ }
3695
+ catch { }
4774
3696
  }
4775
3697
  }
4776
3698
  }
4777
- /** Parse a single Grok session summary.json into session metadata. */
4778
3699
  export function readGrokMeta(filePath, currentVersion) {
4779
3700
  let summary;
4780
3701
  try {
@@ -4784,7 +3705,6 @@ export function readGrokMeta(filePath, currentVersion) {
4784
3705
  return null;
4785
3706
  }
4786
3707
  const sessionDir = path.dirname(filePath);
4787
- // The uuid directory name is the canonical id; summary.info.id mirrors it.
4788
3708
  const sessionId = (typeof summary?.info?.id === 'string' && summary.info.id) || path.basename(sessionDir);
4789
3709
  if (!sessionId)
4790
3710
  return null;
@@ -4792,9 +3712,6 @@ export function readGrokMeta(filePath, currentVersion) {
4792
3712
  const topic = (typeof summary?.generated_title === 'string' && summary.generated_title.trim()) ||
4793
3713
  (typeof summary?.session_summary === 'string' && summary.session_summary.trim()) ||
4794
3714
  undefined;
4795
- // created_at is the session start; last_active_at/updated_at is the latest
4796
- // activity. Coerce timestamp to never-null (NOT NULL column) via the file mtime,
4797
- // matching how the other dir-per-session parsers (Kimi) fall back.
4798
3715
  const createdAt = typeof summary?.created_at === 'string' ? summary.created_at : undefined;
4799
3716
  const lastActivity = (typeof summary?.last_active_at === 'string' && summary.last_active_at) ||
4800
3717
  (typeof summary?.updated_at === 'string' && summary.updated_at) ||
@@ -4806,11 +3723,6 @@ export function readGrokMeta(filePath, currentVersion) {
4806
3723
  : typeof summary?.num_messages === 'number'
4807
3724
  ? summary.num_messages
4808
3725
  : undefined;
4809
- // Grok records its managed home in summary.grok_home
4810
- // (…/versions/grok/<version>/home/.grok) — recover the version from it. The
4811
- // value is written by the Grok CLI in the writing host's native separators, so
4812
- // a Windows-authored summary is backslash-separated; normalize to `/` before
4813
- // matching or the version never resolves on Windows (RUSH-2286).
4814
3726
  let embeddedVersion;
4815
3727
  if (typeof summary?.grok_home === 'string') {
4816
3728
  embeddedVersion = summary.grok_home.replace(/\\/g, '/').match(/versions\/grok\/([^/]+)\//)?.[1];
@@ -4831,9 +3743,4 @@ export function readGrokMeta(filePath, currentVersion) {
4831
3743
  };
4832
3744
  return { meta, content: topic || '' };
4833
3745
  }
4834
- // parseTimeFilter moved to ./relative-time.js — a leaf module — so a caller that
4835
- // only needs the duration parser does not pull this file's `../sqlite.js` import
4836
- // (and Node's SQLite ExperimentalWarning on stderr) into its module graph.
4837
- // Re-exported so every existing importer keeps working unchanged. Imported too,
4838
- // because a bare re-export does not bind the name for this file's own callers.
4839
3746
  export { parseTimeFilter } from './relative-time.js';