@ai-devkit/agent-manager 0.36.0 → 0.37.0

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 (618) hide show
  1. package/dist/AgentManager.d.ts +9 -4
  2. package/dist/AgentManager.d.ts.map +1 -1
  3. package/dist/AgentManager.js +21 -2
  4. package/dist/AgentManager.js.map +1 -1
  5. package/dist/__tests__/AgentManager.test.js +151 -3
  6. package/dist/__tests__/AgentManager.test.js.map +1 -1
  7. package/dist/__tests__/adapters/IncrementalSessionRefresh.test.js +486 -0
  8. package/dist/__tests__/adapters/IncrementalSessionRefresh.test.js.map +1 -0
  9. package/dist/__tests__/adapters/adapterProcessImports.test.js +52 -0
  10. package/dist/__tests__/adapters/adapterProcessImports.test.js.map +1 -0
  11. package/dist/__tests__/adapters/adapterSnapshotCandidates.test.js +247 -0
  12. package/dist/__tests__/adapters/adapterSnapshotCandidates.test.js.map +1 -0
  13. package/dist/__tests__/capacity/openai.test.js +12 -14
  14. package/dist/__tests__/capacity/openai.test.js.map +1 -1
  15. package/dist/__tests__/harnesses/BoundedSummarySkip.test.js +568 -0
  16. package/dist/__tests__/harnesses/BoundedSummarySkip.test.js.map +1 -0
  17. package/dist/__tests__/harnesses/SessionSummaryEquivalence.test.js +1089 -0
  18. package/dist/__tests__/harnesses/SessionSummaryEquivalence.test.js.map +1 -0
  19. package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.subprocess.test.js +143 -0
  20. package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.subprocess.test.js.map +1 -0
  21. package/dist/__tests__/{adapters → harnesses/antigravity}/AntigravityCliAdapter.test.js +103 -22
  22. package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.test.js.map +1 -0
  23. package/dist/__tests__/harnesses/builtinAdapters.test.js +33 -0
  24. package/dist/__tests__/harnesses/builtinAdapters.test.js.map +1 -0
  25. package/dist/__tests__/{providers → harnesses}/claude/ClaudeAgentMapper.test.js +4 -4
  26. package/dist/__tests__/harnesses/claude/ClaudeAgentMapper.test.js.map +1 -0
  27. package/dist/__tests__/{adapters → harnesses/claude}/ClaudeCodeAdapter.test.js +47 -19
  28. package/dist/__tests__/harnesses/claude/ClaudeCodeAdapter.test.js.map +1 -0
  29. package/dist/__tests__/{providers → harnesses}/claude/ClaudeSessionLocator.test.js +1 -12
  30. package/dist/__tests__/{providers → harnesses}/claude/ClaudeSessionLocator.test.js.map +1 -1
  31. package/dist/__tests__/{utils → harnesses/claude}/ClaudeSessionParser.test.js +2 -2
  32. package/dist/__tests__/harnesses/claude/ClaudeSessionParser.test.js.map +1 -0
  33. package/dist/__tests__/{print → harnesses/claude/durable}/ClaudeCliProbe.test.js +1 -1
  34. package/dist/__tests__/harnesses/claude/durable/ClaudeCliProbe.test.js.map +1 -0
  35. package/dist/__tests__/{print → harnesses/claude/durable}/ClaudePrintAgent.integration.test.js +1 -1
  36. package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js.map +1 -0
  37. package/dist/__tests__/{print → harnesses/claude/durable}/ClaudePrintAgentService.test.js +4 -4
  38. package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgentService.test.js.map +1 -0
  39. package/dist/__tests__/{print → harnesses/claude/durable}/ClaudePrintRunner.test.js +1 -1
  40. package/dist/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.js.map +1 -0
  41. package/dist/__tests__/{adapters → harnesses/codex}/CodexAdapter.test.js +304 -10
  42. package/dist/__tests__/harnesses/codex/CodexAdapter.test.js.map +1 -0
  43. package/dist/__tests__/harnesses/codex/CodexSessionLocator.test.js +463 -0
  44. package/dist/__tests__/harnesses/codex/CodexSessionLocator.test.js.map +1 -0
  45. package/dist/__tests__/{providers → harnesses}/codex/CodexSessionMapping.test.js +1 -1
  46. package/dist/__tests__/{providers → harnesses}/codex/CodexSessionMapping.test.js.map +1 -1
  47. package/dist/__tests__/{providers → harnesses}/codex/CodexSessionParser.test.js +1 -1
  48. package/dist/__tests__/{providers → harnesses}/codex/CodexSessionParser.test.js.map +1 -1
  49. package/dist/__tests__/{durable → harnesses/codex/durable}/CodexCliProbe.test.js +4 -4
  50. package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js.map +1 -0
  51. package/dist/__tests__/{durable → harnesses/codex/durable}/CodexDurableAgentRepository.test.js +1 -1
  52. package/dist/__tests__/harnesses/codex/durable/CodexDurableAgentRepository.test.js.map +1 -0
  53. package/dist/__tests__/{durable → harnesses/codex/durable}/CodexPrintAgent.integration.test.js +1 -1
  54. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js.map +1 -0
  55. package/dist/__tests__/{durable → harnesses/codex/durable}/CodexPrintAgentService.test.js +8 -18
  56. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js.map +1 -0
  57. package/dist/__tests__/{durable → harnesses/codex/durable}/CodexPrintRunner.test.js +2 -7
  58. package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js.map +1 -0
  59. package/dist/__tests__/{providers → harnesses}/copilot/CopilotAdapter.test.js +1 -1
  60. package/dist/__tests__/{providers → harnesses}/copilot/CopilotAdapter.test.js.map +1 -1
  61. package/dist/__tests__/harnesses/copilot/CopilotRefreshIO.test.js +290 -0
  62. package/dist/__tests__/harnesses/copilot/CopilotRefreshIO.test.js.map +1 -0
  63. package/dist/__tests__/{providers → harnesses}/gemini/GeminiCliAdapter.test.js +34 -25
  64. package/dist/__tests__/harnesses/gemini/GeminiCliAdapter.test.js.map +1 -0
  65. package/dist/__tests__/harnesses/gemini/GeminiSessionJsonl.test.js +491 -0
  66. package/dist/__tests__/harnesses/gemini/GeminiSessionJsonl.test.js.map +1 -0
  67. package/dist/__tests__/harnesses/gemini/GeminiSessionLocator.test.js +399 -0
  68. package/dist/__tests__/harnesses/gemini/GeminiSessionLocator.test.js.map +1 -0
  69. package/dist/__tests__/{providers → harnesses}/grok/GrokAgentMapper.test.js +1 -1
  70. package/dist/__tests__/{providers → harnesses}/grok/GrokAgentMapper.test.js.map +1 -1
  71. package/dist/__tests__/{providers → harnesses}/grok/GrokCliAdapter.test.js +1 -1
  72. package/dist/__tests__/{providers → harnesses}/grok/GrokCliAdapter.test.js.map +1 -1
  73. package/dist/__tests__/harnesses/grok/GrokIncrementalRefresh.test.js +167 -0
  74. package/dist/__tests__/harnesses/grok/GrokIncrementalRefresh.test.js.map +1 -0
  75. package/dist/__tests__/{providers → harnesses}/grok/GrokSessionLocator.test.js +1 -1
  76. package/dist/__tests__/{providers → harnesses}/grok/GrokSessionLocator.test.js.map +1 -1
  77. package/dist/__tests__/harnesses/grok/GrokSessionParser.test.js +301 -0
  78. package/dist/__tests__/harnesses/grok/GrokSessionParser.test.js.map +1 -0
  79. package/dist/__tests__/{adapters → harnesses/kiro}/KiroAdapter.test.js +137 -82
  80. package/dist/__tests__/harnesses/kiro/KiroAdapter.test.js.map +1 -0
  81. package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeAdapter.test.js +1 -1
  82. package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeAdapter.test.js.map +1 -1
  83. package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeAgentMapper.test.js +1 -1
  84. package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeAgentMapper.test.js.map +1 -1
  85. package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeSessionLocator.test.js +2 -2
  86. package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeSessionLocator.test.js.map +1 -1
  87. package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeSessionParser.test.js +1 -1
  88. package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeSessionParser.test.js.map +1 -1
  89. package/dist/__tests__/{providers → harnesses}/pi/PiAdapter.test.js +1 -1
  90. package/dist/__tests__/{providers → harnesses}/pi/PiAdapter.test.js.map +1 -1
  91. package/dist/__tests__/harnesses/pi/PiDiscoveryIO.test.js +382 -0
  92. package/dist/__tests__/harnesses/pi/PiDiscoveryIO.test.js.map +1 -0
  93. package/dist/__tests__/{providers → harnesses}/pi/PiSessionParser.test.js +171 -1
  94. package/dist/__tests__/harnesses/pi/PiSessionParser.test.js.map +1 -0
  95. package/dist/__tests__/{providers → harnesses}/pi/PiSessionTracker.test.js +1 -1
  96. package/dist/__tests__/{providers → harnesses}/pi/PiSessionTracker.test.js.map +1 -1
  97. package/dist/__tests__/{providers → harnesses}/pi/durable/PiCliProbe.test.js.map +1 -1
  98. package/dist/__tests__/{providers → harnesses}/pi/durable/PiDurableAgentRepository.test.js.map +1 -1
  99. package/dist/__tests__/{providers → harnesses}/pi/durable/PiPrintAgentService.test.js.map +1 -1
  100. package/dist/__tests__/{providers → harnesses}/pi/durable/PiPrintProtocol.test.js +1 -1
  101. package/dist/__tests__/{providers → harnesses}/pi/durable/PiPrintProtocol.test.js.map +1 -1
  102. package/dist/__tests__/{providers → harnesses}/pi/durable/PiPrintRunner.test.js.map +1 -1
  103. package/dist/__tests__/{providers → harnesses}/pi/durable/PiStreamParser.test.js +1 -1
  104. package/dist/__tests__/{providers → harnesses}/pi/durable/PiStreamParser.test.js.map +1 -1
  105. package/dist/__tests__/readiness/AgentReadiness.test.js +20 -0
  106. package/dist/__tests__/readiness/AgentReadiness.test.js.map +1 -1
  107. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js +49 -0
  108. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -1
  109. package/dist/__tests__/utils/IncrementalJsonlSummary.test.js +650 -0
  110. package/dist/__tests__/utils/IncrementalJsonlSummary.test.js.map +1 -0
  111. package/dist/__tests__/utils/agents.test.js +66 -2
  112. package/dist/__tests__/utils/agents.test.js.map +1 -1
  113. package/dist/__tests__/utils/conversationTail.bench.test.js +258 -0
  114. package/dist/__tests__/utils/conversationTail.bench.test.js.map +1 -0
  115. package/dist/__tests__/utils/conversationTailParity.test.js +588 -0
  116. package/dist/__tests__/utils/conversationTailParity.test.js.map +1 -0
  117. package/dist/__tests__/utils/jsonlTail.test.js +360 -0
  118. package/dist/__tests__/utils/jsonlTail.test.js.map +1 -0
  119. package/dist/__tests__/utils/matchingConstants.test.js +35 -0
  120. package/dist/__tests__/utils/matchingConstants.test.js.map +1 -0
  121. package/dist/__tests__/utils/process.test.js +436 -2
  122. package/dist/__tests__/utils/process.test.js.map +1 -1
  123. package/dist/adapters/AgentAdapter.d.ts +25 -6
  124. package/dist/adapters/AgentAdapter.d.ts.map +1 -1
  125. package/dist/adapters/AgentAdapter.js +12 -3
  126. package/dist/adapters/AgentAdapter.js.map +1 -1
  127. package/dist/capacity/openai.d.ts +0 -1
  128. package/dist/capacity/openai.d.ts.map +1 -1
  129. package/dist/capacity/openai.js +0 -5
  130. package/dist/capacity/openai.js.map +1 -1
  131. package/dist/harnesses/antigravity/AntigravityAgentMapper.d.ts +13 -0
  132. package/dist/harnesses/antigravity/AntigravityAgentMapper.d.ts.map +1 -0
  133. package/dist/harnesses/antigravity/AntigravityAgentMapper.js +30 -0
  134. package/dist/harnesses/antigravity/AntigravityAgentMapper.js.map +1 -0
  135. package/dist/harnesses/antigravity/AntigravityCliAdapter.d.ts +32 -0
  136. package/dist/harnesses/antigravity/AntigravityCliAdapter.d.ts.map +1 -0
  137. package/dist/harnesses/antigravity/AntigravityCliAdapter.js +97 -0
  138. package/dist/harnesses/antigravity/AntigravityCliAdapter.js.map +1 -0
  139. package/dist/harnesses/antigravity/AntigravitySessionLocator.d.ts +30 -0
  140. package/dist/harnesses/antigravity/AntigravitySessionLocator.d.ts.map +1 -0
  141. package/dist/harnesses/antigravity/AntigravitySessionLocator.js +56 -0
  142. package/dist/harnesses/antigravity/AntigravitySessionLocator.js.map +1 -0
  143. package/dist/harnesses/antigravity/AntigravitySessionParser.d.ts +75 -0
  144. package/dist/harnesses/antigravity/AntigravitySessionParser.d.ts.map +1 -0
  145. package/dist/harnesses/antigravity/AntigravitySessionParser.js +174 -0
  146. package/dist/harnesses/antigravity/AntigravitySessionParser.js.map +1 -0
  147. package/dist/{providers → harnesses}/claude/ClaudeAgentMapper.d.ts.map +1 -1
  148. package/dist/{providers → harnesses}/claude/ClaudeAgentMapper.js +4 -10
  149. package/dist/harnesses/claude/ClaudeAgentMapper.js.map +1 -0
  150. package/dist/{providers → harnesses}/claude/ClaudeCodeAdapter.d.ts +5 -6
  151. package/dist/harnesses/claude/ClaudeCodeAdapter.d.ts.map +1 -0
  152. package/dist/{providers → harnesses}/claude/ClaudeCodeAdapter.js +17 -15
  153. package/dist/harnesses/claude/ClaudeCodeAdapter.js.map +1 -0
  154. package/dist/{providers → harnesses}/claude/ClaudeSessionLocator.d.ts.map +1 -1
  155. package/dist/{providers → harnesses}/claude/ClaudeSessionLocator.js +3 -3
  156. package/dist/harnesses/claude/ClaudeSessionLocator.js.map +1 -0
  157. package/dist/{providers → harnesses}/claude/ClaudeSessionParser.d.ts +40 -6
  158. package/dist/harnesses/claude/ClaudeSessionParser.d.ts.map +1 -0
  159. package/dist/{providers → harnesses}/claude/ClaudeSessionParser.js +141 -85
  160. package/dist/harnesses/claude/ClaudeSessionParser.js.map +1 -0
  161. package/dist/{providers → harnesses}/claude/durable/ClaudeCliProbe.d.ts.map +1 -1
  162. package/dist/{providers → harnesses}/claude/durable/ClaudeCliProbe.js.map +1 -1
  163. package/dist/{providers → harnesses}/claude/durable/ClaudePrintAgentService.d.ts.map +1 -1
  164. package/dist/{providers → harnesses}/claude/durable/ClaudePrintAgentService.js.map +1 -1
  165. package/dist/{providers → harnesses}/claude/durable/ClaudePrintRunner.d.ts.map +1 -1
  166. package/dist/{providers → harnesses}/claude/durable/ClaudePrintRunner.js.map +1 -1
  167. package/dist/{providers → harnesses}/claude/durable/ClaudeStreamParser.d.ts.map +1 -1
  168. package/dist/{providers → harnesses}/claude/durable/ClaudeStreamParser.js.map +1 -1
  169. package/dist/{providers → harnesses}/codex/CodexAdapter.d.ts +5 -4
  170. package/dist/harnesses/codex/CodexAdapter.d.ts.map +1 -0
  171. package/dist/{providers → harnesses}/codex/CodexAdapter.js +139 -19
  172. package/dist/harnesses/codex/CodexAdapter.js.map +1 -0
  173. package/dist/{providers → harnesses}/codex/CodexAgentMapper.d.ts.map +1 -1
  174. package/dist/{providers → harnesses}/codex/CodexAgentMapper.js +4 -11
  175. package/dist/harnesses/codex/CodexAgentMapper.js.map +1 -0
  176. package/dist/harnesses/codex/CodexSessionLocator.d.ts +74 -0
  177. package/dist/harnesses/codex/CodexSessionLocator.d.ts.map +1 -0
  178. package/dist/harnesses/codex/CodexSessionLocator.js +359 -0
  179. package/dist/harnesses/codex/CodexSessionLocator.js.map +1 -0
  180. package/dist/{providers → harnesses}/codex/CodexSessionMapping.d.ts.map +1 -1
  181. package/dist/{providers → harnesses}/codex/CodexSessionMapping.js +3 -3
  182. package/dist/harnesses/codex/CodexSessionMapping.js.map +1 -0
  183. package/dist/harnesses/codex/CodexSessionParser.d.ts +89 -0
  184. package/dist/harnesses/codex/CodexSessionParser.d.ts.map +1 -0
  185. package/dist/{providers → harnesses}/codex/CodexSessionParser.js +124 -78
  186. package/dist/harnesses/codex/CodexSessionParser.js.map +1 -0
  187. package/dist/{providers → harnesses}/codex/durable/CodexCliProbe.d.ts.map +1 -1
  188. package/dist/{providers → harnesses}/codex/durable/CodexCliProbe.js.map +1 -1
  189. package/dist/{providers → harnesses}/codex/durable/CodexPrintAgentService.d.ts.map +1 -1
  190. package/dist/{providers → harnesses}/codex/durable/CodexPrintAgentService.js.map +1 -1
  191. package/dist/{providers → harnesses}/codex/durable/CodexPrintRunner.d.ts.map +1 -1
  192. package/dist/{providers → harnesses}/codex/durable/CodexPrintRunner.js.map +1 -1
  193. package/dist/{providers → harnesses}/codex/durable/CodexStreamParser.d.ts.map +1 -1
  194. package/dist/{providers → harnesses}/codex/durable/CodexStreamParser.js.map +1 -1
  195. package/dist/{providers → harnesses}/copilot/CopilotAdapter.d.ts +7 -6
  196. package/dist/harnesses/copilot/CopilotAdapter.d.ts.map +1 -0
  197. package/dist/{providers → harnesses}/copilot/CopilotAdapter.js +19 -14
  198. package/dist/harnesses/copilot/CopilotAdapter.js.map +1 -0
  199. package/dist/{providers → harnesses}/copilot/CopilotAgentMapper.d.ts.map +1 -1
  200. package/dist/{providers → harnesses}/copilot/CopilotAgentMapper.js +4 -11
  201. package/dist/harnesses/copilot/CopilotAgentMapper.js.map +1 -0
  202. package/dist/harnesses/copilot/CopilotSessionLocator.d.ts +42 -0
  203. package/dist/harnesses/copilot/CopilotSessionLocator.d.ts.map +1 -0
  204. package/dist/harnesses/copilot/CopilotSessionLocator.js +126 -0
  205. package/dist/harnesses/copilot/CopilotSessionLocator.js.map +1 -0
  206. package/dist/harnesses/copilot/CopilotSessionParser.d.ts +62 -0
  207. package/dist/harnesses/copilot/CopilotSessionParser.d.ts.map +1 -0
  208. package/dist/harnesses/copilot/CopilotSessionParser.js +236 -0
  209. package/dist/harnesses/copilot/CopilotSessionParser.js.map +1 -0
  210. package/dist/{providers → harnesses}/gemini/GeminiAgentMapper.d.ts.map +1 -1
  211. package/dist/{providers → harnesses}/gemini/GeminiAgentMapper.js +4 -11
  212. package/dist/harnesses/gemini/GeminiAgentMapper.js.map +1 -0
  213. package/dist/{providers → harnesses}/gemini/GeminiCliAdapter.d.ts +4 -5
  214. package/dist/harnesses/gemini/GeminiCliAdapter.d.ts.map +1 -0
  215. package/dist/{providers → harnesses}/gemini/GeminiCliAdapter.js +6 -7
  216. package/dist/harnesses/gemini/GeminiCliAdapter.js.map +1 -0
  217. package/dist/harnesses/gemini/GeminiSessionLocator.d.ts +72 -0
  218. package/dist/harnesses/gemini/GeminiSessionLocator.d.ts.map +1 -0
  219. package/dist/harnesses/gemini/GeminiSessionLocator.js +300 -0
  220. package/dist/harnesses/gemini/GeminiSessionLocator.js.map +1 -0
  221. package/dist/{providers → harnesses}/gemini/GeminiSessionParser.d.ts +34 -7
  222. package/dist/harnesses/gemini/GeminiSessionParser.d.ts.map +1 -0
  223. package/dist/harnesses/gemini/GeminiSessionParser.js +272 -0
  224. package/dist/harnesses/gemini/GeminiSessionParser.js.map +1 -0
  225. package/dist/harnesses/gemini/fileSignature.d.ts +8 -0
  226. package/dist/harnesses/gemini/fileSignature.d.ts.map +1 -0
  227. package/dist/harnesses/gemini/fileSignature.js +9 -0
  228. package/dist/harnesses/gemini/fileSignature.js.map +1 -0
  229. package/dist/{providers → harnesses}/grok/GrokAgentMapper.d.ts.map +1 -1
  230. package/dist/{providers → harnesses}/grok/GrokAgentMapper.js +4 -10
  231. package/dist/harnesses/grok/GrokAgentMapper.js.map +1 -0
  232. package/dist/{providers → harnesses}/grok/GrokCliAdapter.d.ts +5 -5
  233. package/dist/harnesses/grok/GrokCliAdapter.d.ts.map +1 -0
  234. package/dist/{providers → harnesses}/grok/GrokCliAdapter.js +14 -10
  235. package/dist/harnesses/grok/GrokCliAdapter.js.map +1 -0
  236. package/dist/{providers → harnesses}/grok/GrokSessionLocator.d.ts.map +1 -1
  237. package/dist/{providers → harnesses}/grok/GrokSessionLocator.js +2 -2
  238. package/dist/harnesses/grok/GrokSessionLocator.js.map +1 -0
  239. package/dist/harnesses/grok/GrokSessionParser.d.ts +87 -0
  240. package/dist/harnesses/grok/GrokSessionParser.d.ts.map +1 -0
  241. package/dist/harnesses/grok/GrokSessionParser.js +185 -0
  242. package/dist/harnesses/grok/GrokSessionParser.js.map +1 -0
  243. package/dist/harnesses/index.d.ts +7 -0
  244. package/dist/harnesses/index.d.ts.map +1 -0
  245. package/dist/harnesses/index.js +27 -0
  246. package/dist/harnesses/index.js.map +1 -0
  247. package/dist/harnesses/kiro/KiroAdapter.d.ts +31 -0
  248. package/dist/harnesses/kiro/KiroAdapter.d.ts.map +1 -0
  249. package/dist/harnesses/kiro/KiroAdapter.js +125 -0
  250. package/dist/harnesses/kiro/KiroAdapter.js.map +1 -0
  251. package/dist/harnesses/kiro/KiroAgentMapper.d.ts +13 -0
  252. package/dist/harnesses/kiro/KiroAgentMapper.d.ts.map +1 -0
  253. package/dist/harnesses/kiro/KiroAgentMapper.js +29 -0
  254. package/dist/harnesses/kiro/KiroAgentMapper.js.map +1 -0
  255. package/dist/harnesses/kiro/KiroSessionLocator.d.ts +38 -0
  256. package/dist/harnesses/kiro/KiroSessionLocator.d.ts.map +1 -0
  257. package/dist/harnesses/kiro/KiroSessionLocator.js +95 -0
  258. package/dist/harnesses/kiro/KiroSessionLocator.js.map +1 -0
  259. package/dist/harnesses/kiro/KiroSessionParser.d.ts +81 -0
  260. package/dist/harnesses/kiro/KiroSessionParser.d.ts.map +1 -0
  261. package/dist/harnesses/kiro/KiroSessionParser.js +251 -0
  262. package/dist/harnesses/kiro/KiroSessionParser.js.map +1 -0
  263. package/dist/{providers → harnesses}/opencode/OpenCodeAdapter.d.ts +2 -4
  264. package/dist/harnesses/opencode/OpenCodeAdapter.d.ts.map +1 -0
  265. package/dist/{providers → harnesses}/opencode/OpenCodeAdapter.js +4 -7
  266. package/dist/harnesses/opencode/OpenCodeAdapter.js.map +1 -0
  267. package/dist/{providers → harnesses}/opencode/OpenCodeAgentMapper.d.ts.map +1 -1
  268. package/dist/{providers → harnesses}/opencode/OpenCodeAgentMapper.js +5 -13
  269. package/dist/harnesses/opencode/OpenCodeAgentMapper.js.map +1 -0
  270. package/dist/{providers → harnesses}/opencode/OpenCodeSessionLocator.d.ts.map +1 -1
  271. package/dist/{providers → harnesses}/opencode/OpenCodeSessionLocator.js +2 -2
  272. package/dist/harnesses/opencode/OpenCodeSessionLocator.js.map +1 -0
  273. package/dist/{providers → harnesses}/opencode/OpenCodeSessionParser.d.ts +2 -4
  274. package/dist/harnesses/opencode/OpenCodeSessionParser.d.ts.map +1 -0
  275. package/dist/{providers → harnesses}/opencode/OpenCodeSessionParser.js +2 -1
  276. package/dist/harnesses/opencode/OpenCodeSessionParser.js.map +1 -0
  277. package/dist/{providers → harnesses}/pi/PiAdapter.d.ts +5 -4
  278. package/dist/harnesses/pi/PiAdapter.d.ts.map +1 -0
  279. package/dist/{providers → harnesses}/pi/PiAdapter.js +16 -12
  280. package/dist/harnesses/pi/PiAdapter.js.map +1 -0
  281. package/dist/{providers → harnesses}/pi/PiAgentMapper.d.ts.map +1 -1
  282. package/dist/{providers → harnesses}/pi/PiAgentMapper.js +4 -11
  283. package/dist/harnesses/pi/PiAgentMapper.js.map +1 -0
  284. package/dist/harnesses/pi/PiSessionLocator.d.ts +61 -0
  285. package/dist/harnesses/pi/PiSessionLocator.d.ts.map +1 -0
  286. package/dist/harnesses/pi/PiSessionLocator.js +212 -0
  287. package/dist/harnesses/pi/PiSessionLocator.js.map +1 -0
  288. package/dist/harnesses/pi/PiSessionParser.d.ts +88 -0
  289. package/dist/harnesses/pi/PiSessionParser.d.ts.map +1 -0
  290. package/dist/harnesses/pi/PiSessionParser.js +318 -0
  291. package/dist/harnesses/pi/PiSessionParser.js.map +1 -0
  292. package/dist/{providers → harnesses}/pi/PiSessionTracker.d.ts.map +1 -1
  293. package/dist/{providers → harnesses}/pi/PiSessionTracker.js +2 -2
  294. package/dist/harnesses/pi/PiSessionTracker.js.map +1 -0
  295. package/dist/{providers → harnesses}/pi/durable/PiCliProbe.d.ts.map +1 -1
  296. package/dist/{providers → harnesses}/pi/durable/PiCliProbe.js.map +1 -1
  297. package/dist/{providers → harnesses}/pi/durable/PiPrintAgentService.d.ts.map +1 -1
  298. package/dist/{providers → harnesses}/pi/durable/PiPrintAgentService.js.map +1 -1
  299. package/dist/{providers → harnesses}/pi/durable/PiPrintProtocol.d.ts.map +1 -1
  300. package/dist/{providers → harnesses}/pi/durable/PiPrintProtocol.js.map +1 -1
  301. package/dist/{providers → harnesses}/pi/durable/PiPrintRunner.d.ts.map +1 -1
  302. package/dist/{providers → harnesses}/pi/durable/PiPrintRunner.js.map +1 -1
  303. package/dist/{providers → harnesses}/pi/durable/PiStreamParser.d.ts.map +1 -1
  304. package/dist/{providers → harnesses}/pi/durable/PiStreamParser.js.map +1 -1
  305. package/dist/harnesses/shared.d.ts +41 -0
  306. package/dist/harnesses/shared.d.ts.map +1 -0
  307. package/dist/harnesses/shared.js +71 -0
  308. package/dist/harnesses/shared.js.map +1 -0
  309. package/dist/index.d.ts +26 -25
  310. package/dist/index.d.ts.map +1 -1
  311. package/dist/index.js +18 -17
  312. package/dist/index.js.map +1 -1
  313. package/dist/utils/IncrementalJsonlSummary.d.ts +100 -0
  314. package/dist/utils/IncrementalJsonlSummary.d.ts.map +1 -0
  315. package/dist/utils/IncrementalJsonlSummary.js +209 -0
  316. package/dist/utils/IncrementalJsonlSummary.js.map +1 -0
  317. package/dist/utils/agents.d.ts +3 -2
  318. package/dist/utils/agents.d.ts.map +1 -1
  319. package/dist/utils/agents.js +50 -15
  320. package/dist/utils/agents.js.map +1 -1
  321. package/dist/utils/index.d.ts +2 -1
  322. package/dist/utils/index.d.ts.map +1 -1
  323. package/dist/utils/index.js +1 -1
  324. package/dist/utils/index.js.map +1 -1
  325. package/dist/utils/jsonlTail.d.ts +73 -0
  326. package/dist/utils/jsonlTail.d.ts.map +1 -0
  327. package/dist/utils/jsonlTail.js +238 -0
  328. package/dist/utils/jsonlTail.js.map +1 -0
  329. package/dist/utils/matching.d.ts +2 -0
  330. package/dist/utils/matching.d.ts.map +1 -1
  331. package/dist/utils/matching.js +3 -2
  332. package/dist/utils/matching.js.map +1 -1
  333. package/dist/utils/matchingConstants.d.ts +15 -0
  334. package/dist/utils/matchingConstants.d.ts.map +1 -0
  335. package/dist/utils/matchingConstants.js +14 -0
  336. package/dist/utils/matchingConstants.js.map +1 -0
  337. package/dist/utils/process.d.ts +38 -2
  338. package/dist/utils/process.d.ts.map +1 -1
  339. package/dist/utils/process.js +131 -43
  340. package/dist/utils/process.js.map +1 -1
  341. package/package.json +2 -1
  342. package/scripts/benchmark-cold-start.mjs +350 -0
  343. package/src/AgentManager.ts +26 -5
  344. package/src/__tests__/AgentManager.test.ts +141 -3
  345. package/src/__tests__/adapters/IncrementalSessionRefresh.test.ts +437 -0
  346. package/src/__tests__/adapters/adapterProcessImports.test.ts +58 -0
  347. package/src/__tests__/adapters/adapterSnapshotCandidates.test.ts +243 -0
  348. package/src/__tests__/capacity/openai.test.ts +5 -15
  349. package/src/__tests__/harnesses/BoundedSummarySkip.test.ts +496 -0
  350. package/src/__tests__/harnesses/SessionSummaryEquivalence.test.ts +726 -0
  351. package/src/__tests__/harnesses/antigravity/AntigravityCliAdapter.subprocess.test.ts +133 -0
  352. package/src/__tests__/{adapters → harnesses/antigravity}/AntigravityCliAdapter.test.ts +97 -25
  353. package/src/__tests__/harnesses/builtinAdapters.test.ts +33 -0
  354. package/src/__tests__/{providers → harnesses}/claude/ClaudeAgentMapper.test.ts +5 -5
  355. package/src/__tests__/{adapters → harnesses/claude}/ClaudeCodeAdapter.test.ts +54 -24
  356. package/src/__tests__/{providers → harnesses}/claude/ClaudeSessionLocator.test.ts +1 -12
  357. package/src/__tests__/{utils → harnesses/claude}/ClaudeSessionParser.test.ts +2 -2
  358. package/src/__tests__/{print → harnesses/claude/durable}/ClaudeCliProbe.test.ts +1 -1
  359. package/src/__tests__/{print → harnesses/claude/durable}/ClaudePrintAgent.integration.test.ts +1 -1
  360. package/src/__tests__/{print → harnesses/claude/durable}/ClaudePrintAgentService.test.ts +4 -4
  361. package/src/__tests__/{print → harnesses/claude/durable}/ClaudePrintRunner.test.ts +2 -2
  362. package/src/__tests__/{adapters → harnesses/codex}/CodexAdapter.test.ts +277 -12
  363. package/src/__tests__/harnesses/codex/CodexSessionLocator.test.ts +419 -0
  364. package/src/__tests__/{providers → harnesses}/codex/CodexSessionMapping.test.ts +1 -1
  365. package/src/__tests__/{providers → harnesses}/codex/CodexSessionParser.test.ts +1 -1
  366. package/src/__tests__/{durable → harnesses/codex/durable}/CodexCliProbe.test.ts +4 -4
  367. package/src/__tests__/{durable → harnesses/codex/durable}/CodexDurableAgentRepository.test.ts +1 -1
  368. package/src/__tests__/{durable → harnesses/codex/durable}/CodexPrintAgent.integration.test.ts +1 -1
  369. package/src/__tests__/{durable → harnesses/codex/durable}/CodexPrintAgentService.test.ts +8 -18
  370. package/src/__tests__/{durable → harnesses/codex/durable}/CodexPrintRunner.test.ts +3 -9
  371. package/src/__tests__/{providers → harnesses}/copilot/CopilotAdapter.test.ts +1 -1
  372. package/src/__tests__/harnesses/copilot/CopilotRefreshIO.test.ts +270 -0
  373. package/src/__tests__/{providers → harnesses}/gemini/GeminiCliAdapter.test.ts +27 -23
  374. package/src/__tests__/harnesses/gemini/GeminiSessionJsonl.test.ts +402 -0
  375. package/src/__tests__/harnesses/gemini/GeminiSessionLocator.test.ts +396 -0
  376. package/src/__tests__/{providers → harnesses}/grok/GrokAgentMapper.test.ts +2 -2
  377. package/src/__tests__/{providers → harnesses}/grok/GrokCliAdapter.test.ts +1 -1
  378. package/src/__tests__/harnesses/grok/GrokIncrementalRefresh.test.ts +170 -0
  379. package/src/__tests__/{providers → harnesses}/grok/GrokSessionLocator.test.ts +1 -1
  380. package/src/__tests__/harnesses/grok/GrokSessionParser.test.ts +230 -0
  381. package/src/__tests__/{adapters → harnesses/kiro}/KiroAdapter.test.ts +127 -109
  382. package/src/__tests__/{providers → harnesses}/opencode/OpenCodeAdapter.test.ts +1 -1
  383. package/src/__tests__/{providers → harnesses}/opencode/OpenCodeAgentMapper.test.ts +1 -1
  384. package/src/__tests__/{providers → harnesses}/opencode/OpenCodeSessionLocator.test.ts +2 -2
  385. package/src/__tests__/{providers → harnesses}/opencode/OpenCodeSessionParser.test.ts +1 -1
  386. package/src/__tests__/{providers → harnesses}/pi/PiAdapter.test.ts +1 -1
  387. package/src/__tests__/harnesses/pi/PiDiscoveryIO.test.ts +337 -0
  388. package/src/__tests__/{providers → harnesses}/pi/PiSessionParser.test.ts +91 -1
  389. package/src/__tests__/{providers → harnesses}/pi/PiSessionTracker.test.ts +1 -1
  390. package/src/__tests__/{providers → harnesses}/pi/durable/PiPrintProtocol.test.ts +1 -1
  391. package/src/__tests__/{providers → harnesses}/pi/durable/PiStreamParser.test.ts +1 -1
  392. package/src/__tests__/readiness/AgentReadiness.test.ts +16 -0
  393. package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +30 -0
  394. package/src/__tests__/utils/IncrementalJsonlSummary.test.ts +414 -0
  395. package/src/__tests__/utils/agents.test.ts +76 -2
  396. package/src/__tests__/utils/conversationTail.bench.test.ts +193 -0
  397. package/src/__tests__/utils/conversationTailParity.test.ts +365 -0
  398. package/src/__tests__/utils/jsonlTail.test.ts +317 -0
  399. package/src/__tests__/utils/matchingConstants.test.ts +40 -0
  400. package/src/__tests__/utils/process.test.ts +254 -0
  401. package/src/adapters/AgentAdapter.ts +37 -14
  402. package/src/capacity/openai.ts +0 -6
  403. package/src/harnesses/antigravity/AntigravityAgentMapper.ts +34 -0
  404. package/src/harnesses/antigravity/AntigravityCliAdapter.ts +126 -0
  405. package/src/harnesses/antigravity/AntigravitySessionLocator.ts +75 -0
  406. package/src/harnesses/antigravity/AntigravitySessionParser.ts +252 -0
  407. package/src/{providers → harnesses}/claude/ClaudeAgentMapper.ts +2 -10
  408. package/src/{providers → harnesses}/claude/ClaudeCodeAdapter.ts +22 -20
  409. package/src/{providers → harnesses}/claude/ClaudeSessionLocator.ts +3 -3
  410. package/src/{providers → harnesses}/claude/ClaudeSessionParser.ts +189 -97
  411. package/src/{providers → harnesses}/codex/CodexAdapter.ts +153 -29
  412. package/src/{providers → harnesses}/codex/CodexAgentMapper.ts +2 -11
  413. package/src/harnesses/codex/CodexSessionLocator.ts +509 -0
  414. package/src/{providers → harnesses}/codex/CodexSessionMapping.ts +3 -3
  415. package/src/{providers → harnesses}/codex/CodexSessionParser.ts +169 -92
  416. package/src/{providers → harnesses}/copilot/CopilotAdapter.ts +22 -22
  417. package/src/{providers → harnesses}/copilot/CopilotAgentMapper.ts +2 -11
  418. package/src/harnesses/copilot/CopilotSessionLocator.ts +161 -0
  419. package/src/harnesses/copilot/CopilotSessionParser.ts +380 -0
  420. package/src/{providers → harnesses}/gemini/GeminiAgentMapper.ts +2 -11
  421. package/src/{providers → harnesses}/gemini/GeminiCliAdapter.ts +7 -9
  422. package/src/harnesses/gemini/GeminiSessionLocator.ts +394 -0
  423. package/src/{providers → harnesses}/gemini/GeminiSessionParser.ts +155 -31
  424. package/src/harnesses/gemini/fileSignature.ts +10 -0
  425. package/src/{providers → harnesses}/grok/GrokAgentMapper.ts +2 -11
  426. package/src/{providers → harnesses}/grok/GrokCliAdapter.ts +16 -15
  427. package/src/{providers → harnesses}/grok/GrokSessionLocator.ts +2 -2
  428. package/src/harnesses/grok/GrokSessionParser.ts +251 -0
  429. package/src/harnesses/index.ts +28 -0
  430. package/src/harnesses/kiro/KiroAdapter.ts +143 -0
  431. package/src/harnesses/kiro/KiroAgentMapper.ts +34 -0
  432. package/src/harnesses/kiro/KiroSessionLocator.ts +143 -0
  433. package/src/harnesses/kiro/KiroSessionParser.ts +376 -0
  434. package/src/{providers → harnesses}/opencode/OpenCodeAdapter.ts +5 -11
  435. package/src/{providers → harnesses}/opencode/OpenCodeAgentMapper.ts +3 -13
  436. package/src/{providers → harnesses}/opencode/OpenCodeSessionLocator.ts +2 -2
  437. package/src/{providers → harnesses}/opencode/OpenCodeSessionParser.ts +4 -3
  438. package/src/{providers → harnesses}/pi/PiAdapter.ts +20 -18
  439. package/src/{providers → harnesses}/pi/PiAgentMapper.ts +2 -11
  440. package/src/harnesses/pi/PiSessionLocator.ts +288 -0
  441. package/src/harnesses/pi/PiSessionParser.ts +488 -0
  442. package/src/{providers → harnesses}/pi/PiSessionTracker.ts +2 -2
  443. package/src/harnesses/shared.ts +119 -0
  444. package/src/index.ts +26 -24
  445. package/src/utils/IncrementalJsonlSummary.ts +306 -0
  446. package/src/utils/agents.ts +60 -28
  447. package/src/utils/index.ts +2 -0
  448. package/src/utils/jsonlTail.ts +349 -0
  449. package/src/utils/matching.ts +3 -3
  450. package/src/utils/matchingConstants.ts +15 -0
  451. package/src/utils/process.ts +189 -45
  452. package/dist/__tests__/adapters/AntigravityCliAdapter.test.js.map +0 -1
  453. package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js.map +0 -1
  454. package/dist/__tests__/adapters/CodexAdapter.test.js.map +0 -1
  455. package/dist/__tests__/adapters/KiroAdapter.test.js.map +0 -1
  456. package/dist/__tests__/durable/CodexCliProbe.test.js.map +0 -1
  457. package/dist/__tests__/durable/CodexDurableAgentRepository.test.js.map +0 -1
  458. package/dist/__tests__/durable/CodexPrintAgent.integration.test.js.map +0 -1
  459. package/dist/__tests__/durable/CodexPrintAgentService.test.js.map +0 -1
  460. package/dist/__tests__/durable/CodexPrintRunner.test.js.map +0 -1
  461. package/dist/__tests__/print/ClaudeCliProbe.test.js.map +0 -1
  462. package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +0 -1
  463. package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +0 -1
  464. package/dist/__tests__/print/ClaudePrintRunner.test.js.map +0 -1
  465. package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js.map +0 -1
  466. package/dist/__tests__/providers/codex/CodexSessionLocator.test.js +0 -194
  467. package/dist/__tests__/providers/codex/CodexSessionLocator.test.js.map +0 -1
  468. package/dist/__tests__/providers/gemini/GeminiCliAdapter.test.js.map +0 -1
  469. package/dist/__tests__/providers/pi/PiSessionParser.test.js.map +0 -1
  470. package/dist/__tests__/utils/ClaudeSessionParser.test.js.map +0 -1
  471. package/dist/adapters/AntigravityCliAdapter.d.ts +0 -57
  472. package/dist/adapters/AntigravityCliAdapter.d.ts.map +0 -1
  473. package/dist/adapters/AntigravityCliAdapter.js +0 -273
  474. package/dist/adapters/AntigravityCliAdapter.js.map +0 -1
  475. package/dist/adapters/KiroAdapter.d.ts +0 -46
  476. package/dist/adapters/KiroAdapter.d.ts.map +0 -1
  477. package/dist/adapters/KiroAdapter.js +0 -344
  478. package/dist/adapters/KiroAdapter.js.map +0 -1
  479. package/dist/adapters/index.d.ts +0 -12
  480. package/dist/adapters/index.d.ts.map +0 -1
  481. package/dist/adapters/index.js +0 -12
  482. package/dist/adapters/index.js.map +0 -1
  483. package/dist/providers/claude/ClaudeAgentMapper.js.map +0 -1
  484. package/dist/providers/claude/ClaudeCodeAdapter.d.ts.map +0 -1
  485. package/dist/providers/claude/ClaudeCodeAdapter.js.map +0 -1
  486. package/dist/providers/claude/ClaudeSessionLocator.js.map +0 -1
  487. package/dist/providers/claude/ClaudeSessionParser.d.ts.map +0 -1
  488. package/dist/providers/claude/ClaudeSessionParser.js.map +0 -1
  489. package/dist/providers/codex/CodexAdapter.d.ts.map +0 -1
  490. package/dist/providers/codex/CodexAdapter.js.map +0 -1
  491. package/dist/providers/codex/CodexAgentMapper.js.map +0 -1
  492. package/dist/providers/codex/CodexSessionLocator.d.ts +0 -44
  493. package/dist/providers/codex/CodexSessionLocator.d.ts.map +0 -1
  494. package/dist/providers/codex/CodexSessionLocator.js +0 -207
  495. package/dist/providers/codex/CodexSessionLocator.js.map +0 -1
  496. package/dist/providers/codex/CodexSessionMapping.js.map +0 -1
  497. package/dist/providers/codex/CodexSessionParser.d.ts +0 -58
  498. package/dist/providers/codex/CodexSessionParser.d.ts.map +0 -1
  499. package/dist/providers/codex/CodexSessionParser.js.map +0 -1
  500. package/dist/providers/copilot/CopilotAdapter.d.ts.map +0 -1
  501. package/dist/providers/copilot/CopilotAdapter.js.map +0 -1
  502. package/dist/providers/copilot/CopilotAgentMapper.js.map +0 -1
  503. package/dist/providers/copilot/CopilotSessionLocator.d.ts +0 -20
  504. package/dist/providers/copilot/CopilotSessionLocator.d.ts.map +0 -1
  505. package/dist/providers/copilot/CopilotSessionLocator.js +0 -49
  506. package/dist/providers/copilot/CopilotSessionLocator.js.map +0 -1
  507. package/dist/providers/copilot/CopilotSessionParser.d.ts +0 -30
  508. package/dist/providers/copilot/CopilotSessionParser.d.ts.map +0 -1
  509. package/dist/providers/copilot/CopilotSessionParser.js +0 -181
  510. package/dist/providers/copilot/CopilotSessionParser.js.map +0 -1
  511. package/dist/providers/gemini/GeminiAgentMapper.js.map +0 -1
  512. package/dist/providers/gemini/GeminiCliAdapter.d.ts.map +0 -1
  513. package/dist/providers/gemini/GeminiCliAdapter.js.map +0 -1
  514. package/dist/providers/gemini/GeminiSessionLocator.d.ts +0 -30
  515. package/dist/providers/gemini/GeminiSessionLocator.d.ts.map +0 -1
  516. package/dist/providers/gemini/GeminiSessionLocator.js +0 -142
  517. package/dist/providers/gemini/GeminiSessionLocator.js.map +0 -1
  518. package/dist/providers/gemini/GeminiSessionParser.d.ts.map +0 -1
  519. package/dist/providers/gemini/GeminiSessionParser.js +0 -166
  520. package/dist/providers/gemini/GeminiSessionParser.js.map +0 -1
  521. package/dist/providers/grok/GrokAgentMapper.js.map +0 -1
  522. package/dist/providers/grok/GrokCliAdapter.d.ts.map +0 -1
  523. package/dist/providers/grok/GrokCliAdapter.js.map +0 -1
  524. package/dist/providers/grok/GrokSessionLocator.js.map +0 -1
  525. package/dist/providers/grok/GrokSessionParser.d.ts +0 -54
  526. package/dist/providers/grok/GrokSessionParser.d.ts.map +0 -1
  527. package/dist/providers/grok/GrokSessionParser.js +0 -122
  528. package/dist/providers/grok/GrokSessionParser.js.map +0 -1
  529. package/dist/providers/opencode/OpenCodeAdapter.d.ts.map +0 -1
  530. package/dist/providers/opencode/OpenCodeAdapter.js.map +0 -1
  531. package/dist/providers/opencode/OpenCodeAgentMapper.js.map +0 -1
  532. package/dist/providers/opencode/OpenCodeSessionLocator.js.map +0 -1
  533. package/dist/providers/opencode/OpenCodeSessionParser.d.ts.map +0 -1
  534. package/dist/providers/opencode/OpenCodeSessionParser.js.map +0 -1
  535. package/dist/providers/pi/PiAdapter.d.ts.map +0 -1
  536. package/dist/providers/pi/PiAdapter.js.map +0 -1
  537. package/dist/providers/pi/PiAgentMapper.js.map +0 -1
  538. package/dist/providers/pi/PiSessionLocator.d.ts +0 -24
  539. package/dist/providers/pi/PiSessionLocator.d.ts.map +0 -1
  540. package/dist/providers/pi/PiSessionLocator.js +0 -86
  541. package/dist/providers/pi/PiSessionLocator.js.map +0 -1
  542. package/dist/providers/pi/PiSessionParser.d.ts +0 -36
  543. package/dist/providers/pi/PiSessionParser.d.ts.map +0 -1
  544. package/dist/providers/pi/PiSessionParser.js +0 -191
  545. package/dist/providers/pi/PiSessionParser.js.map +0 -1
  546. package/dist/providers/pi/PiSessionTracker.js.map +0 -1
  547. package/src/__tests__/fixtures/fake-claude.cjs +0 -31
  548. package/src/__tests__/fixtures/fake-codex.cjs +0 -56
  549. package/src/__tests__/providers/codex/CodexSessionLocator.test.ts +0 -182
  550. package/src/adapters/AntigravityCliAdapter.ts +0 -356
  551. package/src/adapters/KiroAdapter.ts +0 -456
  552. package/src/adapters/index.ts +0 -17
  553. package/src/providers/codex/CodexSessionLocator.ts +0 -279
  554. package/src/providers/copilot/CopilotSessionLocator.ts +0 -63
  555. package/src/providers/copilot/CopilotSessionParser.ts +0 -289
  556. package/src/providers/gemini/GeminiSessionLocator.ts +0 -183
  557. package/src/providers/grok/GrokSessionParser.ts +0 -166
  558. package/src/providers/pi/PiSessionLocator.ts +0 -110
  559. package/src/providers/pi/PiSessionParser.ts +0 -284
  560. /package/dist/__tests__/{providers → harnesses}/pi/durable/PiCliProbe.test.js +0 -0
  561. /package/dist/__tests__/{providers → harnesses}/pi/durable/PiDurableAgentRepository.test.js +0 -0
  562. /package/dist/__tests__/{providers → harnesses}/pi/durable/PiPrintAgentService.test.js +0 -0
  563. /package/dist/__tests__/{providers → harnesses}/pi/durable/PiPrintRunner.test.js +0 -0
  564. /package/dist/{providers → harnesses}/claude/ClaudeAgentMapper.d.ts +0 -0
  565. /package/dist/{providers → harnesses}/claude/ClaudeSessionLocator.d.ts +0 -0
  566. /package/dist/{providers → harnesses}/claude/durable/ClaudeCliProbe.d.ts +0 -0
  567. /package/dist/{providers → harnesses}/claude/durable/ClaudeCliProbe.js +0 -0
  568. /package/dist/{providers → harnesses}/claude/durable/ClaudePrintAgentService.d.ts +0 -0
  569. /package/dist/{providers → harnesses}/claude/durable/ClaudePrintAgentService.js +0 -0
  570. /package/dist/{providers → harnesses}/claude/durable/ClaudePrintRunner.d.ts +0 -0
  571. /package/dist/{providers → harnesses}/claude/durable/ClaudePrintRunner.js +0 -0
  572. /package/dist/{providers → harnesses}/claude/durable/ClaudeStreamParser.d.ts +0 -0
  573. /package/dist/{providers → harnesses}/claude/durable/ClaudeStreamParser.js +0 -0
  574. /package/dist/{providers → harnesses}/codex/CodexAgentMapper.d.ts +0 -0
  575. /package/dist/{providers → harnesses}/codex/CodexSessionMapping.d.ts +0 -0
  576. /package/dist/{providers → harnesses}/codex/durable/CodexCliProbe.d.ts +0 -0
  577. /package/dist/{providers → harnesses}/codex/durable/CodexCliProbe.js +0 -0
  578. /package/dist/{providers → harnesses}/codex/durable/CodexPrintAgentService.d.ts +0 -0
  579. /package/dist/{providers → harnesses}/codex/durable/CodexPrintAgentService.js +0 -0
  580. /package/dist/{providers → harnesses}/codex/durable/CodexPrintRunner.d.ts +0 -0
  581. /package/dist/{providers → harnesses}/codex/durable/CodexPrintRunner.js +0 -0
  582. /package/dist/{providers → harnesses}/codex/durable/CodexStreamParser.d.ts +0 -0
  583. /package/dist/{providers → harnesses}/codex/durable/CodexStreamParser.js +0 -0
  584. /package/dist/{providers → harnesses}/copilot/CopilotAgentMapper.d.ts +0 -0
  585. /package/dist/{providers → harnesses}/gemini/GeminiAgentMapper.d.ts +0 -0
  586. /package/dist/{providers → harnesses}/grok/GrokAgentMapper.d.ts +0 -0
  587. /package/dist/{providers → harnesses}/grok/GrokSessionLocator.d.ts +0 -0
  588. /package/dist/{providers → harnesses}/opencode/OpenCodeAgentMapper.d.ts +0 -0
  589. /package/dist/{providers → harnesses}/opencode/OpenCodeSessionLocator.d.ts +0 -0
  590. /package/dist/{providers → harnesses}/pi/PiAgentMapper.d.ts +0 -0
  591. /package/dist/{providers → harnesses}/pi/PiSessionTracker.d.ts +0 -0
  592. /package/dist/{providers → harnesses}/pi/durable/PiCliProbe.d.ts +0 -0
  593. /package/dist/{providers → harnesses}/pi/durable/PiCliProbe.js +0 -0
  594. /package/dist/{providers → harnesses}/pi/durable/PiPrintAgentService.d.ts +0 -0
  595. /package/dist/{providers → harnesses}/pi/durable/PiPrintAgentService.js +0 -0
  596. /package/dist/{providers → harnesses}/pi/durable/PiPrintProtocol.d.ts +0 -0
  597. /package/dist/{providers → harnesses}/pi/durable/PiPrintProtocol.js +0 -0
  598. /package/dist/{providers → harnesses}/pi/durable/PiPrintRunner.d.ts +0 -0
  599. /package/dist/{providers → harnesses}/pi/durable/PiPrintRunner.js +0 -0
  600. /package/dist/{providers → harnesses}/pi/durable/PiStreamParser.d.ts +0 -0
  601. /package/dist/{providers → harnesses}/pi/durable/PiStreamParser.js +0 -0
  602. /package/src/__tests__/{providers → harnesses}/pi/durable/PiCliProbe.test.ts +0 -0
  603. /package/src/__tests__/{providers → harnesses}/pi/durable/PiDurableAgentRepository.test.ts +0 -0
  604. /package/src/__tests__/{providers → harnesses}/pi/durable/PiPrintAgentService.test.ts +0 -0
  605. /package/src/__tests__/{providers → harnesses}/pi/durable/PiPrintRunner.test.ts +0 -0
  606. /package/src/{providers → harnesses}/claude/durable/ClaudeCliProbe.ts +0 -0
  607. /package/src/{providers → harnesses}/claude/durable/ClaudePrintAgentService.ts +0 -0
  608. /package/src/{providers → harnesses}/claude/durable/ClaudePrintRunner.ts +0 -0
  609. /package/src/{providers → harnesses}/claude/durable/ClaudeStreamParser.ts +0 -0
  610. /package/src/{providers → harnesses}/codex/durable/CodexCliProbe.ts +0 -0
  611. /package/src/{providers → harnesses}/codex/durable/CodexPrintAgentService.ts +0 -0
  612. /package/src/{providers → harnesses}/codex/durable/CodexPrintRunner.ts +0 -0
  613. /package/src/{providers → harnesses}/codex/durable/CodexStreamParser.ts +0 -0
  614. /package/src/{providers → harnesses}/pi/durable/PiCliProbe.ts +0 -0
  615. /package/src/{providers → harnesses}/pi/durable/PiPrintAgentService.ts +0 -0
  616. /package/src/{providers → harnesses}/pi/durable/PiPrintProtocol.ts +0 -0
  617. /package/src/{providers → harnesses}/pi/durable/PiPrintRunner.ts +0 -0
  618. /package/src/{providers → harnesses}/pi/durable/PiStreamParser.ts +0 -0
@@ -0,0 +1,394 @@
1
+ import * as crypto from "crypto";
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import type { ProcessInfo } from "../../adapters/AgentAdapter.js";
5
+ import { MATCH_TOLERANCE_MS } from "../../utils/matchingConstants.js";
6
+ import type { SessionFile } from "../../utils/session.js";
7
+ import { isDirectory, safeReadFile, safeReaddir, safeStat } from "../../utils/session.js";
8
+ import { fileSignature } from "./fileSignature.js";
9
+ import { isSessionLogPath } from "./GeminiSessionParser.js";
10
+ import { homeDir } from "../shared.js";
11
+
12
+ export interface GeminiSessionDiscovery {
13
+ sessions: SessionFile[];
14
+ }
15
+
16
+ export interface GeminiSessionLocatorOptions {
17
+ geminiTmpDir?: string;
18
+ }
19
+
20
+ interface GeminiSessionMetadata {
21
+ sessionId?: string;
22
+ projectHash?: string;
23
+ }
24
+
25
+ interface CachedSessionMetadata extends GeminiSessionMetadata {
26
+ signature: string;
27
+ }
28
+
29
+ interface CachedProjectMarker {
30
+ signature: string;
31
+ projectRoot: string;
32
+ }
33
+
34
+ interface CandidateProjects {
35
+ /** sha256(projectRoot) -> process CWD that may own sessions for that root. */
36
+ cwdByHash: Map<string, string>;
37
+ /** Normalized candidate project roots, compared against `.project_root` markers. */
38
+ roots: Set<string>;
39
+ }
40
+
41
+ const SESSION_FILE_PREFIX = "session-";
42
+ /** Legacy single-document sessions. */
43
+ const SESSION_DOCUMENT_EXTENSION = ".json";
44
+ /** Gemini CLI 0.46+ append-only session logs; line 1 is the metadata record. */
45
+ const SESSION_LOG_EXTENSION = ".jsonl";
46
+ const CHATS_DIR_NAME = "chats";
47
+ /** Ownership marker Gemini CLI writes into slug-named project temp dirs. */
48
+ const PROJECT_ROOT_MARKER = ".project_root";
49
+ /** Legacy Gemini CLI temp dirs are named sha256(projectRoot). */
50
+ const LEGACY_HASH_DIR_PATTERN = /^[0-9a-f]{64}$/;
51
+ /** Slack for coarse filesystem timestamp granularity. */
52
+ const MTIME_SLACK_MS = 2 * 1000;
53
+ /**
54
+ * Both formats start with sessionId/projectHash (a legacy document's leading
55
+ * keys, a log's line-1 metadata record); a small head is enough.
56
+ */
57
+ const METADATA_HEAD_BYTES = 8 * 1024;
58
+
59
+ export class GeminiSessionLocator {
60
+ private readonly geminiTmpDir: string;
61
+ private metadataCache = new Map<string, CachedSessionMetadata>();
62
+ private markerCache = new Map<string, CachedProjectMarker>();
63
+
64
+ constructor(options: GeminiSessionLocatorOptions = {}) {
65
+ this.geminiTmpDir = options.geminiTmpDir ?? path.join(homeDir(), ".gemini", "tmp");
66
+ }
67
+
68
+ /**
69
+ * Discover session files for the given processes.
70
+ *
71
+ * Gemini CLI writes sessions to ~/.gemini/tmp/<shortId>/chats/session-*.jsonl
72
+ * (0.46+; older versions wrote session-*.json) where <shortId> is either sha256(projectRoot) (legacy) or a slug whose
73
+ * owner is recorded in <shortId>/.project_root. Each session's projectHash
74
+ * is matched against sha256 of every candidate project root of a process.
75
+ *
76
+ * To keep each refresh cheap:
77
+ * - project dirs whose name or marker can't belong to a candidate root are
78
+ * skipped without listing or opening their chats;
79
+ * - chat files last modified before the earliest candidate process start
80
+ * (minus the matching tolerance) are skipped after a stat;
81
+ * - sessionId/projectHash come from a bounded head read, cached by
82
+ * inode+size+mtime, so unchanged files are never re-read.
83
+ */
84
+ discoverSessions(processes: ProcessInfo[]): GeminiSessionDiscovery {
85
+ const empty: GeminiSessionDiscovery = { sessions: [] };
86
+ if (!fs.existsSync(this.geminiTmpDir)) return empty;
87
+
88
+ const candidates = this.buildCandidateProjects(processes);
89
+ if (candidates.cwdByHash.size === 0) return empty;
90
+
91
+ let shortIdEntries: string[];
92
+ try {
93
+ shortIdEntries = fs.readdirSync(this.geminiTmpDir);
94
+ } catch {
95
+ return empty;
96
+ }
97
+
98
+ const minMtimeMs = this.earliestMatchableMtime(processes);
99
+ const nextMetadataCache = new Map<string, CachedSessionMetadata>();
100
+ const nextMarkerCache = new Map<string, CachedProjectMarker>();
101
+ const sessions: SessionFile[] = [];
102
+
103
+ for (const shortId of shortIdEntries) {
104
+ const projectDir = path.join(this.geminiTmpDir, shortId);
105
+ if (!this.mayBelongToCandidates(projectDir, shortId, candidates, nextMarkerCache)) continue;
106
+
107
+ const chatsDir = path.join(projectDir, CHATS_DIR_NAME);
108
+ if (!isDirectory(chatsDir)) continue;
109
+
110
+ for (const fileName of this.listSessionFileNames(chatsDir)) {
111
+ const session = this.readCandidateSession(
112
+ chatsDir,
113
+ fileName,
114
+ candidates.cwdByHash,
115
+ minMtimeMs,
116
+ nextMetadataCache,
117
+ );
118
+ if (session) sessions.push(session);
119
+ }
120
+ }
121
+
122
+ // Keep metadata only for files still in scope so the caches stay bounded.
123
+ this.metadataCache = nextMetadataCache;
124
+ this.markerCache = nextMarkerCache;
125
+ return { sessions };
126
+ }
127
+
128
+ discoverHistoricalSessionFiles(): string[] {
129
+ if (!isDirectory(this.geminiTmpDir)) return [];
130
+
131
+ const files: string[] = [];
132
+ for (const shortId of safeReaddir(this.geminiTmpDir)) {
133
+ const chatsDir = path.join(this.geminiTmpDir, shortId, CHATS_DIR_NAME);
134
+ if (!isDirectory(chatsDir)) continue;
135
+
136
+ for (const fileName of this.listSessionFileNames(chatsDir)) {
137
+ files.push(path.join(chatsDir, fileName));
138
+ }
139
+ }
140
+
141
+ return files;
142
+ }
143
+
144
+ private readCandidateSession(
145
+ chatsDir: string,
146
+ fileName: string,
147
+ cwdByHash: Map<string, string>,
148
+ minMtimeMs: number,
149
+ nextMetadataCache: Map<string, CachedSessionMetadata>,
150
+ ): SessionFile | null {
151
+ const filePath = path.join(chatsDir, fileName);
152
+
153
+ const stat = safeStat(filePath);
154
+ if (!stat || stat.mtimeMs < minMtimeMs) return null;
155
+
156
+ const metadata = this.readSessionMetadata(filePath, stat);
157
+ nextMetadataCache.set(filePath, metadata);
158
+ if (!metadata.projectHash) return null;
159
+
160
+ const resolvedCwd = cwdByHash.get(metadata.projectHash);
161
+ if (!resolvedCwd) return null;
162
+
163
+ return {
164
+ sessionId: metadata.sessionId || fileName.replace(/\.jsonl?$/, ""),
165
+ filePath,
166
+ projectDir: chatsDir,
167
+ birthtimeMs: stat.birthtimeMs,
168
+ resolvedCwd,
169
+ };
170
+ }
171
+
172
+ private readSessionMetadata(filePath: string, stat: fs.Stats): CachedSessionMetadata {
173
+ const signature = fileSignature(stat);
174
+ const cached = this.metadataCache.get(filePath);
175
+ if (cached?.signature === signature) return cached;
176
+
177
+ return { signature, ...this.extractSessionMetadata(filePath) };
178
+ }
179
+
180
+ /**
181
+ * Read sessionId/projectHash from the first METADATA_HEAD_BYTES. Files that
182
+ * fit in the head are parsed as JSON exactly; larger files are scanned for
183
+ * the leading keys and only fully parsed when the head lacks them.
184
+ */
185
+ private extractSessionMetadata(filePath: string): GeminiSessionMetadata {
186
+ const head = this.readHead(filePath);
187
+ if (head === null) return {};
188
+ if (isSessionLogPath(filePath)) return this.extractLogMetadata(head);
189
+ if (head.complete) return this.pickMetadata(this.parseSessionMetadata(head.text));
190
+
191
+ const sessionId = this.matchStringField(head.text, "sessionId");
192
+ const projectHash = this.matchStringField(head.text, "projectHash");
193
+ if (sessionId !== undefined && projectHash !== undefined) {
194
+ return { sessionId, projectHash };
195
+ }
196
+
197
+ const content = safeReadFile(filePath);
198
+ if (content === undefined) return {};
199
+ return this.pickMetadata(this.parseSessionMetadata(content));
200
+ }
201
+
202
+ /**
203
+ * A `.jsonl` log's metadata is its first line. Never fall back to reading
204
+ * the whole log: it only grows, and a log whose first record is not
205
+ * metadata cannot be attributed from its head anyway.
206
+ */
207
+ private extractLogMetadata(head: { text: string; complete: boolean }): GeminiSessionMetadata {
208
+ const newline = head.text.indexOf("\n");
209
+ if (newline !== -1 || head.complete) {
210
+ const firstLine = newline === -1 ? head.text : head.text.slice(0, newline);
211
+ return this.pickMetadata(this.parseSessionMetadata(firstLine));
212
+ }
213
+ // First line longer than the head: pick the leading keys from its prefix.
214
+ return {
215
+ sessionId: this.matchStringField(head.text, "sessionId"),
216
+ projectHash: this.matchStringField(head.text, "projectHash"),
217
+ };
218
+ }
219
+
220
+ private readHead(filePath: string): { text: string; complete: boolean } | null {
221
+ let fd: number | undefined;
222
+ try {
223
+ fd = fs.openSync(filePath, "r");
224
+ // One extra byte tells "exactly METADATA_HEAD_BYTES long" from "longer".
225
+ const buffer = Buffer.alloc(METADATA_HEAD_BYTES + 1);
226
+ let length = 0;
227
+ while (length < buffer.length) {
228
+ const bytesRead = fs.readSync(fd, buffer, length, buffer.length - length, length);
229
+ if (bytesRead === 0) break;
230
+ length += bytesRead;
231
+ }
232
+ return {
233
+ text: buffer.toString("utf-8", 0, Math.min(length, METADATA_HEAD_BYTES)),
234
+ complete: length <= METADATA_HEAD_BYTES,
235
+ };
236
+ } catch {
237
+ return null;
238
+ } finally {
239
+ if (fd !== undefined) {
240
+ try {
241
+ fs.closeSync(fd);
242
+ } catch {
243
+ // Nothing useful to do if closing a read-only descriptor fails.
244
+ }
245
+ }
246
+ }
247
+ }
248
+
249
+ private matchStringField(text: string, key: string): string | undefined {
250
+ const match = new RegExp(`"${key}"\\s*:\\s*"((?:[^"\\\\]|\\\\.)*)"`).exec(text);
251
+ if (!match) return undefined;
252
+ try {
253
+ return JSON.parse(`"${match[1]}"`) as string;
254
+ } catch {
255
+ return undefined;
256
+ }
257
+ }
258
+
259
+ private pickMetadata(parsed: GeminiSessionMetadata | null): GeminiSessionMetadata {
260
+ if (!parsed || typeof parsed !== "object") return {};
261
+ return { sessionId: parsed.sessionId, projectHash: parsed.projectHash };
262
+ }
263
+
264
+ /**
265
+ * Decide from the directory name or its `.project_root` marker whether a
266
+ * project temp dir can hold sessions for a candidate root. Dirs with no
267
+ * recognisable ownership are scanned conservatively.
268
+ */
269
+ private mayBelongToCandidates(
270
+ projectDir: string,
271
+ shortId: string,
272
+ candidates: CandidateProjects,
273
+ nextMarkerCache: Map<string, CachedProjectMarker>,
274
+ ): boolean {
275
+ if (LEGACY_HASH_DIR_PATTERN.test(shortId)) return candidates.cwdByHash.has(shortId);
276
+
277
+ const projectRoot = this.readProjectMarker(projectDir, nextMarkerCache);
278
+ if (projectRoot === undefined) return true;
279
+ return candidates.roots.has(this.normalizeRoot(projectRoot));
280
+ }
281
+
282
+ private readProjectMarker(
283
+ projectDir: string,
284
+ nextMarkerCache: Map<string, CachedProjectMarker>,
285
+ ): string | undefined {
286
+ const markerPath = path.join(projectDir, PROJECT_ROOT_MARKER);
287
+ const stat = safeStat(markerPath);
288
+ if (!stat?.isFile()) return undefined;
289
+
290
+ const signature = fileSignature(stat);
291
+ const cached = this.markerCache.get(markerPath);
292
+ const projectRoot =
293
+ cached?.signature === signature ? cached.projectRoot : safeReadFile(markerPath)?.trim();
294
+ if (!projectRoot) return undefined;
295
+
296
+ nextMarkerCache.set(markerPath, { signature, projectRoot });
297
+ return projectRoot;
298
+ }
299
+
300
+ private earliestMatchableMtime(processes: ProcessInfo[]): number {
301
+ let earliestStartMs = Number.POSITIVE_INFINITY;
302
+ for (const proc of processes) {
303
+ if (!proc.cwd || !proc.startTime) continue;
304
+ const startMs = proc.startTime.getTime();
305
+ if (Number.isFinite(startMs)) earliestStartMs = Math.min(earliestStartMs, startMs);
306
+ }
307
+ // No start times: nothing can be windowed safely, so scan every file.
308
+ if (!Number.isFinite(earliestStartMs)) return Number.NEGATIVE_INFINITY;
309
+ // A file last modified before (earliest start - matcher tolerance) was also
310
+ // born before it, so it can never be matched to any candidate process.
311
+ return earliestStartMs - MATCH_TOLERANCE_MS - MTIME_SLACK_MS;
312
+ }
313
+
314
+ private buildCandidateProjects(processes: ProcessInfo[]): CandidateProjects {
315
+ const cwdByHash = new Map<string, string>();
316
+ const roots = new Set<string>();
317
+ for (const proc of processes) {
318
+ if (!proc.cwd) continue;
319
+
320
+ // Gemini CLI resolves its project root by walking up from the
321
+ // startup directory looking for a `.git` boundary marker. A
322
+ // session's projectHash therefore tracks that ancestor rather
323
+ // than the process' actual CWD. Enumerate every ancestor as a
324
+ // candidate so subdirectory invocations still line up with the
325
+ // session the Gemini process wrote.
326
+ for (const candidate of this.candidateProjectRoots(proc.cwd)) {
327
+ roots.add(this.normalizeRoot(candidate));
328
+ const hash = this.hashProjectRoot(candidate);
329
+ if (!cwdByHash.has(hash)) {
330
+ cwdByHash.set(hash, proc.cwd);
331
+ }
332
+ }
333
+ }
334
+ return { cwdByHash, roots };
335
+ }
336
+
337
+ /** Match Gemini CLI's project registry normalization (lower-cased on Windows). */
338
+ private normalizeRoot(projectRoot: string): string {
339
+ const resolved = path.resolve(projectRoot);
340
+ return process.platform === "win32" ? resolved.toLowerCase() : resolved;
341
+ }
342
+
343
+ private candidateProjectRoots(cwd: string): string[] {
344
+ const roots: string[] = [];
345
+ let current = path.resolve(cwd);
346
+ let parent = path.dirname(current);
347
+ while (parent !== current) {
348
+ roots.push(current);
349
+ current = parent;
350
+ parent = path.dirname(current);
351
+ }
352
+ roots.push(current);
353
+ return roots;
354
+ }
355
+
356
+ private hashProjectRoot(projectRoot: string): string {
357
+ return crypto.createHash("sha256").update(projectRoot).digest("hex");
358
+ }
359
+
360
+ /**
361
+ * Session files in a chats dir, in both formats. Resuming a legacy session
362
+ * makes Gemini CLI continue it in `<name>.jsonl` next to the stale
363
+ * `<name>.json`, so a `.json` with a `.jsonl` sibling is skipped.
364
+ */
365
+ private listSessionFileNames(chatsDir: string): string[] {
366
+ const sessionFiles = safeReaddir(chatsDir).filter((fileName) => this.isSessionFile(fileName));
367
+ const names = new Set(sessionFiles);
368
+ return sessionFiles.filter(
369
+ (fileName) =>
370
+ !fileName.endsWith(SESSION_DOCUMENT_EXTENSION) ||
371
+ !names.has(this.toSessionLogName(fileName)),
372
+ );
373
+ }
374
+
375
+ private toSessionLogName(documentFileName: string): string {
376
+ const baseName = documentFileName.slice(0, -SESSION_DOCUMENT_EXTENSION.length);
377
+ return `${baseName}${SESSION_LOG_EXTENSION}`;
378
+ }
379
+
380
+ private isSessionFile(fileName: string): boolean {
381
+ return (
382
+ fileName.startsWith(SESSION_FILE_PREFIX) &&
383
+ (fileName.endsWith(SESSION_DOCUMENT_EXTENSION) || fileName.endsWith(SESSION_LOG_EXTENSION))
384
+ );
385
+ }
386
+
387
+ private parseSessionMetadata(content: string): GeminiSessionMetadata | null {
388
+ try {
389
+ return JSON.parse(content) as GeminiSessionMetadata;
390
+ } catch {
391
+ return null;
392
+ }
393
+ }
394
+ }
@@ -1,7 +1,14 @@
1
1
  import * as fs from "fs";
2
- import type { ConversationMessage, SessionSummary } from "../../adapters/AgentAdapter.js";
2
+ import type {
3
+ ConversationMessage,
4
+ ConversationOptions,
5
+ SessionSummary,
6
+ } from "../../adapters/AgentAdapter.js";
3
7
  import { AgentStatus } from "../../adapters/AgentAdapter.js";
8
+ import { sliceTail } from "../../utils/jsonlTail.js";
4
9
  import { safeReadFile, safeStat } from "../../utils/session.js";
10
+ import { fileSignature } from "./fileSignature.js";
11
+ import { isIdle, parseTimestamp, SUMMARY_MAX_LENGTH, truncate } from "../shared.js";
5
12
 
6
13
  /**
7
14
  * A single Gemini CLI message content part. Mirrors the `{text?: string}`
@@ -54,31 +61,70 @@ export interface GeminiSession {
54
61
  lastMessageType?: string;
55
62
  }
56
63
 
57
- const IDLE_THRESHOLD_MINUTES = 5;
64
+ interface CachedParsedSession {
65
+ signature: string;
66
+ session: GeminiSession | null;
67
+ }
68
+
69
+ const SESSION_LOG_EXTENSION = ".jsonl";
70
+ /** Parsed sessions are small (summary is truncated); cap entries, not bytes. */
71
+ const MAX_CACHED_SESSIONS = 256;
58
72
 
59
73
  export class GeminiSessionParser {
74
+ private readonly sessionCache = new Map<string, CachedParsedSession>();
75
+
60
76
  /**
61
77
  * Parse session file content into GeminiSession.
62
- * Uses cached content if available, otherwise reads from disk.
78
+ * Uses the given content if available; otherwise reads from disk, reusing
79
+ * the previous result while the file's inode, size and mtime are unchanged.
63
80
  */
64
81
  parseSession(cachedContent: string | undefined, filePath: string): GeminiSession | null {
65
- const content = cachedContent ?? this.readSessionFile(filePath);
66
- if (content === null) return null;
82
+ const fileStat = safeStat(filePath);
83
+ if (cachedContent !== undefined) return this.buildSession(cachedContent, filePath, fileStat);
84
+
85
+ if (!fileStat) {
86
+ this.sessionCache.delete(filePath);
87
+ return null;
88
+ }
89
+
90
+ const signature = fileSignature(fileStat);
91
+ const cached = this.sessionCache.get(filePath);
92
+ if (cached?.signature === signature) return cached.session;
93
+
94
+ const content = this.readSessionFile(filePath);
95
+ const session = content === null ? null : this.buildSession(content, filePath, fileStat);
96
+ this.rememberSession(filePath, { signature, session });
97
+ return session;
98
+ }
99
+
100
+ private rememberSession(filePath: string, entry: CachedParsedSession): void {
101
+ this.sessionCache.delete(filePath);
102
+ this.sessionCache.set(filePath, entry);
103
+ while (this.sessionCache.size > MAX_CACHED_SESSIONS) {
104
+ const oldest = this.sessionCache.keys().next().value;
105
+ if (oldest === undefined) break;
106
+ this.sessionCache.delete(oldest);
107
+ }
108
+ }
67
109
 
68
- const parsed = this.parseSessionJson(content);
110
+ private buildSession(
111
+ content: string,
112
+ filePath: string,
113
+ fileStat: fs.Stats | undefined,
114
+ ): GeminiSession | null {
115
+ const parsed = this.parseSessionContent(content, filePath);
69
116
  if (!parsed?.sessionId) return null;
70
117
 
71
118
  const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
72
119
  const lastEntry = messages.length > 0 ? messages[messages.length - 1] : undefined;
73
- const fileStat = safeStat(filePath);
74
120
 
75
121
  const lastActive =
76
- this.parseTimestamp(parsed.lastUpdated) ||
77
- this.parseTimestamp(lastEntry?.timestamp) ||
122
+ parseTimestamp(parsed.lastUpdated) ||
123
+ parseTimestamp(lastEntry?.timestamp) ||
78
124
  fileStat?.mtime ||
79
125
  new Date();
80
126
 
81
- const sessionStart = this.parseTimestamp(parsed.startTime) || lastActive;
127
+ const sessionStart = parseTimestamp(parsed.startTime) || lastActive;
82
128
  const projectPath =
83
129
  Array.isArray(parsed.directories) && parsed.directories.length > 0
84
130
  ? parsed.directories[0]
@@ -95,10 +141,7 @@ export class GeminiSessionParser {
95
141
  }
96
142
 
97
143
  determineStatus(session: GeminiSession): AgentStatus {
98
- const diffMs = Date.now() - session.lastActive.getTime();
99
- const diffMinutes = diffMs / 60000;
100
-
101
- if (diffMinutes > IDLE_THRESHOLD_MINUTES) {
144
+ if (isIdle(session.lastActive)) {
102
145
  return AgentStatus.IDLE;
103
146
  }
104
147
 
@@ -114,13 +157,17 @@ export class GeminiSessionParser {
114
157
  *
115
158
  * Gemini sessions store messages in an array with `type` field — typically
116
159
  * 'user' or 'gemini' for visible turns, with tool and system entries mixed in.
160
+ *
161
+ * `tail` only slices the result: the session is a single JSON document, so
162
+ * it cannot be read from the end and is always parsed in full. Callers that
163
+ * poll (the console preview) rely on their mtime cache to skip re-parses.
117
164
  */
118
- getConversation(sessionFilePath: string, options?: { verbose?: boolean }): ConversationMessage[] {
165
+ getConversation(sessionFilePath: string, options?: ConversationOptions): ConversationMessage[] {
119
166
  const verbose = options?.verbose ?? false;
120
167
  const content = safeReadFile(sessionFilePath);
121
168
  if (content === undefined) return [];
122
169
 
123
- const parsed = this.parseSessionJson(content);
170
+ const parsed = this.parseSessionContent(content, sessionFilePath);
124
171
  if (!Array.isArray(parsed?.messages)) return [];
125
172
 
126
173
  const messages: ConversationMessage[] = [];
@@ -138,7 +185,7 @@ export class GeminiSessionParser {
138
185
  });
139
186
  }
140
187
 
141
- return messages;
188
+ return sliceTail(messages, options?.tail);
142
189
  }
143
190
 
144
191
  /**
@@ -150,7 +197,7 @@ export class GeminiSessionParser {
150
197
  const content = safeReadFile(filePath);
151
198
  if (content === undefined) return null;
152
199
 
153
- const parsed = this.parseSessionJson(content);
200
+ const parsed = this.parseSessionContent(content, filePath);
154
201
  if (!parsed?.sessionId) return null;
155
202
 
156
203
  const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
@@ -161,13 +208,13 @@ export class GeminiSessionParser {
161
208
  : "";
162
209
 
163
210
  const stat = safeStat(filePath);
164
- const lastEntryTimestamp = this.parseTimestamp(
211
+ const lastEntryTimestamp = parseTimestamp(
165
212
  messages.length > 0 ? messages[messages.length - 1]?.timestamp : undefined,
166
213
  );
167
214
  const lastActive =
168
- this.parseTimestamp(parsed.lastUpdated) || lastEntryTimestamp || stat?.mtime || new Date();
215
+ parseTimestamp(parsed.lastUpdated) || lastEntryTimestamp || stat?.mtime || new Date();
169
216
  const startedAt =
170
- this.parseTimestamp(parsed.startTime) || stat?.birthtime || stat?.mtime || lastActive;
217
+ parseTimestamp(parsed.startTime) || stat?.birthtime || stat?.mtime || lastActive;
171
218
 
172
219
  return {
173
220
  type: "gemini_cli",
@@ -180,6 +227,85 @@ export class GeminiSessionParser {
180
227
  };
181
228
  }
182
229
 
230
+ /**
231
+ * Parse either session format into the legacy single-document shape:
232
+ * `session-*.json` is one JSON document, `session-*.jsonl` (Gemini CLI
233
+ * 0.46+) is an append-only log replayed by {@link replaySessionLog}.
234
+ */
235
+ private parseSessionContent(content: string, filePath: string): GeminiSessionFile | null {
236
+ return isSessionLogPath(filePath)
237
+ ? this.replaySessionLog(content)
238
+ : this.parseSessionJson(content);
239
+ }
240
+
241
+ /**
242
+ * Rebuild a session document from a `.jsonl` log, mirroring Gemini CLI's
243
+ * own loader (`loadConversationRecord`):
244
+ * - a record with a string `id` is a message, upserted by id in place;
245
+ * - `{"$set": {...}}` merges metadata; a `$set.messages` array replaces
246
+ * every message;
247
+ * - `{"$rewindTo": id}` drops that message and all later ones (all
248
+ * messages when the id is unknown);
249
+ * - a record with `sessionId` and `projectHash` (line 1) merges metadata.
250
+ * Unknown operators, non-object lines and a torn trailing line (a write
251
+ * in progress) are ignored.
252
+ */
253
+ private replaySessionLog(content: string): GeminiSessionFile | null {
254
+ let metadata: Record<string, unknown> = {};
255
+ const messages = new Map<string, GeminiMessageEntry>();
256
+ const upsertAll = (entries: unknown): void => {
257
+ if (!Array.isArray(entries)) return;
258
+ for (const entry of entries) {
259
+ if (isRecord(entry) && typeof entry.id === "string") messages.set(entry.id, entry);
260
+ }
261
+ };
262
+
263
+ for (const line of content.split("\n")) {
264
+ if (!line.trim()) continue;
265
+ const record = this.parseLogRecord(line);
266
+ if (!record) continue;
267
+
268
+ if (typeof record.$rewindTo === "string") {
269
+ this.rewindMessages(messages, record.$rewindTo);
270
+ } else if (typeof record.id === "string") {
271
+ messages.set(record.id, record);
272
+ } else if (isRecord(record.$set)) {
273
+ if (Array.isArray(record.$set.messages)) {
274
+ messages.clear();
275
+ upsertAll(record.$set.messages);
276
+ }
277
+ metadata = { ...metadata, ...record.$set };
278
+ } else if (typeof record.sessionId === "string" && typeof record.projectHash === "string") {
279
+ metadata = { ...metadata, ...record };
280
+ upsertAll(record.messages);
281
+ }
282
+ }
283
+
284
+ if (typeof metadata.sessionId !== "string") return null;
285
+ return { ...(metadata as GeminiSessionFile), messages: Array.from(messages.values()) };
286
+ }
287
+
288
+ private rewindMessages(messages: Map<string, GeminiMessageEntry>, messageId: string): void {
289
+ if (!messages.has(messageId)) {
290
+ messages.clear();
291
+ return;
292
+ }
293
+ let found = false;
294
+ for (const id of Array.from(messages.keys())) {
295
+ if (id === messageId) found = true;
296
+ if (found) messages.delete(id);
297
+ }
298
+ }
299
+
300
+ private parseLogRecord(line: string): Record<string, unknown> | null {
301
+ try {
302
+ const record: unknown = JSON.parse(line);
303
+ return isRecord(record) ? record : null;
304
+ } catch {
305
+ return null;
306
+ }
307
+ }
308
+
183
309
  private parseSessionJson(content: string): GeminiSessionFile | null {
184
310
  try {
185
311
  return JSON.parse(content) as GeminiSessionFile;
@@ -211,7 +337,7 @@ export class GeminiSessionParser {
211
337
  const entry = messages[i];
212
338
  if (entry?.type !== "user") continue;
213
339
  const text = this.messageText(entry).trim();
214
- if (text) return this.truncate(text, 120);
340
+ if (text) return truncate(text, SUMMARY_MAX_LENGTH);
215
341
  }
216
342
 
217
343
  return "Gemini CLI session active";
@@ -257,15 +383,13 @@ export class GeminiSessionParser {
257
383
  }
258
384
  return "";
259
385
  }
386
+ }
260
387
 
261
- private parseTimestamp(value?: string): Date | null {
262
- if (!value) return null;
263
- const timestamp = new Date(value);
264
- return Number.isNaN(timestamp.getTime()) ? null : timestamp;
265
- }
388
+ /** Gemini CLI 0.46+ writes sessions as append-only `.jsonl` logs. */
389
+ export function isSessionLogPath(filePath: string): boolean {
390
+ return filePath.endsWith(SESSION_LOG_EXTENSION);
391
+ }
266
392
 
267
- private truncate(value: string, maxLength: number): string {
268
- if (value.length <= maxLength) return value;
269
- return `${value.slice(0, maxLength - 3)}...`;
270
- }
393
+ function isRecord(value: unknown): value is Record<string, unknown> {
394
+ return value !== null && typeof value === "object" && !Array.isArray(value);
271
395
  }
@@ -0,0 +1,10 @@
1
+ import type * as fs from "fs";
2
+
3
+ /**
4
+ * Identity of a file's current contents derived from `stat` alone:
5
+ * inode, size and mtime. Used to reuse metadata and parse results across
6
+ * refreshes without re-reading unchanged Gemini chat files.
7
+ */
8
+ export function fileSignature(stat: fs.Stats): string {
9
+ return `${stat.ino}:${stat.size}:${stat.mtimeMs}`;
10
+ }